forked from I2P_Developers/i2p.i2p
New interface and context hooks for in-jvm outproxy
Support in HTTP client proxy All preliminary, maybe better to use ClientAppManager?
This commit is contained in:
@ -29,6 +29,7 @@ import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.i2ptunnel.localServer.LocalHTTPServer;
|
||||
import net.i2p.outproxy.Outproxy;
|
||||
import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.PortMapper;
|
||||
@ -320,6 +321,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
public static final String PROP_VIA = "i2ptunnel.httpclient.sendVia";
|
||||
public static final String PROP_JUMP_SERVERS = "i2ptunnel.httpclient.jumpServers";
|
||||
public static final String PROP_DISABLE_HELPER = "i2ptunnel.httpclient.disableAddressHelper";
|
||||
public static final String PROP_OUTPROXY = "i2ptunnel.useLocalOutproxy";
|
||||
|
||||
protected void clientConnectionRun(Socket s) {
|
||||
OutputStream out = null;
|
||||
@ -330,6 +332,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
String targetRequest = null;
|
||||
|
||||
boolean usingWWWProxy = false;
|
||||
boolean usingOutproxy = false;
|
||||
Outproxy outproxy = null;
|
||||
boolean usingInternalServer = false;
|
||||
String internalPath = null;
|
||||
String internalRawQuery = null;
|
||||
@ -677,34 +681,47 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
s.close();
|
||||
return;
|
||||
} else if(host.contains(".") || host.startsWith("[")) {
|
||||
if(port >= 0) {
|
||||
host = host + ':' + port;
|
||||
}
|
||||
// The request must be forwarded to a WWW proxy
|
||||
if(_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("Before selecting outproxy for " + host);
|
||||
}
|
||||
currentProxy = selectProxy();
|
||||
if(_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("After selecting outproxy for " + host + ": " + currentProxy);
|
||||
}
|
||||
if(currentProxy == null) {
|
||||
if(_log.shouldLog(Log.WARN)) {
|
||||
_log.warn(getPrefix(requestId) + "Host wants to be outproxied, but we dont have any!");
|
||||
if (Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_OUTPROXY)) &&
|
||||
(outproxy = _context.outproxy()) != null) {
|
||||
int rPort = requestURI.getPort();
|
||||
if (rPort > 0)
|
||||
remotePort = rPort;
|
||||
else
|
||||
remotePort = 80;
|
||||
usingOutproxy = true;
|
||||
targetRequest = requestURI.toASCIIString();
|
||||
if(_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix(requestId) + " [" + host + "]: outproxy!");
|
||||
} else {
|
||||
if(port >= 0) {
|
||||
host = host + ':' + port;
|
||||
}
|
||||
l.log("No HTTP outproxy found for the request.");
|
||||
if(out != null) {
|
||||
out.write(getErrorPage("noproxy", _ERR_NO_OUTPROXY));
|
||||
writeFooter(out);
|
||||
// The request must be forwarded to a WWW proxy
|
||||
if(_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("Before selecting outproxy for " + host);
|
||||
}
|
||||
currentProxy = selectProxy();
|
||||
if(_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("After selecting outproxy for " + host + ": " + currentProxy);
|
||||
}
|
||||
if(currentProxy == null) {
|
||||
if(_log.shouldLog(Log.WARN)) {
|
||||
_log.warn(getPrefix(requestId) + "Host wants to be outproxied, but we dont have any!");
|
||||
}
|
||||
l.log("No HTTP outproxy found for the request.");
|
||||
if(out != null) {
|
||||
out.write(getErrorPage("noproxy", _ERR_NO_OUTPROXY));
|
||||
writeFooter(out);
|
||||
}
|
||||
s.close();
|
||||
return;
|
||||
}
|
||||
destination = currentProxy;
|
||||
usingWWWProxy = true;
|
||||
targetRequest = requestURI.toASCIIString();
|
||||
if(_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug(getPrefix(requestId) + " [" + host + "]: wwwProxy!");
|
||||
}
|
||||
s.close();
|
||||
return;
|
||||
}
|
||||
destination = currentProxy;
|
||||
usingWWWProxy = true;
|
||||
targetRequest = requestURI.toASCIIString();
|
||||
if(_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug(getPrefix(requestId) + " [" + host + "]: wwwProxy!");
|
||||
}
|
||||
} else {
|
||||
// what is left for here? a hostname with no dots, and != "i2p"
|
||||
@ -722,7 +739,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
return;
|
||||
} // end host name processing
|
||||
|
||||
boolean isValid = usingWWWProxy || usingInternalServer || isSupportedAddress(host, protocol);
|
||||
boolean isValid = usingOutproxy || usingWWWProxy ||
|
||||
usingInternalServer || isSupportedAddress(host, protocol);
|
||||
if(!isValid) {
|
||||
if(_log.shouldLog(Log.INFO)) {
|
||||
_log.info(getPrefix(requestId) + "notValid(" + host + ")");
|
||||
@ -743,7 +761,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
// end first line processing
|
||||
|
||||
} else {
|
||||
if(lowercaseLine.startsWith("host: ") && !usingWWWProxy) {
|
||||
if(lowercaseLine.startsWith("host: ") && !usingWWWProxy && !usingOutproxy) {
|
||||
// Note that we only pass the original Host: line through to the outproxy
|
||||
// But we don't create a Host: line if it wasn't sent to us
|
||||
line = "Host: " + host;
|
||||
@ -815,7 +833,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
if(!shout) {
|
||||
if(!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_USER_AGENT))) {
|
||||
// let's not advertise to external sites that we are from I2P
|
||||
if(usingWWWProxy) {
|
||||
if(usingWWWProxy || usingOutproxy) {
|
||||
newRequest.append("User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6\r\n");
|
||||
} else {
|
||||
newRequest.append("User-Agent: MYOB/6.66 (AN/ON)\r\n");
|
||||
@ -848,7 +866,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
_log.debug(getPrefix(requestId) + "NewRequest header: [" + newRequest.toString() + "]");
|
||||
}
|
||||
|
||||
if(method == null || destination == null) {
|
||||
if(method == null || (destination == null && !usingOutproxy)) {
|
||||
//l.log("No HTTP method found in the request.");
|
||||
if(out != null) {
|
||||
if(protocol != null && "http".equals(protocol.toLowerCase(Locale.US))) {
|
||||
@ -896,6 +914,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
return;
|
||||
}
|
||||
|
||||
// no destination, going to outproxy plugin
|
||||
if (usingOutproxy) {
|
||||
Socket outSocket = outproxy.connect(host, remotePort);
|
||||
byte[] data = newRequest.toString().getBytes("ISO-8859-1");
|
||||
Runnable onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
|
||||
new I2PTunnelOutproxyRunner(s, outSocket, sockLock, data, onTimeout);
|
||||
return;
|
||||
}
|
||||
|
||||
// LOOKUP
|
||||
// If the host is "i2p", the getHostName() lookup failed, don't try to
|
||||
// look it up again as the naming service does not do negative caching
|
||||
|
@ -25,6 +25,7 @@ import net.i2p.crypto.TransientSessionKeyManager;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.RoutingKeyGenerator;
|
||||
import net.i2p.internal.InternalClientManager;
|
||||
import net.i2p.outproxy.Outproxy;
|
||||
import net.i2p.stat.StatManager;
|
||||
import net.i2p.update.UpdateManager;
|
||||
import net.i2p.util.Clock;
|
||||
@ -94,6 +95,7 @@ public class I2PAppContext {
|
||||
private SimpleTimer _simpleTimer;
|
||||
private SimpleTimer2 _simpleTimer2;
|
||||
private final PortMapper _portMapper;
|
||||
private Outproxy _outproxy;
|
||||
private volatile boolean _statManagerInitialized;
|
||||
private volatile boolean _sessionKeyManagerInitialized;
|
||||
private volatile boolean _namingServiceInitialized;
|
||||
@ -127,7 +129,8 @@ public class I2PAppContext {
|
||||
_lock5 = new Object(), _lock6 = new Object(), _lock7 = new Object(), _lock8 = new Object(),
|
||||
_lock9 = new Object(), _lock10 = new Object(), _lock11 = new Object(), _lock12 = new Object(),
|
||||
_lock13 = new Object(), _lock14 = new Object(), _lock15 = new Object(), _lock16 = new Object(),
|
||||
_lock17 = new Object(), _lock18 = new Object(), _lock19 = new Object(), _lock20 = new Object();
|
||||
_lock17 = new Object(), _lock18 = new Object(), _lock19 = new Object(), _lock20 = new Object(),
|
||||
_lock21 = new Object();
|
||||
|
||||
/**
|
||||
* Pull the default context, creating a new one if necessary, else using
|
||||
@ -1023,4 +1026,39 @@ public class I2PAppContext {
|
||||
public UpdateManager updateManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A local outproxy
|
||||
* @return The outproxy if it is registered, else null
|
||||
* @since 0.9.11
|
||||
*/
|
||||
public Outproxy outproxy() {
|
||||
return _outproxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register as the outproxy. For now, only one.
|
||||
* @throws IllegalStateException if one was already registered
|
||||
* @since 0.9.11
|
||||
*/
|
||||
public void registerOutproxy(Outproxy oproxy) {
|
||||
synchronized(_lock21) {
|
||||
if (_outproxy != null)
|
||||
throw new IllegalStateException();
|
||||
_outproxy = oproxy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister the outproxy.
|
||||
* @throws IllegalStateException if it was not registered
|
||||
* @since 0.9.11
|
||||
*/
|
||||
public void unregisterOutproxy(Outproxy oproxy) {
|
||||
synchronized(_lock21) {
|
||||
if (_outproxy != oproxy)
|
||||
throw new IllegalStateException();
|
||||
_outproxy = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
core/java/src/net/i2p/outproxy/Outproxy.java
Normal file
17
core/java/src/net/i2p/outproxy/Outproxy.java
Normal file
@ -0,0 +1,17 @@
|
||||
package net.i2p.outproxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 0.9.11
|
||||
*/
|
||||
public interface Outproxy {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public Socket connect(String host, int port) throws IOException;
|
||||
|
||||
}
|
Reference in New Issue
Block a user