Issue #4770 - Deprecate GzipTester

+ Renamed TestDirContentServlet to AbstractFileContentServlet
+ Renamed various TestServlet*Write classes to BlockingServlet*Write to better
  represent their purpose.
+ Renamed TestServletBufferTypeLengthWrite to HttpOutputWriteFileContentServlet
+ Cleaned up GzipContentLengthTest to be one big ParameterizedTest
  - now does Internal vs External GzipHandler testing too.
+ Introduced AbstractGzipTest to house simple common methods
+ Cleanup remaining testcases

Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
This commit is contained in:
Joakim Erdfelt 2020-04-14 15:11:54 -05:00
parent 6694f94cd5
commit aa702c06bd
No known key found for this signature in database
GPG Key ID: 2D0E1FB8FE4B68B4
28 changed files with 2058 additions and 2196 deletions

View File

@ -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);
}
}

View File

@ -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.
* <p>
* 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).
* </p>
*
* @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);
}
}
}

View File

@ -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);

View File

@ -43,7 +43,7 @@ import static org.hamcrest.Matchers.nullValue;
* </pre>
*/
@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);

View File

@ -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);

View File

@ -42,12 +42,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler;
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@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);

View File

@ -42,12 +42,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler;
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@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);

View File

@ -42,12 +42,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler;
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@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();

View File

@ -42,12 +42,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler;
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@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();

View File

@ -42,12 +42,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler;
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@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();

View File

@ -42,12 +42,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler;
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@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"))

View File

@ -42,12 +42,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler;
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@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"))

View File

