diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractFileContentServlet.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractFileContentServlet.java new file mode 100644 index 00000000000..0857532c93c --- /dev/null +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractFileContentServlet.java @@ -0,0 +1,46 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under +// the terms of the Eclipse Public License 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0 +// +// This Source Code may also be made available under the following +// Secondary Licenses when the conditions for such availability set +// forth in the Eclipse Public License, v. 2.0 are satisfied: +// the Apache License v2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.servlets; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import javax.servlet.http.HttpServlet; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public abstract class AbstractFileContentServlet extends HttpServlet +{ + protected byte[] loadContentFileBytes(final String fileName) throws IOException + { + String relPath = fileName; + relPath = relPath.replaceFirst("^/context/", ""); + relPath = relPath.replaceFirst("^/", ""); + + String realPath = getServletContext().getRealPath(relPath); + assertNotNull(realPath, "Unable to find real path for " + relPath); + + Path realFile = Paths.get(realPath); + assertTrue(Files.exists(realFile), "Content File should exist: " + realFile); + + return Files.readAllBytes(realFile); + } +} diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractGzipTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractGzipTest.java new file mode 100644 index 00000000000..0f02789693f --- /dev/null +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractGzipTest.java @@ -0,0 +1,165 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under +// the terms of the Eclipse Public License 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0 +// +// This Source Code may also be made available under the following +// Secondary Licenses when the conditions for such availability set +// forth in the Eclipse Public License, v. 2.0 are satisfied: +// the Apache License v2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.servlets; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.security.DigestOutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Locale; +import java.util.zip.GZIPInputStream; +import java.util.zip.Inflater; +import java.util.zip.InflaterInputStream; + +import org.eclipse.jetty.http.tools.HttpTester; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.handler.gzip.GzipHandler; +import org.eclipse.jetty.toolchain.test.FS; +import org.eclipse.jetty.toolchain.test.IO; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.util.TypeUtil; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public abstract class AbstractGzipTest +{ + protected static final int DEFAULT_OUTPUT_BUFFER_SIZE; + + static + { + HttpConfiguration defaultHttp = new HttpConfiguration(); + DEFAULT_OUTPUT_BUFFER_SIZE = defaultHttp.getOutputBufferSize(); + } + + protected Path workDir; + + public AbstractGzipTest() + { + workDir = MavenTestingUtils.getTargetTestingPath(this.getClass().getName()); + FS.ensureEmpty(workDir); + } + + protected FilterInputStream newContentEncodingFilterInputStream(String contentEncoding, InputStream inputStream) throws IOException + { + if (contentEncoding == null) + { + return new FilterInputStream(inputStream) {}; + } + else if (contentEncoding.contains(GzipHandler.GZIP)) + { + return new GZIPInputStream(inputStream); + } + else if (contentEncoding.contains(GzipHandler.DEFLATE)) + { + return new InflaterInputStream(inputStream, new Inflater(true)); + } + throw new RuntimeException("Unexpected response content-encoding: " + contentEncoding); + } + + protected UncompressedMetadata parseResponseContent(HttpTester.Response response) throws NoSuchAlgorithmException, IOException + { + UncompressedMetadata metadata = new UncompressedMetadata(); + metadata.contentLength = response.getContentBytes().length; + + String contentEncoding = response.get("Content-Encoding"); + MessageDigest digest = MessageDigest.getInstance("SHA1"); + + try (ByteArrayInputStream bais = new ByteArrayInputStream(response.getContentBytes()); + FilterInputStream streamFilter = newContentEncodingFilterInputStream(contentEncoding, bais); + ByteArrayOutputStream uncompressedStream = new ByteArrayOutputStream(metadata.contentLength); + DigestOutputStream digester = new DigestOutputStream(uncompressedStream, digest)) + { + IO.copy(streamFilter, digester); + metadata.uncompressedContent = uncompressedStream.toByteArray(); + metadata.uncompressedSize = metadata.uncompressedContent.length; + // Odd toLowerCase is because TypeUtil.toHexString is mixed case results!?? + metadata.uncompressedSha1Sum = TypeUtil.toHexString(digest.digest()).toLowerCase(Locale.ENGLISH); + return metadata; + } + } + + protected Path createFile(Path contextDir, String fileName, int fileSize) throws IOException + { + Path destPath = contextDir.resolve(fileName); + byte[] content = generateContent(fileSize); + Files.write(destPath, content, StandardOpenOption.CREATE, StandardOpenOption.WRITE); + return destPath; + } + + /** + * Generate semi-realistic text content of arbitrary length. + *
+ * Note: We don't just create a single string of repeating characters + * as that doesn't test the gzip behavior very well. (too efficient) + * We also don't just generate a random byte array as that is the opposite + * extreme of gzip handling (terribly inefficient). + *
+ * + * @param length the length of the content to generate. + * @return the content. + */ + private byte[] generateContent(int length) + { + StringBuilder builder = new StringBuilder(); + do + { + builder.append("Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc.\n"); + builder.append("Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque\n"); + builder.append("habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.\n"); + builder.append("Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam\n"); + builder.append("at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate\n"); + builder.append("velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum.\n"); + builder.append("Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum\n"); + builder.append("eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa\n"); + builder.append("sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam\n"); + builder.append("consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque.\n"); + builder.append("Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse\n"); + builder.append("et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.\n"); + } + while (builder.length() < length); + + // Make sure we are exactly at requested length. (truncate the extra) + if (builder.length() > length) + { + builder.setLength(length); + } + + return builder.toString().getBytes(UTF_8); + } + + public static class UncompressedMetadata + { + public byte[] uncompressedContent; + public int contentLength; + public String uncompressedSha1Sum; + public int uncompressedSize; + + public String getContentUTF8() + { + return new String(uncompressedContent, UTF_8); + } + } +} diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncScheduledDispatchWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncScheduledDispatchWrite.java index 7732af42f47..869f24e94a5 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncScheduledDispatchWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncScheduledDispatchWrite.java @@ -30,7 +30,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @SuppressWarnings("serial") -public abstract class AsyncScheduledDispatchWrite extends TestDirContentServlet +public abstract class AsyncScheduledDispatchWrite extends AbstractFileContentServlet { public static class Default extends AsyncScheduledDispatchWrite { @@ -102,7 +102,7 @@ public abstract class AsyncScheduledDispatchWrite extends TestDirContentServlet } else { - String fileName = request.getServletPath(); + String fileName = request.getPathInfo(); byte[] dataBytes = loadContentFileBytes(fileName); response.setContentLength(dataBytes.length); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncTimeoutCompleteWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncTimeoutCompleteWrite.java index f2e1ebd3006..ab25a4c4e44 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncTimeoutCompleteWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncTimeoutCompleteWrite.java @@ -43,7 +43,7 @@ import static org.hamcrest.Matchers.nullValue; * */ @SuppressWarnings("serial") -public abstract class AsyncTimeoutCompleteWrite extends TestDirContentServlet implements AsyncListener +public abstract class AsyncTimeoutCompleteWrite extends AbstractFileContentServlet implements AsyncListener { public static class Default extends AsyncTimeoutCompleteWrite { @@ -86,7 +86,7 @@ public abstract class AsyncTimeoutCompleteWrite extends TestDirContentServlet im // Pass Request & Response ctx = request.startAsync(request, response); } - String fileName = request.getServletPath(); + String fileName = request.getPathInfo(); request.setAttribute("filename", fileName); ctx.addListener(this); ctx.setTimeout(20); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncTimeoutDispatchWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncTimeoutDispatchWrite.java index 8ad05d75ead..567f86e259c 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncTimeoutDispatchWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncTimeoutDispatchWrite.java @@ -28,7 +28,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @SuppressWarnings("serial") -public class AsyncTimeoutDispatchWrite extends TestDirContentServlet implements AsyncListener +public class AsyncTimeoutDispatchWrite extends AbstractFileContentServlet implements AsyncListener { public static class Default extends AsyncTimeoutDispatchWrite { @@ -77,7 +77,7 @@ public class AsyncTimeoutDispatchWrite extends TestDirContentServlet implements else { // second pass through, as result of timeout -> dispatch - String fileName = request.getServletPath(); + String fileName = request.getPathInfo(); byte[] dataBytes = loadContentFileBytes(fileName); response.setContentLength(dataBytes.length); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletLengthStreamTypeWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletLengthStreamTypeWrite.java similarity index 93% rename from jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletLengthStreamTypeWrite.java rename to jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletLengthStreamTypeWrite.java index 618a8a3dba6..ab37d9d6afe 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletLengthStreamTypeWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletLengthStreamTypeWrite.java @@ -42,12 +42,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler; * @see http://bugs.eclipse.org/354014 */ @SuppressWarnings("serial") -public class TestServletLengthStreamTypeWrite extends TestDirContentServlet +public class BlockingServletLengthStreamTypeWrite extends AbstractFileContentServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String fileName = request.getServletPath(); + String fileName = request.getPathInfo(); byte[] dataBytes = loadContentFileBytes(fileName); response.setContentLength(dataBytes.length); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletLengthTypeStreamWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletLengthTypeStreamWrite.java similarity index 93% rename from jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletLengthTypeStreamWrite.java rename to jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletLengthTypeStreamWrite.java index 65c0184b133..9ff632ed7a9 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletLengthTypeStreamWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletLengthTypeStreamWrite.java @@ -42,12 +42,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler; * @see http://bugs.eclipse.org/354014 */ @SuppressWarnings("serial") -public class TestServletLengthTypeStreamWrite extends TestDirContentServlet +public class BlockingServletLengthTypeStreamWrite extends AbstractFileContentServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String fileName = request.getServletPath(); + String fileName = request.getPathInfo(); byte[] dataBytes = loadContentFileBytes(fileName); response.setContentLength(dataBytes.length); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletStreamLengthTypeWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletStreamLengthTypeWrite.java similarity index 93% rename from jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletStreamLengthTypeWrite.java rename to jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletStreamLengthTypeWrite.java index b83d56a3e67..063cb6a9a82 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletStreamLengthTypeWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletStreamLengthTypeWrite.java @@ -42,12 +42,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler; * @see http://bugs.eclipse.org/354014 */ @SuppressWarnings("serial") -public class TestServletStreamLengthTypeWrite extends TestDirContentServlet +public class BlockingServletStreamLengthTypeWrite extends AbstractFileContentServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String fileName = request.getServletPath(); + String fileName = request.getPathInfo(); byte[] dataBytes = loadContentFileBytes(fileName); ServletOutputStream out = response.getOutputStream(); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletStreamLengthTypeWriteWithFlush.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletStreamLengthTypeWriteWithFlush.java similarity index 94% rename from jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletStreamLengthTypeWriteWithFlush.java rename to jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletStreamLengthTypeWriteWithFlush.java index 45901e5fe42..3fa9b757615 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletStreamLengthTypeWriteWithFlush.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletStreamLengthTypeWriteWithFlush.java @@ -42,12 +42,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler; * @see http://bugs.eclipse.org/354014 */ @SuppressWarnings("serial") -public class TestServletStreamLengthTypeWriteWithFlush extends TestDirContentServlet +public class BlockingServletStreamLengthTypeWriteWithFlush extends AbstractFileContentServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String fileName = request.getServletPath(); + String fileName = request.getPathInfo(); byte[] dataBytes = loadContentFileBytes(fileName); ServletOutputStream out = response.getOutputStream(); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletStreamTypeLengthWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletStreamTypeLengthWrite.java similarity index 93% rename from jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletStreamTypeLengthWrite.java rename to jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletStreamTypeLengthWrite.java index 2ccc85c2d7d..7c793b8f25a 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletStreamTypeLengthWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletStreamTypeLengthWrite.java @@ -42,12 +42,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler; * @see http://bugs.eclipse.org/354014 */ @SuppressWarnings("serial") -public class TestServletStreamTypeLengthWrite extends TestDirContentServlet +public class BlockingServletStreamTypeLengthWrite extends AbstractFileContentServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String fileName = request.getServletPath(); + String fileName = request.getPathInfo(); byte[] dataBytes = loadContentFileBytes(fileName); ServletOutputStream out = response.getOutputStream(); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletTypeLengthStreamWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletTypeLengthStreamWrite.java similarity index 93% rename from jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletTypeLengthStreamWrite.java rename to jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletTypeLengthStreamWrite.java index f3ee50fe588..0af3dc38eac 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletTypeLengthStreamWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletTypeLengthStreamWrite.java @@ -42,12 +42,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler; * @see http://bugs.eclipse.org/354014 */ @SuppressWarnings("serial") -public class TestServletTypeLengthStreamWrite extends TestDirContentServlet +public class BlockingServletTypeLengthStreamWrite extends AbstractFileContentServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String fileName = request.getServletPath(); + String fileName = request.getPathInfo(); byte[] dataBytes = loadContentFileBytes(fileName); if (fileName.endsWith("txt")) diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletTypeStreamLengthWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletTypeStreamLengthWrite.java similarity index 93% rename from jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletTypeStreamLengthWrite.java rename to jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletTypeStreamLengthWrite.java index 21ec41b19fc..0c622d54667 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/TestServletTypeStreamLengthWrite.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/BlockingServletTypeStreamLengthWrite.java @@ -42,12 +42,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler; * @see http://bugs.eclipse.org/354014 */ @SuppressWarnings("serial") -public class TestServletTypeStreamLengthWrite extends TestDirContentServlet +public class BlockingServletTypeStreamLengthWrite extends AbstractFileContentServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String fileName = request.getServletPath(); + String fileName = request.getPathInfo(); byte[] dataBytes = loadContentFileBytes(fileName); if (fileName.endsWith("txt")) diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipContentLengthTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipContentLengthTest.java index fda091b8e7c..a3f3305d6bd 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipContentLengthTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipContentLengthTest.java @@ -18,20 +18,27 @@ package org.eclipse.jetty.servlets; -import java.io.File; +import java.nio.ByteBuffer; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; +import javax.servlet.Servlet; import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.tools.HttpTester; -import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.LocalConnector; +import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.gzip.GzipHandler; -import org.eclipse.jetty.servlets.GzipTester.ContentMetadata; -import org.eclipse.jetty.toolchain.test.jupiter.WorkDir; -import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension; -import org.junit.jupiter.api.extension.ExtendWith; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.toolchain.test.FS; +import org.eclipse.jetty.toolchain.test.Sha1Sum; +import org.eclipse.jetty.util.component.LifeCycle; +import org.eclipse.jetty.util.resource.PathResource; +import org.hamcrest.Matcher; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -42,317 +49,180 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; /** - * Test the GzipHandler support for Content-Length setting variations. - * - * @see http://bugs.eclipse.org/354014 + * Test the {@code GzipHandler} support for the various ways that an App can set {@code Content-Length}. */ -@ExtendWith(WorkDirExtension.class) -public class GzipContentLengthTest +public class GzipContentLengthTest extends AbstractGzipTest { - public WorkDir workDir; - - private static final HttpConfiguration defaultHttp = new HttpConfiguration(); - private static final int LARGE = defaultHttp.getOutputBufferSize() * 8; - private static final int MEDIUM = defaultHttp.getOutputBufferSize(); - private static final int SMALL = defaultHttp.getOutputBufferSize() / 4; - private static final int TINY = GzipHandler.DEFAULT_MIN_GZIP_SIZE / 2; - private static final boolean EXPECT_COMPRESSED = true; + enum GzipMode + { + INTERNAL, EXTERNAL + } public static Stream+ * A quality of 0 results in no compression. + *
+ * + * See: http://bugs.eclipse.org/388072 + */ + @Test + public void testIsNotGzipCompressedWithZeroQ() throws Exception + { + GzipHandler gzipHandler = new GzipHandler(); + gzipHandler.addIncludedMimeTypes("text/plain"); + + server = new Server(); + LocalConnector localConnector = new LocalConnector(server); + server.addConnector(localConnector); + + Path contextDir = workDir.resolve("context"); + FS.ensureDirExists(contextDir); + + ServletContextHandler servletContextHandler = new ServletContextHandler(); + servletContextHandler.setContextPath("/context"); + servletContextHandler.setBaseResource(new PathResource(contextDir)); + ServletHolder holder = new ServletHolder("default", DefaultServlet.class); + holder.setInitParameter("etags", "true"); + servletContextHandler.addServlet(holder, "/"); + servletContextHandler.insertHandler(gzipHandler); + + server.setHandler(servletContextHandler); + + // Prepare Server File + int fileSize = DEFAULT_OUTPUT_BUFFER_SIZE / 4; + Path file = createFile(contextDir, "file.txt", fileSize); + String expectedSha1Sum = Sha1Sum.calculate(file); + + server.start(); + + // Setup request + HttpTester.Request request = HttpTester.newRequest(); + request.setMethod("GET"); + request.setVersion(HttpVersion.HTTP_1_1); + request.setHeader("Host", "tester"); + request.setHeader("Connection", "close"); + request.setHeader("Accept-Encoding", "gzip; q=0"); // TESTING THIS + request.setURI("/context/file.txt"); + + // Issue request + ByteBuffer rawResponse = localConnector.getResponse(request.generate(), 5, TimeUnit.SECONDS); + + // Parse response + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200)); + + // Response Content-Encoding check + assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), not(containsString("gzip"))); + assertThat("Response[Vary]", response.get("Vary"), containsString("Accept-Encoding, User-Agent")); + + // Response Content checks + UncompressedMetadata metadata = parseResponseContent(response); + assertThat("(Uncompressed) Content Length", metadata.uncompressedSize, is(fileSize)); + assertThat("(Uncompressed) Content Hash", metadata.uncompressedSha1Sum, is(expectedSha1Sum)); + } + + @Test + public void testIsGzipCompressedWithQ() throws Exception + { + GzipHandler gzipHandler = new GzipHandler(); + gzipHandler.addIncludedMimeTypes("text/plain"); + + server = new Server(); + LocalConnector localConnector = new LocalConnector(server); + server.addConnector(localConnector); + + Path contextDir = workDir.resolve("context"); + FS.ensureDirExists(contextDir); + + ServletContextHandler servletContextHandler = new ServletContextHandler(); + servletContextHandler.setContextPath("/context"); + servletContextHandler.setBaseResource(new PathResource(contextDir)); + ServletHolder holder = new ServletHolder("default", DefaultServlet.class); + holder.setInitParameter("etags", "true"); + servletContextHandler.addServlet(holder, "/"); + servletContextHandler.insertHandler(gzipHandler); + + server.setHandler(servletContextHandler); + + // Prepare Server File + int fileSize = DEFAULT_OUTPUT_BUFFER_SIZE / 4; + Path file = createFile(contextDir, "file.txt", fileSize); + String expectedSha1Sum = Sha1Sum.calculate(file); + + server.start(); + + // Setup request + HttpTester.Request request = HttpTester.newRequest(); + request.setMethod("GET"); + request.setVersion(HttpVersion.HTTP_1_1); + request.setHeader("Host", "tester"); + request.setHeader("Connection", "close"); + request.setHeader("Accept-Encoding", "something; q=0.1, gzip; q=0.5"); // TESTING THIS + request.setURI("/context/file.txt"); + + // Issue request + ByteBuffer rawResponse = localConnector.getResponse(request.generate(), 5, TimeUnit.SECONDS); + + // Parse response + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200)); + + // Response Content-Encoding check + assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), containsString("gzip")); + assertThat("Response[Vary]", response.get("Vary"), containsString("Accept-Encoding, User-Agent")); + + // Response Content checks + UncompressedMetadata metadata = parseResponseContent(response); + assertThat("(Uncompressed) Content Length", metadata.uncompressedSize, is(fileSize)); + assertThat("(Uncompressed) Content Hash", metadata.uncompressedSha1Sum, is(expectedSha1Sum)); + } + + @Test + public void testIsNotGzipCompressedByContentType() throws Exception + { + GzipHandler gzipHandler = new GzipHandler(); + gzipHandler.addIncludedMimeTypes("text/plain"); + + server = new Server(); + LocalConnector localConnector = new LocalConnector(server); + server.addConnector(localConnector); + + Path contextDir = workDir.resolve("context"); + FS.ensureDirExists(contextDir); + + ServletContextHandler servletContextHandler = new ServletContextHandler(); + servletContextHandler.setContextPath("/context"); + servletContextHandler.setBaseResource(new PathResource(contextDir)); + ServletHolder holder = new ServletHolder("default", DefaultServlet.class); + holder.setInitParameter("etags", "true"); + servletContextHandler.addServlet(holder, "/"); + servletContextHandler.insertHandler(gzipHandler); + + server.setHandler(servletContextHandler); + + // Prepare Server File + int fileSize = DEFAULT_OUTPUT_BUFFER_SIZE * 4; + Path file = createFile(contextDir, "file.mp3", fileSize); + String expectedSha1Sum = Sha1Sum.calculate(file); + + server.start(); + + // Setup request + HttpTester.Request request = HttpTester.newRequest(); + request.setMethod("GET"); + request.setVersion(HttpVersion.HTTP_1_1); + request.setHeader("Host", "tester"); + request.setHeader("Connection", "close"); + request.setHeader("Accept-Encoding", "gzip"); + request.setURI("/context/file.mp3"); + + // Issue request + ByteBuffer rawResponse = localConnector.getResponse(request.generate(), 5, TimeUnit.SECONDS); + + // Parse response + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200)); + + // Response Content-Encoding check + assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), not(containsString("gzip"))); + assertThat("Response[Vary]", response.get("Vary"), is(nullValue())); + + // Response Content checks + UncompressedMetadata metadata = parseResponseContent(response); + assertThat("Response Content Length", metadata.contentLength, is(fileSize)); + assertThat("(Uncompressed) Content Length", metadata.uncompressedSize, is(fileSize)); + assertThat("(Uncompressed) Content Hash", metadata.uncompressedSha1Sum, is(expectedSha1Sum)); + } + + @Test + public void testIsNotGzipCompressedByExcludedContentType() throws Exception + { + GzipHandler gzipHandler = new GzipHandler(); + gzipHandler.addExcludedMimeTypes("text/plain"); + + server = new Server(); + LocalConnector localConnector = new LocalConnector(server); + server.addConnector(localConnector); + + Path contextDir = workDir.resolve("context"); + FS.ensureDirExists(contextDir); + + ServletContextHandler servletContextHandler = new ServletContextHandler(); + servletContextHandler.setContextPath("/context"); + servletContextHandler.setBaseResource(new PathResource(contextDir)); + ServletHolder holder = new ServletHolder("default", DefaultServlet.class); + holder.setInitParameter("etags", "true"); + servletContextHandler.addServlet(holder, "/"); + servletContextHandler.insertHandler(gzipHandler); + + server.setHandler(servletContextHandler); + + // Prepare Server File + int fileSize = DEFAULT_OUTPUT_BUFFER_SIZE * 4; + Path file = createFile(contextDir, "file.txt", fileSize); + String expectedSha1Sum = Sha1Sum.calculate(file); + + server.start(); + + // Setup request + HttpTester.Request request = HttpTester.newRequest(); + request.setMethod("GET"); + request.setVersion(HttpVersion.HTTP_1_1); + request.setHeader("Host", "tester"); + request.setHeader("Connection", "close"); + request.setHeader("Accept-Encoding", "gzip"); + request.setURI("/context/file.txt"); + + // Issue request + ByteBuffer rawResponse = localConnector.getResponse(request.generate(), 5, TimeUnit.SECONDS); + + // Parse response + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200)); + + // Response Content-Encoding check + assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), not(containsString("gzip"))); + assertThat("Response[Vary]", response.get("Vary"), is(nullValue())); + + // Response Content checks + UncompressedMetadata metadata = parseResponseContent(response); + assertThat("Response Content Length", metadata.contentLength, is(fileSize)); + assertThat("(Uncompressed) Content Length", metadata.uncompressedSize, is(fileSize)); + assertThat("(Uncompressed) Content Hash", metadata.uncompressedSha1Sum, is(expectedSha1Sum)); + } + + @Test + public void testIsNotGzipCompressedByExcludedContentTypeWithCharset() throws Exception + { + GzipHandler gzipHandler = new GzipHandler(); + gzipHandler.addExcludedMimeTypes("text/plain"); + + server = new Server(); + LocalConnector localConnector = new LocalConnector(server); + server.addConnector(localConnector); + + Path contextDir = workDir.resolve("context"); + FS.ensureDirExists(contextDir); + + ServletContextHandler servletContextHandler = new ServletContextHandler(); + servletContextHandler.setContextPath("/context"); + servletContextHandler.setBaseResource(new PathResource(contextDir)); + servletContextHandler.getMimeTypes().addMimeMapping("txt", "text/plain;charset=UTF-8"); + ServletHolder holder = new ServletHolder("default", DefaultServlet.class); + holder.setInitParameter("etags", "true"); + servletContextHandler.addServlet(holder, "/"); + servletContextHandler.insertHandler(gzipHandler); + + server.setHandler(servletContextHandler); + + // Prepare Server File + int fileSize = DEFAULT_OUTPUT_BUFFER_SIZE * 4; + Path file = createFile(contextDir, "test_quotes.txt", fileSize); + String expectedSha1Sum = Sha1Sum.calculate(file); + + server.start(); + + // Setup request + HttpTester.Request request = HttpTester.newRequest(); + request.setMethod("GET"); + request.setVersion(HttpVersion.HTTP_1_1); + request.setHeader("Host", "tester"); + request.setHeader("Connection", "close"); + request.setHeader("Accept-Encoding", "gzip"); + request.setURI("/context/test_quotes.txt"); + + // Issue request + ByteBuffer rawResponse = localConnector.getResponse(request.generate(), 5, TimeUnit.SECONDS); + + // Parse response + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200)); + + // Response Content-Encoding check + assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), not(containsString("gzip"))); + assertThat("Response[Vary]", response.get("Vary"), is(nullValue())); + + // Response Content checks + UncompressedMetadata metadata = parseResponseContent(response); + assertThat("(Uncompressed) Content Length", metadata.uncompressedSize, is(fileSize)); + assertThat("(Uncompressed) Content Hash", metadata.uncompressedSha1Sum, is(expectedSha1Sum)); + } + + @Test + public void testUserAgentExclusionNoUAProvided() throws Exception + { + GzipHandler gzipHandler = new GzipHandler(); + gzipHandler.addIncludedMimeTypes("text/plain"); + gzipHandler.setExcludedAgentPatterns("bar", "foo"); + + server = new Server(); + LocalConnector localConnector = new LocalConnector(server); + server.addConnector(localConnector); + + Path contextDir = workDir.resolve("context"); + FS.ensureDirExists(contextDir); + + ServletContextHandler servletContextHandler = new ServletContextHandler(); + servletContextHandler.setContextPath("/context"); + servletContextHandler.setBaseResource(new PathResource(contextDir)); + ServletHolder holder = new ServletHolder("default", DefaultServlet.class); + servletContextHandler.addServlet(holder, "/"); + servletContextHandler.insertHandler(gzipHandler); + + server.setHandler(servletContextHandler); + + // Prepare Server File + int fileSize = DEFAULT_OUTPUT_BUFFER_SIZE * 4; + Path file = createFile(contextDir, "file.txt", fileSize); + String expectedSha1Sum = Sha1Sum.calculate(file); + + server.start(); + + // Setup request + HttpTester.Request request = HttpTester.newRequest(); + request.setMethod("GET"); + request.setVersion(HttpVersion.HTTP_1_1); + request.setHeader("Host", "tester"); + request.setHeader("Connection", "close"); + request.setHeader("Accept-Encoding", "gzip"); + // INTENTIONALLY NOT SET - request.setHeader("User-Agent", "foo"); + request.setURI("/context/file.txt"); + + // Issue request + ByteBuffer rawResponse = localConnector.getResponse(request.generate(), 5, TimeUnit.SECONDS); + + // Parse response + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200)); + + // Response Content-Encoding check + assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), containsString("gzip")); + assertThat("Response[Vary]", response.get("Vary"), is("Accept-Encoding, User-Agent")); + + // Response Content checks + UncompressedMetadata metadata = parseResponseContent(response); + assertThat("(Uncompressed) Content Length", metadata.uncompressedSize, is(fileSize)); + assertThat("(Uncompressed) Content Hash", metadata.uncompressedSha1Sum, is(expectedSha1Sum)); + } + + @Test + public void testUserAgentExclusionUAMatch() throws Exception + { + GzipHandler gzipHandler = new GzipHandler(); + gzipHandler.addIncludedMimeTypes("text/plain"); + gzipHandler.setExcludedAgentPatterns("bar", "foo"); + + server = new Server(); + LocalConnector localConnector = new LocalConnector(server); + server.addConnector(localConnector); + + Path contextDir = workDir.resolve("context"); + FS.ensureDirExists(contextDir); + + ServletContextHandler servletContextHandler = new ServletContextHandler(); + servletContextHandler.setContextPath("/context"); + servletContextHandler.setBaseResource(new PathResource(contextDir)); + ServletHolder holder = new ServletHolder("default", DefaultServlet.class); + servletContextHandler.addServlet(holder, "/"); + servletContextHandler.insertHandler(gzipHandler); + + server.setHandler(servletContextHandler); + + // Prepare Server File + int fileSize = DEFAULT_OUTPUT_BUFFER_SIZE * 4; + Path file = createFile(contextDir, "file.txt", fileSize); + String expectedSha1Sum = Sha1Sum.calculate(file); + + server.start(); + + // Setup request + HttpTester.Request request = HttpTester.newRequest(); + request.setMethod("GET"); + request.setVersion(HttpVersion.HTTP_1_1); + request.setHeader("Host", "tester"); + request.setHeader("Connection", "close"); + request.setHeader("Accept-Encoding", "gzip"); + request.setHeader("User-Agent", "foo"); + request.setURI("/context/file.txt"); + + // Issue request + ByteBuffer rawResponse = localConnector.getResponse(request.generate(), 5, TimeUnit.SECONDS); + + // Parse response + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200)); + + // Response Content-Encoding check + assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), not(containsString("gzip"))); + assertThat("Response[Vary]", response.get("Vary"), is("Accept-Encoding, User-Agent")); + + // Response Content checks + UncompressedMetadata metadata = parseResponseContent(response); + assertThat("Response Content Length", metadata.contentLength, is(fileSize)); + assertThat("(Uncompressed) Content Length", metadata.uncompressedSize, is(fileSize)); + assertThat("(Uncompressed) Content Hash", metadata.uncompressedSha1Sum, is(expectedSha1Sum)); + } + + @Test + public void testUserAgentExclusionDefault() throws Exception + { + GzipHandler gzipHandler = new GzipHandler(); + gzipHandler.addIncludedMimeTypes("text/plain"); + + server = new Server(); + LocalConnector localConnector = new LocalConnector(server); + server.addConnector(localConnector); + + Path contextDir = workDir.resolve("context"); + FS.ensureDirExists(contextDir); + + ServletContextHandler servletContextHandler = new ServletContextHandler(); + servletContextHandler.setContextPath("/context"); + servletContextHandler.setBaseResource(new PathResource(contextDir)); + ServletHolder holder = new ServletHolder("default", DefaultServlet.class); + servletContextHandler.addServlet(holder, "/"); + servletContextHandler.insertHandler(gzipHandler); + + server.setHandler(servletContextHandler); + + // Prepare Server File + int fileSize = DEFAULT_OUTPUT_BUFFER_SIZE * 4; + Path file = createFile(contextDir, "file.txt", fileSize); + String expectedSha1Sum = Sha1Sum.calculate(file); + + server.start(); + + // Setup request + HttpTester.Request request = HttpTester.newRequest(); + request.setMethod("GET"); + request.setVersion(HttpVersion.HTTP_1_1); + request.setHeader("Host", "tester"); + request.setHeader("Connection", "close"); + request.setHeader("Accept-Encoding", "gzip"); + request.setHeader("User-Agent", "Some MSIE 6.0 user-agent"); + request.setURI("/context/file.txt"); + + // Issue request + ByteBuffer rawResponse = localConnector.getResponse(request.generate(), 5, TimeUnit.SECONDS); + + // Parse response + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200)); + + // Response Content-Encoding check + assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), not(containsString("gzip"))); + assertThat("Response[Vary]", response.get("Vary"), is("Accept-Encoding, User-Agent")); + + // Response Content checks + UncompressedMetadata metadata = parseResponseContent(response); + assertThat("Response Content Length", metadata.contentLength, is(fileSize)); + assertThat("(Uncompressed) Content Length", metadata.uncompressedSize, is(fileSize)); + assertThat("(Uncompressed) Content Hash", metadata.uncompressedSha1Sum, is(expectedSha1Sum)); + } + + @Test + public void testUserAgentExclusionByExcludedAgentPatterns() throws Exception + { + GzipHandler gzipHandler = new GzipHandler(); + gzipHandler.addIncludedMimeTypes("text/plain"); + gzipHandler.setExcludedAgentPatterns("bar", "fo.*"); + + server = new Server(); + LocalConnector localConnector = new LocalConnector(server); + server.addConnector(localConnector); + + Path contextDir = workDir.resolve("context"); + FS.ensureDirExists(contextDir); + + ServletContextHandler servletContextHandler = new ServletContextHandler(); + servletContextHandler.setContextPath("/context"); + servletContextHandler.setBaseResource(new PathResource(contextDir)); + ServletHolder holder = new ServletHolder("default", DefaultServlet.class); + servletContextHandler.addServlet(holder, "/"); + servletContextHandler.insertHandler(gzipHandler); + + server.setHandler(servletContextHandler); + + // Prepare Server File + int fileSize = DEFAULT_OUTPUT_BUFFER_SIZE * 4; + Path file = createFile(contextDir, "file.txt", fileSize); + String expectedSha1Sum = Sha1Sum.calculate(file); + + server.start(); + + // Setup request + HttpTester.Request request = HttpTester.newRequest(); + request.setMethod("GET"); + request.setVersion(HttpVersion.HTTP_1_1); + request.setHeader("Host", "tester"); + request.setHeader("Connection", "close"); + request.setHeader("Accept-Encoding", "gzip"); + request.setHeader("User-Agent", "foo"); + request.setURI("/context/file.txt"); + + // Issue request + ByteBuffer rawResponse = localConnector.getResponse(request.generate(), 5, TimeUnit.SECONDS); + + // Parse response + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200)); + + // Response Content-Encoding check + assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), not(containsString("gzip"))); + assertThat("Response[Vary]", response.get("Vary"), is("Accept-Encoding, User-Agent")); + + // Response Content checks + UncompressedMetadata metadata = parseResponseContent(response); + assertThat("Response Content Length", metadata.contentLength, is(fileSize)); + assertThat("(Uncompressed) Content Length", metadata.uncompressedSize, is(fileSize)); + assertThat("(Uncompressed) Content Hash", metadata.uncompressedSha1Sum, is(expectedSha1Sum)); + } + + @Test + public void testExcludePaths() throws Exception + { + GzipHandler gzipHandler = new GzipHandler(); + gzipHandler.addIncludedMimeTypes("text/plain"); + gzipHandler.setExcludedPaths("*.txt"); + + server = new Server(); + LocalConnector localConnector = new LocalConnector(server); + server.addConnector(localConnector); + + Path contextDir = workDir.resolve("context"); + FS.ensureDirExists(contextDir); + + ServletContextHandler servletContextHandler = new ServletContextHandler(); + servletContextHandler.setContextPath("/context"); + servletContextHandler.setBaseResource(new PathResource(contextDir)); + ServletHolder holder = new ServletHolder("default", DefaultServlet.class); + servletContextHandler.addServlet(holder, "/"); + servletContextHandler.insertHandler(gzipHandler); + + server.setHandler(servletContextHandler); + + // Prepare Server File + int fileSize = DEFAULT_OUTPUT_BUFFER_SIZE * 4; + Path file = createFile(contextDir, "file.txt", fileSize); + String expectedSha1Sum = Sha1Sum.calculate(file); + + server.start(); + + // Setup request + HttpTester.Request request = HttpTester.newRequest(); + request.setMethod("GET"); + request.setVersion(HttpVersion.HTTP_1_1); + request.setHeader("Host", "tester"); + request.setHeader("Connection", "close"); + request.setHeader("Accept-Encoding", "gzip"); + request.setURI("/context/file.txt"); + + // Issue request + ByteBuffer rawResponse = localConnector.getResponse(request.generate(), 5, TimeUnit.SECONDS); + + // Parse response + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200)); + + // Response Content-Encoding check + assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), not(containsString("gzip"))); + assertThat("Response[Vary]", response.get("Vary"), is(nullValue())); + + // Response Content checks + UncompressedMetadata metadata = parseResponseContent(response); + assertThat("Response Content Length", metadata.contentLength, is(fileSize)); + assertThat("(Uncompressed) Content Length", metadata.uncompressedSize, is(fileSize)); + assertThat("(Uncompressed) Content Hash", metadata.uncompressedSha1Sum, is(expectedSha1Sum)); + } + + @Test + public void testIncludedPaths() throws Exception + { + GzipHandler gzipHandler = new GzipHandler(); + gzipHandler.setExcludedPaths("/bad.txt"); + gzipHandler.setIncludedPaths("*.txt"); + + server = new Server(); + LocalConnector localConnector = new LocalConnector(server); + server.addConnector(localConnector); + + Path contextDir = workDir.resolve("context"); + FS.ensureDirExists(contextDir); + + ServletContextHandler servletContextHandler = new ServletContextHandler(); + servletContextHandler.setContextPath("/context"); + servletContextHandler.setBaseResource(new PathResource(contextDir)); + ServletHolder holder = new ServletHolder("default", DefaultServlet.class); + servletContextHandler.addServlet(holder, "/"); + servletContextHandler.insertHandler(gzipHandler); + + server.setHandler(servletContextHandler); + + // Prepare Server File + Path fileGood = createFile(contextDir, "file.txt", DEFAULT_OUTPUT_BUFFER_SIZE * 4); + Path fileBad = createFile(contextDir, "bad.txt", DEFAULT_OUTPUT_BUFFER_SIZE * 2); + String expectedGoodSha1Sum = Sha1Sum.calculate(fileGood); + String expectedBadSha1Sum = Sha1Sum.calculate(fileBad); + + server.start(); + + // Test Request 1 + { + HttpTester.Request request = HttpTester.newRequest(); + request.setMethod("GET"); + request.setVersion(HttpVersion.HTTP_1_1); + request.setHeader("Host", "tester"); + request.setHeader("Connection", "close"); + request.setHeader("Accept-Encoding", "gzip"); + request.setURI("/context/file.txt"); + + ByteBuffer rawResponse = localConnector.getResponse(request.generate(), 5, TimeUnit.SECONDS); + + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200)); + + assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), containsString("gzip")); + assertThat("Response[Vary]", response.get("Vary"), is("Accept-Encoding, User-Agent")); + + UncompressedMetadata metadata = parseResponseContent(response); + assertThat("(Uncompressed) Content Length", metadata.uncompressedSize, is((int)Files.size(fileGood))); + assertThat("(Uncompressed) Content Hash", metadata.uncompressedSha1Sum, is(expectedGoodSha1Sum)); + } + + // Test Request 2 + { + HttpTester.Request request = HttpTester.newRequest(); + request.setMethod("GET"); + request.setVersion(HttpVersion.HTTP_1_1); + request.setHeader("Host", "tester"); + request.setHeader("Connection", "close"); + request.setHeader("Accept-Encoding", "gzip"); + request.setURI("/context/bad.txt"); + + ByteBuffer rawResponse = localConnector.getResponse(request.generate(), 5, TimeUnit.SECONDS); + + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200)); + + assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), not(containsString("gzip"))); + assertThat("Response[Vary]", response.get("Vary"), is(nullValue())); + + UncompressedMetadata metadata = parseResponseContent(response); + int fileSize = (int)Files.size(fileBad); + assertThat("Response Content Length", metadata.contentLength, is(fileSize)); + assertThat("(Uncompressed) Content Length", metadata.uncompressedSize, is(fileSize)); + assertThat("(Uncompressed) Content Hash", metadata.uncompressedSha1Sum, is(expectedBadSha1Sum)); + } + } + + @Test + public void testIsNotGzipCompressedSVGZ() throws Exception + { + GzipHandler gzipHandler = new GzipHandler(); + + server = new Server(); + LocalConnector localConnector = new LocalConnector(server); + server.addConnector(localConnector); + + Path contextDir = workDir.resolve("context"); + FS.ensureDirExists(contextDir); + + ServletContextHandler servletContextHandler = new ServletContextHandler(); + servletContextHandler.setContextPath("/context"); + servletContextHandler.setBaseResource(new PathResource(contextDir)); + ServletHolder holder = new ServletHolder("default", DefaultServlet.class); + servletContextHandler.addServlet(holder, "/"); + servletContextHandler.insertHandler(gzipHandler); + + server.setHandler(servletContextHandler); + + // Prepare Server File + Path testResource = MavenTestingUtils.getTestResourcePath("test.svgz"); + Path file = contextDir.resolve("test.svgz"); + IO.copy(testResource.toFile(), file.toFile()); + int fileSize = (int)Files.size(file); + + server.start(); + + // Setup request + HttpTester.Request request = HttpTester.newRequest(); + request.setMethod("GET"); + request.setVersion(HttpVersion.HTTP_1_1); + request.setHeader("Host", "tester"); + request.setHeader("Connection", "close"); + request.setHeader("Accept-Encoding", "gzip"); + request.setURI("/context/test.svgz"); + + // Issue request + ByteBuffer rawResponse = localConnector.getResponse(request.generate(), 5, TimeUnit.SECONDS); + + // Parse response + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + + assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200)); + + // Response Header checks + assertThat("Response[Content-Type]", response.get("Content-Type"), containsString("image/svg+xml")); + assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), containsString("gzip")); + assertThat("Response[Vary]", response.get("Vary"), is(nullValue())); + + // Response Content checks + UncompressedMetadata metadata = parseResponseContent(response); + assertThat("Response Content Length", metadata.contentLength, is(fileSize)); + } +} diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipDefaultTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipDefaultTest.java deleted file mode 100644 index a30150100c7..00000000000 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipDefaultTest.java +++ /dev/null @@ -1,765 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. -// -// This program and the accompanying materials are made available under -// the terms of the Eclipse Public License 2.0 which is available at -// https://www.eclipse.org/legal/epl-2.0 -// -// This Source Code may also be made available under the following -// Secondary Licenses when the conditions for such availability set -// forth in the Eclipse Public License, v. 2.0 are satisfied: -// the Apache License v2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0 -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// ======================================================================== -// - -package org.eclipse.jetty.servlets; - -import java.io.File; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.concurrent.TimeUnit; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.http.CompressedContentFormat; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.tools.HttpTester; -import org.eclipse.jetty.server.handler.gzip.GzipHandler; -import org.eclipse.jetty.servlet.DefaultServlet; -import org.eclipse.jetty.toolchain.test.IO; -import org.eclipse.jetty.toolchain.test.jupiter.WorkDir; -import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension; -import org.eclipse.jetty.util.StringUtil; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.emptyOrNullString; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.startsWith; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -/** - * Test the GzipHandler support built into the {@link DefaultServlet} - */ -@ExtendWith(WorkDirExtension.class) -public class GzipDefaultTest -{ - private String compressionType; - - public GzipDefaultTest() - { - this.compressionType = GzipHandler.GZIP; - } - - @SuppressWarnings("serial") - public static class HttpStatusServlet extends HttpServlet - { - private int _status = 204; - - public HttpStatusServlet() - { - super(); - } - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException - { - resp.setStatus(_status); - resp.setHeader("ETag", "W/\"204\""); - } - } - - @SuppressWarnings("serial") - public static class HttpErrorServlet extends HttpServlet - { - private int _status = 400; - - public HttpErrorServlet() - { - super(); - } - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException - { - resp.getOutputStream().write("error message".getBytes()); - resp.setStatus(_status); - } - } - - @SuppressWarnings("serial") - public static class HttpContentTypeWithEncoding extends HttpServlet - { - public static final String COMPRESSED_CONTENT = "" +
+ "This content must be longer than the default min gzip length, which is " + GzipHandler.DEFAULT_MIN_GZIP_SIZE + " bytes. " +
+ "The moon is blue to a fish in love.
" +
+ "How now brown cow.
" +
+ "The quick brown fox jumped over the lazy dog.
" +
+ "A woman needs a man like a fish needs a bicycle!" +
+ "
- * This is used to test exclusions and passthroughs in the GzipHandler. - *
- * An example is to test that it is possible to configure GzipFilter to not recompress content that shouldn't be compressed by the GzipFilter. - * - * @param requestedFilename the filename used to on the GET request,. - * @param testResourceSha1Sum the sha1sum file that contains the SHA1SUM checksum that will be used to verify that the response contents are what is intended. - * @param expectedContentType the expected content type - * @throws Exception on test failure - */ - public void assertIsResponseNotGziped(String requestedFilename, String testResourceSha1Sum, String expectedContentType) throws Exception - { - assertIsResponseNotGzipFiltered(requestedFilename, testResourceSha1Sum, expectedContentType, null); - } - - /** - * Makes sure that the response contains an unfiltered file contents. - *
- * This is used to test exclusions and passthroughs in the GzipHandler. - *
- * An example is to test that it is possible to configure GzipFilter to not recompress content that shouldn't be compressed by the GzipFilter.
- *
- * @param requestedFilename the filename used to on the GET request,.
- * @param testResourceSha1Sum the sha1sum file that contains the SHA1SUM checksum that will be used to verify that the response contents are what is intended.
- * @param expectedContentType the expected content type
- * @param expectedContentEncoding can be non-null in some circumstances, eg when dealing with pre-gzipped .svgz files
- * @throws Exception on test failure
- */
- public void assertIsResponseNotGzipFiltered(String requestedFilename, String testResourceSha1Sum, String expectedContentType, String expectedContentEncoding)
- throws Exception
- {
- HttpTester.Request request = HttpTester.newRequest();
- HttpTester.Response response;
-
- request.setMethod("GET");
- request.setVersion("HTTP/1.0");
- request.setHeader("Host", "tester");
- request.setHeader("Accept-Encoding", compressionType);
- if (this.userAgent != null)
- request.setHeader("User-Agent", this.userAgent);
- request.setURI("/context/" + requestedFilename);
-
- // Issue the request
- response = HttpTester.parseResponse(tester.getResponses(request.generate()));
-
- dumpHeaders(requestedFilename + " / Response Headers", response);
-
- // Assert the response headers
- String prefix = requestedFilename + " / Response";
- assertThat(prefix + ".status", response.getStatus(), is(HttpServletResponse.SC_OK));
- assertThat(prefix + ".header[Content-Length]", response.get("Content-Length"), notNullValue());
- assertThat(prefix + ".header[Content-Encoding] (should not be recompressed by GzipHandler)", response.get("Content-Encoding"),
- expectedContentEncoding == null ? nullValue() : notNullValue());
- if (expectedContentEncoding != null)
- assertThat(prefix + ".header[Content-Encoding]", response.get("Content-Encoding"), is(expectedContentEncoding));
- assertThat(prefix + ".header[Content-Type] (should have a Content-Type associated with it)", response.get("Content-Type"), notNullValue());
- assertThat(prefix + ".header[Content-Type]", response.get("Content-Type"), is(expectedContentType));
-
- assertThat(response.get("ETAG"), Matchers.startsWith("W/"));
-
- ByteArrayInputStream bais = null;
- DigestOutputStream digester = null;
- try
- {
- MessageDigest digest = MessageDigest.getInstance("SHA1");
- bais = new ByteArrayInputStream(response.getContentBytes());
- digester = new DigestOutputStream(new NoOpOutputStream(), digest);
- IO.copy(bais, digester);
-
- String actualSha1Sum = Hex.asHex(digest.digest());
- File sha1File = MavenTestingUtils.getTestResourceFile(testResourceSha1Sum);
- String expectedSha1Sum = Sha1Sum.loadSha1(sha1File);
- assertEquals(expectedSha1Sum, actualSha1Sum, requestedFilename + " / SHA1Sum of content");
- }
- finally
- {
- IO.close(digester);
- IO.close(bais);
- }
- }
-
- private void dumpHeaders(String prefix, HttpTester.Message message)
- {
- LOG.debug("dumpHeaders: {}", prefix);
- Enumeration