Some changes to remove 404-responses from the webserver on empty map-tiles

This commit is contained in:
Blue (Lukas Rieger) 2021-03-28 13:25:39 +02:00
parent bd5071eb61
commit 481a452b9c
No known key found for this signature in database
GPG Key ID: 904C4995F9E1F800
7 changed files with 95 additions and 75 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@ build/
bin/
doc/
logs/
.run/
run/
node_modules/

@ -1 +1 @@
Subproject commit f3dc8d5dd478475cf8a1f0f1b166843821109ad2
Subproject commit 4bef101c6ee6ddef23049287cc1a3736d954979e

View File

@ -31,7 +31,6 @@
import de.bluecolored.bluemap.api.marker.Marker;
import ninja.leaping.configurate.ConfigurationNode;
import java.util.Objects;
import java.util.Optional;
public abstract class MarkerImpl implements Marker {

View File

@ -24,24 +24,7 @@
*/
package de.bluecolored.bluemap.common.plugin;
import java.io.DataInputStream;
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.*;
import de.bluecolored.bluemap.common.api.BlueMapAPIImpl;
import de.bluecolored.bluemap.common.live.LiveAPIRequestHandler;
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerInterface;
@ -59,6 +42,14 @@
import de.bluecolored.bluemap.core.webserver.WebServer;
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 static final String PLUGIN_ID = "bluemap";
@ -207,7 +198,10 @@ public void load() throws IOException, ParseResourceException {
//start skin updater
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);
}

View File

@ -24,7 +24,13 @@
*/
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.io.File;
import java.io.IOException;
@ -33,19 +39,7 @@
import java.net.URL;
import java.util.Base64;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
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;
import java.util.concurrent.*;
public class PlayerSkin {
@ -57,23 +51,32 @@ public PlayerSkin(UUID uuid) {
this.lastUpdate = -1;
}
public void update(File storageFolder) {
public void update(File storageFolder, File fallback) {
long now = System.currentTimeMillis();
if (lastUpdate > 0 && lastUpdate + 600000 > now) return; // only update if skin is older than 10 minutes
lastUpdate = now;
new Thread(() -> {
BufferedImage head = null;
try {
Future<BufferedImage> futureSkin = loadSkin();
BufferedImage skin = futureSkin.get(10, TimeUnit.SECONDS);
BufferedImage head = createHead(skin);
ImageIO.write(head, "png", new File(storageFolder, uuid.toString() + ".png"));
head = createHead(skin);
} catch (ExecutionException | TimeoutException 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) {
Logger.global.logError("Failed to write player-head image!", e);
} catch (InterruptedException ignore) { Thread.currentThread().interrupt(); }
}
}).start();
}

View File

@ -24,24 +24,28 @@
*/
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.IOException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerEventListener;
public class PlayerSkinUpdater implements ServerEventListener {
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.defaultSkin = defaultSkin;
this.skins = new ConcurrentHashMap<>();
this.storageFolder.mkdirs();
FileUtils.forceMkdir(this.storageFolder);
}
public void updateSkin(UUID playerUuid) {
@ -52,12 +56,28 @@ public void updateSkin(UUID playerUuid) {
skins.put(playerUuid, skin);
}
skin.update(storageFolder);
skin.update(storageFolder, defaultSkin);
}
@Override
public void onPlayerJoin(UUID 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;
}
}

View File

@ -24,12 +24,14 @@
*/
package de.bluecolored.bluemap.core.web;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
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;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.io.*;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.util.GregorianCalendar;
@ -40,26 +42,22 @@
import java.util.zip.GZIPInputStream;
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 {
private static final long DEFLATE_MIN_SIZE = 10L * 1024L;
private static final long DEFLATE_MAX_SIZE = 10L * 1024L * 1024L;
private static final long INFLATE_MAX_SIZE = 10L * 1024L * 1024L;
private Path webRoot;
private String serverName;
private final Path webRoot;
private final String serverName;
private final File emptyTileFile;
public FileRequestHandler(Path webRoot, String serverName) {
this.webRoot = webRoot;
this.webRoot = webRoot.normalize();
this.serverName = serverName;
this.emptyTileFile = webRoot.resolve("assets").resolve("emptyTile.json").toFile();
}
@Override
@ -84,10 +82,10 @@ public HttpResponse handle(HttpRequest request) {
private HttpResponse generateResponse(HttpRequest request) {
String path = request.getPath();
//normalize path
// normalize path
if (path.startsWith("/")) path = path.substring(1);
if (path.endsWith("/")) path = path.substring(0, path.length() - 1);
Path filePath = webRoot;
try {
filePath = webRoot.resolve(path);
@ -95,12 +93,12 @@ private HttpResponse generateResponse(HttpRequest request) {
return new HttpResponse(HttpStatusCode.NOT_FOUND);
}
//can we use deflation?
// can we use deflation?
boolean isDeflationPossible = request.getLowercaseHeader("Accept-Encoding").contains("gzip");
boolean isDeflated = false;
//check if file is in web-root
if (!filePath.normalize().startsWith(webRoot.normalize())){
// check if file is in web-root
if (!filePath.normalize().startsWith(webRoot)){
return new HttpResponse(HttpStatusCode.FORBIDDEN);
}
@ -128,7 +126,12 @@ private HttpResponse generateResponse(HttpRequest request) {
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);
}
@ -140,12 +143,12 @@ private HttpResponse generateResponse(HttpRequest request) {
}
}
//check if file is still in web-root
if (!file.toPath().normalize().startsWith(webRoot.normalize())){
// check if file is still in web-root and is not a directory
if (!file.toPath().normalize().startsWith(webRoot) || file.isDirectory()){
return new HttpResponse(HttpStatusCode.FORBIDDEN);
}
//check modified
// check modified
long lastModified = file.lastModified();
Set<String> modStringSet = request.getHeader("If-Modified-Since");
if (!modStringSet.isEmpty()){
@ -154,7 +157,7 @@ private HttpResponse generateResponse(HttpRequest request) {
if (since + 1000 >= lastModified){
return new HttpResponse(HttpStatusCode.NOT_MODIFIED);
}
} catch (IllegalArgumentException e){}
} catch (IllegalArgumentException ignored){}
}
//check ETag
@ -174,7 +177,7 @@ private HttpResponse generateResponse(HttpRequest request) {
response.addHeader("Cache-Control", "max-age=" + TimeUnit.HOURS.toSeconds(1));
//add content type header
String filetype = file.getName().toString();
String filetype = file.getName();
if (filetype.endsWith(".gz")) filetype = filetype.substring(0, filetype.length() - 3);
int pointIndex = filetype.lastIndexOf('.');
if (pointIndex >= 0) filetype = filetype.substring(pointIndex + 1);