mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-11-21 18:16:09 +01:00
Some changes to remove 404-responses from the webserver on empty map-tiles
This commit is contained in:
parent
bd5071eb61
commit
481a452b9c
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,6 +4,7 @@ build/
|
|||||||
bin/
|
bin/
|
||||||
doc/
|
doc/
|
||||||
logs/
|
logs/
|
||||||
|
.run/
|
||||||
run/
|
run/
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit f3dc8d5dd478475cf8a1f0f1b166843821109ad2
|
Subproject commit 4bef101c6ee6ddef23049287cc1a3736d954979e
|
@ -31,7 +31,6 @@
|
|||||||
import de.bluecolored.bluemap.api.marker.Marker;
|
import de.bluecolored.bluemap.api.marker.Marker;
|
||||||
import ninja.leaping.configurate.ConfigurationNode;
|
import ninja.leaping.configurate.ConfigurationNode;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public abstract class MarkerImpl implements Marker {
|
public abstract class MarkerImpl implements Marker {
|
||||||
|
@ -24,24 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
package de.bluecolored.bluemap.common.plugin;
|
package de.bluecolored.bluemap.common.plugin;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import de.bluecolored.bluemap.common.*;
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.zip.GZIPInputStream;
|
|
||||||
import java.util.zip.GZIPOutputStream;
|
|
||||||
|
|
||||||
import de.bluecolored.bluemap.common.BlueMapService;
|
|
||||||
import de.bluecolored.bluemap.common.InterruptableReentrantLock;
|
|
||||||
import de.bluecolored.bluemap.common.MapType;
|
|
||||||
import de.bluecolored.bluemap.common.MissingResourcesException;
|
|
||||||
import de.bluecolored.bluemap.common.RenderManager;
|
|
||||||
import de.bluecolored.bluemap.common.api.BlueMapAPIImpl;
|
import de.bluecolored.bluemap.common.api.BlueMapAPIImpl;
|
||||||
import de.bluecolored.bluemap.common.live.LiveAPIRequestHandler;
|
import de.bluecolored.bluemap.common.live.LiveAPIRequestHandler;
|
||||||
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerInterface;
|
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerInterface;
|
||||||
@ -59,6 +42,14 @@
|
|||||||
import de.bluecolored.bluemap.core.webserver.WebServer;
|
import de.bluecolored.bluemap.core.webserver.WebServer;
|
||||||
import de.bluecolored.bluemap.core.world.World;
|
import de.bluecolored.bluemap.core.world.World;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
public class Plugin {
|
public class Plugin {
|
||||||
|
|
||||||
public static final String PLUGIN_ID = "bluemap";
|
public static final String PLUGIN_ID = "bluemap";
|
||||||
@ -207,7 +198,10 @@ public void load() throws IOException, ParseResourceException {
|
|||||||
|
|
||||||
//start skin updater
|
//start skin updater
|
||||||
if (pluginConfig.isLiveUpdatesEnabled()) {
|
if (pluginConfig.isLiveUpdatesEnabled()) {
|
||||||
this.skinUpdater = new PlayerSkinUpdater(new File(renderConfig.getWebRoot(), "assets" + File.separator + "playerheads"));
|
this.skinUpdater = new PlayerSkinUpdater(
|
||||||
|
new File(renderConfig.getWebRoot(), "assets" + File.separator + "playerheads"),
|
||||||
|
new File(renderConfig.getWebRoot(), "assets" + File.separator + "steve.png")
|
||||||
|
);
|
||||||
serverInterface.registerListener(skinUpdater);
|
serverInterface.registerListener(skinUpdater);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,13 @@
|
|||||||
*/
|
*/
|
||||||
package de.bluecolored.bluemap.common.plugin.skins;
|
package de.bluecolored.bluemap.common.plugin.skins;
|
||||||
|
|
||||||
import java.awt.Graphics2D;
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import de.bluecolored.bluemap.core.logger.Logger;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -33,19 +39,7 @@
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
|
|
||||||
import de.bluecolored.bluemap.core.logger.Logger;
|
|
||||||
|
|
||||||
public class PlayerSkin {
|
public class PlayerSkin {
|
||||||
|
|
||||||
@ -57,23 +51,32 @@ public PlayerSkin(UUID uuid) {
|
|||||||
this.lastUpdate = -1;
|
this.lastUpdate = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(File storageFolder) {
|
public void update(File storageFolder, File fallback) {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
if (lastUpdate > 0 && lastUpdate + 600000 > now) return; // only update if skin is older than 10 minutes
|
if (lastUpdate > 0 && lastUpdate + 600000 > now) return; // only update if skin is older than 10 minutes
|
||||||
|
|
||||||
lastUpdate = now;
|
lastUpdate = now;
|
||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
|
BufferedImage head = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Future<BufferedImage> futureSkin = loadSkin();
|
Future<BufferedImage> futureSkin = loadSkin();
|
||||||
BufferedImage skin = futureSkin.get(10, TimeUnit.SECONDS);
|
BufferedImage skin = futureSkin.get(10, TimeUnit.SECONDS);
|
||||||
BufferedImage head = createHead(skin);
|
head = createHead(skin);
|
||||||
ImageIO.write(head, "png", new File(storageFolder, uuid.toString() + ".png"));
|
|
||||||
} catch (ExecutionException | TimeoutException e) {
|
} catch (ExecutionException | TimeoutException e) {
|
||||||
Logger.global.logDebug("Failed to load player-skin from mojang-servers: " + e);
|
Logger.global.logDebug("Failed to load player-skin from mojang-servers: " + e);
|
||||||
|
} catch (InterruptedException ignore) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (head == null) head = ImageIO.read(fallback);
|
||||||
|
ImageIO.write(head, "png", new File(storageFolder, uuid.toString() + ".png"));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Logger.global.logError("Failed to write player-head image!", e);
|
Logger.global.logError("Failed to write player-head image!", e);
|
||||||
} catch (InterruptedException ignore) { Thread.currentThread().interrupt(); }
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,24 +24,28 @@
|
|||||||
*/
|
*/
|
||||||
package de.bluecolored.bluemap.common.plugin.skins;
|
package de.bluecolored.bluemap.common.plugin.skins;
|
||||||
|
|
||||||
|
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerEventListener;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerEventListener;
|
|
||||||
|
|
||||||
public class PlayerSkinUpdater implements ServerEventListener {
|
public class PlayerSkinUpdater implements ServerEventListener {
|
||||||
|
|
||||||
private File storageFolder;
|
private File storageFolder;
|
||||||
|
private File defaultSkin;
|
||||||
|
|
||||||
private Map<UUID, PlayerSkin> skins;
|
private final Map<UUID, PlayerSkin> skins;
|
||||||
|
|
||||||
public PlayerSkinUpdater(File storageFolder) {
|
public PlayerSkinUpdater(File storageFolder, File defaultSkin) throws IOException {
|
||||||
this.storageFolder = storageFolder;
|
this.storageFolder = storageFolder;
|
||||||
|
this.defaultSkin = defaultSkin;
|
||||||
this.skins = new ConcurrentHashMap<>();
|
this.skins = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
this.storageFolder.mkdirs();
|
FileUtils.forceMkdir(this.storageFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateSkin(UUID playerUuid) {
|
public void updateSkin(UUID playerUuid) {
|
||||||
@ -52,12 +56,28 @@ public void updateSkin(UUID playerUuid) {
|
|||||||
skins.put(playerUuid, skin);
|
skins.put(playerUuid, skin);
|
||||||
}
|
}
|
||||||
|
|
||||||
skin.update(storageFolder);
|
skin.update(storageFolder, defaultSkin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlayerJoin(UUID playerUuid) {
|
public void onPlayerJoin(UUID playerUuid) {
|
||||||
updateSkin(playerUuid);
|
updateSkin(playerUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public File getStorageFolder() {
|
||||||
|
return storageFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStorageFolder(File storageFolder) {
|
||||||
|
this.storageFolder = storageFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getDefaultSkin() {
|
||||||
|
return defaultSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultSkin(File defaultSkin) {
|
||||||
|
this.defaultSkin = defaultSkin;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,14 @@
|
|||||||
*/
|
*/
|
||||||
package de.bluecolored.bluemap.core.web;
|
package de.bluecolored.bluemap.core.web;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import de.bluecolored.bluemap.core.webserver.HttpRequest;
|
||||||
import java.io.ByteArrayOutputStream;
|
import de.bluecolored.bluemap.core.webserver.HttpRequestHandler;
|
||||||
import java.io.File;
|
import de.bluecolored.bluemap.core.webserver.HttpResponse;
|
||||||
import java.io.FileInputStream;
|
import de.bluecolored.bluemap.core.webserver.HttpStatusCode;
|
||||||
import java.io.FileNotFoundException;
|
import org.apache.commons.io.IOUtils;
|
||||||
import java.io.IOException;
|
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
import java.nio.file.InvalidPathException;
|
import java.nio.file.InvalidPathException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
@ -40,26 +42,22 @@
|
|||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
import java.util.zip.GZIPOutputStream;
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
|
||||||
|
|
||||||
import de.bluecolored.bluemap.core.webserver.HttpRequest;
|
|
||||||
import de.bluecolored.bluemap.core.webserver.HttpRequestHandler;
|
|
||||||
import de.bluecolored.bluemap.core.webserver.HttpResponse;
|
|
||||||
import de.bluecolored.bluemap.core.webserver.HttpStatusCode;
|
|
||||||
|
|
||||||
public class FileRequestHandler implements HttpRequestHandler {
|
public class FileRequestHandler implements HttpRequestHandler {
|
||||||
|
|
||||||
private static final long DEFLATE_MIN_SIZE = 10L * 1024L;
|
private static final long DEFLATE_MIN_SIZE = 10L * 1024L;
|
||||||
private static final long DEFLATE_MAX_SIZE = 10L * 1024L * 1024L;
|
private static final long DEFLATE_MAX_SIZE = 10L * 1024L * 1024L;
|
||||||
private static final long INFLATE_MAX_SIZE = 10L * 1024L * 1024L;
|
private static final long INFLATE_MAX_SIZE = 10L * 1024L * 1024L;
|
||||||
|
|
||||||
private Path webRoot;
|
private final Path webRoot;
|
||||||
private String serverName;
|
private final String serverName;
|
||||||
|
|
||||||
|
private final File emptyTileFile;
|
||||||
|
|
||||||
public FileRequestHandler(Path webRoot, String serverName) {
|
public FileRequestHandler(Path webRoot, String serverName) {
|
||||||
this.webRoot = webRoot;
|
this.webRoot = webRoot.normalize();
|
||||||
this.serverName = serverName;
|
this.serverName = serverName;
|
||||||
|
|
||||||
|
this.emptyTileFile = webRoot.resolve("assets").resolve("emptyTile.json").toFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -84,10 +82,10 @@ public HttpResponse handle(HttpRequest request) {
|
|||||||
private HttpResponse generateResponse(HttpRequest request) {
|
private HttpResponse generateResponse(HttpRequest request) {
|
||||||
String path = request.getPath();
|
String path = request.getPath();
|
||||||
|
|
||||||
//normalize path
|
// normalize path
|
||||||
if (path.startsWith("/")) path = path.substring(1);
|
if (path.startsWith("/")) path = path.substring(1);
|
||||||
if (path.endsWith("/")) path = path.substring(0, path.length() - 1);
|
if (path.endsWith("/")) path = path.substring(0, path.length() - 1);
|
||||||
|
|
||||||
Path filePath = webRoot;
|
Path filePath = webRoot;
|
||||||
try {
|
try {
|
||||||
filePath = webRoot.resolve(path);
|
filePath = webRoot.resolve(path);
|
||||||
@ -95,12 +93,12 @@ private HttpResponse generateResponse(HttpRequest request) {
|
|||||||
return new HttpResponse(HttpStatusCode.NOT_FOUND);
|
return new HttpResponse(HttpStatusCode.NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
//can we use deflation?
|
// can we use deflation?
|
||||||
boolean isDeflationPossible = request.getLowercaseHeader("Accept-Encoding").contains("gzip");
|
boolean isDeflationPossible = request.getLowercaseHeader("Accept-Encoding").contains("gzip");
|
||||||
boolean isDeflated = false;
|
boolean isDeflated = false;
|
||||||
|
|
||||||
//check if file is in web-root
|
// check if file is in web-root
|
||||||
if (!filePath.normalize().startsWith(webRoot.normalize())){
|
if (!filePath.normalize().startsWith(webRoot)){
|
||||||
return new HttpResponse(HttpStatusCode.FORBIDDEN);
|
return new HttpResponse(HttpStatusCode.FORBIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +126,12 @@ private HttpResponse generateResponse(HttpRequest request) {
|
|||||||
isDeflated = true;
|
isDeflated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file.exists()){
|
if (!file.exists() && file.toPath().startsWith(webRoot.resolve("data"))){
|
||||||
|
file = emptyTileFile;
|
||||||
|
isDeflated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file.exists() || file.isDirectory()) {
|
||||||
return new HttpResponse(HttpStatusCode.NOT_FOUND);
|
return new HttpResponse(HttpStatusCode.NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,12 +143,12 @@ private HttpResponse generateResponse(HttpRequest request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if file is still in web-root
|
// check if file is still in web-root and is not a directory
|
||||||
if (!file.toPath().normalize().startsWith(webRoot.normalize())){
|
if (!file.toPath().normalize().startsWith(webRoot) || file.isDirectory()){
|
||||||
return new HttpResponse(HttpStatusCode.FORBIDDEN);
|
return new HttpResponse(HttpStatusCode.FORBIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
//check modified
|
// check modified
|
||||||
long lastModified = file.lastModified();
|
long lastModified = file.lastModified();
|
||||||
Set<String> modStringSet = request.getHeader("If-Modified-Since");
|
Set<String> modStringSet = request.getHeader("If-Modified-Since");
|
||||||
if (!modStringSet.isEmpty()){
|
if (!modStringSet.isEmpty()){
|
||||||
@ -154,7 +157,7 @@ private HttpResponse generateResponse(HttpRequest request) {
|
|||||||
if (since + 1000 >= lastModified){
|
if (since + 1000 >= lastModified){
|
||||||
return new HttpResponse(HttpStatusCode.NOT_MODIFIED);
|
return new HttpResponse(HttpStatusCode.NOT_MODIFIED);
|
||||||
}
|
}
|
||||||
} catch (IllegalArgumentException e){}
|
} catch (IllegalArgumentException ignored){}
|
||||||
}
|
}
|
||||||
|
|
||||||
//check ETag
|
//check ETag
|
||||||
@ -174,7 +177,7 @@ private HttpResponse generateResponse(HttpRequest request) {
|
|||||||
response.addHeader("Cache-Control", "max-age=" + TimeUnit.HOURS.toSeconds(1));
|
response.addHeader("Cache-Control", "max-age=" + TimeUnit.HOURS.toSeconds(1));
|
||||||
|
|
||||||
//add content type header
|
//add content type header
|
||||||
String filetype = file.getName().toString();
|
String filetype = file.getName();
|
||||||
if (filetype.endsWith(".gz")) filetype = filetype.substring(0, filetype.length() - 3);
|
if (filetype.endsWith(".gz")) filetype = filetype.substring(0, filetype.length() - 3);
|
||||||
int pointIndex = filetype.lastIndexOf('.');
|
int pointIndex = filetype.lastIndexOf('.');
|
||||||
if (pointIndex >= 0) filetype = filetype.substring(pointIndex + 1);
|
if (pointIndex >= 0) filetype = filetype.substring(pointIndex + 1);
|
||||||
|
Loading…
Reference in New Issue
Block a user