Return-Path: Delivered-To: apmail-jakarta-tomcat-dev-archive@apache.org Received: (qmail 72490 invoked from network); 18 Dec 2002 20:37:09 -0000 Received: from exchange.sun.com (HELO nagoya.betaversion.org) (192.18.33.10) by daedalus.apache.org with SMTP; 18 Dec 2002 20:37:09 -0000 Received: (qmail 5732 invoked by uid 97); 18 Dec 2002 20:38:18 -0000 Delivered-To: qmlist-jakarta-archive-tomcat-dev@jakarta.apache.org Received: (qmail 5702 invoked by uid 97); 18 Dec 2002 20:38:17 -0000 Mailing-List: contact tomcat-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Tomcat Developers List" Reply-To: "Tomcat Developers List" Delivered-To: mailing list tomcat-dev@jakarta.apache.org Received: (qmail 5691 invoked by uid 97); 18 Dec 2002 20:38:17 -0000 X-Antivirus: nagoya (v4218 created Aug 14 2002) Date: 18 Dec 2002 20:36:58 -0000 Message-ID: <20021218203658.86142.qmail@icarus.apache.org> From: remm@apache.org To: jakarta-tomcat-connectors-cvs@apache.org Subject: cvs commit: jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/filters GzipOutputFilter.java X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N remm 2002/12/18 12:36:58 Modified: http11/src/java/org/apache/coyote/http11 Constants.java Http11Processor.java Http11Protocol.java Added: http11/src/java/org/apache/coyote/http11/filters GzipOutputFilter.java Log: - Add support for gzip content encoding. - I believe some broken user agents must be excluded. Revision Changes Path 1.13 +6 -0 jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Constants.java Index: Constants.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Constants.java,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- Constants.java 24 Nov 2002 22:00:04 -0000 1.12 +++ Constants.java 18 Dec 2002 20:36:58 -0000 1.13 @@ -199,6 +199,12 @@ /** + * GZIP filters (input and output). + */ + public static final int GZIP_FILTER = 3; + + + /** * HTTP/1.0. */ public static final String HTTP_10 = "HTTP/1.0"; 1.48 +86 -0 jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Processor.java Index: Http11Processor.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Processor.java,v retrieving revision 1.47 retrieving revision 1.48 diff -u -r1.47 -r1.48 --- Http11Processor.java 28 Nov 2002 15:15:02 -0000 1.47 +++ Http11Processor.java 18 Dec 2002 20:36:58 -0000 1.48 @@ -86,6 +86,8 @@ import org.apache.coyote.http11.filters.ChunkedInputFilter; import org.apache.coyote.http11.filters.ChunkedOutputFilter; +//import org.apache.coyote.http11.filters.GzipInputFilter; +import org.apache.coyote.http11.filters.GzipOutputFilter; import org.apache.coyote.http11.filters.IdentityInputFilter; import org.apache.coyote.http11.filters.IdentityOutputFilter; import org.apache.coyote.http11.filters.VoidInputFilter; @@ -223,32 +225,76 @@ */ protected Socket socket; + /** * Remote Address associated with the current connection. */ protected String remoteAddr = null; + /** * Remote Host associated with the current connection. */ protected String remoteHost = null; + /** * Maximum timeout on uploads. */ protected int timeout = 300000; // 5 minutes as in Apache HTTPD server + /** * Flag to disable setting a different time-out on uploads. */ protected boolean disableUploadTimeout = false; + + /** + * Allowed compression level. + */ + protected int compressionLevel = 0; + + /** * Host name (used to avoid useless B2C conversion on the host name). */ protected char[] hostNameC = new char[0]; + // ------------------------------------------------------------- Properties + + + /** + * Return compression level. + */ + public String getCompression() { + switch (compressionLevel) { + case 0: + return "off"; + case 1: + return "on"; + case 2: + return "force"; + } + return "off"; + } + + + /** + * Set compression level. + */ + public void setCompression(String compression) { + if (compression.equals("on")) { + this.compressionLevel = 1; + } else if (compression.equals("force")) { + this.compressionLevel = 2; + } else { + this.compressionLevel = 0; + } + } + + // --------------------------------------------------------- Public Methods @@ -350,6 +396,7 @@ public void setDisableUploadTimeout(boolean isDisabled) { disableUploadTimeout = isDisabled; } + /** * Get the flag that controls upload time-outs. */ @@ -363,6 +410,7 @@ public void setTimeout( int timeouts ) { timeout = timeouts ; } + /** * Get the upload timeout. */ @@ -918,6 +966,34 @@ contentDelimitation = true; } + // Check for compression + boolean useCompression = false; + if (entityBody && (compressionLevel > 0)) { + // Check accept-encoding + // FIXME: write a comma parser; also reuse + // for transfer-encoding parsing + MessageBytes acceptEncodingMB = + request.getMimeHeaders().getValue("accept-encoding"); + if ((acceptEncodingMB != null) + && (acceptEncodingMB.indexOf("gzip") != -1)) { + // Check content-type + if (compressionLevel == 1) { + int contentLength = response.getContentLength(); + // FIXME: Make the value configurable + if ((contentLength == -1) || (contentLength > 2048)) { + useCompression = + response.getContentType().startsWith("text/"); + } + } else { + useCompression = true; + } + // Change content-length to -1 to force chunking + if (useCompression) { + response.setContentLength(-1); + } + } + } + MimeHeaders headers = response.getMimeHeaders(); if (!entityBody) { response.setContentLength(-1); @@ -949,6 +1025,12 @@ } } + if (useCompression) { + outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]); + // FIXME: Make content-encoding generation dynamic + response.setHeader("Content-Encoding", "gzip"); + } + // Add date header if (! response.containsHeader("Date")) response.addHeader("Date", FastHttpDateFormat.getCurrentDate()); @@ -999,6 +1081,10 @@ // Create and add the void filters. inputBuffer.addFilter(new VoidInputFilter()); outputBuffer.addFilter(new VoidOutputFilter()); + + // Create and add the chunked filters. + //inputBuffer.addFilter(new GzipInputFilter()); + outputBuffer.addFilter(new GzipOutputFilter()); } 1.18 +6 -0 jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Protocol.java Index: Http11Protocol.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Protocol.java,v retrieving revision 1.17 retrieving revision 1.18 diff -u -r1.17 -r1.18 --- Http11Protocol.java 26 Nov 2002 03:32:50 -0000 1.17 +++ Http11Protocol.java 18 Dec 2002 20:36:58 -0000 1.18 @@ -186,6 +186,7 @@ private String reportedname; private int socketCloseDelay=-1; private boolean disableUploadTimeout = false; + private String compression = "off"; // -------------------- Pool setup -------------------- @@ -251,6 +252,10 @@ disableUploadTimeout = isDisabled; } + public void setCompression(String valueS) { + compression = valueS; + } + public void setSoLinger( int i ) { ep.setSoLinger( i ); setAttribute("soLinger", "" + i); @@ -352,6 +357,7 @@ processor.setMaxKeepAliveRequests( proto.maxKeepAliveRequests ); processor.setTimeout( proto.timeout ); processor.setDisableUploadTimeout( proto.disableUploadTimeout ); + processor.setCompression( proto.compression ); //thData[0]=adapter; thData[1]=processor; 1.1 jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/filters/GzipOutputFilter.java Index: GzipOutputFilter.java =================================================================== /* * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * [Additional notices, if required by prior licensing conditions] * */ package org.apache.coyote.http11.filters; import java.io.IOException; import java.io.OutputStream; import java.util.zip.GZIPOutputStream; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.coyote.OutputBuffer; import org.apache.coyote.Response; import org.apache.coyote.http11.OutputFilter; /** * Gzip output filter. * * @author Remy Maucherat */ public class GzipOutputFilter implements OutputFilter { // -------------------------------------------------------------- Constants protected static final String ENCODING_NAME = "gzip"; protected static final ByteChunk ENCODING = new ByteChunk(); // ----------------------------------------------------- Static Initializer static { ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); } // ----------------------------------------------------- Instance Variables /** * Next buffer in the pipeline. */ protected OutputBuffer buffer; /** * Compression output stream. */ protected GZIPOutputStream compressionStream = null; /** * Fake internal output stream. */ protected OutputStream fakeOutputStream = new FakeOutputStream(); // --------------------------------------------------- OutputBuffer Methods /** * Write some bytes. * * @return number of bytes written by the filter */ public int doWrite(ByteChunk chunk, Response res) throws IOException { if (compressionStream == null) { compressionStream = new GZIPOutputStream(fakeOutputStream); } compressionStream.write(chunk.getBytes(), chunk.getStart(), chunk.getLength()); return chunk.getLength(); } // --------------------------------------------------- OutputFilter Methods /** * Some filters need additional parameters from the response. All the * necessary reading can occur in that method, as this method is called * after the response header processing is complete. */ public void setResponse(Response response) { } /** * Set the next buffer in the filter pipeline. */ public void setBuffer(OutputBuffer buffer) { this.buffer = buffer; } /** * End the current request. It is acceptable to write extra bytes using * buffer.doWrite during the execution of this method. */ public long end() throws IOException { if (compressionStream == null) { compressionStream = new GZIPOutputStream(fakeOutputStream); } compressionStream.finish(); return ((OutputFilter) buffer).end(); } /** * Make the filter ready to process the next request. */ public void recycle() { // Set compression stream to null compressionStream = null; } /** * Return the name of the associated encoding; Here, the value is * "identity". */ public ByteChunk getEncodingName() { return ENCODING; } // ------------------------------------------- FakeOutputStream Inner Class protected class FakeOutputStream extends OutputStream { protected ByteChunk outputChunk = new ByteChunk(); public void write(int b) { // Shouldn't get called System.out.println("FIXME"); } public void write(byte[] b, int off, int len) throws IOException { outputChunk.setBytes(b, off, len); buffer.doWrite(outputChunk, null); } public void flush() throws IOException {} public void close() throws IOException {} } } -- To unsubscribe, e-mail: For additional commands, e-mail: