From 38264cc0fa8cc26d7f0c395526ee65a2ef34cafe Mon Sep 17 00:00:00 2001 From: Maxim Nesen Date: Tue, 3 Oct 2023 13:07:44 +0200 Subject: [PATCH] Expect:100-continue fixes for Netty Signed-off-by: Maxim Nesen --- .../netty/connector/NettyConnector.java | 43 ++++++++----------- .../netty/httpserver/JerseyServerHandler.java | 2 +- .../nettyconnector/Expect100ContinueTest.java | 3 -- 3 files changed, 19 insertions(+), 29 deletions(-) diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java index 262c0e732cb..e4a8e1df9d4 100644 --- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java +++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java @@ -46,7 +46,6 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; @@ -413,27 +412,24 @@ public void operationComplete(io.netty.util.concurrent.Future futu final Expect100ContinueConnectorExtension expect100ContinueExtension = new Expect100ContinueConnectorExtension(); - final DefaultFullHttpRequest rq = new DefaultFullHttpRequest(nettyRequest.protocolVersion(), - nettyRequest.method(), nettyRequest.uri()); - rq.headers().setAll(nettyRequest.headers()); - expect100ContinueExtension.invoke(jerseyRequest, rq); - - ChannelFutureListener expect100ContinueListener = null; - ChannelFuture expect100ContinueFuture = null; - - if (HttpUtil.is100ContinueExpected(rq)) { - expect100ContinueListener = - future -> { - if (future.isSuccess()) { - entityWriter.writeAndFlush(nettyRequest); - } else { - future.channel().pipeline().fireExceptionCaught(future.cause()); - } - }; - expect100ContinueFuture = ch.pipeline().writeAndFlush(rq).sync().awaitUninterruptibly() - .addListener(expect100ContinueListener); - } else { - // Send the HTTP request. + final DefaultFullHttpRequest nettyRequestHeaders = + new DefaultFullHttpRequest(nettyRequest.protocolVersion(), nettyRequest.method(), nettyRequest.uri()); + nettyRequestHeaders.headers().setAll(nettyRequest.headers()); + //If Expect:100-continue feature is enabled and client supports it, the nettyRequestHeaders will be + //enriched with the 'Expect:100-continue' header. + expect100ContinueExtension.invoke(jerseyRequest, nettyRequestHeaders); + + final ChannelFuture expect100ContinueFuture = (HttpUtil.is100ContinueExpected(nettyRequestHeaders)) + // Send only head of the HTTP request enriched with Expect:100-continue header. + ? ch.writeAndFlush(nettyRequestHeaders).sync().awaitUninterruptibly() + // Expect:100-Continue either is not supported or is turned off + : null; + + + if (expect100ContinueFuture == null + || !expect100ContinueFuture.isSuccess()) { + // Send the HTTP request. In case of Expect:100-continue processing, this is the + // 2nd attempt without Expect:100-continue header. entityWriter.writeAndFlush(nettyRequest); } @@ -449,9 +445,6 @@ public OutputStream getOutputStream(int contentLength) throws IOException { } else { entityWriter.write(entityWriter.getChunkedInput()); } - if (expect100ContinueFuture != null && expect100ContinueListener != null) { - expect100ContinueFuture.removeListener(expect100ContinueListener); - } executorService.execute(new Runnable() { @Override diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerHandler.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerHandler.java index 8e3491a9f6c..1576f7e4421 100644 --- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerHandler.java +++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/nettyconnector/Expect100ContinueTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/nettyconnector/Expect100ContinueTest.java index 9c7900e3524..372cf8e0f99 100644 --- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/nettyconnector/Expect100ContinueTest.java +++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/nettyconnector/Expect100ContinueTest.java @@ -23,20 +23,17 @@ import org.glassfish.jersey.netty.connector.NettyConnectorProvider; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; -import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory; import org.glassfish.jersey.test.netty.NettyTestContainerFactory; import org.glassfish.jersey.test.spi.TestContainerException; import org.glassfish.jersey.test.spi.TestContainerFactory; import org.junit.jupiter.api.Test; -import javax.ws.rs.Consumes; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.client.Entity; import javax.ws.rs.core.Application; import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import static org.junit.jupiter.api.Assertions.assertEquals;