Skip to content

Commit f2a1bd2

Browse files
committed
Added cors, afterResponse methods
1 parent e613cb5 commit f2a1bd2

File tree

13 files changed

+146
-18
lines changed

13 files changed

+146
-18
lines changed

src/main/java/dev/latvian/apps/tinyserver/HTTPServer.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,20 @@ public void http(HTTPMethod method, String path, HTTPHandler<REQ> handler) {
154154
var pathHandler = new HTTPPathHandler<>(method, compiledPath, handler);
155155

156156
if (compiledPath == CompiledPath.EMPTY) {
157-
rootHandlers.put(method, pathHandler);
157+
if (!rootHandlers.containsKey(method)) {
158+
rootHandlers.put(method, pathHandler);
159+
}
158160
} else {
159161
var hl = handlers.computeIfAbsent(method, HandlerList::new);
160162

161163
if (compiledPath.variables() > 0) {
162164
hl.dynamicHandlers().add(pathHandler);
163165
} else {
164-
hl.staticHandlers().put(Arrays.stream(compiledPath.parts()).map(CompiledPath.Part::name).collect(Collectors.joining("/")), pathHandler);
166+
var p = Arrays.stream(compiledPath.parts()).map(CompiledPath.Part::name).collect(Collectors.joining("/"));
167+
168+
if (!hl.staticHandlers().containsKey(p)) {
169+
hl.staticHandlers().put(p, pathHandler);
170+
}
165171
}
166172
}
167173
}
@@ -433,13 +439,17 @@ public HTTPPayload createBuilder(REQ req, @Nullable HTTPHandler<REQ> handler) {
433439
response = handler.handle(req);
434440
error = null;
435441
} catch (Throwable error1) {
436-
response = error1 instanceof HTTPError h ? h.getStatus() : HTTPStatus.INTERNAL_ERROR;
442+
response = (error1 instanceof HTTPError h ? h.getStatus() : HTTPStatus.INTERNAL_ERROR).defaultResponse();
437443
error = error1;
438444
}
439445

440-
payload.setResponse(req.handleResponse(payload, response, error));
446+
var res = req.handleResponse(payload, response, error);
447+
payload.setResponse(res);
448+
req.afterResponse(payload, res, handler, error);
441449
} else {
442-
payload.setResponse(HTTPStatus.NOT_FOUND.defaultResponse());
450+
var res = HTTPStatus.NOT_FOUND.defaultResponse();
451+
payload.setResponse(res);
452+
req.afterResponse(payload, res, null, null);
443453
}
444454

445455
return payload;

src/main/java/dev/latvian/apps/tinyserver/OptionalString.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

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

5+
import java.time.ZoneId;
6+
import java.time.ZoneOffset;
57
import java.util.function.Function;
68

79
public record OptionalString(String value) {
@@ -148,4 +150,46 @@ public double asDouble(double def) {
148150
return def;
149151
}
150152
}
153+
154+
public ZoneId asZoneId() {
155+
if (value == null) {
156+
return ZoneOffset.UTC;
157+
}
158+
159+
var string = asString("UTC");
160+
161+
if (string.isEmpty() || string.equals("UTC")) {
162+
return ZoneOffset.UTC;
163+
} else if (string.startsWith("GMT")) {
164+
string = "Etc/" + string;
165+
}
166+
167+
try {
168+
return ZoneId.of(string);
169+
} catch (Exception ignore) {
170+
}
171+
172+
var l = string.toLowerCase();
173+
var allZones = ZoneId.getAvailableZoneIds();
174+
175+
try {
176+
for (var s : allZones) {
177+
if (s.toLowerCase().equals(l)) {
178+
return ZoneId.of(s);
179+
}
180+
}
181+
} catch (Exception ignore) {
182+
}
183+
184+
try {
185+
for (var s : allZones) {
186+
if (s.toLowerCase().contains(l)) {
187+
return ZoneId.of(s);
188+
}
189+
}
190+
} catch (Exception ignore) {
191+
}
192+
193+
throw new IllegalArgumentException("Unknown zone ID!");
194+
}
151195
}

src/main/java/dev/latvian/apps/tinyserver/http/HTTPHandler.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@
44

55
public interface HTTPHandler<REQ extends HTTPRequest> {
66
HTTPResponse handle(REQ req) throws Exception;
7+
8+
default boolean isFileHandler() {
9+
return false;
10+
}
711
}

src/main/java/dev/latvian/apps/tinyserver/http/HTTPRequest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ public String ip() {
251251
return header("CF-Connecting-IP").asString();
252252
}
253253

254+
public String ipv6() {
255+
return header("CF-Connecting-IPv6").asString();
256+
}
257+
254258
public String country() {
255259
return header("CF-IPCountry").asString("XX");
256260
}
@@ -275,4 +279,7 @@ public HTTPResponse handleResponse(HTTPPayload payload, HTTPResponse response, @
275279

276280
return response;
277281
}
282+
283+
public void afterResponse(HTTPPayload payload, HTTPResponse response, @Nullable HTTPHandler<?> handler, @Nullable Throwable error) {
284+
}
278285
}

src/main/java/dev/latvian/apps/tinyserver/http/file/DynamicFileHandler.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,9 @@ public HTTPResponse handle(REQ req) throws IOException {
3434

3535
return HTTPStatus.NOT_FOUND;
3636
}
37+
38+
@Override
39+
public boolean isFileHandler() {
40+
return true;
41+
}
3742
}

