HttpObjectDecoder resetRequested not updated after reset
Motivation: HttpObjectDecoder maintains a resetRequested flag which is used to determine if internal state should be reset when a decode occurs. However after a reset is done the resetRequested flag is not set to false. This leads to all data after this point being discarded. Modifications: - Set resetRequested to false when a reset is done Result: HttpObjectDecoder can still function after a reset.
This commit is contained in:
parent
4145fae919
commit
dd1ba2a252
@ -509,6 +509,7 @@ public abstract class HttpObjectDecoder extends ByteToMessageDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetRequested = false;
|
||||||
currentState = State.SKIP_CONTROL_CHARS;
|
currentState = State.SKIP_CONTROL_CHARS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ package io.netty.handler.codec.http;
|
|||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||||
import io.netty.channel.embedded.EmbeddedChannel;
|
import io.netty.channel.embedded.EmbeddedChannel;
|
||||||
import io.netty.handler.codec.compression.ZlibCodecFactory;
|
import io.netty.handler.codec.compression.ZlibCodecFactory;
|
||||||
import io.netty.handler.codec.compression.ZlibDecoder;
|
import io.netty.handler.codec.compression.ZlibDecoder;
|
||||||
@ -30,9 +32,16 @@ import org.junit.Test;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
import static org.junit.Assert.*;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class HttpContentDecoderTest {
|
public class HttpContentDecoderTest {
|
||||||
private static final String HELLO_WORLD = "hello, world";
|
private static final String HELLO_WORLD = "hello, world";
|
||||||
@ -217,6 +226,60 @@ public class HttpContentDecoderTest {
|
|||||||
assertFalse(channel.finish());
|
assertFalse(channel.finish());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpectContinueResetHttpObjectDecoder() {
|
||||||
|
// request with header "Expect: 100-continue" must be replied with one "100 Continue" response
|
||||||
|
// case 5: Test that HttpObjectDecoder correctly resets its internal state after a failed expectation.
|
||||||
|
HttpRequestDecoder decoder = new HttpRequestDecoder();
|
||||||
|
final int maxBytes = 10;
|
||||||
|
HttpObjectAggregator aggregator = new HttpObjectAggregator(maxBytes);
|
||||||
|
final AtomicReference<FullHttpRequest> secondRequestRef = new AtomicReference<FullHttpRequest>();
|
||||||
|
EmbeddedChannel channel = new EmbeddedChannel(decoder, aggregator, new ChannelInboundHandlerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||||
|
if (msg instanceof FullHttpRequest) {
|
||||||
|
if (!secondRequestRef.compareAndSet(null, (FullHttpRequest) msg)) {
|
||||||
|
((FullHttpRequest) msg).release();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ReferenceCountUtil.release(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
String req1 = "POST /1 HTTP/1.1\r\n" +
|
||||||
|
"Content-Length: " + (maxBytes + 1) + "\r\n" +
|
||||||
|
"Expect: 100-continue\r\n" +
|
||||||
|
"\r\n";
|
||||||
|
assertFalse(channel.writeInbound(Unpooled.wrappedBuffer(req1.getBytes(CharsetUtil.US_ASCII))));
|
||||||
|
|
||||||
|
FullHttpResponse resp = channel.readOutbound();
|
||||||
|
assertEquals(HttpStatusClass.CLIENT_ERROR, resp.status().codeClass());
|
||||||
|
resp.release();
|
||||||
|
|
||||||
|
String req2 = "POST /2 HTTP/1.1\r\n" +
|
||||||
|
"Content-Length: " + maxBytes + "\r\n" +
|
||||||
|
"Expect: 100-continue\r\n" +
|
||||||
|
"\r\n";
|
||||||
|
assertFalse(channel.writeInbound(Unpooled.wrappedBuffer(req2.getBytes(CharsetUtil.US_ASCII))));
|
||||||
|
|
||||||
|
resp = channel.readOutbound();
|
||||||
|
assertEquals(100, resp.status().code());
|
||||||
|
resp.release();
|
||||||
|
|
||||||
|
byte[] content = new byte[maxBytes];
|
||||||
|
assertFalse(channel.writeInbound(Unpooled.wrappedBuffer(content)));
|
||||||
|
|
||||||
|
FullHttpRequest req = secondRequestRef.get();
|
||||||
|
assertNotNull(req);
|
||||||
|
assertEquals("/2", req.uri());
|
||||||
|
assertEquals(10, req.content().readableBytes());
|
||||||
|
req.release();
|
||||||
|
|
||||||
|
assertHasInboundMessages(channel, false);
|
||||||
|
assertHasOutboundMessages(channel, false);
|
||||||
|
assertFalse(channel.finish());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestContentLength1() {
|
public void testRequestContentLength1() {
|
||||||
// case 1: test that ContentDecompressor either sets the correct Content-Length header
|
// case 1: test that ContentDecompressor either sets the correct Content-Length header
|
||||||
|
Loading…
Reference in New Issue
Block a user