From 8c63ca989b6355fc0a09af8eb9965d177d6e4b9f Mon Sep 17 00:00:00 2001 From: Michael Gorovoy Date: Tue, 21 Jun 2011 02:26:18 +0000 Subject: [PATCH] 302566 GZIP handler for embedded Jetty servers git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@3406 7e9141cc-0065-0410-87d8-b60c137991c4 --- VERSION.txt | 1 + example-jetty-embedded/pom.xml | 11 + .../jetty/embedded}/GzipHandlerTest.java | 5 +- jetty-http/pom.xml | 5 + .../jetty/http/gzip/GzipResponseWrapper.java | 394 +++++++++++++ .../eclipse/jetty/http/gzip/GzipStream.java | 300 ++++++++++ .../jetty/server/handler/GzipHandler.java | 471 ++------------- .../jetty/server/handler/HttpTester.java | 537 ------------------ .../eclipse/jetty/servlets/GzipFilter.java | 481 ++-------------- .../jetty/servlets/IncludableGzipFilter.java | 20 +- .../jetty/servlets/GzipFilterTest.java | 15 +- .../servlets/IncludableGzipFilterTest.java | 115 ++++ 12 files changed, 935 insertions(+), 1420 deletions(-) rename {jetty-server/src/test/java/org/eclipse/jetty/server/handler => example-jetty-embedded/src/test/java/org/eclipse/jetty/embedded}/GzipHandlerTest.java (96%) create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipResponseWrapper.java create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipStream.java delete mode 100644 jetty-server/src/test/java/org/eclipse/jetty/server/handler/HttpTester.java create mode 100644 jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java diff --git a/VERSION.txt b/VERSION.txt index 09117b5bb34..3936ac0d044 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1,5 +1,6 @@ jetty-7.4.3-SNAPSHOT + 295832 ProxyServlet more extensible and configurable + + 302566 GZIP handler for embedded Jetty servers + 347617 Dynamically install/update/remove OSGi bundles discovered in the contexts folder + 347717 start.jar destroys dependent child of --exec + 347898 Close channel on JVM exceptions diff --git a/example-jetty-embedded/pom.xml b/example-jetty-embedded/pom.xml index 588d52ff3df..7a8ea059e5b 100644 --- a/example-jetty-embedded/pom.xml +++ b/example-jetty-embedded/pom.xml @@ -48,5 +48,16 @@ jetty-websocket ${project.version} + + junit + junit + test + + + org.eclipse.jetty + test-jetty-servlet + ${project.version} + test + diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/GzipHandlerTest.java b/example-jetty-embedded/src/test/java/org/eclipse/jetty/embedded/GzipHandlerTest.java similarity index 96% rename from jetty-server/src/test/java/org/eclipse/jetty/server/handler/GzipHandlerTest.java rename to example-jetty-embedded/src/test/java/org/eclipse/jetty/embedded/GzipHandlerTest.java index 5b8abe6a3ed..56122ea150c 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/GzipHandlerTest.java +++ b/example-jetty-embedded/src/test/java/org/eclipse/jetty/embedded/GzipHandlerTest.java @@ -11,7 +11,7 @@ // You may elect to redistribute this code under either of these licenses. // ======================================================================== -package org.eclipse.jetty.server.handler; +package org.eclipse.jetty.embedded; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -32,6 +32,9 @@ import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.GzipHandler; +import org.eclipse.jetty.testing.HttpTester; import org.eclipse.jetty.util.IO; import org.junit.After; import org.junit.Before; diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml index 680e118b679..9b268466e9e 100644 --- a/jetty-http/pom.xml +++ b/jetty-http/pom.xml @@ -17,6 +17,11 @@ jetty-io ${project.version} + + javax.servlet + servlet-api + provided + junit junit diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipResponseWrapper.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipResponseWrapper.java new file mode 100644 index 00000000000..e53f20ee236 --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipResponseWrapper.java @@ -0,0 +1,394 @@ +// ======================================================================== +// Copyright (c) Webtide LLC +// ------------------------------------------------------------------------ +// 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.http.gzip; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.util.Set; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +import org.eclipse.jetty.util.StringUtil; + + +/* ------------------------------------------------------------ */ +/** + */ +public class GzipResponseWrapper extends HttpServletResponseWrapper +{ + private HttpServletRequest _request; + private Set _mimeTypes; + private int _bufferSize=8192; + private int _minGzipSize=256; + + private PrintWriter _writer; + private GzipStream _gzStream; + private long _contentLength=-1; + private boolean _noGzip; + + /** + * Instantiates a new gzip response wrapper. + * + * @param request the request + * @param response the response + */ + public GzipResponseWrapper(HttpServletRequest request, HttpServletResponse response) + { + super(response); + _request=request; + } + + /* ------------------------------------------------------------ */ + /** + * Sets the mime types. + * + * @param mimeTypes the new mime types + */ + public void setMimeTypes(Set mimeTypes) + { + _mimeTypes = mimeTypes; + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.ServletResponseWrapper#setBufferSize(int) + */ + public void setBufferSize(int bufferSize) + { + _bufferSize = bufferSize; + } + + /* ------------------------------------------------------------ */ + /** + * Sets the min gzip size. + * + * @param minGzipSize the new min gzip size + */ + public void setMinGzipSize(int minGzipSize) + { + _minGzipSize = minGzipSize; + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.ServletResponseWrapper#setContentType(java.lang.String) + */ + public void setContentType(String ct) + { + super.setContentType(ct); + + if (ct!=null) + { + int colon=ct.indexOf(";"); + if (colon>0) + ct=ct.substring(0,colon); + } + + if ((_gzStream==null || _gzStream._out==null) && + (_mimeTypes==null && "application/gzip".equalsIgnoreCase(ct) || + _mimeTypes!=null && (ct==null||!_mimeTypes.contains(StringUtil.asciiToLowerCase(ct))))) + { + noGzip(); + } + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.http.HttpServletResponseWrapper#setStatus(int, java.lang.String) + */ + public void setStatus(int sc, String sm) + { + super.setStatus(sc,sm); + if (sc<200||sc>=300) + noGzip(); + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.http.HttpServletResponseWrapper#setStatus(int) + */ + public void setStatus(int sc) + { + super.setStatus(sc); + if (sc<200||sc>=300) + noGzip(); + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.ServletResponseWrapper#setContentLength(int) + */ + public void setContentLength(int length) + { + _contentLength=length; + if (_gzStream!=null) + _gzStream.setContentLength(length); + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.http.HttpServletResponseWrapper#addHeader(java.lang.String, java.lang.String) + */ + public void addHeader(String name, String value) + { + if ("content-length".equalsIgnoreCase(name)) + { + _contentLength=Long.parseLong(value); + if (_gzStream!=null) + _gzStream.setContentLength(_contentLength); + } + else if ("content-type".equalsIgnoreCase(name)) + { + setContentType(value); + } + else if ("content-encoding".equalsIgnoreCase(name)) + { + super.addHeader(name,value); + if (!isCommitted()) + { + noGzip(); + } + } + else + super.addHeader(name,value); + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.http.HttpServletResponseWrapper#setHeader(java.lang.String, java.lang.String) + */ + public void setHeader(String name, String value) + { + if ("content-length".equalsIgnoreCase(name)) + { + _contentLength=Long.parseLong(value); + if (_gzStream!=null) + _gzStream.setContentLength(_contentLength); + } + else if ("content-type".equalsIgnoreCase(name)) + { + setContentType(value); + } + else if ("content-encoding".equalsIgnoreCase(name)) + { + super.setHeader(name,value); + if (!isCommitted()) + { + noGzip(); + } + } + else + super.setHeader(name,value); + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.http.HttpServletResponseWrapper#setIntHeader(java.lang.String, int) + */ + public void setIntHeader(String name, int value) + { + if ("content-length".equalsIgnoreCase(name)) + { + _contentLength=value; + if (_gzStream!=null) + _gzStream.setContentLength(_contentLength); + } + else + super.setIntHeader(name,value); + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.ServletResponseWrapper#flushBuffer() + */ + public void flushBuffer() throws IOException + { + if (_writer!=null) + _writer.flush(); + if (_gzStream!=null) + _gzStream.finish(); + else + getResponse().flushBuffer(); + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.ServletResponseWrapper#reset() + */ + public void reset() + { + super.reset(); + if (_gzStream!=null) + _gzStream.resetBuffer(); + _writer=null; + _gzStream=null; + _noGzip=false; + _contentLength=-1; + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.ServletResponseWrapper#resetBuffer() + */ + public void resetBuffer() + { + super.resetBuffer(); + if (_gzStream!=null) + _gzStream.resetBuffer(); + _writer=null; + _gzStream=null; + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.http.HttpServletResponseWrapper#sendError(int, java.lang.String) + */ + public void sendError(int sc, String msg) throws IOException + { + resetBuffer(); + super.sendError(sc,msg); + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.http.HttpServletResponseWrapper#sendError(int) + */ + public void sendError(int sc) throws IOException + { + resetBuffer(); + super.sendError(sc); + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.http.HttpServletResponseWrapper#sendRedirect(java.lang.String) + */ + public void sendRedirect(String location) throws IOException + { + resetBuffer(); + super.sendRedirect(location); + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.ServletResponseWrapper#getOutputStream() + */ + public ServletOutputStream getOutputStream() throws IOException + { + if (_gzStream==null) + { + if (getResponse().isCommitted() || _noGzip) + return getResponse().getOutputStream(); + + _gzStream=newGzipStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minGzipSize); + } + else if (_writer!=null) + throw new IllegalStateException("getWriter() called"); + + return _gzStream; + } + + /* ------------------------------------------------------------ */ + /** + * @see javax.servlet.ServletResponseWrapper#getWriter() + */ + public PrintWriter getWriter() throws IOException + { + if (_writer==null) + { + if (_gzStream!=null) + throw new IllegalStateException("getOutputStream() called"); + + if (getResponse().isCommitted() || _noGzip) + return getResponse().getWriter(); + + _gzStream=newGzipStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minGzipSize); + _writer=newWriter(_gzStream,getCharacterEncoding()); + } + return _writer; + } + + /* ------------------------------------------------------------ */ + /** + * No gzip. + */ + public void noGzip() + { + _noGzip=true; + if (_gzStream!=null) + { + try + { + _gzStream.doNotGzip(); + } + catch (IOException e) + { + throw new IllegalStateException(e); + } + } + } + + /* ------------------------------------------------------------ */ + /** + * Finish. + * + * @throws IOException Signals that an I/O exception has occurred. + */ + public void finish() throws IOException + { + if (_writer!=null && !_gzStream._closed) + _writer.flush(); + if (_gzStream!=null) + _gzStream.finish(); + } + + /* ------------------------------------------------------------ */ + /** + * Allows derived implementations to replace GzipStream implementation. + * + * @param request the request + * @param response the response + * @param contentLength the content length + * @param bufferSize the buffer size + * @param minGzipSize the min gzip size + * @return the gzip stream + * @throws IOException Signals that an I/O exception has occurred. + */ + protected GzipStream newGzipStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minGzipSize) throws IOException + { + return new GzipStream(request,response,contentLength,bufferSize,minGzipSize); + } + + /* ------------------------------------------------------------ */ + /** + * Allows derived implementations to replace PrintWriter implementation. + * + * @param out the out + * @param encoding the encoding + * @return the prints the writer + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException + { + return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding)); + } +} + diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipStream.java new file mode 100644 index 00000000000..cf44c479b4a --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipStream.java @@ -0,0 +1,300 @@ +// ======================================================================== +// Copyright (c) Webtide LLC +// ------------------------------------------------------------------------ +// 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.http.gzip; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.util.zip.GZIPOutputStream; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.util.ByteArrayOutputStream2; + + +/* ------------------------------------------------------------ */ +/** + */ +public class GzipStream extends ServletOutputStream +{ + protected HttpServletRequest _request; + protected HttpServletResponse _response; + protected OutputStream _out; + protected ByteArrayOutputStream2 _bOut; + protected GZIPOutputStream _gzOut; + protected boolean _closed; + protected int _bufferSize; + protected int _minGzipSize; + protected long _contentLength; + + /** + * Instantiates a new gzip stream. + * + * @param request the request + * @param response the response + * @param contentLength the content length + * @param bufferSize the buffer size + * @param minGzipSize the min gzip size + * @throws IOException Signals that an I/O exception has occurred. + */ + public GzipStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minGzipSize) throws IOException + { + _request=request; + _response=response; + _contentLength=contentLength; + _bufferSize=bufferSize; + _minGzipSize=minGzipSize; + if (minGzipSize==0) + doGzip(); + } + + /** + * Reset buffer. + */ + public void resetBuffer() + { + if (_response.isCommitted()) + throw new IllegalStateException("Committed"); + _closed=false; + _out=null; + _bOut=null; + if (_gzOut!=null) + _response.setHeader("Content-Encoding",null); + _gzOut=null; + } + + /** + * Sets the content length. + * + * @param length the new content length + */ + public void setContentLength(long length) + { + _contentLength=length; + } + + /* ------------------------------------------------------------ */ + /** + * @see java.io.OutputStream#flush() + */ + public void flush() throws IOException + { + if (_out==null || _bOut!=null) + { + if (_contentLength>0 && _contentLength<_minGzipSize) + doNotGzip(); + else + doGzip(); + } + + _out.flush(); + } + + /* ------------------------------------------------------------ */ + /** + * @see java.io.OutputStream#close() + */ + public void close() throws IOException + { + if (_closed) + return; + + if (_request.getAttribute("javax.servlet.include.request_uri")!=null) + flush(); + else + { + if (_bOut!=null) + { + if (_contentLength<0) + _contentLength=_bOut.getCount(); + if (_contentLength<_minGzipSize) + doNotGzip(); + else + doGzip(); + } + else if (_out==null) + { + doNotGzip(); + } + + if (_gzOut!=null) + _gzOut.close(); + else + _out.close(); + _closed=true; + } + } + + /** + * Finish. + * + * @throws IOException Signals that an I/O exception has occurred. + */ + public void finish() throws IOException + { + if (!_closed) + { + if (_out==null || _bOut!=null) + { + if (_contentLength>0 && _contentLength<_minGzipSize) + doNotGzip(); + else + doGzip(); + } + + if (_gzOut!=null && !_closed) + { + _closed=true; + _gzOut.close(); + } + } + } + + /* ------------------------------------------------------------ */ + /** + * @see java.io.OutputStream#write(int) + */ + public void write(int b) throws IOException + { + checkOut(1); + _out.write(b); + } + + /* ------------------------------------------------------------ */ + /** + * @see java.io.OutputStream#write(byte[]) + */ + public void write(byte b[]) throws IOException + { + checkOut(b.length); + _out.write(b); + } + + /* ------------------------------------------------------------ */ + /** + * @see java.io.OutputStream#write(byte[], int, int) + */ + public void write(byte b[], int off, int len) throws IOException + { + checkOut(len); + _out.write(b,off,len); + } + + /** + * Sets the content encoding gzip. + * + * @return true, if successful + */ + protected boolean setContentEncodingGzip() + { + _response.setHeader("Content-Encoding", "gzip"); + return _response.containsHeader("Content-Encoding"); + } + + /** + * Do gzip. + * + * @throws IOException Signals that an I/O exception has occurred. + */ + public void doGzip() throws IOException + { + if (_gzOut==null) + { + if (_response.isCommitted()) + throw new IllegalStateException(); + + if (setContentEncodingGzip()) + { + _out=_gzOut=new GZIPOutputStream(_response.getOutputStream(),_bufferSize); + + if (_bOut!=null) + { + _out.write(_bOut.getBuf(),0,_bOut.getCount()); + _bOut=null; + } + } + else + doNotGzip(); + } + } + + /** + * Do not gzip. + * + * @throws IOException Signals that an I/O exception has occurred. + */ + public void doNotGzip() throws IOException + { + if (_gzOut!=null) + throw new IllegalStateException(); + if (_out==null || _bOut!=null ) + { + _out=_response.getOutputStream(); + if (_contentLength>=0) + { + if(_contentLength=0 && _contentLength<_minGzipSize)) + doNotGzip(); + else if (length>_minGzipSize) + doGzip(); + else + _out=_bOut=new ByteArrayOutputStream2(_bufferSize); + } + else if (_bOut!=null) + { + if (_response.isCommitted() || (_contentLength>=0 && _contentLength<_minGzipSize)) + doNotGzip(); + else if (length>=(_bOut.getBuf().length -_bOut.getCount())) + doGzip(); + } + } + + /** + * Allows derived implementations to replace PrintWriter implementation. + */ + protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException + { + return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding)); + } +} + diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/GzipHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/GzipHandler.java index 7aac5ed65b3..003846cfc4d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/GzipHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/GzipHandler.java @@ -21,21 +21,17 @@ import java.io.UnsupportedEncodingException; import java.util.HashSet; import java.util.Set; import java.util.StringTokenizer; -import java.util.zip.GZIPOutputStream; import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; 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.HttpMethods; +import org.eclipse.jetty.http.gzip.GzipResponseWrapper; import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.util.ByteArrayOutputStream2; -import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.log.Log; /* ------------------------------------------------------------ */ @@ -64,6 +60,7 @@ public class GzipHandler extends HandlerWrapper /* ------------------------------------------------------------ */ /** + * Instantiates a new gzip handler. */ public GzipHandler() { @@ -199,6 +196,10 @@ public class GzipHandler extends HandlerWrapper _minGzipSize = minGzipSize; } + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { @@ -218,7 +219,7 @@ public class GzipHandler extends HandlerWrapper } } - final GZIPResponseWrapper wrappedResponse = newGZIPResponseWrapper(request,response); + final GzipResponseWrapper wrappedResponse = newGzipResponseWrapper(request,response); boolean exceptional=true; try @@ -265,435 +266,41 @@ public class GzipHandler extends HandlerWrapper } } - protected GZIPResponseWrapper newGZIPResponseWrapper(HttpServletRequest request, HttpServletResponse response) - { - return new GZIPResponseWrapper(request,response); - } - - /* - * Allows derived implementations to replace PrintWriter implementation + /** + * Allows derived implementations to replace ResponseWrapper implementation. + * + * @param request the request + * @param response the response + * @return the gzip response wrapper */ - protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException + protected GzipResponseWrapper newGzipResponseWrapper(HttpServletRequest request, HttpServletResponse response) { - return encoding == null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding)); + return new GzipResponseWrapper(request, response) + { + { + _mimeTypes = GzipHandler.this._mimeTypes; + _bufferSize = GzipHandler.this._bufferSize; + _minGzipSize = GzipHandler.this._minGzipSize; + } + + @Override + protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException + { + return GzipHandler.this.newWriter(out,encoding); + } + }; } - - public class GZIPResponseWrapper extends HttpServletResponseWrapper + + /** + * Allows derived implementations to replace PrintWriter implementation. + * + * @param out the out + * @param encoding the encoding + * @return the prints the writer + * @throws UnsupportedEncodingException + */ + protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException { - HttpServletRequest _request; - boolean _noGzip; - PrintWriter _writer; - GzipStream _gzStream; - long _contentLength = -1; - - public GZIPResponseWrapper(HttpServletRequest request, HttpServletResponse response) - { - super(response); - _request = request; - } - - public void setContentType(String ct) - { - super.setContentType(ct); - - if (ct != null) - { - int colon = ct.indexOf(";"); - if (colon > 0) - ct = ct.substring(0,colon); - } - - if ((_gzStream == null || _gzStream._out == null) - && (_mimeTypes == null && "application/gzip".equalsIgnoreCase(ct) || _mimeTypes != null - && (ct == null || !_mimeTypes.contains(StringUtil.asciiToLowerCase(ct))))) - { - noGzip(); - } - } - - public void setStatus(int sc, String sm) - { - super.setStatus(sc,sm); - if (sc < 200 || sc >= 300) - noGzip(); - } - - public void setStatus(int sc) - { - super.setStatus(sc); - if (sc < 200 || sc >= 300) - noGzip(); - } - - public void setContentLength(int length) - { - _contentLength = length; - if (_gzStream != null) - _gzStream.setContentLength(length); - } - - public void addHeader(String name, String value) - { - if ("content-length".equalsIgnoreCase(name)) - { - _contentLength = Long.parseLong(value); - if (_gzStream != null) - _gzStream.setContentLength(_contentLength); - } - else if ("content-type".equalsIgnoreCase(name)) - { - setContentType(value); - } - else if ("content-encoding".equalsIgnoreCase(name)) - { - super.addHeader(name,value); - if (!isCommitted()) - { - noGzip(); - } - } - else - super.addHeader(name,value); - } - - public void setHeader(String name, String value) - { - if ("content-length".equalsIgnoreCase(name)) - { - _contentLength = Long.parseLong(value); - if (_gzStream != null) - _gzStream.setContentLength(_contentLength); - } - else if ("content-type".equalsIgnoreCase(name)) - { - setContentType(value); - } - else if ("content-encoding".equalsIgnoreCase(name)) - { - super.setHeader(name,value); - if (!isCommitted()) - { - noGzip(); - } - } - else - super.setHeader(name,value); - } - - public void setIntHeader(String name, int value) - { - if ("content-length".equalsIgnoreCase(name)) - { - _contentLength = value; - if (_gzStream != null) - _gzStream.setContentLength(_contentLength); - } - else - super.setIntHeader(name,value); - } - - public void flushBuffer() throws IOException - { - if (_writer != null) - _writer.flush(); - if (_gzStream != null) - _gzStream.finish(); - else - getResponse().flushBuffer(); - } - - public void reset() - { - super.reset(); - if (_gzStream != null) - _gzStream.resetBuffer(); - _writer = null; - _gzStream = null; - _noGzip = false; - _contentLength = -1; - } - - public void resetBuffer() - { - super.resetBuffer(); - if (_gzStream != null) - _gzStream.resetBuffer(); - _writer = null; - _gzStream = null; - } - - public void sendError(int sc, String msg) throws IOException - { - resetBuffer(); - super.sendError(sc,msg); - } - - public void sendError(int sc) throws IOException - { - resetBuffer(); - super.sendError(sc); - } - - public void sendRedirect(String location) throws IOException - { - resetBuffer(); - super.sendRedirect(location); - } - - public ServletOutputStream getOutputStream() throws IOException - { - if (_gzStream == null) - { - if (getResponse().isCommitted() || _noGzip) - return getResponse().getOutputStream(); - - _gzStream = newGzipStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minGzipSize); - } - else if (_writer != null) - throw new IllegalStateException("getWriter() called"); - - return _gzStream; - } - - public PrintWriter getWriter() throws IOException - { - if (_writer == null) - { - if (_gzStream != null) - throw new IllegalStateException("getOutputStream() called"); - - if (getResponse().isCommitted() || _noGzip) - return getResponse().getWriter(); - - _gzStream = newGzipStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minGzipSize); - _writer = newWriter(_gzStream,getCharacterEncoding()); - } - return _writer; - } - - void noGzip() - { - _noGzip = true; - if (_gzStream != null) - { - try - { - _gzStream.doNotGzip(); - } - catch (IOException e) - { - throw new IllegalStateException(e); - } - } - } - - void finish() throws IOException - { - if (_writer != null && !_gzStream._closed) - _writer.flush(); - if (_gzStream != null) - _gzStream.finish(); - } - - protected GzipStream newGzipStream(HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minGzipSize) - throws IOException - { - return new GzipStream(request,response,contentLength,bufferSize,minGzipSize); - } - } - - public static class GzipStream extends ServletOutputStream - { - protected HttpServletRequest _request; - protected HttpServletResponse _response; - protected OutputStream _out; - protected ByteArrayOutputStream2 _bOut; - protected GZIPOutputStream _gzOut; - protected boolean _closed; - protected int _bufferSize; - protected int _minGzipSize; - protected long _contentLength; - - public GzipStream(HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minGzipSize) throws IOException - { - _request = request; - _response = response; - _contentLength = contentLength; - _bufferSize = bufferSize; - _minGzipSize = minGzipSize; - if (minGzipSize == 0) - doGzip(); - } - - public void resetBuffer() - { - if (_response.isCommitted()) - throw new IllegalStateException("Committed"); - _closed = false; - _out = null; - _bOut = null; - if (_gzOut != null) - _response.setHeader("Content-Encoding",null); - _gzOut = null; - } - - public void setContentLength(long length) - { - _contentLength = length; - } - - public void flush() throws IOException - { - if (_out == null || _bOut != null) - { - if (_contentLength > 0 && _contentLength < _minGzipSize) - doNotGzip(); - else - doGzip(); - } - - _out.flush(); - } - - public void close() throws IOException - { - if (_closed) - return; - - if (_request.getAttribute("javax.servlet.include.request_uri") != null) - flush(); - else - { - if (_bOut != null) - { - if (_contentLength < 0) - _contentLength = _bOut.getCount(); - if (_contentLength < _minGzipSize) - doNotGzip(); - else - doGzip(); - } - else if (_out == null) - { - doNotGzip(); - } - - if (_gzOut != null) - _gzOut.close(); - else - _out.close(); - _closed = true; - } - } - - public void finish() throws IOException - { - if (!_closed) - { - if (_out == null || _bOut != null) - { - if (_contentLength > 0 && _contentLength < _minGzipSize) - doNotGzip(); - else - doGzip(); - } - - if (_gzOut != null && !_closed) - { - _closed = true; - _gzOut.close(); - } - } - } - - public void write(int b) throws IOException - { - checkOut(1); - _out.write(b); - } - - public void write(byte b[]) throws IOException - { - checkOut(b.length); - _out.write(b); - } - - public void write(byte b[], int off, int len) throws IOException - { - checkOut(len); - _out.write(b,off,len); - } - - protected boolean setContentEncodingGzip() - { - _response.setHeader("Content-Encoding","gzip"); - return _response.containsHeader("Content-Encoding"); - } - - public void doGzip() throws IOException - { - if (_gzOut == null) - { - if (_response.isCommitted()) - throw new IllegalStateException(); - - if (setContentEncodingGzip()) - { - _out = _gzOut = new GZIPOutputStream(_response.getOutputStream(),_bufferSize); - - if (_bOut != null) - { - _out.write(_bOut.getBuf(),0,_bOut.getCount()); - _bOut = null; - } - } - else - doNotGzip(); - } - } - - public void doNotGzip() throws IOException - { - if (_gzOut != null) - throw new IllegalStateException(); - if (_out == null || _bOut != null) - { - _out = _response.getOutputStream(); - if (_contentLength >= 0) - { - if (_contentLength < Integer.MAX_VALUE) - _response.setContentLength((int)_contentLength); - else - _response.setHeader("Content-Length",Long.toString(_contentLength)); - } - - if (_bOut != null) - _out.write(_bOut.getBuf(),0,_bOut.getCount()); - _bOut = null; - } - } - - private void checkOut(int length) throws IOException - { - if (_closed) - throw new IOException("CLOSED"); - - if (_out == null) - { - if (_response.isCommitted() || (_contentLength >= 0 && _contentLength < _minGzipSize)) - doNotGzip(); - else if (length > _minGzipSize) - doGzip(); - else - _out = _bOut = new ByteArrayOutputStream2(_bufferSize); - } - else if (_bOut != null) - { - if (_response.isCommitted() || (_contentLength >= 0 && _contentLength < _minGzipSize)) - doNotGzip(); - else if (length >= (_bOut.getBuf().length - _bOut.getCount())) - doGzip(); - } - } + return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding)); } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/HttpTester.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/HttpTester.java deleted file mode 100644 index 2844422e31c..00000000000 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/HttpTester.java +++ /dev/null @@ -1,537 +0,0 @@ -// ======================================================================== -// Copyright (c) 2004-2009 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.server.handler; - -import java.io.IOException; -import java.util.Enumeration; - -import javax.servlet.http.Cookie; - -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpGenerator; -import org.eclipse.jetty.http.HttpHeaders; -import org.eclipse.jetty.http.HttpParser; -import org.eclipse.jetty.http.HttpVersions; -import org.eclipse.jetty.http.MimeTypes; -import org.eclipse.jetty.io.Buffer; -import org.eclipse.jetty.io.ByteArrayBuffer; -import org.eclipse.jetty.io.SimpleBuffers; -import org.eclipse.jetty.io.View; -import org.eclipse.jetty.io.bio.StringEndPoint; -import org.eclipse.jetty.util.ByteArrayOutputStream2; - -/* ------------------------------------------------------------ */ -/** Test support class. - * Assist with parsing and generating HTTP requests and responses. - * - *
- *      HttpTester tester = new HttpTester();
- *      
- *      tester.parse(
- *          "GET /uri HTTP/1.1\r\n"+
- *          "Host: fakehost\r\n"+
- *          "Content-Length: 10\r\n" +
- *          "\r\n");
- *     
- *      System.err.println(tester.getMethod());
- *      System.err.println(tester.getURI());
- *      System.err.println(tester.getVersion());
- *      System.err.println(tester.getHeader("Host"));
- *      System.err.println(tester.getContent());
- * 
- * - * - * @see org.eclipse.jetty.testing.ServletTester - */ -public class HttpTester -{ - protected HttpFields _fields=new HttpFields(); - protected String _method; - protected String _uri; - protected String _version; - protected int _status; - protected String _reason; - protected ByteArrayOutputStream2 _parsedContent; - protected byte[] _genContent; - - private String _charset, _defaultCharset; - private Buffer _contentType; - - public HttpTester() - { - this("UTF-8"); - } - - public HttpTester(String charset) - { - _defaultCharset = charset; - } - - public void reset() - { - _fields.clear(); - _method=null; - _uri=null; - _version=null; - _status=0; - _reason=null; - _parsedContent=null; - _genContent=null; - } - - private String getString(Buffer buffer) - { - return getString(buffer.asArray()); - } - - private String getString(byte[] b) - { - if(_charset==null) - return new String(b); - try - { - return new String(b, _charset); - } - catch(Exception e) - { - return new String(b); - } - } - - private byte[] getByteArray(String str) - { - if(_charset==null) - return str.getBytes(); - try - { - return str.getBytes(_charset); - } - catch(Exception e) - { - return str.getBytes(); - } - } - - /* ------------------------------------------------------------ */ - /** - * Parse one HTTP request or response - * @param rawHTTP Raw HTTP to parse - * @return Any unparsed data in the rawHTTP (eg pipelined requests) - * @throws IOException - */ - public String parse(String rawHTTP) throws IOException - { - _charset = _defaultCharset; - ByteArrayBuffer buf = new ByteArrayBuffer(getByteArray(rawHTTP)); - View view = new View(buf); - HttpParser parser = new HttpParser(view,new PH()); - parser.parse(); - return getString(view.asArray()); - } - - /* ------------------------------------------------------------ */ - /** - * Parse one HTTP request or response - * @param rawHTTP Raw HTTP to parse - * @return Any unparsed data in the rawHTTP (eg pipelined requests) - * @throws IOException - */ - public byte[] parse(byte[] rawHTTP) throws IOException - { - _charset = _defaultCharset; - ByteArrayBuffer buf = new ByteArrayBuffer(rawHTTP); - View view = new View(buf); - HttpParser parser = new HttpParser(view,new PH()); - parser.parse(); - return view.asArray(); - } - - /* ------------------------------------------------------------ */ - public String generate() throws IOException - { - _charset = _defaultCharset; - _contentType = _fields.get(HttpHeaders.CONTENT_TYPE_BUFFER); - if(_contentType!=null) - { - String charset = MimeTypes.getCharsetFromContentType(_contentType); - if(charset!=null) - _charset = charset; - } - Buffer bb=new ByteArrayBuffer(32*1024 + (_genContent!=null?_genContent.length:0)); - Buffer sb=new ByteArrayBuffer(4*1024); - StringEndPoint endp = new StringEndPoint(_charset); - HttpGenerator generator = new HttpGenerator(new SimpleBuffers(sb,bb),endp); - - if (_method!=null) - { - generator.setRequest(getMethod(),getURI()); - if (_version==null) - generator.setVersion(HttpVersions.HTTP_1_1_ORDINAL); - else - generator.setVersion(HttpVersions.CACHE.getOrdinal(HttpVersions.CACHE.lookup(_version))); - generator.completeHeader(_fields,false); - if (_genContent!=null) - generator.addContent(new View(new ByteArrayBuffer(_genContent)),false); - else if (_parsedContent!=null) - generator.addContent(new ByteArrayBuffer(_parsedContent.toByteArray()),false); - } - - generator.complete(); - generator.flushBuffer(); - return endp.getOutput(); - } - - /* ------------------------------------------------------------ */ - /** - * @return the method - */ - public String getMethod() - { - return _method; - } - - /* ------------------------------------------------------------ */ - /** - * @param method the method to set - */ - public void setMethod(String method) - { - _method=method; - } - - /* ------------------------------------------------------------ */ - /** - * @return the reason - */ - public String getReason() - { - return _reason; - } - - /* ------------------------------------------------------------ */ - /** - * @param reason the reason to set - */ - public void setReason(String reason) - { - _reason=reason; - } - - /* ------------------------------------------------------------ */ - /** - * @return the status - */ - public int getStatus() - { - return _status; - } - - /* ------------------------------------------------------------ */ - /** - * @param status the status to set - */ - public void setStatus(int status) - { - _status=status; - } - - /* ------------------------------------------------------------ */ - /** - * @return the uri - */ - public String getURI() - { - return _uri; - } - - /* ------------------------------------------------------------ */ - /** - * @param uri the uri to set - */ - public void setURI(String uri) - { - _uri=uri; - } - - /* ------------------------------------------------------------ */ - /** - * @return the version - */ - public String getVersion() - { - return _version; - } - - /* ------------------------------------------------------------ */ - /** - * @param version the version to set - */ - public void setVersion(String version) - { - _version=version; - } - - /* ------------------------------------------------------------ */ - public String getContentType() - { - return getString(_contentType); - } - - /* ------------------------------------------------------------ */ - public String getCharacterEncoding() - { - return _charset; - } - - /* ------------------------------------------------------------ */ - /** - * @param name - * @param value - * @throws IllegalArgumentException - * @see org.eclipse.jetty.http.HttpFields#add(java.lang.String, java.lang.String) - */ - public void addHeader(String name, String value) throws IllegalArgumentException - { - _fields.add(name,value); - } - - /* ------------------------------------------------------------ */ - /** - * @param name - * @param date - * @see org.eclipse.jetty.http.HttpFields#addDateField(java.lang.String, long) - */ - public void addDateHeader(String name, long date) - { - _fields.addDateField(name,date); - } - - /* ------------------------------------------------------------ */ - /** - * @param name - * @param value - * @see org.eclipse.jetty.http.HttpFields#addLongField(java.lang.String, long) - */ - public void addLongHeader(String name, long value) - { - _fields.addLongField(name,value); - } - - /* ------------------------------------------------------------ */ - /** - * @param cookie - * @see org.eclipse.jetty.http.HttpFields#addSetCookie(org.eclipse.jetty.http.HttpCookie) - */ - public void addSetCookie(Cookie cookie) - { - _fields.addSetCookie( - cookie.getName(), - cookie.getValue(), - cookie.getDomain(), - cookie.getPath(), - cookie.getMaxAge(), - cookie.getComment(), - cookie.getSecure(), - false, - cookie.getVersion()); - } - - /* ------------------------------------------------------------ */ - /** - * @param name - * @return the header value as a date - * @see org.eclipse.jetty.http.HttpFields#getDateField(java.lang.String) - */ - public long getDateHeader(String name) - { - return _fields.getDateField(name); - } - - /* ------------------------------------------------------------ */ - /** - * @return the header value names - * @see org.eclipse.jetty.http.HttpFields#getFieldNames() - */ - public Enumeration getHeaderNames() - { - return _fields.getFieldNames(); - } - - /* ------------------------------------------------------------ */ - /** - * @param name - * @return the header value as a long - * @throws NumberFormatException - * @see org.eclipse.jetty.http.HttpFields#getLongField(java.lang.String) - */ - public long getLongHeader(String name) throws NumberFormatException - { - return _fields.getLongField(name); - } - - /* ------------------------------------------------------------ */ - /** - * @param name - * @return the header value - * @see org.eclipse.jetty.http.HttpFields#getStringField(java.lang.String) - */ - public String getHeader(String name) - { - return _fields.getStringField(name); - } - - /* ------------------------------------------------------------ */ - /** - * @param name - * @return the header values - * @see org.eclipse.jetty.http.HttpFields#getValues(java.lang.String) - */ - public Enumeration getHeaderValues(String name) - { - return _fields.getValues(name); - } - - /* ------------------------------------------------------------ */ - /** - * @param name - * @param value - * @see org.eclipse.jetty.http.HttpFields#put(java.lang.String, java.lang.String) - */ - public void setHeader(String name, String value) - { - _fields.put(name,value); - } - - /* ------------------------------------------------------------ */ - /** - * @param name - * @param date - * @see org.eclipse.jetty.http.HttpFields#putDateField(java.lang.String, long) - */ - public void setDateHeader(String name, long date) - { - _fields.putDateField(name,date); - } - - /* ------------------------------------------------------------ */ - /** - * @param name - * @param value - * @see org.eclipse.jetty.http.HttpFields#putLongField(java.lang.String, long) - */ - public void setLongHeader(String name, long value) - { - _fields.putLongField(name,value); - } - - /* ------------------------------------------------------------ */ - /** - * @param name - * @see org.eclipse.jetty.http.HttpFields#remove(java.lang.String) - */ - public void removeHeader(String name) - { - _fields.remove(name); - } - - /* ------------------------------------------------------------ */ - public String getContent() - { - if (_parsedContent!=null) - return getString(_parsedContent.toByteArray()); - if (_genContent!=null) - return getString(_genContent); - return null; - } - - /* ------------------------------------------------------------ */ - public byte[] getContentBytes() - { - if (_parsedContent!=null) - return _parsedContent.toByteArray(); - if (_genContent!=null) - return _genContent; - return null; - } - - /* ------------------------------------------------------------ */ - public void setContent(String content) - { - _parsedContent=null; - if (content!=null) - { - _genContent=getByteArray(content); - setLongHeader(HttpHeaders.CONTENT_LENGTH,_genContent.length); - } - else - { - removeHeader(HttpHeaders.CONTENT_LENGTH); - _genContent=null; - } - } - - /* ------------------------------------------------------------ */ - private class PH extends HttpParser.EventHandler - { - @Override - public void startRequest(Buffer method, Buffer url, Buffer version) throws IOException - { - reset(); - _method=getString(method); - _uri=getString(url); - _version=getString(version); - } - - @Override - public void startResponse(Buffer version, int status, Buffer reason) throws IOException - { - reset(); - _version=getString(version); - _status=status; - _reason=getString(reason); - } - - @Override - public void parsedHeader(Buffer name, Buffer value) throws IOException - { - _fields.add(name,value); - } - - @Override - public void headerComplete() throws IOException - { - _contentType = _fields.get(HttpHeaders.CONTENT_TYPE_BUFFER); - if(_contentType!=null) - { - String charset = MimeTypes.getCharsetFromContentType(_contentType); - if(charset!=null) - _charset = charset; - } - } - - @Override - public void messageComplete(long contextLength) throws IOException - { - } - - @Override - public void content(Buffer ref) throws IOException - { - if (_parsedContent==null) - _parsedContent=new ByteArrayOutputStream2(); - _parsedContent.write(ref.asArray()); - } - } - -} 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 b77d783c4c3..e48cb702847 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 @@ -20,24 +20,20 @@ import java.io.UnsupportedEncodingException; import java.util.HashSet; import java.util.Set; import java.util.StringTokenizer; -import java.util.zip.GZIPOutputStream; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; 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.HttpMethods; -import org.eclipse.jetty.util.ByteArrayOutputStream2; -import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.http.gzip.GzipResponseWrapper; import org.eclipse.jetty.util.log.Log; /* ------------------------------------------------------------ */ @@ -65,11 +61,15 @@ import org.eclipse.jetty.util.log.Log; */ public class GzipFilter extends UserAgentFilter { - protected Set _mimeTypes; + protected Set _mimeTypes; protected int _bufferSize=8192; protected int _minGzipSize=256; - protected Set _excluded; + protected Set _excluded; + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.servlets.UserAgentFilter#init(javax.servlet.FilterConfig) + */ public void init(FilterConfig filterConfig) throws ServletException { super.init(filterConfig); @@ -85,7 +85,7 @@ public class GzipFilter extends UserAgentFilter tmp=filterConfig.getInitParameter("mimeTypes"); if (tmp!=null) { - _mimeTypes=new HashSet(); + _mimeTypes=new HashSet(); StringTokenizer tok = new StringTokenizer(tmp,",",false); while (tok.hasMoreTokens()) _mimeTypes.add(tok.nextToken()); @@ -94,17 +94,25 @@ public class GzipFilter extends UserAgentFilter tmp=filterConfig.getInitParameter("excludedAgents"); if (tmp!=null) { - _excluded=new HashSet(); + _excluded=new HashSet(); StringTokenizer tok = new StringTokenizer(tmp,",",false); while (tok.hasMoreTokens()) _excluded.add(tok.nextToken()); } } + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.servlets.UserAgentFilter#destroy() + */ public void destroy() { } + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.servlets.UserAgentFilter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) + */ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { @@ -125,7 +133,7 @@ public class GzipFilter extends UserAgentFilter } } - final GZIPResponseWrapper wrappedResponse=newGZIPResponseWrapper(request,response); + final GzipResponseWrapper wrappedResponse=newGzipResponseWrapper(request,response); boolean exceptional=true; try @@ -171,436 +179,41 @@ public class GzipFilter extends UserAgentFilter } } - protected GZIPResponseWrapper newGZIPResponseWrapper(HttpServletRequest request, HttpServletResponse response) + /** + * Allows derived implementations to replace ResponseWrapper implementation. + * + * @param request the request + * @param response the response + * @return the gzip response wrapper + */ + protected GzipResponseWrapper newGzipResponseWrapper(HttpServletRequest request, HttpServletResponse response) { - return new GZIPResponseWrapper(request,response); + return new GzipResponseWrapper(request, response) + { + { + _mimeTypes = GzipFilter.this._mimeTypes; + _bufferSize = GzipFilter.this._bufferSize; + _minGzipSize = GzipFilter.this._minGzipSize; + } + + @Override + protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException + { + return GzipFilter.this.newWriter(out,encoding); + } + }; } - /* - * Allows derived implementations to replace PrintWriter implementation + /** + * Allows derived implementations to replace PrintWriter implementation. + * + * @param out the out + * @param encoding the encoding + * @return the prints the writer + * @throws UnsupportedEncodingException */ protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException { return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding)); } - - public class GZIPResponseWrapper extends HttpServletResponseWrapper - { - HttpServletRequest _request; - boolean _noGzip; - PrintWriter _writer; - GzipStream _gzStream; - long _contentLength=-1; - - public GZIPResponseWrapper(HttpServletRequest request, HttpServletResponse response) - { - super(response); - _request=request; - } - - public void setContentType(String ct) - { - super.setContentType(ct); - - if (ct!=null) - { - int colon=ct.indexOf(";"); - if (colon>0) - ct=ct.substring(0,colon); - } - - if ((_gzStream==null || _gzStream._out==null) && - (_mimeTypes==null && "application/gzip".equalsIgnoreCase(ct) || - _mimeTypes!=null && (ct==null||!_mimeTypes.contains(StringUtil.asciiToLowerCase(ct))))) - { - noGzip(); - } - } - - public void setStatus(int sc, String sm) - { - super.setStatus(sc,sm); - if (sc<200||sc>=300) - noGzip(); - } - - public void setStatus(int sc) - { - super.setStatus(sc); - if (sc<200||sc>=300) - noGzip(); - } - - public void setContentLength(int length) - { - _contentLength=length; - if (_gzStream!=null) - _gzStream.setContentLength(length); - } - - public void addHeader(String name, String value) - { - if ("content-length".equalsIgnoreCase(name)) - { - _contentLength=Long.parseLong(value); - if (_gzStream!=null) - _gzStream.setContentLength(_contentLength); - } - else if ("content-type".equalsIgnoreCase(name)) - { - setContentType(value); - } - else if ("content-encoding".equalsIgnoreCase(name)) - { - super.addHeader(name,value); - if (!isCommitted()) - { - noGzip(); - } - } - else - super.addHeader(name,value); - } - - public void setHeader(String name, String value) - { - if ("content-length".equalsIgnoreCase(name)) - { - _contentLength=Long.parseLong(value); - if (_gzStream!=null) - _gzStream.setContentLength(_contentLength); - } - else if ("content-type".equalsIgnoreCase(name)) - { - setContentType(value); - } - else if ("content-encoding".equalsIgnoreCase(name)) - { - super.setHeader(name,value); - if (!isCommitted()) - { - noGzip(); - } - } - else - super.setHeader(name,value); - } - - public void setIntHeader(String name, int value) - { - if ("content-length".equalsIgnoreCase(name)) - { - _contentLength=value; - if (_gzStream!=null) - _gzStream.setContentLength(_contentLength); - } - else - super.setIntHeader(name,value); - } - - public void flushBuffer() throws IOException - { - if (_writer!=null) - _writer.flush(); - if (_gzStream!=null) - _gzStream.finish(); - else - getResponse().flushBuffer(); - } - - public void reset() - { - super.reset(); - if (_gzStream!=null) - _gzStream.resetBuffer(); - _writer=null; - _gzStream=null; - _noGzip=false; - _contentLength=-1; - } - - public void resetBuffer() - { - super.resetBuffer(); - if (_gzStream!=null) - _gzStream.resetBuffer(); - _writer=null; - _gzStream=null; - } - - public void sendError(int sc, String msg) throws IOException - { - resetBuffer(); - super.sendError(sc,msg); - } - - public void sendError(int sc) throws IOException - { - resetBuffer(); - super.sendError(sc); - } - - public void sendRedirect(String location) throws IOException - { - resetBuffer(); - super.sendRedirect(location); - } - - public ServletOutputStream getOutputStream() throws IOException - { - if (_gzStream==null) - { - if (getResponse().isCommitted() || _noGzip) - return getResponse().getOutputStream(); - - _gzStream=newGzipStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minGzipSize); - } - else if (_writer!=null) - throw new IllegalStateException("getWriter() called"); - - return _gzStream; - } - - public PrintWriter getWriter() throws IOException - { - if (_writer==null) - { - if (_gzStream!=null) - throw new IllegalStateException("getOutputStream() called"); - - if (getResponse().isCommitted() || _noGzip) - return getResponse().getWriter(); - - _gzStream=newGzipStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minGzipSize); - _writer=newWriter(_gzStream,getCharacterEncoding()); - } - return _writer; - } - - void noGzip() - { - _noGzip=true; - if (_gzStream!=null) - { - try - { - _gzStream.doNotGzip(); - } - catch (IOException e) - { - throw new IllegalStateException(e); - } - } - } - - void finish() throws IOException - { - if (_writer!=null && !_gzStream._closed) - _writer.flush(); - if (_gzStream!=null) - _gzStream.finish(); - } - - protected GzipStream newGzipStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minGzipSize) throws IOException - { - return new GzipStream(request,response,contentLength,bufferSize,minGzipSize); - } - } - - - public static class GzipStream extends ServletOutputStream - { - protected HttpServletRequest _request; - protected HttpServletResponse _response; - protected OutputStream _out; - protected ByteArrayOutputStream2 _bOut; - protected GZIPOutputStream _gzOut; - protected boolean _closed; - protected int _bufferSize; - protected int _minGzipSize; - protected long _contentLength; - - public GzipStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minGzipSize) throws IOException - { - _request=request; - _response=response; - _contentLength=contentLength; - _bufferSize=bufferSize; - _minGzipSize=minGzipSize; - if (minGzipSize==0) - doGzip(); - } - - public void resetBuffer() - { - if (_response.isCommitted()) - throw new IllegalStateException("Committed"); - _closed=false; - _out=null; - _bOut=null; - if (_gzOut!=null) - _response.setHeader("Content-Encoding",null); - _gzOut=null; - } - - public void setContentLength(long length) - { - _contentLength=length; - } - - public void flush() throws IOException - { - if (_out==null || _bOut!=null) - { - if (_contentLength>0 && _contentLength<_minGzipSize) - doNotGzip(); - else - doGzip(); - } - - _out.flush(); - } - - public void close() throws IOException - { - if (_closed) - return; - - if (_request.getAttribute("javax.servlet.include.request_uri")!=null) - flush(); - else - { - if (_bOut!=null) - { - if (_contentLength<0) - _contentLength=_bOut.getCount(); - if (_contentLength<_minGzipSize) - doNotGzip(); - else - doGzip(); - } - else if (_out==null) - { - doNotGzip(); - } - - if (_gzOut!=null) - _gzOut.close(); - else - _out.close(); - _closed=true; - } - } - - public void finish() throws IOException - { - if (!_closed) - { - if (_out==null || _bOut!=null) - { - if (_contentLength>0 && _contentLength<_minGzipSize) - doNotGzip(); - else - doGzip(); - } - - if (_gzOut!=null && !_closed) - { - _closed=true; - _gzOut.close(); - } - } - } - - public void write(int b) throws IOException - { - checkOut(1); - _out.write(b); - } - - public void write(byte b[]) throws IOException - { - checkOut(b.length); - _out.write(b); - } - - public void write(byte b[], int off, int len) throws IOException - { - checkOut(len); - _out.write(b,off,len); - } - - protected boolean setContentEncodingGzip() - { - _response.setHeader("Content-Encoding", "gzip"); - return _response.containsHeader("Content-Encoding"); - } - - public void doGzip() throws IOException - { - if (_gzOut==null) - { - if (_response.isCommitted()) - throw new IllegalStateException(); - - if (setContentEncodingGzip()) - { - _out=_gzOut=new GZIPOutputStream(_response.getOutputStream(),_bufferSize); - - if (_bOut!=null) - { - _out.write(_bOut.getBuf(),0,_bOut.getCount()); - _bOut=null; - } - } - else - doNotGzip(); - } - } - - public void doNotGzip() throws IOException - { - if (_gzOut!=null) - throw new IllegalStateException(); - if (_out==null || _bOut!=null ) - { - _out=_response.getOutputStream(); - if (_contentLength>=0) - { - if(_contentLength=0 && _contentLength<_minGzipSize)) - doNotGzip(); - else if (length>_minGzipSize) - doGzip(); - else - _out=_bOut=new ByteArrayOutputStream2(_bufferSize); - } - else if (_bOut!=null) - { - if (_response.isCommitted() || (_contentLength>=0 && _contentLength<_minGzipSize)) - doNotGzip(); - else if (length>=(_bOut.getBuf().length -_bOut.getCount())) - doGzip(); - } - } - } - } diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java index 97fdee7f90a..0084ddaf861 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java @@ -24,6 +24,8 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.gzip.GzipResponseWrapper; +import org.eclipse.jetty.http.gzip.GzipStream; import org.eclipse.jetty.io.UncheckedPrintWriter; @@ -55,16 +57,20 @@ public class IncludableGzipFilter extends GzipFilter } @Override - protected GZIPResponseWrapper newGZIPResponseWrapper(HttpServletRequest request, HttpServletResponse response) + protected GzipResponseWrapper newGzipResponseWrapper(HttpServletRequest request, HttpServletResponse response) { return new IncludableResponseWrapper(request,response); } - public class IncludableResponseWrapper extends GzipFilter.GZIPResponseWrapper + public class IncludableResponseWrapper extends GzipResponseWrapper { public IncludableResponseWrapper(HttpServletRequest request, HttpServletResponse response) { super(request,response); + + _mimeTypes = IncludableGzipFilter.this._mimeTypes; + _bufferSize = IncludableGzipFilter.this._bufferSize; + _minGzipSize = IncludableGzipFilter.this._minGzipSize; } @Override @@ -72,9 +78,15 @@ public class IncludableGzipFilter extends GzipFilter { return new IncludableGzipStream(request,response,contentLength,bufferSize,minGzipSize); } + + @Override + protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException + { + return IncludableGzipFilter.this.newWriter(out,encoding); + } } - public class IncludableGzipStream extends GzipFilter.GzipStream + public class IncludableGzipStream extends GzipStream { public IncludableGzipStream(HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minGzipSize) throws IOException @@ -93,7 +105,7 @@ public class IncludableGzipFilter extends GzipFilter return _response.containsHeader("Content-Encoding"); } } - + @Override protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException { diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterTest.java index 2ff72060ba5..7329e03e838 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterTest.java @@ -13,21 +13,15 @@ package org.eclipse.jetty.servlets; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.FileWriter; import java.io.InputStream; -import java.io.OutputStream; -import java.io.StringReader; -import java.net.Socket; -import java.net.URL; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; import java.util.zip.GZIPInputStream; import javax.servlet.http.HttpServletResponse; @@ -43,9 +37,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - public class GzipFilterTest { private static String __content = diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java new file mode 100644 index 00000000000..63b0dd9d262 --- /dev/null +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java @@ -0,0 +1,115 @@ +// ======================================================================== +// Copyright (c) 2004-2009 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +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.util.zip.GZIPInputStream; + +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.io.ByteArrayBuffer; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.testing.HttpTester; +import org.eclipse.jetty.testing.ServletTester; +import org.eclipse.jetty.toolchain.test.TestingDir; +import org.eclipse.jetty.util.IO; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +public class IncludableGzipFilterTest +{ + 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."; + + @Rule + public TestingDir testdir = new TestingDir(); + + private ServletTester tester; + + @Before + public void setUp() throws Exception + { + testdir.ensureEmpty(); + + File testFile = testdir.getFile("file.txt"); + BufferedOutputStream testOut = new BufferedOutputStream(new FileOutputStream(testFile)); + ByteArrayInputStream testIn = new ByteArrayInputStream(__content.getBytes("ISO8859_1")); + IO.copy(testIn,testOut); + testOut.close(); + + tester=new ServletTester(); + tester.setContextPath("/context"); + tester.setResourceBase(testdir.getDir().getCanonicalPath()); + tester.addServlet(org.eclipse.jetty.servlet.DefaultServlet.class, "/"); + FilterHolder holder = tester.addFilter(IncludableGzipFilter.class,"/*",0); + holder.setInitParameter("mimeTypes","text/plain"); + tester.start(); + } + + @After + public void tearDown() throws Exception + { + tester.stop(); + IO.delete(testdir.getDir()); + } + + @Test + public void testGzipFilter() throws Exception + { + // generated and parsed test + HttpTester request = new HttpTester(); + HttpTester response = new HttpTester(); + + request.setMethod("GET"); + request.setVersion("HTTP/1.0"); + request.setHeader("Host","tester"); + request.setHeader("accept-encoding","gzip"); + request.setURI("/context/file.txt"); + + ByteArrayBuffer reqsBuff = new ByteArrayBuffer(request.generate().getBytes()); + ByteArrayBuffer respBuff = tester.getResponses(reqsBuff); + response.parse(respBuff.asArray()); + + assertTrue(response.getMethod()==null); + assertTrue(response.getHeader("Content-Encoding").equalsIgnoreCase("gzip")); + assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + + InputStream testIn = new GZIPInputStream(new ByteArrayInputStream(response.getContentBytes())); + ByteArrayOutputStream testOut = new ByteArrayOutputStream(); + IO.copy(testIn,testOut); + + assertEquals(__content, testOut.toString("ISO8859_1")); + } +}