use of io.micronaut.web.router.UriRouteMatch in project micronaut-core by micronaut-projects.
the class NettyServerWebSocketUpgradeHandler method channelRead0.
@Override
protected final void channelRead0(ChannelHandlerContext ctx, NettyHttpRequest<?> msg) {
ServerRequestContext.set(msg);
Optional<UriRouteMatch<Object, Object>> optionalRoute = router.find(HttpMethod.GET, msg.getUri().toString(), msg).filter(rm -> rm.isAnnotationPresent(OnMessage.class) || rm.isAnnotationPresent(OnOpen.class)).findFirst();
MutableHttpResponse<?> proceed = HttpResponse.ok();
AtomicReference<HttpRequest<?>> requestReference = new AtomicReference<>(msg);
Flux<MutableHttpResponse<?>> responsePublisher;
if (optionalRoute.isPresent()) {
UriRouteMatch<Object, Object> rm = optionalRoute.get();
msg.setAttribute(HttpAttributes.ROUTE_MATCH, rm);
msg.setAttribute(HttpAttributes.ROUTE_INFO, rm);
proceed.setAttribute(HttpAttributes.ROUTE_MATCH, rm);
proceed.setAttribute(HttpAttributes.ROUTE_INFO, rm);
responsePublisher = Flux.just(proceed);
} else {
responsePublisher = routeExecutor.onError(new HttpStatusException(HttpStatus.NOT_FOUND, "WebSocket Not Found"), msg);
}
Publisher<? extends MutableHttpResponse<?>> finalPublisher = routeExecutor.filterPublisher(requestReference, responsePublisher);
final Scheduler scheduler = Schedulers.fromExecutorService(ctx.channel().eventLoop());
Mono.from(finalPublisher).publishOn(scheduler).subscribeOn(scheduler).contextWrite(reactorContext -> reactorContext.put(ServerRequestContext.KEY, requestReference.get())).subscribe((Consumer<MutableHttpResponse<?>>) actualResponse -> {
if (actualResponse == proceed) {
UriRouteMatch routeMatch = actualResponse.getAttribute(HttpAttributes.ROUTE_MATCH, UriRouteMatch.class).get();
WebSocketBean<?> webSocketBean = webSocketBeanRegistry.getWebSocket(routeMatch.getTarget().getClass());
handleHandshake(ctx, msg, webSocketBean, actualResponse);
ChannelPipeline pipeline = ctx.pipeline();
try {
NettyServerWebSocketHandler webSocketHandler = new NettyServerWebSocketHandler(nettyEmbeddedServices, webSocketSessionRepository, handshaker, webSocketBean, msg, routeMatch, ctx, routeExecutor.getCoroutineHelper().orElse(null));
pipeline.addBefore(ctx.name(), NettyServerWebSocketHandler.ID, webSocketHandler);
pipeline.remove(ChannelPipelineCustomizer.HANDLER_HTTP_STREAM);
pipeline.remove(NettyServerWebSocketUpgradeHandler.this);
ChannelHandler accessLoggerHandler = pipeline.get(ChannelPipelineCustomizer.HANDLER_ACCESS_LOGGER);
if (accessLoggerHandler != null) {
pipeline.remove(accessLoggerHandler);
}
} catch (Throwable e) {
if (LOG.isErrorEnabled()) {
LOG.error("Error opening WebSocket: " + e.getMessage(), e);
}
ctx.writeAndFlush(new CloseWebSocketFrame(CloseReason.INTERNAL_ERROR.getCode(), CloseReason.INTERNAL_ERROR.getReason()));
}
} else {
ctx.writeAndFlush(actualResponse);
}
});
}
use of io.micronaut.web.router.UriRouteMatch in project micronaut-core by micronaut-projects.
the class RoutingInBoundHandler method channelRead0.
@Override
protected void channelRead0(ChannelHandlerContext ctx, io.micronaut.http.HttpRequest<?> request) {
ctx.channel().config().setAutoRead(false);
io.micronaut.http.HttpMethod httpMethod = request.getMethod();
String requestPath = request.getUri().getPath();
ServerRequestContext.set(request);
if (LOG.isDebugEnabled()) {
LOG.debug("Request {} {}", httpMethod, request.getUri());
}
NettyHttpRequest nettyHttpRequest = (NettyHttpRequest) request;
io.netty.handler.codec.http.HttpRequest nativeRequest = nettyHttpRequest.getNativeRequest();
// handle decoding failure
DecoderResult decoderResult = nativeRequest.decoderResult();
if (decoderResult.isFailure()) {
Throwable cause = decoderResult.cause();
HttpStatus status = cause instanceof TooLongFrameException ? HttpStatus.REQUEST_ENTITY_TOO_LARGE : HttpStatus.BAD_REQUEST;
handleStatusError(ctx, nettyHttpRequest, HttpResponse.status(status), status.getReason());
return;
}
MediaType contentType = request.getContentType().orElse(null);
final String requestMethodName = request.getMethodName();
if (!multipartEnabled && contentType != null && contentType.equals(MediaType.MULTIPART_FORM_DATA_TYPE)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Multipart uploads have been disabled via configuration. Rejected request for URI {}, method {}, and content type {}", request.getUri(), requestMethodName, contentType);
}
handleStatusError(ctx, nettyHttpRequest, HttpResponse.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE), "Content Type [" + contentType + "] not allowed");
return;
}
UriRouteMatch<Object, Object> routeMatch = null;
List<UriRouteMatch<Object, Object>> uriRoutes = router.findAllClosest(request);
if (uriRoutes.size() > 1) {
throw new DuplicateRouteException(requestPath, uriRoutes);
} else if (uriRoutes.size() == 1) {
UriRouteMatch<Object, Object> establishedRoute = uriRoutes.get(0);
request.setAttribute(HttpAttributes.ROUTE, establishedRoute.getRoute());
request.setAttribute(HttpAttributes.ROUTE_MATCH, establishedRoute);
request.setAttribute(HttpAttributes.ROUTE_INFO, establishedRoute);
request.setAttribute(HttpAttributes.URI_TEMPLATE, establishedRoute.getRoute().getUriMatchTemplate().toString());
routeMatch = establishedRoute;
}
RouteMatch<?> route;
if (routeMatch == null) {
// Check if there is a file for the route before returning route not found
Optional<? extends FileCustomizableResponseType> optionalFile = matchFile(requestPath);
if (optionalFile.isPresent()) {
filterAndEncodeResponse(ctx, nettyHttpRequest, Flux.just(HttpResponse.ok(optionalFile.get())));
return;
}
if (LOG.isDebugEnabled()) {
LOG.debug("No matching route: {} {}", httpMethod, request.getUri());
}
// if there is no route present try to locate a route that matches a different HTTP method
final List<UriRouteMatch<?, ?>> anyMatchingRoutes = router.findAny(request.getUri().toString(), request).collect(Collectors.toList());
final Collection<MediaType> acceptedTypes = request.accept();
final boolean hasAcceptHeader = CollectionUtils.isNotEmpty(acceptedTypes);
Set<MediaType> acceptableContentTypes = contentType != null ? new HashSet<>(5) : null;
Set<String> allowedMethods = new HashSet<>(5);
Set<MediaType> produceableContentTypes = hasAcceptHeader ? new HashSet<>(5) : null;
for (UriRouteMatch<?, ?> anyRoute : anyMatchingRoutes) {
final String routeMethod = anyRoute.getRoute().getHttpMethodName();
if (!requestMethodName.equals(routeMethod)) {
allowedMethods.add(routeMethod);
}
if (contentType != null && !anyRoute.doesConsume(contentType)) {
acceptableContentTypes.addAll(anyRoute.getRoute().getConsumes());
}
if (hasAcceptHeader && !anyRoute.doesProduce(acceptedTypes)) {
produceableContentTypes.addAll(anyRoute.getRoute().getProduces());
}
}
if (CollectionUtils.isNotEmpty(acceptableContentTypes)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Content type not allowed for URI {}, method {}, and content type {}", request.getUri(), requestMethodName, contentType);
}
handleStatusError(ctx, nettyHttpRequest, HttpResponse.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE), "Content Type [" + contentType + "] not allowed. Allowed types: " + acceptableContentTypes);
return;
}
if (CollectionUtils.isNotEmpty(produceableContentTypes)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Content type not allowed for URI {}, method {}, and content type {}", request.getUri(), requestMethodName, contentType);
}
handleStatusError(ctx, nettyHttpRequest, HttpResponse.status(HttpStatus.NOT_ACCEPTABLE), "Specified Accept Types " + acceptedTypes + " not supported. Supported types: " + produceableContentTypes);
return;
}
if (!allowedMethods.isEmpty()) {
if (LOG.isDebugEnabled()) {
LOG.debug("Method not allowed for URI {} and method {}", request.getUri(), requestMethodName);
}
handleStatusError(ctx, nettyHttpRequest, HttpResponse.notAllowedGeneric(allowedMethods), "Method [" + requestMethodName + "] not allowed for URI [" + request.getUri() + "]. Allowed methods: " + allowedMethods);
return;
} else {
handleStatusError(ctx, nettyHttpRequest, HttpResponse.status(HttpStatus.NOT_FOUND), "Page Not Found");
}
return;
} else {
route = routeMatch;
}
if (LOG.isTraceEnabled()) {
if (route instanceof MethodBasedRouteMatch) {
LOG.trace("Matched route {} - {} to controller {}", requestMethodName, requestPath, route.getDeclaringType());
} else {
LOG.trace("Matched route {} - {}", requestMethodName, requestPath);
}
}
// all ok proceed to try and execute the route
if (route.isWebSocketRoute()) {
handleStatusError(ctx, nettyHttpRequest, HttpResponse.status(HttpStatus.BAD_REQUEST), "Not a WebSocket request");
} else {
handleRouteMatch(route, nettyHttpRequest, ctx);
}
}
Aggregations