Bug 57866 - FlushableGZIPOutputStream only compresses first flush()
Summary: FlushableGZIPOutputStream only compresses first flush()
Status: RESOLVED WONTFIX
Alias: None
Product: Tomcat 7
Classification: Unclassified
Component: Connectors (show other bugs)
Version: 7.0.54
Hardware: PC Linux
: P2 minor (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-04-28 09:57 UTC by j__n
Modified: 2015-04-28 12:44 UTC (History)
1 user (show)



Attachments
minimum webapp exhibiting issue (change server.xml webapps path and run with maven) (24.21 KB, application/x-tar-gz)
2015-04-28 09:57 UTC, j__n
Details

Note You need to log in before you can comment on or make changes to this bug.
Description j__n 2015-04-28 09:57:39 UTC
Created attachment 32695 [details]
minimum webapp exhibiting issue (change server.xml webapps path and run with maven)

Sorry if this bug is against the wrong component.  I'm not sure which component includes Coyote filters.

I have a servlet that streams its response, and I also need it to be compressed.  Looking in wireshark and stepping through FlushableGZIPOutputStream/GZIPOutputStream/Deflater it seems that only the data up to the first flush is being compressed.  deflateBytes seems to be called appropriately but after the first flush() the deflated bytes seem to be a binary header followed by uncompressed text.

My server environment uses Java 7, but I tried Java 6 in case FlushableGZIPOutputStream interferes with Java 7's Deflater.  (Both workaround/fix JDK bugs 4255743 and 4813885.)  Java 6 behaves the same as Java 7.
Comment 1 Konstantin Kolinko 2015-04-28 11:31:33 UTC
(In reply to j__n from comment #0)
> the deflated bytes seem to
> be a binary header followed by uncompressed text.

This is expected. There shall be several uncompressed bytes of data (one byte of data, if I remember correctly), but if you write more then the compression shall be re-enabled automatically.

See "flagReenableCompression" field in FlushableGZIPOutputStream.java
Comment 2 j__n 2015-04-28 11:38:21 UTC
Every byte of data remains uncompressed.  No data is compressed after the first flush.  Compression is [re]enabled, but Deflater doesn't actually compress anything, just makes every write bigger.
Comment 3 Konstantin Kolinko 2015-04-28 12:25:19 UTC
1. If Tomcat did call "def.setLevel(Deflater.DEFAULT_COMPRESSION);" but that call did not re-enable compression, that would be a bug in Deflater class.

From Tomcat point of view that is a WONTFIX. It is up to JRE vendor (Oracle) to fix their Deflater implementation.

(Disclaimer: I have not run your example yet. IIRC, when I tested it several years ago the compression was re-enabled successfully.)


2. See o.a.coyote.http11.filters.GzipOutputFilter #doWrite(ByteChunk chunk, Response res). That is where FlushableGZIPOutputStream is instantiated.

Tomcat 8 does not use FlushableGZIPOutputStream, but uses new Java7+ constructor for java.util.zip.GZIPOutputStream to enable flushing.

It should be possible to backport that to Tomcat 7 to call that constructor via reflection when running on Java 7+. (As such, this issue becomes an enhancement request).
Comment 4 j__n 2015-04-28 12:44:22 UTC
1. Thanks for that.  Tomcat did call "def.setLevel(Deflater.DEFAULT_COMPRESSION);" but that call did not re-enable compression.  I found a bug report upstream https://bugs.openjdk.java.net/browse/JDK-8020687 so it may be fixed in Java 8.  Will give it a try.

2. Thanks for that.  I'll give Tomcat 8 a try and open an RFE accordingly.