diff --git a/smack-compression-jzlib/src/main/java/org/jivesoftware/smack/compression/jzlib/JzlibInputOutputStream.java b/smack-compression-jzlib/src/main/java/org/jivesoftware/smack/compression/jzlib/JzlibInputOutputStream.java index 356eef8a0..68e4d16d5 100644 --- a/smack-compression-jzlib/src/main/java/org/jivesoftware/smack/compression/jzlib/JzlibInputOutputStream.java +++ b/smack-compression-jzlib/src/main/java/org/jivesoftware/smack/compression/jzlib/JzlibInputOutputStream.java @@ -58,7 +58,9 @@ public class JzlibInputOutputStream extends XMPPInputOutputStream { @Override public OutputStream getOutputStream(OutputStream outputStream) throws IOException { final DeflaterOutputStream os = new DeflaterOutputStream(outputStream); - os.setSyncFlush(true); + if (flushMethod == FlushMethod.SYNC_FLUSH) { + os.setSyncFlush(true); + } return os; } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/compression/Java7ZlibInputOutputStream.java b/smack-core/src/main/java/org/jivesoftware/smack/compression/Java7ZlibInputOutputStream.java index 906a8e1f0..0f7933faa 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/compression/Java7ZlibInputOutputStream.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/compression/Java7ZlibInputOutputStream.java @@ -48,6 +48,9 @@ public class Java7ZlibInputOutputStream extends XMPPInputOutputStream { private final static boolean supported; private final static int compressionLevel = Deflater.DEFAULT_COMPRESSION; + private static final int SYNC_FLUSH_INT = 2; + private static final int FULL_FLUSH_INT = 3; + static { Method m = null; try { @@ -100,25 +103,23 @@ public class Java7ZlibInputOutputStream extends XMPPInputOutputStream { @Override public OutputStream getOutputStream(OutputStream outputStream) { + final int flushMethodInt; + if (flushMethod == FlushMethod.SYNC_FLUSH) { + flushMethodInt = SYNC_FLUSH_INT; + } else { + flushMethodInt = FULL_FLUSH_INT; + } return new DeflaterOutputStream(outputStream, new Deflater(compressionLevel)) { public void flush() throws IOException { if (!supported) { super.flush(); return; } - int count = 0; - if (!def.needsInput()) { - do { - count = def.deflate(buf, 0, buf.length); - out.write(buf, 0, count); - } while (count > 0); - out.flush(); - } try { - do { - count = (Integer) method.invoke(def, buf, 0, buf.length, 2); + int count; + while ((count = (Integer) method.invoke(def, buf, 0, buf.length, flushMethodInt)) != 0) { out.write(buf, 0, count); - } while (count > 0); + } } catch (IllegalArgumentException e) { throw new IOException("Can't flush"); } catch (IllegalAccessException e) { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/compression/XMPPInputOutputStream.java b/smack-core/src/main/java/org/jivesoftware/smack/compression/XMPPInputOutputStream.java index 41308243f..6fd289325 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/compression/XMPPInputOutputStream.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/compression/XMPPInputOutputStream.java @@ -20,6 +20,21 @@ import java.io.InputStream; import java.io.OutputStream; public abstract class XMPPInputOutputStream { + + protected static FlushMethod flushMethod; + + /** + * Set the used flushed method when compressing data. The default is full flush which may not + * achieve the best compression ratio, but provides better security against certain attacks. + * Only use sync flush if you fully understand the implications. + * + * @see Attacks against XMPP when using compression + * @param flushMethod + */ + public static void setFlushMethod(FlushMethod flushMethod) { + XMPPInputOutputStream.flushMethod = flushMethod; + } + protected String compressionMethod; public String getCompressionMethod() { @@ -31,4 +46,9 @@ public abstract class XMPPInputOutputStream { public abstract InputStream getInputStream(InputStream inputStream) throws Exception; public abstract OutputStream getOutputStream(OutputStream outputStream) throws Exception; + + public enum FlushMethod { + FULL_FLUSH, + SYNC_FLUSH, + } }