Add rate limiting, CORS support, custom HTTP method annotations, and HTTP server enhancements

- Introduced rate limiting functionality with multiple algorithms (Token Bucket, Fixed Window, Leaky Bucket, Sliding Window) via `RateLimiter` interface.
- Added CORS handling with `CorsConfig` and `CorsHandler` for flexible origin, headers, and method configuration.
- Implemented support for custom HTTP methods via `PATCH` and `CUSTOM` annotations in `AnnotationScanner`.
- Enhanced `HttpServer` to support builder pattern and optional integrations for CORS and rate limiting.
- Updated `HttpRequestHandler` to incorporate CORS and rate limiting logic.
This commit is contained in:
CodingPhoenix
2026-05-08 12:00:09 +02:00
parent 392658d54e
commit 05c6ad3dd4
15 changed files with 733 additions and 7 deletions
@@ -1,5 +1,8 @@
package dev.coph.nextusweb.server;
import dev.coph.nextusweb.server.cores.CorsHandler;
import dev.coph.nextusweb.server.ratelimit.RateLimitGate;
import dev.coph.nextusweb.server.ratelimit.RateLimiter;
import dev.coph.nextusweb.server.router.Request;
import dev.coph.nextusweb.server.router.Response;
import dev.coph.nextusweb.server.router.Router;
@@ -10,6 +13,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import java.net.InetSocketAddress;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
@@ -20,9 +24,14 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<FullHt
Executors.newVirtualThreadPerTaskExecutor();
private final Router router;
private final CorsHandler cors;
private final RateLimitGate rateLimit;
public HttpRequestHandler(Router router) {
public HttpRequestHandler(Router router, CorsHandler cors, RateLimitGate rateLimit) {
this.router = router;
this.cors = cors;
this.rateLimit = rateLimit;
}
@Override
@@ -38,7 +47,29 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<FullHt
}
private void handle(ChannelHandlerContext ctx, FullHttpRequest raw) {
String origin = raw.headers().get("Origin");
if (cors != null && cors.isPreflight(raw.method(), raw.headers())) {
send(ctx, cors.handlePreflight(origin, raw.headers()));
return;
}
String path = new QueryStringDecoder(raw.uri()).path();
RateLimiter.Result rlResult = null;
if (rateLimit != null) {
String remote = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress().getHostAddress();
rlResult = rateLimit.check(raw, path, remote);
if (rlResult != null && !rlResult.allowed()) {
Response res = new Response().status(429).json("{\"error\":\"Too Many Requests\"}");
RateLimitGate.applyHeaders(rlResult, res);
if (cors != null) cors.applyHeaders(origin, res);
send(ctx, res);
return;
}
}
Router.Resolution resolution = router.resolve(raw.method(), path);
Response res = new Response();
@@ -67,6 +98,8 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<FullHt
case Router.Resolution.NotFound nf -> res.status(404).json("{\"error\":\"Not Found\"}");
}
RateLimitGate.applyHeaders(rlResult, res);
if (cors != null) cors.applyHeaders(origin, res);
send(ctx, res);
}