parent
12c614a7eb
commit
6ecca2722e
@ -15,15 +15,20 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.handler.codec.http;
|
package io.netty.handler.codec.http;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBufUtil;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.embedded.EmbeddedChannel;
|
import io.netty.channel.embedded.EmbeddedChannel;
|
||||||
import io.netty.handler.codec.compression.ZlibWrapper;
|
import io.netty.handler.codec.compression.ZlibWrapper;
|
||||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders.Values;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class HttpContentCompressorTest {
|
public class HttpContentCompressorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetTargetContentEncoding() throws Exception {
|
public void testGetTargetContentEncoding() throws Exception {
|
||||||
HttpContentCompressor compressor = new HttpContentCompressor();
|
HttpContentCompressor compressor = new HttpContentCompressor();
|
||||||
@ -62,33 +67,250 @@ public class HttpContentCompressorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEmptyContentCompression() throws Exception {
|
public void testSplitContent() throws Exception {
|
||||||
EmbeddedChannel ch = new EmbeddedChannel(new HttpContentCompressor());
|
EmbeddedChannel ch = new EmbeddedChannel(new HttpContentCompressor());
|
||||||
FullHttpRequest req = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/");
|
ch.writeInbound(newRequest());
|
||||||
req.headers().set(Names.ACCEPT_ENCODING, "deflate");
|
|
||||||
ch.writeInbound(req);
|
|
||||||
|
|
||||||
ch.writeOutbound(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK));
|
ch.writeOutbound(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK));
|
||||||
|
ch.writeOutbound(new DefaultHttpContent(Unpooled.copiedBuffer("Hell", CharsetUtil.US_ASCII)));
|
||||||
|
ch.writeOutbound(new DefaultHttpContent(Unpooled.copiedBuffer("o, w", CharsetUtil.US_ASCII)));
|
||||||
|
ch.writeOutbound(new DefaultLastHttpContent(Unpooled.copiedBuffer("orld", CharsetUtil.US_ASCII)));
|
||||||
|
|
||||||
HttpResponse res = ch.readOutbound();
|
assertEncodedResponse(ch);
|
||||||
assertThat(res, is(not(instanceOf(FullHttpResponse.class))));
|
|
||||||
assertThat(res.headers().get(Names.TRANSFER_ENCODING), is("chunked"));
|
|
||||||
assertThat(res.headers().get(Names.CONTENT_LENGTH), is(nullValue()));
|
|
||||||
assertThat(res.headers().get(Names.CONTENT_ENCODING), is("deflate"));
|
|
||||||
|
|
||||||
ch.writeOutbound(LastHttpContent.EMPTY_LAST_CONTENT);
|
|
||||||
|
|
||||||
HttpContent chunk;
|
HttpContent chunk;
|
||||||
chunk = ch.readOutbound();
|
chunk = ch.readOutbound();
|
||||||
assertThat(chunk, is(instanceOf(HttpContent.class)));
|
assertThat(ByteBufUtil.hexDump(chunk.content()), is("1f8b0800000000000000f248cdc901000000ffff"));
|
||||||
assertThat(chunk.content().isReadable(), is(true));
|
chunk.release();
|
||||||
|
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(chunk.content()), is("cad7512807000000ffff"));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(chunk.content()), is("ca2fca4901000000ffff"));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(chunk.content()), is("0300c2a99ae70c000000"));
|
||||||
|
assertThat(chunk, is(instanceOf(HttpContent.class)));
|
||||||
chunk.release();
|
chunk.release();
|
||||||
|
|
||||||
chunk = ch.readOutbound();
|
chunk = ch.readOutbound();
|
||||||
assertThat(chunk, is(instanceOf(LastHttpContent.class)));
|
|
||||||
assertThat(chunk.content().isReadable(), is(false));
|
assertThat(chunk.content().isReadable(), is(false));
|
||||||
|
assertThat(chunk, is(instanceOf(LastHttpContent.class)));
|
||||||
chunk.release();
|
chunk.release();
|
||||||
|
|
||||||
assertThat(ch.readOutbound(), is(nullValue()));
|
assertThat(ch.readOutbound(), is(nullValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChunkedContent() throws Exception {
|
||||||
|
EmbeddedChannel ch = new EmbeddedChannel(new HttpContentCompressor());
|
||||||
|
ch.writeInbound(newRequest());
|
||||||
|
|
||||||
|
HttpResponse res = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
|
||||||
|
res.headers().set(Names.TRANSFER_ENCODING, Values.CHUNKED);
|
||||||
|
ch.writeOutbound(res);
|
||||||
|
|
||||||
|
assertEncodedResponse(ch);
|
||||||
|
|
||||||
|
ch.writeOutbound(new DefaultHttpContent(Unpooled.copiedBuffer("Hell", CharsetUtil.US_ASCII)));
|
||||||
|
ch.writeOutbound(new DefaultHttpContent(Unpooled.copiedBuffer("o, w", CharsetUtil.US_ASCII)));
|
||||||
|
ch.writeOutbound(new DefaultLastHttpContent(Unpooled.copiedBuffer("orld", CharsetUtil.US_ASCII)));
|
||||||
|
|
||||||
|
HttpContent chunk;
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(chunk.content()), is("1f8b0800000000000000f248cdc901000000ffff"));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(chunk.content()), is("cad7512807000000ffff"));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(chunk.content()), is("ca2fca4901000000ffff"));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(chunk.content()), is("0300c2a99ae70c000000"));
|
||||||
|
assertThat(chunk, is(instanceOf(HttpContent.class)));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(chunk.content().isReadable(), is(false));
|
||||||
|
assertThat(chunk, is(instanceOf(LastHttpContent.class)));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
assertThat(ch.readOutbound(), is(nullValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChunkedContentWithTrailingHeader() throws Exception {
|
||||||
|
EmbeddedChannel ch = new EmbeddedChannel(new HttpContentCompressor());
|
||||||
|
ch.writeInbound(newRequest());
|
||||||
|
|
||||||
|
HttpResponse res = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
|
||||||
|
res.headers().set(Names.TRANSFER_ENCODING, Values.CHUNKED);
|
||||||
|
ch.writeOutbound(res);
|
||||||
|
|
||||||
|
assertEncodedResponse(ch);
|
||||||
|
|
||||||
|
ch.writeOutbound(new DefaultHttpContent(Unpooled.copiedBuffer("Hell", CharsetUtil.US_ASCII)));
|
||||||
|
ch.writeOutbound(new DefaultHttpContent(Unpooled.copiedBuffer("o, w", CharsetUtil.US_ASCII)));
|
||||||
|
LastHttpContent content = new DefaultLastHttpContent(Unpooled.copiedBuffer("orld", CharsetUtil.US_ASCII));
|
||||||
|
content.trailingHeaders().set("X-Test", "Netty");
|
||||||
|
ch.writeOutbound(content);
|
||||||
|
|
||||||
|
HttpContent chunk;
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(chunk.content()), is("1f8b0800000000000000f248cdc901000000ffff"));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(chunk.content()), is("cad7512807000000ffff"));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(chunk.content()), is("ca2fca4901000000ffff"));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(chunk.content()), is("0300c2a99ae70c000000"));
|
||||||
|
assertThat(chunk, is(instanceOf(HttpContent.class)));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(chunk.content().isReadable(), is(false));
|
||||||
|
assertThat(chunk, is(instanceOf(LastHttpContent.class)));
|
||||||
|
assertEquals("Netty", ((LastHttpContent) chunk).trailingHeaders().get("X-Test"));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
assertThat(ch.readOutbound(), is(nullValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFullContent() throws Exception {
|
||||||
|
EmbeddedChannel ch = new EmbeddedChannel(new HttpContentCompressor());
|
||||||
|
ch.writeInbound(newRequest());
|
||||||
|
|
||||||
|
FullHttpResponse res = new DefaultFullHttpResponse(
|
||||||
|
HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
|
||||||
|
Unpooled.copiedBuffer("Hello, World", CharsetUtil.US_ASCII));
|
||||||
|
res.headers().set(Names.CONTENT_LENGTH, res.content().readableBytes());
|
||||||
|
ch.writeOutbound(res);
|
||||||
|
|
||||||
|
assertEncodedResponse(ch);
|
||||||
|
HttpContent c = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(c.content()), is("1f8b0800000000000000f248cdc9c9d75108cf2fca4901000000ffff"));
|
||||||
|
c.release();
|
||||||
|
|
||||||
|
c = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(c.content()), is("0300c6865b260c000000"));
|
||||||
|
c.release();
|
||||||
|
|
||||||
|
LastHttpContent last = ch.readOutbound();
|
||||||
|
assertThat(last.content().readableBytes(), is(0));
|
||||||
|
last.release();
|
||||||
|
|
||||||
|
assertThat(ch.readOutbound(), is(nullValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the length of the content is unknown, {@link HttpContentEncoder} should not skip encoding the content
|
||||||
|
* even if the actual length is turned out to be 0.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEmptySplitContent() throws Exception {
|
||||||
|
EmbeddedChannel ch = new EmbeddedChannel(new HttpContentCompressor());
|
||||||
|
ch.writeInbound(newRequest());
|
||||||
|
|
||||||
|
ch.writeOutbound(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK));
|
||||||
|
assertEncodedResponse(ch);
|
||||||
|
|
||||||
|
ch.writeOutbound(LastHttpContent.EMPTY_LAST_CONTENT);
|
||||||
|
HttpContent chunk = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(chunk.content()), is("1f8b0800000000000000"));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(ByteBufUtil.hexDump(chunk.content()), is("03000000000000000000"));
|
||||||
|
assertThat(chunk, is(instanceOf(HttpContent.class)));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
chunk = ch.readOutbound();
|
||||||
|
assertThat(chunk.content().isReadable(), is(false));
|
||||||
|
assertThat(chunk, is(instanceOf(LastHttpContent.class)));
|
||||||
|
chunk.release();
|
||||||
|
|
||||||
|
assertThat(ch.readOutbound(), is(nullValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the length of the content is 0 for sure, {@link HttpContentEncoder} should skip encoding.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEmptyFullContent() throws Exception {
|
||||||
|
EmbeddedChannel ch = new EmbeddedChannel(new HttpContentCompressor());
|
||||||
|
ch.writeInbound(newRequest());
|
||||||
|
|
||||||
|
FullHttpResponse res = new DefaultFullHttpResponse(
|
||||||
|
HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.EMPTY_BUFFER);
|
||||||
|
ch.writeOutbound(res);
|
||||||
|
|
||||||
|
Object o = ch.readOutbound();
|
||||||
|
assertThat(o, is(instanceOf(FullHttpResponse.class)));
|
||||||
|
|
||||||
|
res = (FullHttpResponse) o;
|
||||||
|
assertThat(res.headers().get(Names.TRANSFER_ENCODING), is(nullValue()));
|
||||||
|
|
||||||
|
// Content encoding shouldn't be modified.
|
||||||
|
assertThat(res.headers().get(Names.CONTENT_ENCODING), is(nullValue()));
|
||||||
|
assertThat(res.content().readableBytes(), is(0));
|
||||||
|
assertThat(res.content().toString(CharsetUtil.US_ASCII), is(""));
|
||||||
|
res.release();
|
||||||
|
|
||||||
|
assertThat(ch.readOutbound(), is(nullValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEmptyFullContentWithTrailer() throws Exception {
|
||||||
|
EmbeddedChannel ch = new EmbeddedChannel(new HttpContentCompressor());
|
||||||
|
ch.writeInbound(newRequest());
|
||||||
|
|
||||||
|
FullHttpResponse res = new DefaultFullHttpResponse(
|
||||||
|
HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.EMPTY_BUFFER);
|
||||||
|
res.trailingHeaders().set("X-Test", "Netty");
|
||||||
|
ch.writeOutbound(res);
|
||||||
|
|
||||||
|
Object o = ch.readOutbound();
|
||||||
|
assertThat(o, is(instanceOf(FullHttpResponse.class)));
|
||||||
|
|
||||||
|
res = (FullHttpResponse) o;
|
||||||
|
assertThat(res.headers().get(Names.TRANSFER_ENCODING), is(nullValue()));
|
||||||
|
|
||||||
|
// Content encoding shouldn't be modified.
|
||||||
|
assertThat(res.headers().get(Names.CONTENT_ENCODING), is(nullValue()));
|
||||||
|
assertThat(res.content().readableBytes(), is(0));
|
||||||
|
assertThat(res.content().toString(CharsetUtil.US_ASCII), is(""));
|
||||||
|
assertEquals("Netty", res.trailingHeaders().get("X-Test"));
|
||||||
|
assertThat(ch.readOutbound(), is(nullValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FullHttpRequest newRequest() {
|
||||||
|
FullHttpRequest req = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/");
|
||||||
|
req.headers().set(Names.ACCEPT_ENCODING, "gzip");
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertEncodedResponse(EmbeddedChannel ch) {
|
||||||
|
Object o = ch.readOutbound();
|
||||||
|
assertThat(o, is(instanceOf(HttpResponse.class)));
|
||||||
|
|
||||||
|
HttpResponse res = (HttpResponse) o;
|
||||||
|
assertThat(res, is(not(instanceOf(HttpContent.class))));
|
||||||
|
assertThat(res.headers().get(Names.TRANSFER_ENCODING), is("chunked"));
|
||||||
|
assertThat(res.headers().get(Names.CONTENT_LENGTH), is(nullValue()));
|
||||||
|
assertThat(res.headers().get(Names.CONTENT_ENCODING), is("gzip"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user