forked from I2P_Developers/i2p.i2p
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:
@@ -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 {
|
||||
|
@@ -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) {
|
||||
|
Reference in New Issue
Block a user