Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Wilkins2013-04-15 01:06:06 +0000
committerGreg Wilkins2013-04-15 01:06:06 +0000
commit9a26992c8aa2e8a39822cd5590617484d1508c6f (patch)
treebd6edb433862ec462fa46722ab268732dc45fdac
parent70e6655ec5a5b45839fcd6b6bbe7be7427f5e8ef (diff)
downloadorg.eclipse.jetty.project-9a26992c8aa2e8a39822cd5590617484d1508c6f.tar.gz
org.eclipse.jetty.project-9a26992c8aa2e8a39822cd5590617484d1508c6f.tar.xz
org.eclipse.jetty.project-9a26992c8aa2e8a39822cd5590617484d1508c6f.zip
402885 reuse Deflaters in GzipFilter
-rw-r--r--jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java122
-rw-r--r--jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java32
-rw-r--r--jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipOutputStream.java70
-rw-r--r--jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PipelineHelper.java4
4 files changed, 155 insertions, 73 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 bd5a21b911..03752cb7f1 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
@@ -26,26 +26,22 @@ import java.util.StringTokenizer;
import java.util.regex.Pattern;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
-import java.util.zip.GZIPOutputStream;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
-import javax.servlet.ServletResponseWrapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpServletResponseWrapper;
-import org.eclipse.jetty.continuation.Continuation;
-import org.eclipse.jetty.continuation.ContinuationListener;
-import org.eclipse.jetty.continuation.ContinuationSupport;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.servlets.gzip.AbstractCompressedStream;
import org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper;
-import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.servlets.gzip.GzipOutputStream;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@@ -129,6 +125,9 @@ public class GzipFilter extends UserAgentFilter
protected int _minGzipSize=256;
protected int _deflateCompressionLevel=Deflater.DEFAULT_COMPRESSION;
protected boolean _deflateNoWrap = true;
+
+ // non-static, as other GzipFilter instances may have different configurations
+ protected final ThreadLocal<Deflater> _deflater = new ThreadLocal<Deflater>();
protected final Set<String> _methods=new HashSet<String>();
protected Set<String> _excludedAgents;
@@ -296,10 +295,10 @@ public class GzipFilter extends UserAgentFilter
}
finally
{
- Continuation continuation = ContinuationSupport.getContinuation(request);
- if (continuation.isSuspended() && continuation.isResponseWrapped())
+ if (request.isAsyncStarted())
{
- continuation.addContinuationListener(new ContinuationListenerWaitingForWrappedResponseToFinish(wrappedResponse));
+
+ request.getAsyncContext().addListener(new FinishOnCompleteListener(wrappedResponse));
}
else if (exceptional && !response.isCommitted())
{
@@ -403,64 +402,55 @@ public class GzipFilter extends UserAgentFilter
protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, final String compressionType)
{
CompressedResponseWrapper wrappedResponse = null;
- if (compressionType==null)
+ wrappedResponse = new CompressedResponseWrapper(request,response)
{
- wrappedResponse = new CompressedResponseWrapper(request,response)
+ @Override
+ protected AbstractCompressedStream newCompressedStream(HttpServletRequest request, HttpServletResponse response) throws IOException
{
- @Override
- protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
+ return new AbstractCompressedStream(compressionType,request,this,_vary)
{
- return new AbstractCompressedStream(null,request,this,_vary)
+ private Deflater _allocatedDeflater;
+
+ @Override
+ protected DeflaterOutputStream createStream() throws IOException
{
- @Override
- protected DeflaterOutputStream createStream() throws IOException
+ if (compressionType == null)
{
return null;
}
- };
- }
- };
- }
- else if (compressionType.equals(GZIP))
- {
- wrappedResponse = new CompressedResponseWrapper(request,response)
- {
- @Override
- protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
- {
- return new AbstractCompressedStream(compressionType,request,this,_vary)
- {
- @Override
- protected DeflaterOutputStream createStream() throws IOException
+
+ // acquire deflater instance
+ _allocatedDeflater = _deflater.get();
+ if (_allocatedDeflater==null)
+ _allocatedDeflater = new Deflater(_deflateCompressionLevel,_deflateNoWrap);
+ else
{
- return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
+ _deflater.remove();
+ _allocatedDeflater.reset();
}
- };
- }
- };
- }
- else if (compressionType.equals(DEFLATE))
- {
- wrappedResponse = new CompressedResponseWrapper(request,response)
- {
- @Override
- protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
- {
- return new AbstractCompressedStream(compressionType,request,this,_vary)
+
+ switch (compressionType)
+ {
+ case GZIP:
+ return new GzipOutputStream(_response.getOutputStream(),_allocatedDeflater,_bufferSize);
+ case DEFLATE:
+ return new DeflaterOutputStream(_response.getOutputStream(),_allocatedDeflater,_bufferSize);
+ }
+ throw new IllegalStateException(compressionType + " not supported");
+ }
+
+ @Override
+ public void finish() throws IOException
{
- @Override
- protected DeflaterOutputStream createStream() throws IOException
+ super.finish();
+ if (_allocatedDeflater != null && _deflater.get() == null)
{
- return new DeflaterOutputStream(_response.getOutputStream(),new Deflater(_deflateCompressionLevel,_deflateNoWrap));
+ _deflater.set(_allocatedDeflater);
}
- };
- }
- };
- }
- else
- {
- throw new IllegalStateException(compressionType + " not supported");
- }
+ }
+ };
+ }
+ };
configureWrappedResponse(wrappedResponse);
return wrappedResponse;
}
@@ -472,18 +462,18 @@ public class GzipFilter extends UserAgentFilter
wrappedResponse.setMinCompressSize(_minGzipSize);
}
- private class ContinuationListenerWaitingForWrappedResponseToFinish implements ContinuationListener
+ private class FinishOnCompleteListener implements AsyncListener
{
private CompressedResponseWrapper wrappedResponse;
- public ContinuationListenerWaitingForWrappedResponseToFinish(CompressedResponseWrapper wrappedResponse)
+ public FinishOnCompleteListener(CompressedResponseWrapper wrappedResponse)
{
this.wrappedResponse = wrappedResponse;
}
@Override
- public void onComplete(Continuation continuation)
- {
+ public void onComplete(AsyncEvent event) throws IOException
+ {
try
{
wrappedResponse.finish();
@@ -495,7 +485,17 @@ public class GzipFilter extends UserAgentFilter
}
@Override
- public void onTimeout(Continuation continuation)
+ public void onTimeout(AsyncEvent event) throws IOException
+ {
+ }
+
+ @Override
+ public void onError(AsyncEvent event) throws IOException
+ {
+ }
+
+ @Override
+ public void onStartAsync(AsyncEvent event) throws IOException
{
}
}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java
index 3ea1c2af69..ec125b9429 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java
@@ -29,13 +29,12 @@ import java.util.StringTokenizer;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.GZIPOutputStream;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.eclipse.jetty.continuation.Continuation;
-import org.eclipse.jetty.continuation.ContinuationListener;
-import org.eclipse.jetty.continuation.ContinuationSupport;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper;
@@ -265,12 +264,28 @@ public class GzipHandler extends HandlerWrapper
}
finally
{
- Continuation continuation = ContinuationSupport.getContinuation(request);
- if (continuation.isSuspended() && continuation.isResponseWrapped())
+ if (request.isAsyncStarted())
{
- continuation.addContinuationListener(new ContinuationListener()
+ request.getAsyncContext().addListener(new AsyncListener()
{
- public void onComplete(Continuation continuation)
+
+ @Override
+ public void onTimeout(AsyncEvent event) throws IOException
+ {
+ }
+
+ @Override
+ public void onStartAsync(AsyncEvent event) throws IOException
+ {
+ }
+
+ @Override
+ public void onError(AsyncEvent event) throws IOException
+ {
+ }
+
+ @Override
+ public void onComplete(AsyncEvent event) throws IOException
{
try
{
@@ -281,9 +296,6 @@ public class GzipHandler extends HandlerWrapper
LOG.warn(e);
}
}
-
- public void onTimeout(Continuation continuation)
- {}
});
}
else if (exceptional && !response.isCommitted())
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipOutputStream.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipOutputStream.java
new file mode 100644
index 0000000000..d19bb008b1
--- /dev/null
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipOutputStream.java
@@ -0,0 +1,70 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+package org.eclipse.jetty.servlets.gzip;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.CRC32;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+
+/**
+ * Reimplementation of {@link java.util.zip.GZIPOutputStream} that supports reusing a {@link Deflater} instance.
+ */
+public class GzipOutputStream extends DeflaterOutputStream
+{
+
+ private final static byte[] GZIP_HEADER = new byte[]
+ { (byte)0x1f, (byte)0x8b, Deflater.DEFLATED, 0, 0, 0, 0, 0, 0, 0 };
+
+ private final CRC32 _crc = new CRC32();
+
+ public GzipOutputStream(OutputStream out, Deflater deflater, int size) throws IOException
+ {
+ super(out,deflater,size);
+ out.write(GZIP_HEADER);
+ }
+
+ public synchronized void write(byte[] buf, int off, int len) throws IOException
+ {
+ super.write(buf,off,len);
+ _crc.update(buf,off,len);
+ }
+
+ public void finish() throws IOException
+ {
+ if (!def.finished())
+ {
+ super.finish();
+ byte[] trailer = new byte[8];
+ writeInt((int)_crc.getValue(),trailer,0);
+ writeInt(def.getTotalIn(),trailer,4);
+ out.write(trailer);
+ }
+ }
+
+ private void writeInt(int i, byte[] buf, int offset)
+ {
+ int o = offset;
+ buf[o++] = (byte)(i & 0xFF);
+ buf[o++] = (byte)((i >>> 8) & 0xFF);
+ buf[o++] = (byte)((i >>> 16) & 0xFF);
+ buf[o++] = (byte)((i >>> 24) & 0xFF);
+ }
+
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PipelineHelper.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PipelineHelper.java
index 8e2fea7b56..95f0a23412 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PipelineHelper.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PipelineHelper.java
@@ -219,8 +219,8 @@ public class PipelineHelper
int val = inputStream.read();
try
{
- if (left % 10 == 0)
- Thread.sleep(1);
+ if (left % 1000 == 0)
+ Thread.sleep(10);
}
catch (InterruptedException e)
{

Back to the top