From e6d44a6199ef7832c9ca386d74b090ec825a7de7 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Mon, 19 Sep 2011 23:50:25 +0000 Subject: [PATCH] * I2PTunnelHTTPServer: Don't compress small responses or images --- .../i2ptunnel/HTTPResponseOutputStream.java | 17 +++++++- .../i2p/i2ptunnel/I2PTunnelHTTPServer.java | 41 +++++++++++++++++-- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java index 7be986cc86..441c863f9a 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java @@ -46,6 +46,9 @@ class HTTPResponseOutputStream extends FilterOutputStream { private final byte _buf1[]; protected boolean _gzip; private long _dataWritten; + protected long _dataExpected; + protected String _contentType; + private static final int CACHE_SIZE = 8*1024; private static final ByteCache _cache = ByteCache.getInstance(8, CACHE_SIZE); // OOM DOS prevention @@ -130,10 +133,11 @@ class HTTPResponseOutputStream extends FilterOutputStream { } /** - * Tweak that first HTTP response line (HTTP 200 OK, etc) + * Possibly tweak that first HTTP response line (HTTP/1.0 200 OK, etc). + * Overridden on server side. * */ - protected static String filterResponseLine(String line) { + protected String filterResponseLine(String line) { return line; } @@ -184,6 +188,15 @@ class HTTPResponseOutputStream extends FilterOutputStream { } else if ("Proxy-Authenticate".equalsIgnoreCase(key)) { // filter this hop-by-hop header; outproxy authentication must be configured in I2PTunnelHTTPClient } else { + if ("Content-Length".equalsIgnoreCase(key)) { + // save for compress decision on server side + try { + _dataExpected = Long.parseLong(val); + } catch (NumberFormatException nfe) {} + } else if ("Content-Type".equalsIgnoreCase(key)) { + // save for compress decision on server side + _contentType = val; + } out.write((key.trim() + ": " + val.trim() + "\r\n").getBytes()); } break; diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java index d44f5539a9..ea665e398e 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java @@ -303,19 +303,48 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { } } + /** + * This plus a typ. HTTP response header will fit into a 1730-byte streaming message. + */ + private static final int MIN_TO_COMPRESS = 1300; + private static class CompressedResponseOutputStream extends HTTPResponseOutputStream { private InternalGZIPOutputStream _gzipOut; + public CompressedResponseOutputStream(OutputStream o) { super(o); + _dataExpected = -1; } + /** + * Overridden to peek at response code. Always returns line. + */ + @Override + protected String filterResponseLine(String line) { + String[] s = line.split(" ", 3); + if (s.length > 1 && + (s[1].startsWith("3") || s[1].startsWith("5"))) + _dataExpected = 0; + return line; + } + + /** + * Don't compress small responses or images. + * Compression is inline but decompression on the client side + * creates a new thread. + */ @Override - protected boolean shouldCompress() { return true; } + protected boolean shouldCompress() { + return (_dataExpected < 0 || _dataExpected >= MIN_TO_COMPRESS) && + (_contentType == null || !_contentType.startsWith("image/")); + } + @Override protected void finishHeaders() throws IOException { //if (_log.shouldLog(Log.INFO)) // _log.info("Including x-i2p-gzip as the content encoding in the response"); - out.write("Content-encoding: x-i2p-gzip\r\n".getBytes()); + if (shouldCompress()) + out.write("Content-encoding: x-i2p-gzip\r\n".getBytes()); super.finishHeaders(); } @@ -324,9 +353,12 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { //if (_log.shouldLog(Log.INFO)) // _log.info("Beginning compression processing"); //out.flush(); - _gzipOut = new InternalGZIPOutputStream(out); - out = _gzipOut; + if (shouldCompress()) { + _gzipOut = new InternalGZIPOutputStream(out); + out = _gzipOut; + } } + public long getTotalRead() { InternalGZIPOutputStream gzipOut = _gzipOut; if (gzipOut != null) @@ -334,6 +366,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { else return 0; } + public long getTotalCompressed() { InternalGZIPOutputStream gzipOut = _gzipOut; if (gzipOut != null) -- GitLab