2005-09-16 jrandom

* Adjust I2PTunnelHTTPServer so it can be used for outproxy operators
      (just specify the spoofed host as an empty string), allowing them to
      honor x-i2p-gzip encoding.
    * Let windows users build the exes too (thanks bar and redzara!)
    * Allow I2PTunnel httpserver operators to disable gzip compression on
      individual tunnels with the i2ptunnel.gzip=false client option
      (good idea susi!)
This commit is contained in:
jrandom
2005-09-16 18:28:26 +00:00
committed by zzz
parent 3aba12631b
commit dab1b4d256
7 changed files with 547 additions and 31 deletions

View File

@@ -42,9 +42,9 @@ class HTTPResponseOutputStream extends FilterOutputStream {
public HTTPResponseOutputStream(OutputStream raw) {
super(raw);
_context = I2PAppContext.getGlobalContext();
_context.statManager().createRateStat("i2ptunnel.http.compressionRatio", "ratio of compressed size to decompressed size after transfer", "i2ptunnel", new long[] { 60*1000, 30*60*1000 });
_context.statManager().createRateStat("i2ptunnel.http.compressed", "compressed size transferred", "i2ptunnel", new long[] { 60*1000, 30*60*1000 });
_context.statManager().createRateStat("i2ptunnel.http.expanded", "size transferred after expansion", "i2ptunnel", new long[] { 60*1000, 30*60*1000 });
_context.statManager().createRateStat("i2ptunnel.httpCompressionRatio", "ratio of compressed size to decompressed size after transfer", "i2ptunnel", new long[] { 60*1000, 30*60*1000 });
_context.statManager().createRateStat("i2ptunnel.httpCompressed", "compressed size transferred", "i2ptunnel", new long[] { 60*1000, 30*60*1000 });
_context.statManager().createRateStat("i2ptunnel.httpExpanded", "size transferred after expansion", "i2ptunnel", new long[] { 60*1000, 30*60*1000 });
_log = _context.logManager().getLog(getClass());
_cache = ByteCache.getInstance(8, CACHE_SIZE);
_headerBuffer = _cache.acquire();
@@ -175,15 +175,17 @@ class HTTPResponseOutputStream extends FilterOutputStream {
out.write("Proxy-Connection: close\n".getBytes());
finishHeaders();
boolean shouldCompress = shouldCompress();
if (_log.shouldLog(Log.INFO))
_log.info("After headers: gzip? " + _gzip + " compress? " + shouldCompress);
// done, shove off
if (_headerBuffer.getData().length == CACHE_SIZE)
_cache.release(_headerBuffer);
else
_headerBuffer = null;
if (_log.shouldLog(Log.INFO))
_log.info("After headers: gzip? " + _gzip);
if (shouldCompress()) {
if (shouldCompress) {
beginProcessing();
}
}
@@ -212,34 +214,37 @@ class HTTPResponseOutputStream extends FilterOutputStream {
public void run() {
OutputStream to = null;
InternalGZIPInputStream in = null;
long start = System.currentTimeMillis();
long written = 0;
try {
long start = System.currentTimeMillis();
in = new InternalGZIPInputStream(_in);
byte buf[] = new byte[8192];
int read = -1;
while ( (read = in.read(buf)) != -1) {
if (_log.shouldLog(Log.INFO))
_log.info("Read " + read + " and writing it to the browser/streams");
if (_log.shouldLog(Log.DEBUG))
_log.debug("Read " + read + " and writing it to the browser/streams");
_out.write(buf, 0, read);
_out.flush();
written += read;
}
if (_log.shouldLog(Log.INFO))
_log.info("Decompressed: " + _dataWritten + ", " + in.getTotalRead() + "/" + in.getTotalExpanded());
long end = System.currentTimeMillis();
long compressed = in.getTotalRead();
long expanded = in.getTotalExpanded();
double ratio = 0;
if (expanded > 0)
ratio = compressed/expanded;
_context.statManager().addRateData("i2ptunnel.http.compressionRatio", (int)(100d*ratio), end-start);
_context.statManager().addRateData("i2ptunnel.http.compressed", compressed, end-start);
_context.statManager().addRateData("i2ptunnel.http.expanded", expanded, end-start);
_log.info("Decompressed: " + written + ", " + in.getTotalRead() + "/" + in.getTotalExpanded());
} catch (IOException ioe) {
if (_log.shouldLog(Log.WARN))
_log.warn("Error decompressing: " + _dataWritten + ", " + in.getTotalRead() + "/" + in.getTotalExpanded(), ioe);
_log.warn("Error decompressing: " + written + ", " + in.getTotalRead() + "/" + in.getTotalExpanded(), ioe);
} finally {
if (_out != null) try { _out.close(); } catch (IOException ioe) {}
}
long end = System.currentTimeMillis();
long compressed = in.getTotalRead();
long expanded = in.getTotalExpanded();
double ratio = 0;
if (expanded > 0)
ratio = compressed/expanded;
_context.statManager().addRateData("i2ptunnel.httpCompressionRatio", (int)(100d*ratio), end-start);
_context.statManager().addRateData("i2ptunnel.httpCompressed", compressed, end-start);
_context.statManager().addRateData("i2ptunnel.httpExpanded", expanded, end-start);
}
}
private class InternalGZIPInputStream extends GZIPInputStream {

View File

@@ -68,7 +68,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
StringBuffer command = new StringBuffer(128);
Properties headers = readHeaders(in, command);
headers.setProperty("Host", _spoofHost);
if ( (_spoofHost != null) && (_spoofHost.trim().length() > 0) )
headers.setProperty("Host", _spoofHost);
headers.setProperty("Connection", "close");
String modifiedHeader = formatHeaders(headers, command);
@@ -83,10 +84,17 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
// request from the socket, modifies the headers, sends the request to the
// server, reads the response headers, rewriting to include Content-encoding: x-i2p-gzip
// if it was one of the Accept-encoding: values, and gzip the payload
Properties opts = getTunnel().getClientOptions();
boolean allowGZIP = true;
if (opts != null) {
String val = opts.getProperty("i2ptunnel.gzip");
if ( (val != null) && (!Boolean.valueOf(val).booleanValue()) )
allowGZIP = false;
}
String enc = headers.getProperty("Accept-encoding");
if (_log.shouldLog(Log.INFO))
_log.info("HTTP server encoding header: " + enc);
if ( (enc != null) && (enc.indexOf("x-i2p-gzip") >= 0) ) {
if ( allowGZIP && (enc != null) && (enc.indexOf("x-i2p-gzip") >= 0) ) {
I2PThread req = new I2PThread(new CompressedRequestor(s, socket, modifiedHeader), "http compressor");
req.start();
} else {
@@ -139,12 +147,13 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
browserout = _browser.getOutputStream();
serverin = _webserver.getInputStream();
Sender s = new Sender(new CompressedResponseOutputStream(browserout), serverin, "server: server to browser");
CompressedResponseOutputStream compressedOut = new CompressedResponseOutputStream(browserout);
Sender s = new Sender(compressedOut, serverin, "server: server to browser");
if (_log.shouldLog(Log.INFO))
_log.info("Before pumping the compressed response");
s.run(); // same thread
if (_log.shouldLog(Log.INFO))
_log.info("After pumping the compressed response");
_log.info("After pumping the compressed response: " + compressedOut.getTotalRead() + "/" + compressedOut.getTotalCompressed());
} catch (IOException ioe) {
if (_log.shouldLog(Log.WARN))
_log.warn("error compressing", ioe);
@@ -182,8 +191,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
_log.info(_name + ": Done sending: " + total);
_out.flush();
} catch (IOException ioe) {
if (_log.shouldLog(Log.WARN))
_log.warn("Error sending", ioe);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Error sending", ioe);
} finally {
if (_in != null) try { _in.close(); } catch (IOException ioe) {}
if (_out != null) try { _out.close(); } catch (IOException ioe) {}
@@ -191,6 +200,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
}
}
private class CompressedResponseOutputStream extends HTTPResponseOutputStream {
private InternalGZIPOutputStream _gzipOut;
public CompressedResponseOutputStream(OutputStream o) {
super(o);
}
@@ -207,8 +217,18 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
if (_log.shouldLog(Log.INFO))
_log.info("Beginning compression processing");
out.flush();
out = new GZIPOutputStream(out);
_gzipOut = new InternalGZIPOutputStream(out);
out = _gzipOut;
}
public long getTotalRead() { return _gzipOut.getTotalRead(); }
public long getTotalCompressed() { return _gzipOut.getTotalCompressed(); }
}
private class InternalGZIPOutputStream extends GZIPOutputStream {
public InternalGZIPOutputStream(OutputStream target) throws IOException {
super(target);
}
public long getTotalRead() { return super.def.getTotalIn(); }
public long getTotalCompressed() { return super.def.getTotalOut(); }
}
private String formatHeaders(Properties headers, StringBuffer command) {