per mule's patch, added support for a round robin across multiple outproxies

instead of the standard 'httpclient 4444' or 'httpclient 4444 squid.i2p', you can now specify a comma delimited list of outproxies:
'httpclient 4444 squid.i2p,www1.squid.i2p,www2.squid.i2p' and each individual http request goes through a randomly selected proxy
there are a few general issues with this, such as a lack of affinity (web applications that require a session to always come from a single IP address will break)
but it should work most of the time.
This commit is contained in:
jrandom
2004-08-05 18:17:33 +00:00
committed by zzz
parent 4859cd7dcf
commit cdb4576bd7

View File

@ -9,8 +9,12 @@ import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException; import java.net.SocketException;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import net.i2p.I2PException; import net.i2p.I2PException;
import net.i2p.client.streaming.I2PSocket; import net.i2p.client.streaming.I2PSocket;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
@ -42,7 +46,7 @@ import net.i2p.util.Log;
public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable { public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable {
private static final Log _log = new Log(I2PTunnelHTTPClient.class); private static final Log _log = new Log(I2PTunnelHTTPClient.class);
private String wwwProxy; private List proxyList;
private final static byte[] ERR_REQUEST_DENIED = private final static byte[] ERR_REQUEST_DENIED =
("HTTP/1.1 403 Access Denied\r\n"+ ("HTTP/1.1 403 Access Denied\r\n"+
@ -95,9 +99,14 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
return; return;
} }
this.wwwProxy = wwwProxy; proxyList = new ArrayList();
if (wwwProxy != null) {
StringTokenizer tok = new StringTokenizer(wwwProxy, ",");
while (tok.hasMoreTokens())
proxyList.add(tok.nextToken().trim());
}
setName(getLocalPort() + " -> HTTPClient [WWW outproxy: " + this.wwwProxy + "]"); setName(getLocalPort() + " -> HTTPClient [WWW outproxy list: " + wwwProxy + "]");
startRunning(); startRunning();
@ -106,10 +115,20 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
private String getPrefix() { return "Client[" + _clientId + "]: "; } private String getPrefix() { return "Client[" + _clientId + "]: "; }
private String selectProxy() {
if (proxyList.size() <= 0) {
l.log("Proxy list is emtpy - no outproxy available");
return null;
}
int index = I2PAppContext.getGlobalContext().random().nextInt(proxyList.size()-1);
return (String)proxyList.get(index);
}
protected void clientConnectionRun(Socket s) { protected void clientConnectionRun(Socket s) {
OutputStream out = null; OutputStream out = null;
String targetRequest = null; String targetRequest = null;
boolean usingWWWProxy = false; boolean usingWWWProxy = false;
String currentProxy = null;
InactivityTimeoutThread timeoutThread = null; InactivityTimeoutThread timeoutThread = null;
try { try {
out = s.getOutputStream(); out = s.getOutputStream();
@ -160,7 +179,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
line = method + " " + request.substring(pos); line = method + " " + request.substring(pos);
} else if (host.indexOf(".") != -1) { } else if (host.indexOf(".") != -1) {
// The request must be forwarded to a WWW proxy // The request must be forwarded to a WWW proxy
destination = wwwProxy; currentProxy = selectProxy();
destination = currentProxy;
usingWWWProxy = true; usingWWWProxy = true;
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug(getPrefix() + "Host doesnt end with .i2p and it contains a period [" + host + "]: wwwProxy!"); _log.debug(getPrefix() + "Host doesnt end with .i2p and it contains a period [" + host + "]: wwwProxy!");
@ -242,25 +262,25 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
I2PSocket i2ps = createI2PSocket(dest); I2PSocket i2ps = createI2PSocket(dest);
byte[] data = newRequest.toString().getBytes("ISO-8859-1"); byte[] data = newRequest.toString().getBytes("ISO-8859-1");
I2PTunnelRunner runner = new I2PTunnelRunner(s, i2ps, sockLock, data); I2PTunnelRunner runner = new I2PTunnelRunner(s, i2ps, sockLock, data);
timeoutThread = new InactivityTimeoutThread(runner, out, targetRequest, usingWWWProxy, s); timeoutThread = new InactivityTimeoutThread(runner, out, targetRequest, usingWWWProxy, currentProxy, s);
timeoutThread.start(); timeoutThread.start();
} catch (SocketException ex) { } catch (SocketException ex) {
if (timeoutThread != null) timeoutThread.disable(); if (timeoutThread != null) timeoutThread.disable();
_log.info(getPrefix() + "Error trying to connect", ex); _log.info(getPrefix() + "Error trying to connect", ex);
l.log(ex.getMessage()); l.log(ex.getMessage());
handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, wwwProxy); handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, currentProxy);
closeSocket(s); closeSocket(s);
} catch (IOException ex) { } catch (IOException ex) {
if (timeoutThread != null) timeoutThread.disable(); if (timeoutThread != null) timeoutThread.disable();
_log.info(getPrefix() + "Error trying to connect", ex); _log.info(getPrefix() + "Error trying to connect", ex);
l.log(ex.getMessage()); l.log(ex.getMessage());
handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, wwwProxy); handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, currentProxy);
closeSocket(s); closeSocket(s);
} catch (I2PException ex) { } catch (I2PException ex) {
if (timeoutThread != null) timeoutThread.disable(); if (timeoutThread != null) timeoutThread.disable();
_log.info("getPrefix() + Error trying to connect", ex); _log.info("getPrefix() + Error trying to connect", ex);
l.log(ex.getMessage()); l.log(ex.getMessage());
handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, wwwProxy); handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, currentProxy);
closeSocket(s); closeSocket(s);
} }
} }
@ -275,16 +295,18 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
private OutputStream _out; private OutputStream _out;
private String _targetRequest; private String _targetRequest;
private boolean _useWWWProxy; private boolean _useWWWProxy;
private String _currentProxy;
private boolean _disabled; private boolean _disabled;
private Object _disableLock = new Object(); private Object _disableLock = new Object();
public InactivityTimeoutThread(I2PTunnelRunner runner, OutputStream out, String targetRequest, public InactivityTimeoutThread(I2PTunnelRunner runner, OutputStream out, String targetRequest,
boolean useWWWProxy, Socket s) { boolean useWWWProxy, String currentProxy, Socket s) {
this.s = s; this.s = s;
_runner = runner; _runner = runner;
_out = out; _out = out;
_targetRequest = targetRequest; _targetRequest = targetRequest;
_useWWWProxy = useWWWProxy; _useWWWProxy = useWWWProxy;
_currentProxy = currentProxy;
_disabled = false; _disabled = false;
long timeoutId = ++__timeoutId; long timeoutId = ++__timeoutId;
setName("InactivityThread " + getPrefix() + timeoutId); setName("InactivityThread " + getPrefix() + timeoutId);
@ -334,7 +356,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
if (_runner.getLastActivityOn() > 0) { if (_runner.getLastActivityOn() > 0) {
// some data has been sent, so don't 404 it // some data has been sent, so don't 404 it
} else { } else {
writeErrorMessage(ERR_TIMEOUT, _out, _targetRequest, _useWWWProxy, wwwProxy); writeErrorMessage(ERR_TIMEOUT, _out, _targetRequest, _useWWWProxy, _currentProxy);
} }
} catch (IOException ioe) { } catch (IOException ioe) {
_log.warn(getPrefix() + "Error writing out the 'timeout' message", ioe); _log.warn(getPrefix() + "Error writing out the 'timeout' message", ioe);