Author: markt
Date: Tue Sep 7 16:01:38 2010
New Revision: 993406
URL: http://svn.apache.org/viewvc?rev=993406&view=rev
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=48738
Add flush support for gzip'd output
Added:
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/filters/FlushableGZIPOutputStream.java
(with props)
Modified:
tomcat/tc6.0.x/trunk/STATUS.txt
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalAprOutputBuffer.java
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalNioOutputBuffer.java
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalOutputBuffer.java
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/filters/GzipOutputFilter.java
tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
Modified: tomcat/tc6.0.x/trunk/STATUS.txt
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=993406&r1=993405&r2=993406&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/STATUS.txt (original)
+++ tomcat/tc6.0.x/trunk/STATUS.txt Tue Sep 7 16:01:38 2010
@@ -160,12 +160,6 @@ PATCHES PROPOSED TO BACKPORT:
-1:
rjung: s/vesion/version/g
-* Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=48738
- Add flush support for gzip'd output
- https://issues.apache.org/bugzilla/attachment.cgi?id=25932
- +1: markt, rjung, kfujino
- -1:
-
* Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=49749
Add httpOnly support to SSO cookie
http://people.apache.org/~markt/patches/2010-08-25-bug49749.patch
Modified:
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalAprOutputBuffer.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalAprOutputBuffer.java?rev=993406&r1=993405&r2=993406&view=diff
==============================================================================
---
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalAprOutputBuffer.java
(original)
+++
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalAprOutputBuffer.java
Tue Sep 7 16:01:38 2010
@@ -31,6 +31,7 @@ import org.apache.tomcat.util.res.String
import org.apache.coyote.ActionCode;
import org.apache.coyote.OutputBuffer;
import org.apache.coyote.Response;
+import org.apache.coyote.http11.filters.GzipOutputFilter;
/**
* Output buffer.
@@ -94,6 +95,12 @@ public class InternalAprOutputBuffer
protected static StringManager sm =
StringManager.getManager(Constants.Package);
+ /**
+ * Logger.
+ */
+ private static final org.apache.juli.logging.Log log
+ = org.apache.juli.logging.LogFactory.getLog(
+ InternalAprOutputBuffer.class);
// ----------------------------------------------------- Instance Variables
@@ -280,6 +287,19 @@ public class InternalAprOutputBuffer
}
+ // go through the filters and if there is gzip filter
+ // invoke it to flush
+ for (int i = 0; i <= lastActiveFilter; i++) {
+ if (activeFilters[i] instanceof GzipOutputFilter) {
+ if (log.isDebugEnabled()) {
+ log.debug("Flushing the gzip filter at position " + i +
+ " of the filter chain...");
+ }
+ ((GzipOutputFilter) activeFilters[i]).flush();
+ break;
+ }
+ }
+
// Flush the current buffer
flushBuffer();
Modified:
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalNioOutputBuffer.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalNioOutputBuffer.java?rev=993406&r1=993405&r2=993406&view=diff
==============================================================================
---
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalNioOutputBuffer.java
(original)
+++
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalNioOutputBuffer.java
Tue Sep 7 16:01:38 2010
@@ -25,6 +25,7 @@ import java.nio.channels.Selector;
import org.apache.coyote.ActionCode;
import org.apache.coyote.OutputBuffer;
import org.apache.coyote.Response;
+import org.apache.coyote.http11.filters.GzipOutputFilter;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.CharChunk;
import org.apache.tomcat.util.buf.MessageBytes;
@@ -34,7 +35,6 @@ import org.apache.tomcat.util.net.NioCha
import org.apache.tomcat.util.net.NioEndpoint;
import org.apache.tomcat.util.net.NioSelectorPool;
import org.apache.tomcat.util.res.StringManager;
-import java.io.EOFException;
import org.apache.tomcat.util.MutableInteger;
/**
@@ -103,6 +103,12 @@ public class InternalNioOutputBuffer
protected static StringManager sm =
StringManager.getManager(Constants.Package);
+ /**
+ * Logger.
+ */
+ private static final org.apache.juli.logging.Log log
+ = org.apache.juli.logging.LogFactory.getLog(
+ InternalNioOutputBuffer.class);
// ----------------------------------------------------- Instance Variables
@@ -296,6 +302,19 @@ public class InternalNioOutputBuffer
}
+ // go through the filters and if there is gzip filter
+ // invoke it to flush
+ for (int i = 0; i <= lastActiveFilter; i++) {
+ if (activeFilters[i] instanceof GzipOutputFilter) {
+ if (log.isDebugEnabled()) {
+ log.debug("Flushing the gzip filter at position " + i +
+ " of the filter chain...");
+ }
+ ((GzipOutputFilter) activeFilters[i]).flush();
+ break;
+ }
+ }
+
// Flush the current buffer
flushBuffer();
Modified:
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalOutputBuffer.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalOutputBuffer.java?rev=993406&r1=993405&r2=993406&view=diff
==============================================================================
---
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalOutputBuffer.java
(original)
+++
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/InternalOutputBuffer.java
Tue Sep 7 16:01:38 2010
@@ -32,6 +32,7 @@ import org.apache.tomcat.util.res.String
import org.apache.coyote.ActionCode;
import org.apache.coyote.OutputBuffer;
import org.apache.coyote.Response;
+import org.apache.coyote.http11.filters.GzipOutputFilter;
/**
* Output buffer.
@@ -90,6 +91,11 @@ public class InternalOutputBuffer
protected static StringManager sm =
StringManager.getManager(Constants.Package);
+ /**
+ * Logger.
+ */
+ private static final org.apache.juli.logging.Log log
+ =
org.apache.juli.logging.LogFactory.getLog(InternalOutputBuffer.class);
// ----------------------------------------------------- Instance Variables
@@ -294,6 +300,19 @@ public class InternalOutputBuffer
}
+ // go through the filters and if there is gzip filter
+ // invoke it to flush
+ for (int i = 0; i <= lastActiveFilter; i++) {
+ if (activeFilters[i] instanceof GzipOutputFilter) {
+ if (log.isDebugEnabled()) {
+ log.debug("Flushing the gzip filter at position " + i +
+ " of the filter chain...");
+ }
+ ((GzipOutputFilter) activeFilters[i]).flush();
+ break;
+ }
+ }
+
// Flush the current buffer
if (useSocketBuffer) {
socketBuffer.flushBuffer();
Added:
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/filters/FlushableGZIPOutputStream.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/filters/FlushableGZIPOutputStream.java?rev=993406&view=auto
==============================================================================
---
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/filters/FlushableGZIPOutputStream.java
(added)
+++
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/filters/FlushableGZIPOutputStream.java
Tue Sep 7 16:01:38 2010
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.coyote.http11.filters;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.Deflater;
+import java.util.zip.GZIPOutputStream;
+
+/**
+ * Extension of {...@link GZIPOutputStream} to workaround for a couple of long
+ * standing JDK bugs
+ * (<a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4255743">Bug
+ * 4255743</a> and
+ * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4813885">Bug
+ * 4813885</a>) so the GZIP'd output can be flushed.
+ */
+public class FlushableGZIPOutputStream extends GZIPOutputStream {
+ public FlushableGZIPOutputStream(OutputStream os) throws IOException {
+ super(os);
+ }
+
+ private static final byte[] EMPTYBYTEARRAY = new byte[0];
+ private boolean hasData = false;
+
+ /**
+ * Here we make sure we have received data, so that the header has been for
+ * sure written to the output stream already.
+ */
+ @Override
+ public synchronized void write(byte[] bytes, int i, int i1)
+ throws IOException {
+ super.write(bytes, i, i1);
+ hasData = true;
+ }
+
+ @Override
+ public synchronized void write(int i) throws IOException {
+ super.write(i);
+ hasData = true;
+ }
+
+ @Override
+ public synchronized void write(byte[] bytes) throws IOException {
+ super.write(bytes);
+ hasData = true;
+ }
+
+ @Override
+ public synchronized void flush() throws IOException {
+ if (!hasData) {
+ return; // do not allow the gzip header to be flushed on its own
+ }
+
+ // trick the deflater to flush
+ /**
+ * Now this is tricky: We force the Deflater to flush its data by
+ * switching compression level. As yet, a perplexingly simple
workaround
+ * for
+ * http://developer.java.sun.com/developer/bugParade/bugs/4255743.html
+ */
+ if (!def.finished()) {
+ def.setInput(EMPTYBYTEARRAY, 0, 0);
+
+ def.setLevel(Deflater.NO_COMPRESSION);
+ deflate();
+
+ def.setLevel(Deflater.DEFAULT_COMPRESSION);
+ deflate();
+
+ out.flush();
+ }
+
+ hasData = false; // no more data to flush
+ }
+
+ /*
+ * Keep on calling deflate until it runs dry. The default implementation
+ * only does it once and can therefore hold onto data when they need to be
+ * flushed out.
+ */
+ @Override
+ protected void deflate() throws IOException {
+ int len;
+ do {
+ len = def.deflate(buf, 0, buf.length);
+ if (len > 0) {
+ out.write(buf, 0, len);
+ }
+ } while (len != 0);
+ }
+
+}
Propchange:
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/filters/FlushableGZIPOutputStream.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/filters/GzipOutputFilter.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/filters/GzipOutputFilter.java?rev=993406&r1=993405&r2=993406&view=diff
==============================================================================
---
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/filters/GzipOutputFilter.java
(original)
+++
tomcat/tc6.0.x/trunk/java/org/apache/coyote/http11/filters/GzipOutputFilter.java
Tue Sep 7 16:01:38 2010
@@ -42,6 +42,13 @@ public class GzipOutputFilter implements
protected static final ByteChunk ENCODING = new ByteChunk();
+ /**
+ * Logger.
+ */
+ protected static org.apache.juli.logging.Log log =
+ org.apache.juli.logging.LogFactory.getLog(GzipOutputFilter.class);
+
+
// ----------------------------------------------------- Static Initializer
@@ -82,7 +89,7 @@ public class GzipOutputFilter implements
public int doWrite(ByteChunk chunk, Response res)
throws IOException {
if (compressionStream == null) {
- compressionStream = new GZIPOutputStream(fakeOutputStream);
+ compressionStream = new
FlushableGZIPOutputStream(fakeOutputStream);
}
compressionStream.write(chunk.getBytes(), chunk.getStart(),
chunk.getLength());
@@ -92,6 +99,23 @@ public class GzipOutputFilter implements
// --------------------------------------------------- OutputFilter Methods
+ /**
+ * Added to allow flushing to happen for the gzip'ed outputstream
+ */
+ public void flush() {
+ if (compressionStream != null) {
+ try {
+ if (log.isDebugEnabled()) {
+ log.debug("Flushing the compression stream!");
+ }
+ compressionStream.flush();
+ } catch (IOException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Ignored exception while flushing gzip filter",
e);
+ }
+ }
+ }
+ }
/**
* Some filters need additional parameters from the response. All the
@@ -117,7 +141,7 @@ public class GzipOutputFilter implements
public long end()
throws IOException {
if (compressionStream == null) {
- compressionStream = new GZIPOutputStream(fakeOutputStream);
+ compressionStream = new
FlushableGZIPOutputStream(fakeOutputStream);
}
compressionStream.finish();
compressionStream.close();
Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=993406&r1=993405&r2=993406&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Tue Sep 7 16:01:38 2010
@@ -61,6 +61,14 @@
</fix>
</changelog>
</subsection>
+ <subsection name="Coyote">
+ <changelog>
+ <add>
+ <bug>48738</bug>: Add support for flushing gzipped output. Based on a
+ patch by Jiong Wang. (markt)
+ </add>
+ </changelog>
+ </subsection>
<subsection name="Cluster">
<changelog>
<fix>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]