18

I have a piece of code to connect to a Socket server, and it works fine.

Socket socket = new Socket();
socket.connect(new InetSocketAddress(address, port));

Now I want to connect via a HTTP proxy, what should I do?

I tried this and failed

SocketAddress proxyAddr = new InetSocketAddress(proxyHost, proxyPort);
Proxy proxy = new Proxy(Proxy.Type.SOCKS, addr);
Socket socket = new Socket(proxy);
socket.connect(new InetSocketAddress(address, port));

this post suggests that I should use Jakarta Commons HttpClient, but how to use it to connect a Socket server via the HTTP proxy?

UPDATED: I used SOCKS proxy and it doesn't work, if I use HTTP proxy:

SocketAddress proxyAddr = new InetSocketAddress(proxyHost, proxyPort);
Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);
Socket socket = new Socket(proxy);
socket.connect(new InetSocketAddress(address, port));

and it will throw an IllegalArgumentException

java.lang.IllegalArgumentException: Proxy is null or invalid type
    at java.net.Socket.<init>(Socket.java:88)
6
  • Some good info here too: download.oracle.com/javase/6/docs/technotes/guides/net/… Commented Aug 29, 2011 at 4:06
  • There's a doTunneling() in sun.net.www.protocol.http.HttpURLConnection. Maybe it's possible to pick apart that class and get access to the socket underneath after the tunnel is established... but you'd be using a propriety API that could go away at any time. This would not be a problem if you went with HttpClient. Commented Aug 29, 2011 at 7:35
  • where you able to figure this out? It's a problem I'm looking at now Commented Oct 21, 2013 at 13:55
  • 2
    you create 'proxyAddr', but don't use it when creating the Proxy which seems wrong here. Commented Mar 5, 2014 at 5:55
  • new Socket(new Proxy(Proxy.Type.HTTP, ...)) should work since Java 8 Commented Feb 13, 2020 at 15:16

9 Answers 9

8

I've created small Socket Factory class to handle the HTTP CONNECT via socket. The socket then can be used as per-normal provided the proxy supports CONNECT to the destination.

public final class SocketFactory {

    public static Socket GetSocket(String host, String port) throws IOException {

        /*************************
         * Get the jvm arguments
         *************************/

        int proxyPort = Integer.parseInt(System.getProperty("http.proxyPort"));
        String proxyHost = System.getProperty("http.proxyHost");

        // Socket object connecting to proxy
        Socket sock = new Socket(proxyHost, proxyPort);

        /***********************************
         * HTTP CONNECT protocol RFC 2616
         ***********************************/
        String proxyConnect = "CONNECT " + host + ":" + port;

        // Add Proxy Authorization if proxyUser and proxyPass is set
        try {
            String proxyUserPass = String.format("%s:%s",
                    System.getProperty("http.proxyUser"),
                    System.getProperty("http.proxyPass"));

            proxyConnect.concat(" HTTP/1.0\nProxy-Authorization:Basic "
                    + Base64.encode(proxyUserPass.getBytes()));
        } catch (Exception e) {
        } finally {
            proxyConnect.concat("\n\n");
        }

        sock.getOutputStream().write(proxyConnect.getBytes());
        /***********************************/

        /***************************
         * validate HTTP response.
         ***************************/
        byte[] tmpBuffer = new byte[512];
        InputStream socketInput = sock.getInputStream();

        int len = socketInput.read(tmpBuffer, 0, tmpBuffer.length);

        if (len == 0) {
            throw new SocketException("Invalid response from proxy");
        }

        String proxyResponse = new String(tmpBuffer, 0, len, "UTF-8");

        // Expecting HTTP/1.x 200 OK
        if (proxyResponse.indexOf("200") != -1) {

            // Flush any outstanding message in buffer
            if (socketInput.available() > 0)
                socketInput.skip(socketInput.available());

            // Proxy Connect Successful, return the socket for IO
            return sock;
        } else {
            throw new SocketFactoryException("Fail to create Socket",
                    proxyResponse);
        }
    }

    /**
     * Simplest Base64 Encoder adopted from GeorgeK
     * 
     * @see http://stackoverflow.com/questions/469695/decode-base64-data-in-java/4265472#4265472
     */
    private static class Base64 {
        /***********************
         * Base64 character set
         ***********************/
        private final static char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
                .toCharArray();

        /**
         * Translates the specified byte array into Base64 string.
         * 
         * @param buf
         *            the byte array (not null)
         * @return the translated Base64 string (not null)
         */
        public static String encode(byte[] buf) {
            int size = buf.length;
            char[] ar = new char[((size + 2) / 3) * 4];
            int a = 0;
            int i = 0;
            while (i < size) {
                byte b0 = buf[i++];
                byte b1 = (i < size) ? buf[i++] : 0;
                byte b2 = (i < size) ? buf[i++] : 0;

                int mask = 0x3F;
                ar[a++] = ALPHABET[(b0 >> 2) & mask];
                ar[a++] = ALPHABET[((b0 << 4) | ((b1 & 0xFF) >> 4)) & mask];
                ar[a++] = ALPHABET[((b1 << 2) | ((b2 & 0xFF) >> 6)) & mask];
                ar[a++] = ALPHABET[b2 & mask];
            }
            switch (size % 3) {
            case 1:
                ar[--a] = '=';
            case 2:
                ar[--a] = '=';
            }
            return new String(ar);
        }
    }
}

https://code.google.com/p/java-socket-over-http-proxy-connect/

Sign up to request clarification or add additional context in comments.

Comments

3

You could try JHttpTunnel, though you need software running on both sides of the tunnel for this to work.

2 Comments

The problem is I can't install software on either side. I looked at the JHttpTunnel, is there an equivalent way in Apache or Android?
@Johnny If you can't install software on both sides, JHttpTunnel wont work. JHttpTunnel is based on GNU HttpTunnel if that helps.
2

