Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Bartel2012-08-30 10:17:59 +0000
committerJan Bartel2012-08-30 10:17:59 +0000
commitb97a7b6193db5f16965eb9c73473521ccd54a467 (patch)
treef5f3e78c7b4586b1cb8d70b2cf313570be1a1a93
parent1cdef414b429f4833fd0f1f63ba9dcc0644d422a (diff)
downloadorg.eclipse.jetty.project-b97a7b6193db5f16965eb9c73473521ccd54a467.tar.gz
org.eclipse.jetty.project-b97a7b6193db5f16965eb9c73473521ccd54a467.tar.xz
org.eclipse.jetty.project-b97a7b6193db5f16965eb9c73473521ccd54a467.zip
388072 GZipFilter incorrectly gzips when Accept-Encoding: gzip; q=0
-rw-r--r--jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java90
-rw-r--r--jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java4
-rw-r--r--jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java68
-rw-r--r--jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java13
4 files changed, 166 insertions, 9 deletions
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java
index 4209fdb57b..78d47cf2e8 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java
@@ -106,6 +106,7 @@ public class GzipFilter extends UserAgentFilter
private static final Logger LOG = Log.getLogger(GzipFilter.class);
public final static String GZIP="gzip";
public final static String DEFLATE="deflate";
+
protected Set<String> _mimeTypes;
protected int _bufferSize=8192;
@@ -116,6 +117,11 @@ public class GzipFilter extends UserAgentFilter
protected Set<Pattern> _excludedAgentPatterns;
protected Set<String> _excludedPaths;
protected Set<Pattern> _excludedPathPatterns;
+
+ private static final int STATE_SEPARATOR = 0;
+ private static final int STATE_Q = 1;
+ private static final int STATE_QVALUE = 2;
+ private static final int STATE_DEFAULT = 3;
/* ------------------------------------------------------------ */
@@ -263,16 +269,90 @@ public class GzipFilter extends UserAgentFilter
{
// TODO, this could be a little more robust.
// prefer gzip over deflate
+ String compression = null;
if (encodingHeader!=null)
{
- if (encodingHeader.toLowerCase().contains(GZIP))
- return GZIP;
- else if (encodingHeader.toLowerCase().contains(DEFLATE))
- return DEFLATE;
+
+ String[] encodings = getEncodings(encodingHeader);
+ if (encodings != null)
+ {
+ for (int i=0; i< encodings.length; i++)
+ {
+ if (encodings[i].toLowerCase().contains(GZIP))
+ {
+ if (isEncodingAcceptable(encodings[i]))
+ {
+ compression = GZIP;
+ break; //prefer Gzip over deflate
+ }
+ }
+
+ if (encodings[i].toLowerCase().contains(DEFLATE))
+ {
+ if (isEncodingAcceptable(encodings[i]))
+ {
+ compression = DEFLATE; //Keep checking in case gzip is acceptable
+ }
+ }
+ }
+ }
}
- return null;
+ return compression;
+ }
+
+
+ private String[] getEncodings (String encodingHeader)
+ {
+ if (encodingHeader == null)
+ return null;
+ return encodingHeader.split(",");
}
+ private boolean isEncodingAcceptable(String encoding)
+ {
+ int state = STATE_DEFAULT;
+ int qvalueIdx = -1;
+ for (int i=0;i<encoding.length();i++)
+ {
+ char c = encoding.charAt(i);
+ switch (state)
+ {
+ case STATE_DEFAULT:
+ {
+ if (';' == c)
+ state = STATE_SEPARATOR;
+ break;
+ }
+ case STATE_SEPARATOR:
+ {
+ if ('q' == c || 'Q' == c)
+ state = STATE_Q;
+ break;
+ }
+ case STATE_Q:
+ {
+ if ('=' == c)
+ state = STATE_QVALUE;
+ break;
+ }
+ case STATE_QVALUE:
+ {
+ if (qvalueIdx < 0 && '0' == c || '1' == c)
+ qvalueIdx = i;
+ break;
+ }
+ }
+ }
+
+ if (qvalueIdx < 0)
+ return true;
+
+ if ("0".equals(encoding.substring(qvalueIdx).trim()))
+ return false;
+ return true;
+ }
+
+
protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, final String compressionType)
{
CompressedResponseWrapper wrappedResponse = null;
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java
index 0cebfd6c78..9cadebba23 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java
@@ -65,6 +65,10 @@ public class GzipFilterDefaultNoRecompressTest
{ "jetty_logo.tiff", "image/tiff", GzipFilter.GZIP },
{ "jetty_logo.xcf", "image/xcf", GzipFilter.GZIP },
{ "jetty_logo.jp2", "image/jpeg2000", GzipFilter.GZIP },
+ //qvalue disables compression
+ { "test_quotes.txt", "text/plain", GzipFilter.GZIP+";q=0"},
+ { "test_quotes.txt", "text/plain", GzipFilter.GZIP+"; q = 0 "},
+
// Same tests again for deflate
// Some already compressed files
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java
index d7489e36e3..04bbe5cc0e 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java
@@ -124,6 +124,52 @@ public class GzipFilterDefaultTest
}
@Test
+ public void testIsGzipCompressedTinyWithQ() throws Exception
+ {
+ GzipTester tester = new GzipTester(testingdir, compressionType+";q=0.5");
+
+ // Test content that is smaller than the buffer.
+ int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE / 4;
+ tester.prepareServerFile("file.txt",filesize);
+
+ FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
+ holder.setInitParameter("mimeTypes","text/plain");
+
+ try
+ {
+ tester.start();
+ tester.assertIsResponseGzipCompressed("file.txt");
+ }
+ finally
+ {
+ tester.stop();
+ }
+ }
+
+ @Test
+ public void testIsGzipCompressedTinyWithBadQ() throws Exception
+ {
+ GzipTester tester = new GzipTester(testingdir, compressionType+";q=");
+
+ // Test content that is smaller than the buffer.
+ int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE / 4;
+ tester.prepareServerFile("file.txt",filesize);
+
+ FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
+ holder.setInitParameter("mimeTypes","text/plain");
+
+ try
+ {
+ tester.start();
+ tester.assertIsResponseGzipCompressed("file.txt");
+ }
+ finally
+ {
+ tester.stop();
+ }
+ }
+
+ @Test
public void testIsGzipCompressedLarge() throws Exception
{
GzipTester tester = new GzipTester(testingdir, compressionType);
@@ -147,6 +193,28 @@ public class GzipFilterDefaultTest
}
@Test
+ public void testIsNotGzipCompressedWithQ() throws Exception
+ {
+ GzipTester tester = new GzipTester(testingdir, compressionType+"; q = 0");
+
+ int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE / 4;
+ tester.prepareServerFile("file.txt",filesize);
+
+ FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
+ holder.setInitParameter("mimeTypes","text/plain");
+
+ try
+ {
+ tester.start();
+ tester.assertIsResponseNotGzipCompressed("file.txt", filesize, HttpStatus.OK_200);
+ }
+ finally
+ {
+ tester.stop();
+ }
+ }
+
+ @Test
public void testIsNotGzipCompressed() throws Exception
{
GzipTester tester = new GzipTester(testingdir, compressionType);
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java
index affd66def6..de3aa98fb3 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java
@@ -100,9 +100,13 @@ public class GzipTester
// Assert the response headers
Assert.assertThat("Response.method",response.getMethod(),nullValue());
-// Assert.assertThat("Response.status",response.getStatus(),is(HttpServletResponse.SC_OK));
+ // Assert.assertThat("Response.status",response.getStatus(),is(HttpServletResponse.SC_OK));
Assert.assertThat("Response.header[Content-Length]",response.getHeader("Content-Length"),notNullValue());
- Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),containsString(compressionType));
+ int qindex = compressionType.indexOf(";");
+ if (qindex < 0)
+ Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),containsString(compressionType));
+ else
+ Assert.assertThat("Response.header[Content-Encoding]", response.getHeader("Content-Encoding"),containsString(compressionType.substring(0,qindex)));
// Assert that the decompressed contents are what we expect.
File serverFile = testdir.getFile(serverFilename);
@@ -115,11 +119,11 @@ public class GzipTester
try
{
bais = new ByteArrayInputStream(response.getContentBytes());
- if (compressionType.equals(GzipFilter.GZIP))
+ if (compressionType.startsWith(GzipFilter.GZIP))
{
in = new GZIPInputStream(bais);
}
- else if (compressionType.equals(GzipFilter.DEFLATE))
+ else if (compressionType.startsWith(GzipFilter.DEFLATE))
{
in = new InflaterInputStream(bais, new Inflater(true));
}
@@ -255,6 +259,7 @@ public class GzipTester
Assert.assertEquals("Expected response equals actual response",expectedResponse,actual);
}
}
+
/**
* Asserts that the request results in a properly structured GzipFilter response, where the content is

Back to the top