001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.coyote.http11.filters;
019:
020: import java.io.IOException;
021: import java.io.OutputStream;
022: import java.util.zip.GZIPOutputStream;
023:
024: import org.apache.tomcat.util.buf.ByteChunk;
025:
026: import org.apache.coyote.OutputBuffer;
027: import org.apache.coyote.Response;
028: import org.apache.coyote.http11.OutputFilter;
029:
030: /**
031: * Gzip output filter.
032: *
033: * @author Remy Maucherat
034: */
035: public class GzipOutputFilter implements OutputFilter {
036:
037: // -------------------------------------------------------------- Constants
038:
039: protected static final String ENCODING_NAME = "gzip";
040: protected static final ByteChunk ENCODING = new ByteChunk();
041:
042: // ----------------------------------------------------- Static Initializer
043:
044: static {
045: ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME
046: .length());
047: }
048:
049: // ----------------------------------------------------- Instance Variables
050:
051: /**
052: * Next buffer in the pipeline.
053: */
054: protected OutputBuffer buffer;
055:
056: /**
057: * Compression output stream.
058: */
059: protected GZIPOutputStream compressionStream = null;
060:
061: /**
062: * Fake internal output stream.
063: */
064: protected OutputStream fakeOutputStream = new FakeOutputStream();
065:
066: // --------------------------------------------------- OutputBuffer Methods
067:
068: /**
069: * Write some bytes.
070: *
071: * @return number of bytes written by the filter
072: */
073: public int doWrite(ByteChunk chunk, Response res)
074: throws IOException {
075: if (compressionStream == null) {
076: compressionStream = new GZIPOutputStream(fakeOutputStream);
077: }
078: compressionStream.write(chunk.getBytes(), chunk.getStart(),
079: chunk.getLength());
080: return chunk.getLength();
081: }
082:
083: // --------------------------------------------------- OutputFilter Methods
084:
085: /**
086: * Some filters need additional parameters from the response. All the
087: * necessary reading can occur in that method, as this method is called
088: * after the response header processing is complete.
089: */
090: public void setResponse(Response response) {
091: }
092:
093: /**
094: * Set the next buffer in the filter pipeline.
095: */
096: public void setBuffer(OutputBuffer buffer) {
097: this .buffer = buffer;
098: }
099:
100: /**
101: * End the current request. It is acceptable to write extra bytes using
102: * buffer.doWrite during the execution of this method.
103: */
104: public long end() throws IOException {
105: if (compressionStream == null) {
106: compressionStream = new GZIPOutputStream(fakeOutputStream);
107: }
108: compressionStream.finish();
109: compressionStream.close();
110: return ((OutputFilter) buffer).end();
111: }
112:
113: /**
114: * Make the filter ready to process the next request.
115: */
116: public void recycle() {
117: // Set compression stream to null
118: compressionStream = null;
119: }
120:
121: /**
122: * Return the name of the associated encoding; Here, the value is
123: * "identity".
124: */
125: public ByteChunk getEncodingName() {
126: return ENCODING;
127: }
128:
129: // ------------------------------------------- FakeOutputStream Inner Class
130:
131: protected class FakeOutputStream extends OutputStream {
132: protected ByteChunk outputChunk = new ByteChunk();
133: protected byte[] singleByteBuffer = new byte[1];
134:
135: public void write(int b) throws IOException {
136: // Shouldn't get used for good performance, but is needed for
137: // compatibility with Sun JDK 1.4.0
138: singleByteBuffer[0] = (byte) (b & 0xff);
139: outputChunk.setBytes(singleByteBuffer, 0, 1);
140: buffer.doWrite(outputChunk, null);
141: }
142:
143: public void write(byte[] b, int off, int len)
144: throws IOException {
145: outputChunk.setBytes(b, off, len);
146: buffer.doWrite(outputChunk, null);
147: }
148:
149: public void flush() throws IOException {
150: }
151:
152: public void close() throws IOException {
153: }
154: }
155:
156: }
|