@ -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 <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
* 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<Arguments> scenarios()
{
List<Scenario> ret = new ArrayList<>();
// The list of servlets that implement various content sending behaviors
// some behaviors are more sane then others, but they are all real world scenarios
// that we have seen or had issues reported against Jetty.
List<Class<? extends AbstractFileContentServlet>> servlets = new ArrayList<>();
ret.add(new Scenario(0, "empty.txt", !EXPECT_COMPRESSED));
ret.add(new Scenario(TINY, "file-tiny.txt", !EXPECT_COMPRESSED));
ret.add(new Scenario(SMALL, "file-small.txt", EXPECT_COMPRESSED));
ret.add(new Scenario(SMALL, "file-small.mp3", !EXPECT_COMPRESSED));
ret.add(new Scenario(MEDIUM, "file-med.txt", EXPECT_COMPRESSED));
ret.add(new Scenario(MEDIUM, "file-medium.mp3", !EXPECT_COMPRESSED));
ret.add(new Scenario(LARGE, "file-large.txt", EXPECT_COMPRESSED));
ret.add(new Scenario(LARGE, "file-large.mp3", !EXPECT_COMPRESSED));
// AsyncContext create -> timeout -> onTimeout -> write-response -> complete
servlets.add(AsyncTimeoutCompleteWrite.Default.class);
servlets.add(AsyncTimeoutCompleteWrite.Passed.class);
// AsyncContext create -> timeout -> onTimeout -> dispatch -> write-response
servlets.add(AsyncTimeoutDispatchWrite.Default.class);
servlets.add(AsyncTimeoutDispatchWrite.Passed.class);
// AsyncContext create -> no-timeout -> scheduler.schedule -> dispatch -> write-response
servlets.add(AsyncScheduledDispatchWrite.Default.class);
servlets.add(AsyncScheduledDispatchWrite.Passed.class);
return ret.stream().map(Arguments::of);
}
// HttpOutput usage scenario from http://bugs.eclipse.org/450873
// 1. getOutputStream()
// 2. setHeader(content-type)
// 3. setHeader(content-length)
// 4. (unwrapped) HttpOutput.write(ByteBuffer)
servlets.add(HttpOutputWriteFileContentServlet.class);
private void testWithGzip(Scenario scenario, Class<? extends TestDirContentServlet> contentServlet) throws Exception
{
GzipTester tester = new GzipTester(workDir.getPath(), GzipHandler.GZIP);
// The following blocking scenarios are from http://bugs.eclipse.org/354014
// Blocking
// 1. setHeader(content-length)
// 2. getOutputStream()
// 3. setHeader(content-type)
// 4. outputStream.write()
servlets.add(BlockingServletLengthStreamTypeWrite.class);
// Blocking
// 1. setHeader(content-length)
// 2. setHeader(content-type)
// 3. getOutputStream()
// 4. outputStream.write()
servlets.add(BlockingServletLengthTypeStreamWrite.class);
// Blocking
// 1. getOutputStream()
// 2. setHeader(content-length)
// 3. setHeader(content-type)
// 4. outputStream.write()
servlets.add(BlockingServletStreamLengthTypeWrite.class);
// Blocking
// 1. getOutputStream()
// 2. setHeader(content-length)
// 3. setHeader(content-type)
// 4. outputStream.write() (with frequent response flush)
servlets.add(BlockingServletStreamLengthTypeWriteWithFlush.class);
// Blocking
// 1. getOutputStream()
// 2. setHeader(content-type)
// 3. setHeader(content-length)
// 4. outputStream.write()
servlets.add(BlockingServletStreamTypeLengthWrite.class);
// Blocking
// 1. setHeader(content-type)
// 2. setHeader(content-length)
// 3. getOutputStream()
// 4. outputStream.write()
servlets.add(BlockingServletTypeLengthStreamWrite.class);
// Blocking
// 1. setHeader(content-type)
// 2. getOutputStream()
// 3. setHeader(content-length)
// 4. outputStream.write()
servlets.add(BlockingServletTypeStreamLengthWrite.class);
// Add AsyncGzip Configuration
tester.getGzipHandler().setIncludedMimeTypes("text/plain");
tester.getGzipHandler().setIncludedPaths("*.txt", "*.mp3");
List<Arguments> scenarios = new ArrayList<>();
// Add content servlet
tester.setContentServlet(contentServlet);
try
for (Class<? extends Servlet> servlet : servlets)
{
String testFilename = String.format("%s-%s", contentServlet.getSimpleName(), scenario.fileName);
File testFile = tester.prepareServerFile(testFilename, scenario.fileSize);
tester.start();
HttpTester.Response response = tester.executeRequest("GET", "/context/" + testFile.getName(), 5, TimeUnit.SECONDS);
if (response.getStatus() != 200)
System.err.println("DANG!!!! " + response);
assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200));
if (scenario.expectCompressed)
for (GzipMode gzipMode : GzipMode.values())
{
// Must be gzip compressed
assertThat("Content-Encoding", response.get("Content-Encoding"), containsString(GzipHandler.GZIP));
// Not compressible (not large enough)
scenarios.add(Arguments.of(gzipMode, servlet, 0, "empty.txt", false));
scenarios.add(Arguments.of(gzipMode, servlet, GzipHandler.DEFAULT_MIN_GZIP_SIZE / 2, "file-tiny.txt", false));
// Compressible.
scenarios.add(Arguments.of(gzipMode, servlet, DEFAULT_OUTPUT_BUFFER_SIZE / 2, "file-small.txt", true));
scenarios.add(Arguments.of(gzipMode, servlet, DEFAULT_OUTPUT_BUFFER_SIZE, "file-medium.txt", true));
scenarios.add(Arguments.of(gzipMode, servlet, DEFAULT_OUTPUT_BUFFER_SIZE * 4, "file-large.txt", true));
// Not compressible (not a matching Content-Type)
scenarios.add(Arguments.of(gzipMode, servlet, DEFAULT_OUTPUT_BUFFER_SIZE / 2, "file-small.mp3", false));
scenarios.add(Arguments.of(gzipMode, servlet, DEFAULT_OUTPUT_BUFFER_SIZE, "file-medium.mp3", false));
scenarios.add(Arguments.of(gzipMode, servlet, DEFAULT_OUTPUT_BUFFER_SIZE * 4, "file-large.mp3", false));
}
else
{
assertThat("Content-Encoding", response.get("Content-Encoding"), not(containsString(GzipHandler.GZIP)));
}
// Uncompressed content Size
ContentMetadata content = tester.getResponseMetadata(response);
assertThat("(Uncompressed) Content Length", content.size, is((long)scenario.fileSize));
}
finally
return scenarios.stream();
}
private Server server;
@AfterEach
public void stopServer()
{
LifeCycle.stop(server);
}
@ParameterizedTest
@MethodSource("scenarios")
public void executeScenario(GzipMode gzipMode, Class<? extends Servlet> contentServlet, int fileSize, String fileName, boolean compressible) throws Exception
{
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.addServlet(contentServlet, "/*");
GzipHandler gzipHandler = new GzipHandler();
switch (gzipMode)
{
tester.stop();
case INTERNAL:
servletContextHandler.insertHandler(gzipHandler);
server.setHandler(servletContextHandler);
break;
case EXTERNAL:
gzipHandler.setHandler(servletContextHandler);
server.setHandler(gzipHandler);
break;
}
}
/**
* Test with content servlet that does:
* AsyncContext create -> timeout -> onTimeout -> write-response -> complete
*
* @throws Exception on test failure
*/
@ParameterizedTest
@MethodSource("scenarios")
public void testAsyncTimeoutCompleteWriteDefault(Scenario scenario) throws Exception
{
testWithGzip(scenario, AsyncTimeoutCompleteWrite.Default.class);
}
Path file = createFile(contextDir, fileName, fileSize);
String expectedSha1Sum = Sha1Sum.calculate(file);
/**
* Test with content servlet that does:
* AsyncContext create -> timeout -> onTimeout -> write-response -> complete
*
* @throws Exception on test failure
*/
@ParameterizedTest
@MethodSource("scenarios")
public void testAsyncTimeoutCompleteWritePassed(Scenario scenario) throws Exception
{
testWithGzip(scenario, AsyncTimeoutCompleteWrite.Passed.class);
}
server.start();
/**
* Test with content servlet that does:
* AsyncContext create -> timeout -> onTimeout -> dispatch -> write-response
*
* @throws Exception on test failure
*/
@ParameterizedTest
@MethodSource("scenarios")
public void testAsyncTimeoutDispatchWriteDefault(Scenario scenario) throws Exception
{
testWithGzip(scenario, AsyncTimeoutDispatchWrite.Default.class);
}
// 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.getFileName().toString());
/**
* Test with content servlet that does:
* AsyncContext create -> timeout -> onTimeout -> dispatch -> write-response
*
* @throws Exception on test failure
*/
@ParameterizedTest
@MethodSource("scenarios")
public void testAsyncTimeoutDispatchWritePassed(Scenario scenario) throws Exception
{
testWithGzip(scenario, AsyncTimeoutDispatchWrite.Passed.class);
}
// Issue request
ByteBuffer rawResponse = localConnector.getResponse(request.generate(), 5, TimeUnit.SECONDS);
/**
* Test with content servlet that does:
* AsyncContext create -> no-timeout -> scheduler.schedule -> dispatch -> write-response
*
* @throws Exception on test failure
*/
@ParameterizedTest
@MethodSource("scenarios")
public void testAsyncScheduledDispatchWriteDefault(Scenario scenario) throws Exception
{
testWithGzip(scenario, AsyncScheduledDispatchWrite.Default.class);
}
// Parse response
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
/**
* Test with content servlet that does:
* AsyncContext create -> no-timeout -> scheduler.schedule -> dispatch -> write-response
*
* @throws Exception on test failure
*/
@ParameterizedTest
@MethodSource("scenarios")
public void testAsyncScheduledDispatchWritePassed(Scenario scenario) throws Exception
{
testWithGzip(scenario, AsyncScheduledDispatchWrite.Passed.class);
}
assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200));
/**
* Test with content servlet that does:
* 1) setHeader(content-length)
* 2) getOutputStream()
* 3) setHeader(content-type)
* 4) outputStream.write()
*
* @throws Exception on test failure
* @see <a href="http://bugs.eclipse.org/354014">Eclipse Bug 354014</a>
*/
@ParameterizedTest
@MethodSource("scenarios")
public void testServletLengthStreamTypeWrite(Scenario scenario) throws Exception
{
testWithGzip(scenario, TestServletLengthStreamTypeWrite.class);
}
/**
* Test with content servlet that does:
* 1) setHeader(content-length)
* 2) setHeader(content-type)
* 3) getOutputStream()
* 4) outputStream.write()
*
* @throws Exception on test failure
* @see <a href="http://bugs.eclipse.org/354014">Eclipse Bug 354014</a>
*/
@ParameterizedTest
@MethodSource("scenarios")
public void testServletLengthTypeStreamWrite(Scenario scenario) throws Exception
{
testWithGzip(scenario, TestServletLengthTypeStreamWrite.class);
}
/**
* Test with content servlet that does:
* 1) getOutputStream()
* 2) setHeader(content-length)
* 3) setHeader(content-type)
* 4) outputStream.write()
*
* @throws Exception on test failure
* @see <a href="http://bugs.eclipse.org/354014">Eclipse Bug 354014</a>
*/
@ParameterizedTest
@MethodSource("scenarios")
public void testServletStreamLengthTypeWrite(Scenario scenario) throws Exception
{
testWithGzip(scenario, TestServletStreamLengthTypeWrite.class);
}
/**
* Test with content servlet that does:
* 1) getOutputStream()
* 2) setHeader(content-length)
* 3) setHeader(content-type)
* 4) outputStream.write() (with frequent response flush)
*
* @throws Exception on test failure
* @see <a href="http://bugs.eclipse.org/354014">Eclipse Bug 354014</a>
*/
@ParameterizedTest
@MethodSource("scenarios")
public void testServletStreamLengthTypeWriteWithFlush(Scenario scenario) throws Exception
{
testWithGzip(scenario, TestServletStreamLengthTypeWriteWithFlush.class);
}
/**
* Test with content servlet that does:
* 1) getOutputStream()
* 2) setHeader(content-type)
* 3) setHeader(content-length)
* 4) outputStream.write()
*
* @throws Exception on test failure
* @see <a href="http://bugs.eclipse.org/354014">Eclipse Bug 354014</a>
*/
@ParameterizedTest
@MethodSource("scenarios")
public void testServletStreamTypeLengthWrite(Scenario scenario) throws Exception
{
testWithGzip(scenario, TestServletStreamTypeLengthWrite.class);
}
/**
* Test with content servlet that does:
* 1) setHeader(content-type)
* 2) setHeader(content-length)
* 3) getOutputStream()
* 4) outputStream.write()
*
* @throws Exception on test failure
* @see <a href="http://bugs.eclipse.org/354014">Eclipse Bug 354014</a>
*/
@ParameterizedTest
@MethodSource("scenarios")
public void testServletTypeLengthStreamWrite(Scenario scenario) throws Exception
{
testWithGzip(scenario, TestServletTypeLengthStreamWrite.class);
}
/**
* Test with content servlet that does:
* 1) setHeader(content-type)
* 2) getOutputStream()
* 3) setHeader(content-length)
* 4) outputStream.write()
*
* @throws Exception on test failure
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@ParameterizedTest
@MethodSource("scenarios")
public void testServletTypeStreamLengthWrite(Scenario scenario) throws Exception
{
testWithGzip(scenario, TestServletTypeStreamLengthWrite.class);
}
/**
* Test with content servlet that does:
* 2) getOutputStream()
* 1) setHeader(content-type)
* 3) setHeader(content-length)
* 4) (unwrapped) HttpOutput.write(ByteBuffer)
*
* This is done to demonstrate a bug with using HttpOutput.write()
* while also using GzipFilter
*
* @throws Exception on test failure
* @see <a href="http://bugs.eclipse.org/450873">Eclipse Bug 450873</a>
*/
@ParameterizedTest
@MethodSource("scenarios")
public void testHttpOutputWrite(Scenario scenario) throws Exception
{
testWithGzip(scenario, TestServletBufferTypeLengthWrite.class);
}
public static class Scenario
{
final int fileSize;
final String fileName;
final boolean expectCompressed;
public Scenario(int fileSize, String fileName, boolean expectCompressed)
// Response Content-Encoding check
Matcher<String> contentEncodingMatcher = containsString(GzipHandler.GZIP);
if (!compressible)
{
this.fileSize = fileSize;
this.fileName = fileName;
this.expectCompressed = expectCompressed;
contentEncodingMatcher = not(contentEncodingMatcher);
}
assertThat("Content-Encoding", response.get("Content-Encoding"), contentEncodingMatcher);
@Override
public String toString()
{
return String.format("%s [%,d bytes, compressed=%b]", fileName, fileSize, expectCompressed);
}
// Response Content checks
UncompressedMetadata metadata = parseResponseContent(response);
assertThat("(Uncompressed) Content Length", metadata.uncompressedSize, is(fileSize));
// TODO: Assertions.assertArrayEquals();
// TODO: compare bytes
assertThat("(Uncompressed) Content Hash", metadata.uncompressedSha1Sum, is(expectedSha1Sum));
}
}

View File

@ -1,100 +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.util.Arrays;
import java.util.stream.Stream;
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.MavenTestingUtils;
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.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
/**
* Tests {@link GzipHandler} in combination with {@link DefaultServlet} for ability to configure {@link GzipHandler} to
* ignore recompress situations from upstream.
*/
@ExtendWith(WorkDirExtension.class)
public class GzipDefaultNoRecompressTest
{
public static Stream<Arguments> data()
{
return Arrays.asList(new Object[][]
{
// Some already compressed files
{"test_quotes.gz", "application/gzip", GzipHandler.GZIP},
{"test_quotes.br", "application/brotli", GzipHandler.GZIP},
{"test_quotes.bz2", "application/bzip2", GzipHandler.GZIP},
{"test_quotes.zip", "application/zip", GzipHandler.GZIP},
{"test_quotes.rar", "application/x-rar-compressed", GzipHandler.GZIP},
// Some images (common first)
{"jetty_logo.png", "image/png", GzipHandler.GZIP},
{"jetty_logo.gif", "image/gif", GzipHandler.GZIP},
{"jetty_logo.jpeg", "image/jpeg", GzipHandler.GZIP},
{"jetty_logo.jpg", "image/jpeg", GzipHandler.GZIP},
// Lesser encountered images (usually found being requested from non-browser clients)
{"jetty_logo.bmp", "image/bmp", GzipHandler.GZIP},
{"jetty_logo.tif", "image/tiff", GzipHandler.GZIP},
{"jetty_logo.tiff", "image/tiff", GzipHandler.GZIP},
{"jetty_logo.xcf", "image/xcf", GzipHandler.GZIP},
{"jetty_logo.jp2", "image/jpeg2000", GzipHandler.GZIP},
//qvalue disables compression
{"test_quotes.txt", "text/plain", GzipHandler.GZIP + ";q=0"},
{"test_quotes.txt", "text/plain", GzipHandler.GZIP + "; q = 0 "}
}).stream().map(Arguments::of);
}
public WorkDir testingdir;
@ParameterizedTest
@MethodSource("data")
public void testNotGzipHandleredDefaultAlreadyCompressed(String alreadyCompressedFilename, String expectedContentType, String compressionType) throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
copyTestFileToServer(alreadyCompressedFilename);
tester.setContentServlet(TestStaticMimeTypeServlet.class);
try
{
tester.start();
tester.assertIsResponseNotGziped(alreadyCompressedFilename, alreadyCompressedFilename + ".sha1", expectedContentType);
}
finally
{
tester.stop();
}
}
private void copyTestFileToServer(String testFilename) throws IOException
{
File testFile = MavenTestingUtils.getTestResourceFile(testFilename);
File outFile = testingdir.getPathFile(testFilename).toFile();
IO.copy(testFile, outFile);
}
}

View File

@ -0,0 +1,106 @@
//
// ========================================================================
// 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;
/**
* GzipHandler setting of headers when reset and/or not compressed.
*
* The GzipHandler now sets deferred headers (content-length and etag) when it decides not to commit.
* Also does not allow a reset after a decision to commit
*
* Originally from http://bugs.eclipse.org/408909
*/
public class GzipDefaultServletDeferredContentTypeTest extends AbstractGzipTest
{
/*
public static class AddDefaultServletCustomizer extends ServerHandlerCustomizer
{
@Override
public Handler customize(ServletContextHandler servletContextHandler, Class<? extends Servlet> servletClass)
{
ServletHolder holder = new ServletHolder("default", servletClass);
servletContextHandler.addServlet(holder, "/");
return servletContextHandler;
}
}
@Test
public void testIsNotGzipCompressedByDeferredContentType() throws Exception
{
createServer(new AddDefaultServletCustomizer(), DeferredGetDefaultServlet.class);
int fileSize = DEFAULT_OUTPUT_BUFFER_SIZE * 4;
Path file = createFile("file.mp3.deferred", 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.deferred");
// 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")));
// Response Vary check
assertThat("Response[Vary]", response.get("Vary"), is(emptyOrNullString()));
// Response Content checks
UncompressedMetadata metadata = parseResponseContent(response);
assertThat("(Uncompressed) Content Length", metadata.uncompressedSize, is(fileSize));
assertThat("(Uncompressed) Content Hash", metadata.uncompressedSha1Sum, is(expectedSha1Sum));
}
public static class DeferredGetDefaultServlet extends DefaultServlet
{
public DeferredGetDefaultServlet()
{
super();
}
@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException
{
String uri = req.getRequestURI();
if (uri.endsWith(".deferred"))
{
// System.err.println("type for "+uri.substring(0,uri.length()-9)+" is "+getServletContext().getMimeType(uri.substring(0,uri.length()-9)));
resp.setContentType(getServletContext().getMimeType(uri.substring(0, uri.length() - 9)));
}
doGet(req, resp);
}
}
*/
}

View File

@ -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 = "<html><head></head><body><h1>COMPRESSABLE CONTENT</h1>" +
"This content must be longer than the default min gzip length, which is 256 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!" +
"</body></html>";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setContentType("text/plain;charset=UTF8");
resp.setStatus(200);
ServletOutputStream out = resp.getOutputStream();
out.print(COMPRESSED_CONTENT);
}
}
public WorkDir testingdir;
@Test
public void testIsGzipByMethod() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
// Configure Gzip Handler
tester.getGzipHandler().setIncludedMethods("POST", "WIBBLE", "HEAD");
// Prepare Server File
int filesize = tester.getOutputBufferSize() * 2;
tester.prepareServerFile("file.txt", filesize);
// Content Servlet
tester.setContentServlet(GetServlet.class);
try
{
tester.start();
HttpTester.Response response;
//These methods have content bodies of the compressed response
tester.assertIsResponseGzipCompressed("POST", "file.txt");
tester.assertIsResponseGzipCompressed("WIBBLE", "file.txt");
//A HEAD request should have similar headers, but no body
response = tester.executeRequest("HEAD", "/context/file.txt", 5, TimeUnit.SECONDS);
assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200));
assertThat("ETag", response.get("ETag"), containsString(CompressedContentFormat.GZIP._etag));
assertThat("Content encoding", response.get("Content-Encoding"), containsString("gzip"));
assertNull(response.get("Content-Length"), "Content length");
response = tester.executeRequest("GET", "/context/file.txt", 5, TimeUnit.SECONDS);
assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200));
assertThat("Content-Encoding", response.get("Content-Encoding"), not(containsString(compressionType)));
String content = tester.readResponse(response);
assertThat("Response content size", content.length(), is(filesize));
String expectedContent = IO.readToString(testingdir.getPathFile("file.txt").toFile());
assertThat("Response content", content, is(expectedContent));
}
finally
{
tester.stop();
}
}
@SuppressWarnings("serial")
public static class GetServlet extends DefaultServlet
{
public GetServlet()
{
super();
}
@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException
{
String uri = req.getRequestURI();
if (uri.endsWith(".deferred"))
{
// System.err.println("type for "+uri.substring(0,uri.length()-9)+" is "+getServletContext().getMimeType(uri.substring(0,uri.length()-9)));
resp.setContentType(getServletContext().getMimeType(uri.substring(0, uri.length() - 9)));
}
doGet(req, resp);
}
}
@Test
public void testIsGzipCompressedEmpty() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
// Configure Gzip Handler
tester.getGzipHandler().addIncludedMimeTypes("text/plain");
// Prepare server file
tester.prepareServerFile("empty.txt", 0);
// Set content servlet
tester.setContentServlet(DefaultServlet.class);
try
{
tester.start();
HttpTester.Response response;
response = tester.executeRequest("GET", "/context/empty.txt", 5, TimeUnit.SECONDS);
assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200));
assertThat("Content-Encoding", response.get("Content-Encoding"), not(containsString(compressionType)));
String content = tester.readResponse(response);
assertThat("Response content size", content.length(), is(0));
String expectedContent = IO.readToString(testingdir.getPathFile("empty.txt").toFile());
assertThat("Response content", content, is(expectedContent));
}
finally
{
tester.stop();
}
}
@Test
public void testIsGzipCompressedTiny() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
int filesize = tester.getOutputBufferSize() / 4;
tester.prepareServerFile("file.txt", filesize);
tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
try
{
tester.start();
HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET", "file.txt");
assertEquals("Accept-Encoding, User-Agent", http.get("Vary"));
}
finally
{
tester.stop();
}
}
@Test
public void testIsGzipCompressedLarge() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
int filesize = tester.getOutputBufferSize() * 4;
tester.prepareServerFile("file.txt", filesize);
tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
tester.getGzipHandler().setExcludedAgentPatterns();
try
{
tester.start();
HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET", "file.txt");
assertEquals("Accept-Encoding", http.get("Vary"));
}
finally
{
tester.stop();
}
}
@Test
public void testGzipedIfModified() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
int filesize = tester.getOutputBufferSize() * 4;
tester.prepareServerFile("file.txt", filesize);
tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
try
{
tester.start();
HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET", "file.txt", TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - 4000);
assertEquals("Accept-Encoding, User-Agent", http.get("Vary"));
}
finally
{
tester.stop();
}
}
@Test
public void testGzippedIfSVG() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
tester.copyTestServerFile("test.svg");
tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
tester.getGzipHandler().addIncludedMimeTypes("image/svg+xml");
try
{
tester.start();
HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET", "test.svg", TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - 4000);
assertEquals("Accept-Encoding, User-Agent", http.get("Vary"));
}
finally
{
tester.stop();
}
}
@Test
public void testNotGzipedIfNotModified() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
int filesize = tester.getOutputBufferSize() * 4;
tester.prepareServerFile("file.txt", filesize);
tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
try
{
tester.start();
tester.assertIsResponseNotModified("GET", "file.txt", System.currentTimeMillis() + 4000);
}
finally
{
tester.stop();
}
}
@Test
public void testIsNotGzipCompressedWithZeroQ() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType + "; q=0");
// Configure Gzip Handler
tester.getGzipHandler().addIncludedMimeTypes("text/plain");
// Prepare server file
int filesize = tester.getOutputBufferSize() / 4;
tester.prepareServerFile("file.txt", filesize);
// Add content servlet
tester.setContentServlet(DefaultServlet.class);
try
{
tester.start();
HttpTester.Response http = assertIsResponseNotGzipCompressed(tester, "GET", "file.txt", filesize, HttpStatus.OK_200);
assertThat("Response[Vary]", http.get("Vary"), containsString("Accept-Encoding"));
}
finally
{
tester.stop();
}
}
@Test
public void testIsGzipCompressedWithQ() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType, "something;q=0.1," + compressionType + ";q=0.5");
int filesize = tester.getOutputBufferSize() / 4;
tester.prepareServerFile("file.txt", filesize);
tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
tester.getGzipHandler().setExcludedAgentPatterns();
try
{
tester.start();
HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET", "file.txt");
assertEquals("Accept-Encoding", http.get("Vary"));
}
finally
{
tester.stop();
}
}
@Test
public void testIsNotGzipCompressedByContentType() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
// Prepare server file
int filesize = tester.getOutputBufferSize() * 4;
tester.prepareServerFile("file.mp3", filesize);
// Add content servlet
tester.setContentServlet(DefaultServlet.class);
try
{
tester.start();
HttpTester.Response http = assertIsResponseNotGzipCompressed(tester, "GET", "file.mp3", filesize, HttpStatus.OK_200);
assertNull(http.get("Vary"));
}
finally
{
tester.stop();
}
}
@Test
public void testIsNotGzipCompressedByExcludedContentType() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
// Configure Gzip Handler
tester.getGzipHandler().addExcludedMimeTypes("text/plain");
// Prepare server file
int filesize = tester.getOutputBufferSize() * 4;
tester.prepareServerFile("test_quotes.txt", filesize);
// Add content servlet
tester.setContentServlet(DefaultServlet.class);
try
{
tester.start();
HttpTester.Response http = assertIsResponseNotGzipCompressed(tester, "GET", "test_quotes.txt", filesize, HttpStatus.OK_200);
assertNull(http.get("Vary"));
}
finally
{
tester.stop();
}
}
@Test
public void testIsNotGzipCompressedByExcludedContentTypeWithCharset() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
// Configure Gzip Handler
tester.getGzipHandler().addExcludedMimeTypes("text/plain");
// Prepare server file
int filesize = tester.getOutputBufferSize() * 4;
tester.prepareServerFile("test_quotes.txt", filesize);
tester.addMimeType("txt", "text/plain;charset=UTF-8");
// Add content servlet
tester.setContentServlet(DefaultServlet.class);
try
{
tester.start();
HttpTester.Response http = assertIsResponseNotGzipCompressed(tester, "GET", "test_quotes.txt", filesize, HttpStatus.OK_200);
assertNull(http.get("Vary"));
}
finally
{
tester.stop();
}
}
@Test
public void testGzipCompressedByContentTypeWithEncoding() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
tester.setContentServlet(HttpContentTypeWithEncoding.class);
tester.getGzipHandler().setMinGzipSize(16);
tester.getGzipHandler().addIncludedMimeTypes("text/plain");
tester.getGzipHandler().setExcludedAgentPatterns();
try
{
tester.start();
HttpTester.Response http = tester.assertNonStaticContentIsResponseGzipCompressed("GET", "xxx", HttpContentTypeWithEncoding.COMPRESSED_CONTENT);
assertEquals("Accept-Encoding", http.get("Vary"));
}
finally
{
tester.stop();
}
}
@Test
public void testIsNotGzipCompressedByDeferredContentType() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
// Configure Gzip Handler
tester.getGzipHandler().addIncludedMimeTypes("text/plain");
// Prepare server file
int filesize = tester.getOutputBufferSize() * 4;
tester.prepareServerFile("file.mp3.deferred", filesize);
// Add content servlet
tester.setContentServlet(GetServlet.class);
try
{
tester.start();
HttpTester.Response response = assertIsResponseNotGzipCompressed(tester, "GET", "file.mp3.deferred", filesize, HttpStatus.OK_200);
assertThat("Response[Vary]", response.get("Vary"), is(emptyOrNullString()));
}
finally
{
tester.stop();
}
}
@Test
public void testIsNotGzipCompressedHttpStatus() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
// Configure Gzip Handler
tester.getGzipHandler().addIncludedMimeTypes("text/plain");
// Test error code 204
tester.setContentServlet(HttpStatusServlet.class);
try
{
tester.start();
HttpTester.Response response = tester.executeRequest("GET", "/context/", 5, TimeUnit.SECONDS);
assertThat("Response status", response.getStatus(), is(HttpStatus.NO_CONTENT_204));
assertThat("Content-Encoding", response.get("Content-Encoding"), not(containsString(compressionType)));
}
finally
{
tester.stop();
}
}
@Test
public void testIsNotGzipCompressedHttpBadRequestStatus() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
// Configure Gzip Handler
tester.getGzipHandler().addIncludedMimeTypes("text/plain");
// Test error code 400
tester.setContentServlet(HttpErrorServlet.class);
try
{
tester.start();
HttpTester.Response response = tester.executeRequest("GET", "/context/", 5, TimeUnit.SECONDS);
assertThat("Response status", response.getStatus(), is(HttpStatus.BAD_REQUEST_400));
assertThat("Content-Encoding", response.get("Content-Encoding"), not(containsString(compressionType)));
String content = tester.readResponse(response);
assertThat("Response content", content, is("error message"));
}
finally
{
tester.stop();
}
}
@Test
public void testUserAgentExclusion() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
tester.setUserAgent("foo");
// Configure Gzip Handler
tester.getGzipHandler().addIncludedMimeTypes("text/plain");
tester.getGzipHandler().setExcludedAgentPatterns("bar", "foo");
// Prepare server file
int filesize = tester.getOutputBufferSize() * 4;
tester.prepareServerFile("file.txt", filesize);
// Add content servlet
tester.setContentServlet(DefaultServlet.class);
try
{
tester.start();
assertIsResponseNotGzipCompressed(tester, "GET", "file.txt", filesize, HttpStatus.OK_200);
}
finally
{
tester.stop();
}
}
@Test
public void testUserAgentExclusionDefault() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
tester.setContentServlet(DefaultServlet.class);
tester.setUserAgent("Some MSIE 6.0 user-agent");
int filesize = tester.getOutputBufferSize() * 4;
tester.prepareServerFile("file.txt", filesize);
try
{
tester.start();
HttpTester.Response http = assertIsResponseNotGzipCompressed(tester, "GET", "file.txt", filesize, HttpStatus.OK_200);
assertEquals("Accept-Encoding, User-Agent", http.get("Vary"));
}
finally
{
tester.stop();
}
}
@Test
public void testUserAgentExclusionByExcludedAgentPatterns() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
tester.setUserAgent("foo");
// Configure Gzip Handler
tester.getGzipHandler().setExcludedAgentPatterns("bar", "fo.*");
// Prepare server file
int filesize = tester.getOutputBufferSize() * 4;
tester.prepareServerFile("file.txt", filesize);
// Set content servlet
tester.setContentServlet(DefaultServlet.class);
try
{
tester.start();
assertIsResponseNotGzipCompressed(tester, "GET", "file.txt", filesize, HttpStatus.OK_200);
}
finally
{
tester.stop();
}
}
@Test
public void testExcludePaths() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
// Configure Gzip Handler
tester.getGzipHandler().setExcludedPaths("*.txt");
// Prepare server file
int filesize = tester.getOutputBufferSize() * 4;
tester.prepareServerFile("file.txt", filesize);
// Set content servlet
tester.setContentServlet(DefaultServlet.class);
try
{
tester.start();
assertIsResponseNotGzipCompressed(tester, "GET", "file.txt", filesize, HttpStatus.OK_200);
}
finally
{
tester.stop();
}
}
@Test
public void testIncludedPaths() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
// Configure Gzip Handler
tester.getGzipHandler().setExcludedPaths(tester.getContextPath() + "/bad.txt");
tester.getGzipHandler().setIncludedPaths("*.txt");
// Prepare server file
int filesize = tester.getOutputBufferSize() * 4;
tester.prepareServerFile("file.txt", filesize);
tester.prepareServerFile("bad.txt", filesize);
// Set content servlet
tester.setContentServlet(DefaultServlet.class);
try
{
tester.start();
tester.assertIsResponseGzipCompressed("GET", "file.txt");
}
finally
{
tester.stop();
}
try
{
tester.start();
assertIsResponseNotGzipCompressed(tester, "GET", "bad.txt", filesize, HttpStatus.OK_200);
}
finally
{
tester.stop();
}
}
public HttpTester.Response assertIsResponseNotGzipCompressed(GzipTester tester, String method, String filename, int expectedFilesize, int status)
throws Exception
{
HttpTester.Response response = tester.executeRequest(method, "/context/" + filename, 5, TimeUnit.SECONDS);
assertThat("Response status", response.getStatus(), is(status));
assertThat("Content-Encoding", response.get("Content-Encoding"), not(containsString(compressionType)));
assertResponseContent(tester, response, status, filename, expectedFilesize);
return response;
}
private void assertResponseContent(GzipTester tester, HttpTester.Response response, int status, String filename, int expectedFilesize) throws IOException,
UnsupportedEncodingException
{
if (expectedFilesize >= 0)
{
assertThat("filename", filename, notNullValue());
assertThat("Response contentBytes.length", response.getContentBytes().length, is(expectedFilesize));
String contentLength = response.get("Content-Length");
if (StringUtil.isNotBlank(contentLength))
{
assertThat("Content-Length", response.get("Content-Length"), is(Integer.toString(expectedFilesize)));
}
if (status >= 200 && status < 300)
{
assertThat("ETag", response.get("ETAG"), startsWith("W/"));
}
File serverFile = testingdir.getPathFile(filename).toFile();
String expectedResponse = IO.readToString(serverFile);
String actual = tester.readResponse(response);
assertEquals(expectedResponse, actual, "Expected response equals actual response");
}
}
@Test
public void testIsNotGzipCompressedSVGZ() throws Exception
{
GzipTester tester = new GzipTester(testingdir.getEmptyPathDir(), compressionType);
tester.setContentServlet(DefaultServlet.class);
tester.copyTestServerFile("test.svgz");
try
{
tester.start();
tester.assertIsResponseNotGzipFiltered("test.svgz", "test.svgz.sha1", "image/svg+xml", "gzip");
}
finally
{
tester.stop();
}
}
}

View File

@ -0,0 +1,146 @@
//
// ========================================================================
// 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.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.tools.HttpTester;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.Sha1Sum;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.PathResource;
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;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
/**
* Tests {@link GzipHandler} in combination with {@link DefaultServlet} for ability to configure {@link GzipHandler} to
* ignore recompress situations from upstream.
*/
public class GzipHandlerNoReCompressTest extends AbstractGzipTest
{
public static Stream<Arguments> scenarios()
{
return Stream.of(
Arguments.of("test_quotes.gz", "application/gzip"),
Arguments.of("test_quotes.br", "application/brotli"),
Arguments.of("test_quotes.bz2", "application/bzip2"),
Arguments.of("test_quotes.zip", "application/zip"),
Arguments.of("test_quotes.rar", "application/x-rar-compressed"),
// Some images (common first)
Arguments.of("jetty_logo.png", "image/png"),
Arguments.of("jetty_logo.gif", "image/gif"),
Arguments.of("jetty_logo.jpeg", "image/jpeg"),
Arguments.of("jetty_logo.jpg", "image/jpeg"),
// Lesser encountered images (usually found being requested from non-browser clients)
Arguments.of("jetty_logo.bmp", "image/bmp"),
Arguments.of("jetty_logo.tif", "image/tiff"),
Arguments.of("jetty_logo.tiff", "image/tiff"),
Arguments.of("jetty_logo.xcf", "image/xcf"),
Arguments.of("jetty_logo.jp2", "image/jpeg2000")
);
}
private Server server;
@AfterEach
public void stopServer()
{
LifeCycle.stop(server);
}
@ParameterizedTest
@MethodSource("scenarios")
public void testNotGzipAlreadyCompressed(String fileName, String expectedContentType) 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));
servletContextHandler.addServlet(TestStaticMimeTypeServlet.class, "/*");
servletContextHandler.insertHandler(gzipHandler);
server.setHandler(servletContextHandler);
// Prepare Server File
Path testResource = MavenTestingUtils.getTestResourcePath(fileName);
Path file = contextDir.resolve(fileName);
IO.copy(testResource.toFile(), file.toFile());
String expectedSha1Sum = Sha1Sum.loadSha1(MavenTestingUtils.getTestResourceFile(fileName + ".sha1"));
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/" + fileName);
// 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 Headers check
assertThat("Response[Content-Type]", response.get("Content-Type"), is(expectedContentType));
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));
}
}

View File

@ -0,0 +1,226 @@
//
// ========================================================================
// 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.ByteBuffer;
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.HttpStatus;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.tools.HttpTester;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.component.LifeCycle;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
public class GzipHandlerTest extends AbstractGzipTest
{
private Server server;
@AfterEach
public void stopServer()
{
LifeCycle.stop(server);
}
@Test
public void testGzipCompressedByContentTypeWithEncoding() throws Exception
{
GzipHandler gzipHandler = new GzipHandler();
gzipHandler.setMinGzipSize(32);
gzipHandler.addIncludedMimeTypes("text/plain");
gzipHandler.setExcludedAgentPatterns();
server = new Server();
LocalConnector localConnector = new LocalConnector(server);
server.addConnector(localConnector);
ServletContextHandler contextHandler = new ServletContextHandler();
contextHandler.setContextPath("/context");
contextHandler.addServlet(HttpContentTypeWithEncodingServlet.class, "/*");
gzipHandler.setHandler(contextHandler);
server.setHandler(gzipHandler);
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/xxx");
// 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"));
// Response Content checks
UncompressedMetadata metadata = parseResponseContent(response);
assertThat("Response[Content] raw length vs uncompressed length", metadata.contentLength, not(is(metadata.uncompressedSize)));
assertThat("(Uncompressed) Content", metadata.getContentUTF8(), is(HttpContentTypeWithEncodingServlet.CONTENT));
}
public static class HttpContentTypeWithEncodingServlet extends HttpServlet
{
public static final String CONTENT = "<html><head></head><body><h1>COMPRESSIBLE CONTENT</h1>" +
"<p>" +
"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. <br/>" +
"How now brown cow. <br/>" +
"The quick brown fox jumped over the lazy dog. <br/>" +
"A woman needs a man like a fish needs a bicycle!" +
"</p>" +
"</body></html>";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setContentType("text/plain;charset=UTF8");
resp.setStatus(200);
ServletOutputStream out = resp.getOutputStream();
out.print(CONTENT);
}
}
@Test
public void testIsNotGzipCompressedHttpStatus() throws Exception
{
GzipHandler gzipHandler = new GzipHandler();
gzipHandler.addIncludedMimeTypes("text/plain");
server = new Server();
LocalConnector localConnector = new LocalConnector(server);
server.addConnector(localConnector);
ServletContextHandler contextHandler = new ServletContextHandler();
contextHandler.setContextPath("/context");
contextHandler.addServlet(HttpStatusServlet.class, "/*");
gzipHandler.setHandler(contextHandler);
server.setHandler(gzipHandler);
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/xxx");
// 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.NO_CONTENT_204));
// Response Content-Encoding check
assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), not(containsString("gzip")));
}
public static class HttpStatusServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
resp.setHeader("ETag", "W/\"204\"");
}
}
@Test
public void testIsNotGzipCompressedHttpBadRequestStatus() throws Exception
{
GzipHandler gzipHandler = new GzipHandler();
gzipHandler.addIncludedMimeTypes("text/plain");
server = new Server();
LocalConnector localConnector = new LocalConnector(server);
server.addConnector(localConnector);
ServletContextHandler contextHandler = new ServletContextHandler();
contextHandler.setContextPath("/context");
contextHandler.addServlet(HttpErrorServlet.class, "/*");
gzipHandler.setHandler(contextHandler);
server.setHandler(gzipHandler);
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/xxx");
// 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.BAD_REQUEST_400));
// Response Content-Encoding check
assertThat("Response[Content-Encoding]", response.get("Content-Encoding"), not(containsString("gzip")));
assertThat("Response Content", response.getContent(), is("error message"));
}
public static class HttpErrorServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.getOutputStream().write("error message".getBytes());
resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}
}
}

View File

