From 5892a14234dcbe1de169d4f767ca1d452cac0891 Mon Sep 17 00:00:00 2001 From: JanHolger Date: Fri, 7 Oct 2022 23:06:58 +0200 Subject: [PATCH 01/24] Incremented version --- README.md | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b7d54a3..96c0388 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,6 @@ work-in-progress project though so it's not yet complete. org.javawebstack http-server - 1.0.2 + 1.0.3 ``` \ No newline at end of file diff --git a/pom.xml b/pom.xml index ecab3e2..97fd7b4 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ 8 8 - 1.0.2-SNAPSHOT + 1.0.3-SNAPSHOT org.javawebstack From ff30c0d7ff7e6d67e187bbd58986ae8ce5e3d1bf Mon Sep 17 00:00:00 2001 From: JanHolger Date: Mon, 10 Oct 2022 17:00:00 +0200 Subject: [PATCH 02/24] Hotfix for formMethod --- src/main/java/org/javawebstack/httpserver/Exchange.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/javawebstack/httpserver/Exchange.java b/src/main/java/org/javawebstack/httpserver/Exchange.java index c29e568..d249b03 100644 --- a/src/main/java/org/javawebstack/httpserver/Exchange.java +++ b/src/main/java/org/javawebstack/httpserver/Exchange.java @@ -291,9 +291,12 @@ private HTTPMethod getRequestMethodFromSocket(IHTTPSocket socket) { if ("websocket".equalsIgnoreCase(socket.getRequestHeader("upgrade"))) return HTTPMethod.WEBSOCKET; if (server.isFormMethods() && (socket.getRequestMethod() == HTTPMethod.GET || socket.getRequestMethod() == HTTPMethod.POST) && getMimeType() == MimeType.X_WWW_FORM_URLENCODED) { - String rawMethodOverride = getBodyPathElement("_method").string(); - if (rawMethodOverride != null) - return HTTPMethod.valueOf(rawMethodOverride); + AbstractElement e = getBodyPathElement("_method"); + if (e != null) { + try { + return HTTPMethod.valueOf(e.string()); + } catch (IllegalArgumentException ignored) {} + } } return socket.getRequestMethod(); } From cc28a1b1083750f5b2fc38dd10aa83e45daa5a6c Mon Sep 17 00:00:00 2001 From: Jake Esser Date: Tue, 24 Jan 2023 12:16:23 +0100 Subject: [PATCH 03/24] Added null filtering to methods --- .../java/org/javawebstack/httpserver/router/RouteBinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/javawebstack/httpserver/router/RouteBinder.java b/src/main/java/org/javawebstack/httpserver/router/RouteBinder.java index e8eb2eb..357f60e 100644 --- a/src/main/java/org/javawebstack/httpserver/router/RouteBinder.java +++ b/src/main/java/org/javawebstack/httpserver/router/RouteBinder.java @@ -187,7 +187,7 @@ private static List getMethodsRecursive(Class type) { List methods = new ArrayList<>(Arrays.asList(type.getDeclaredMethods())); if (type.getSuperclass() != null && type.getSuperclass() != Object.class) methods.addAll(getMethodsRecursive(type.getSuperclass())); - return methods; + return methods.stream().filter(Objects::nonNull).collect(Collectors.toList()); } private static class BindMapper { From 8fd050d6a4fb3e385a09a9747bf4a1e65bc8488e Mon Sep 17 00:00:00 2001 From: Jake Esser Date: Thu, 30 Mar 2023 23:07:51 +0200 Subject: [PATCH 04/24] Try to fix Websocket timing issues --- .../util/websocket/WebSocketFrame.java | 64 ++++++++++--------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java b/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java index c0948d4..0efddd6 100644 --- a/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java +++ b/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java @@ -74,7 +74,7 @@ public WebSocketFrame setPayload(byte[] payload) { return this; } - public void write(OutputStream stream) throws IOException { + public synchronized void write(OutputStream stream) throws IOException { stream.write(flags | opcode); int lengthByte = payload.length > 125 ? (payload.length > 0xFFFF ? 127 : 126) : payload.length; stream.write((maskKey != null ? 0b1000_0000 : 0) | lengthByte); @@ -97,37 +97,39 @@ public void write(OutputStream stream) throws IOException { } public static WebSocketFrame read(InputStream stream) throws IOException { - WebSocketFrame frame = new WebSocketFrame(); - byte b = safeRead(stream); - frame.flags = (byte) (b & 0xF0); - frame.opcode = (byte) (b & 0x0F); - b = safeRead(stream); - frame.maskKey = ((b & 0xFF) >> 7) == 1 ? new byte[4] : null; - int len = b & 0b0111_1111; - if(len == 126) { - len = safeRead(stream) << 8; - len |= safeRead(stream); - } else if(len == 127) { - len = safeRead(stream) << 24; - len |= safeRead(stream) << 16; - len |= safeRead(stream) << 8; - len |= safeRead(stream); + synchronized (stream) { + WebSocketFrame frame = new WebSocketFrame(); + byte b = safeRead(stream); + frame.flags = (byte) (b & 0xF0); + frame.opcode = (byte) (b & 0x0F); + b = safeRead(stream); + frame.maskKey = ((b & 0xFF) >> 7) == 1 ? new byte[4] : null; + int len = b & 0b0111_1111; + if(len == 126) { + len = safeRead(stream) << 8; + len |= safeRead(stream); + } else if(len == 127) { + len = safeRead(stream) << 24; + len |= safeRead(stream) << 16; + len |= safeRead(stream) << 8; + len |= safeRead(stream); + } + if(frame.maskKey != null) { + frame.maskKey[0] = safeRead(stream); + frame.maskKey[1] = safeRead(stream); + frame.maskKey[2] = safeRead(stream); + frame.maskKey[3] = safeRead(stream); + } + frame.payload = new byte[len]; + if(frame.maskKey != null) { + for(int i=0; i Date: Thu, 30 Mar 2023 23:35:13 +0200 Subject: [PATCH 05/24] Removed synchronized from write method --- .../javawebstack/httpserver/util/websocket/WebSocketFrame.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java b/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java index 0efddd6..0b9dbb9 100644 --- a/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java +++ b/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java @@ -74,7 +74,7 @@ public WebSocketFrame setPayload(byte[] payload) { return this; } - public synchronized void write(OutputStream stream) throws IOException { + public void write(OutputStream stream) throws IOException { stream.write(flags | opcode); int lengthByte = payload.length > 125 ? (payload.length > 0xFFFF ? 127 : 126) : payload.length; stream.write((maskKey != null ? 0b1000_0000 : 0) | lengthByte); From 4aab54320cbf035c57fdd54c7069a9115aaf378b Mon Sep 17 00:00:00 2001 From: Jake Esser Date: Thu, 30 Mar 2023 23:54:34 +0200 Subject: [PATCH 06/24] Revert "Removed synchronized from write method" This reverts commit e8da70da9fc3913a07e734f1acb3c7fe9c2cc7a2. --- .../javawebstack/httpserver/util/websocket/WebSocketFrame.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java b/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java index 0b9dbb9..0efddd6 100644 --- a/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java +++ b/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java @@ -74,7 +74,7 @@ public WebSocketFrame setPayload(byte[] payload) { return this; } - public void write(OutputStream stream) throws IOException { + public synchronized void write(OutputStream stream) throws IOException { stream.write(flags | opcode); int lengthByte = payload.length > 125 ? (payload.length > 0xFFFF ? 127 : 126) : payload.length; stream.write((maskKey != null ? 0b1000_0000 : 0) | lengthByte); From e45ae01a3e022c0b5734b88a639b7329080336a5 Mon Sep 17 00:00:00 2001 From: Jake Esser Date: Fri, 31 Mar 2023 00:56:48 +0200 Subject: [PATCH 07/24] Added error handling in case of an IOException --- .../websocket/InternalWebSocketRequestHandler.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/javawebstack/httpserver/websocket/InternalWebSocketRequestHandler.java b/src/main/java/org/javawebstack/httpserver/websocket/InternalWebSocketRequestHandler.java index 99831de..8a70253 100644 --- a/src/main/java/org/javawebstack/httpserver/websocket/InternalWebSocketRequestHandler.java +++ b/src/main/java/org/javawebstack/httpserver/websocket/InternalWebSocketRequestHandler.java @@ -20,8 +20,8 @@ public InternalWebSocketRequestHandler(WebSocketHandler handler) { public Object handle(Exchange exchange) { IHTTPSocket socket = exchange.socket(); + WebSocket webSocket = new WebSocket(exchange); try { - WebSocket webSocket = new WebSocket(exchange); handler.onConnect(webSocket); WebSocketFrame frame; while (true) { @@ -48,10 +48,17 @@ public Object handle(Exchange exchange) { } if(frame.getOpcode() == WebSocketUtil.OP_TEXT) { handler.onMessage(webSocket, new String(frame.getPayload(), StandardCharsets.UTF_8)); - continue; } } - } catch (IOException ignored) {} + } catch (IOException e) { + handler.onClose(webSocket, null, null); + try { + socket.close(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + throw new RuntimeException(e); + } return null; } } From 8c0b7a66c4d4b12b4f7010e81aa55c8e4be2ced1 Mon Sep 17 00:00:00 2001 From: Jake Esser Date: Mon, 22 May 2023 08:57:33 +0200 Subject: [PATCH 08/24] Fixed ArrayIndexOutOfBoundsException in MimeType.byFileName --- src/main/java/org/javawebstack/httpserver/util/MimeType.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/javawebstack/httpserver/util/MimeType.java b/src/main/java/org/javawebstack/httpserver/util/MimeType.java index 3703170..2293582 100644 --- a/src/main/java/org/javawebstack/httpserver/util/MimeType.java +++ b/src/main/java/org/javawebstack/httpserver/util/MimeType.java @@ -68,6 +68,8 @@ public static MimeType byMimeType(String mimeType) { public static MimeType byFileName(String fileName) { if (fileName.contains("/")) { String[] spl = fileName.split("/"); + if (spl.length == 0) + return PLAIN; fileName = spl[spl.length - 1]; } if (!fileName.contains(".")) From 684a331f584007ecb562fcbfa7887cee239f1ede Mon Sep 17 00:00:00 2001 From: JanHolger Date: Sun, 3 Sep 2023 20:52:21 +0200 Subject: [PATCH 09/24] Fixed TestHTTPSocket headers and incremented dependency versions --- pom.xml | 13 ++----- .../httpserver/adapter/IHTTPSocket.java | 7 +++- .../httpserver/test/TestHTTPSocket.java | 35 +++++++++++-------- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/pom.xml b/pom.xml index 97fd7b4..f6a69f4 100644 --- a/pom.xml +++ b/pom.xml @@ -60,24 +60,17 @@ org.junit.jupiter junit-jupiter-api - 5.9.0 + 5.10.0 io.undertow undertow-core - 2.2.19.Final + 2.3.8.Final - - - org.jboss.xnio - xnio-api - 3.8.8.Final - - org.junit.jupiter junit-jupiter-engine - 5.9.0 + 5.10.0 test diff --git a/src/main/java/org/javawebstack/httpserver/adapter/IHTTPSocket.java b/src/main/java/org/javawebstack/httpserver/adapter/IHTTPSocket.java index bf4bc33..af47269 100644 --- a/src/main/java/org/javawebstack/httpserver/adapter/IHTTPSocket.java +++ b/src/main/java/org/javawebstack/httpserver/adapter/IHTTPSocket.java @@ -43,7 +43,12 @@ default IHTTPSocket setResponseStatus(int status) { Set getRequestHeaderNames(); - String getRequestHeader(String name); + default String getRequestHeader(String name) { + List headers = getRequestHeaders(name); + if(headers == null || headers.size() == 0) + return null; + return headers.get(0); + } List getRequestHeaders(String name); diff --git a/src/main/java/org/javawebstack/httpserver/test/TestHTTPSocket.java b/src/main/java/org/javawebstack/httpserver/test/TestHTTPSocket.java index 5dc1a70..2ac8b68 100644 --- a/src/main/java/org/javawebstack/httpserver/test/TestHTTPSocket.java +++ b/src/main/java/org/javawebstack/httpserver/test/TestHTTPSocket.java @@ -19,15 +19,11 @@ public class TestHTTPSocket implements IHTTPSocket { private final Map> requestHeaders = new HashMap<>(); private final Map> responseHeaders = new HashMap<>(); - public Map> getRequestHeaders() { - return requestHeaders; - } - - public Map> getResponseHeaders() { - return responseHeaders; + public TestHTTPSocket(HTTPMethod method, String url) { + this(method, url, null); } - public TestHTTPSocket(HTTPMethod method, String url) { + public TestHTTPSocket(HTTPMethod method, String url, Map headers) { this.requestMethod = method; String[] pathSplit = url.split("\\?", 2); requestPath = pathSplit[0]; @@ -35,6 +31,21 @@ public TestHTTPSocket(HTTPMethod method, String url) { requestQuery = pathSplit[1]; else requestQuery = null; + if(headers != null) { + headers.entrySet().forEach(e -> { + List list = new ArrayList<>(); + list.add(e.getValue()); + this.requestHeaders.put(e.getKey(), list); + }); + } + } + + public Map> getRequestHeaders() { + return requestHeaders; + } + + public Map> getResponseHeaders() { + return responseHeaders; } public TestHTTPSocket setInputStream(InputStream inputStream) { @@ -91,15 +102,11 @@ public String getRequestVersion() { } public Set getRequestHeaderNames() { - return Collections.emptySet(); - } - - public String getRequestHeader(String name) { - return null; + return requestHeaders.keySet(); } public List getRequestHeaders(String name) { - return null; + return requestHeaders.get(name); } public int getResponseStatus() { @@ -115,7 +122,7 @@ public void writeHeaders() throws IOException { } public String getRemoteAddress() { - return null; + return "127.0.0.1"; } } From 1c786d06f21c2d63f27fe24444ddcb307a2cff1b Mon Sep 17 00:00:00 2001 From: JanHolger Date: Sun, 3 Sep 2023 21:23:44 +0200 Subject: [PATCH 10/24] Moved undertow to a separate repository and removed HTTPServer's empty constructor --- pom.xml | 5 - .../javawebstack/httpserver/HTTPServer.java | 6 +- .../undertow/StreamSinkOutputStream.java | 29 ---- .../undertow/StreamSourceInputStream.java | 29 ---- .../adapter/undertow/UndertowHTTPSocket.java | 132 ------------------ .../undertow/UndertowHTTPSocketServer.java | 80 ----------- 6 files changed, 1 insertion(+), 280 deletions(-) delete mode 100644 src/main/java/org/javawebstack/httpserver/adapter/undertow/StreamSinkOutputStream.java delete mode 100644 src/main/java/org/javawebstack/httpserver/adapter/undertow/StreamSourceInputStream.java delete mode 100644 src/main/java/org/javawebstack/httpserver/adapter/undertow/UndertowHTTPSocket.java delete mode 100644 src/main/java/org/javawebstack/httpserver/adapter/undertow/UndertowHTTPSocketServer.java diff --git a/pom.xml b/pom.xml index f6a69f4..3ad7423 100644 --- a/pom.xml +++ b/pom.xml @@ -62,11 +62,6 @@ junit-jupiter-api 5.10.0 - - io.undertow - undertow-core - 2.3.8.Final - org.junit.jupiter junit-jupiter-engine diff --git a/src/main/java/org/javawebstack/httpserver/HTTPServer.java b/src/main/java/org/javawebstack/httpserver/HTTPServer.java index c3ee9b8..ffa5e4c 100644 --- a/src/main/java/org/javawebstack/httpserver/HTTPServer.java +++ b/src/main/java/org/javawebstack/httpserver/HTTPServer.java @@ -3,7 +3,6 @@ import org.javawebstack.abstractdata.AbstractMapper; import org.javawebstack.abstractdata.NamingPolicy; import org.javawebstack.httpserver.adapter.IHTTPSocketServer; -import org.javawebstack.httpserver.adapter.undertow.UndertowHTTPSocketServer; import org.javawebstack.httpserver.handler.*; import org.javawebstack.httpserver.router.DefaultRouteAutoInjector; import org.javawebstack.httpserver.router.Route; @@ -45,10 +44,6 @@ public class HTTPServer implements RouteParamTransformerProvider { private Function, Object> controllerInitiator = this::defaultControllerInitiator; private boolean formMethods = true; - public HTTPServer() { - this(new UndertowHTTPSocketServer()); - } - public HTTPServer(IHTTPSocketServer server) { this.server = server; routeParamTransformers.add(DefaultRouteParamTransformer.INSTANCE); @@ -424,4 +419,5 @@ public HTTPServer disableFormMethods() { formMethods = false; return this; } + } diff --git a/src/main/java/org/javawebstack/httpserver/adapter/undertow/StreamSinkOutputStream.java b/src/main/java/org/javawebstack/httpserver/adapter/undertow/StreamSinkOutputStream.java deleted file mode 100644 index 56fcb2b..0000000 --- a/src/main/java/org/javawebstack/httpserver/adapter/undertow/StreamSinkOutputStream.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.javawebstack.httpserver.adapter.undertow; - -import org.xnio.channels.StreamSinkChannel; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; - -public class StreamSinkOutputStream extends OutputStream { - - private final StreamSinkChannel sink; - private final ByteBuffer byteBuffer = ByteBuffer.allocate(1); - - public StreamSinkOutputStream(StreamSinkChannel sink) { - this.sink = sink; - } - - public void write(int i) throws IOException { - byteBuffer.position(0); - byteBuffer.put((byte) i); - byteBuffer.position(0); - sink.write(byteBuffer); - } - - public void close() throws IOException { - sink.close(); - } - -} diff --git a/src/main/java/org/javawebstack/httpserver/adapter/undertow/StreamSourceInputStream.java b/src/main/java/org/javawebstack/httpserver/adapter/undertow/StreamSourceInputStream.java deleted file mode 100644 index 79ffba5..0000000 --- a/src/main/java/org/javawebstack/httpserver/adapter/undertow/StreamSourceInputStream.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.javawebstack.httpserver.adapter.undertow; - -import org.xnio.channels.StreamSourceChannel; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; - -public class StreamSourceInputStream extends InputStream { - - private final StreamSourceChannel source; - private final ByteBuffer byteBuffer = ByteBuffer.allocate(1); - - public StreamSourceInputStream(StreamSourceChannel source) { - this.source = source; - } - - public synchronized int read() throws IOException { - byteBuffer.position(0); - int r; - while ((r = source.read(byteBuffer)) == 0) - Thread.yield(); - if(r == -1) - return -1; - byteBuffer.position(0); - return byteBuffer.get(); - } - -} diff --git a/src/main/java/org/javawebstack/httpserver/adapter/undertow/UndertowHTTPSocket.java b/src/main/java/org/javawebstack/httpserver/adapter/undertow/UndertowHTTPSocket.java deleted file mode 100644 index 356b513..0000000 --- a/src/main/java/org/javawebstack/httpserver/adapter/undertow/UndertowHTTPSocket.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.javawebstack.httpserver.adapter.undertow; - -import io.undertow.server.HttpServerExchange; -import io.undertow.util.HeaderValues; -import io.undertow.util.HttpString; -import org.javawebstack.httpserver.HTTPMethod; -import org.javawebstack.httpserver.HTTPStatus; -import org.javawebstack.httpserver.adapter.IHTTPSocket; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.*; -import java.util.stream.Collectors; - -public class UndertowHTTPSocket implements IHTTPSocket { - - private final HttpServerExchange exchange; - private final InputStream inputStream; - private final OutputStream outputStream; - private boolean closed; - - public UndertowHTTPSocket(HttpServerExchange exchange, InputStream inputStream, OutputStream outputStream) { - this.exchange = exchange; - InputStream is = inputStream == null ? exchange.getInputStream() : inputStream; - this.inputStream = new InputStream() { - public int read() throws IOException { - return is.read(); - } - public int available() throws IOException { - int a = is.available(); - if(a == 0 && !exchange.isRequestComplete()) - a = 1; - return a; - } - }; - this.outputStream = outputStream == null ? exchange.getOutputStream() : outputStream; - } - - public InputStream getInputStream() throws IOException { - return inputStream; - } - - public OutputStream getOutputStream() throws IOException { - return outputStream; - } - - public void close() throws IOException { - if(closed) - return; - closed = true; - exchange.getOutputStream().close(); - } - - public boolean isClosed() { - return exchange.isComplete(); - } - - public IHTTPSocket setResponseStatus(int status, String message) { - if(!exchange.isResponseStarted()) - exchange.setStatusCode(status); - return this; - } - - public IHTTPSocket setResponseHeader(String name, String value) { - exchange.getResponseHeaders().put(new HttpString(name), value); - return this; - } - - public IHTTPSocket addResponseHeader(String name, String value) { - exchange.getResponseHeaders().add(new HttpString(name), value); - return this; - } - - public HTTPMethod getRequestMethod() { - return HTTPMethod.valueOf(exchange.getRequestMethod().toString()); - } - - public String getRequestPath() { - return exchange.getRequestPath(); - } - - public String getRequestQuery() { - return exchange.getQueryString(); - } - - public String getRequestVersion() { - return exchange.getProtocol().toString(); - } - - public Set getRequestHeaderNames() { - return exchange.getRequestHeaders().getHeaderNames().stream().map(HttpString::toString).collect(Collectors.toSet()); - } - - public String getRequestHeader(String name) { - HeaderValues values = exchange.getRequestHeaders().get(name); - if(values == null) - return null; - return values.getFirst(); - } - - public List getRequestHeaders(String name) { - HeaderValues values = exchange.getRequestHeaders().get(name); - if(values == null) - return Collections.emptyList(); - return new ArrayList<>(values); - } - - public int getResponseStatus() { - return exchange.getStatusCode(); - } - - public String getResponseStatusMessage() { - HTTPStatus status = HTTPStatus.byStatus(getResponseStatus()); - if(status == null) - return null; - return status.getMessage(); - } - - public void writeHeaders() throws IOException { - exchange.getOutputStream().write(new byte[0]); - } - - public String getRemoteAddress() { - return exchange.getSourceAddress().getAddress().getHostAddress(); - } - - public HttpServerExchange getExchange() { - return exchange; - } - -} diff --git a/src/main/java/org/javawebstack/httpserver/adapter/undertow/UndertowHTTPSocketServer.java b/src/main/java/org/javawebstack/httpserver/adapter/undertow/UndertowHTTPSocketServer.java deleted file mode 100644 index 178d0d2..0000000 --- a/src/main/java/org/javawebstack/httpserver/adapter/undertow/UndertowHTTPSocketServer.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.javawebstack.httpserver.adapter.undertow; - -import io.undertow.Undertow; -import io.undertow.server.handlers.BlockingHandler; -import io.undertow.websockets.core.WebSocketVersion; -import org.javawebstack.httpserver.adapter.IHTTPSocketHandler; -import org.javawebstack.httpserver.adapter.IHTTPSocketServer; -import org.javawebstack.httpserver.util.websocket.WebSocketUtil; -import org.xnio.Options; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.concurrent.*; - -public class UndertowHTTPSocketServer implements IHTTPSocketServer { - - private int port = 80; - private int maxThreads = 64; - private Undertow server; - private IHTTPSocketHandler handler; - private ExecutorService executorService; - - public void setPort(int port) { - this.port = port; - } - - public int getPort() { - return port; - } - - public void start() throws IOException { - executorService = new ThreadPoolExecutor(1, maxThreads, 60L, TimeUnit.SECONDS, new SynchronousQueue()); - server = Undertow.builder() - .addHttpListener(port, "0.0.0.0") - .setServerOption(Options.KEEP_ALIVE, true) - .setHandler(new BlockingHandler(httpServerExchange -> { - httpServerExchange.setDispatchExecutor(executorService); - if(httpServerExchange.getRequestHeaders().contains("sec-websocket-key")) { - httpServerExchange.upgradeChannel((streamConnection, httpServerExchange1) -> { - InputStream inputStream = new StreamSourceInputStream(streamConnection.getSourceChannel()); - OutputStream outputStream = new StreamSinkOutputStream(streamConnection.getSinkChannel()); - handler.handle(new UndertowHTTPSocket(httpServerExchange1, inputStream, outputStream)); - }); - httpServerExchange.putAttachment(WebSocketVersion.ATTACHMENT_KEY, WebSocketVersion.V13); - if(!WebSocketUtil.accept(new UndertowHTTPSocket(httpServerExchange, null, null), null)) - return; - httpServerExchange.endExchange(); - } else { - handler.handle(new UndertowHTTPSocket(httpServerExchange, null, null)); - } - })) - .build(); - server.start(); - } - - public void stop() { - executorService.shutdown(); - server.stop(); - } - - public void join() { - try { - server.getWorker().awaitTermination(); - } catch (InterruptedException e) {} - } - - public void setHandler(IHTTPSocketHandler handler) { - this.handler = handler; - } - - public void setMaxThreads(int maxThreads) { - this.maxThreads = maxThreads; - } - - public boolean isWebSocketSupported() { - return true; - } - -} From 3176ee91bc1ef35d67ca2b4f8602bdde14829b0f Mon Sep 17 00:00:00 2001 From: JanHolger Date: Sun, 3 Sep 2023 22:01:59 +0200 Subject: [PATCH 11/24] Moved simple implementation and testing to separate repositories and updated the description --- README.md | 2 +- pom.xml | 13 +- .../adapter/simple/SimpleHTTPSocket.java | 195 ------------ .../simple/SimpleHTTPSocketServer.java | 82 ----- .../httpserver/test/HTTPTest.java | 79 ----- .../httpserver/test/TestExchange.java | 290 ------------------ .../httpserver/test/TestHTTPSocket.java | 128 -------- 7 files changed, 2 insertions(+), 787 deletions(-) delete mode 100644 src/main/java/org/javawebstack/httpserver/adapter/simple/SimpleHTTPSocket.java delete mode 100644 src/main/java/org/javawebstack/httpserver/adapter/simple/SimpleHTTPSocketServer.java delete mode 100644 src/main/java/org/javawebstack/httpserver/test/HTTPTest.java delete mode 100644 src/main/java/org/javawebstack/httpserver/test/TestExchange.java delete mode 100644 src/main/java/org/javawebstack/httpserver/test/TestHTTPSocket.java diff --git a/README.md b/README.md index 96c0388..6fea1c5 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ JWS HTTP Routing Library ## Introduction -This library provides a routing and request mapping stack on top of the well known and industry proven eclipse jetty http server. It also supports websockets. +This library provides an http routing and request mapping stack ## Documentation diff --git a/pom.xml b/pom.xml index 3ad7423..5bd8deb 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ ${buildVersion} http-server - This library provides a routing and request mapping stack on top of the well known and industry proven eclipse jetty http server. It also supports websockets. + This library provides an http routing and request mapping stack https://github.com/JavaWebStack/http-server @@ -57,17 +57,6 @@ reflections 0.10.2 - - org.junit.jupiter - junit-jupiter-api - 5.10.0 - - - org.junit.jupiter - junit-jupiter-engine - 5.10.0 - test - diff --git a/src/main/java/org/javawebstack/httpserver/adapter/simple/SimpleHTTPSocket.java b/src/main/java/org/javawebstack/httpserver/adapter/simple/SimpleHTTPSocket.java deleted file mode 100644 index 6d9ad27..0000000 --- a/src/main/java/org/javawebstack/httpserver/adapter/simple/SimpleHTTPSocket.java +++ /dev/null @@ -1,195 +0,0 @@ -package org.javawebstack.httpserver.adapter.simple; - -import org.javawebstack.httpserver.HTTPMethod; -import org.javawebstack.httpserver.HTTPStatus; -import org.javawebstack.httpserver.adapter.IHTTPSocket; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; -import java.nio.charset.StandardCharsets; -import java.util.*; - -public class SimpleHTTPSocket implements IHTTPSocket { - - private final Socket socket; - private final InputStream inputStream; - private final OutputStream outputStream; - private final HTTPMethod requestMethod; - private final String requestPath; - private String requestQuery; - private final String requestVersion; - private final Map> requestHeaders = new HashMap<>(); - private final Map> responseHeaders = new LinkedHashMap<>(); - private int responseStatus = 200; - private String responseStatusMessage = "OK"; - private boolean headersSent; - - public SimpleHTTPSocket(Socket socket) throws IOException { - this.socket = socket; - this.inputStream = socket.getInputStream(); - this.outputStream = socket.getOutputStream(); - socket.getOutputStream().flush(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - int lb = -1; - while (true) { - int b = inputStream.read(); - if(b == -1) { - socket.close(); - throw new IOException("Unexpected end of stream"); - } - if(b == '\r' && lb == '\n') { - b = inputStream.read(); - break; - } - baos.write(b); - lb = b; - } - String[] lines = new String(baos.toByteArray(), StandardCharsets.UTF_8).split("\\r?\\n"); - if(lines.length < 2) { - socket.close(); - throw new IOException("Invalid http request"); - } - String[] first = lines[0].split(" "); - if(first.length != 3 || !first[1].startsWith("/")) { - socket.close(); - throw new IOException("Invalid http request"); - } - requestMethod = HTTPMethod.valueOf(first[0]); - String[] pathSplit = first[1].split("\\?", 2); - requestPath = pathSplit[0]; - if(pathSplit.length == 2) - requestQuery = pathSplit[1]; - requestVersion = first[2]; - if(!requestVersion.equals("HTTP/1.1") && !requestVersion.equals("HTTP/1.0")) { - setResponseStatus(HTTPStatus.HTTP_VERSION_NOT_SUPPORTED); - writeHeaders(); - close(); - throw new IOException("Unsupported http version"); - } - for(int i=1; i values = requestHeaders.computeIfAbsent(hspl[0].toLowerCase(Locale.ROOT), h -> new ArrayList<>()); - values.add(hspl[1]); - } - } - - public String getRemoteAddress() { - return socket.getInetAddress().getHostAddress(); - } - - public SimpleHTTPSocket setResponseStatus(HTTPStatus status) { - return setResponseStatus(status.getStatus(), status.getMessage()); - } - - public SimpleHTTPSocket setResponseStatus(int status) { - HTTPStatus s = HTTPStatus.byStatus(status); - return setResponseStatus(status, s != null ? s.getMessage() : "Unknown"); - } - - public SimpleHTTPSocket setResponseStatus(int status, String message) { - this.responseStatus = status; - this.responseStatusMessage = message; - return this; - } - - public SimpleHTTPSocket setResponseHeader(String name, String value) { - responseHeaders.put(name.toLowerCase(Locale.ROOT), Arrays.asList(value)); - return this; - } - - public SimpleHTTPSocket addResponseHeader(String name, String value) { - responseHeaders.computeIfAbsent(name.toLowerCase(Locale.ROOT), h -> new ArrayList<>()).add(value); - return this; - } - - public void close() throws IOException { - socket.close(); - } - - public void writeHeaders() throws IOException { - if(headersSent) - return; - headersSent = true; - StringBuilder sb = new StringBuilder(requestVersion) - .append(' ') - .append(responseStatus) - .append(' ') - .append(responseStatusMessage) - .append("\r\n"); - responseHeaders.forEach((k, l) -> l.forEach(v -> sb.append(k.toLowerCase(Locale.ROOT)).append(": ").append(v).append("\r\n"))); - sb.append("\r\n"); - outputStream.write(sb.toString().getBytes(StandardCharsets.UTF_8)); - outputStream.flush(); - } - - public InputStream getInputStream() { - return inputStream; - } - - public OutputStream getOutputStream() { - return new HTTPOutputStream(); - } - - public HTTPMethod getRequestMethod() { - return requestMethod; - } - - public String getRequestPath() { - return requestPath; - } - - public String getRequestQuery() { - return requestQuery; - } - - public String getRequestVersion() { - return requestVersion; - } - - public Set getRequestHeaderNames() { - return requestHeaders.keySet(); - } - - public String getRequestHeader(String name) { - List values = requestHeaders.get(name.toLowerCase(Locale.ROOT)); - return values == null || values.size() == 0 ? null : values.get(0); - } - - public List getRequestHeaders(String name) { - return requestHeaders.getOrDefault(name.toLowerCase(Locale.ROOT), Collections.emptyList()); - } - - public int getResponseStatus() { - return responseStatus; - } - - public String getResponseStatusMessage() { - return responseStatusMessage; - } - - public boolean isClosed() { - return socket.isClosed(); - } - - private class HTTPOutputStream extends OutputStream { - public void write(int i) throws IOException { - if(!headersSent) - writeHeaders(); - outputStream.write(i); - } - public void close() throws IOException { - outputStream.close(); - } - public void flush() throws IOException { - outputStream.flush(); - } - } - -} diff --git a/src/main/java/org/javawebstack/httpserver/adapter/simple/SimpleHTTPSocketServer.java b/src/main/java/org/javawebstack/httpserver/adapter/simple/SimpleHTTPSocketServer.java deleted file mode 100644 index 1341629..0000000 --- a/src/main/java/org/javawebstack/httpserver/adapter/simple/SimpleHTTPSocketServer.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.javawebstack.httpserver.adapter.simple; - -import org.javawebstack.httpserver.adapter.IHTTPSocketHandler; -import org.javawebstack.httpserver.adapter.IHTTPSocketServer; -import org.javawebstack.httpserver.util.websocket.WebSocketUtil; - -import java.io.IOException; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.concurrent.*; - -public class SimpleHTTPSocketServer implements IHTTPSocketServer { - - private final Thread schedulerThread; - private ExecutorService executorService; - private ServerSocket serverSocket; - private int port = 80; - private int maxThreads = 64; - private IHTTPSocketHandler handler; - - public SimpleHTTPSocketServer() { - this.schedulerThread = new Thread(() -> { - while (!serverSocket.isClosed()) { - try { - Socket socket = serverSocket.accept(); - SimpleHTTPSocket httpSocket = new SimpleHTTPSocket(socket); - executorService.execute(() -> { - if(httpSocket.getRequestHeaderNames().contains("sec-websocket-key")) { - try { - if(!WebSocketUtil.accept(httpSocket, null)) - return; - } catch (IOException e) { - return; - } - } - handler.handle(httpSocket); - }); - } catch (IOException exception) {} - } - }); - } - - public void setPort(int port) { - this.port = port; - } - - public int getPort() { - return port; - } - - public void setHandler(IHTTPSocketHandler handler) { - this.handler = handler; - } - - public void setMaxThreads(int maxThreads) { - this.maxThreads = maxThreads; - } - - public void start() throws IOException { - this.serverSocket = new ServerSocket(port); - this.executorService = new ThreadPoolExecutor(1, maxThreads, 60L, TimeUnit.SECONDS, new SynchronousQueue()); - this.schedulerThread.start(); - } - - public void join() { - try { - schedulerThread.join(); - } catch (InterruptedException e) {} - } - - public void stop() { - this.executorService.shutdown(); - try { - this.serverSocket.close(); - } catch (IOException e) {} - } - - public boolean isWebSocketSupported() { - return true; - } - -} diff --git a/src/main/java/org/javawebstack/httpserver/test/HTTPTest.java b/src/main/java/org/javawebstack/httpserver/test/HTTPTest.java deleted file mode 100644 index 375b94d..0000000 --- a/src/main/java/org/javawebstack/httpserver/test/HTTPTest.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.javawebstack.httpserver.test; - -import org.javawebstack.httpserver.HTTPMethod; -import org.javawebstack.httpserver.HTTPServer; - -import java.io.ByteArrayInputStream; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -public abstract class HTTPTest { - - private final HTTPServer server; - private final Map defaultHeaders = new HashMap<>(); - - protected HTTPTest(HTTPServer server) { - this.server = server; - } - - public HTTPServer getServer() { - return server; - } - - public void setDefaultHeader(String key, String value) { - defaultHeaders.put(key, value); - } - - public void setBearerToken(String token) { - setDefaultHeader("Authorization", "Bearer " + token); - } - - public TestExchange httpGet(String url) { - return httpRequest(HTTPMethod.GET, url, null); - } - - public TestExchange httpPost(String url) { - return httpPost(url, null); - } - - public TestExchange httpPost(String url, Object content) { - return httpRequest(HTTPMethod.POST, url, content); - } - - public TestExchange httpPut(String url) { - return httpPut(url, null); - } - - public TestExchange httpPut(String url, Object content) { - return httpRequest(HTTPMethod.PUT, url, content); - } - - public TestExchange httpDelete(String url) { - return httpDelete(url, null); - } - - public TestExchange httpDelete(String url, Object content) { - return httpRequest(HTTPMethod.DELETE, url, content); - } - - public TestExchange httpRequest(HTTPMethod method, String url, Object content) { - TestHTTPSocket socket = new TestHTTPSocket(method, url); - defaultHeaders.forEach((k, v) -> socket.getRequestHeaders().put(k.toLowerCase(Locale.ROOT), Collections.singletonList(v))); - if (content != null) { - if (content instanceof String) { - socket.setInputStream(new ByteArrayInputStream(((String) content).getBytes(StandardCharsets.UTF_8))); - } else if (content instanceof byte[]) { - socket.setInputStream(new ByteArrayInputStream((byte[]) content)); - } else { - socket.setInputStream(new ByteArrayInputStream(server.getAbstractMapper().toAbstract(content).toJsonString().getBytes(StandardCharsets.UTF_8))); - } - } - TestExchange exchange = new TestExchange(server, socket); - server.execute(exchange); - return exchange; - } - -} diff --git a/src/main/java/org/javawebstack/httpserver/test/TestExchange.java b/src/main/java/org/javawebstack/httpserver/test/TestExchange.java deleted file mode 100644 index a7de3ba..0000000 --- a/src/main/java/org/javawebstack/httpserver/test/TestExchange.java +++ /dev/null @@ -1,290 +0,0 @@ -package org.javawebstack.httpserver.test; - -import org.javawebstack.abstractdata.AbstractElement; -import org.javawebstack.httpserver.Exchange; -import org.javawebstack.httpserver.HTTPServer; -import org.javawebstack.httpserver.adapter.IHTTPSocket; -import org.javawebstack.httpserver.util.MimeType; -import org.junit.jupiter.api.Assertions; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -public class TestExchange extends Exchange { - - private TestHTTPSocket testSocket; - - public TestExchange(HTTPServer service, TestHTTPSocket socket) { - super(service, socket); - this.testSocket = socket; - } - - public TestExchange print() { - printResponse(); - return this; - } - - public String getOutputString() { - try { - return new String(((ByteArrayOutputStream) testSocket.getOutputStream()).toByteArray(), StandardCharsets.UTF_8); - } catch (IOException ignored) { - return null; - } - } - - public TestExchange printResponse() { - System.out.println("HTTP Response " + testSocket.getResponseStatus()); - System.out.println(getOutputString()); - return this; - } - - public TestExchange assertStatus(int status) { - Assertions.assertEquals(status, testSocket.getResponseStatus()); - return this; - } - - public TestExchange assertStatus(int status, String message) { - Assertions.assertEquals(status, testSocket.getResponseStatus(), message); - return this; - } - - public TestExchange assertNotStatus(int status) { - Assertions.assertNotEquals(status, testSocket.getResponseStatus()); - return this; - } - - public TestExchange assertNotStatus(int status, String message) { - Assertions.assertNotEquals(status, testSocket.getResponseStatus(), message); - return this; - } - - public TestExchange assertOk() { - Assertions.assertEquals(200, testSocket.getResponseStatus()); - return this; - } - - public TestExchange assertOk(String message) { - Assertions.assertEquals(200, testSocket.getResponseStatus(), message); - return this; - } - - public TestExchange assertCreated() { - Assertions.assertEquals(201, testSocket.getResponseStatus()); - return this; - } - - public TestExchange assertCreated(String message) { - Assertions.assertEquals(201, testSocket.getResponseStatus(), message); - return this; - } - - public TestExchange assertNoContent() { - Assertions.assertEquals(204, testSocket.getResponseStatus()); - return this; - } - - public TestExchange assertNoContent(String message) { - Assertions.assertEquals(204, testSocket.getResponseStatus(), message); - return this; - } - - public TestExchange assertRedirect() { - Assertions.assertTrue(isRedirect()); - return this; - } - - public TestExchange assertRedirect(String message) { - Assertions.assertTrue(isRedirect(), message); - return this; - } - - public TestExchange assertRedirectTo(String url) { - assertRedirect(); - Assertions.assertEquals(url, testSocket.getResponseHeaders().get("location")); - return this; - } - - public TestExchange assertRedirectTo(String url, String message) { - assertRedirect(message); - Assertions.assertEquals(url, testSocket.getResponseHeaders().get("location"), message); - return this; - } - - public TestExchange assertNotFound() { - Assertions.assertEquals(404, testSocket.getResponseStatus()); - return this; - } - - public TestExchange assertNotFound(String message) { - Assertions.assertEquals(404, testSocket.getResponseStatus(), message); - return this; - } - - public TestExchange assertBadRequest() { - Assertions.assertEquals(400, testSocket.getResponseStatus()); - return this; - } - - public TestExchange assertBadRequest(String message) { - Assertions.assertEquals(400, testSocket.getResponseStatus(), message); - return this; - } - - public TestExchange assertForbidden() { - Assertions.assertEquals(403, testSocket.getResponseStatus()); - return this; - } - - public TestExchange assertForbidden(String message) { - Assertions.assertEquals(403, testSocket.getResponseStatus(), message); - return this; - } - - public TestExchange assertUnauthorized() { - Assertions.assertEquals(401, testSocket.getResponseStatus()); - return this; - } - - public TestExchange assertUnauthorized(String message) { - Assertions.assertEquals(401, testSocket.getResponseStatus(), message); - return this; - } - - public TestExchange assertSuccess() { - Assertions.assertEquals(200, (testSocket.getResponseStatus() / 100) * 100); - return this; - } - - public TestExchange assertSuccess(String message) { - Assertions.assertEquals(200, (testSocket.getResponseStatus() / 100) * 100, message); - return this; - } - - public TestExchange assertError() { - Assertions.assertTrue(testSocket.getResponseStatus() >= 400); - return this; - } - - public TestExchange assertError(String message) { - Assertions.assertTrue(testSocket.getResponseStatus() >= 400, message); - return this; - } - - public TestExchange assertHeader(String key, String value) { - Assertions.assertEquals(value, testSocket.getResponseHeaders().get(key.toLowerCase(Locale.ROOT))); - return this; - } - - public TestExchange assertHeader(String key, String value, String message) { - Assertions.assertEquals(value, testSocket.getResponseHeaders().get(key.toLowerCase(Locale.ROOT)), message); - return this; - } - - public TestExchange assertJsonPath(String path, Object value) { - Assertions.assertTrue(checkGraph(getPathElement(mockResponseBody(), path), value)); - return this; - } - - public TestExchange assertJsonPath(String path, Object value, String message) { - Assertions.assertTrue(checkGraph(getPathElement(mockResponseBody(), path), value), message); - return this; - } - - public TestExchange assertJson(Object value) { - assertJsonPath(null, value); - return this; - } - - public TestExchange assertJson(Object value, String message) { - assertJsonPath(null, value, message); - return this; - } - - public TestExchange assertBody(String content) { - Assertions.assertEquals(content, getOutputString()); - return this; - } - - public TestExchange assertBody(String content, String message) { - Assertions.assertEquals(content, getOutputString(), message); - return this; - } - - private AbstractElement mockResponseBody() { - List contentTypes = testSocket.getResponseHeaders().get("content-type"); - MimeType type = MimeType.byMimeType(contentTypes.size() > 0 ? contentTypes.get(0) : null); - if (type == null) - type = MimeType.JSON; - switch (type) { - default: - return AbstractElement.fromJson(getOutputString()); - case YAML: - return AbstractElement.fromYaml(getOutputString(), true); - case X_WWW_FORM_URLENCODED: - return AbstractElement.fromFormData(getOutputString()); - } - } - - private boolean checkGraph(AbstractElement element, Object value) { - if (value == null) - return element == null; - if (element == null) - return false; - AbstractElement val = getServer().getAbstractMapper().toAbstract(value); - if (val.isNull()) - return element.isNull(); - if (val.isObject()) { - if (!element.isObject()) - return false; - for (String key : val.object().keys()) { - if (!element.object().has(key)) - return false; - if (!checkGraph(element.object().get(key), val.object().get(key))) - return false; - } - return true; - } - if (val.isArray()) { - if (!element.isArray()) - return false; - if (val.array().size() != element.array().size()) - return false; - for (int i = 0; i < val.array().size(); i++) { - if (!checkGraph(element.array().get(i), val.array().get(i))) - return false; - } - return true; - } - if (val.isString()) { - if (!element.isString()) - return false; - return val.string().equals(element.string()); - } - if (val.isNumber()) { - if (!element.isNumber()) - return false; - return val.number().equals(element.number()); - } - if (val.isBoolean()) { - if (!element.isBoolean()) - return false; - return val.bool() == element.bool(); - } - return false; - } - - private boolean isRedirect() { - List redirectCodes = new ArrayList<>(); - redirectCodes.add(301); - redirectCodes.add(302); - redirectCodes.add(303); - redirectCodes.add(307); - redirectCodes.add(308); - - return redirectCodes.contains(testSocket.getResponseStatus()); - } -} diff --git a/src/main/java/org/javawebstack/httpserver/test/TestHTTPSocket.java b/src/main/java/org/javawebstack/httpserver/test/TestHTTPSocket.java deleted file mode 100644 index 2ac8b68..0000000 --- a/src/main/java/org/javawebstack/httpserver/test/TestHTTPSocket.java +++ /dev/null @@ -1,128 +0,0 @@ -package org.javawebstack.httpserver.test; - -import org.javawebstack.httpserver.HTTPMethod; -import org.javawebstack.httpserver.adapter.IHTTPSocket; - -import java.io.*; -import java.util.*; - -public class TestHTTPSocket implements IHTTPSocket { - - private final HTTPMethod requestMethod; - private final String requestPath; - private final String requestQuery; - private InputStream inputStream = new ByteArrayInputStream(new byte[0]); - private final OutputStream outputStream = new ByteArrayOutputStream(); - private boolean closed; - private int responseStatus = 200; - private String responseStatusMessage = "OK"; - private final Map> requestHeaders = new HashMap<>(); - private final Map> responseHeaders = new HashMap<>(); - - public TestHTTPSocket(HTTPMethod method, String url) { - this(method, url, null); - } - - public TestHTTPSocket(HTTPMethod method, String url, Map headers) { - this.requestMethod = method; - String[] pathSplit = url.split("\\?", 2); - requestPath = pathSplit[0]; - if(pathSplit.length == 2) - requestQuery = pathSplit[1]; - else - requestQuery = null; - if(headers != null) { - headers.entrySet().forEach(e -> { - List list = new ArrayList<>(); - list.add(e.getValue()); - this.requestHeaders.put(e.getKey(), list); - }); - } - } - - public Map> getRequestHeaders() { - return requestHeaders; - } - - public Map> getResponseHeaders() { - return responseHeaders; - } - - public TestHTTPSocket setInputStream(InputStream inputStream) { - this.inputStream = inputStream; - return this; - } - - public InputStream getInputStream() throws IOException { - return inputStream; - } - - public OutputStream getOutputStream() throws IOException { - return outputStream; - } - - public void close() throws IOException { - closed = true; - } - - public boolean isClosed() { - return closed; - } - - public TestHTTPSocket setResponseStatus(int status, String message) { - this.responseStatus = status; - this.responseStatusMessage = message; - return this; - } - - public TestHTTPSocket setResponseHeader(String name, String value) { - responseHeaders.put(name.toLowerCase(Locale.ROOT), Arrays.asList(value)); - return this; - } - - public TestHTTPSocket addResponseHeader(String name, String value) { - responseHeaders.computeIfAbsent(name.toLowerCase(Locale.ROOT), h -> new ArrayList<>()).add(value); - return this; - } - - public HTTPMethod getRequestMethod() { - return requestMethod; - } - - public String getRequestPath() { - return requestPath; - } - - public String getRequestQuery() { - return requestQuery; - } - - public String getRequestVersion() { - return "HTTP/1.1"; - } - - public Set getRequestHeaderNames() { - return requestHeaders.keySet(); - } - - public List getRequestHeaders(String name) { - return requestHeaders.get(name); - } - - public int getResponseStatus() { - return responseStatus; - } - - public String getResponseStatusMessage() { - return responseStatusMessage; - } - - public void writeHeaders() throws IOException { - - } - - public String getRemoteAddress() { - return "127.0.0.1"; - } - -} From 0ce09870d02d7f047c39ec1215c5a95e25a30ec7 Mon Sep 17 00:00:00 2001 From: JanHolger Date: Sun, 3 Sep 2023 22:52:49 +0200 Subject: [PATCH 12/24] Renaming to http-router and added SerializedResponseTransformer --- README.md | 10 +- pom.xml | 12 +- .../{httpserver => http/router}/Exchange.java | 26 ++-- .../router}/HTTPMethod.java | 2 +- .../router/HTTPRouter.java} | 140 +++++++++--------- .../router}/HTTPStatus.java | 2 +- .../router}/adapter/IHTTPSocket.java | 6 +- .../router}/adapter/IHTTPSocketHandler.java | 2 +- .../router}/adapter/IHTTPSocketServer.java | 2 +- .../router}/handler/AfterRequestHandler.java | 4 +- .../handler/DefaultNotFoundHandler.java | 4 +- .../router}/handler/ExceptionHandler.java | 6 +- .../router}/handler/Middleware.java | 2 +- .../http/router/handler/RequestHandler.java | 9 ++ .../router/handler/RequestInterceptor.java | 7 + .../router}/handler/StaticFileHandler.java | 8 +- .../router}/handler/WebSocketHandler.java | 4 +- .../router/DefaultRouteAutoInjector.java | 8 +- .../router}/router/Route.java | 12 +- .../router}/router/RouteAutoInjector.java | 4 +- .../router}/router/RouteBinder.java | 70 ++++----- .../router}/router/annotation/PathPrefix.java | 2 +- .../router}/router/annotation/With.java | 2 +- .../router/annotation/params/Attrib.java | 2 +- .../router/annotation/params/Body.java | 2 +- .../annotation/params/DefaultValue.java | 2 +- .../router/annotation/params/Path.java | 2 +- .../router/annotation/params/Query.java | 2 +- .../router/annotation/params/WSCode.java | 2 +- .../router/annotation/params/WSMessage.java | 2 +- .../router/annotation/params/WSReason.java | 2 +- .../router/annotation/verbs/Delete.java | 2 +- .../router}/router/annotation/verbs/Get.java | 2 +- .../router}/router/annotation/verbs/Head.java | 2 +- .../router/annotation/verbs/Options.java | 2 +- .../router/annotation/verbs/Patch.java | 2 +- .../router}/router/annotation/verbs/Post.java | 2 +- .../router}/router/annotation/verbs/Put.java | 2 +- .../router/annotation/verbs/Trace.java | 2 +- .../annotation/verbs/WebSocketClose.java | 2 +- .../annotation/verbs/WebSocketConnect.java | 2 +- .../annotation/verbs/WebSocketMessage.java | 2 +- .../response/JsonResponseTransformer.java | 17 ++- .../response/ResponseTransformer.java | 4 +- .../SerializedResponseTransformer.java | 52 +++++++ .../route/DefaultRouteParamTransformer.java | 2 +- .../route/RouteParamTransformFunction.java | 4 +- .../route/RouteParamTransformer.java | 4 +- .../route/RouteParamTransformerProvider.java | 2 +- .../router}/util/DirectoryFileProvider.java | 2 +- .../router}/util/FileProvider.java | 2 +- .../router}/util/MimeType.java | 2 +- .../router}/util/ResourceFileProvider.java | 2 +- .../util/websocket/WebSocketFrame.java | 2 +- .../router}/util/websocket/WebSocketUtil.java | 6 +- .../InternalWebSocketRequestHandler.java | 14 +- .../router}/websocket/WebSocket.java | 6 +- .../httpserver/handler/RequestHandler.java | 9 -- .../handler/RequestInterceptor.java | 7 - 59 files changed, 286 insertions(+), 233 deletions(-) rename src/main/java/org/javawebstack/{httpserver => http/router}/Exchange.java (93%) rename src/main/java/org/javawebstack/{httpserver => http/router}/HTTPMethod.java (78%) rename src/main/java/org/javawebstack/{httpserver/HTTPServer.java => http/router/HTTPRouter.java} (73%) rename src/main/java/org/javawebstack/{httpserver => http/router}/HTTPStatus.java (98%) rename src/main/java/org/javawebstack/{httpserver => http/router}/adapter/IHTTPSocket.java (91%) rename src/main/java/org/javawebstack/{httpserver => http/router}/adapter/IHTTPSocketHandler.java (63%) rename src/main/java/org/javawebstack/{httpserver => http/router}/adapter/IHTTPSocketServer.java (87%) rename src/main/java/org/javawebstack/{httpserver => http/router}/handler/AfterRequestHandler.java (52%) rename src/main/java/org/javawebstack/{httpserver => http/router}/handler/DefaultNotFoundHandler.java (66%) rename src/main/java/org/javawebstack/{httpserver => http/router}/handler/ExceptionHandler.java (74%) rename src/main/java/org/javawebstack/{httpserver => http/router}/handler/Middleware.java (55%) create mode 100644 src/main/java/org/javawebstack/http/router/handler/RequestHandler.java create mode 100644 src/main/java/org/javawebstack/http/router/handler/RequestInterceptor.java rename src/main/java/org/javawebstack/{httpserver => http/router}/handler/StaticFileHandler.java (82%) rename src/main/java/org/javawebstack/{httpserver => http/router}/handler/WebSocketHandler.java (71%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/DefaultRouteAutoInjector.java (75%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/Route.java (93%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/RouteAutoInjector.java (62%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/RouteBinder.java (86%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/PathPrefix.java (83%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/With.java (84%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/params/Attrib.java (81%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/params/Body.java (80%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/params/DefaultValue.java (81%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/params/Path.java (81%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/params/Query.java (81%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/params/WSCode.java (80%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/params/WSMessage.java (80%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/params/WSReason.java (80%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/verbs/Delete.java (83%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/verbs/Get.java (83%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/verbs/Head.java (87%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/verbs/Options.java (84%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/verbs/Patch.java (83%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/verbs/Post.java (83%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/verbs/Put.java (83%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/verbs/Trace.java (87%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/verbs/WebSocketClose.java (85%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/verbs/WebSocketConnect.java (86%) rename src/main/java/org/javawebstack/{httpserver => http/router}/router/annotation/verbs/WebSocketMessage.java (86%) rename src/main/java/org/javawebstack/{httpserver => http/router}/transformer/response/JsonResponseTransformer.java (54%) rename src/main/java/org/javawebstack/{httpserver => http/router}/transformer/response/ResponseTransformer.java (80%) create mode 100644 src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java rename src/main/java/org/javawebstack/{httpserver => http/router}/transformer/route/DefaultRouteParamTransformer.java (96%) rename src/main/java/org/javawebstack/{httpserver => http/router}/transformer/route/RouteParamTransformFunction.java (51%) rename src/main/java/org/javawebstack/{httpserver => http/router}/transformer/route/RouteParamTransformer.java (94%) rename src/main/java/org/javawebstack/{httpserver => http/router}/transformer/route/RouteParamTransformerProvider.java (87%) rename src/main/java/org/javawebstack/{httpserver => http/router}/util/DirectoryFileProvider.java (95%) rename src/main/java/org/javawebstack/{httpserver => http/router}/util/FileProvider.java (70%) rename src/main/java/org/javawebstack/{httpserver => http/router}/util/MimeType.java (98%) rename src/main/java/org/javawebstack/{httpserver => http/router}/util/ResourceFileProvider.java (93%) rename src/main/java/org/javawebstack/{httpserver => http/router}/util/websocket/WebSocketFrame.java (98%) rename src/main/java/org/javawebstack/{httpserver => http/router}/util/websocket/WebSocketUtil.java (96%) rename src/main/java/org/javawebstack/{httpserver => http/router}/websocket/InternalWebSocketRequestHandler.java (83%) rename src/main/java/org/javawebstack/{httpserver => http/router}/websocket/WebSocket.java (83%) delete mode 100644 src/main/java/org/javawebstack/httpserver/handler/RequestHandler.java delete mode 100644 src/main/java/org/javawebstack/httpserver/handler/RequestInterceptor.java diff --git a/README.md b/README.md index 6fea1c5..36e16e3 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ JWS HTTP Routing Library

-![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/JavaWebStack/http-server/Maven%20Deploy/master) -![GitHub](https://img.shields.io/github/license/JavaWebStack/http-server) +![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/JavaWebStack/http-router/Maven%20Deploy/master) +![GitHub](https://img.shields.io/github/license/JavaWebStack/http-router) ![Maven metadata URL](https://img.shields.io/maven-metadata/v?metadataUrl=https%3A%2F%2Frepo1.maven.org%2Fmaven2%2Forg%2Fjavawebstack%2FHTTP-Server%2Fmaven-metadata.xml) -![GitHub contributors](https://img.shields.io/github/contributors/JavaWebStack/http-server) -![Lines of code](https://img.shields.io/tokei/lines/github/JavaWebStack/http-server) +![GitHub contributors](https://img.shields.io/github/contributors/JavaWebStack/http-router) +![Lines of code](https://img.shields.io/tokei/lines/github/JavaWebStack/http-router) ![Discord](https://img.shields.io/discord/815612319378833408?color=%237289DA&label=discord) ![Twitter Follow](https://img.shields.io/twitter/follow/JavaWebStack?style=social) @@ -24,7 +24,7 @@ work-in-progress project though so it's not yet complete. ```xml org.javawebstack - http-server + http-router 1.0.3 ``` \ No newline at end of file diff --git a/pom.xml b/pom.xml index 5bd8deb..fe78071 100644 --- a/pom.xml +++ b/pom.xml @@ -11,12 +11,12 @@ org.javawebstack - http-server + http-router ${buildVersion} - http-server + http-router This library provides an http routing and request mapping stack - https://github.com/JavaWebStack/http-server + https://github.com/JavaWebStack/http-router @@ -41,9 +41,9 @@ - scm:git:git://github.com/JavaWebStack/http-server.git - scm:git:ssh://github.com:JavaWebStack/http-server.git - https://github.com/JavaWebStack/http-server/tree/master + scm:git:git://github.com/JavaWebStack/http-router.git + scm:git:ssh://github.com:JavaWebStack/http-router.git + https://github.com/JavaWebStack/http-router/tree/master diff --git a/src/main/java/org/javawebstack/httpserver/Exchange.java b/src/main/java/org/javawebstack/http/router/Exchange.java similarity index 93% rename from src/main/java/org/javawebstack/httpserver/Exchange.java rename to src/main/java/org/javawebstack/http/router/Exchange.java index d249b03..11c6122 100644 --- a/src/main/java/org/javawebstack/httpserver/Exchange.java +++ b/src/main/java/org/javawebstack/http/router/Exchange.java @@ -1,8 +1,9 @@ -package org.javawebstack.httpserver; +package org.javawebstack.http.router; import org.javawebstack.abstractdata.*; -import org.javawebstack.httpserver.adapter.IHTTPSocket; -import org.javawebstack.httpserver.util.MimeType; +import org.javawebstack.abstractdata.mapper.Mapper; +import org.javawebstack.http.router.adapter.IHTTPSocket; +import org.javawebstack.http.router.util.MimeType; import org.javawebstack.validator.ValidationContext; import org.javawebstack.validator.ValidationException; import org.javawebstack.validator.ValidationResult; @@ -11,7 +12,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; @@ -25,7 +25,7 @@ public static Exchange current() { return exchanges.get(); } - private final HTTPServer server; + private final HTTPRouter router; private final HTTPMethod method; private byte[] body = null; private final Map pathVariables = new HashMap<>(); @@ -33,8 +33,8 @@ public static Exchange current() { private final IHTTPSocket socket; private final Map attributes = new HashMap<>(); - public Exchange(HTTPServer server, IHTTPSocket socket) { - this.server = server; + public Exchange(HTTPRouter router, IHTTPSocket socket) { + this.router = router; this.socket = socket; this.method = getRequestMethodFromSocket(socket); this.queryParameters = AbstractElement.fromFormData(socket.getRequestQuery()).object(); @@ -74,11 +74,11 @@ public T body(Class clazz) { ValidationResult result = Validator.getValidator(clazz).validate(new ValidationContext().attrib("exchange", this), request); if (!result.isValid()) throw new ValidationException(result); - return server.getAbstractMapper().fromAbstract(request, clazz); + return router.getMapper().map(request, clazz); } - public HTTPServer getServer() { - return server; + public HTTPRouter getRouter() { + return router; } public HTTPMethod getMethod() { @@ -236,7 +236,7 @@ public T query(String name, Class type) { } public T query(String name, Class type, T defaultValue) { - T t = new AbstractMapper().fromAbstract(queryParameters.get(name, AbstractNull.INSTANCE), type); + T t = new Mapper().map(queryParameters.get(name, AbstractNull.VALUE), type); if (t == null) return defaultValue; return t; @@ -264,7 +264,7 @@ public String bearerAuth() { } public T getBodyPath(String path, Class clazz) { - return server.getAbstractMapper().fromAbstract(getBodyPathElement(path), clazz); + return router.getMapper().map(getBodyPathElement(path), clazz); } public AbstractElement getBodyPathElement(String path) { @@ -290,7 +290,7 @@ protected static AbstractElement getPathElement(AbstractElement source, String p private HTTPMethod getRequestMethodFromSocket(IHTTPSocket socket) { if ("websocket".equalsIgnoreCase(socket.getRequestHeader("upgrade"))) return HTTPMethod.WEBSOCKET; - if (server.isFormMethods() && (socket.getRequestMethod() == HTTPMethod.GET || socket.getRequestMethod() == HTTPMethod.POST) && getMimeType() == MimeType.X_WWW_FORM_URLENCODED) { + if (router.isFormMethods() && (socket.getRequestMethod() == HTTPMethod.GET || socket.getRequestMethod() == HTTPMethod.POST) && getMimeType() == MimeType.X_WWW_FORM_URLENCODED) { AbstractElement e = getBodyPathElement("_method"); if (e != null) { try { diff --git a/src/main/java/org/javawebstack/httpserver/HTTPMethod.java b/src/main/java/org/javawebstack/http/router/HTTPMethod.java similarity index 78% rename from src/main/java/org/javawebstack/httpserver/HTTPMethod.java rename to src/main/java/org/javawebstack/http/router/HTTPMethod.java index 6bc93f4..6cb61d5 100644 --- a/src/main/java/org/javawebstack/httpserver/HTTPMethod.java +++ b/src/main/java/org/javawebstack/http/router/HTTPMethod.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver; +package org.javawebstack.http.router; public enum HTTPMethod { diff --git a/src/main/java/org/javawebstack/httpserver/HTTPServer.java b/src/main/java/org/javawebstack/http/router/HTTPRouter.java similarity index 73% rename from src/main/java/org/javawebstack/httpserver/HTTPServer.java rename to src/main/java/org/javawebstack/http/router/HTTPRouter.java index ffa5e4c..f79e5f5 100644 --- a/src/main/java/org/javawebstack/httpserver/HTTPServer.java +++ b/src/main/java/org/javawebstack/http/router/HTTPRouter.java @@ -1,20 +1,20 @@ -package org.javawebstack.httpserver; - -import org.javawebstack.abstractdata.AbstractMapper; -import org.javawebstack.abstractdata.NamingPolicy; -import org.javawebstack.httpserver.adapter.IHTTPSocketServer; -import org.javawebstack.httpserver.handler.*; -import org.javawebstack.httpserver.router.DefaultRouteAutoInjector; -import org.javawebstack.httpserver.router.Route; -import org.javawebstack.httpserver.router.RouteAutoInjector; -import org.javawebstack.httpserver.router.RouteBinder; -import org.javawebstack.httpserver.transformer.response.ResponseTransformer; -import org.javawebstack.httpserver.transformer.route.DefaultRouteParamTransformer; -import org.javawebstack.httpserver.transformer.route.RouteParamTransformer; -import org.javawebstack.httpserver.transformer.route.RouteParamTransformerProvider; -import org.javawebstack.httpserver.util.DirectoryFileProvider; -import org.javawebstack.httpserver.util.ResourceFileProvider; -import org.javawebstack.httpserver.websocket.InternalWebSocketRequestHandler; +package org.javawebstack.http.router; + +import org.javawebstack.abstractdata.mapper.Mapper; +import org.javawebstack.abstractdata.mapper.naming.NamingPolicy; +import org.javawebstack.http.router.adapter.IHTTPSocketServer; +import org.javawebstack.http.router.handler.*; +import org.javawebstack.http.router.router.DefaultRouteAutoInjector; +import org.javawebstack.http.router.router.Route; +import org.javawebstack.http.router.router.RouteAutoInjector; +import org.javawebstack.http.router.router.RouteBinder; +import org.javawebstack.http.router.transformer.response.ResponseTransformer; +import org.javawebstack.http.router.transformer.route.DefaultRouteParamTransformer; +import org.javawebstack.http.router.transformer.route.RouteParamTransformer; +import org.javawebstack.http.router.transformer.route.RouteParamTransformerProvider; +import org.javawebstack.http.router.util.DirectoryFileProvider; +import org.javawebstack.http.router.util.ResourceFileProvider; +import org.javawebstack.http.router.websocket.InternalWebSocketRequestHandler; import org.reflections.Reflections; import java.io.File; @@ -24,9 +24,9 @@ import java.util.logging.Level; import java.util.logging.Logger; -public class HTTPServer implements RouteParamTransformerProvider { +public class HTTPRouter implements RouteParamTransformerProvider { - private Logger logger = Logger.getLogger("HTTP-Server"); + private Logger logger = Logger.getLogger("HTTP-Router"); private final List routes = new ArrayList<>(); private final RouteBinder routeBinder = new RouteBinder(this); private final List routeParamTransformers = new ArrayList<>(); @@ -37,197 +37,197 @@ public class HTTPServer implements RouteParamTransformerProvider { private final List afterRoutes = new ArrayList<>(); private final IHTTPSocketServer server; private final List beforeInterceptors = new ArrayList<>(); - private AbstractMapper abstractMapper = new AbstractMapper().setNamingPolicy(NamingPolicy.SNAKE_CASE); + private Mapper mapper = new Mapper().namingPolicy(NamingPolicy.SNAKE_CASE); private final List routeAutoInjectors = new ArrayList<>(); private final Map beforeMiddleware = new HashMap<>(); private final Map afterMiddleware = new HashMap<>(); private Function, Object> controllerInitiator = this::defaultControllerInitiator; private boolean formMethods = true; - public HTTPServer(IHTTPSocketServer server) { + public HTTPRouter(IHTTPSocketServer server) { this.server = server; routeParamTransformers.add(DefaultRouteParamTransformer.INSTANCE); routeAutoInjectors.add(DefaultRouteAutoInjector.INSTANCE); } - public HTTPServer maxThreads(int maxThreads) { + public HTTPRouter maxThreads(int maxThreads) { this.server.setMaxThreads(maxThreads); return this; } - public HTTPServer logger(Logger logger) { + public HTTPRouter logger(Logger logger) { this.logger = logger; return this; } - public HTTPServer abstractMapper(AbstractMapper mapper) { - this.abstractMapper = mapper; + public HTTPRouter mapper(Mapper mapper) { + this.mapper = mapper; return this; } - public AbstractMapper getAbstractMapper() { - return abstractMapper; + public Mapper getMapper() { + return mapper; } public Logger getLogger() { return logger; } - public HTTPServer beforeInterceptor(RequestInterceptor handler) { + public HTTPRouter beforeInterceptor(RequestInterceptor handler) { beforeInterceptors.add(handler); return this; } - public HTTPServer routeAutoInjector(RouteAutoInjector injector) { + public HTTPRouter routeAutoInjector(RouteAutoInjector injector) { routeAutoInjectors.add(injector); return this; } - public HTTPServer get(String pattern, RequestHandler... handlers) { + public HTTPRouter get(String pattern, RequestHandler... handlers) { return route(HTTPMethod.GET, pattern, handlers); } - public HTTPServer beforeGet(String pattern, RequestHandler... handlers) { + public HTTPRouter beforeGet(String pattern, RequestHandler... handlers) { return beforeRoute(HTTPMethod.GET, pattern, handlers); } - public HTTPServer afterGet(String pattern, AfterRequestHandler... handlers) { + public HTTPRouter afterGet(String pattern, AfterRequestHandler... handlers) { return afterRoute(HTTPMethod.GET, pattern, handlers); } - public HTTPServer post(String pattern, RequestHandler... handlers) { + public HTTPRouter post(String pattern, RequestHandler... handlers) { return route(HTTPMethod.POST, pattern, handlers); } - public HTTPServer beforePost(String pattern, RequestHandler... handlers) { + public HTTPRouter beforePost(String pattern, RequestHandler... handlers) { return beforeRoute(HTTPMethod.POST, pattern, handlers); } - public HTTPServer afterPost(String pattern, AfterRequestHandler... handlers) { + public HTTPRouter afterPost(String pattern, AfterRequestHandler... handlers) { return afterRoute(HTTPMethod.POST, pattern, handlers); } - public HTTPServer put(String pattern, RequestHandler... handlers) { + public HTTPRouter put(String pattern, RequestHandler... handlers) { return route(HTTPMethod.PUT, pattern, handlers); } - public HTTPServer beforePut(String pattern, RequestHandler... handlers) { + public HTTPRouter beforePut(String pattern, RequestHandler... handlers) { return beforeRoute(HTTPMethod.PUT, pattern, handlers); } - public HTTPServer afterPut(String pattern, AfterRequestHandler... handlers) { + public HTTPRouter afterPut(String pattern, AfterRequestHandler... handlers) { return afterRoute(HTTPMethod.PUT, pattern, handlers); } - public HTTPServer delete(String pattern, RequestHandler... handlers) { + public HTTPRouter delete(String pattern, RequestHandler... handlers) { return route(HTTPMethod.DELETE, pattern, handlers); } - public HTTPServer staticDirectory(String pathPrefix, File directory) { + public HTTPRouter staticDirectory(String pathPrefix, File directory) { return staticHandler(pathPrefix, new StaticFileHandler().add(new DirectoryFileProvider(directory))); } - public HTTPServer staticDirectory(String pathPrefix, String directory) { + public HTTPRouter staticDirectory(String pathPrefix, String directory) { return staticDirectory(pathPrefix, new File(directory)); } - public HTTPServer staticResourceDirectory(String pathPrefix, String prefix) { + public HTTPRouter staticResourceDirectory(String pathPrefix, String prefix) { return staticResourceDirectory(pathPrefix, null, prefix); } - public HTTPServer staticResourceDirectory(String pathPrefix, ClassLoader classLoader, String prefix) { + public HTTPRouter staticResourceDirectory(String pathPrefix, ClassLoader classLoader, String prefix) { return staticHandler(pathPrefix, new StaticFileHandler().add(new ResourceFileProvider(classLoader, prefix))); } - public HTTPServer staticHandler(String pathPrefix, StaticFileHandler handler) { + public HTTPRouter staticHandler(String pathPrefix, StaticFileHandler handler) { return get(pathPrefix + (pathPrefix.endsWith("/") ? "" : "/") + "{*:path}", handler); } - public HTTPServer beforeDelete(String pattern, RequestHandler... handlers) { + public HTTPRouter beforeDelete(String pattern, RequestHandler... handlers) { return beforeRoute(HTTPMethod.DELETE, pattern, handlers); } - public HTTPServer afterDelete(String pattern, AfterRequestHandler... handlers) { + public HTTPRouter afterDelete(String pattern, AfterRequestHandler... handlers) { return afterRoute(HTTPMethod.DELETE, pattern, handlers); } - public HTTPServer route(HTTPMethod method, String pattern, RequestHandler... handlers) { + public HTTPRouter route(HTTPMethod method, String pattern, RequestHandler... handlers) { routes.add(new Route(this, method, pattern, Arrays.asList(handlers))); return this; } - public HTTPServer beforeRoute(HTTPMethod method, String pattern, RequestHandler... handlers) { + public HTTPRouter beforeRoute(HTTPMethod method, String pattern, RequestHandler... handlers) { beforeRoutes.add(new Route(this, method, pattern, Arrays.asList(handlers))); return this; } - public HTTPServer afterRoute(HTTPMethod method, String pattern, AfterRequestHandler... handlers) { + public HTTPRouter afterRoute(HTTPMethod method, String pattern, AfterRequestHandler... handlers) { afterRoutes.add(new Route(this, method, pattern, null).setAfterHandlers(Arrays.asList(handlers))); return this; } - public HTTPServer route(HTTPMethod[] methods, String pattern, RequestHandler... handlers) { + public HTTPRouter route(HTTPMethod[] methods, String pattern, RequestHandler... handlers) { for (HTTPMethod method : methods) route(method, pattern, handlers); return this; } - public HTTPServer beforeRoute(HTTPMethod[] methods, String pattern, RequestHandler... handlers) { + public HTTPRouter beforeRoute(HTTPMethod[] methods, String pattern, RequestHandler... handlers) { for (HTTPMethod method : methods) beforeRoute(method, pattern, handlers); return this; } - public HTTPServer afterRoute(HTTPMethod[] methods, String pattern, AfterRequestHandler... handlers) { + public HTTPRouter afterRoute(HTTPMethod[] methods, String pattern, AfterRequestHandler... handlers) { for (HTTPMethod method : methods) afterRoute(method, pattern, handlers); return this; } - public HTTPServer any(String pattern, RequestHandler... handlers) { + public HTTPRouter any(String pattern, RequestHandler... handlers) { return route(HTTPMethod.values(), pattern, handlers); } - public HTTPServer beforeAny(String pattern, RequestHandler... handlers) { + public HTTPRouter beforeAny(String pattern, RequestHandler... handlers) { return beforeRoute(HTTPMethod.values(), pattern, handlers); } - public HTTPServer afterAny(String pattern, AfterRequestHandler... handlers) { + public HTTPRouter afterAny(String pattern, AfterRequestHandler... handlers) { return afterRoute(HTTPMethod.values(), pattern, handlers); } - public HTTPServer webSocket(String pattern, WebSocketHandler handler) { + public HTTPRouter webSocket(String pattern, WebSocketHandler handler) { if(!server.isWebSocketSupported()) throw new UnsupportedOperationException(server.getClass().getName() + " does not support websockets!"); return route(HTTPMethod.WEBSOCKET, pattern, new InternalWebSocketRequestHandler(handler)); } - public HTTPServer middleware(String name, RequestHandler handler) { + public HTTPRouter middleware(String name, RequestHandler handler) { beforeMiddleware.put(name, handler); return this; } - public HTTPServer middleware(String name, AfterRequestHandler handler) { + public HTTPRouter middleware(String name, AfterRequestHandler handler) { afterMiddleware.put(name, handler); return this; } - public HTTPServer notFound(RequestHandler handler) { + public HTTPRouter notFound(RequestHandler handler) { notFoundHandler = handler; return this; } - public HTTPServer routeParamTransformer(RouteParamTransformer transformer) { + public HTTPRouter routeParamTransformer(RouteParamTransformer transformer) { routeParamTransformers.add(transformer); return this; } - public HTTPServer responseTransformer(ResponseTransformer transformer) { + public HTTPRouter responseTransformer(ResponseTransformer transformer) { responseTransformers.add(transformer); return this; } - public HTTPServer exceptionHandler(ExceptionHandler handler) { + public HTTPRouter exceptionHandler(ExceptionHandler handler) { exceptionHandler = handler; return this; } @@ -242,16 +242,16 @@ private Object defaultControllerInitiator (Class clazz) { return null; } - public HTTPServer controllerInitiator (Function, Object> initiator) { + public HTTPRouter controllerInitiator (Function, Object> initiator) { controllerInitiator = initiator; return this; } - public HTTPServer controller(Class parentClass, Package p) { + public HTTPRouter controller(Class parentClass, Package p) { return controller("", parentClass, p); } - public HTTPServer controller(String globalPrefix, Class parentClass, Package p) { + public HTTPRouter controller(String globalPrefix, Class parentClass, Package p) { Reflections reflections = new Reflections(p.getName()); reflections.getSubTypesOf(parentClass) .stream() @@ -260,21 +260,21 @@ public HTTPServer controller(String globalPrefix, Class parentClass, Package return this; } - public HTTPServer controller(Object controller) { + public HTTPRouter controller(Object controller) { return controller("", controller); } - public HTTPServer controller(String globalPrefix, Object controller) { + public HTTPRouter controller(String globalPrefix, Object controller) { routeBinder.bind(globalPrefix, controller); return this; } - public HTTPServer port(int port) { + public HTTPRouter port(int port) { server.setPort(port); return this; } - public HTTPServer start() { + public HTTPRouter start() { server.setHandler(socket -> execute(new Exchange(this, socket))); try { server.start(); @@ -415,7 +415,7 @@ public boolean isFormMethods() { return formMethods; } - public HTTPServer disableFormMethods() { + public HTTPRouter disableFormMethods() { formMethods = false; return this; } diff --git a/src/main/java/org/javawebstack/httpserver/HTTPStatus.java b/src/main/java/org/javawebstack/http/router/HTTPStatus.java similarity index 98% rename from src/main/java/org/javawebstack/httpserver/HTTPStatus.java rename to src/main/java/org/javawebstack/http/router/HTTPStatus.java index 1b03a38..596aebf 100644 --- a/src/main/java/org/javawebstack/httpserver/HTTPStatus.java +++ b/src/main/java/org/javawebstack/http/router/HTTPStatus.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver; +package org.javawebstack.http.router; public enum HTTPStatus { diff --git a/src/main/java/org/javawebstack/httpserver/adapter/IHTTPSocket.java b/src/main/java/org/javawebstack/http/router/adapter/IHTTPSocket.java similarity index 91% rename from src/main/java/org/javawebstack/httpserver/adapter/IHTTPSocket.java rename to src/main/java/org/javawebstack/http/router/adapter/IHTTPSocket.java index af47269..e4de41b 100644 --- a/src/main/java/org/javawebstack/httpserver/adapter/IHTTPSocket.java +++ b/src/main/java/org/javawebstack/http/router/adapter/IHTTPSocket.java @@ -1,7 +1,7 @@ -package org.javawebstack.httpserver.adapter; +package org.javawebstack.http.router.adapter; -import org.javawebstack.httpserver.HTTPMethod; -import org.javawebstack.httpserver.HTTPStatus; +import org.javawebstack.http.router.HTTPMethod; +import org.javawebstack.http.router.HTTPStatus; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/org/javawebstack/httpserver/adapter/IHTTPSocketHandler.java b/src/main/java/org/javawebstack/http/router/adapter/IHTTPSocketHandler.java similarity index 63% rename from src/main/java/org/javawebstack/httpserver/adapter/IHTTPSocketHandler.java rename to src/main/java/org/javawebstack/http/router/adapter/IHTTPSocketHandler.java index d21ba29..a76171d 100644 --- a/src/main/java/org/javawebstack/httpserver/adapter/IHTTPSocketHandler.java +++ b/src/main/java/org/javawebstack/http/router/adapter/IHTTPSocketHandler.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.adapter; +package org.javawebstack.http.router.adapter; public interface IHTTPSocketHandler { diff --git a/src/main/java/org/javawebstack/httpserver/adapter/IHTTPSocketServer.java b/src/main/java/org/javawebstack/http/router/adapter/IHTTPSocketServer.java similarity index 87% rename from src/main/java/org/javawebstack/httpserver/adapter/IHTTPSocketServer.java rename to src/main/java/org/javawebstack/http/router/adapter/IHTTPSocketServer.java index 28dd1dd..6f24f30 100644 --- a/src/main/java/org/javawebstack/httpserver/adapter/IHTTPSocketServer.java +++ b/src/main/java/org/javawebstack/http/router/adapter/IHTTPSocketServer.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.adapter; +package org.javawebstack.http.router.adapter; import java.io.IOException; diff --git a/src/main/java/org/javawebstack/httpserver/handler/AfterRequestHandler.java b/src/main/java/org/javawebstack/http/router/handler/AfterRequestHandler.java similarity index 52% rename from src/main/java/org/javawebstack/httpserver/handler/AfterRequestHandler.java rename to src/main/java/org/javawebstack/http/router/handler/AfterRequestHandler.java index b21e4f3..e35648f 100644 --- a/src/main/java/org/javawebstack/httpserver/handler/AfterRequestHandler.java +++ b/src/main/java/org/javawebstack/http/router/handler/AfterRequestHandler.java @@ -1,6 +1,6 @@ -package org.javawebstack.httpserver.handler; +package org.javawebstack.http.router.handler; -import org.javawebstack.httpserver.Exchange; +import org.javawebstack.http.router.Exchange; public interface AfterRequestHandler { Object handleAfter(Exchange exchange, Object response); diff --git a/src/main/java/org/javawebstack/httpserver/handler/DefaultNotFoundHandler.java b/src/main/java/org/javawebstack/http/router/handler/DefaultNotFoundHandler.java similarity index 66% rename from src/main/java/org/javawebstack/httpserver/handler/DefaultNotFoundHandler.java rename to src/main/java/org/javawebstack/http/router/handler/DefaultNotFoundHandler.java index c757e76..60e3d06 100644 --- a/src/main/java/org/javawebstack/httpserver/handler/DefaultNotFoundHandler.java +++ b/src/main/java/org/javawebstack/http/router/handler/DefaultNotFoundHandler.java @@ -1,6 +1,6 @@ -package org.javawebstack.httpserver.handler; +package org.javawebstack.http.router.handler; -import org.javawebstack.httpserver.Exchange; +import org.javawebstack.http.router.Exchange; public class DefaultNotFoundHandler implements RequestHandler { public Object handle(Exchange exchange) { diff --git a/src/main/java/org/javawebstack/httpserver/handler/ExceptionHandler.java b/src/main/java/org/javawebstack/http/router/handler/ExceptionHandler.java similarity index 74% rename from src/main/java/org/javawebstack/httpserver/handler/ExceptionHandler.java rename to src/main/java/org/javawebstack/http/router/handler/ExceptionHandler.java index 1c9391d..110c72f 100644 --- a/src/main/java/org/javawebstack/httpserver/handler/ExceptionHandler.java +++ b/src/main/java/org/javawebstack/http/router/handler/ExceptionHandler.java @@ -1,6 +1,6 @@ -package org.javawebstack.httpserver.handler; +package org.javawebstack.http.router.handler; -import org.javawebstack.httpserver.Exchange; +import org.javawebstack.http.router.Exchange; import java.util.logging.Level; @@ -9,7 +9,7 @@ public interface ExceptionHandler { class DefaultExceptionHandler implements ExceptionHandler { public Object handle(Exchange exchange, Throwable ex) { - exchange.getServer().getLogger().log(Level.SEVERE, ex, () -> "An internal server error occured!"); + exchange.getRouter().getLogger().log(Level.SEVERE, ex, () -> "An internal server error occured!"); return "An internal server error occured! Please contact the server administrator in case you think this is a problem."; } } diff --git a/src/main/java/org/javawebstack/httpserver/handler/Middleware.java b/src/main/java/org/javawebstack/http/router/handler/Middleware.java similarity index 55% rename from src/main/java/org/javawebstack/httpserver/handler/Middleware.java rename to src/main/java/org/javawebstack/http/router/handler/Middleware.java index fa12801..975d0fb 100644 --- a/src/main/java/org/javawebstack/httpserver/handler/Middleware.java +++ b/src/main/java/org/javawebstack/http/router/handler/Middleware.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.handler; +package org.javawebstack.http.router.handler; public interface Middleware extends RequestHandler { diff --git a/src/main/java/org/javawebstack/http/router/handler/RequestHandler.java b/src/main/java/org/javawebstack/http/router/handler/RequestHandler.java new file mode 100644 index 0000000..bea23df --- /dev/null +++ b/src/main/java/org/javawebstack/http/router/handler/RequestHandler.java @@ -0,0 +1,9 @@ +package org.javawebstack.http.router.handler; + +import org.javawebstack.http.router.Exchange; + +public interface RequestHandler { + + Object handle(Exchange exchange); + +} diff --git a/src/main/java/org/javawebstack/http/router/handler/RequestInterceptor.java b/src/main/java/org/javawebstack/http/router/handler/RequestInterceptor.java new file mode 100644 index 0000000..ffd1cdb --- /dev/null +++ b/src/main/java/org/javawebstack/http/router/handler/RequestInterceptor.java @@ -0,0 +1,7 @@ +package org.javawebstack.http.router.handler; + +import org.javawebstack.http.router.Exchange; + +public interface RequestInterceptor { + boolean intercept(Exchange exchange); +} \ No newline at end of file diff --git a/src/main/java/org/javawebstack/httpserver/handler/StaticFileHandler.java b/src/main/java/org/javawebstack/http/router/handler/StaticFileHandler.java similarity index 82% rename from src/main/java/org/javawebstack/httpserver/handler/StaticFileHandler.java rename to src/main/java/org/javawebstack/http/router/handler/StaticFileHandler.java index f6fb6a9..fc3e3c7 100644 --- a/src/main/java/org/javawebstack/httpserver/handler/StaticFileHandler.java +++ b/src/main/java/org/javawebstack/http/router/handler/StaticFileHandler.java @@ -1,8 +1,8 @@ -package org.javawebstack.httpserver.handler; +package org.javawebstack.http.router.handler; -import org.javawebstack.httpserver.Exchange; -import org.javawebstack.httpserver.util.MimeType; -import org.javawebstack.httpserver.util.FileProvider; +import org.javawebstack.http.router.Exchange; +import org.javawebstack.http.router.util.MimeType; +import org.javawebstack.http.router.util.FileProvider; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/org/javawebstack/httpserver/handler/WebSocketHandler.java b/src/main/java/org/javawebstack/http/router/handler/WebSocketHandler.java similarity index 71% rename from src/main/java/org/javawebstack/httpserver/handler/WebSocketHandler.java rename to src/main/java/org/javawebstack/http/router/handler/WebSocketHandler.java index a194a40..dcfdbe5 100644 --- a/src/main/java/org/javawebstack/httpserver/handler/WebSocketHandler.java +++ b/src/main/java/org/javawebstack/http/router/handler/WebSocketHandler.java @@ -1,6 +1,6 @@ -package org.javawebstack.httpserver.handler; +package org.javawebstack.http.router.handler; -import org.javawebstack.httpserver.websocket.WebSocket; +import org.javawebstack.http.router.websocket.WebSocket; public interface WebSocketHandler { void onConnect(WebSocket socket); diff --git a/src/main/java/org/javawebstack/httpserver/router/DefaultRouteAutoInjector.java b/src/main/java/org/javawebstack/http/router/router/DefaultRouteAutoInjector.java similarity index 75% rename from src/main/java/org/javawebstack/httpserver/router/DefaultRouteAutoInjector.java rename to src/main/java/org/javawebstack/http/router/router/DefaultRouteAutoInjector.java index 54a2afe..e7c9f5c 100644 --- a/src/main/java/org/javawebstack/httpserver/router/DefaultRouteAutoInjector.java +++ b/src/main/java/org/javawebstack/http/router/router/DefaultRouteAutoInjector.java @@ -1,8 +1,8 @@ -package org.javawebstack.httpserver.router; +package org.javawebstack.http.router.router; -import org.javawebstack.httpserver.Exchange; -import org.javawebstack.httpserver.HTTPMethod; -import org.javawebstack.httpserver.websocket.WebSocket; +import org.javawebstack.http.router.Exchange; +import org.javawebstack.http.router.HTTPMethod; +import org.javawebstack.http.router.websocket.WebSocket; import java.util.Map; diff --git a/src/main/java/org/javawebstack/httpserver/router/Route.java b/src/main/java/org/javawebstack/http/router/router/Route.java similarity index 93% rename from src/main/java/org/javawebstack/httpserver/router/Route.java rename to src/main/java/org/javawebstack/http/router/router/Route.java index 7adaae7..65f0cf0 100644 --- a/src/main/java/org/javawebstack/httpserver/router/Route.java +++ b/src/main/java/org/javawebstack/http/router/router/Route.java @@ -1,10 +1,10 @@ -package org.javawebstack.httpserver.router; +package org.javawebstack.http.router.router; -import org.javawebstack.httpserver.Exchange; -import org.javawebstack.httpserver.HTTPMethod; -import org.javawebstack.httpserver.handler.AfterRequestHandler; -import org.javawebstack.httpserver.handler.RequestHandler; -import org.javawebstack.httpserver.transformer.route.RouteParamTransformerProvider; +import org.javawebstack.http.router.Exchange; +import org.javawebstack.http.router.HTTPMethod; +import org.javawebstack.http.router.handler.AfterRequestHandler; +import org.javawebstack.http.router.handler.RequestHandler; +import org.javawebstack.http.router.transformer.route.RouteParamTransformerProvider; import java.util.HashMap; import java.util.List; diff --git a/src/main/java/org/javawebstack/httpserver/router/RouteAutoInjector.java b/src/main/java/org/javawebstack/http/router/router/RouteAutoInjector.java similarity index 62% rename from src/main/java/org/javawebstack/httpserver/router/RouteAutoInjector.java rename to src/main/java/org/javawebstack/http/router/router/RouteAutoInjector.java index e2ac27e..f984990 100644 --- a/src/main/java/org/javawebstack/httpserver/router/RouteAutoInjector.java +++ b/src/main/java/org/javawebstack/http/router/router/RouteAutoInjector.java @@ -1,6 +1,6 @@ -package org.javawebstack.httpserver.router; +package org.javawebstack.http.router.router; -import org.javawebstack.httpserver.Exchange; +import org.javawebstack.http.router.Exchange; import java.util.Map; diff --git a/src/main/java/org/javawebstack/httpserver/router/RouteBinder.java b/src/main/java/org/javawebstack/http/router/router/RouteBinder.java similarity index 86% rename from src/main/java/org/javawebstack/httpserver/router/RouteBinder.java rename to src/main/java/org/javawebstack/http/router/router/RouteBinder.java index 357f60e..af5c45c 100644 --- a/src/main/java/org/javawebstack/httpserver/router/RouteBinder.java +++ b/src/main/java/org/javawebstack/http/router/router/RouteBinder.java @@ -1,16 +1,16 @@ -package org.javawebstack.httpserver.router; - -import org.javawebstack.httpserver.Exchange; -import org.javawebstack.httpserver.HTTPMethod; -import org.javawebstack.httpserver.HTTPServer; -import org.javawebstack.httpserver.handler.AfterRequestHandler; -import org.javawebstack.httpserver.handler.RequestHandler; -import org.javawebstack.httpserver.handler.WebSocketHandler; -import org.javawebstack.httpserver.router.annotation.PathPrefix; -import org.javawebstack.httpserver.router.annotation.With; -import org.javawebstack.httpserver.router.annotation.params.*; -import org.javawebstack.httpserver.router.annotation.verbs.*; -import org.javawebstack.httpserver.websocket.WebSocket; +package org.javawebstack.http.router.router; + +import org.javawebstack.http.router.Exchange; +import org.javawebstack.http.router.HTTPMethod; +import org.javawebstack.http.router.HTTPRouter; +import org.javawebstack.http.router.handler.AfterRequestHandler; +import org.javawebstack.http.router.handler.RequestHandler; +import org.javawebstack.http.router.handler.WebSocketHandler; +import org.javawebstack.http.router.router.annotation.PathPrefix; +import org.javawebstack.http.router.router.annotation.With; +import org.javawebstack.http.router.router.annotation.params.*; +import org.javawebstack.http.router.router.annotation.verbs.*; +import org.javawebstack.http.router.websocket.WebSocket; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; @@ -21,10 +21,10 @@ public class RouteBinder { - private final HTTPServer server; + private final HTTPRouter router; - public RouteBinder(HTTPServer server) { - this.server = server; + public RouteBinder(HTTPRouter router) { + this.router = router; } public void bind(String globalPrefix, Object controller) { @@ -91,10 +91,10 @@ public Bind(HTTPMethod method, String path) { bindMiddlewares(HTTPMethod.GET, globalPrefix, prefixes, a.value(), middlewares); handler = new WebSocketBindHandler(); for (String prefix : prefixes) - server.webSocket(buildPattern(globalPrefix, prefix, a.value()), handler); + router.webSocket(buildPattern(globalPrefix, prefix, a.value()), handler); websocketHandlers.put(a.name(), handler); } - handler.messageHandler = new BindMapper(server, controller, method); + handler.messageHandler = new BindMapper(router, controller, method); } for (WebSocketConnect a : getAnnotations(WebSocketConnect.class, method)) { WebSocketBindHandler handler = websocketHandlers.get(a.name()); @@ -102,10 +102,10 @@ public Bind(HTTPMethod method, String path) { bindMiddlewares(HTTPMethod.GET, globalPrefix, prefixes, a.value(), middlewares); handler = new WebSocketBindHandler(); for (String prefix : prefixes) - server.webSocket(buildPattern(globalPrefix, prefix, a.value()), handler); + router.webSocket(buildPattern(globalPrefix, prefix, a.value()), handler); websocketHandlers.put(a.name(), handler); } - handler.connectHandler = new BindMapper(server, controller, method); + handler.connectHandler = new BindMapper(router, controller, method); } for (WebSocketClose a : getAnnotations(WebSocketClose.class, method)) { WebSocketBindHandler handler = websocketHandlers.get(a.name()); @@ -113,18 +113,18 @@ public Bind(HTTPMethod method, String path) { bindMiddlewares(HTTPMethod.GET, globalPrefix, prefixes, a.value(), middlewares); handler = new WebSocketBindHandler(); for (String prefix : prefixes) - server.webSocket(buildPattern(globalPrefix, prefix, a.value()), handler); + router.webSocket(buildPattern(globalPrefix, prefix, a.value()), handler); websocketHandlers.put(a.name(), handler); } - handler.closeHandler = new BindMapper(server, controller, method); + handler.closeHandler = new BindMapper(router, controller, method); } //endregion if (binds.size() > 0) { - BindHandler handler = new BindHandler(server, controller, method); + BindHandler handler = new BindHandler(router, controller, method); for (String prefix : prefixes) { for (Bind bind : binds) { - server.route(bind.method, buildPattern(globalPrefix, prefix, bind.path), handler); + router.route(bind.method, buildPattern(globalPrefix, prefix, bind.path), handler); } } } @@ -133,17 +133,17 @@ public Bind(HTTPMethod method, String path) { private void bindMiddlewares(HTTPMethod method, String globalPrefix, List prefixes, String path, List middlewares) { for (String name : middlewares) { - RequestHandler before = server.getBeforeMiddleware(name); - AfterRequestHandler after = server.getAfterMiddleware(name); + RequestHandler before = router.getBeforeMiddleware(name); + AfterRequestHandler after = router.getAfterMiddleware(name); for (String prefix : prefixes) { if (before == null && after == null) { - server.getLogger().warning("Middleware \"" + name + "\" not found!"); + router.getLogger().warning("Middleware \"" + name + "\" not found!"); continue; } if (before != null) - server.beforeRoute(method, buildPattern(globalPrefix, prefix, path), before); + router.beforeRoute(method, buildPattern(globalPrefix, prefix, path), before); if (after != null) - server.afterRoute(method, buildPattern(globalPrefix, prefix, path), after); + router.afterRoute(method, buildPattern(globalPrefix, prefix, path), after); } } } @@ -192,15 +192,15 @@ private static List getMethodsRecursive(Class type) { private static class BindMapper { - private final HTTPServer server; + private final HTTPRouter router; private final Object controller; private final Method method; private final Object[] parameterAnnotations; private final Class[] parameterTypes; private final String[] defaultValues; - public BindMapper(HTTPServer server, Object controller, Method method) { - this.server = server; + public BindMapper(HTTPRouter router, Object controller, Method method) { + this.router = router; this.controller = controller; this.method = method; method.setAccessible(true); @@ -250,7 +250,7 @@ public Object invoke(Exchange exchange, Map extraArgs) { } else if (a instanceof WSReason) { args[i] = extraArgs.get("websocketReason"); } else { - for (RouteAutoInjector autoInjector : server.getRouteAutoInjectors()) { + for (RouteAutoInjector autoInjector : router.getRouteAutoInjectors()) { args[i] = autoInjector.getValue(exchange, extraArgs, (Class) parameterTypes[i]); if (args[i] != null) break; @@ -307,8 +307,8 @@ public void onClose(WebSocket socket, Integer code, String reason) { private static class BindHandler implements RequestHandler { private final BindMapper handler; - public BindHandler(HTTPServer server, Object controller, Method method) { - handler = new BindMapper(server, controller, method); + public BindHandler(HTTPRouter router, Object controller, Method method) { + handler = new BindMapper(router, controller, method); } public Object handle(Exchange exchange) { diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/PathPrefix.java b/src/main/java/org/javawebstack/http/router/router/annotation/PathPrefix.java similarity index 83% rename from src/main/java/org/javawebstack/httpserver/router/annotation/PathPrefix.java rename to src/main/java/org/javawebstack/http/router/router/annotation/PathPrefix.java index 9cc1e0f..a9d5689 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/PathPrefix.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/PathPrefix.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation; +package org.javawebstack.http.router.router.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/With.java b/src/main/java/org/javawebstack/http/router/router/annotation/With.java similarity index 84% rename from src/main/java/org/javawebstack/httpserver/router/annotation/With.java rename to src/main/java/org/javawebstack/http/router/router/annotation/With.java index 2f98b66..f648248 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/With.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/With.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation; +package org.javawebstack.http.router.router.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/params/Attrib.java b/src/main/java/org/javawebstack/http/router/router/annotation/params/Attrib.java similarity index 81% rename from src/main/java/org/javawebstack/httpserver/router/annotation/params/Attrib.java rename to src/main/java/org/javawebstack/http/router/router/annotation/params/Attrib.java index ab9c39b..717b45f 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/params/Attrib.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/params/Attrib.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.params; +package org.javawebstack.http.router.router.annotation.params; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/params/Body.java b/src/main/java/org/javawebstack/http/router/router/annotation/params/Body.java similarity index 80% rename from src/main/java/org/javawebstack/httpserver/router/annotation/params/Body.java rename to src/main/java/org/javawebstack/http/router/router/annotation/params/Body.java index 7ad467e..9a6536b 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/params/Body.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/params/Body.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.params; +package org.javawebstack.http.router.router.annotation.params; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/params/DefaultValue.java b/src/main/java/org/javawebstack/http/router/router/annotation/params/DefaultValue.java similarity index 81% rename from src/main/java/org/javawebstack/httpserver/router/annotation/params/DefaultValue.java rename to src/main/java/org/javawebstack/http/router/router/annotation/params/DefaultValue.java index 3f3fdf3..5b50e98 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/params/DefaultValue.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/params/DefaultValue.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.params; +package org.javawebstack.http.router.router.annotation.params; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/params/Path.java b/src/main/java/org/javawebstack/http/router/router/annotation/params/Path.java similarity index 81% rename from src/main/java/org/javawebstack/httpserver/router/annotation/params/Path.java rename to src/main/java/org/javawebstack/http/router/router/annotation/params/Path.java index d54e9f3..cabbaee 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/params/Path.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/params/Path.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.params; +package org.javawebstack.http.router.router.annotation.params; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/params/Query.java b/src/main/java/org/javawebstack/http/router/router/annotation/params/Query.java similarity index 81% rename from src/main/java/org/javawebstack/httpserver/router/annotation/params/Query.java rename to src/main/java/org/javawebstack/http/router/router/annotation/params/Query.java index df7f4fb..b2d67a6 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/params/Query.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/params/Query.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.params; +package org.javawebstack.http.router.router.annotation.params; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/params/WSCode.java b/src/main/java/org/javawebstack/http/router/router/annotation/params/WSCode.java similarity index 80% rename from src/main/java/org/javawebstack/httpserver/router/annotation/params/WSCode.java rename to src/main/java/org/javawebstack/http/router/router/annotation/params/WSCode.java index a567351..a1b6db8 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/params/WSCode.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/params/WSCode.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.params; +package org.javawebstack.http.router.router.annotation.params; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/params/WSMessage.java b/src/main/java/org/javawebstack/http/router/router/annotation/params/WSMessage.java similarity index 80% rename from src/main/java/org/javawebstack/httpserver/router/annotation/params/WSMessage.java rename to src/main/java/org/javawebstack/http/router/router/annotation/params/WSMessage.java index ce8d160..535e174 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/params/WSMessage.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/params/WSMessage.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.params; +package org.javawebstack.http.router.router.annotation.params; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/params/WSReason.java b/src/main/java/org/javawebstack/http/router/router/annotation/params/WSReason.java similarity index 80% rename from src/main/java/org/javawebstack/httpserver/router/annotation/params/WSReason.java rename to src/main/java/org/javawebstack/http/router/router/annotation/params/WSReason.java index 2ed23dd..1d51877 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/params/WSReason.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/params/WSReason.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.params; +package org.javawebstack.http.router.router.annotation.params; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Delete.java b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Delete.java similarity index 83% rename from src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Delete.java rename to src/main/java/org/javawebstack/http/router/router/annotation/verbs/Delete.java index c0a514c..b7e3051 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Delete.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Delete.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.verbs; +package org.javawebstack.http.router.router.annotation.verbs; import java.lang.annotation.*; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Get.java b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Get.java similarity index 83% rename from src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Get.java rename to src/main/java/org/javawebstack/http/router/router/annotation/verbs/Get.java index 4df7cff..3874204 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Get.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Get.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.verbs; +package org.javawebstack.http.router.router.annotation.verbs; import java.lang.annotation.*; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Head.java b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Head.java similarity index 87% rename from src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Head.java rename to src/main/java/org/javawebstack/http/router/router/annotation/verbs/Head.java index 362a8fc..d3bac81 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Head.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Head.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.verbs; +package org.javawebstack.http.router.router.annotation.verbs; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Options.java b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Options.java similarity index 84% rename from src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Options.java rename to src/main/java/org/javawebstack/http/router/router/annotation/verbs/Options.java index b672118..e767bee 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Options.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Options.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.verbs; +package org.javawebstack.http.router.router.annotation.verbs; import java.lang.annotation.*; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Patch.java b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Patch.java similarity index 83% rename from src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Patch.java rename to src/main/java/org/javawebstack/http/router/router/annotation/verbs/Patch.java index 40fc8fc..845093c 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Patch.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Patch.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.verbs; +package org.javawebstack.http.router.router.annotation.verbs; import java.lang.annotation.*; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Post.java b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Post.java similarity index 83% rename from src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Post.java rename to src/main/java/org/javawebstack/http/router/router/annotation/verbs/Post.java index e96d49c..53812b1 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Post.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Post.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.verbs; +package org.javawebstack.http.router.router.annotation.verbs; import java.lang.annotation.*; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Put.java b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Put.java similarity index 83% rename from src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Put.java rename to src/main/java/org/javawebstack/http/router/router/annotation/verbs/Put.java index f0f87b7..d0518fc 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Put.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Put.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.verbs; +package org.javawebstack.http.router.router.annotation.verbs; import java.lang.annotation.*; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Trace.java b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Trace.java similarity index 87% rename from src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Trace.java rename to src/main/java/org/javawebstack/http/router/router/annotation/verbs/Trace.java index 79fea31..8b97ac7 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/Trace.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/Trace.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.verbs; +package org.javawebstack.http.router.router.annotation.verbs; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/WebSocketClose.java b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/WebSocketClose.java similarity index 85% rename from src/main/java/org/javawebstack/httpserver/router/annotation/verbs/WebSocketClose.java rename to src/main/java/org/javawebstack/http/router/router/annotation/verbs/WebSocketClose.java index 7dfe93d..829e655 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/WebSocketClose.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/WebSocketClose.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.verbs; +package org.javawebstack.http.router.router.annotation.verbs; import java.lang.annotation.*; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/WebSocketConnect.java b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/WebSocketConnect.java similarity index 86% rename from src/main/java/org/javawebstack/httpserver/router/annotation/verbs/WebSocketConnect.java rename to src/main/java/org/javawebstack/http/router/router/annotation/verbs/WebSocketConnect.java index efbf2fa..a7d6600 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/WebSocketConnect.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/WebSocketConnect.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.verbs; +package org.javawebstack.http.router.router.annotation.verbs; import java.lang.annotation.*; diff --git a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/WebSocketMessage.java b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/WebSocketMessage.java similarity index 86% rename from src/main/java/org/javawebstack/httpserver/router/annotation/verbs/WebSocketMessage.java rename to src/main/java/org/javawebstack/http/router/router/annotation/verbs/WebSocketMessage.java index ebdf816..440af15 100644 --- a/src/main/java/org/javawebstack/httpserver/router/annotation/verbs/WebSocketMessage.java +++ b/src/main/java/org/javawebstack/http/router/router/annotation/verbs/WebSocketMessage.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.router.annotation.verbs; +package org.javawebstack.http.router.router.annotation.verbs; import java.lang.annotation.*; diff --git a/src/main/java/org/javawebstack/httpserver/transformer/response/JsonResponseTransformer.java b/src/main/java/org/javawebstack/http/router/transformer/response/JsonResponseTransformer.java similarity index 54% rename from src/main/java/org/javawebstack/httpserver/transformer/response/JsonResponseTransformer.java rename to src/main/java/org/javawebstack/http/router/transformer/response/JsonResponseTransformer.java index 99a8f9c..75a5bf1 100644 --- a/src/main/java/org/javawebstack/httpserver/transformer/response/JsonResponseTransformer.java +++ b/src/main/java/org/javawebstack/http/router/transformer/response/JsonResponseTransformer.java @@ -1,19 +1,19 @@ -package org.javawebstack.httpserver.transformer.response; +package org.javawebstack.http.router.transformer.response; -import org.javawebstack.abstractdata.AbstractMapper; -import org.javawebstack.abstractdata.NamingPolicy; -import org.javawebstack.httpserver.Exchange; +import org.javawebstack.abstractdata.mapper.Mapper; +import org.javawebstack.abstractdata.mapper.naming.NamingPolicy; +import org.javawebstack.http.router.Exchange; public class JsonResponseTransformer implements ResponseTransformer { - private final AbstractMapper mapper; + private final Mapper mapper; private boolean ignoreStrings = false; public JsonResponseTransformer() { - this(new AbstractMapper().setNamingPolicy(NamingPolicy.SNAKE_CASE)); + this(new Mapper().namingPolicy(NamingPolicy.SNAKE_CASE)); } - public JsonResponseTransformer(AbstractMapper mapper) { + public JsonResponseTransformer(Mapper mapper) { this.mapper = mapper; } @@ -27,6 +27,7 @@ public String transform(Exchange exchange, Object object) { return null; if (ignoreStrings && object instanceof String) return null; - return mapper.toAbstract(object).toJsonString(); + return mapper.map(object).toJsonString(); } + } diff --git a/src/main/java/org/javawebstack/httpserver/transformer/response/ResponseTransformer.java b/src/main/java/org/javawebstack/http/router/transformer/response/ResponseTransformer.java similarity index 80% rename from src/main/java/org/javawebstack/httpserver/transformer/response/ResponseTransformer.java rename to src/main/java/org/javawebstack/http/router/transformer/response/ResponseTransformer.java index cb4566b..35aef87 100644 --- a/src/main/java/org/javawebstack/httpserver/transformer/response/ResponseTransformer.java +++ b/src/main/java/org/javawebstack/http/router/transformer/response/ResponseTransformer.java @@ -1,6 +1,6 @@ -package org.javawebstack.httpserver.transformer.response; +package org.javawebstack.http.router.transformer.response; -import org.javawebstack.httpserver.Exchange; +import org.javawebstack.http.router.Exchange; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java b/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java new file mode 100644 index 0000000..0d5e495 --- /dev/null +++ b/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java @@ -0,0 +1,52 @@ +package org.javawebstack.http.router.transformer.response; + +import org.javawebstack.abstractdata.mapper.Mapper; +import org.javawebstack.abstractdata.mapper.naming.NamingPolicy; +import org.javawebstack.http.router.Exchange; + +public class SerializedResponseTransformer implements ResponseTransformer { + + private final Mapper mapper; + private boolean ignoreStrings; + + public SerializedResponseTransformer() { + this((new Mapper()).namingPolicy(NamingPolicy.SNAKE_CASE)); + } + + public SerializedResponseTransformer(Mapper mapper) { + this.ignoreStrings = false; + this.mapper = mapper; + } + + public SerializedResponseTransformer ignoreStrings() { + this.ignoreStrings = true; + return this; + } + + public String transform(Exchange exchange, Object object) { + if (object instanceof byte[]) { + return null; + } else { + if (this.ignoreStrings && object instanceof String) + return null; + String accept = exchange.header("Accept"); + + if (accept != null) { + switch (accept.toLowerCase()) { + case "application/x-yaml": + case "application/yaml": + case "text/yaml": + case "text/x-yaml": + exchange.contentType(accept); + return this.mapper.map(object).toYaml(); + case "application/x-www-form-urlencoded": + exchange.contentType(accept); + return this.mapper.map(object).toFormDataString(); + } + } + + exchange.contentType("application/json"); + return this.mapper.map(object).toJsonString(); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/javawebstack/httpserver/transformer/route/DefaultRouteParamTransformer.java b/src/main/java/org/javawebstack/http/router/transformer/route/DefaultRouteParamTransformer.java similarity index 96% rename from src/main/java/org/javawebstack/httpserver/transformer/route/DefaultRouteParamTransformer.java rename to src/main/java/org/javawebstack/http/router/transformer/route/DefaultRouteParamTransformer.java index 6c60621..86641c3 100644 --- a/src/main/java/org/javawebstack/httpserver/transformer/route/DefaultRouteParamTransformer.java +++ b/src/main/java/org/javawebstack/http/router/transformer/route/DefaultRouteParamTransformer.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.transformer.route; +package org.javawebstack.http.router.transformer.route; import java.util.UUID; diff --git a/src/main/java/org/javawebstack/httpserver/transformer/route/RouteParamTransformFunction.java b/src/main/java/org/javawebstack/http/router/transformer/route/RouteParamTransformFunction.java similarity index 51% rename from src/main/java/org/javawebstack/httpserver/transformer/route/RouteParamTransformFunction.java rename to src/main/java/org/javawebstack/http/router/transformer/route/RouteParamTransformFunction.java index 56cbc50..a2a2fcb 100644 --- a/src/main/java/org/javawebstack/httpserver/transformer/route/RouteParamTransformFunction.java +++ b/src/main/java/org/javawebstack/http/router/transformer/route/RouteParamTransformFunction.java @@ -1,6 +1,6 @@ -package org.javawebstack.httpserver.transformer.route; +package org.javawebstack.http.router.transformer.route; -import org.javawebstack.httpserver.Exchange; +import org.javawebstack.http.router.Exchange; public interface RouteParamTransformFunction { Object transform(Exchange exchange, Object source); diff --git a/src/main/java/org/javawebstack/httpserver/transformer/route/RouteParamTransformer.java b/src/main/java/org/javawebstack/http/router/transformer/route/RouteParamTransformer.java similarity index 94% rename from src/main/java/org/javawebstack/httpserver/transformer/route/RouteParamTransformer.java rename to src/main/java/org/javawebstack/http/router/transformer/route/RouteParamTransformer.java index 827e40a..3956805 100644 --- a/src/main/java/org/javawebstack/httpserver/transformer/route/RouteParamTransformer.java +++ b/src/main/java/org/javawebstack/http/router/transformer/route/RouteParamTransformer.java @@ -1,6 +1,6 @@ -package org.javawebstack.httpserver.transformer.route; +package org.javawebstack.http.router.transformer.route; -import org.javawebstack.httpserver.Exchange; +import org.javawebstack.http.router.Exchange; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/org/javawebstack/httpserver/transformer/route/RouteParamTransformerProvider.java b/src/main/java/org/javawebstack/http/router/transformer/route/RouteParamTransformerProvider.java similarity index 87% rename from src/main/java/org/javawebstack/httpserver/transformer/route/RouteParamTransformerProvider.java rename to src/main/java/org/javawebstack/http/router/transformer/route/RouteParamTransformerProvider.java index 03f89a9..c23cff7 100644 --- a/src/main/java/org/javawebstack/httpserver/transformer/route/RouteParamTransformerProvider.java +++ b/src/main/java/org/javawebstack/http/router/transformer/route/RouteParamTransformerProvider.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.transformer.route; +package org.javawebstack.http.router.transformer.route; import java.util.List; diff --git a/src/main/java/org/javawebstack/httpserver/util/DirectoryFileProvider.java b/src/main/java/org/javawebstack/http/router/util/DirectoryFileProvider.java similarity index 95% rename from src/main/java/org/javawebstack/httpserver/util/DirectoryFileProvider.java rename to src/main/java/org/javawebstack/http/router/util/DirectoryFileProvider.java index 56bb804..60619c6 100644 --- a/src/main/java/org/javawebstack/httpserver/util/DirectoryFileProvider.java +++ b/src/main/java/org/javawebstack/http/router/util/DirectoryFileProvider.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.util; +package org.javawebstack.http.router.util; import java.io.File; import java.io.FileInputStream; diff --git a/src/main/java/org/javawebstack/httpserver/util/FileProvider.java b/src/main/java/org/javawebstack/http/router/util/FileProvider.java similarity index 70% rename from src/main/java/org/javawebstack/httpserver/util/FileProvider.java rename to src/main/java/org/javawebstack/http/router/util/FileProvider.java index 2aefd1a..a07cbaa 100644 --- a/src/main/java/org/javawebstack/httpserver/util/FileProvider.java +++ b/src/main/java/org/javawebstack/http/router/util/FileProvider.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.util; +package org.javawebstack.http.router.util; import java.io.InputStream; diff --git a/src/main/java/org/javawebstack/httpserver/util/MimeType.java b/src/main/java/org/javawebstack/http/router/util/MimeType.java similarity index 98% rename from src/main/java/org/javawebstack/httpserver/util/MimeType.java rename to src/main/java/org/javawebstack/http/router/util/MimeType.java index 2293582..54bfba3 100644 --- a/src/main/java/org/javawebstack/httpserver/util/MimeType.java +++ b/src/main/java/org/javawebstack/http/router/util/MimeType.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.util; +package org.javawebstack.http.router.util; import java.util.Arrays; import java.util.List; diff --git a/src/main/java/org/javawebstack/httpserver/util/ResourceFileProvider.java b/src/main/java/org/javawebstack/http/router/util/ResourceFileProvider.java similarity index 93% rename from src/main/java/org/javawebstack/httpserver/util/ResourceFileProvider.java rename to src/main/java/org/javawebstack/http/router/util/ResourceFileProvider.java index b9b4ae9..7cda378 100644 --- a/src/main/java/org/javawebstack/httpserver/util/ResourceFileProvider.java +++ b/src/main/java/org/javawebstack/http/router/util/ResourceFileProvider.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.util; +package org.javawebstack.http.router.util; import java.io.InputStream; diff --git a/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java b/src/main/java/org/javawebstack/http/router/util/websocket/WebSocketFrame.java similarity index 98% rename from src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java rename to src/main/java/org/javawebstack/http/router/util/websocket/WebSocketFrame.java index 0efddd6..49ee56a 100644 --- a/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketFrame.java +++ b/src/main/java/org/javawebstack/http/router/util/websocket/WebSocketFrame.java @@ -1,4 +1,4 @@ -package org.javawebstack.httpserver.util.websocket; +package org.javawebstack.http.router.util.websocket; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketUtil.java b/src/main/java/org/javawebstack/http/router/util/websocket/WebSocketUtil.java similarity index 96% rename from src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketUtil.java rename to src/main/java/org/javawebstack/http/router/util/websocket/WebSocketUtil.java index f1e0a4a..e7467d8 100644 --- a/src/main/java/org/javawebstack/httpserver/util/websocket/WebSocketUtil.java +++ b/src/main/java/org/javawebstack/http/router/util/websocket/WebSocketUtil.java @@ -1,7 +1,7 @@ -package org.javawebstack.httpserver.util.websocket; +package org.javawebstack.http.router.util.websocket; -import org.javawebstack.httpserver.HTTPStatus; -import org.javawebstack.httpserver.adapter.IHTTPSocket; +import org.javawebstack.http.router.HTTPStatus; +import org.javawebstack.http.router.adapter.IHTTPSocket; import java.io.IOException; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/javawebstack/httpserver/websocket/InternalWebSocketRequestHandler.java b/src/main/java/org/javawebstack/http/router/websocket/InternalWebSocketRequestHandler.java similarity index 83% rename from src/main/java/org/javawebstack/httpserver/websocket/InternalWebSocketRequestHandler.java rename to src/main/java/org/javawebstack/http/router/websocket/InternalWebSocketRequestHandler.java index 8a70253..3b2efbf 100644 --- a/src/main/java/org/javawebstack/httpserver/websocket/InternalWebSocketRequestHandler.java +++ b/src/main/java/org/javawebstack/http/router/websocket/InternalWebSocketRequestHandler.java @@ -1,11 +1,11 @@ -package org.javawebstack.httpserver.websocket; +package org.javawebstack.http.router.websocket; -import org.javawebstack.httpserver.Exchange; -import org.javawebstack.httpserver.adapter.IHTTPSocket; -import org.javawebstack.httpserver.handler.RequestHandler; -import org.javawebstack.httpserver.handler.WebSocketHandler; -import org.javawebstack.httpserver.util.websocket.WebSocketFrame; -import org.javawebstack.httpserver.util.websocket.WebSocketUtil; +import org.javawebstack.http.router.Exchange; +import org.javawebstack.http.router.adapter.IHTTPSocket; +import org.javawebstack.http.router.handler.RequestHandler; +import org.javawebstack.http.router.handler.WebSocketHandler; +import org.javawebstack.http.router.util.websocket.WebSocketFrame; +import org.javawebstack.http.router.util.websocket.WebSocketUtil; import java.io.IOException; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/org/javawebstack/httpserver/websocket/WebSocket.java b/src/main/java/org/javawebstack/http/router/websocket/WebSocket.java similarity index 83% rename from src/main/java/org/javawebstack/httpserver/websocket/WebSocket.java rename to src/main/java/org/javawebstack/http/router/websocket/WebSocket.java index 014b0f2..36534a4 100644 --- a/src/main/java/org/javawebstack/httpserver/websocket/WebSocket.java +++ b/src/main/java/org/javawebstack/http/router/websocket/WebSocket.java @@ -1,7 +1,7 @@ -package org.javawebstack.httpserver.websocket; +package org.javawebstack.http.router.websocket; -import org.javawebstack.httpserver.Exchange; -import org.javawebstack.httpserver.util.websocket.WebSocketUtil; +import org.javawebstack.http.router.Exchange; +import org.javawebstack.http.router.util.websocket.WebSocketUtil; import java.io.IOException; diff --git a/src/main/java/org/javawebstack/httpserver/handler/RequestHandler.java b/src/main/java/org/javawebstack/httpserver/handler/RequestHandler.java deleted file mode 100644 index 257e4c6..0000000 --- a/src/main/java/org/javawebstack/httpserver/handler/RequestHandler.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.javawebstack.httpserver.handler; - -import org.javawebstack.httpserver.Exchange; - -public interface RequestHandler { - - Object handle(Exchange exchange); - -} diff --git a/src/main/java/org/javawebstack/httpserver/handler/RequestInterceptor.java b/src/main/java/org/javawebstack/httpserver/handler/RequestInterceptor.java deleted file mode 100644 index e125c08..0000000 --- a/src/main/java/org/javawebstack/httpserver/handler/RequestInterceptor.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.javawebstack.httpserver.handler; - -import org.javawebstack.httpserver.Exchange; - -public interface RequestInterceptor { - boolean intercept(Exchange exchange); -} \ No newline at end of file From 08fc77f94b3544508674e6851479ef99648f89fb Mon Sep 17 00:00:00 2001 From: JanHolger Date: Mon, 4 Sep 2023 00:50:01 +0200 Subject: [PATCH 13/24] Implemented multipart support --- pom.xml | 5 + .../javawebstack/http/router/Exchange.java | 72 ++++++++-- .../javawebstack/http/router/HTTPRouter.java | 129 ++++++++++-------- .../http/router/multipart/Part.java | 97 +++++++++++++ .../multipart/content/ByteArrayContent.java | 24 ++++ .../multipart/content/FilePartContent.java | 31 +++++ .../multipart/content/InMemoryCache.java | 34 +++++ .../router/multipart/content/PartContent.java | 10 ++ .../multipart/content/PartContentCache.java | 28 ++++ .../multipart/content/TmpFolderCache.java | 49 +++++++ .../http/router/util/HeaderValue.java | 32 +++++ 11 files changed, 446 insertions(+), 65 deletions(-) create mode 100644 src/main/java/org/javawebstack/http/router/multipart/Part.java create mode 100644 src/main/java/org/javawebstack/http/router/multipart/content/ByteArrayContent.java create mode 100644 src/main/java/org/javawebstack/http/router/multipart/content/FilePartContent.java create mode 100644 src/main/java/org/javawebstack/http/router/multipart/content/InMemoryCache.java create mode 100644 src/main/java/org/javawebstack/http/router/multipart/content/PartContent.java create mode 100644 src/main/java/org/javawebstack/http/router/multipart/content/PartContentCache.java create mode 100644 src/main/java/org/javawebstack/http/router/multipart/content/TmpFolderCache.java create mode 100644 src/main/java/org/javawebstack/http/router/util/HeaderValue.java diff --git a/pom.xml b/pom.xml index fe78071..8857d15 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,11 @@ reflections 0.10.2 + + commons-fileupload + commons-fileupload + 1.5 + diff --git a/src/main/java/org/javawebstack/http/router/Exchange.java b/src/main/java/org/javawebstack/http/router/Exchange.java index 11c6122..b319eab 100644 --- a/src/main/java/org/javawebstack/http/router/Exchange.java +++ b/src/main/java/org/javawebstack/http/router/Exchange.java @@ -3,15 +3,18 @@ import org.javawebstack.abstractdata.*; import org.javawebstack.abstractdata.mapper.Mapper; import org.javawebstack.http.router.adapter.IHTTPSocket; +import org.javawebstack.http.router.multipart.Part; +import org.javawebstack.http.router.multipart.content.InMemoryCache; +import org.javawebstack.http.router.multipart.content.PartContentCache; +import org.javawebstack.http.router.multipart.content.TmpFolderCache; +import org.javawebstack.http.router.util.HeaderValue; import org.javawebstack.http.router.util.MimeType; import org.javawebstack.validator.ValidationContext; import org.javawebstack.validator.ValidationException; import org.javawebstack.validator.ValidationResult; import org.javawebstack.validator.Validator; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; @@ -32,6 +35,7 @@ public static Exchange current() { private final AbstractObject queryParameters; private final IHTTPSocket socket; private final Map attributes = new HashMap<>(); + private List parts = null; public Exchange(HTTPRouter router, IHTTPSocket socket) { this.router = router; @@ -301,12 +305,64 @@ private HTTPMethod getRequestMethodFromSocket(IHTTPSocket socket) { return socket.getRequestMethod(); } - public MimeType getMimeType() { - String contentType = getContentType().toLowerCase(); - if (contentType.contains(";")) { - contentType = contentType.split(";")[0].trim(); + /** + * Use with CAUTION! This will load all parts into memory + * @return + */ + public Exchange enableMultipart() { + return enableMultipart(new InMemoryCache()); + } + + /** + * Use with CAUTION! This will run an expensive cleanup routine on each call and store files on disk + * @param tmpFolder + * @return + */ + public Exchange enableMultipart(File tmpFolder) { + PartContentCache cache = new TmpFolderCache(tmpFolder); + cache.cleanup(); + return enableMultipart(cache); + } + + public Exchange enableMultipart(PartContentCache cache) { + if(parts != null) + return this; + HeaderValue contentType = new HeaderValue(getContentType()); + if(!contentType.getValue().toLowerCase(Locale.ROOT).equals("multipart/form-data")) + return this; + body = new byte[0]; + byte[] boundary = contentType.getDirectives().get("boundary").getBytes(); + try { + InputStream stream; + if(body != null) { + stream = new ByteArrayInputStream(body); + } else { + stream = socket.getInputStream(); + } + parts = Part.parse(stream, boundary, cache); + } catch (Exception ex) { + parts = new ArrayList<>(); } + return this; + } + + public boolean isMultipart() { + return parts != null; + } + + public List getParts() { + if(!isMultipart()) + throw new IllegalStateException("This is not a multipart request or multipart parsing is not enabled. Use enableMultipart to enable it or check with isMultipart"); + return parts; + } - return MimeType.byMimeType(contentType); + public Part getPart(String name) { + return getParts().stream().filter(p -> name.equals(p.getName())).findFirst().orElse(null); } + + public MimeType getMimeType() { + HeaderValue contentType = new HeaderValue(getContentType()); + return MimeType.byMimeType(contentType.getValue().toLowerCase(Locale.ROOT)); + } + } diff --git a/src/main/java/org/javawebstack/http/router/HTTPRouter.java b/src/main/java/org/javawebstack/http/router/HTTPRouter.java index f79e5f5..cfd67c6 100644 --- a/src/main/java/org/javawebstack/http/router/HTTPRouter.java +++ b/src/main/java/org/javawebstack/http/router/HTTPRouter.java @@ -4,6 +4,7 @@ import org.javawebstack.abstractdata.mapper.naming.NamingPolicy; import org.javawebstack.http.router.adapter.IHTTPSocketServer; import org.javawebstack.http.router.handler.*; +import org.javawebstack.http.router.multipart.content.PartContentCache; import org.javawebstack.http.router.router.DefaultRouteAutoInjector; import org.javawebstack.http.router.router.Route; import org.javawebstack.http.router.router.RouteAutoInjector; @@ -43,6 +44,7 @@ public class HTTPRouter implements RouteParamTransformerProvider { private final Map afterMiddleware = new HashMap<>(); private Function, Object> controllerInitiator = this::defaultControllerInitiator; private boolean formMethods = true; + private PartContentCache multipartContentCache; public HTTPRouter(IHTTPSocketServer server) { this.server = server; @@ -300,78 +302,86 @@ public void stop() { public void execute(Exchange exchange) { Exchange.exchanges.set(exchange); try { - Object response = null; try { - for (RequestInterceptor ic : beforeInterceptors) { - if (ic.intercept(exchange)) { - exchange.close(); - Exchange.exchanges.remove(); - return; - } - } - middlewares: - for (Route route : beforeRoutes) { - Map pathVariables = route.match(exchange); - if (pathVariables == null) - continue; - exchange.getPathVariables().putAll(pathVariables); - for (RequestHandler handler : route.getHandlers()) { - try { - response = handler.handle(exchange); - } catch (Throwable ex) { - response = exceptionHandler.handle(exchange, ex); + if(multipartContentCache != null) + exchange.enableMultipart(multipartContentCache); + Object response = null; + try { + for (RequestInterceptor ic : beforeInterceptors) { + if (ic.intercept(exchange)) { + exchange.close(); + Exchange.exchanges.remove(); + return; } - if (response != null) - break middlewares; } - } - exchange.getPathVariables().clear(); - if (response == null) { - routes: - for (Route route : routes) { + middlewares: + for (Route route : beforeRoutes) { Map pathVariables = route.match(exchange); if (pathVariables == null) continue; exchange.getPathVariables().putAll(pathVariables); for (RequestHandler handler : route.getHandlers()) { - response = handler.handle(exchange); - if (exchange.getMethod() == HTTPMethod.WEBSOCKET) { - Exchange.exchanges.remove(); - return; + try { + response = handler.handle(exchange); + } catch (Throwable ex) { + response = exceptionHandler.handle(exchange, ex); } if (response != null) - break routes; + break middlewares; + } + } + exchange.getPathVariables().clear(); + if (response == null) { + routes: + for (Route route : routes) { + Map pathVariables = route.match(exchange); + if (pathVariables == null) + continue; + exchange.getPathVariables().putAll(pathVariables); + for (RequestHandler handler : route.getHandlers()) { + response = handler.handle(exchange); + if (exchange.getMethod() == HTTPMethod.WEBSOCKET) { + Exchange.exchanges.remove(); + return; + } + if (response != null) + break routes; + } + exchange.getPathVariables().clear(); } - exchange.getPathVariables().clear(); } + } catch (Throwable ex) { + response = exceptionHandler.handle(exchange, ex); } - } catch (Throwable ex) { - response = exceptionHandler.handle(exchange, ex); - } - if (response == null) - response = notFoundHandler.handle(exchange); - exchange.getPathVariables().clear(); - for (Route route : afterRoutes) { - Map pathVariables = route.match(exchange); - if (pathVariables == null) - continue; - exchange.getPathVariables().putAll(pathVariables); - for (AfterRequestHandler handler : route.getAfterHandlers()) - response = handler.handleAfter(exchange, response); + if (response == null) + response = notFoundHandler.handle(exchange); exchange.getPathVariables().clear(); + for (Route route : afterRoutes) { + Map pathVariables = route.match(exchange); + if (pathVariables == null) + continue; + exchange.getPathVariables().putAll(pathVariables); + for (AfterRequestHandler handler : route.getAfterHandlers()) + response = handler.handleAfter(exchange, response); + exchange.getPathVariables().clear(); + } + if (response != null) + exchange.write(transformResponse(exchange, response)); + if (exchange.getMethod() != HTTPMethod.WEBSOCKET) + exchange.close(); + Exchange.exchanges.remove(); + return; + } catch (Throwable ex) { + try { + exchange.write(transformResponse(exchange, exceptionHandler.handle(exchange, ex))); + } catch (Throwable ex2) { + exchange.status(500); + logger.log(Level.SEVERE, ex2, () -> "An error occured in the exception handler!"); + } } - if (response != null) - exchange.write(transformResponse(exchange, response)); - if (exchange.getMethod() != HTTPMethod.WEBSOCKET) - exchange.close(); - Exchange.exchanges.remove(); - return; - } catch (Throwable ex) { - try { - exchange.write(transformResponse(exchange, exceptionHandler.handle(exchange, ex))); - } catch (Throwable ex2) { - logger.log(Level.SEVERE, ex2, () -> "An error occured in the exception handler!"); - } + } catch (Exception ex) { + // This should never be reached, just added this as a precaution + logger.log(Level.SEVERE, ex, () -> "An unexpected error occured in the exception handling of the exception handler (probably while setting the status)"); } Exchange.exchanges.remove(); exchange.close(); @@ -411,6 +421,11 @@ public ExceptionHandler getExceptionHandler() { return exceptionHandler; } + public HTTPRouter enableMultipart(PartContentCache cache) { + this.multipartContentCache = cache; + return this; + } + public boolean isFormMethods() { return formMethods; } diff --git a/src/main/java/org/javawebstack/http/router/multipart/Part.java b/src/main/java/org/javawebstack/http/router/multipart/Part.java new file mode 100644 index 0000000..c84f185 --- /dev/null +++ b/src/main/java/org/javawebstack/http/router/multipart/Part.java @@ -0,0 +1,97 @@ +package org.javawebstack.http.router.multipart; + +import org.apache.commons.fileupload.MultipartStream; +import org.javawebstack.http.router.Exchange; +import org.javawebstack.http.router.multipart.content.PartContent; +import org.javawebstack.http.router.multipart.content.PartContentCache; +import org.javawebstack.http.router.util.HeaderValue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class Part { + + final Map headers; + final PartContent content; + String name; + String contentType; + + public Part(Map headers, PartContent content) { + this.headers = headers; + this.content = content; + if(headers.containsKey("content-disposition")) { + HeaderValue contentDisposition = new HeaderValue(headers.get("content-disposition")); + if(contentDisposition.getDirectives().containsKey("name")) + name = contentDisposition.getDirectives().get("name"); + } + if(headers.containsKey("content-type")) { + contentType = new HeaderValue(headers.get("content-type")).getValue(); + } + } + + public static List parse(InputStream inputStream, byte[] boundary, PartContentCache cache) throws IOException { + MultipartStream stream = new MultipartStream(inputStream, boundary, 1024, null); + List parts = new ArrayList<>(); + if(stream.skipPreamble()) { + do { + Map headers = Stream.of( + stream.readHeaders().split("\r?\n") + ) + .filter(l -> !l.trim().isEmpty()) + .map(l -> l.split(": ", 2)) + .collect(Collectors.toMap( + a -> a[0].toLowerCase(Locale.ROOT), + a -> a.length == 2 ? a[1] : "" + )); + PartContent c = cache.store(os -> { + try { + stream.readBodyData(os); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + parts.add(new Part(headers, c)); + } while (stream.readBoundary()); + } + return parts; + } + + public Map getHeaders() { + return headers; + } + + public InputStream getContentStream() { + return content.read(); + } + + public String getName() { + return name; + } + + public String getContentType() { + return contentType; + } + + public byte[] getContentBytes() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream stream = getContentStream(); + int b; + try { + while ((b = stream.read()) != -1) + baos.write(b); + stream.close(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + return baos.toByteArray(); + } + + public void discard() { + content.discard(); + } + +} diff --git a/src/main/java/org/javawebstack/http/router/multipart/content/ByteArrayContent.java b/src/main/java/org/javawebstack/http/router/multipart/content/ByteArrayContent.java new file mode 100644 index 0000000..927a28f --- /dev/null +++ b/src/main/java/org/javawebstack/http/router/multipart/content/ByteArrayContent.java @@ -0,0 +1,24 @@ +package org.javawebstack.http.router.multipart.content; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +public class ByteArrayContent implements PartContent { + + private byte[] data; + + public ByteArrayContent(byte[] data) { + this.data = data; + } + + public InputStream read() { + if(data == null) + throw new RuntimeException("Data has already been discarded"); + return new ByteArrayInputStream(data); + } + + public void discard() { + data = null; + } + +} diff --git a/src/main/java/org/javawebstack/http/router/multipart/content/FilePartContent.java b/src/main/java/org/javawebstack/http/router/multipart/content/FilePartContent.java new file mode 100644 index 0000000..9a1b810 --- /dev/null +++ b/src/main/java/org/javawebstack/http/router/multipart/content/FilePartContent.java @@ -0,0 +1,31 @@ +package org.javawebstack.http.router.multipart.content; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; + +public class FilePartContent implements PartContent { + + private final File file; + + public FilePartContent(File file) { + this.file = file; + } + + public InputStream read() { + if(!file.exists()) + throw new RuntimeException("File does not exist anymore"); + try { + return new FileInputStream(file); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } + + public void discard() { + if(file.exists()) + file.delete(); + } + +} diff --git a/src/main/java/org/javawebstack/http/router/multipart/content/InMemoryCache.java b/src/main/java/org/javawebstack/http/router/multipart/content/InMemoryCache.java new file mode 100644 index 0000000..eef2340 --- /dev/null +++ b/src/main/java/org/javawebstack/http/router/multipart/content/InMemoryCache.java @@ -0,0 +1,34 @@ +package org.javawebstack.http.router.multipart.content; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.function.Consumer; + +public class InMemoryCache implements PartContentCache { + + public PartContent store(InputStream stream) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int b; + try { + while ((b = stream.read()) != -1) + baos.write(b); + stream.close(); + return new ByteArrayContent(baos.toByteArray()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public PartContent store(Consumer streamConsumer) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + streamConsumer.accept(baos); + return new ByteArrayContent(baos.toByteArray()); + } + + public void cleanup() { + // Nothing to cleanup + } + +} diff --git a/src/main/java/org/javawebstack/http/router/multipart/content/PartContent.java b/src/main/java/org/javawebstack/http/router/multipart/content/PartContent.java new file mode 100644 index 0000000..9975c21 --- /dev/null +++ b/src/main/java/org/javawebstack/http/router/multipart/content/PartContent.java @@ -0,0 +1,10 @@ +package org.javawebstack.http.router.multipart.content; + +import java.io.InputStream; + +public interface PartContent { + + InputStream read(); + void discard(); + +} diff --git a/src/main/java/org/javawebstack/http/router/multipart/content/PartContentCache.java b/src/main/java/org/javawebstack/http/router/multipart/content/PartContentCache.java new file mode 100644 index 0000000..3be1b2d --- /dev/null +++ b/src/main/java/org/javawebstack/http/router/multipart/content/PartContentCache.java @@ -0,0 +1,28 @@ +package org.javawebstack.http.router.multipart.content; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.function.Consumer; + +public interface PartContentCache { + + default PartContent store(InputStream stream) { + return store(os -> { + int b; + try { + while ((b = stream.read()) != -1) + os.write(b); + os.close(); + stream.close(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + }); + } + + PartContent store(Consumer streamConsumer); + + void cleanup(); + +} diff --git a/src/main/java/org/javawebstack/http/router/multipart/content/TmpFolderCache.java b/src/main/java/org/javawebstack/http/router/multipart/content/TmpFolderCache.java new file mode 100644 index 0000000..ea19508 --- /dev/null +++ b/src/main/java/org/javawebstack/http/router/multipart/content/TmpFolderCache.java @@ -0,0 +1,49 @@ +package org.javawebstack.http.router.multipart.content; + +import java.io.*; +import java.util.UUID; +import java.util.function.Consumer; + +public class TmpFolderCache implements PartContentCache { + + private final File folder; + private final long cacheLifetime = 60000; + + public TmpFolderCache(File folder) { + this.folder = folder; + if(!folder.exists()) + folder.mkdirs(); + } + + public PartContent store(Consumer streamConsumer) { + String id = UUID.randomUUID().toString(); + File file = new File(folder, id + ".tmp"); + try { + FileOutputStream fos = new FileOutputStream(file); + file.deleteOnExit(); + streamConsumer.accept(fos); + fos.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + return new FilePartContent(file); + } + + public void cleanup() { + for(File file : folder.listFiles()) { + if(file.isDirectory() || file.getName().endsWith(".tmp")) + continue; + long lifetime = System.currentTimeMillis() - file.lastModified(); + if(lifetime < cacheLifetime) + continue; + String key = file.getName().substring(0, file.getName().length()-4); + try { + UUID.fromString(key); + } catch (IllegalArgumentException ignored) { + continue; + } + file.delete(); + } + } + +} diff --git a/src/main/java/org/javawebstack/http/router/util/HeaderValue.java b/src/main/java/org/javawebstack/http/router/util/HeaderValue.java new file mode 100644 index 0000000..b464beb --- /dev/null +++ b/src/main/java/org/javawebstack/http/router/util/HeaderValue.java @@ -0,0 +1,32 @@ +package org.javawebstack.http.router.util; + +import java.util.HashMap; +import java.util.Map; + +public class HeaderValue { + + final String value; + final Map directives = new HashMap<>(); + + public HeaderValue(String source) { + String[] spl = source.split("; "); + value = spl[0]; + for(int i=1; i getDirectives() { + return directives; + } + +} From 03800c95d3a2c89fa87dea50390553963e219bdb Mon Sep 17 00:00:00 2001 From: JanHolger Date: Mon, 4 Sep 2023 01:28:56 +0200 Subject: [PATCH 14/24] Implemented support for case-insensitive routing --- .../javawebstack/http/router/Exchange.java | 4 +- .../javawebstack/http/router/HTTPRouter.java | 27 +++++++--- .../http/router/HTTPRoutingOptions.java | 40 +++++++++++++++ .../http/router/router/Route.java | 49 +++++++++++++++---- 4 files changed, 102 insertions(+), 18 deletions(-) create mode 100644 src/main/java/org/javawebstack/http/router/HTTPRoutingOptions.java diff --git a/src/main/java/org/javawebstack/http/router/Exchange.java b/src/main/java/org/javawebstack/http/router/Exchange.java index b319eab..756eb5c 100644 --- a/src/main/java/org/javawebstack/http/router/Exchange.java +++ b/src/main/java/org/javawebstack/http/router/Exchange.java @@ -294,8 +294,8 @@ protected static AbstractElement getPathElement(AbstractElement source, String p private HTTPMethod getRequestMethodFromSocket(IHTTPSocket socket) { if ("websocket".equalsIgnoreCase(socket.getRequestHeader("upgrade"))) return HTTPMethod.WEBSOCKET; - if (router.isFormMethods() && (socket.getRequestMethod() == HTTPMethod.GET || socket.getRequestMethod() == HTTPMethod.POST) && getMimeType() == MimeType.X_WWW_FORM_URLENCODED) { - AbstractElement e = getBodyPathElement("_method"); + if (router.getRoutingOptions().hasFormMethodParameter() && (socket.getRequestMethod() == HTTPMethod.GET || socket.getRequestMethod() == HTTPMethod.POST) && getMimeType() == MimeType.X_WWW_FORM_URLENCODED) { + AbstractElement e = getBodyPathElement(router.getRoutingOptions().getFormMethodParameter()); if (e != null) { try { return HTTPMethod.valueOf(e.string()); diff --git a/src/main/java/org/javawebstack/http/router/HTTPRouter.java b/src/main/java/org/javawebstack/http/router/HTTPRouter.java index cfd67c6..01c6256 100644 --- a/src/main/java/org/javawebstack/http/router/HTTPRouter.java +++ b/src/main/java/org/javawebstack/http/router/HTTPRouter.java @@ -44,6 +44,7 @@ public class HTTPRouter implements RouteParamTransformerProvider { private final Map afterMiddleware = new HashMap<>(); private Function, Object> controllerInitiator = this::defaultControllerInitiator; private boolean formMethods = true; + private HTTPRoutingOptions routingOptions = new HTTPRoutingOptions(); private PartContentCache multipartContentCache; public HTTPRouter(IHTTPSocketServer server) { @@ -154,17 +155,17 @@ public HTTPRouter afterDelete(String pattern, AfterRequestHandler... handlers) { } public HTTPRouter route(HTTPMethod method, String pattern, RequestHandler... handlers) { - routes.add(new Route(this, method, pattern, Arrays.asList(handlers))); + routes.add(new Route(this, method, pattern, routingOptions, Arrays.asList(handlers))); return this; } public HTTPRouter beforeRoute(HTTPMethod method, String pattern, RequestHandler... handlers) { - beforeRoutes.add(new Route(this, method, pattern, Arrays.asList(handlers))); + beforeRoutes.add(new Route(this, method, pattern, routingOptions, Arrays.asList(handlers))); return this; } public HTTPRouter afterRoute(HTTPMethod method, String pattern, AfterRequestHandler... handlers) { - afterRoutes.add(new Route(this, method, pattern, null).setAfterHandlers(Arrays.asList(handlers))); + afterRoutes.add(new Route(this, method, pattern, routingOptions, null).setAfterHandlers(Arrays.asList(handlers))); return this; } @@ -426,12 +427,26 @@ public HTTPRouter enableMultipart(PartContentCache cache) { return this; } - public boolean isFormMethods() { - return formMethods; + public HTTPRouter caseInsensitiveRouting() { + return caseInsensitiveRouting(true); } + public HTTPRouter caseInsensitiveRouting(boolean caseInsensitiveRouting) { + routingOptions.caseInsensitive(caseInsensitiveRouting); + return this; + } + + public HTTPRoutingOptions getRoutingOptions() { + return routingOptions; + } + + @Deprecated public HTTPRouter disableFormMethods() { - formMethods = false; + return formMethodParameter(null); + } + + public HTTPRouter formMethodParameter(String parameter) { + routingOptions.formMethodParameter(parameter); return this; } diff --git a/src/main/java/org/javawebstack/http/router/HTTPRoutingOptions.java b/src/main/java/org/javawebstack/http/router/HTTPRoutingOptions.java new file mode 100644 index 0000000..ed8603e --- /dev/null +++ b/src/main/java/org/javawebstack/http/router/HTTPRoutingOptions.java @@ -0,0 +1,40 @@ +package org.javawebstack.http.router; + +public class HTTPRoutingOptions { + + private boolean caseInsensitive; + private boolean ignoreTrailingSlash = true; + private String formMethodParameter = "_method"; + + public HTTPRoutingOptions formMethodParameter(String formMethodParameter) { + this.formMethodParameter = formMethodParameter; + return this; + } + + public HTTPRoutingOptions caseInsensitive(boolean caseInsensitive) { + this.caseInsensitive = caseInsensitive; + return this; + } + + public HTTPRoutingOptions ignoreTrailingSlash(boolean ignoreTrailingSlash) { + this.ignoreTrailingSlash = ignoreTrailingSlash; + return this; + } + + public boolean isCaseInsensitive() { + return caseInsensitive; + } + + public boolean isIgnoreTrailingSlash() { + return ignoreTrailingSlash; + } + + public String getFormMethodParameter() { + return formMethodParameter; + } + + public boolean hasFormMethodParameter() { + return formMethodParameter != null; + } + +} diff --git a/src/main/java/org/javawebstack/http/router/router/Route.java b/src/main/java/org/javawebstack/http/router/router/Route.java index 65f0cf0..1f587ce 100644 --- a/src/main/java/org/javawebstack/http/router/router/Route.java +++ b/src/main/java/org/javawebstack/http/router/router/Route.java @@ -2,6 +2,7 @@ import org.javawebstack.http.router.Exchange; import org.javawebstack.http.router.HTTPMethod; +import org.javawebstack.http.router.HTTPRoutingOptions; import org.javawebstack.http.router.handler.AfterRequestHandler; import org.javawebstack.http.router.handler.RequestHandler; import org.javawebstack.http.router.transformer.route.RouteParamTransformerProvider; @@ -21,17 +22,19 @@ public class Route { private List handlers; private List afterHandlers; - public Route(RouteParamTransformerProvider routeParamTransformerProvider, HTTPMethod method, String pattern, List handlers) { - this(routeParamTransformerProvider, method, pattern, ":", handlers); + public Route(RouteParamTransformerProvider routeParamTransformerProvider, HTTPMethod method, String pattern, HTTPRoutingOptions options, List handlers) { + this(routeParamTransformerProvider, method, pattern, options, ":", handlers); } - public Route(RouteParamTransformerProvider routeParamTransformerProvider, HTTPMethod method, String pattern, String variableDelimiter, List handlers) { + public Route(RouteParamTransformerProvider routeParamTransformerProvider, HTTPMethod method, String pattern, HTTPRoutingOptions options, String variableDelimiter, List handlers) { this.handlers = handlers; this.method = method; this.routeParamTransformerProvider = routeParamTransformerProvider; pattern = pattern.toLowerCase(Locale.ENGLISH); - if (pattern.endsWith("/")) - pattern = pattern.substring(0, pattern.length() - 1); + if(options.isIgnoreTrailingSlash()) { + if (pattern.endsWith("/")) + pattern = pattern.substring(0, pattern.length() - 1); + } if (!pattern.startsWith("/")) pattern = "/" + pattern; int pos = 0; @@ -39,19 +42,20 @@ public Route(RouteParamTransformerProvider routeParamTransformerProvider, HTTPMe StringBuilder text = new StringBuilder(); boolean inVar = false; while (pos < pattern.length()) { - if (pattern.charAt(pos) == '{') { + char c = pattern.charAt(pos); + if (c == '{') { if (inVar) { throw new RuntimeException("Unexpected character '{' in route at position " + pos); } if (text.length() > 0) { - sb.append("(" + regexEscape(text.toString()) + ")"); + sb.append("(" + prepareRegex(options, text.toString()) + ")"); text = new StringBuilder(); } inVar = true; pos++; continue; } - if (pattern.charAt(pos) == '}') { + if (c == '}') { if (!inVar) { throw new RuntimeException("Unexpected character '}' in route at position " + pos); } @@ -74,14 +78,17 @@ public Route(RouteParamTransformerProvider routeParamTransformerProvider, HTTPMe pos++; continue; } - text.append(pattern.charAt(pos)); + text.append(c); pos++; } if (inVar) { throw new RuntimeException("Unexpected end in route"); } if (text.length() > 0) { - sb.append("(" + regexEscape(text.toString()) + ")"); + sb.append("(" + prepareRegex(options, text.toString()) + ")"); + } + if(options.isIgnoreTrailingSlash()) { + sb.append("/?"); } this.pattern = Pattern.compile(sb.toString()); } @@ -117,6 +124,28 @@ public List getAfterHandlers() { return afterHandlers; } + private static String prepareRegex(HTTPRoutingOptions options, String text) { + text = regexEscape(text); + if(options.isCaseInsensitive()) + text = ignoreCase(text); + return text; + } + + private static String ignoreCase(String s) { + StringBuilder sb = new StringBuilder(); + for(char c : s.toCharArray()) { + if(Character.isAlphabetic(c)) { + char inverted = Character.isUpperCase(c) ? Character.toLowerCase(c) : Character.toUpperCase(c); + if(c != inverted) { + sb.append("[").append(c).append(inverted).append("]"); + continue; + } + } + sb.append(c); + } + return sb.toString(); + } + private static String regexEscape(String s) { for (char c : "\\<([{^-=$!|]})?*+.>".toCharArray()) { s = s.replace(String.valueOf(c), "\\" + c); From 631c9f3a5d1917425fc7562fdd93705cbd90862d Mon Sep 17 00:00:00 2001 From: JanHolger Date: Mon, 4 Sep 2023 11:59:43 +0200 Subject: [PATCH 15/24] Upgraded validator --- pom.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8857d15..b392b96 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,12 @@ org.javawebstack validator - 1.0.1 + 1.0.2 + + + org.javawebstack + abstract-data + 1.0.6 org.reflections From 2dfd8f923007476520acc1526effdd321dd5da28 Mon Sep 17 00:00:00 2001 From: JanHolger Date: Mon, 4 Sep 2023 12:10:52 +0200 Subject: [PATCH 16/24] Added named routes --- .../javawebstack/http/router/HTTPRouter.java | 18 ++++++++++++- .../http/router/router/Route.java | 27 ++++++++++++++++--- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/javawebstack/http/router/HTTPRouter.java b/src/main/java/org/javawebstack/http/router/HTTPRouter.java index 01c6256..bd08ba6 100644 --- a/src/main/java/org/javawebstack/http/router/HTTPRouter.java +++ b/src/main/java/org/javawebstack/http/router/HTTPRouter.java @@ -155,7 +155,11 @@ public HTTPRouter afterDelete(String pattern, AfterRequestHandler... handlers) { } public HTTPRouter route(HTTPMethod method, String pattern, RequestHandler... handlers) { - routes.add(new Route(this, method, pattern, routingOptions, Arrays.asList(handlers))); + return route(null, method, pattern, handlers); + } + + public HTTPRouter route(String name, HTTPMethod method, String pattern, RequestHandler... handlers) { + routes.add(new Route(this, method, pattern, routingOptions, Arrays.asList(handlers)).setName(name)); return this; } @@ -187,6 +191,18 @@ public HTTPRouter afterRoute(HTTPMethod[] methods, String pattern, AfterRequestH return this; } + public List getBeforeRoutes() { + return beforeRoutes; + } + + public List getRoutes() { + return routes; + } + + public List getAfterRoutes() { + return afterRoutes; + } + public HTTPRouter any(String pattern, RequestHandler... handlers) { return route(HTTPMethod.values(), pattern, handlers); } diff --git a/src/main/java/org/javawebstack/http/router/router/Route.java b/src/main/java/org/javawebstack/http/router/router/Route.java index 1f587ce..1d1dbf8 100644 --- a/src/main/java/org/javawebstack/http/router/router/Route.java +++ b/src/main/java/org/javawebstack/http/router/router/Route.java @@ -15,9 +15,12 @@ import java.util.regex.Pattern; public class Route { + + private String name; private final RouteParamTransformerProvider routeParamTransformerProvider; private final HTTPMethod method; - private final Pattern pattern; + private final String pattern; + private final Pattern compiledPattern; private final Map variables = new HashMap<>(); private List handlers; private List afterHandlers; @@ -30,6 +33,7 @@ public Route(RouteParamTransformerProvider routeParamTransformerProvider, HTTPMe this.handlers = handlers; this.method = method; this.routeParamTransformerProvider = routeParamTransformerProvider; + this.pattern = pattern; pattern = pattern.toLowerCase(Locale.ENGLISH); if(options.isIgnoreTrailingSlash()) { if (pattern.endsWith("/")) @@ -90,7 +94,16 @@ public Route(RouteParamTransformerProvider routeParamTransformerProvider, HTTPMe if(options.isIgnoreTrailingSlash()) { sb.append("/?"); } - this.pattern = Pattern.compile(sb.toString()); + this.compiledPattern = Pattern.compile(sb.toString()); + } + + public Route setName(String name) { + this.name = name; + return this; + } + + public String getName() { + return name; } public Route setAfterHandlers(List afterHandlers) { @@ -98,6 +111,14 @@ public Route setAfterHandlers(List afterHandlers) { return this; } + public String getPattern() { + return pattern; + } + + public Map getVariables() { + return variables; + } + public Map match(Exchange exchange) { return match(exchange, exchange.getMethod(), exchange.getPath()); } @@ -105,7 +126,7 @@ public Map match(Exchange exchange) { public Map match(Exchange exchange, HTTPMethod method, String path) { if (this.method != method) return null; - Matcher matcher = pattern.matcher(path); + Matcher matcher = compiledPattern.matcher(path); if (matcher.matches()) { Map params = new HashMap<>(); for (String name : variables.keySet()) { From ea3b909fb8ab4e57d0e39798f67f3c5e4cfbc042 Mon Sep 17 00:00:00 2001 From: JanHolger Date: Fri, 8 Sep 2023 18:09:37 +0200 Subject: [PATCH 17/24] Added dependency injection, removed controller initiator --- pom.xml | 12 ++++ .../javawebstack/http/router/HTTPRouter.java | 72 ++++++++++++++----- 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/pom.xml b/pom.xml index b392b96..2ec49f9 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,19 @@ https://github.com/JavaWebStack/http-router/tree/master + + + ossrh + https://s01.oss.sonatype.org/content/repositories/snapshots + + + + + org.javawebstack + commons + 1.0.0-SNAPSHOT + org.javawebstack validator diff --git a/src/main/java/org/javawebstack/http/router/HTTPRouter.java b/src/main/java/org/javawebstack/http/router/HTTPRouter.java index bd08ba6..026f158 100644 --- a/src/main/java/org/javawebstack/http/router/HTTPRouter.java +++ b/src/main/java/org/javawebstack/http/router/HTTPRouter.java @@ -2,6 +2,7 @@ import org.javawebstack.abstractdata.mapper.Mapper; import org.javawebstack.abstractdata.mapper.naming.NamingPolicy; +import org.javawebstack.commons.inject.Injector; import org.javawebstack.http.router.adapter.IHTTPSocketServer; import org.javawebstack.http.router.handler.*; import org.javawebstack.http.router.multipart.content.PartContentCache; @@ -21,7 +22,6 @@ import java.io.File; import java.nio.charset.StandardCharsets; import java.util.*; -import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; @@ -42,9 +42,8 @@ public class HTTPRouter implements RouteParamTransformerProvider { private final List routeAutoInjectors = new ArrayList<>(); private final Map beforeMiddleware = new HashMap<>(); private final Map afterMiddleware = new HashMap<>(); - private Function, Object> controllerInitiator = this::defaultControllerInitiator; - private boolean formMethods = true; - private HTTPRoutingOptions routingOptions = new HTTPRoutingOptions(); + private Injector injector; + private final HTTPRoutingOptions routingOptions = new HTTPRoutingOptions(); private PartContentCache multipartContentCache; public HTTPRouter(IHTTPSocketServer server) { @@ -77,11 +76,15 @@ public Logger getLogger() { } public HTTPRouter beforeInterceptor(RequestInterceptor handler) { + if(injector != null) + injector.inject(handler); beforeInterceptors.add(handler); return this; } public HTTPRouter routeAutoInjector(RouteAutoInjector injector) { + if(this.injector != null) + this.injector.inject(injector); routeAutoInjectors.add(injector); return this; } @@ -143,6 +146,8 @@ public HTTPRouter staticResourceDirectory(String pathPrefix, ClassLoader classLo } public HTTPRouter staticHandler(String pathPrefix, StaticFileHandler handler) { + if(injector != null) + injector.inject(handler); return get(pathPrefix + (pathPrefix.endsWith("/") ? "" : "/") + "{*:path}", handler); } @@ -159,16 +164,31 @@ public HTTPRouter route(HTTPMethod method, String pattern, RequestHandler... han } public HTTPRouter route(String name, HTTPMethod method, String pattern, RequestHandler... handlers) { + if(injector != null) { + for(RequestHandler handler : handlers) { + injector.inject(handler); + } + } routes.add(new Route(this, method, pattern, routingOptions, Arrays.asList(handlers)).setName(name)); return this; } public HTTPRouter beforeRoute(HTTPMethod method, String pattern, RequestHandler... handlers) { + if(injector != null) { + for(RequestHandler handler : handlers) { + injector.inject(handler); + } + } beforeRoutes.add(new Route(this, method, pattern, routingOptions, Arrays.asList(handlers))); return this; } public HTTPRouter afterRoute(HTTPMethod method, String pattern, AfterRequestHandler... handlers) { + if(injector != null) { + for(AfterRequestHandler handler : handlers) { + injector.inject(handler); + } + } afterRoutes.add(new Route(this, method, pattern, routingOptions, null).setAfterHandlers(Arrays.asList(handlers))); return this; } @@ -216,54 +236,62 @@ public HTTPRouter afterAny(String pattern, AfterRequestHandler... handlers) { } public HTTPRouter webSocket(String pattern, WebSocketHandler handler) { + if(injector != null) + injector.inject(handler); if(!server.isWebSocketSupported()) throw new UnsupportedOperationException(server.getClass().getName() + " does not support websockets!"); return route(HTTPMethod.WEBSOCKET, pattern, new InternalWebSocketRequestHandler(handler)); } public HTTPRouter middleware(String name, RequestHandler handler) { + if(injector != null) + injector.inject(handler); beforeMiddleware.put(name, handler); return this; } public HTTPRouter middleware(String name, AfterRequestHandler handler) { + if(injector != null) + injector.inject(handler); afterMiddleware.put(name, handler); return this; } public HTTPRouter notFound(RequestHandler handler) { + if(injector != null) + injector.inject(handler); notFoundHandler = handler; return this; } public HTTPRouter routeParamTransformer(RouteParamTransformer transformer) { + if(injector != null) + injector.inject(transformer); routeParamTransformers.add(transformer); return this; } public HTTPRouter responseTransformer(ResponseTransformer transformer) { + if(injector != null) + injector.inject(transformer); responseTransformers.add(transformer); return this; } public HTTPRouter exceptionHandler(ExceptionHandler handler) { + if(injector != null) + injector.inject(handler); exceptionHandler = handler; return this; } - private Object defaultControllerInitiator (Class clazz) { - try { - return clazz.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { - e.printStackTrace(); - } - - return null; + public HTTPRouter injector(Injector injector) { + this.injector = injector; + return this; } - public HTTPRouter controllerInitiator (Function, Object> initiator) { - controllerInitiator = initiator; - return this; + public Injector getInjector() { + return injector; } public HTTPRouter controller(Class parentClass, Package p) { @@ -274,7 +302,17 @@ public HTTPRouter controller(String globalPrefix, Class parentClass, Package Reflections reflections = new Reflections(p.getName()); reflections.getSubTypesOf(parentClass) .stream() - .map(controllerInitiator) + .map(t -> { + if(injector == null) { + try { + return t.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } else { + return injector.getInstance(t); + } + }) .forEach(c -> controller(globalPrefix, c)); return this; } @@ -284,6 +322,8 @@ public HTTPRouter controller(Object controller) { } public HTTPRouter controller(String globalPrefix, Object controller) { + if(injector != null) + injector.inject(controller); routeBinder.bind(globalPrefix, controller); return this; } From 939065e22d921198d3fcc9a65483320538ec01c2 Mon Sep 17 00:00:00 2001 From: JanHolger Date: Thu, 14 Sep 2023 23:38:08 +0200 Subject: [PATCH 18/24] Fixed multipart --- src/main/java/org/javawebstack/http/router/Exchange.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/javawebstack/http/router/Exchange.java b/src/main/java/org/javawebstack/http/router/Exchange.java index 756eb5c..3af4e75 100644 --- a/src/main/java/org/javawebstack/http/router/Exchange.java +++ b/src/main/java/org/javawebstack/http/router/Exchange.java @@ -330,13 +330,13 @@ public Exchange enableMultipart(PartContentCache cache) { HeaderValue contentType = new HeaderValue(getContentType()); if(!contentType.getValue().toLowerCase(Locale.ROOT).equals("multipart/form-data")) return this; - body = new byte[0]; byte[] boundary = contentType.getDirectives().get("boundary").getBytes(); try { InputStream stream; if(body != null) { stream = new ByteArrayInputStream(body); } else { + body = new byte[0]; stream = socket.getInputStream(); } parts = Part.parse(stream, boundary, cache); From 3839de68f6832b8050aea6811b6ed02351091642 Mon Sep 17 00:00:00 2001 From: JanHolger Date: Tue, 24 Oct 2023 18:50:12 +0200 Subject: [PATCH 19/24] Added a fix for mime type parsing --- .../java/org/javawebstack/http/router/util/HeaderValue.java | 4 ++-- src/main/java/org/javawebstack/http/router/util/MimeType.java | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/javawebstack/http/router/util/HeaderValue.java b/src/main/java/org/javawebstack/http/router/util/HeaderValue.java index b464beb..0e136cf 100644 --- a/src/main/java/org/javawebstack/http/router/util/HeaderValue.java +++ b/src/main/java/org/javawebstack/http/router/util/HeaderValue.java @@ -5,8 +5,8 @@ public class HeaderValue { - final String value; - final Map directives = new HashMap<>(); + private final String value; + private final Map directives = new HashMap<>(); public HeaderValue(String source) { String[] spl = source.split("; "); diff --git a/src/main/java/org/javawebstack/http/router/util/MimeType.java b/src/main/java/org/javawebstack/http/router/util/MimeType.java index 54bfba3..618835e 100644 --- a/src/main/java/org/javawebstack/http/router/util/MimeType.java +++ b/src/main/java/org/javawebstack/http/router/util/MimeType.java @@ -57,6 +57,10 @@ public static MimeType byExtension(String extension) { } public static MimeType byMimeType(String mimeType) { + if(mimeType == null) + return null; + if(mimeType.contains(";")) + mimeType = new HeaderValue(mimeType).getValue(); for (MimeType type : values()) { if (type.mimeTypes.contains(mimeType)) { return type; From c6b9a7f09994a194d2d264d092e2d8c19f167b86 Mon Sep 17 00:00:00 2001 From: Jake Esser Date: Tue, 31 Oct 2023 17:11:49 +0100 Subject: [PATCH 20/24] Fixed Accept header parsing issue in SerializedResponseTransformer --- .../response/SerializedResponseTransformer.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java b/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java index 0d5e495..816d2df 100644 --- a/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java +++ b/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java @@ -3,6 +3,7 @@ import org.javawebstack.abstractdata.mapper.Mapper; import org.javawebstack.abstractdata.mapper.naming.NamingPolicy; import org.javawebstack.http.router.Exchange; +import org.javawebstack.http.router.util.HeaderValue; public class SerializedResponseTransformer implements ResponseTransformer { @@ -29,18 +30,20 @@ public String transform(Exchange exchange, Object object) { } else { if (this.ignoreStrings && object instanceof String) return null; - String accept = exchange.header("Accept"); + String rawAccept = exchange.header("Accept"); - if (accept != null) { - switch (accept.toLowerCase()) { + if (rawAccept != null) { + HeaderValue accept = new HeaderValue(rawAccept); + + switch (accept.getValue().toLowerCase()) { case "application/x-yaml": case "application/yaml": case "text/yaml": case "text/x-yaml": - exchange.contentType(accept); + exchange.contentType(rawAccept); return this.mapper.map(object).toYaml(); case "application/x-www-form-urlencoded": - exchange.contentType(accept); + exchange.contentType(rawAccept); return this.mapper.map(object).toFormDataString(); } } From 402aff723ffe9ce3071f9c9053487a5eb16aab56 Mon Sep 17 00:00:00 2001 From: Jake Esser Date: Tue, 31 Oct 2023 17:16:27 +0100 Subject: [PATCH 21/24] Added status code 406 for unsupported Accept values --- .../response/SerializedResponseTransformer.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java b/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java index 816d2df..28a80a3 100644 --- a/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java +++ b/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java @@ -35,16 +35,20 @@ public String transform(Exchange exchange, Object object) { if (rawAccept != null) { HeaderValue accept = new HeaderValue(rawAccept); + exchange.contentType(rawAccept); switch (accept.getValue().toLowerCase()) { case "application/x-yaml": case "application/yaml": case "text/yaml": case "text/x-yaml": - exchange.contentType(rawAccept); return this.mapper.map(object).toYaml(); case "application/x-www-form-urlencoded": - exchange.contentType(rawAccept); return this.mapper.map(object).toFormDataString(); + case "application/json": + return this.mapper.map(object).toJsonString(); + default: + exchange.status(406); + return "Not Acceptable"; } } From ba03cde4692913e53a9f7857d8f58b3c0329fdce Mon Sep 17 00:00:00 2001 From: Jake Esser Date: Tue, 31 Oct 2023 17:26:54 +0100 Subject: [PATCH 22/24] Removed space from HeaderValue parsing and added trimming --- .../java/org/javawebstack/http/router/util/HeaderValue.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/javawebstack/http/router/util/HeaderValue.java b/src/main/java/org/javawebstack/http/router/util/HeaderValue.java index 0e136cf..1dea862 100644 --- a/src/main/java/org/javawebstack/http/router/util/HeaderValue.java +++ b/src/main/java/org/javawebstack/http/router/util/HeaderValue.java @@ -9,10 +9,10 @@ public class HeaderValue { private final Map directives = new HashMap<>(); public HeaderValue(String source) { - String[] spl = source.split("; "); - value = spl[0]; + String[] spl = source.split(";"); + value = spl[0].trim(); for(int i=1; i Date: Tue, 31 Oct 2023 17:35:30 +0100 Subject: [PATCH 23/24] Removed 406 status code because of missing Mime type parsing --- .../transformer/response/SerializedResponseTransformer.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java b/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java index 28a80a3..4613bfb 100644 --- a/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java +++ b/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java @@ -44,11 +44,6 @@ public String transform(Exchange exchange, Object object) { return this.mapper.map(object).toYaml(); case "application/x-www-form-urlencoded": return this.mapper.map(object).toFormDataString(); - case "application/json": - return this.mapper.map(object).toJsonString(); - default: - exchange.status(406); - return "Not Acceptable"; } } From 4354fcd88b28f364f7527d54fbd1c20898d50ebb Mon Sep 17 00:00:00 2001 From: JanHolger Date: Wed, 4 Feb 2026 18:55:58 +0100 Subject: [PATCH 24/24] Switch from OSSRH to new central --- .github/workflows/maven-deploy-release.yml | 5 ++- .github/workflows/maven-deploy.yml | 5 ++- build/settings.xml | 16 ++------- pom.xml | 40 +++++++++------------- 4 files changed, 23 insertions(+), 43 deletions(-) diff --git a/.github/workflows/maven-deploy-release.yml b/.github/workflows/maven-deploy-release.yml index 0c3c94b..8ad24f1 100644 --- a/.github/workflows/maven-deploy-release.yml +++ b/.github/workflows/maven-deploy-release.yml @@ -20,7 +20,6 @@ jobs: - name: Deploy to JavaWebStack Repository run: mvn deploy -DbuildVersion=${{ github.event.release.tag_name }} -s build/settings.xml env: - DEPLOYMENT_USERNAME: ${{ secrets.DEPLOYMENT_USERNAME }} - DEPLOYMENT_PASSWORD: ${{ secrets.DEPLOYMENT_PASSWORD }} + CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} + CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }} GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} diff --git a/.github/workflows/maven-deploy.yml b/.github/workflows/maven-deploy.yml index c6ac3fb..e08cc36 100644 --- a/.github/workflows/maven-deploy.yml +++ b/.github/workflows/maven-deploy.yml @@ -21,7 +21,6 @@ jobs: - name: Deploy to JavaWebStack Repository run: mvn deploy -s build/settings.xml env: - DEPLOYMENT_USERNAME: ${{ secrets.DEPLOYMENT_USERNAME }} - DEPLOYMENT_PASSWORD: ${{ secrets.DEPLOYMENT_PASSWORD }} + CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} + CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }} GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} diff --git a/build/settings.xml b/build/settings.xml index 07e7726..88571fa 100644 --- a/build/settings.xml +++ b/build/settings.xml @@ -5,19 +5,9 @@ > - javawebstack-snapshots - ${env.DEPLOYMENT_USERNAME} - ${env.DEPLOYMENT_PASSWORD} - - - javawebstack-releases - ${env.DEPLOYMENT_USERNAME} - ${env.DEPLOYMENT_PASSWORD} - - - ossrh - JavaWebStack - ${env.OSSRH_PASSWORD} + central + ${env.CENTRAL_USERNAME} + ${env.CENTRAL_PASSWORD} gpg diff --git a/pom.xml b/pom.xml index 2ec49f9..1e5846a 100644 --- a/pom.xml +++ b/pom.xml @@ -48,8 +48,8 @@ - ossrh - https://s01.oss.sonatype.org/content/repositories/snapshots + central-snapshots + https://central.sonatype.com/repository/maven-snapshots/ @@ -62,12 +62,12 @@ org.javawebstack validator - 1.0.2 + 1.0.3-SNAPSHOT org.javawebstack abstract-data - 1.0.6 + 1.0.7-SNAPSHOT org.reflections @@ -83,24 +83,20 @@ + + org.sonatype.central + central-publishing-maven-plugin + 0.9.0 + true + + central + + org.apache.maven.plugins maven-surefire-plugin 2.22.1 - - maven-deploy-plugin - 3.0.0-M1 - - - default-deploy - deploy - - deploy - - - - org.apache.maven.plugins maven-source-plugin @@ -139,7 +135,7 @@ sign - A313520526A8DFE1C2A30399C35A3D43C557B112 + EC9CCFF8901F0AA22191DCEDD619376246C066D0 gpg --no-tty @@ -155,13 +151,9 @@ - ossrh - https://s01.oss.sonatype.org/content/repositories/snapshots + central + https://central.sonatype.com/repository/maven-snapshots/ - - ossrh - https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ -