402885 reuse Deflaters in GzipFilter
This commit is contained in:
parent
70e6655ec5
commit
9a26992c8a
|
@ -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;
|
||||
|
||||
|
@ -130,6 +126,9 @@ public class GzipFilter extends UserAgentFilter
|
|||
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;
|
||||
protected Set<Pattern> _excludedAgentPatterns;
|
||||
|
@ -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)
|
||||
{
|
||||
@Override
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
return new AbstractCompressedStream(null,request,this,_vary)
|
||||
return new AbstractCompressedStream(compressionType,request,this,_vary)
|
||||
{
|
||||
private Deflater _allocatedDeflater;
|
||||
|
||||
@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
|
||||
{
|
||||
return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
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)
|
||||
{
|
||||
@Override
|
||||
protected DeflaterOutputStream createStream() throws IOException
|
||||
{
|
||||
return new DeflaterOutputStream(_response.getOutputStream(),new Deflater(_deflateCompressionLevel,_deflateNoWrap));
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// acquire deflater instance
|
||||
_allocatedDeflater = _deflater.get();
|
||||
if (_allocatedDeflater==null)
|
||||
_allocatedDeflater = new Deflater(_deflateCompressionLevel,_deflateNoWrap);
|
||||
else
|
||||
{
|
||||
_deflater.remove();
|
||||
_allocatedDeflater.reset();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
super.finish();
|
||||
if (_allocatedDeflater != null && _deflater.get() == null)
|
||||
{
|
||||
_deflater.set(_allocatedDeflater);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
configureWrappedResponse(wrappedResponse);
|
||||
return wrappedResponse;
|
||||
}
|
||||
|
@ -472,17 +462,17 @@ 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
|
||||
{
|
||||
|
@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue