0

我正在尝试使用套接字在java中编写一个简单的HTTP代理,基本上只是接受一个请求,读取它并将其转发到服务器,读取响应并返回给浏览器。我遇到的问题是在响应中有一个我解析的 Content-Length 字段,我编写了一个循环来准确读取要发送回浏览器的字节数,但它在之前到达流的末尾读取正确的数量(读取返回 -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只是您的代理可以知道要读取多少字节的众多方法之一。在某些情况下,您必须忽略Content-Length是否存在(在这些条件下它不应该存在,但有时无论如何都会存在)。有关如何正确读取响应数据的官方规则,请阅读RFC 2616 第 4.4 节。

于 2012-05-31T00:16:32.283 回答
1

这不是您编写 HTTP 代理的方式。您唯一需要解析的是初始 CONNECT 命令。之后的一切只是前后复制字节。传入的 HTTP 已经正确(或不正确):不要乱用它。

于 2012-05-31T00:19:20.310 回答