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/README.md b/README.md
index b7d54a3..36e16e3 100644
--- a/README.md
+++ b/README.md
@@ -3,17 +3,17 @@
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
@@ -24,7 +24,7 @@ work-in-progress project though so it's not yet complete.
```xml
org.javawebstack
- http-server
- 1.0.2
+ http-router
+ 1.0.3
```
\ No newline at end of file
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 ecab3e2..1e5846a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,16 +7,16 @@
8
8
- 1.0.2-SNAPSHOT
+ 1.0.3-SNAPSHOT
org.javawebstack
- http-server
+ http-router
${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.
- https://github.com/JavaWebStack/http-server
+ http-router
+ This library provides an http routing and request mapping stack
+ https://github.com/JavaWebStack/http-router
@@ -41,67 +41,62 @@
- 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
+
+
+ central-snapshots
+ https://central.sonatype.com/repository/maven-snapshots/
+
+
+
org.javawebstack
- validator
- 1.0.1
-
-
- org.reflections
- reflections
- 0.10.2
+ commons
+ 1.0.0-SNAPSHOT
- org.junit.jupiter
- junit-jupiter-api
- 5.9.0
+ org.javawebstack
+ validator
+ 1.0.3-SNAPSHOT
- io.undertow
- undertow-core
- 2.2.19.Final
+ org.javawebstack
+ abstract-data
+ 1.0.7-SNAPSHOT
-
- org.jboss.xnio
- xnio-api
- 3.8.8.Final
+ org.reflections
+ reflections
+ 0.10.2
-
- org.junit.jupiter
- junit-jupiter-engine
- 5.9.0
- test
+ commons-fileupload
+ commons-fileupload
+ 1.5
+
+ 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
@@ -140,7 +135,7 @@
sign
- A313520526A8DFE1C2A30399C35A3D43C557B112
+ EC9CCFF8901F0AA22191DCEDD619376246C066D0
gpg
--no-tty
@@ -156,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/
-
diff --git a/src/main/java/org/javawebstack/httpserver/Exchange.java b/src/main/java/org/javawebstack/http/router/Exchange.java
similarity index 71%
rename from src/main/java/org/javawebstack/httpserver/Exchange.java
rename to src/main/java/org/javawebstack/http/router/Exchange.java
index c29e568..3af4e75 100644
--- a/src/main/java/org/javawebstack/httpserver/Exchange.java
+++ b/src/main/java/org/javawebstack/http/router/Exchange.java
@@ -1,17 +1,20 @@
-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.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.net.Socket;
+import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
@@ -25,16 +28,17 @@ 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<>();
private final AbstractObject queryParameters;
private final IHTTPSocket socket;
private final Map attributes = new HashMap<>();
+ private List parts = null;
- 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 +78,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 +240,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 +268,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,20 +294,75 @@ 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) {
- String rawMethodOverride = getBodyPathElement("_method").string();
- if (rawMethodOverride != null)
- return HTTPMethod.valueOf(rawMethodOverride);
+ 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());
+ } catch (IllegalArgumentException ignored) {}
+ }
}
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;
+ 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);
+ } catch (Exception ex) {
+ parts = new ArrayList<>();
}
+ return this;
+ }
- return MimeType.byMimeType(contentType);
+ 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;
+ }
+
+ 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/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/http/router/HTTPRouter.java b/src/main/java/org/javawebstack/http/router/HTTPRouter.java
new file mode 100644
index 0000000..026f158
--- /dev/null
+++ b/src/main/java/org/javawebstack/http/router/HTTPRouter.java
@@ -0,0 +1,509 @@
+package org.javawebstack.http.router;
+
+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;
+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;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class HTTPRouter implements RouteParamTransformerProvider {
+
+ 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<>();
+ private final List responseTransformers = new ArrayList<>();
+ private RequestHandler notFoundHandler = new DefaultNotFoundHandler();
+ private ExceptionHandler exceptionHandler = new ExceptionHandler.DefaultExceptionHandler();
+ private final List beforeRoutes = new ArrayList<>();
+ private final List afterRoutes = new ArrayList<>();
+ private final IHTTPSocketServer server;
+ private final List beforeInterceptors = new ArrayList<>();
+ 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 Injector injector;
+ private final HTTPRoutingOptions routingOptions = new HTTPRoutingOptions();
+ private PartContentCache multipartContentCache;
+
+ public HTTPRouter(IHTTPSocketServer server) {
+ this.server = server;
+ routeParamTransformers.add(DefaultRouteParamTransformer.INSTANCE);
+ routeAutoInjectors.add(DefaultRouteAutoInjector.INSTANCE);
+ }
+
+ public HTTPRouter maxThreads(int maxThreads) {
+ this.server.setMaxThreads(maxThreads);
+ return this;
+ }
+
+ public HTTPRouter logger(Logger logger) {
+ this.logger = logger;
+ return this;
+ }
+
+ public HTTPRouter mapper(Mapper mapper) {
+ this.mapper = mapper;
+ return this;
+ }
+
+ public Mapper getMapper() {
+ return mapper;
+ }
+
+ public Logger getLogger() {
+ return logger;
+ }
+
+ 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;
+ }
+
+ public HTTPRouter get(String pattern, RequestHandler... handlers) {
+ return route(HTTPMethod.GET, pattern, handlers);
+ }
+
+ public HTTPRouter beforeGet(String pattern, RequestHandler... handlers) {
+ return beforeRoute(HTTPMethod.GET, pattern, handlers);
+ }
+
+ public HTTPRouter afterGet(String pattern, AfterRequestHandler... handlers) {
+ return afterRoute(HTTPMethod.GET, pattern, handlers);
+ }
+
+ public HTTPRouter post(String pattern, RequestHandler... handlers) {
+ return route(HTTPMethod.POST, pattern, handlers);
+ }
+
+ public HTTPRouter beforePost(String pattern, RequestHandler... handlers) {
+ return beforeRoute(HTTPMethod.POST, pattern, handlers);
+ }
+
+ public HTTPRouter afterPost(String pattern, AfterRequestHandler... handlers) {
+ return afterRoute(HTTPMethod.POST, pattern, handlers);
+ }
+
+ public HTTPRouter put(String pattern, RequestHandler... handlers) {
+ return route(HTTPMethod.PUT, pattern, handlers);
+ }
+
+ public HTTPRouter beforePut(String pattern, RequestHandler... handlers) {
+ return beforeRoute(HTTPMethod.PUT, pattern, handlers);
+ }
+
+ public HTTPRouter afterPut(String pattern, AfterRequestHandler... handlers) {
+ return afterRoute(HTTPMethod.PUT, pattern, handlers);
+ }
+
+ public HTTPRouter delete(String pattern, RequestHandler... handlers) {
+ return route(HTTPMethod.DELETE, pattern, handlers);
+ }
+
+ public HTTPRouter staticDirectory(String pathPrefix, File directory) {
+ return staticHandler(pathPrefix, new StaticFileHandler().add(new DirectoryFileProvider(directory)));
+ }
+
+ public HTTPRouter staticDirectory(String pathPrefix, String directory) {
+ return staticDirectory(pathPrefix, new File(directory));
+ }
+
+ public HTTPRouter staticResourceDirectory(String pathPrefix, String prefix) {
+ return staticResourceDirectory(pathPrefix, null, prefix);
+ }
+
+ public HTTPRouter staticResourceDirectory(String pathPrefix, ClassLoader classLoader, String prefix) {
+ return staticHandler(pathPrefix, new StaticFileHandler().add(new ResourceFileProvider(classLoader, prefix)));
+ }
+
+ public HTTPRouter staticHandler(String pathPrefix, StaticFileHandler handler) {
+ if(injector != null)
+ injector.inject(handler);
+ return get(pathPrefix + (pathPrefix.endsWith("/") ? "" : "/") + "{*:path}", handler);
+ }
+
+ public HTTPRouter beforeDelete(String pattern, RequestHandler... handlers) {
+ return beforeRoute(HTTPMethod.DELETE, pattern, handlers);
+ }
+
+ public HTTPRouter afterDelete(String pattern, AfterRequestHandler... handlers) {
+ return afterRoute(HTTPMethod.DELETE, pattern, handlers);
+ }
+
+ public HTTPRouter route(HTTPMethod method, String pattern, RequestHandler... handlers) {
+ return route(null, method, pattern, handlers);
+ }
+
+ 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;
+ }
+
+ public HTTPRouter route(HTTPMethod[] methods, String pattern, RequestHandler... handlers) {
+ for (HTTPMethod method : methods)
+ route(method, pattern, handlers);
+ return this;
+ }
+
+ public HTTPRouter beforeRoute(HTTPMethod[] methods, String pattern, RequestHandler... handlers) {
+ for (HTTPMethod method : methods)
+ beforeRoute(method, pattern, handlers);
+ return this;
+ }
+
+ public HTTPRouter afterRoute(HTTPMethod[] methods, String pattern, AfterRequestHandler... handlers) {
+ for (HTTPMethod method : methods)
+ afterRoute(method, pattern, handlers);
+ 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);
+ }
+
+ public HTTPRouter beforeAny(String pattern, RequestHandler... handlers) {
+ return beforeRoute(HTTPMethod.values(), pattern, handlers);
+ }
+
+ public HTTPRouter afterAny(String pattern, AfterRequestHandler... handlers) {
+ return afterRoute(HTTPMethod.values(), pattern, 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;
+ }
+
+ public HTTPRouter injector(Injector injector) {
+ this.injector = injector;
+ return this;
+ }
+
+ public Injector getInjector() {
+ return injector;
+ }
+
+ public HTTPRouter controller(Class> parentClass, Package p) {
+ return controller("", parentClass, p);
+ }
+
+ public HTTPRouter controller(String globalPrefix, Class> parentClass, Package p) {
+ Reflections reflections = new Reflections(p.getName());
+ reflections.getSubTypesOf(parentClass)
+ .stream()
+ .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;
+ }
+
+ public HTTPRouter controller(Object controller) {
+ return controller("", controller);
+ }
+
+ public HTTPRouter controller(String globalPrefix, Object controller) {
+ if(injector != null)
+ injector.inject(controller);
+ routeBinder.bind(globalPrefix, controller);
+ return this;
+ }
+
+ public HTTPRouter port(int port) {
+ server.setPort(port);
+ return this;
+ }
+
+ public HTTPRouter start() {
+ server.setHandler(socket -> execute(new Exchange(this, socket)));
+ try {
+ server.start();
+ logger.info("HTTP-Server started on port " + server.getPort());
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ return this;
+ }
+
+ public void join() {
+ server.join();
+ }
+
+ public void stop() {
+ try {
+ server.stop();
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public void execute(Exchange exchange) {
+ Exchange.exchanges.set(exchange);
+ try {
+ try {
+ if(multipartContentCache != null)
+ exchange.enableMultipart(multipartContentCache);
+ 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 (response != null)
+ 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();
+ }
+ }
+ } 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);
+ 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!");
+ }
+ }
+ } 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();
+ }
+
+ public List getRouteParamTransformer() {
+ return routeParamTransformers;
+ }
+
+ public RouteParamTransformer getRouteParamTransformer(String type) {
+ return routeParamTransformers.stream().filter(t -> t.canTransform(type)).findFirst().orElse(null);
+ }
+ public RequestHandler getBeforeMiddleware(String name) {
+ return beforeMiddleware.get(name);
+ }
+
+ public AfterRequestHandler getAfterMiddleware(String name) {
+ return afterMiddleware.get(name);
+ }
+
+ public List getRouteAutoInjectors() {
+ return routeAutoInjectors;
+ }
+
+ public byte[] transformResponse(Exchange exchange, Object object) {
+ for (ResponseTransformer t : responseTransformers) {
+ byte[] res = t.transformBytes(exchange, object);
+ if (res != null)
+ return res;
+ }
+ if(object instanceof byte[])
+ return (byte[]) object;
+ return object.toString().getBytes(StandardCharsets.UTF_8);
+ }
+
+ public ExceptionHandler getExceptionHandler() {
+ return exceptionHandler;
+ }
+
+ public HTTPRouter enableMultipart(PartContentCache cache) {
+ this.multipartContentCache = cache;
+ return this;
+ }
+
+ 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() {
+ 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/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 77%
rename from src/main/java/org/javawebstack/httpserver/adapter/IHTTPSocket.java
rename to src/main/java/org/javawebstack/http/router/adapter/IHTTPSocket.java
index bf4bc33..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;
@@ -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/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/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/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 60%
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..1d1dbf8 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,11 @@
-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.HTTPRoutingOptions;
+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;
@@ -14,24 +15,30 @@
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;
- 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;
+ this.pattern = pattern;
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 +46,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,16 +82,28 @@ 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());
+ 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) {
@@ -91,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());
}
@@ -98,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()) {
@@ -117,6 +145,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);
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 e8eb2eb..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);
}
}
}
@@ -187,20 +187,20 @@ 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 {
- 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..4613bfb
--- /dev/null
+++ b/src/main/java/org/javawebstack/http/router/transformer/response/SerializedResponseTransformer.java
@@ -0,0 +1,54 @@
+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;
+import org.javawebstack.http.router.util.HeaderValue;
+
+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 rawAccept = exchange.header("Accept");
+
+ 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":
+ return this.mapper.map(object).toYaml();
+ case "application/x-www-form-urlencoded":
+ 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/http/router/util/HeaderValue.java b/src/main/java/org/javawebstack/http/router/util/HeaderValue.java
new file mode 100644
index 0000000..1dea862
--- /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 {
+
+ private final String value;
+ private final Map directives = new HashMap<>();
+
+ public HeaderValue(String source) {
+ String[] spl = source.split(";");
+ value = spl[0].trim();
+ for(int i=1; i getDirectives() {
+ return directives;
+ }
+
+}
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 90%
rename from src/main/java/org/javawebstack/httpserver/util/MimeType.java
rename to src/main/java/org/javawebstack/http/router/util/MimeType.java
index 3703170..618835e 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;
@@ -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;
@@ -68,6 +72,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("."))
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 65%
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 c0948d4..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;
@@ -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 routes = new ArrayList<>();
- private final RouteBinder routeBinder = new RouteBinder(this);
- private final List routeParamTransformers = new ArrayList<>();
- private final List responseTransformers = new ArrayList<>();
- private RequestHandler notFoundHandler = new DefaultNotFoundHandler();
- private ExceptionHandler exceptionHandler = new ExceptionHandler.DefaultExceptionHandler();
- private final List beforeRoutes = new ArrayList<>();
- 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 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() {
- this(new UndertowHTTPSocketServer());
- }
-
- public HTTPServer(IHTTPSocketServer server) {
- this.server = server;
- routeParamTransformers.add(DefaultRouteParamTransformer.INSTANCE);
- routeAutoInjectors.add(DefaultRouteAutoInjector.INSTANCE);
- }
-
- public HTTPServer maxThreads(int maxThreads) {
- this.server.setMaxThreads(maxThreads);
- return this;
- }
-
- public HTTPServer logger(Logger logger) {
- this.logger = logger;
- return this;
- }
-
- public HTTPServer abstractMapper(AbstractMapper mapper) {
- this.abstractMapper = mapper;
- return this;
- }
-
- public AbstractMapper getAbstractMapper() {
- return abstractMapper;
- }
-
- public Logger getLogger() {
- return logger;
- }
-
- public HTTPServer beforeInterceptor(RequestInterceptor handler) {
- beforeInterceptors.add(handler);
- return this;
- }
-
- public HTTPServer routeAutoInjector(RouteAutoInjector injector) {
- routeAutoInjectors.add(injector);
- return this;
- }
-
- public HTTPServer get(String pattern, RequestHandler... handlers) {
- return route(HTTPMethod.GET, pattern, handlers);
- }
-
- public HTTPServer beforeGet(String pattern, RequestHandler... handlers) {
- return beforeRoute(HTTPMethod.GET, pattern, handlers);
- }
-
- public HTTPServer afterGet(String pattern, AfterRequestHandler... handlers) {
- return afterRoute(HTTPMethod.GET, pattern, handlers);
- }
-
- public HTTPServer post(String pattern, RequestHandler... handlers) {
- return route(HTTPMethod.POST, pattern, handlers);
- }
-
- public HTTPServer beforePost(String pattern, RequestHandler... handlers) {
- return beforeRoute(HTTPMethod.POST, pattern, handlers);
- }
-
- public HTTPServer afterPost(String pattern, AfterRequestHandler... handlers) {
- return afterRoute(HTTPMethod.POST, pattern, handlers);
- }
-
- public HTTPServer put(String pattern, RequestHandler... handlers) {
- return route(HTTPMethod.PUT, pattern, handlers);
- }
-
- public HTTPServer beforePut(String pattern, RequestHandler... handlers) {
- return beforeRoute(HTTPMethod.PUT, pattern, handlers);
- }
-
- public HTTPServer afterPut(String pattern, AfterRequestHandler... handlers) {
- return afterRoute(HTTPMethod.PUT, pattern, handlers);
- }
-
- public HTTPServer delete(String pattern, RequestHandler... handlers) {
- return route(HTTPMethod.DELETE, pattern, handlers);
- }
-
- public HTTPServer staticDirectory(String pathPrefix, File directory) {
- return staticHandler(pathPrefix, new StaticFileHandler().add(new DirectoryFileProvider(directory)));
- }
-
- public HTTPServer staticDirectory(String pathPrefix, String directory) {
- return staticDirectory(pathPrefix, new File(directory));
- }
-
- public HTTPServer staticResourceDirectory(String pathPrefix, String prefix) {
- return staticResourceDirectory(pathPrefix, null, prefix);
- }
-
- public HTTPServer staticResourceDirectory(String pathPrefix, ClassLoader classLoader, String prefix) {
- return staticHandler(pathPrefix, new StaticFileHandler().add(new ResourceFileProvider(classLoader, prefix)));
- }
-
- public HTTPServer staticHandler(String pathPrefix, StaticFileHandler handler) {
- return get(pathPrefix + (pathPrefix.endsWith("/") ? "" : "/") + "{*:path}", handler);
- }
-
- public HTTPServer beforeDelete(String pattern, RequestHandler... handlers) {
- return beforeRoute(HTTPMethod.DELETE, pattern, handlers);
- }
-
- public HTTPServer afterDelete(String pattern, AfterRequestHandler... handlers) {
- return afterRoute(HTTPMethod.DELETE, pattern, handlers);
- }
-
- public HTTPServer 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) {
- beforeRoutes.add(new Route(this, method, pattern, Arrays.asList(handlers)));
- return this;
- }
-
- public HTTPServer 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) {
- for (HTTPMethod method : methods)
- route(method, pattern, handlers);
- return this;
- }
-
- public HTTPServer 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) {
- for (HTTPMethod method : methods)
- afterRoute(method, pattern, handlers);
- return this;
- }
-
- public HTTPServer any(String pattern, RequestHandler... handlers) {
- return route(HTTPMethod.values(), pattern, handlers);
- }
-
- public HTTPServer beforeAny(String pattern, RequestHandler... handlers) {
- return beforeRoute(HTTPMethod.values(), pattern, handlers);
- }
-
- public HTTPServer afterAny(String pattern, AfterRequestHandler... handlers) {
- return afterRoute(HTTPMethod.values(), pattern, handlers);
- }
-
- public HTTPServer 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) {
- beforeMiddleware.put(name, handler);
- return this;
- }
-
- public HTTPServer middleware(String name, AfterRequestHandler handler) {
- afterMiddleware.put(name, handler);
- return this;
- }
-
- public HTTPServer notFound(RequestHandler handler) {
- notFoundHandler = handler;
- return this;
- }
-
- public HTTPServer routeParamTransformer(RouteParamTransformer transformer) {
- routeParamTransformers.add(transformer);
- return this;
- }
-
- public HTTPServer responseTransformer(ResponseTransformer transformer) {
- responseTransformers.add(transformer);
- return this;
- }
-
- public HTTPServer exceptionHandler(ExceptionHandler handler) {
- exceptionHandler = handler;
- return this;
- }
-
- private Object defaultControllerInitiator (Class> clazz) {
- try {
- return clazz.newInstance();
- } catch (InstantiationException | IllegalAccessException e) {
- e.printStackTrace();
- }
-
- return null;
- }
-
- public HTTPServer controllerInitiator (Function, Object> initiator) {
- controllerInitiator = initiator;
- return this;
- }
-
- public HTTPServer controller(Class> parentClass, Package p) {
- return controller("", parentClass, p);
- }
-
- public HTTPServer controller(String globalPrefix, Class> parentClass, Package p) {
- Reflections reflections = new Reflections(p.getName());
- reflections.getSubTypesOf(parentClass)
- .stream()
- .map(controllerInitiator)
- .forEach(c -> controller(globalPrefix, c));
- return this;
- }
-
- public HTTPServer controller(Object controller) {
- return controller("", controller);
- }
-
- public HTTPServer controller(String globalPrefix, Object controller) {
- routeBinder.bind(globalPrefix, controller);
- return this;
- }
-
- public HTTPServer port(int port) {
- server.setPort(port);
- return this;
- }
-
- public HTTPServer start() {
- server.setHandler(socket -> execute(new Exchange(this, socket)));
- try {
- server.start();
- logger.info("HTTP-Server started on port " + server.getPort());
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- return this;
- }
-
- public void join() {
- server.join();
- }
-
- public void stop() {
- try {
- server.stop();
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- }
-
- 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 (response != null)
- 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();
- }
- }
- } 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);
- 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) {
- logger.log(Level.SEVERE, ex2, () -> "An error occured in the exception handler!");
- }
- }
- Exchange.exchanges.remove();
- exchange.close();
- }
-
- public List getRouteParamTransformer() {
- return routeParamTransformers;
- }
-
- public RouteParamTransformer getRouteParamTransformer(String type) {
- return routeParamTransformers.stream().filter(t -> t.canTransform(type)).findFirst().orElse(null);
- }
- public RequestHandler getBeforeMiddleware(String name) {
- return beforeMiddleware.get(name);
- }
-
- public AfterRequestHandler getAfterMiddleware(String name) {
- return afterMiddleware.get(name);
- }
-
- public List getRouteAutoInjectors() {
- return routeAutoInjectors;
- }
-
- public byte[] transformResponse(Exchange exchange, Object object) {
- for (ResponseTransformer t : responseTransformers) {
- byte[] res = t.transformBytes(exchange, object);
- if (res != null)
- return res;
- }
- if(object instanceof byte[])
- return (byte[]) object;
- return object.toString().getBytes(StandardCharsets.UTF_8);
- }
-
- public ExceptionHandler getExceptionHandler() {
- return exceptionHandler;
- }
-
- public boolean isFormMethods() {
- return formMethods;
- }
-
- public HTTPServer disableFormMethods() {
- formMethods = false;
- return this;
- }
-}
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/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;
- }
-
-}
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
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 5dc1a70..0000000
--- a/src/main/java/org/javawebstack/httpserver/test/TestHTTPSocket.java
+++ /dev/null
@@ -1,121 +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 Map> getRequestHeaders() {
- return requestHeaders;
- }
-
- public Map> getResponseHeaders() {
- return responseHeaders;
- }
-
- public TestHTTPSocket(HTTPMethod method, String url) {
- this.requestMethod = method;
- String[] pathSplit = url.split("\\?", 2);
- requestPath = pathSplit[0];
- if(pathSplit.length == 2)
- requestQuery = pathSplit[1];
- else
- requestQuery = null;
- }
-
- 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 Collections.emptySet();
- }
-
- public String getRequestHeader(String name) {
- return null;
- }
-
- public List getRequestHeaders(String name) {
- return null;
- }
-
- public int getResponseStatus() {
- return responseStatus;
- }
-
- public String getResponseStatusMessage() {
- return responseStatusMessage;
- }
-
- public void writeHeaders() throws IOException {
-
- }
-
- public String getRemoteAddress() {
- return null;
- }
-
-}