Skip to content

Commit

Permalink
Added cors, afterResponse methods
Browse files Browse the repository at this point in the history
  • Loading branch information
LatvianModder committed Nov 20, 2024
1 parent e613cb5 commit f2a1bd2
Show file tree
Hide file tree
Showing 13 changed files with 146 additions and 18 deletions.
20 changes: 15 additions & 5 deletions src/main/java/dev/latvian/apps/tinyserver/HTTPServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,20 @@ public void http(HTTPMethod method, String path, HTTPHandler<REQ> handler) {
var pathHandler = new HTTPPathHandler<>(method, compiledPath, handler);

if (compiledPath == CompiledPath.EMPTY) {
rootHandlers.put(method, pathHandler);
if (!rootHandlers.containsKey(method)) {
rootHandlers.put(method, pathHandler);
}
} else {
var hl = handlers.computeIfAbsent(method, HandlerList::new);

if (compiledPath.variables() > 0) {
hl.dynamicHandlers().add(pathHandler);
} else {
hl.staticHandlers().put(Arrays.stream(compiledPath.parts()).map(CompiledPath.Part::name).collect(Collectors.joining("/")), pathHandler);
var p = Arrays.stream(compiledPath.parts()).map(CompiledPath.Part::name).collect(Collectors.joining("/"));

if (!hl.staticHandlers().containsKey(p)) {
hl.staticHandlers().put(p, pathHandler);
}
}
}
}
Expand Down Expand Up @@ -433,13 +439,17 @@ public HTTPPayload createBuilder(REQ req, @Nullable HTTPHandler<REQ> handler) {
response = handler.handle(req);
error = null;
} catch (Throwable error1) {
response = error1 instanceof HTTPError h ? h.getStatus() : HTTPStatus.INTERNAL_ERROR;
response = (error1 instanceof HTTPError h ? h.getStatus() : HTTPStatus.INTERNAL_ERROR).defaultResponse();
error = error1;
}

payload.setResponse(req.handleResponse(payload, response, error));
var res = req.handleResponse(payload, response, error);
payload.setResponse(res);
req.afterResponse(payload, res, handler, error);
} else {
payload.setResponse(HTTPStatus.NOT_FOUND.defaultResponse());
var res = HTTPStatus.NOT_FOUND.defaultResponse();
payload.setResponse(res);
req.afterResponse(payload, res, null, null);
}

return payload;
Expand Down
44 changes: 44 additions & 0 deletions src/main/java/dev/latvian/apps/tinyserver/OptionalString.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import dev.latvian.apps.tinyserver.http.response.error.client.BadRequestError;

import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.function.Function;

public record OptionalString(String value) {
Expand Down Expand Up @@ -148,4 +150,46 @@ public double asDouble(double def) {
return def;
}
}

public ZoneId asZoneId() {
if (value == null) {
return ZoneOffset.UTC;
}

var string = asString("UTC");

if (string.isEmpty() || string.equals("UTC")) {
return ZoneOffset.UTC;
} else if (string.startsWith("GMT")) {
string = "Etc/" + string;
}

try {
return ZoneId.of(string);
} catch (Exception ignore) {
}

var l = string.toLowerCase();
var allZones = ZoneId.getAvailableZoneIds();

try {
for (var s : allZones) {
if (s.toLowerCase().equals(l)) {
return ZoneId.of(s);
}
}
} catch (Exception ignore) {
}

try {
for (var s : allZones) {
if (s.toLowerCase().contains(l)) {
return ZoneId.of(s);
}
}
} catch (Exception ignore) {
}

throw new IllegalArgumentException("Unknown zone ID!");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@

public interface HTTPHandler<REQ extends HTTPRequest> {
HTTPResponse handle(REQ req) throws Exception;

default boolean isFileHandler() {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ public String ip() {
return header("CF-Connecting-IP").asString();
}

public String ipv6() {
return header("CF-Connecting-IPv6").asString();
}

public String country() {
return header("CF-IPCountry").asString("XX");
}
Expand All @@ -275,4 +279,7 @@ public HTTPResponse handleResponse(HTTPPayload payload, HTTPResponse response, @

return response;
}

public void afterResponse(HTTPPayload payload, HTTPResponse response, @Nullable HTTPHandler<?> handler, @Nullable Throwable error) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ public HTTPResponse handle(REQ req) throws IOException {

return HTTPStatus.NOT_FOUND;
}

@Override
public boolean isFileHandler() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,9 @@ public static HTTPResponse index(String httpPath, Path rootDirectory, Path direc

return HTTPResponse.ok().content(sb, MimeType.HTML);
}

@Override
public boolean isFileHandler() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,22 @@

@FunctionalInterface
public interface FileResponseHandler {
record PublicCache(Duration duration, boolean gzip) implements FileResponseHandler {
record Cache(Duration duration, boolean gzip, boolean cacheStyleAndScripts) implements FileResponseHandler {
@Override
public HTTPResponse apply(HTTPResponse response, boolean directory, Path path) {
if (!directory) {
if (duration.isZero()) {
response = response.noCache();
if (!duration.isZero()) {
if (cacheStyleAndScripts) {
response = response.publicCache(duration);
} else {
var n = path.toString();

if (n.endsWith(".css") || n.endsWith(".js")) {
response = response.noCache();
} else {
response = response.publicCache(duration);
}
}
}

if (gzip) {
Expand All @@ -24,12 +34,15 @@ public HTTPResponse apply(HTTPResponse response, boolean directory, Path path) {
}
}

static FileResponseHandler publicCache(Duration duration, boolean gzip) {
return new PublicCache(duration, gzip);
FileResponseHandler CACHE_5_MIN = cache(Duration.ofMinutes(5L));
FileResponseHandler CACHE_1_HOUR = cache(Duration.ofHours(1L));

static FileResponseHandler cache(Duration duration, boolean gzip, boolean cacheStyleAndScripts) {
return new Cache(duration, gzip, cacheStyleAndScripts);
}

static FileResponseHandler publicCache(long minutes, boolean gzip) {
return publicCache(Duration.ofMinutes(minutes), gzip);
static FileResponseHandler cache(Duration duration) {
return new Cache(duration, true, false);
}

HTTPResponse apply(HTTPResponse response, boolean directory, Path path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,9 @@ public HTTPResponse handle(REQ req) {

return HTTPStatus.NOT_FOUND;
}

@Override
public boolean isFileHandler() {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package dev.latvian.apps.tinyserver.http.response;

public record CORSResponse(HTTPResponse original, String value) implements ChainedHTTPResponse {
@Override
public void build(HTTPPayload payload) {
payload.setCors(value);
original.build(payload);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class HTTPPayload {
private HTTPStatus status = HTTPStatus.NO_CONTENT;
private final List<Header> headers = new ArrayList<>();
private String cacheControl = "";
private String cors = "";
private Map<String, String> cookies;
private ResponseContent body = ByteContent.EMPTY;
private HTTPUpgrade<?> upgrade = null;
Expand All @@ -51,6 +52,7 @@ public void clear() {
status = HTTPStatus.NO_CONTENT;
headers.clear();
cacheControl = "";
cors = "";
cookies = null;
body = ByteContent.EMPTY;
upgrade = null;
Expand Down Expand Up @@ -88,6 +90,14 @@ public String getCacheControl() {
return cacheControl;
}

public void setCors(String cors) {
this.cors = cors;
}

public String getCors() {
return cors;
}

public void setCookie(String key, String value) {
if (cookies == null) {
cookies = new HashMap<>(1);
Expand Down Expand Up @@ -160,6 +170,7 @@ public void process(HTTPRequest req, int keepAliveTimeout, int maxKeepAliveConne
responseHeaders = new ArrayList<>(headers.size()
+ (cookies == null ? 0 : cookies.size())
+ (cacheControl.isEmpty() ? 0 : 1)
+ (cors.isEmpty() ? 0 : 1)
+ (hasBodyData ? 2 : 1)
+ (responseEncodings == null ? 0 : 1)
);
Expand All @@ -182,6 +193,10 @@ public void process(HTTPRequest req, int keepAliveTimeout, int maxKeepAliveConne
responseHeaders.add(new Header("Cache-Control", cacheControl));
}

if (!cors.isEmpty()) {
responseHeaders.add(new Header("Access-Control-Allow-Origin", cors));
}

if (responseEncodings != null) {
responseHeaders.add(new Header("Content-Encoding", responseEncodings));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ default HTTPResponse privateCache(Duration duration) {
return cache(false, duration);
}

default HTTPResponse cors(String value) {
return new CORSResponse(this, value);
}

default HTTPResponse cors() {
return cors("*");
}

default HTTPResponse content(ResponseContent content) {
return new ContentResponse(this, content);
}
Expand All @@ -100,7 +108,7 @@ default HTTPResponse content(byte[] bytes, String type) {
}

default HTTPResponse content(CharSequence string, String type) {
return new ContentResponse(this, new ByteContent(string.toString().getBytes(StandardCharsets.UTF_8), type));
return new ContentResponse(this, new ByteContent(String.valueOf(string).getBytes(StandardCharsets.UTF_8), type));
}

default HTTPResponse content(Path file, String overrideType) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.latvian.apps.tinyserver.http.response;

import dev.latvian.apps.tinyserver.StatusCode;
import dev.latvian.apps.tinyserver.content.MimeType;
import org.jetbrains.annotations.Nullable;

import java.nio.ByteBuffer;
Expand Down Expand Up @@ -148,7 +149,7 @@ public int code() {

public HTTPResponse defaultResponse() {
if (defaultResponse == null) {
return text(statusCode.message());
defaultResponse = content(statusCode.message(), MimeType.TEXT);
}

return defaultResponse;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@ public static void main(String[] args) throws IOException {
server.post("/form-submit", TinyServerTest::formSubmit);

var testFilesDir = Path.of("src/test/resources");
server.dynamicFiles("/files/dynamic", testFilesDir, FileResponseHandler.publicCache(1L, true), true);
server.dynamicFiles("/files/dynamic-no-index", testFilesDir, FileResponseHandler.publicCache(1L, true), false);
server.staticFiles("/files/static", testFilesDir, FileResponseHandler.publicCache(1L, true), true);
server.staticFiles("/files/static-no-index", testFilesDir, FileResponseHandler.publicCache(1L, true), false);
var cache = FileResponseHandler.CACHE_5_MIN;

server.dynamicFiles("/files/dynamic", testFilesDir, cache, true);
server.dynamicFiles("/files/dynamic-no-index", testFilesDir, cache, false);
server.staticFiles("/files/static", testFilesDir, cache, true);
server.staticFiles("/files/static-no-index", testFilesDir, cache, false);

wsHandler = server.ws("/console/{console-type}", TestWSSession::new);

Expand Down

0 comments on commit f2a1bd2

Please sign in to comment.