src/main/java/dev/latvian/apps/tinyserver/http/file/FileIndexHandler.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,9 @@ public static HTTPResponse index(String httpPath, Path rootDirectory, Path direc
3737

3838
return HTTPResponse.ok().content(sb, MimeType.HTML);
3939
}
40+
41+
@Override
42+
public boolean isFileHandler() {
43+
return true;
44+
}
4045
}

src/main/java/dev/latvian/apps/tinyserver/http/file/FileResponseHandler.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,22 @@
77

88
@FunctionalInterface
99
public interface FileResponseHandler {
10-
record PublicCache(Duration duration, boolean gzip) implements FileResponseHandler {
10+
record Cache(Duration duration, boolean gzip, boolean cacheStyleAndScripts) implements FileResponseHandler {
1111
@Override
1212
public HTTPResponse apply(HTTPResponse response, boolean directory, Path path) {
1313
if (!directory) {
14-
if (duration.isZero()) {
15-
response = response.noCache();
14+
if (!duration.isZero()) {
15+
if (cacheStyleAndScripts) {
16+
response = response.publicCache(duration);
17+
} else {
18+
var n = path.toString();
19+
20+
if (n.endsWith(".css") || n.endsWith(".js")) {
21+
response = response.noCache();
22+
} else {
23+
response = response.publicCache(duration);
24+
}
25+
}
1626
}
1727

1828
if (gzip) {
@@ -24,12 +34,15 @@ public HTTPResponse apply(HTTPResponse response, boolean directory, Path path) {
2434
}
2535
}
2636

27-
static FileResponseHandler publicCache(Duration duration, boolean gzip) {
28-
return new PublicCache(duration, gzip);
37+
FileResponseHandler CACHE_5_MIN = cache(Duration.ofMinutes(5L));
38+
FileResponseHandler CACHE_1_HOUR = cache(Duration.ofHours(1L));
39+
40+
static FileResponseHandler cache(Duration duration, boolean gzip, boolean cacheStyleAndScripts) {
41+
return new Cache(duration, gzip, cacheStyleAndScripts);
2942
}
3043

31-
static FileResponseHandler publicCache(long minutes, boolean gzip) {
32-
return publicCache(Duration.ofMinutes(minutes), gzip);
44+
static FileResponseHandler cache(Duration duration) {
45+
return new Cache(duration, true, false);
3346
}
3447

3548
HTTPResponse apply(HTTPResponse response, boolean directory, Path path);

src/main/java/dev/latvian/apps/tinyserver/http/file/SingleFileHandler.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,9 @@ public HTTPResponse handle(REQ req) {
1717

1818
return HTTPStatus.NOT_FOUND;
1919
}
20+
21+
@Override
22+
public boolean isFileHandler() {
23+
return true;
24+
}
2025
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package dev.latvian.apps.tinyserver.http.response;
2+
3+
public record CORSResponse(HTTPResponse original, String value) implements ChainedHTTPResponse {
4+
@Override
5+
public void build(HTTPPayload payload) {
6+
payload.setCors(value);
7+
original.build(payload);
8+
}
9+
}

src/main/java/dev/latvian/apps/tinyserver/http/response/HTTPPayload.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class HTTPPayload {
3232
private HTTPStatus status = HTTPStatus.NO_CONTENT;
3333
private final List<Header> headers = new ArrayList<>();
3434
private String cacheControl = "";
35+
private String cors = "";
3536
private Map<String, String> cookies;
3637
private ResponseContent body = ByteContent.EMPTY;
3738
private HTTPUpgrade<?> upgrade = null;
@@ -51,6 +52,7 @@ public void clear() {
5152
status = HTTPStatus.NO_CONTENT;
5253
headers.clear();
5354
cacheControl = "";
55+
cors = "";
5456
cookies = null;
5557
body = ByteContent.EMPTY;
5658
upgrade = null;
@@ -88,6 +90,14 @@ public String getCacheControl() {
8890
return cacheControl;
8991
}
9092

93+
public void setCors(String cors) {
94+
this.cors = cors;
95+
}
96+
97+
public String getCors() {
98+
return cors;
99+
}
100+
91101
public void setCookie(String key, String value) {
92102
if (cookies == null) {
93103
cookies = new HashMap<>(1);
@@ -160,6 +170,7 @@ public void process(HTTPRequest req, int keepAliveTimeout, int maxKeepAliveConne
160170
responseHeaders = new ArrayList<>(headers.size()
161171
+ (cookies == null ? 0 : cookies.size())
162172
+ (cacheControl.isEmpty() ? 0 : 1)
173+
+ (cors.isEmpty() ? 0 : 1)
163174
+ (hasBodyData ? 2 : 1)
164175
+ (responseEncodings == null ? 0 : 1)
165176
);
@@ -182,6 +193,10 @@ public void process(HTTPRequest req, int keepAliveTimeout, int maxKeepAliveConne
182193
responseHeaders.add(new Header("Cache-Control", cacheControl));
183194
}
184195

196+
if (!cors.isEmpty()) {
197+
responseHeaders.add(new Header("Access-Control-Allow-Origin", cors));
198+
}
199+
185200
if (responseEncodings != null) {
186201
responseHeaders.add(new Header("Content-Encoding", responseEncodings));
187202
}

0 commit comments

Comments
 (0)