Skip to content

Commit

Permalink
Netty Expect 100-Continue fix
Browse files Browse the repository at this point in the history
Signed-off-by: Maxim Nesen <maxim.nesen@oracle.com>
  • Loading branch information
senivam committed Jan 23, 2025
1 parent a651077 commit fde00e0
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025 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
Expand All @@ -26,6 +26,7 @@
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.LastHttpContent;
import org.glassfish.jersey.client.ClientRequest;

import javax.ws.rs.ProcessingException;
Expand All @@ -40,6 +41,8 @@ public class JerseyExpectContinueHandler extends ChannelInboundHandlerAdapter {

private boolean isExpected;

private boolean expectReceived;

private static final List<HttpResponseStatus> statusesToBeConsidered = Arrays.asList(HttpResponseStatus.CONTINUE,
HttpResponseStatus.UNAUTHORIZED, HttpResponseStatus.EXPECTATION_FAILED,
HttpResponseStatus.METHOD_NOT_ALLOWED, HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE);
Expand All @@ -56,10 +59,12 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
if (!HttpResponseStatus.CONTINUE.equals(response.status())) {
ctx.fireChannelRead(msg); //bypass the message to the next handler in line
} else {
ctx.pipeline().remove(JerseyExpectContinueHandler.class);
expectReceived = true;
}
} else if (expectReceived && msg instanceof LastHttpContent) {
ctx.pipeline().remove(JerseyExpectContinueHandler.class);
} else {
if (!isExpected) {
if (!isExpected || expectedFuture.isDone()) {
ctx.pipeline().remove(JerseyExpectContinueHandler.class);
}
ctx.fireChannelRead(msg); //bypass the message to the next handler in line
Expand Down Expand Up @@ -93,9 +98,7 @@ CompletableFuture<HttpResponseStatus> processExpect100ContinueRequest(HttpReques
// Expect:100-Continue either is not supported or is turned off
: null;
isExpected = expect100ContinueFuture != null;
if (!isExpected) {
ch.pipeline().remove(JerseyExpectContinueHandler.class);
} else {
if (isExpected) {
final HttpResponseStatus status = expectedFuture
.get(timeout, TimeUnit.MILLISECONDS);

Expand All @@ -119,8 +122,4 @@ private void processExpectationStatus(HttpResponseStatus status)
.UNEXPECTED_VALUE_FOR_EXPECT_100_CONTINUE_STATUSES(status.code()), null);
}
}

boolean isExpected() {
return isExpected;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
Expand Down Expand Up @@ -255,6 +254,8 @@ protected void execute(final ClientRequest jerseyRequest, final Set<URI> redirec
}
}

final JerseyExpectContinueHandler expect100ContinueHandler = new JerseyExpectContinueHandler();

if (chan == null) {
Integer connectTimeout = jerseyRequest.resolveProperty(ClientProperties.CONNECT_TIMEOUT, 0);
Bootstrap b = new Bootstrap();
Expand Down Expand Up @@ -327,12 +328,15 @@ protected void initChannel(SocketChannel ch) throws Exception {
final Integer maxInitialLineLength = ClientProperties.getValue(config.getProperties(),
NettyClientProperties.MAX_INITIAL_LINE_LENGTH,
NettyClientProperties.DEFAULT_INITIAL_LINE_LENGTH);
/*
final Long aggregatorContentLength = ClientProperties.getValue(config.getProperties(),
ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE,
ClientProperties.DEFAULT_EXPECT_100_CONTINUE_THRESHOLD_SIZE);
*/

p.addLast(new HttpClientCodec(maxInitialLineLength, maxHeaderSize, maxChunkSize));
p.addLast(new HttpObjectAggregator(aggregatorContentLength.intValue()));
// p.addLast(new HttpObjectAggregator(aggregatorContentLength.intValue()));
p.addLast(EXPECT_100_CONTINUE_HANDLER, expect100ContinueHandler);
p.addLast(new ChunkedWriteHandler());
p.addLast(new HttpContentDecompressor());
}
Expand Down Expand Up @@ -361,11 +365,10 @@ protected void initChannel(SocketChannel ch) throws Exception {
final Channel ch = chan;
JerseyClientHandler clientHandler =
new JerseyClientHandler(jerseyRequest, responseAvailable, responseDone, redirectUriHistory, this);
final JerseyExpectContinueHandler expect100ContinueHandler = new JerseyExpectContinueHandler();

// read timeout makes sense really as an inactivity timeout
ch.pipeline().addLast(READ_TIMEOUT_HANDLER,
new IdleStateHandler(0, 0, timeout, TimeUnit.MILLISECONDS));
ch.pipeline().addLast(EXPECT_100_CONTINUE_HANDLER, expect100ContinueHandler);
ch.pipeline().addLast(REQUEST_HANDLER, clientHandler);

responseDone.whenComplete((_r, th) -> {
Expand Down

0 comments on commit fde00e0

Please sign in to comment.