简体   繁体   中英

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. 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). 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. 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). Read RFC 2616 Section 4.4 for the official rules of how to read the response data correctly.

That's not how you write an HTTP Proxy. The only thing you have to parse is the initial CONNECT command. Everything after that is just copying bytes backwards and forwards. The incoming HTTP is already correct (or not): don't mess with it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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