Fix possible NPE when using HttpClientCodec (#9465)
Motivation: It was possible to produce a NPE when we for examples received more responses as requests as we did not check if the queue did not contain a method before trying to compare method names. Modifications: - Add extra null check - Add unit tet Result: Fixes https://github.com/netty/netty/issues/9459
This commit is contained in:
parent
e4d9a17ad9
commit
96f92929ab
@ -160,7 +160,7 @@ public final class HttpClientCodec extends CombinedChannelDuplexHandler<HttpResp
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg instanceof HttpRequest && !done) {
|
if (msg instanceof HttpRequest) {
|
||||||
queue.offer(((HttpRequest) msg).method());
|
queue.offer(((HttpRequest) msg).method());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,6 +233,9 @@ public final class HttpClientCodec extends CombinedChannelDuplexHandler<HttpResp
|
|||||||
// current response.
|
// current response.
|
||||||
HttpMethod method = queue.poll();
|
HttpMethod method = queue.poll();
|
||||||
|
|
||||||
|
// If the remote peer did for example send multiple responses for one request (which is not allowed per
|
||||||
|
// spec but may still be possible) method will be null so guard against it.
|
||||||
|
if (method != null) {
|
||||||
char firstChar = method.name().charAt(0);
|
char firstChar = method.name().charAt(0);
|
||||||
switch (firstChar) {
|
switch (firstChar) {
|
||||||
case 'H':
|
case 'H':
|
||||||
@ -261,8 +264,8 @@ public final class HttpClientCodec extends CombinedChannelDuplexHandler<HttpResp
|
|||||||
// Successful CONNECT request results in a response with empty body.
|
// Successful CONNECT request results in a response with empty body.
|
||||||
if (statusCode == 200) {
|
if (statusCode == 200) {
|
||||||
if (HttpMethod.CONNECT.equals(method)) {
|
if (HttpMethod.CONNECT.equals(method)) {
|
||||||
// Proxy connection established - Parse HTTP only if configured by parseHttpAfterConnectRequest,
|
// Proxy connection established - Parse HTTP only if configured by
|
||||||
// else pass through.
|
// parseHttpAfterConnectRequest, else pass through.
|
||||||
if (!parseHttpAfterConnectRequest) {
|
if (!parseHttpAfterConnectRequest) {
|
||||||
done = true;
|
done = true;
|
||||||
queue.clear();
|
queue.clear();
|
||||||
@ -272,7 +275,7 @@ public final class HttpClientCodec extends CombinedChannelDuplexHandler<HttpResp
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return super.isContentAlwaysEmpty(msg);
|
return super.isContentAlwaysEmpty(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,4 +326,28 @@ public class HttpClientCodecTest {
|
|||||||
|
|
||||||
assertThat(ch.readInbound(), is(nullValue()));
|
assertThat(ch.readInbound(), is(nullValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleResponses() {
|
||||||
|
String response = "HTTP/1.1 200 OK\r\n" +
|
||||||
|
"Content-Length: 0\r\n\r\n";
|
||||||
|
|
||||||
|
HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true);
|
||||||
|
EmbeddedChannel ch = new EmbeddedChannel(codec, new HttpObjectAggregator(1024));
|
||||||
|
|
||||||
|
HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/");
|
||||||
|
assertTrue(ch.writeOutbound(request));
|
||||||
|
|
||||||
|
assertTrue(ch.writeInbound(Unpooled.copiedBuffer(response, CharsetUtil.UTF_8)));
|
||||||
|
assertTrue(ch.writeInbound(Unpooled.copiedBuffer(response, CharsetUtil.UTF_8)));
|
||||||
|
FullHttpResponse resp = ch.readInbound();
|
||||||
|
assertTrue(resp.decoderResult().isSuccess());
|
||||||
|
resp.release();
|
||||||
|
|
||||||
|
resp = ch.readInbound();
|
||||||
|
assertTrue(resp.decoderResult().isSuccess());
|
||||||
|
resp.release();
|
||||||
|
assertTrue(ch.finishAndReleaseAll());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user