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:
@ -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);
|
||||||
|
Reference in New Issue
Block a user