use of io.micronaut.http.server.netty.NettyHttpRequest in project micronaut-core by micronaut-projects.
the class NettySystemFileCustomizableResponseType method write.
@Override
public void write(HttpRequest<?> request, MutableHttpResponse<?> response, ChannelHandlerContext context) {
if (response instanceof NettyMutableHttpResponse) {
NettyMutableHttpResponse nettyResponse = ((NettyMutableHttpResponse) response);
// Write the request data
final DefaultHttpResponse finalResponse = new DefaultHttpResponse(nettyResponse.getNettyHttpVersion(), nettyResponse.getNettyHttpStatus(), nettyResponse.getNettyHeaders());
if (request instanceof NettyHttpRequest) {
((NettyHttpRequest<?>) request).prepareHttp2ResponseIfNecessary(finalResponse);
}
context.write(finalResponse, context.voidPromise());
FileHolder file = new FileHolder(getFile());
// Write the content.
if (context.pipeline().get(SslHandler.class) == null && context.pipeline().get(SmartHttpContentCompressor.class).shouldSkip(finalResponse)) {
// SSL not enabled - can use zero-copy file transfer.
context.write(new DefaultFileRegion(file.raf.getChannel(), 0, getLength()), context.newProgressivePromise()).addListener(file);
context.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
} else {
// SSL enabled - cannot use zero-copy file transfer.
try {
// HttpChunkedInput will write the end marker (LastHttpContent) for us.
final HttpChunkedInput chunkedInput = new HttpChunkedInput(new ChunkedFile(file.raf, 0, getLength(), LENGTH_8K));
context.writeAndFlush(chunkedInput, context.newProgressivePromise()).addListener(file);
} catch (IOException e) {
throw new CustomizableResponseTypeException("Could not read file", e);
}
}
} else {
throw new IllegalArgumentException("Unsupported response type. Not a Netty response: " + response);
}
}
use of io.micronaut.http.server.netty.NettyHttpRequest in project micronaut-core by micronaut-projects.
the class NettyServerWebSocketUpgradeHandler method handleHandshake.
/**
* Do the handshaking for WebSocket request.
*
* @param ctx The channel handler context
* @param req The request
* @param webSocketBean The web socket bean
* @param response The response
* @return The channel future
*/
protected ChannelFuture handleHandshake(ChannelHandlerContext ctx, NettyHttpRequest req, WebSocketBean<?> webSocketBean, MutableHttpResponse<?> response) {
int maxFramePayloadLength = webSocketBean.messageMethod().map(m -> m.intValue(OnMessage.class, "maxPayloadLength").orElse(65536)).orElse(65536);
String subprotocols = webSocketBean.getBeanDefinition().stringValue(ServerWebSocket.class, "subprotocols").filter(s -> !StringUtils.isEmpty(s)).orElse(null);
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(getWebSocketURL(ctx, req), subprotocols, true, maxFramePayloadLength);
handshaker = wsFactory.newHandshaker(req.getNativeRequest());
MutableHttpHeaders headers = response.getHeaders();
io.netty.handler.codec.http.HttpHeaders nettyHeaders;
if (headers instanceof NettyHttpHeaders) {
nettyHeaders = ((NettyHttpHeaders) headers).getNettyHeaders();
} else {
nettyHeaders = new DefaultHttpHeaders();
for (Map.Entry<String, List<String>> entry : headers) {
nettyHeaders.add(entry.getKey(), entry.getValue());
}
}
Channel channel = ctx.channel();
if (handshaker == null) {
return WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(channel);
} else {
return handshaker.handshake(channel, req.getNativeRequest(), nettyHeaders, channel.newPromise());
}
}
use of io.micronaut.http.server.netty.NettyHttpRequest 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.http.server.netty.NettyHttpRequest in project micronaut-core by micronaut-projects.
the class HttpRequestTest method testForEach.
public void testForEach() {
final DefaultFullHttpRequest nettyRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, io.netty.handler.codec.http.HttpMethod.GET, "/test");
nettyRequest.headers().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
HttpRequest<?> request = new NettyHttpRequest(nettyRequest, new DetachedMockFactory().Mock(ChannelHandlerContext.class), ConversionService.SHARED, new HttpServerConfiguration());
final HttpHeaders headers = request.getHeaders();
headers.forEach((name, values) -> {
assertEquals(HttpHeaders.CONTENT_TYPE, name);
assertEquals(1, values.size());
assertEquals(MediaType.APPLICATION_JSON, values.iterator().next());
});
}
use of io.micronaut.http.server.netty.NettyHttpRequest in project micronaut-core by micronaut-projects.
the class MultipartBodyArgumentBinder method bind.
@Override
public BindingResult<MultipartBody> bind(ArgumentConversionContext<MultipartBody> context, HttpRequest<?> source) {
if (source instanceof NettyHttpRequest) {
NettyHttpRequest nettyHttpRequest = (NettyHttpRequest) source;
io.netty.handler.codec.http.HttpRequest nativeRequest = nettyHttpRequest.getNativeRequest();
if (nativeRequest instanceof StreamedHttpRequest) {
HttpContentProcessor<?> processor = beanLocator.findBean(HttpContentSubscriberFactory.class, new ConsumesMediaTypeQualifier<>(MediaType.MULTIPART_FORM_DATA_TYPE)).map(factory -> factory.build(nettyHttpRequest)).orElse(new DefaultHttpContentProcessor(nettyHttpRequest, httpServerConfiguration.get()));
// noinspection unchecked
return () -> Optional.of(subscriber -> processor.subscribe(new TypedSubscriber<Object>((Argument) context.getArgument()) {
Subscription s;
AtomicLong partsRequested = new AtomicLong(0);
@Override
protected void doOnSubscribe(Subscription subscription) {
this.s = subscription;
subscriber.onSubscribe(new Subscription() {
@Override
public void request(long n) {
if (partsRequested.getAndUpdate(prev -> prev + n) == 0) {
s.request(n);
}
}
@Override
public void cancel() {
subscription.cancel();
}
});
}
@Override
protected void doOnNext(Object message) {
if (LOG.isTraceEnabled()) {
LOG.trace("Server received streaming message for argument [{}]: {}", context.getArgument(), message);
}
if (message instanceof ByteBufHolder && ((ByteBufHolder) message).content() instanceof EmptyByteBuf) {
return;
}
if (message instanceof HttpData) {
HttpData data = (HttpData) message;
if (data.isCompleted()) {
partsRequested.decrementAndGet();
if (data instanceof FileUpload) {
subscriber.onNext(new NettyCompletedFileUpload((FileUpload) data, false));
} else if (data instanceof Attribute) {
subscriber.onNext(new NettyCompletedAttribute((Attribute) data, false));
}
// If the user didn't release the data, we should
if (data.refCnt() > 0) {
data.release();
}
}
}
if (partsRequested.get() > 0) {
s.request(1);
}
}
@Override
protected void doOnError(Throwable t) {
if (LOG.isTraceEnabled()) {
LOG.trace("Server received error for argument [" + context.getArgument() + "]: " + t.getMessage(), t);
}
try {
subscriber.onError(t);
} finally {
s.cancel();
}
}
@Override
protected void doOnComplete() {
if (LOG.isTraceEnabled()) {
LOG.trace("Done receiving messages for argument: {}", context.getArgument());
}
subscriber.onComplete();
}
}));
}
}
return BindingResult.EMPTY;
}
Aggregations