@ -1,635 +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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.file.Path;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import javax.servlet.DispatcherType;
import javax.servlet.Servlet;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.DateGenerator;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.tools.HttpTester;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.ServletTester;
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.toolchain.test.Sha1Sum;
import org.hamcrest.Matchers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyOrNullString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class GzipTester
{
private static final Logger LOG = LoggerFactory.getLogger(GzipTester.class);
public static class ContentMetadata
{
public final long size;
public final String sha1;
public ContentMetadata(long size, String sha1checksum)
{
this.size = size;
this.sha1 = sha1checksum;
}
}
private String encoding = "ISO8859_1";
private String userAgent = null;
private final GzipHandler gzipHandler = new GzipHandler();
private final ServletTester tester = new ServletTester("/context");
private Path testdir;
private String accept;
private String compressionType;
public GzipTester(Path testingdir, String compressionType)
{
this(testingdir, compressionType, compressionType);
}
public GzipTester(Path testingdir, String compressionType, String accept)
{
this.testdir = testingdir;
this.compressionType = compressionType;
this.accept = accept;
this.tester.getServer().insertHandler(gzipHandler);
}
public String getContextPath()
{
return tester.getContextPath();
}
public GzipHandler getGzipHandler()
{
return gzipHandler;
}
public int getOutputBufferSize()
{
return tester.getConnector().getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration().getOutputBufferSize();
}
public ContentMetadata getResponseMetadata(HttpTester.Response response) throws Exception
{
long size = response.getContentBytes().length;
String contentEncoding = response.get("Content-Encoding");
ByteArrayInputStream bais = null;
InputStream in = null;
DigestOutputStream digester = null;
ByteArrayOutputStream uncompressedStream = null;
try
{
MessageDigest digest = MessageDigest.getInstance("SHA1");
bais = new ByteArrayInputStream(response.getContentBytes());
if (contentEncoding == null)
{
LOG.debug("No response content-encoding");
in = new PassThruInputStream(bais);
}
else if (contentEncoding.contains(GzipHandler.GZIP))
{
in = new GZIPInputStream(bais);
}
else if (contentEncoding.contains(GzipHandler.DEFLATE))
{
in = new InflaterInputStream(bais, new Inflater(true));
}
else
{
assertThat("Unexpected response content-encoding", contentEncoding, is(emptyOrNullString()));
}
uncompressedStream = new ByteArrayOutputStream((int)size);
digester = new DigestOutputStream(uncompressedStream, digest);
IO.copy(in, digester);
byte[] output = uncompressedStream.toByteArray();
String actualSha1Sum = Hex.asHex(digest.digest());
return new ContentMetadata(output.length, actualSha1Sum);
}
finally
{
IO.close(digester);
IO.close(in);
IO.close(bais);
IO.close(uncompressedStream);
}
}
public HttpTester.Response assertIsResponseGzipCompressed(String method, String filename) throws Exception
{
return assertIsResponseGzipCompressed(method, filename, filename, -1);
}
public HttpTester.Response assertIsResponseGzipCompressed(String method, String filename, long ifmodifiedsince) throws Exception
{
return assertIsResponseGzipCompressed(method, filename, filename, ifmodifiedsince);
}
public HttpTester.Response assertIsResponseGzipCompressed(String method, String requestedFilename, String serverFilename) throws Exception
{
return assertIsResponseGzipCompressed(method, requestedFilename, serverFilename, -1);
}
public HttpTester.Response assertNonStaticContentIsResponseGzipCompressed(String method, String path, String expected) throws Exception
{
HttpTester.Request request = HttpTester.newRequest();
HttpTester.Response response;
request.setMethod(method);
request.setVersion("HTTP/1.0");
request.setHeader("Host", "tester");
request.setHeader("Accept-Encoding", accept);
if (this.userAgent != null)
request.setHeader("User-Agent", this.userAgent);
request.setURI("/context/" + path);
// Issue the request
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
int qindex = compressionType.indexOf(";");
if (qindex < 0)
assertThat("Response.header[Content-Encoding]", response.get("Content-Encoding"), containsString(compressionType));
else
assertThat("Response.header[Content-Encoding]", response.get("Content-Encoding"), containsString(compressionType.substring(0, qindex)));
ByteArrayInputStream bais = null;
InputStream in = null;
ByteArrayOutputStream out = null;
String actual = null;
try
{
bais = new ByteArrayInputStream(response.getContentBytes());
if (compressionType.startsWith(GzipHandler.GZIP))
{
in = new GZIPInputStream(bais);
}
else if (compressionType.startsWith(GzipHandler.DEFLATE))
{
in = new InflaterInputStream(bais, new Inflater(true));
}
out = new ByteArrayOutputStream();
IO.copy(in, out);
actual = out.toString(encoding);
assertThat("Uncompressed contents", actual, equalTo(expected));
}
finally
{
IO.close(out);
IO.close(in);
IO.close(bais);
}
return response;
}
public HttpTester.Response assertIsResponseGzipCompressed(String method, String requestedFilename, String serverFilename, long ifmodifiedsince)
throws Exception
{
HttpTester.Request request = HttpTester.newRequest();
HttpTester.Response response;
request.setMethod(method);
request.setVersion("HTTP/1.0");
request.setHeader("Host", "tester");
request.setHeader("Accept-Encoding", compressionType);
if (ifmodifiedsince > 0)
request.setHeader(HttpHeader.IF_MODIFIED_SINCE.asString(), DateGenerator.formatDate(ifmodifiedsince));
if (this.userAgent != null)
request.setHeader("User-Agent", this.userAgent);
request.setURI("/context/" + requestedFilename);
// Issue the request
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
// Assert the response headers
// assertThat("Response.status",response.getStatus(),is(HttpServletResponse.SC_OK));
// Response headers should have either a Transfer-Encoding indicating chunked OR a Content-Length
/*
* TODO need to check for the 3rd option of EOF content. To do this properly you might need to look at both HTTP/1.1 and HTTP/1.0 requests String
* contentLength = response.get("Content-Length"); String transferEncoding = response.get("Transfer-Encoding");
*
* boolean chunked = (transferEncoding != null) && (transferEncoding.indexOf("chunk") >= 0); if(!chunked) {
* assertThat("Response.header[Content-Length]",contentLength,notNullValue()); } else {
* assertThat("Response.header[Transfer-Encoding]",transferEncoding,notNullValue()); }
*/
int qindex = compressionType.indexOf(";");
if (qindex < 0)
assertThat("Response.header[Content-Encoding]", response.get("Content-Encoding"), containsString(compressionType));
else
assertThat("Response.header[Content-Encoding]", response.get("Content-Encoding"), containsString(compressionType.substring(0, qindex)));
assertThat(response.get("ETag"), Matchers.startsWith("W/"));
// Assert that the decompressed contents are what we expect.
File serverFile = testdir.resolve(FS.separators(serverFilename)).toFile();
String expected = IO.readToString(serverFile);
String actual = null;
ByteArrayInputStream bais = null;
InputStream in = null;
ByteArrayOutputStream out = null;
try
{
bais = new ByteArrayInputStream(response.getContentBytes());
if (compressionType.startsWith(GzipHandler.GZIP))
{
in = new GZIPInputStream(bais);
}
else if (compressionType.startsWith(GzipHandler.DEFLATE))
{
in = new InflaterInputStream(bais, new Inflater(true));
}
out = new ByteArrayOutputStream();
IO.copy(in, out);
actual = out.toString(encoding);
assertThat("Uncompressed contents", actual, equalTo(expected));
}
finally
{
IO.close(out);
IO.close(in);
IO.close(bais);
}
return response;
}
public HttpTester.Response assertIsResponseNotModified(String method, String requestedFilename, long ifmodifiedsince) throws Exception
{
HttpTester.Request request = HttpTester.newRequest();
HttpTester.Response response;
request.setMethod(method);
request.setVersion("HTTP/1.0");
request.setHeader("Host", "tester");
request.setHeader("Accept-Encoding", compressionType);
if (ifmodifiedsince > 0)
request.setHeader(HttpHeader.IF_MODIFIED_SINCE.asString(), DateGenerator.formatDate(ifmodifiedsince));
if (this.userAgent != null)
request.setHeader("User-Agent", this.userAgent);
request.setURI("/context/" + requestedFilename);
// Issue the request
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
assertThat(response.getStatus(), Matchers.equalTo(304));
assertThat(response.get("ETag"), Matchers.startsWith("W/"));
return response;
}
/**
* Makes sure that the response contains an unfiltered file contents.
* <p>
* This is used to test exclusions and passthroughs in the GzipHandler.
* <p>
* 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.
* <p>
* This is used to test exclusions and passthroughs in the GzipHandler.
* <p>
* 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<String> names = message.getFieldNames();
while (names.hasMoreElements())
{
String name = names.nextElement();
String value = message.get(name);
LOG.debug("dumpHeaders: {} = {}", name, value);
}
}
public HttpTester.Response executeRequest(String method, String path, int idleFor, TimeUnit idleUnit) throws Exception
{
HttpTester.Request request = HttpTester.newRequest();
request.setMethod(method);
request.setVersion("HTTP/1.1");
request.setHeader("Host", "tester");
request.setHeader("Accept-Encoding", accept);
request.setHeader("Connection", "close");
if (this.userAgent != null)
{
request.setHeader("User-Agent", this.userAgent);
}
request.setURI(path);
// Issue the request
return HttpTester.parseResponse(tester.getResponses(request.generate(), idleFor, idleUnit));
}
public String readResponse(HttpTester.Response response) throws IOException, UnsupportedEncodingException
{
String actual = null;
InputStream in = null;
ByteArrayOutputStream out = null;
try
{
byte[] content = response.getContentBytes();
if (content != null)
actual = new String(response.getContentBytes(), encoding);
else
actual = "";
}
finally
{
IO.close(out);
IO.close(in);
}
return actual;
}
/**
* Generate string content of arbitrary length.
*
* @param length the length of the string to generate.
* @return the string content.
*/
public String 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();
}
public String getEncoding()
{
return encoding;
}
/**
* Create a file on the server resource path of a specified filename and size.
*
* @param filename the filename to create
* @param filesize the file size to create (Note: this isn't suitable for creating large multi-megabyte files)
* @return the prepared file
* @throws IOException if unable to create file
*/
public File prepareServerFile(String filename, int filesize) throws IOException
{
File dir = testdir.toFile();
File testFile = new File(dir, filename);
// Make sure we have a uniq filename (to work around windows File.delete bug)
int i = 0;
while (testFile.exists())
{
testFile = new File(dir, (i++) + "-" + filename);
}
FileOutputStream fos = null;
ByteArrayInputStream in = null;
try
{
fos = new FileOutputStream(testFile, false);
in = new ByteArrayInputStream(generateContent(filesize).getBytes(encoding));
IO.copy(in, fos);
return testFile;
}
finally
{
IO.close(in);
IO.close(fos);
}
}
/**
* Copy a src/test/resource file into the server tree for eventual serving.
*
* @param filename the filename to look for in src/test/resources
* @throws IOException if unable to copy file
*/
public void copyTestServerFile(String filename) throws IOException
{
File srcFile = MavenTestingUtils.getTestResourceFile(filename);
File testFile = testdir.resolve(FS.separators(filename)).toFile();
IO.copy(srcFile, testFile);
}
/**
* Set the servlet that provides content for the GzipHandler in being tested.
*
* @param servletClass the servlet that will provide content.
* @throws IOException if unable to set content servlet
*/
public void setContentServlet(Class<? extends Servlet> servletClass) throws IOException
{
String resourceBase = testdir.toString();
tester.setContextPath("/context");
tester.setResourceBase(resourceBase);
ServletHolder servletHolder = tester.addServlet(servletClass, "/");
servletHolder.setInitParameter("baseDir", resourceBase);
servletHolder.setInitParameter("etags", "true");
}
public void setEncoding(String encoding)
{
this.encoding = encoding;
}
public void setUserAgent(String ua)
{
this.userAgent = ua;
}
public void addMimeType(String extension, String mimetype)
{
this.tester.getContext().getMimeTypes().addMimeMapping(extension, mimetype);
}
/**
* Add an arbitrary filter to the test case.
*
* @param holder the filter to add
* @param pathSpec the path spec for this filter
* @param dispatches the set of {@link DispatcherType} to associate with this filter
* @throws IOException if unable to add filter
*/
public void addFilter(FilterHolder holder, String pathSpec, EnumSet<DispatcherType> dispatches) throws IOException
{
tester.addFilter(holder, pathSpec, dispatches);
}
public void start() throws Exception
{
assertThat("No servlet defined yet. Did you use #setContentServlet()?", tester, notNullValue());
if (LOG.isDebugEnabled())
{
tester.dumpStdErr();
}
tester.start();
}
public void stop()
{
// NOTE: Do not cleanup the workDir. Failures can't be diagnosed if you do that.
// IO.delete(workDir.getDir()):
try
{
tester.stop();
}
catch (Exception e)
{
// Don't toss this out into Junit as this would be the last exception
// that junit will report as being the cause of the test failure.
// when in reality, the earlier setup issue is the real cause.
e.printStackTrace(System.err);
}
}
}

