开发者

How to connect a Socket server via HTTP proxy

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

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


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/


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


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?


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.


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.


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.


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.


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));


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