Skip to content

Commit 5b6bef5

Browse files
authored
backport fix for oversized http content stream (#121255)
1 parent 92e9ffb commit 5b6bef5

File tree

2 files changed

+19
-24
lines changed

2 files changed

+19
-24
lines changed

modules/transport-netty4/src/main/java/org/elasticsearch/http/netty4/Netty4HttpContentSizeHandler.java

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import io.netty.handler.codec.http.HttpResponseStatus;
2727
import io.netty.handler.codec.http.HttpUtil;
2828
import io.netty.handler.codec.http.HttpVersion;
29-
import io.netty.handler.codec.http.LastHttpContent;
3029

3130
import org.elasticsearch.core.SuppressForbidden;
3231

@@ -92,7 +91,7 @@ public class Netty4HttpContentSizeHandler extends ChannelInboundHandlerAdapter {
9291
private final int maxContentLength;
9392
private final HttpRequestDecoder decoder; // need to reset decoder after sending 413
9493
private int currentContentLength; // chunked encoding does not provide content length, need to track actual length
95-
private boolean contentExpected;
94+
private boolean ignoreContent;
9695

9796
public Netty4HttpContentSizeHandler(HttpRequestDecoder decoder, int maxContentLength) {
9897
this.maxContentLength = maxContentLength;
@@ -110,7 +109,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
110109
}
111110

112111
private void handleRequest(ChannelHandlerContext ctx, HttpRequest request) {
113-
contentExpected = false;
112+
ignoreContent = true;
114113
if (request.decoderResult().isFailure()) {
115114
ctx.fireChannelRead(request);
116115
return;
@@ -135,13 +134,10 @@ private void handleRequest(ChannelHandlerContext ctx, HttpRequest request) {
135134
// See https://www.rfc-editor.org/rfc/rfc9110.html#section-10.1.1-11.3
136135
// this content will result in HttpRequestDecoder failure and send downstream
137136
decoder.reset();
138-
ctx.writeAndFlush(TOO_LARGE.retainedDuplicate()).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
139-
} else {
140-
// Client is sending oversized content, we cannot safely take it. Closing channel.
141-
ctx.writeAndFlush(TOO_LARGE_CLOSE.retainedDuplicate()).addListener(ChannelFutureListener.CLOSE);
142137
}
138+
ctx.writeAndFlush(TOO_LARGE.retainedDuplicate()).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
143139
} else {
144-
contentExpected = true;
140+
ignoreContent = false;
145141
currentContentLength = 0;
146142
if (isContinueExpected) {
147143
ctx.writeAndFlush(CONTINUE.retainedDuplicate());
@@ -152,19 +148,16 @@ private void handleRequest(ChannelHandlerContext ctx, HttpRequest request) {
152148
}
153149

154150
private void handleContent(ChannelHandlerContext ctx, HttpContent msg) {
155-
if (contentExpected) {
151+
if (ignoreContent) {
152+
msg.release();
153+
} else {
156154
currentContentLength += msg.content().readableBytes();
157155
if (currentContentLength > maxContentLength) {
158156
msg.release();
159157
ctx.writeAndFlush(TOO_LARGE_CLOSE.retainedDuplicate()).addListener(ChannelFutureListener.CLOSE);
160158
} else {
161159
ctx.fireChannelRead(msg);
162160
}
163-
} else {
164-
msg.release();
165-
if (msg != LastHttpContent.EMPTY_LAST_CONTENT) {
166-
ctx.close(); // there is no reliable recovery from unexpected content, closing channel
167-
}
168161
}
169162
}
170163

modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpContentSizeHandlerTests.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -192,18 +192,20 @@ public void testMixedContent() {
192192
}
193193

194194
/**
195-
* Assert that handler returns 413 Request Entity Too Large and close channel for
196-
* oversized request with content.
195+
* Assert that handler returns 413 Request Entity Too Large and skip following content.
197196
*/
198197
public void testEntityTooLargeWithContentWithoutExpect() {
199-
var sendRequest = httpRequest();
200-
HttpUtil.setContentLength(sendRequest, OVERSIZED_LENGTH);
201-
var unexpectedContent = lastHttpContent(OVERSIZED_LENGTH);
202-
channel.writeInbound(encode(sendRequest, unexpectedContent));
203-
var resp = (FullHttpResponse) channel.readOutbound();
204-
assertEquals(HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE, resp.status());
205-
assertFalse(channel.isOpen());
206-
resp.release();
198+
for (int i = 0; i < REPS; i++) {
199+
var sendRequest = httpRequest();
200+
HttpUtil.setContentLength(sendRequest, OVERSIZED_LENGTH);
201+
var unexpectedContent = lastHttpContent(OVERSIZED_LENGTH);
202+
channel.writeInbound(encode(sendRequest, unexpectedContent));
203+
var resp = (FullHttpResponse) channel.readOutbound();
204+
assertEquals(HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE, resp.status());
205+
resp.release();
206+
assertNull("request and content should not pass", channel.readInbound());
207+
assertTrue("should not close channel", channel.isOpen());
208+
}
207209
}
208210

209211
/**

0 commit comments

Comments
 (0)