views:

96

answers:

3

I am using HttpClient 4.02 to create a connection via proxy (using the CONNECT method) to tunnel a connection to a remote server. HttpClient is very convenient for this but I am new to the API and cannot see how to get at the underlying Socket of the tunneled connection.

The following code taken from: http://svn.apache.org/repos/asf/httpcomponents/httpclient/tags/4.0.1/httpclient/src/examples/org/apache/http/examples/client/ClientExecuteProxy.java

    // make sure to use a proxy that supports CONNECT
    HttpHost target = new HttpHost("target.server.net", 443, "https");
    HttpHost proxy = new HttpHost("some.proxy.net", 8080, "http");

    // general setup
    SchemeRegistry supportedSchemes = new SchemeRegistry();

    // Register the "http" and "https" protocol schemes, they are
    // required by the default operator to look up socket factories.
    supportedSchemes.register(new Scheme("http", 
            PlainSocketFactory.getSocketFactory(), 80));
    supportedSchemes.register(new Scheme("https", 
            SSLSocketFactory.getSocketFactory(), 443));

    // prepare parameters
    HttpParams params = new BasicHttpParams();
    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);

    ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, 
            supportedSchemes);

    DefaultHttpClient httpclient = new DefaultHttpClient(ccm, params);

    httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);

    HttpGet req = new HttpGet("/");

    System.out.println("executing request to " + target + " via " + proxy);
    HttpResponse rsp = httpclient.execute(target, req);
    HttpEntity entity = rsp.getEntity();

This sets up the connection nicely but is there a way to get at the underlying Socket in order for me to use a custom protocol to talk to the server at target.server.net?

+2  A: 

Not sure I completely understand your requirements, but I'll give it my best shot...

Try this: http://svn.apache.org/viewvc/httpcomponents/oac.hc3x/trunk/src/examples/ProxyTunnelDemo.java?view=markup

Eran Harel
Thanks for this, I will try to translate into HttpClient 4.x API (they completely changed the API between 3.x and 4.x) and it seems more difficult to do this kind of thing.
willjcroz
Confirmed this (thanks to you leading me to ProxyClient class) here: http://mail-archives.apache.org/mod_mbox/hc-httpclient-users/201004.mbox/%3C1270841032.4208.1.camel@ubuntu%3E
willjcroz
A: 

In a comment, @willjcroz says:

It is so that my app is usable for people behind firewalls where the only way out would be a web proxy. By connecting to the proxy it will forward data to the target server as HTTPS, giving a secure connection to the target server.

If you are going to successfully tunnel your protocol through web proxies, protocol aware firewalls and so on, the client and server sides of your application have to conform to the HTTP protocol specifications. If you (somehow) managed to drill down to the socket level, the chances are that you would violate the protocol ...

Instead, you should implement your custom protocol by putting your data in the content of the HTTP requests and responses, using custom HTTP headers in messages / responses, custom content types, and so on.

Stephen C
I think what @willjcroz wants is a connection that stays open, and HttpClient doesn't really give you that. This is why (I think) he wants to get his hands on the socket.
Eran Harel
If HttpClient closes the connection, that's because the HTTP protocol says that it should be closed. Getting hold of the underlying socket probably won't help. A proxy won't (or at least shouldn't) relay extra data in violation of the HTTP spec.
Stephen C
I think you need to read up on what the CONNECT method does. What the OP is doing is absolutely legit. It's true that some firewalls might block it, and many proxies simply won't implement CONNECT, but if the users have access to proxies which trust them and support CONNECT, then this should work fine.
Tom Anderson
@Stephen C thanks for your thoughts, as Tom says, I am assuming a proxy supporting CONNECT method. What I should have made clearer was that my data stream of screen data (sent from client) will be streamed as the content body of the tunnelled HTTPS request and the downstream control bytes will be streamed as the response body. The target server is not really a web server it just listens on a common port, strips off the request header and starts reading in the bytes.
willjcroz
+1  A: 

Open a change request in the project's JIRA. This feature simply got overlooked. While it should be fairly trivial to put together an equivalent of ProxyClient from 3.x, it makes sense to ship one with the stock version of HttpClient.

oleg
@Oleg OK, I will do when I get time. Thanks for your great work on HttpClient btw.
willjcroz