This is from the link I posted previously:

SocketAddress addr = new InetSocketAddress("webcache.mydomain.com", 8080);
Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);

Remember, this new proxy object represents a proxy definition, nothing more. How do we use such an object? A new openConnection() method has been added to the URL class and takes a Proxy as an argument, it works the same way as openConnection() with no arguments, except it forces the connection to be established through the specified proxy, ignoring all other settings, including the system properties mentioned above.

So completing the previous example, we can now add:

URL url = new URL("http://java.sun.com/");
URLConnection conn = url.openConnection(proxy);

This is from the link I posted earlier. I'm on the iPad so can't format it properly.

Can you do it this way? I see you're doing sockets directly but you're doing http so maybe do things this way?

1 Comment

Thanks Jord. I'm working fine with the URLConnection, but the problem is that the host server only accepts Socket connection while the proxy server only accepts HTTP connection. So I have to connect to the Socket server via a HTTP proxy.
0

Looks like you're requesting a SOCKS proxy, which is different from an HTTP proxy. Perhaps try Proxy.Type.HTTP.

Question: is your client HTTP based? I'm not sure this will work unless your client speaks HTTP.

1 Comment

Thanks for the hints, I tried HTTP and it doesn't work as well. My client is HTTP based and it works fine if I connect to a HTTP server using this HTTP proxy
0

Am I correct in saying that what you want is to use the http proxy (for exemple squid) to establish a CONNECT method to a remote server (from http rfc 2616)? Basically, the connection goes like this:

     -open a socket to the proxy (host, port)
     -send text to the proxy with basic header 
     ....CONNECT remote.internethost.com:1494 HTTP/1.0
     ....User-Agent: Java Proxy Socket version 1.0a
     ....Host: remote.internethost.com
     ....Proxy-Authorization: Basic YourBase64usernamePasswordIfRequired
     -then, the proxy will return a http status code (multiline text string) and the actual socket (if successfull)
     -this is this socket that needs to be returned to the connection object

That could be done with personal classes but the beauty would be to reuse the proxy classes for it. This way, all the handshake with the http proxy, especially the response code would be handled.

Comments

0

Well, you can manage the proxy by setting the requested url right after the proxy's url, or using Java URL as following:

URL u = new URL("http", ProxyHost, ProxyPort, destinationAddress);

By using this you build an URL like http://ProxyHost:ProxyPorthttp://destinationAddress so you don't have to set a Proxy class instance in Java that will likely throw the mentioned exception:

java.lang.IllegalArgumentException: Proxy is null or invalid type
    at java.net.Socket.<init>(Socket.java:88)

If you need to manage authentication settings you can always set the authenticator as default.

final String authUser = myAuthUser;
        final String authPassword = myAuthPassword;
        Authenticator.setDefault(
           new Authenticator() {
              public PasswordAuthentication getPasswordAuthentication() {
                 return new PasswordAuthentication(
                       authUser, authPassword.toCharArray());
              }
           }
        );

Even though it's a very "rudimental" way to set a proxy it's very likely to work for HTTP Type Proxies if that's the kind of proxy you have to set.

Comments

0

As per Wikipedia on HTTP tunneling, the important thing about a HTTP proxy is that it proxies the HTTP protocol.

So if you have a server and a client and wish them to communicate through a HTTP proxy then both the server and client must be modified to communicate the HTTP protocol.

Alternatively you need additional software that can implement a VPN over HTTP, such as OpenVPN.

Edit: An exception is that some HTTP proxy servers support and have enabled a method called HTTP CONNECT which after a basic setup process over HTTP permits the creation and routing of a regular TCP socket. This permits connectivity to applications without the hard work of full conversion to HTTP tunneling. A good example of this is MSN Messenger. However as the Wikipedia articles notes this feature is often disabled, or not even supported for security reasons.

4 Comments

Is there a lib that helps me to do this programmatically?
@Johnny the main requirement is having a server next to the target host that you can modify.
Not true, you can tunnel any stream via HTTP CONNECT method.
@Martin only if your proxy supports it, many do not or are explicitly configured to disallow it, and cascading proxies can be problematic. MSN Messenger is a popular example of software that tries to use HTTP CONNECT.
0

I see its quite an old post, not sure if anybody is looking for this. For me the blow snippet is working perfectly fine.

Socket socketProxy = null;
    if(System.getProperty("http.proxyHost") != null) {
        if(System.getProperty("http.proxyUser") != null) {
            
            String proxyUser = System.getProperty("http.proxyUser");
            String proxyPassword = System.getProperty("http.proxyPassword");
            
            //For Proxy Authentication
            Authenticator.setDefault( new Authenticator() {
            
             @Override public PasswordAuthentication getPasswordAuthentication() { return
             new PasswordAuthentication(proxyUser, proxyPassword.toCharArray()); } } ); 
             
             System.setProperty("jdk.http.auth.tunneling.disabledSchemes", ""); // By default basic auth is disabled, by this basic auth is enabled
        }
    Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort"))));
    socketProxy = new Socket(proxy);
    InetSocketAddress address = InetSocketAddress.createUnresolved(host, port); // create a socket without resolving the target host to IP
    socketProxy.connect(address); 
    }

One thing I notice from the original post is that the proxyAddr is not used. Not sure if it is typo in this post or a mistake.

SocketAddress **proxyAddr** = new InetSocketAddress(proxyHost, proxyPort);
Proxy proxy = new Proxy(Proxy.Type.HTTP, **addr**);
Socket socket = new Socket(proxy);
socket.connect(new InetSocketAddress(address, port));

Comments

-2

I`m codding an app with c++ using Socks through Proxy, This tool help me a lot, have a look HERE

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.