Mercurial > hg > icedtea8-forest > jdk
changeset 13246:80cebaab0ba5 icedtea-3.7.0 icedtea-3.8.0pre00
8189789, PR3530: tomcat gzip-compressed response bodies appear to be broken in update 151
Reviewed-by: sherman, phh
author | coffeys |
---|---|
date | Mon, 27 Nov 2017 16:53:29 +0000 |
parents | ad4f878bb2fc |
children | a811784cc994 |
files | src/share/native/java/util/zip/Deflater.c src/share/native/java/util/zip/zlib/deflate.c src/share/native/java/util/zip/zlib/patches/ChangeLog_java test/java/util/zip/InflateIn_DeflateOut.java |
diffstat | 4 files changed, 127 insertions(+), 13 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/native/java/util/zip/Deflater.c Thu Feb 08 20:13:38 2018 +0000 +++ b/src/share/native/java/util/zip/Deflater.c Mon Nov 27 16:53:29 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -164,17 +164,14 @@ res = deflateParams(strm, level, strategy); (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0); (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0); - switch (res) { case Z_OK: (*env)->SetBooleanField(env, this, setParamsID, JNI_FALSE); + case Z_BUF_ERROR: this_off += this_len - strm->avail_in; (*env)->SetIntField(env, this, offID, this_off); (*env)->SetIntField(env, this, lenID, strm->avail_in); return (jint) (len - strm->avail_out); - case Z_BUF_ERROR: - (*env)->SetBooleanField(env, this, setParamsID, JNI_FALSE); - return 0; default: JNU_ThrowInternalError(env, strm->msg); return 0; @@ -203,18 +200,16 @@ res = deflate(strm, finish ? Z_FINISH : flush); (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0); (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0); - switch (res) { case Z_STREAM_END: (*env)->SetBooleanField(env, this, finishedID, JNI_TRUE); /* fall through */ case Z_OK: + case Z_BUF_ERROR: this_off += this_len - strm->avail_in; (*env)->SetIntField(env, this, offID, this_off); (*env)->SetIntField(env, this, lenID, strm->avail_in); return len - strm->avail_out; - case Z_BUF_ERROR: - return 0; default: JNU_ThrowInternalError(env, strm->msg); return 0;
--- a/src/share/native/java/util/zip/zlib/deflate.c Thu Feb 08 20:13:38 2018 +0000 +++ b/src/share/native/java/util/zip/zlib/deflate.c Mon Nov 27 16:53:29 2017 +0000 @@ -505,8 +505,6 @@ s->pending = 0; s->pending_out = s->pending_buf; - s->high_water = 0; /* reset to its inital value 0 */ - if (s->wrap < 0) { s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } @@ -520,7 +518,7 @@ s->wrap == 2 ? crc32(0L, Z_NULL, 0) : #endif adler32(0L, Z_NULL, 0); - s->last_flush = Z_NO_FLUSH; + s->last_flush = -2; _tr_init(s); @@ -613,7 +611,7 @@ func = configuration_table[s->level].func; if ((strategy != s->strategy || func != configuration_table[level].func) && - s->high_water) { + s->last_flush != -2) { /* Flush the last buffer: */ int err = deflate(strm, Z_BLOCK); if (err == Z_STREAM_ERROR)
--- a/src/share/native/java/util/zip/zlib/patches/ChangeLog_java Thu Feb 08 20:13:38 2018 +0000 +++ b/src/share/native/java/util/zip/zlib/patches/ChangeLog_java Mon Nov 27 16:53:29 2017 +0000 @@ -78,6 +78,8 @@ (6) deflate.c #8184306 +(7) deflate.c undo (6), replaced withe the official zlib repo fix see#305/#f969409 + *** 503,512 **** --- 503,514 ----
--- a/test/java/util/zip/InflateIn_DeflateOut.java Thu Feb 08 20:13:38 2018 +0000 +++ b/test/java/util/zip/InflateIn_DeflateOut.java Mon Nov 27 16:53:29 2017 +0000 @@ -23,7 +23,7 @@ /** * @test - * @bug 4206909 4813885 + * @bug 4206909 4813885 8189789 * @summary Test basic functionality of DeflaterOutputStream/InflaterInputStream and GZIPOutputStream/GZIPInputStream, including flush * @key randomness */ @@ -147,6 +147,47 @@ check(Arrays.equals(data, buf)); } + private static void TestFlushableGZIPOutputStream() throws Throwable { + Random random = new Random(new Date().getTime()); + + ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(); + OutputStream output = new FlushableGZIPOutputStream(byteOutStream); + + byte[] data = new byte[random.nextInt(1024 * 1024)]; + byte[] buf = new byte[data.length]; + random.nextBytes(data); + + output.write(data); + for (int i=0; i<data.length; i++) { + output.write(data[i]); + } + output.flush(); + for (int i=0; i<data.length; i++) { + output.write(data[i]); + } + output.write(data); + output.close(); + + ByteArrayInputStream byteInStream = + new ByteArrayInputStream(byteOutStream.toByteArray()); + + GZIPInputStream gzis = new GZIPInputStream(byteInStream); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int numRead; + byte[] b = new byte[4 * 1024]; + try { + while ((numRead = gzis.read(buf)) >= 0) { + baos.write(b, 0, numRead); + } + } finally { + baos.close(); + } + + byte[] decompressedBytes = baos.toByteArray(); + + check(decompressedBytes.length == data.length * 4); + } + private static void check(InputStream is, OutputStream os) throws Throwable { @@ -268,6 +309,7 @@ LineOrientedProtocol(); GZWriteFlushRead(); GZLineOrientedProtocol(); + TestFlushableGZIPOutputStream(); } //--------------------- Infrastructure --------------------------- @@ -285,3 +327,80 @@ System.out.println("\nPassed = " + passed + " failed = " + failed); if (failed > 0) throw new AssertionError("Some tests failed");} } + +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); + } + +}