From c1b36adf764b2f0e80691e60eaa081833917d1f0 Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Mon, 6 May 2019 12:54:52 +0300 Subject: [PATCH] Added support for URL parameters This means that localhost:8804/server?name=Name of the server&etc=etc is now supported. This addition will be useful when adding data endpoints for JSON data. --- .../connection/InfoRequestPageHandler.java | 6 +- .../plan/system/webserver/Request.java | 14 ++- .../plan/system/webserver/RequestHandler.java | 1 + .../plan/system/webserver/RequestTarget.java | 93 +++++++++++++++++++ .../system/webserver/ResponseHandler.java | 27 +++--- .../webserver/pages/DebugPageHandler.java | 6 +- .../system/webserver/pages/PageHandler.java | 7 +- .../webserver/pages/PlayerPageHandler.java | 6 +- .../webserver/pages/PlayersPageHandler.java | 6 +- .../webserver/pages/RootPageHandler.java | 6 +- .../webserver/pages/ServerPageHandler.java | 8 +- .../webserver/pages/TreePageHandler.java | 12 +-- 12 files changed, 145 insertions(+), 47 deletions(-) create mode 100644 Plan/common/src/main/java/com/djrapitops/plan/system/webserver/RequestTarget.java diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/info/connection/InfoRequestPageHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/info/connection/InfoRequestPageHandler.java index 65efe125d..7e5da8f27 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/info/connection/InfoRequestPageHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/info/connection/InfoRequestPageHandler.java @@ -21,6 +21,7 @@ import com.djrapitops.plan.api.exceptions.connection.WebException; import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.info.request.InfoRequest; import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.RequestTarget; import com.djrapitops.plan.system.webserver.pages.PageHandler; import com.djrapitops.plan.system.webserver.response.Response; import com.djrapitops.plan.system.webserver.response.ResponseFactory; @@ -30,7 +31,6 @@ import com.djrapitops.plugin.utilities.Verify; import javax.inject.Inject; import javax.inject.Singleton; -import java.util.List; /** * PageHandler for /info/requestclassname pages. @@ -62,7 +62,7 @@ public class InfoRequestPageHandler implements PageHandler { } @Override - public Response getResponse(Request request, List target) throws WebException { + public Response getResponse(Request request, RequestTarget target) throws WebException { int responseCode = 200; try { @@ -85,7 +85,7 @@ public class InfoRequestPageHandler implements PageHandler { responseCode = getResponseCodeFor(e); throw e; } finally { - connectionSystem.getConnectionLog().logConnectionFrom(request.getRemoteAddress(), request.getTarget(), responseCode); + connectionSystem.getConnectionLog().logConnectionFrom(request.getRemoteAddress(), request.getTargetString(), responseCode); } } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/Request.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/Request.java index 004be0f64..1ec705cf3 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/Request.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/Request.java @@ -32,7 +32,7 @@ import java.util.Optional; */ public class Request { private final String requestMethod; - private final String target; + private final String targetString; private final HttpExchange exchange; private final String remoteAddress; private final Locale locale; @@ -40,7 +40,7 @@ public class Request { public Request(HttpExchange exchange, Locale locale) { this.requestMethod = exchange.getRequestMethod(); - this.target = exchange.getRequestURI().getPath(); + this.targetString = exchange.getRequestURI().getPath(); remoteAddress = exchange.getRemoteAddress().getAddress().getHostAddress(); @@ -61,8 +61,12 @@ public class Request { return requestMethod; } - public String getTarget() { - return target; + public String getTargetString() { + return targetString; + } + + public RequestTarget getTarget() { + return new RequestTarget(targetString); } public InputStream getRequestBody() { @@ -71,7 +75,7 @@ public class Request { @Override public String toString() { - return "Request:" + requestMethod + " " + target; + return "Request:" + requestMethod + " " + targetString; } public String getRemoteAddress() { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/RequestHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/RequestHandler.java index 3a69977b6..8d7e99cbc 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/RequestHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/RequestHandler.java @@ -89,6 +89,7 @@ public class RequestHandler implements HttpHandler { public void handle(HttpExchange exchange) { Headers requestHeaders = exchange.getRequestHeaders(); Headers responseHeaders = exchange.getResponseHeaders(); + Request request = new Request(exchange, locale); request.setAuth(getAuthorization(requestHeaders)); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/RequestTarget.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/RequestTarget.java new file mode 100644 index 000000000..7fd887d73 --- /dev/null +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/RequestTarget.java @@ -0,0 +1,93 @@ +/* + * This file is part of Player Analytics (Plan). + * + * Plan is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License v3 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Plan is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Plan. If not, see . + */ +package com.djrapitops.plan.system.webserver; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Represents URI of a requested resource. + * + * @author Rsl1122 + */ +public class RequestTarget { + + private final String resourceString; + private final List resource; + private final Map parameters; + + public RequestTarget(String targetString) { + String[] resourceAndParameters = targetString.split("\\?", 2); + + resourceString = resourceAndParameters.length >= 1 ? resourceAndParameters[0] : "/"; + resource = Arrays.stream(resourceString.split("/")).filter(part -> !part.isEmpty()).collect(Collectors.toList()); + + String parameterString = resourceAndParameters.length >= 2 ? resourceAndParameters[1] : null; + parameters = parseParameters(parameterString); + } + + private Map parseParameters(String parameterString) { + if (parameterString == null || parameterString.isEmpty()) { + return Collections.emptyMap(); + } + + TreeMap parameters = new TreeMap<>(); + + String[] keysAndValues = parameterString.split("&"); + for (String kv : keysAndValues) { + if (kv.isEmpty()) { + continue; + } + String[] keyAndValue = kv.split("=", 2); + if (keyAndValue.length >= 2) { + parameters.put(keyAndValue[0], keyAndValue[1]); + } + } + + return parameters; + } + + public boolean isEmpty() { + return resource.isEmpty(); + } + + public int size() { + return resource.size(); + } + + public String get(int index) { + return resource.get(index); + } + + public void removeFirst() { + if (!isEmpty()) { + resource.remove(0); + } + } + + public boolean endsWith(String suffix) { + return resourceString.endsWith(suffix); + } + + public Optional getParameter(String key) { + return Optional.ofNullable(parameters.get(key)); + } + + public String getResourceString() { + return resourceString; + } +} \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java index 9814a9f6e..b6163515c 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java @@ -95,13 +95,13 @@ public class ResponseHandler extends TreePageHandler { } public Response getResponse(Request request) { - String targetString = request.getTarget(); + String targetString = request.getTargetString(); List target = new ArrayList<>(Arrays.asList(targetString.split("/"))); if (!target.isEmpty()) { target.remove(0); } try { - return getResponse(request, targetString, target); + return tryToGetResponse(request); } catch (NoServersException | NotFoundException e) { return responseFactory.notFound404(e.getMessage()); } catch (WebUserAuthException e) { @@ -116,32 +116,33 @@ public class ResponseHandler extends TreePageHandler { return responseFactory.gatewayError504(e.getMessage()); } catch (InternalErrorException e) { if (e.getCause() != null) { - return responseFactory.internalErrorResponse(e.getCause(), request.getTarget()); + return responseFactory.internalErrorResponse(e.getCause(), request.getTargetString()); } else { - return responseFactory.internalErrorResponse(e, request.getTarget()); + return responseFactory.internalErrorResponse(e, request.getTargetString()); } } catch (Exception e) { errorHandler.log(L.ERROR, this.getClass(), e); - return responseFactory.internalErrorResponse(e, request.getTarget()); + return responseFactory.internalErrorResponse(e, request.getTargetString()); } } - private Response getResponse(Request request, String targetString, List target) throws WebException { - Optional authentication = Optional.empty(); + private Response tryToGetResponse(Request request) throws WebException { + Optional authentication = request.getAuth(); + RequestTarget target = request.getTarget(); + String resource = target.getResourceString(); - if (targetString.endsWith(".css")) { - return ResponseCache.loadResponse(PageId.CSS.of(targetString), () -> responseFactory.cssResponse(targetString)); + if (target.endsWith(".css")) { + return ResponseCache.loadResponse(PageId.CSS.of(resource), () -> responseFactory.cssResponse(resource)); } - if (targetString.endsWith(".js")) { - return ResponseCache.loadResponse(PageId.JS.of(targetString), () -> responseFactory.javaScriptResponse(targetString)); + if (target.endsWith(".js")) { + return ResponseCache.loadResponse(PageId.JS.of(resource), () -> responseFactory.javaScriptResponse(resource)); } - if (targetString.endsWith("favicon.ico")) { + if (target.endsWith("favicon.ico")) { return ResponseCache.loadResponse(PageId.FAVICON.id(), responseFactory::faviconResponse); } boolean isNotInfoRequest = target.isEmpty() || !target.get(0).equals("info"); boolean isAuthRequired = webServer.get().isAuthRequired() && isNotInfoRequest; if (isAuthRequired) { - authentication = request.getAuth(); if (!authentication.isPresent()) { if (webServer.get().isUsingHTTPS()) { return responseFactory.basicAuth(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/DebugPageHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/DebugPageHandler.java index 456da2367..181a38a20 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/DebugPageHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/DebugPageHandler.java @@ -19,13 +19,13 @@ package com.djrapitops.plan.system.webserver.pages; import com.djrapitops.plan.api.exceptions.WebUserAuthException; import com.djrapitops.plan.data.WebUser; import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.RequestTarget; import com.djrapitops.plan.system.webserver.auth.Authentication; import com.djrapitops.plan.system.webserver.response.Response; import com.djrapitops.plan.system.webserver.response.ResponseFactory; import javax.inject.Inject; import javax.inject.Singleton; -import java.util.List; /** * PageHandler for /debug page. @@ -43,12 +43,12 @@ public class DebugPageHandler implements PageHandler { } @Override - public Response getResponse(Request request, List target) { + public Response getResponse(Request request, RequestTarget target) { return responseFactory.debugPageResponse(); } @Override - public boolean isAuthorized(Authentication auth, List target) throws WebUserAuthException { + public boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException { WebUser webUser = auth.getWebUser(); return webUser.getPermLevel() <= 0; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PageHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PageHandler.java index 4c74b4feb..f76cf881a 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PageHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PageHandler.java @@ -19,11 +19,10 @@ package com.djrapitops.plan.system.webserver.pages; import com.djrapitops.plan.api.exceptions.WebUserAuthException; import com.djrapitops.plan.api.exceptions.connection.WebException; import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.RequestTarget; import com.djrapitops.plan.system.webserver.auth.Authentication; import com.djrapitops.plan.system.webserver.response.Response; -import java.util.List; - /** * PageHandlers are used for easier Response management and authorization checking. * @@ -38,9 +37,9 @@ public interface PageHandler { * @param target Rest of the target coordinates after this page has been solved. * @return Response appropriate to the PageHandler. */ - Response getResponse(Request request, List target) throws WebException; + Response getResponse(Request request, RequestTarget target) throws WebException; - default boolean isAuthorized(Authentication auth, List target) throws WebUserAuthException { + default boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException { return true; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayerPageHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayerPageHandler.java index aadb7c59f..0d449836e 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayerPageHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayerPageHandler.java @@ -26,6 +26,7 @@ import com.djrapitops.plan.db.access.queries.PlayerFetchQueries; import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.info.InfoSystem; import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.RequestTarget; import com.djrapitops.plan.system.webserver.auth.Authentication; import com.djrapitops.plan.system.webserver.cache.PageId; import com.djrapitops.plan.system.webserver.cache.ResponseCache; @@ -36,7 +37,6 @@ import com.djrapitops.plan.utilities.uuid.UUIDUtility; import javax.inject.Inject; import javax.inject.Singleton; -import java.util.List; import java.util.UUID; /** @@ -66,7 +66,7 @@ public class PlayerPageHandler implements PageHandler { } @Override - public Response getResponse(Request request, List target) throws WebException { + public Response getResponse(Request request, RequestTarget target) throws WebException { if (target.isEmpty()) { return responseFactory.pageNotFound404(); } @@ -109,7 +109,7 @@ public class PlayerPageHandler implements PageHandler { } @Override - public boolean isAuthorized(Authentication auth, List target) throws WebUserAuthException { + public boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException { WebUser webUser = auth.getWebUser(); return webUser.getPermLevel() <= 1 || webUser.getName().equalsIgnoreCase(target.get(target.size() - 1)); } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayersPageHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayersPageHandler.java index 64c7acc4c..d1be11287 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayersPageHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/PlayersPageHandler.java @@ -22,6 +22,7 @@ import com.djrapitops.plan.api.exceptions.connection.WebException; import com.djrapitops.plan.db.Database; import com.djrapitops.plan.system.database.DBSystem; import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.RequestTarget; import com.djrapitops.plan.system.webserver.auth.Authentication; import com.djrapitops.plan.system.webserver.cache.PageId; import com.djrapitops.plan.system.webserver.cache.ResponseCache; @@ -30,7 +31,6 @@ import com.djrapitops.plan.system.webserver.response.ResponseFactory; import javax.inject.Inject; import javax.inject.Singleton; -import java.util.List; /** * PageHandler for /players page. @@ -53,7 +53,7 @@ public class PlayersPageHandler implements PageHandler { } @Override - public Response getResponse(Request request, List target) throws WebException { + public Response getResponse(Request request, RequestTarget target) throws WebException { Database.State dbState = dbSystem.getDatabase().getState(); if (dbState != Database.State.OPEN) { throw new ForbiddenException("Database is " + dbState.name() + " - Please try again later. You can check database status with /plan info"); @@ -62,7 +62,7 @@ public class PlayersPageHandler implements PageHandler { } @Override - public boolean isAuthorized(Authentication auth, List target) throws WebUserAuthException { + public boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException { return auth.getWebUser().getPermLevel() <= 1; } } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/RootPageHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/RootPageHandler.java index 0391d2c72..47052fa27 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/RootPageHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/RootPageHandler.java @@ -19,12 +19,12 @@ package com.djrapitops.plan.system.webserver.pages; import com.djrapitops.plan.api.exceptions.connection.WebException; import com.djrapitops.plan.data.WebUser; import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.RequestTarget; import com.djrapitops.plan.system.webserver.auth.Authentication; import com.djrapitops.plan.system.webserver.response.RedirectResponse; import com.djrapitops.plan.system.webserver.response.Response; import com.djrapitops.plan.system.webserver.response.ResponseFactory; -import java.util.List; import java.util.Optional; /** @@ -43,7 +43,7 @@ public class RootPageHandler implements PageHandler { } @Override - public Response getResponse(Request request, List target) throws WebException { + public Response getResponse(Request request, RequestTarget target) throws WebException { Optional auth = request.getAuth(); if (!auth.isPresent()) { return responseFactory.basicAuth(); @@ -65,7 +65,7 @@ public class RootPageHandler implements PageHandler { } @Override - public boolean isAuthorized(Authentication auth, List target) { + public boolean isAuthorized(Authentication auth, RequestTarget target) { return true; } } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/ServerPageHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/ServerPageHandler.java index a2219ef48..b947bdbf1 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/ServerPageHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/ServerPageHandler.java @@ -29,6 +29,7 @@ import com.djrapitops.plan.system.info.server.Server; import com.djrapitops.plan.system.info.server.ServerInfo; import com.djrapitops.plan.system.processing.Processing; import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.RequestTarget; import com.djrapitops.plan.system.webserver.auth.Authentication; import com.djrapitops.plan.system.webserver.cache.PageId; import com.djrapitops.plan.system.webserver.cache.ResponseCache; @@ -37,7 +38,6 @@ import com.djrapitops.plan.system.webserver.response.ResponseFactory; import javax.inject.Inject; import javax.inject.Singleton; -import java.util.List; import java.util.Optional; import java.util.UUID; @@ -71,7 +71,7 @@ public class ServerPageHandler implements PageHandler { } @Override - public Response getResponse(Request request, List target) throws WebException { + public Response getResponse(Request request, RequestTarget target) throws WebException { UUID serverUUID = getServerUUID(target); boolean raw = target.size() >= 2 && target.get(1).equalsIgnoreCase("raw"); @@ -114,7 +114,7 @@ public class ServerPageHandler implements PageHandler { return responseFactory.refreshingAnalysisResponse(); } - private UUID getServerUUID(List target) { + private UUID getServerUUID(RequestTarget target) { // Default to current server's page UUID serverUUID = serverInfo.getServerUUID(); @@ -135,7 +135,7 @@ public class ServerPageHandler implements PageHandler { } @Override - public boolean isAuthorized(Authentication auth, List target) throws WebUserAuthException { + public boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException { return auth.getWebUser().getPermLevel() <= 0; } } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/TreePageHandler.java b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/TreePageHandler.java index 3f2bd655a..f082456ba 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/TreePageHandler.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/webserver/pages/TreePageHandler.java @@ -19,12 +19,12 @@ package com.djrapitops.plan.system.webserver.pages; import com.djrapitops.plan.api.exceptions.WebUserAuthException; import com.djrapitops.plan.api.exceptions.connection.WebException; import com.djrapitops.plan.system.webserver.Request; +import com.djrapitops.plan.system.webserver.RequestTarget; import com.djrapitops.plan.system.webserver.auth.Authentication; import com.djrapitops.plan.system.webserver.response.Response; import com.djrapitops.plan.system.webserver.response.ResponseFactory; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -50,31 +50,31 @@ public abstract class TreePageHandler implements PageHandler { public void registerPage(String targetPage, Response response, int requiredPerm) { pages.put(targetPage, new PageHandler() { @Override - public Response getResponse(Request request, List target) { + public Response getResponse(Request request, RequestTarget target) { return response; } @Override - public boolean isAuthorized(Authentication auth, List target) throws WebUserAuthException { + public boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException { return auth.getWebUser().getPermLevel() <= requiredPerm; } }); } @Override - public Response getResponse(Request request, List target) throws WebException { + public Response getResponse(Request request, RequestTarget target) throws WebException { PageHandler pageHandler = getPageHandler(target); return pageHandler != null ? pageHandler.getResponse(request, target) : responseFactory.pageNotFound404(); } - public PageHandler getPageHandler(List target) { + public PageHandler getPageHandler(RequestTarget target) { if (target.isEmpty()) { return pages.get(""); } String targetPage = target.get(0); - target.remove(0); + target.removeFirst(); return pages.get(targetPage); }