Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2997e6a
Incremented version number
JanHolger Nov 6, 2021
f289092
Update pom.xml
JulianFun123 Nov 8, 2021
1e8d867
Added controllerInitiator
x7airworker Nov 28, 2021
d2fc017
Bumped version
x7airworker Nov 29, 2021
69eda02
Fixed body returning null when parsing fails
JanHolger Nov 29, 2021
4427afd
Merge pull request #13 from JavaWebStack/feature/controllerInitiator
JanHolger Nov 29, 2021
cdb5691
Merge remote-tracking branch 'origin/dev' into fix/validationForInval…
JanHolger Nov 29, 2021
6930783
Merge pull request #14 from JavaWebStack/fix/validationForInvalidJson…
JulianFun123 Nov 29, 2021
9cd7a0c
Started to implement a custom http server as an alternative to jetty
JanHolger Dec 3, 2021
fb70dd7
Abstracted the http server logic to allow for using a custom http ser…
JanHolger Dec 5, 2021
313ac67
Fixed locale header
JanHolger Dec 5, 2021
bbe6c85
Made jetty optional and upgraded junit
JanHolger Dec 5, 2021
620c5da
Upgraded jetty from 9.44.x to 11.0.7 because the abstraction allowed …
JanHolger Dec 7, 2021
11d4a67
Added a check for websockets and switched back to jetty as the defaul…
JanHolger Dec 7, 2021
593457c
Merge pull request #15 from JavaWebStack/feature/own-http-server
JanHolger Dec 7, 2021
fe7c3fb
Quick fix for ci
JanHolger Dec 7, 2021
b65bfa3
Quick fix for websocket support in SimpleHTTPSocketServer
JanHolger Dec 7, 2021
0c5b8f4
Implemented Undertow
JanHolger Dec 14, 2021
5fb52ac
Implemented Undertow
JanHolger Dec 14, 2021
a576cd0
Fixed Undertow and added websocket support for it
JanHolger Dec 14, 2021
93c7dea
Removed jetty and downgraded back to Java 8
JanHolger Dec 15, 2021
19c936a
Upgraded to latest Undertow
JanHolger Dec 15, 2021
30409cb
Added an option to set the maximum worker threads
JanHolger Jan 11, 2022
b093159
Added a fix for setResponseStatus when the response is already started
JanHolger Feb 10, 2022
e41b700
Tried to fix empty request body in Undertow
JanHolger Feb 10, 2022
4dbf69a
Tried to fix empty request body in Undertow
JanHolger Feb 10, 2022
f2db13c
Added recursive method resolution of controllers
x7airworker Apr 16, 2022
1538312
Filter Object parentClass
x7airworker Apr 16, 2022
0d03ab1
Merge pull request #16 from JavaWebStack/feature/parentControllers
JanHolger Apr 16, 2022
b56577d
Update maven-deploy.yml
JanHolger May 2, 2022
a67492a
Update pom.xml
JanHolger May 2, 2022
4b73981
Added _method support for forms
x7airworker Jun 7, 2022
cae00df
Added _method override support
x7airworker Jun 7, 2022
62f1e56
Forgot isFormMethods check
x7airworker Jun 7, 2022
9514458
Merge pull request #18 from JavaWebStack/feature/formMethods
JanHolger Jun 7, 2022
9efbf59
Upgraded validator to release version
JanHolger Oct 7, 2022
6d8e5b7
Fixed build
JanHolger Oct 7, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ work-in-progress project though so it's not yet complete.
<dependency>
<groupId>org.javawebstack</groupId>
<artifactId>http-server</artifactId>
<version>1.0.1</version>
<version>1.0.2</version>
</dependency>
```
36 changes: 22 additions & 14 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<buildVersion>1.0.1-SNAPSHOT</buildVersion>
<buildVersion>1.0.2-SNAPSHOT</buildVersion>
</properties>

<groupId>org.javawebstack</groupId>
Expand All @@ -32,6 +32,12 @@
<organization>JavaWebStack</organization>
<organizationUrl>https://javawebstack.org</organizationUrl>
</developer>
<developer>
<name>Julian Gojani</name>
<email>julian@gojani.xyz</email>
<organization>JavaWebStack</organization>
<organizationUrl>https://javawebstack.org</organizationUrl>
</developer>
</developers>

<scm>
Expand All @@ -44,17 +50,7 @@
<dependency>
<groupId>org.javawebstack</groupId>
<artifactId>validator</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.44.v20210927</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-server</artifactId>
<version>9.4.43.v20210629</version>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
Expand All @@ -64,12 +60,24 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.1</version>
<version>5.9.0</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-core</artifactId>
<version>2.2.19.Final</version>
</dependency>
<!--- Temporary fix for transitive vulnerabilities -->
<dependency>
<groupId>org.jboss.xnio</groupId>
<artifactId>xnio-api</artifactId>
<version>3.8.8.Final</version>
</dependency>
<!--- ============================================ -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.1</version>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
140 changes: 62 additions & 78 deletions src/main/java/org/javawebstack/httpserver/Exchange.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
package org.javawebstack.httpserver;

import org.javawebstack.abstractdata.AbstractElement;
import org.javawebstack.abstractdata.AbstractMapper;
import org.javawebstack.abstractdata.AbstractNull;
import org.javawebstack.abstractdata.AbstractObject;
import org.javawebstack.httpserver.helper.HttpMethod;
import org.javawebstack.httpserver.helper.MimeType;
import org.javawebstack.abstractdata.*;
import org.javawebstack.httpserver.adapter.IHTTPSocket;
import org.javawebstack.httpserver.util.MimeType;
import org.javawebstack.validator.ValidationContext;
import org.javawebstack.validator.ValidationException;
import org.javawebstack.validator.ValidationResult;
import org.javawebstack.validator.Validator;

import javax.servlet.MultipartConfigElement;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Exchange {

Expand All @@ -29,22 +26,18 @@ public static Exchange current() {
}

private final HTTPServer server;
private final HttpMethod method;
private final String path;
private final HTTPMethod method;
private byte[] body = null;
private final Map<String, Object> pathVariables = new HashMap<>();
private final AbstractObject queryParameters;
private final HttpServletRequest request;
private final HttpServletResponse response;
private final IHTTPSocket socket;
private final Map<String, Object> attributes = new HashMap<>();

public Exchange(HTTPServer server, HttpServletRequest request, HttpServletResponse response) {
public Exchange(HTTPServer server, IHTTPSocket socket) {
this.server = server;
this.request = request;
this.response = response;
this.path = request.getPathInfo();
this.method = "websocket".equalsIgnoreCase(request.getHeader("Upgrade")) ? HttpMethod.WEBSOCKET : HttpMethod.valueOf(request.getMethod());
this.queryParameters = AbstractElement.fromFormData(request.getQueryString()).object();
this.socket = socket;
this.method = getRequestMethodFromSocket(socket);
this.queryParameters = AbstractElement.fromFormData(socket.getRequestQuery()).object();
}

public <T> T body(Class<T> clazz) {
Expand All @@ -60,30 +53,24 @@ public <T> T body(Class<T> clazz) {
if (body.length() == 0)
body = "{}";

String contentType = getContentType().toLowerCase();

if (contentType.contains(";")) {
contentType = contentType.split(";")[0].trim();
}

MimeType type = MimeType.byMimeType(contentType);
MimeType type = getMimeType();
if (type == null)
type = MimeType.JSON;
AbstractElement request = AbstractNull.INSTANCE;
AbstractElement request = null;
boolean arrayLike = clazz.isArray() || Collection.class.isAssignableFrom(clazz);
switch (type) {
case JSON:
request = AbstractElement.fromJson(body);
break;
case YAML:
request = AbstractElement.fromYaml(body, !(clazz.isArray() || Collection.class.isAssignableFrom(clazz)));
request = AbstractElement.fromYaml(body, !arrayLike);
break;
case X_WWW_FORM_URLENCODED:
request = AbstractElement.fromFormData(body);
break;
default:
request = new AbstractObject();
break;
}
if(request == null || request.isNull())
request = arrayLike ? new AbstractArray() : new AbstractObject();
ValidationResult result = Validator.getValidator(clazz).validate(new ValidationContext().attrib("exchange", this), request);
if (!result.isValid())
throw new ValidationException(result);
Expand All @@ -94,22 +81,23 @@ public HTTPServer getServer() {
return server;
}

public HttpMethod getMethod() {
public HTTPMethod getMethod() {
return method;
}

public String getPath() {
return path;
return socket.getRequestPath();
}

public String getContentType() {
return request.getContentType() != null ? request.getContentType() : "";
String contentType = socket.getRequestHeader("content-type");
return contentType != null ? contentType : "";
}

public byte[] read() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
InputStream is = request.getInputStream();
InputStream is = socket.getInputStream();
byte[] data = new byte[1024];
int r;
while (is.available() > 0) {
Expand All @@ -129,17 +117,17 @@ public Exchange write(String data) {

public Exchange write(byte[] bytes) {
try {
response.getOutputStream().write(bytes);
response.getOutputStream().flush();
socket.getOutputStream().write(bytes);
socket.getOutputStream().flush();
} catch (IOException ignored) {
}
return this;
}

public Exchange write(byte[] bytes, int offset, int length) {
try {
response.getOutputStream().write(bytes, offset, length);
response.getOutputStream().flush();
socket.getOutputStream().write(bytes, offset, length);
socket.getOutputStream().flush();
} catch (IOException ignored) {
}
return this;
Expand All @@ -156,49 +144,50 @@ public Exchange write(InputStream stream) throws IOException {

public Exchange close() {
try {
response.getOutputStream().close();
socket.close();
} catch (IOException ignored) {
}
return this;
}

public Exchange header(String header, String value) {
if (header.equalsIgnoreCase("content-type")) {
response.setContentType(value);
return this;
}
response.setHeader(header, value);
socket.setResponseHeader(header, value);
return this;
}

public Exchange status(int code) {
response.setStatus(code);
socket.setResponseStatus(code);
return this;
}

public String header(String header) {
return request.getHeader(header);
return socket.getRequestHeader(header);
}

public Exchange redirect(String url) {
response.setStatus(302);
socket.setResponseStatus(302);
socket.setResponseHeader("location", url);
try {
response.sendRedirect(url);
} catch (IOException ex) {
throw new RuntimeException(ex);
socket.writeHeaders();
} catch (IOException e) {
e.printStackTrace();
}
return this;
}

public List<Locale> locales() {
return Collections.list(request.getLocales());
String locale = socket.getRequestHeader("accept-language");
if(locale == null)
return new ArrayList<>();
return Stream.of(locale.split(" ?,")).map(s -> s.split(";")[0]).map(Locale::forLanguageTag).collect(Collectors.toList());
}

public Locale locale(Locale... possible) {
List<Locale> requested = locales();
if (possible.length == 0)
return request.getLocale();
return requested.size() > 0 ? requested.get(0) : null;
List<Locale> possibleList = Arrays.asList(possible);
for (Locale l : locales()) {
for (Locale l : requested) {
if (possibleList.contains(l))
return l;
}
Expand All @@ -212,15 +201,11 @@ public Exchange contentType(MimeType type) {
public Exchange contentType(String contentType) {
if (contentType == null || contentType.equals(""))
return contentType("text/plain");
return header("Content-Type", contentType);
return header("content-type", contentType);
}

public HttpServletRequest rawRequest() {
return request;
}

public HttpServletResponse rawResponse() {
return response;
public IHTTPSocket socket() {
return socket;
}

public <T> T attrib(String key) {
Expand Down Expand Up @@ -258,7 +243,7 @@ public <T> T query(String name, Class<T> type, T defaultValue) {
}

public String remoteAddr() {
return request.getRemoteAddr();
return socket.getRemoteAddress();
}

public Map<String, Object> getPathVariables() {
Expand Down Expand Up @@ -302,24 +287,23 @@ protected static AbstractElement getPathElement(AbstractElement source, String p
return getPathElement(getPathElement(source, spl[0]), path.substring(spl[0].length() + 1));
}

public Exchange enableMultipart() {
enableMultipart(System.getProperty("java.io.tmpdir"));
return this;
}

public Exchange enableMultipart(String location) {
enableMultipart(location, -1L);
return this;
}

public Exchange enableMultipart(String location, long maxFileSize) {
enableMultipart(location, maxFileSize, 1_048_576);
return this;
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);
}
return socket.getRequestMethod();
}

public MimeType getMimeType() {
String contentType = getContentType().toLowerCase();
if (contentType.contains(";")) {
contentType = contentType.split(";")[0].trim();
}

public Exchange enableMultipart(String location, long maxFileSize, int fileSizeThreshold) {
request.setAttribute("org.eclipse.jetty.multipartConfig", new MultipartConfigElement(location, maxFileSize, -1L, fileSizeThreshold));
return this;
return MimeType.byMimeType(contentType);
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package org.javawebstack.httpserver.helper;
package org.javawebstack.httpserver;

public enum HTTPMethod {

public enum HttpMethod {
GET,
POST,
PUT,
PATCH,
DELETE,
HEAD,
OPTIONS,
CONNECT,
MOVE,
TRACE,
CONNECT,
WEBSOCKET

}
Loading