0

ソケットを使用して Java で単純な HTTP プロキシを作成しようとしています。基本的には、要求を受け取り、それを読み取ってサーバーに転送し、応答を読み取ってブラウザに戻します。私が抱えている問題は、解析する Content-Length フィールドがある応答にあり、ブラウザに送り返す正確なバイト数を読み取るループを書きましたが、ストリームの最後に到達する前に正しい量を読み取ります (読み取りは -1 を返します)。以下にプロキシの必要最小限のコードを追加します。接続が確立されると、メイン スレッドはこれらのクラスの 1 つを生成するだけです。誰にもアイデアはありますか?とても役に立ちます。

public class ProxyClient implements Runnable {

Socket clientSocket;
Socket netflixSocket;

InputStream isClient = null;
OutputStream osClient = null;
BufferedReader brClient = null;

InputStream isNetflix = null;
OutputStream osNetflix = null;
BufferedReader brNetflix = null;
boolean connectedNetflix = false;

String meta = "";   //header data

public ProxyClient(Socket connectionSocket){
    this.clientSocket = connectionSocket;

    try {
        isClient = clientSocket.getInputStream();
        osClient = clientSocket.getOutputStream();
        brClient = new BufferedReader(new InputStreamReader(isClient));
    } catch (IOException e1) {
        e1.printStackTrace();
    }

}

@Override
public void run() {


    String host = "";

    String temp;        // temp read line from buffer
    String getRequest;
    int contentLength;  //holder for reading bytes.
    int bytesRead;      // Total number of bytes read during consecutive reads
    int numRead;        // Number of bytes read in a single read.


    byte[] dataBuffer = new byte[2000000];


    while(true){

        try {


            // reading client HTTP request / connecting
            host = "";
            meta = "";
            contentLength = 0;
            getRequest = "";
            while((temp = brClient.readLine()).length() > 0){
                    meta += temp + "\r\n";

                    //connect to server
                    if(!connectedNetflix && temp.startsWith("Host")){

                        // extract the host to connect to
                        host = temp.substring(temp.indexOf(':') + 2);

                        //connect to the host
                        try {
                            netflixSocket = new Socket(host, 80);
                            osNetflix = netflixSocket.getOutputStream();
                            isNetflix = netflixSocket.getInputStream();
                            brNetflix = new BufferedReader(new InputStreamReader(isNetflix));
                        } catch (UnknownHostException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                        connectedNetflix = true;

                    }
                    else if (temp.startsWith("Content-Length:")) {
                        contentLength = Integer.parseInt(temp.substring(temp.indexOf(':') + 2));
                    }

            }
            meta += "\r\n"; // add blank line


            //read request content, if any
            if(contentLength > 0){
                numRead = 0;
                bytesRead = 0;
                while(bytesRead != contentLength){
                    numRead = isNetflix.read(dataBuffer, bytesRead, contentLength-bytesRead);
                    if(numRead >0){
                        bytesRead += numRead;
                    }
                }
            }


            //send to server
            osNetflix.write(meta.getBytes());
            if(contentLength > 0){
                osClient.write(dataBuffer, 0, contentLength);
            }
            osNetflix.flush();


            //Read response from server
            contentLength = 0;
            meta = "";
            while((temp = brNetflix.readLine()).length() > 0){
                meta += temp + "\r\n";

                if (temp.startsWith("Content-Length:")) {
                    contentLength = Integer.parseInt(temp.substring(temp.indexOf(':') + 2));
                }

            }               
            meta += "\r\n"; // add blank line


            //read Netflix content
            if(contentLength > 0){
                numRead = 0;
                bytesRead = 0;
                while(bytesRead != contentLength){
                    numRead = isNetflix.read(dataBuffer, bytesRead, contentLength-bytesRead);
                    if(numRead >0){
                        bytesRead += numRead;
                    }

                }

            }               


            // write back to browser/client
            osClient.write(meta.getBytes());
            if(contentLength > 0){
                osClient.write(dataBuffer, 0, contentLength);
            }
            osClient.flush();

        } catch (IOException e) {
            e.printStackTrace();
        }



    }


}
}

応答ヘッダーの例を次に示します。

HTTP/1.1 200 OK
Server: Apache
Accept-Ranges: bytes
Content-Type: text/plain
Content-Type: application/octet-stream
Access-Control-Allow-Origin: *
Content-Type: application/octet-stream
Last-Modified: Fri, 17 Jun 2011 07:52:37 GMT
ETag: "0d6a07a1c0e6772459e73f7c0c4fd899:1308297157"
Date: Thu, 31 May 2012 01:54:10 GMT
Content-Length: 294183
Connection: close
Cache-Control: no-store
4

2 に答える 2

1

Content-Lengthこれは、プロキシが読み取るバイト数を知ることができる多くの方法の1つにすぎません。存在する場合は無視しなければならない条件がいくつかありますContent-Length(これらの条件では存在しないはずですが、とにかく存在する場合もあります)。応答データを正しく読み取る方法の公式ルールについては、RFC2616セクション4.4をお読みください。

于 2012-05-31T00:16:32.283 に答える
1

これは、HTTPプロキシを作成する方法ではありません。解析する必要があるのは、最初のCONNECTコマンドだけです。その後はすべて、バイトを前後にコピーするだけです。着信HTTPはすでに正しい(または正しくない):それを台無しにしないでください。

于 2012-05-31T00:19:20.310 に答える