web-dev-qa-db-ja.com

HTTPプロキシ経由でソケットサーバーに接続する方法

Socketサーバーに接続するコードがあり、正常に動作します。

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

HTTPプロキシ経由で接続したいのですが、どうすればよいですか?

私はこれを試して失敗しました

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

この投稿Jakarta Commons HttpClientを使用する必要があることを示唆していますが、それを使用してHTTPプロキシ経由でソケットサーバーに接続する方法?

更新:私はSOCKSプロキシを使用しましたが、HTTPプロキシを使用すると機能しません。

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

そしてそれはIllegalArgumentExceptionをスローします

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

ソケット経由のHTTP CONNECTを処理する小さなSocket Factoryクラスを作成しました。その後、プロキシが宛先へのCONNECTをサポートしていれば、ソケットは通常どおり使用できます。

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/

4
Ernest Neo

JHttpTunnel を試すこともできますが、これを機能させるには、トンネルの両側でソフトウェアを実行する必要があります。

2
prunge

これは私が以前に投稿したリンクからのものです:

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

この新しいプロキシオブジェクトはプロキシ定義を表していることに注意してください。このようなオブジェクトをどのように使用しますか?新しいopenConnection()メソッドがURLクラスに追加され、プロキシを引数として使用します。これは、接続を強制的に確立することを除いて、引数なしでopenConnection()と同じように機能します。上記のシステムプロパティを含む他のすべての設定を無視して、指定されたプロキシを介して。

前の例を完了して、次のように追加できます。

_URL url = new URL("http://Java.Sun.com/");
URLConnection conn = url.openConnection(proxy);
_

これは、以前に投稿したリンクからのものです。 iPadを使用しているため、適切にフォーマットできません。

このようにできますか?ソケットを直接実行しているようですが、httpを実行しているので、おそらくこの方法で処理を実行しますか?

2
Jord Sonneveld

HTTPプロキシとは異なるSOCKSプロキシをリクエストしているようです。おそらく、Proxy.Type.HTTPを試してください。

質問:クライアントはHTTPベースですか?クライアントがHTTPを話さない限り、これが機能するかどうかはわかりません。

0
Jord Sonneveld

私が望むのは、httpプロキシ(たとえばsquid)を使用して、リモートサーバー(http rfc 2616から)へのCONNECTメソッドを確立することです。基本的に、接続は次のようになります。

     -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

これは個人用クラスで実行できますが、プロキシクラスを再利用できるのが魅力です。このように、httpプロキシとのすべてのハンドシェイク、特に応答コードが処理されます。

0
Gauthier

まあ、プロキシのURLの直後に要求されたURLを設定するか、Java URLを次のように使用して、プロキシを管理できます。

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

これを使用することで、http://ProxyHost:ProxyPorthttp://destinationAddressのようなURLを構築するので、JavaでProxyクラスのインスタンスを設定する必要がなく、前述の例外をスローする可能性があります。

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

認証設定を管理する必要がある場合は、常にオーセンティケーターをデフォルトとして設定できます。

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

プロキシを設定するのは非常に「基本的な」方法ですが、設定する必要があるプロキシの種類であれば、HTTPタイププロキシで機能する可能性が非常に高くなります。

0
atzu

HTTPトンネリング に関するWikipediaによると、HTTPプロキシについて重要なことは、HTTPプロトコルをプロキシすることです。

したがって、サーバーとクライアントがあり、HTTPプロキシを介して通信する場合は、サーバーとクライアントの両方を変更して、HTTPプロトコルを通信する必要があります。

あるいは、OpenVPNなどの VPN over HTTP を実装できる追加のソフトウェアが必要です。

編集:例外は、一部のHTTPプロキシサーバーが基本セットアッププロセス後に HTTP CONNECT と呼ばれるメソッドをサポートし、有効にしていることです。 HTTP経由では、通常のTCPソケットの作成とルーティングが許可されます。これにより、HTTPトンネリングへの完全な変換のハードワークなしでアプリケーションへの接続が許可されます。これの良い例はMSN Messengerです。ただし、ウィキペディアの記事では、この機能は無効になっていることが多く、セキュリティ上の理由からサポートされていないこともあります。

0
Steve-o