简体   繁体   English

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

[英]HTTP Proxy, Content-Length not adding up properly

I am trying to write a simple HTTP proxy in java using sockets, basically just takes a request, reads it and forwards it to the server, reads the response and back to the browser. 我正在尝试使用套接字在java中编写一个简单的HTTP代理,基本上只需要一个请求,读取它并将其转发到服务器,读取响应并返回浏览器。 The issue I am having is in the response there is a Content-Length field which I parse, and I wrote a loop to read exactly that number of bytes to send back to the browser, but it gets to the end of the stream prior to reading the correct amount (read returns -1). 我遇到的问题是在响应中有一个我解析的Content-Length字段,我写了一个循环来准确读取要发送回浏览器的字节数,但它到达流的末尾之前读取正确的数量(读取返回-1)。 I'll add the bare bones code of my proxy below - the main thread just spawns one of these classes when a connection is made. 我将在下面添加我的代理的简单代码 - 主线程在建立连接时只生成其中一个类。 Does anyone have any ideas? 有没有人有任何想法? It would be very helpful. 这将非常有帮助。

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



    }


}
}

Here is a sample response header: 这是一个示例响应头:

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

Content-Length is only one of many ways your proxy can know how many bytes to read. Content-Length只是代理可以知道要读取多少字节的众多方法之一。 There are some conditions in which you have to ignore the Content-Length if it is present (it is not supposed to be present under those conditions, but sometimes it is anyway). 在某些情况下,如果存在Content-Length则必须忽略 Content-Length (在这些条件下不应该存在,但有时它仍然存在)。 Read RFC 2616 Section 4.4 for the official rules of how to read the response data correctly. 阅读RFC 2616第4.4节 ,了解如何正确读取响应数据的官方规则。

That's not how you write an HTTP Proxy. 这不是你编写HTTP代理的方式。 The only thing you have to parse is the initial CONNECT command. 您需要解析的唯一事情是初始CONNECT命令。 Everything after that is just copying bytes backwards and forwards. 之后的一切都只是向后和向前复制字节。 The incoming HTTP is already correct (or not): don't mess with it. 传入的HTTP已经正确(或不是):不要乱用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM