-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Experimental SOCKS4a proxy support added, checkstyle changed, v4.2.5
- Loading branch information
Showing
8 changed files
with
624 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
src/main/java/ai/preferred/venom/socks/SocksConnectingIOReactor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package ai.preferred.venom.socks; | ||
|
||
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor; | ||
import org.apache.http.impl.nio.reactor.IOReactorConfig; | ||
import org.apache.http.nio.reactor.IOEventDispatch; | ||
import org.apache.http.nio.reactor.IOReactorException; | ||
|
||
import java.io.InterruptedIOException; | ||
import java.util.concurrent.ThreadFactory; | ||
|
||
/** | ||
* This IOReactor makes sure that the supplied {@link IOEventDispatch} is decorated with {@link SocksIOEventDispatch}. | ||
*/ | ||
public class SocksConnectingIOReactor extends DefaultConnectingIOReactor { | ||
|
||
/** | ||
* Creates an instance of SocksConnectingIOReactor with the given configuration. | ||
* | ||
* @param config I/O reactor configuration. | ||
* @param threadFactory the factory to create threads. | ||
* Can be {@code null}. | ||
* @throws IOReactorException in case if a non-recoverable I/O error. | ||
*/ | ||
public SocksConnectingIOReactor(IOReactorConfig config, ThreadFactory threadFactory) throws IOReactorException { | ||
super(config, threadFactory); | ||
} | ||
|
||
/** | ||
* Creates an instance of SocksConnectingIOReactor with the given configuration. | ||
* | ||
* @param config I/O reactor configuration. | ||
* Can be {@code null}. | ||
* @throws IOReactorException in case if a non-recoverable I/O error. | ||
*/ | ||
public SocksConnectingIOReactor(IOReactorConfig config) throws IOReactorException { | ||
super(config); | ||
} | ||
|
||
/** | ||
* Creates an instance of SocksConnectingIOReactor with default configuration. | ||
* | ||
* @throws IOReactorException in case if a non-recoverable I/O error. | ||
*/ | ||
public SocksConnectingIOReactor() throws IOReactorException { | ||
super(); | ||
} | ||
|
||
@Override | ||
public void execute(final IOEventDispatch eventDispatch) throws InterruptedIOException, IOReactorException { | ||
super.execute(new SocksIOEventDispatch(eventDispatch)); | ||
} | ||
|
||
} |
40 changes: 40 additions & 0 deletions
40
src/main/java/ai/preferred/venom/socks/SocksHttpRoutePlanner.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package ai.preferred.venom.socks; | ||
|
||
import com.google.common.annotations.Beta; | ||
import org.apache.http.HttpException; | ||
import org.apache.http.HttpHost; | ||
import org.apache.http.HttpRequest; | ||
import org.apache.http.conn.routing.HttpRoute; | ||
import org.apache.http.conn.routing.HttpRoutePlanner; | ||
import org.apache.http.protocol.HttpContext; | ||
|
||
/** | ||
* This route planners ensures that the connection to https server via socks proxy works. It prevents http client from | ||
* tunnelling the IO session twice ({@link SocksIOSessionStrategy} upgrades {@link SocksIOSession} to | ||
* {@link org.apache.http.nio.reactor.ssl.SSLIOSession} when necessary). | ||
*/ | ||
@Beta | ||
public class SocksHttpRoutePlanner implements HttpRoutePlanner { | ||
|
||
private final HttpRoutePlanner rp; | ||
|
||
/** | ||
* Decorates {@link HttpRoutePlanner}. | ||
* | ||
* @param rp decorated route planner | ||
*/ | ||
public SocksHttpRoutePlanner(final HttpRoutePlanner rp) { | ||
this.rp = rp; | ||
} | ||
|
||
@Override | ||
public HttpRoute determineRoute(HttpHost host, HttpRequest request, HttpContext context) throws HttpException { | ||
final HttpRoute route = rp.determineRoute(host, request, context); | ||
final boolean secure = "https".equalsIgnoreCase(route.getTargetHost().getSchemeName()); | ||
if (secure && route.getProxyHost() != null && "socks".equalsIgnoreCase(route.getProxyHost().getSchemeName())) { | ||
return new HttpRoute(route.getTargetHost(), route.getLocalAddress(), route.getProxyHost(), false); | ||
} | ||
return route; | ||
} | ||
|
||
} |
118 changes: 118 additions & 0 deletions
118
src/main/java/ai/preferred/venom/socks/SocksIOEventDispatch.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package ai.preferred.venom.socks; | ||
|
||
import org.apache.http.nio.NHttpClientConnection; | ||
import org.apache.http.nio.NHttpClientEventHandler; | ||
import org.apache.http.nio.NHttpConnection; | ||
import org.apache.http.nio.protocol.HttpAsyncRequestExecutor; | ||
import org.apache.http.nio.reactor.IOEventDispatch; | ||
import org.apache.http.nio.reactor.IOSession; | ||
|
||
import java.io.IOException; | ||
|
||
/** | ||
* This class wraps and handles IO dispatch related to {@link SocksIOSession}. | ||
*/ | ||
public class SocksIOEventDispatch implements IOEventDispatch { | ||
|
||
private final IOEventDispatch dispatch; | ||
|
||
/** | ||
* Decorates {@link IOEventDispatch}. | ||
* | ||
* @param dispatch delegated IO dispatch | ||
*/ | ||
public SocksIOEventDispatch(IOEventDispatch dispatch) { | ||
this.dispatch = dispatch; | ||
} | ||
|
||
@Override | ||
public void connected(IOSession session) { | ||
dispatch.connected(session); | ||
} | ||
|
||
@Override | ||
public void inputReady(IOSession session) { | ||
try { | ||
if (initializeSocksSession(session)) { | ||
dispatch.inputReady(session); | ||
} | ||
} catch (RuntimeException e) { | ||
session.shutdown(); | ||
throw e; | ||
} | ||
} | ||
|
||
@Override | ||
public void outputReady(IOSession session) { | ||
try { | ||
if (initializeSocksSession(session)) { | ||
dispatch.outputReady(session); | ||
} | ||
} catch (RuntimeException e) { | ||
session.shutdown(); | ||
throw e; | ||
} | ||
} | ||
|
||
@Override | ||
public void timeout(IOSession session) { | ||
try { | ||
dispatch.timeout(session); | ||
final SocksIOSession socksIOSession = getSocksSession(session); | ||
if (socksIOSession != null) { | ||
socksIOSession.shutdown(); | ||
} | ||
} catch (RuntimeException e) { | ||
session.shutdown(); | ||
throw e; | ||
} | ||
} | ||
|
||
@Override | ||
public void disconnected(IOSession session) { | ||
dispatch.disconnected(session); | ||
} | ||
|
||
private boolean initializeSocksSession(IOSession session) { | ||
final SocksIOSession socksSession = getSocksSession(session); | ||
if (socksSession != null) { | ||
try { | ||
try { | ||
if (!socksSession.isInitialized()) { | ||
return socksSession.initialize(); | ||
} | ||
} catch (final IOException e) { | ||
onException(socksSession, e); | ||
throw new RuntimeException(e); | ||
} | ||
} catch (final RuntimeException e) { | ||
socksSession.shutdown(); | ||
throw e; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
private void onException(IOSession session, Exception ex) { | ||
final NHttpClientConnection conn = getConnection(session); | ||
if (conn != null) { | ||
final NHttpClientEventHandler handler = getEventHandler(conn); | ||
if (handler != null) { | ||
handler.exception(conn, ex); | ||
} | ||
} | ||
} | ||
|
||
private SocksIOSession getSocksSession(IOSession session) { | ||
return (SocksIOSession) session.getAttribute(SocksIOSession.SESSION_KEY); | ||
} | ||
|
||
private NHttpClientConnection getConnection(IOSession session) { | ||
return (NHttpClientConnection) session.getAttribute(IOEventDispatch.CONNECTION_KEY); | ||
} | ||
|
||
private NHttpClientEventHandler getEventHandler(NHttpConnection conn) { | ||
return (NHttpClientEventHandler) conn.getContext().getAttribute(HttpAsyncRequestExecutor.HTTP_HANDLER); | ||
} | ||
|
||
} |
Oops, something went wrong.