Add comprehensive Javadoc documentation to server components, including annotations, request/response handling, routing, and WebSocket support.
This commit is contained in:
@@ -27,22 +27,56 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* The core inbound channel handler that processes every aggregated HTTP request.
|
||||
*
|
||||
* <p>For each request it, in order: detects and performs WebSocket upgrades (when a WebSocket
|
||||
* router is configured), answers CORS preflight requests, enforces rate limits, resolves the
|
||||
* route via the {@link Router}, runs middlewares and the matched handler, and finally writes the
|
||||
* response with CORS and rate-limit headers applied.</p>
|
||||
*
|
||||
* <p>Blocking handler logic runs on a virtual-thread executor rather than on the Netty event
|
||||
* loop, so handlers may perform blocking work without stalling I/O. WebSocket upgrades, by
|
||||
* contrast, mutate the pipeline and are handled inline on the event loop.</p>
|
||||
*/
|
||||
public final class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
|
||||
|
||||
/** Executor running one virtual thread per task, used to offload blocking handler work. */
|
||||
private static final Executor VT_EXECUTOR =
|
||||
Executors.newVirtualThreadPerTaskExecutor();
|
||||
|
||||
/** Router resolving requests to handlers. */
|
||||
private final Router router;
|
||||
/** CORS handler, or {@code null} if CORS is disabled. */
|
||||
private final CorsHandler cors;
|
||||
/** Rate-limit gate, or {@code null} if rate limiting is disabled. */
|
||||
private final RateLimitGate rateLimit;
|
||||
/** WebSocket router, or {@code null} if WebSocket support is disabled. */
|
||||
private final WebSocketRouter wsRouter;
|
||||
/** WebSocket configuration; only consulted when {@link #wsRouter} is non-null. */
|
||||
private final WebSocketConfig wsConfig;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a handler without WebSocket support.
|
||||
*
|
||||
* @param router the router resolving requests
|
||||
* @param cors the CORS handler, or {@code null} to disable CORS
|
||||
* @param rateLimit the rate-limit gate, or {@code null} to disable rate limiting
|
||||
*/
|
||||
public HttpRequestHandler(Router router, CorsHandler cors, RateLimitGate rateLimit) {
|
||||
this(router, cors, rateLimit, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a handler, optionally with WebSocket support.
|
||||
*
|
||||
* @param router the router resolving requests
|
||||
* @param cors the CORS handler, or {@code null} to disable CORS
|
||||
* @param rateLimit the rate-limit gate, or {@code null} to disable rate limiting
|
||||
* @param wsRouter the WebSocket router, or {@code null} to disable WebSocket support
|
||||
* @param wsConfig the WebSocket configuration, used only when {@code wsRouter} is non-null
|
||||
*/
|
||||
public HttpRequestHandler(Router router, CorsHandler cors, RateLimitGate rateLimit,
|
||||
WebSocketRouter wsRouter, WebSocketConfig wsConfig) {
|
||||
this.router = router;
|
||||
@@ -52,6 +86,14 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<FullHt
|
||||
this.wsConfig = wsConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point invoked by Netty for each fully aggregated request. WebSocket upgrade requests
|
||||
* are handled inline; all other requests are retained and dispatched to a virtual thread for
|
||||
* processing, with the request released once handling completes.
|
||||
*
|
||||
* @param ctx the channel context
|
||||
* @param req the aggregated HTTP request
|
||||
*/
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) {
|
||||
if (wsRouter != null && isWebSocketUpgrade(req)) {
|
||||
@@ -68,6 +110,14 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<FullHt
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a request is a WebSocket upgrade handshake, i.e. a {@code GET} carrying
|
||||
* {@code Upgrade: websocket} and a {@code Connection} header that includes the
|
||||
* {@code upgrade} token.
|
||||
*
|
||||
* @param req the request to inspect
|
||||
* @return {@code true} if the request is a WebSocket upgrade
|
||||
*/
|
||||
private static boolean isWebSocketUpgrade(FullHttpRequest req) {
|
||||
if (req.method() != HttpMethod.GET) return false;
|
||||
String upgrade = req.headers().get(HttpHeaderNames.UPGRADE);
|
||||
@@ -80,6 +130,20 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<FullHt
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to upgrade the connection to WebSocket for the request's path.
|
||||
*
|
||||
* <p>Resolves the path against the WebSocket router; if no handler matches the upgrade is
|
||||
* declined. Otherwise the origin is validated, the WebSocket protocol/compression/idle
|
||||
* handlers and the application frame handler are inserted into the pipeline, and the request
|
||||
* is re-fired so Netty performs the handshake.</p>
|
||||
*
|
||||
* @param ctx the channel context
|
||||
* @param req the upgrade request
|
||||
* @return {@code true} if the request was consumed (handshake started or rejected),
|
||||
* {@code false} if no WebSocket route matched and normal HTTP handling should
|
||||
* continue
|
||||
*/
|
||||
private boolean handleWebSocketUpgrade(ChannelHandlerContext ctx, FullHttpRequest req) {
|
||||
String path = new QueryStringDecoder(req.uri()).path();
|
||||
WebSocketRouter.Resolution resolution = wsRouter.resolve(path);
|
||||
@@ -125,6 +189,18 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<FullHt
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a normal (non-WebSocket) HTTP request: applies CORS preflight handling and rate
|
||||
* limiting, resolves the route, runs middlewares and the handler, and sends the response.
|
||||
*
|
||||
* <p>Exceptions from the handler are mapped to responses: a {@link BadRequestException}
|
||||
* becomes a {@code 400}, any other exception a {@code 500}. Routing misses become
|
||||
* {@code 404}, and method mismatches a {@code 405} with an {@code Allow} header. CORS and
|
||||
* rate-limit headers are applied to the final response in all cases.</p>
|
||||
*
|
||||
* @param ctx the channel context
|
||||
* @param raw the aggregated request being handled
|
||||
*/
|
||||
private void handle(ChannelHandlerContext ctx, FullHttpRequest raw) {
|
||||
String origin = raw.headers().get("Origin");
|
||||
|
||||
@@ -182,6 +258,13 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<FullHt
|
||||
send(ctx, res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the framework {@link Response} into a Netty {@link FullHttpResponse}, sets the
|
||||
* {@code Content-Length}, writes it and closes the connection afterwards.
|
||||
*
|
||||
* @param ctx the channel context
|
||||
* @param res the response to send
|
||||
*/
|
||||
private void send(ChannelHandlerContext ctx, Response res) {
|
||||
var nettyRes = new DefaultFullHttpResponse(
|
||||
HttpVersion.HTTP_1_1,
|
||||
@@ -193,8 +276,14 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<FullHt
|
||||
ctx.writeAndFlush(nettyRes).addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the channel on any unhandled pipeline exception.
|
||||
*
|
||||
* @param ctx the channel context
|
||||
* @param cause the exception that propagated up the pipeline
|
||||
*/
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user