HTTP代理,Content-Length没有正确添加

时间:2012-05-30 23:52:29

标签: java http sockets proxy http-headers

我正在尝试使用套接字在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

2 个答案:

答案 0 :(得分:1)

Content-Length只是您的代理可以知道要读取多少字节的众多方法之一。在某些条件下,您必须忽略 Content-Length如果它存在(在这些条件下不应该存在,但有时它仍然存在)。请阅读RFC 2616 Section 4.4以了解如何正确读取响应数据的官方规则。

答案 1 :(得分:1)

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