Skip to content

Commit 9f10a28

Browse files
franz1981chrisvest
andauthored
HttpMessages implementing HttpContent types too aren't handled correctly (Fixes #12750) (#12751)
Motivation: Changes due to #12709 have added a code path. Modifications: Restore the "just http message" case as separated by the http content ones Result: Same encoding as original code Co-authored-by: Chris Vest <[email protected]>
1 parent 05943f5 commit 9f10a28

File tree

2 files changed

+132
-1
lines changed

2 files changed

+132
-1
lines changed

codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectEncoder.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,9 @@ protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) t
174174
encodeHttpMessageLastContent(ctx, m, out);
175175
} else if (m instanceof HttpContent) {
176176
encodeHttpMessageNotLastContent(ctx, m, out);
177+
} else {
178+
encodeJustHttpMessage(ctx, m, out);
177179
}
178-
encodeJustHttpMessage(ctx, m, out);
179180
} else {
180181
encodeNotHttpMessageContentTypes(ctx, msg, out);
181182
}

codec-http/src/test/java/io/netty/handler/codec/http/HttpRequestEncoderTest.java

+130
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@
2929
import java.nio.charset.Charset;
3030
import java.util.concurrent.ExecutionException;
3131

32+
import static io.netty.util.internal.ObjectUtil.checkNotNull;
3233
import static org.hamcrest.MatcherAssert.assertThat;
3334
import static org.hamcrest.Matchers.instanceOf;
3435
import static org.hamcrest.Matchers.is;
3536
import static org.junit.jupiter.api.Assertions.assertEquals;
3637
import static org.junit.jupiter.api.Assertions.assertFalse;
38+
import static org.junit.jupiter.api.Assertions.assertNull;
3739
import static org.junit.jupiter.api.Assertions.assertThrows;
3840
import static org.junit.jupiter.api.Assertions.assertTrue;
3941

@@ -182,6 +184,134 @@ public void testEmptyContentNotsChunkedWithTrailers() throws Exception {
182184
testEmptyContents(false, true);
183185
}
184186

187+
// this is not using Full types on purpose!!!
188+
private static class CustomFullHttpRequest extends DefaultHttpRequest implements LastHttpContent {
189+
private final ByteBuf content;
190+
private final HttpHeaders trailingHeader;
191+
192+
CustomFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri, ByteBuf content) {
193+
this(httpVersion, method, uri, content, true);
194+
}
195+
196+
CustomFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri,
197+
ByteBuf content, boolean validateHeaders) {
198+
super(httpVersion, method, uri, validateHeaders);
199+
this.content = checkNotNull(content, "content");
200+
trailingHeader = new DefaultHttpHeaders(validateHeaders);
201+
}
202+
203+
private CustomFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri,
204+
ByteBuf content, HttpHeaders headers, HttpHeaders trailingHeader) {
205+
super(httpVersion, method, uri, headers);
206+
this.content = checkNotNull(content, "content");
207+
this.trailingHeader = checkNotNull(trailingHeader, "trailingHeader");
208+
}
209+
210+
@Override
211+
public HttpHeaders trailingHeaders() {
212+
return trailingHeader;
213+
}
214+
215+
@Override
216+
public ByteBuf content() {
217+
return content;
218+
}
219+
220+
@Override
221+
public int refCnt() {
222+
return content.refCnt();
223+
}
224+
225+
@Override
226+
public CustomFullHttpRequest retain() {
227+
content.retain();
228+
return this;
229+
}
230+
231+
@Override
232+
public CustomFullHttpRequest retain(int increment) {
233+
content.retain(increment);
234+
return this;
235+
}
236+
237+
@Override
238+
public CustomFullHttpRequest touch() {
239+
content.touch();
240+
return this;
241+
}
242+
243+
@Override
244+
public CustomFullHttpRequest touch(Object hint) {
245+
content.touch(hint);
246+
return this;
247+
}
248+
249+
@Override
250+
public boolean release() {
251+
return content.release();
252+
}
253+
254+
@Override
255+
public boolean release(int decrement) {
256+
return content.release(decrement);
257+
}
258+
259+
@Override
260+
public CustomFullHttpRequest setProtocolVersion(HttpVersion version) {
261+
super.setProtocolVersion(version);
262+
return this;
263+
}
264+
265+
@Override
266+
public CustomFullHttpRequest setMethod(HttpMethod method) {
267+
super.setMethod(method);
268+
return this;
269+
}
270+
271+
@Override
272+
public CustomFullHttpRequest setUri(String uri) {
273+
super.setUri(uri);
274+
return this;
275+
}
276+
277+
@Override
278+
public CustomFullHttpRequest copy() {
279+
return replace(content().copy());
280+
}
281+
282+
@Override
283+
public CustomFullHttpRequest duplicate() {
284+
return replace(content().duplicate());
285+
}
286+
287+
@Override
288+
public CustomFullHttpRequest retainedDuplicate() {
289+
return replace(content().retainedDuplicate());
290+
}
291+
292+
@Override
293+
public CustomFullHttpRequest replace(ByteBuf content) {
294+
CustomFullHttpRequest request = new CustomFullHttpRequest(protocolVersion(), method(), uri(), content,
295+
headers().copy(), trailingHeaders().copy());
296+
request.setDecoderResult(decoderResult());
297+
return request;
298+
}
299+
}
300+
301+
@Test
302+
public void testCustomMessageEmptyLastContent() {
303+
HttpRequestEncoder encoder = new HttpRequestEncoder();
304+
EmbeddedChannel channel = new EmbeddedChannel(encoder);
305+
HttpRequest customMsg = new CustomFullHttpRequest(HttpVersion.HTTP_1_1,
306+
HttpMethod.POST, "/", Unpooled.EMPTY_BUFFER);
307+
assertTrue(channel.writeOutbound(customMsg));
308+
// Ensure we only produce ByteBuf instances.
309+
ByteBuf head = channel.readOutbound();
310+
assertTrue(head.release());
311+
assertNull(channel.readOutbound());
312+
assertFalse(channel.finish());
313+
}
314+
185315
private void testEmptyContents(boolean chunked, boolean trailers) throws Exception {
186316
HttpRequestEncoder encoder = new HttpRequestEncoder();
187317
EmbeddedChannel channel = new EmbeddedChannel(encoder);

0 commit comments

Comments
 (0)