View File

@ -1,76 +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;
public final class Hex
{
private static final char[] hexcodes = "0123456789abcdef".toCharArray();
public static byte[] asByteArray(String id, int size)
{
if ((id.length() < 0) || (id.length() > (size * 2)))
{
throw new IllegalArgumentException(String.format("Invalid ID length of <%d> expected range of <0> to <%d>", id.length(), (size * 2)));
}
byte[] buf = new byte[size];
byte hex;
int len = id.length();
int idx = (int)Math.floor(((size * 2) - (double)len) / 2);
int i = 0;
if ((len % 2) != 0)
{ // deal with odd numbered chars
i -= 1;
}
for (; i < len; i++)
{
hex = 0;
if (i >= 0)
{
hex = (byte)(Character.digit(id.charAt(i), 16) << 4);
}
i++;
hex += (byte)(Character.digit(id.charAt(i), 16));
buf[idx] = hex;
idx++;
}
return buf;
}
public static String asHex(byte[] buf)
{
int len = buf.length;
char[] out = new char[len * 2];
for (int i = 0; i < len; i++)
{
out[i * 2] = hexcodes[(buf[i] & 0xF0) >> 4];
out[(i * 2) + 1] = hexcodes[(buf[i] & 0x0F)];
}
return String.valueOf(out);
}
private Hex()
{
/* prevent instantiation */
}
}

View File

@ -44,12 +44,12 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler;
* @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
*/
@SuppressWarnings("serial")
public class TestServletBufferTypeLengthWrite extends TestDirContentServlet
public class HttpOutputWriteFileContentServlet 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();

View File

@ -1,95 +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 javax.servlet.Servlet;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
/**
* Perform specific tests on the IncludableGzipHandler's ability to manage
* minGzipSize initialization parameter.
*
* @see <a href="Eclipse Bug 366106">http://bugs.eclipse.org/366106</a>
*/
@ExtendWith(WorkDirExtension.class)
public class IncludedGzipMinSizeTest
{
public IncludedGzipMinSizeTest()
{
this.compressionType = GzipHandler.GZIP;
}
public WorkDir testdir;
private String compressionType;
private Class<? extends Servlet> testServlet = TestMinGzipSizeServlet.class;
@Test
public void testUnderMinSize() throws Exception
{
GzipTester tester = new GzipTester(testdir.getEmptyPathDir(), compressionType);
tester.setContentServlet(testServlet);
// A valid mime type that we will never use in this test.
// configured here to prevent mimeType==null logic
tester.getGzipHandler().addIncludedMimeTypes("application/soap+xml");
tester.getGzipHandler().setMinGzipSize(2048);
tester.copyTestServerFile("small_script.js");
try
{
tester.start();
tester.assertIsResponseNotGziped("small_script.js",
"small_script.js.sha1",
"text/javascript; charset=utf-8");
}
finally
{
tester.stop();
}
}
@Test
public void testOverMinSize() throws Exception
{
GzipTester tester = new GzipTester(testdir.getEmptyPathDir(), compressionType);
tester.setContentServlet(testServlet);
tester.getGzipHandler().addIncludedMimeTypes("application/soap+xml", "text/javascript", "application/javascript");
tester.getGzipHandler().setMinGzipSize(2048);
tester.copyTestServerFile("big_script.js");
try
{
tester.start();
tester.assertIsResponseGzipCompressed("GET", "big_script.js");
}
finally
{
tester.stop();
}
}
}

View File

@ -1,134 +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.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.tools.HttpTester;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.servlet.ServletTester;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.IO;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ExtendWith(WorkDirExtension.class)
public class IncludedGzipTest
{
public WorkDir testdir;
private static String __content =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. " +
"Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque " +
"habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. " +
"Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam " +
"at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate " +
"velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum. " +
"Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum " +
"eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa " +
"sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam " +
"consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque. " +
"Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse " +
"et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.";
private ServletTester tester;
private String compressionType;
public IncludedGzipTest()
{
this.compressionType = GzipHandler.GZIP;
}
@BeforeEach
public void setUp() throws Exception
{
testdir.ensureEmpty();
File testFile = testdir.getPathFile("file.txt").toFile();
try (OutputStream testOut = new BufferedOutputStream(new FileOutputStream(testFile)))
{
ByteArrayInputStream testIn = new ByteArrayInputStream(__content.getBytes("ISO8859_1"));
IO.copy(testIn, testOut);
}
tester = new ServletTester("/context");
tester.getContext().setResourceBase(testdir.getPath().toString());
tester.getContext().addServlet(org.eclipse.jetty.servlet.DefaultServlet.class, "/");
GzipHandler gzipHandler = new GzipHandler();
gzipHandler.setMinGzipSize(16);
tester.getContext().insertHandler(gzipHandler);
tester.start();
}
@AfterEach
public void tearDown() throws Exception
{
tester.stop();
}
@Test
public void testGzip() throws Exception
{
// generated and parsed test
ByteBuffer request = BufferUtil.toBuffer(
"GET /context/file.txt HTTP/1.0\r\n" +
"Host: tester\r\n" +
"Accept-Encoding: " + compressionType + "\r\n" +
"\r\n");
HttpTester.Response response = HttpTester.parseResponse(tester.getResponses(request));
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
assertEquals(compressionType, response.get("Content-Encoding"));
InputStream testIn = null;
ByteArrayInputStream compressedResponseStream = new ByteArrayInputStream(response.getContentBytes());
if (compressionType.equals(GzipHandler.GZIP))
{
testIn = new GZIPInputStream(compressedResponseStream);
}
else if (compressionType.equals(GzipHandler.DEFLATE))
{
testIn = new InflaterInputStream(compressedResponseStream, new Inflater(true));
}
ByteArrayOutputStream testOut = new ByteArrayOutputStream();
IO.copy(testIn, testOut);
assertEquals(__content, testOut.toString("ISO8859_1"));
}
}

View File

@ -1,73 +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.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import org.eclipse.jetty.toolchain.test.PathAssert;
import org.eclipse.jetty.util.IO;
@SuppressWarnings("serial")
public class TestDirContentServlet extends HttpServlet
{
private File basedir;
@Override
public void init(ServletConfig config) throws ServletException
{
basedir = new File(config.getInitParameter("baseDir"));
}
public File getTestFile(String filename)
{
File testfile = new File(basedir, filename);
PathAssert.assertFileExists("Content File should exist", testfile);
return testfile;
}
protected byte[] loadContentFileBytes(final String fileName) throws IOException
{
String relPath = fileName;
relPath = relPath.replaceFirst("^/context/", "");
relPath = relPath.replaceFirst("^/", "");
File contentFile = getTestFile(relPath);
FileInputStream in = null;
ByteArrayOutputStream out = null;
try
{
in = new FileInputStream(contentFile);
out = new ByteArrayOutputStream();
IO.copy(in, out);
return out.toByteArray();
}
finally
{
IO.close(out);
IO.close(in);
}
}
}

View File

@ -31,7 +31,7 @@ import org.eclipse.jetty.http.MimeTypes;
* Test servlet for testing against unusual minGzip configurable.
*/
@SuppressWarnings("serial")
public class TestMinGzipSizeServlet extends TestDirContentServlet
public class TestMinGzipSizeServlet extends AbstractFileContentServlet
{
private MimeTypes mimeTypes;

View File

@ -31,7 +31,7 @@ import org.eclipse.jetty.http.MimeTypes;
* Test servlet for testing against unusual MimeTypes and Content-Types.
*/
@SuppressWarnings("serial")
public class TestStaticMimeTypeServlet extends TestDirContentServlet
public class TestStaticMimeTypeServlet extends AbstractFileContentServlet
{
private MimeTypes mimeTypes;
@ -63,7 +63,7 @@ public class TestStaticMimeTypeServlet extends TestDirContentServlet
@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);

View File

@ -1 +0,0 @@
1ccb7a0b85585d0e9bdc3863ad093d4e53a9ea68 test.svg