From a9566d429c218540f7a7ca74ed465ba9b47f6e39 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 21 Sep 2018 07:44:53 +1000 Subject: [PATCH] Issue #2912 Remove Content-Length from inflated requests (#2915) Issue #2912 Remove Content-Length from inflated requests Signed-off-by: Greg Wilkins --- .../server/handler/gzip/GzipHandler.java | 57 ++++++++++------- .../jetty/servlet/GzipHandlerTest.java | 62 ++++++++++++++++++- 2 files changed, 95 insertions(+), 24 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java index b3f069db07e..719a23715ae 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java @@ -32,12 +32,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.CompressedContentFormat; -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.MimeTypes; -import org.eclipse.jetty.http.PreEncodedHttpField; +import org.eclipse.jetty.http.*; import org.eclipse.jetty.http.pathmap.PathSpecSet; import org.eclipse.jetty.server.DeflaterPool; import org.eclipse.jetty.server.HttpOutput; @@ -156,6 +151,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory public static final int DEFAULT_MIN_GZIP_SIZE=16; private static final Logger LOG = Log.getLogger(GzipHandler.class); private static final HttpField X_CE_GZIP = new PreEncodedHttpField("X-Content-Encoding","gzip"); + private static final HttpField TE_CHUNKED = new PreEncodedHttpField(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED.asString()); private static final Pattern COMMA_GZIP = Pattern.compile(".*, *gzip"); private int POOL_CAPACITY = -1; @@ -622,29 +618,46 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory // Handle request inflation if (_inflateBufferSize>0) { + boolean inflate = false; for (ListIterator i = baseRequest.getHttpFields().listIterator(); i.hasNext();) { HttpField field = i.next(); - if (field.getHeader()!=HttpHeader.CONTENT_ENCODING) - continue; - if (field.getValue().equalsIgnoreCase("gzip")) + if (field.getHeader()==HttpHeader.CONTENT_ENCODING) { - i.set(X_CE_GZIP); - baseRequest.getHttpInput().addInterceptor(new GzipHttpInputInterceptor(baseRequest.getHttpChannel().getByteBufferPool(),_inflateBufferSize)); - break; - } + if (field.getValue().equalsIgnoreCase("gzip")) + { + i.set(X_CE_GZIP); + inflate = true; + break; + } - if (COMMA_GZIP.matcher(field.getValue()).matches()) - { - String v = field.getValue(); - v = v.substring(0,v.lastIndexOf(',')); - i.set(new HttpField(HttpHeader.CONTENT_ENCODING,v)); - i.add(X_CE_GZIP); - baseRequest.getHttpInput().addInterceptor(new GzipHttpInputInterceptor(baseRequest.getHttpChannel().getByteBufferPool(),_inflateBufferSize)); - break; + if (COMMA_GZIP.matcher(field.getValue()).matches()) + { + String v = field.getValue(); + v = v.substring(0, v.lastIndexOf(',')); + i.set(new HttpField(HttpHeader.CONTENT_ENCODING, v)); + i.add(X_CE_GZIP); + inflate = true; + break; + } } - } + } + + if (inflate) + { + baseRequest.getHttpInput().addInterceptor(new GzipHttpInputInterceptor(baseRequest.getHttpChannel().getByteBufferPool(), _inflateBufferSize)); + + for (ListIterator i = baseRequest.getHttpFields().listIterator(); i.hasNext();) + { + HttpField field = i.next(); + if (field.getHeader()==HttpHeader.CONTENT_LENGTH) + { + i.set(new HttpField("X-Content-Length", field.getValue())); + break; + } + } + } } // Are we already being gzipped? diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java index 6a67f25abb9..c720e0f3e15 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java @@ -35,21 +35,24 @@ import java.io.PrintWriter; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.EnumSet; import java.util.Enumeration; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; -import javax.servlet.ServletException; +import javax.servlet.*; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpTester; +import org.eclipse.jetty.server.Dispatcher; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.gzip.GzipHandler; import org.eclipse.jetty.util.IO; import org.hamcrest.Matchers; +import org.junit.Assert; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -104,6 +107,7 @@ public class GzipHandlerTest servlets.addServletWithMapping(IncludeServlet.class,"/include"); servlets.addServletWithMapping(EchoServlet.class,"/echo/*"); servlets.addServletWithMapping(DumpServlet.class,"/dump/*"); + servlets.addFilterWithMapping(CheckFilter.class,"/*", EnumSet.of(DispatcherType.REQUEST)); _server.start(); } @@ -508,6 +512,38 @@ public class GzipHandlerTest assertThat(response.getContent(),is(data)); } + + + @Test + public void testGzipRequestChunked() throws Exception + { + String data = "Hello Nice World! "; + for (int i = 0; i < 10; ++i) + data += data; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream output = new GZIPOutputStream(baos); + output.write(data.getBytes(StandardCharsets.UTF_8)); + output.close(); + byte[] bytes = baos.toByteArray(); + + // generated and parsed test + HttpTester.Request request = HttpTester.newRequest(); + HttpTester.Response response; + + request.setMethod("POST"); + request.setURI("/ctx/echo"); + request.setVersion("HTTP/1.1"); + request.setHeader("Host","tester"); + request.setHeader("Content-Type","text/plain"); + request.setHeader("Content-Encoding","gzip"); + request.add("Transfer-Encoding", "chunked"); + request.setContent(bytes); + response = HttpTester.parseResponse(_connector.getResponse(request.generate())); + + assertThat(response.getStatus(),is(200)); + assertThat(response.getContent(),is(data)); + + } @Test @@ -568,5 +604,27 @@ public class GzipHandlerTest assertThat(response.getStatus(),is(200)); assertThat(response.getContentBytes().length,is(512*1024)); } - + + public static class CheckFilter implements Filter + { + @Override + public void init(FilterConfig filterConfig) throws ServletException + { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException + { + if (request.getParameter("X-Content-Encoding")!=null) + Assert.assertEquals(-1,request.getContentLength()); + else if (request.getContentLength()>=0) + Assert.assertThat(request.getParameter("X-Content-Encoding"),Matchers.nullValue()); + chain.doFilter(request,response); + } + + @Override + public void destroy() + { + } + } }