0

I am coding a simple Java proxy. The general architecture was given to me (method signatures etc), and this is how the Main class looks:

private static Socket clientSocket;
private static ServerSocket client;
private static int myPort;

public static void init(int port) throws IOException {
    client = new ServerSocket(port);
    clientSocket = client.accept();
}
public static void handle(Socket clientSocket) {
    try {
        BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        HttpRequest httpRequest = new HttpRequest(in);

        String hostname = httpRequest.getHost();
        //443 hardcoded from reading the http headers. 
        //Testing using isitchristmas.com
        Socket serverSocket = new Socket(hostname, 443);
        BufferedReader out = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
        HttpResponse httpResponse = new HttpResponse(out);
        serverSocket.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

}
public static void main(String args[]) {
    try {
        myPort = Integer.parseInt(args[0]);
        try {
            System.out.println("Initializing socket...");
            init(myPort);
        } catch (IOException e) {
            System.out.println("[ERROR]: " + e.getMessage());
        }
        handle(clientSocket);
    } catch (Exception e) {
        System.out.println("[ERROR]: " + e.getMessage());
    }
}

However the console hangs and never completes a request when reading in HttpResponse class:

    public HttpResponse(BufferedReader fromServer) throws IOException {
    String line;
    String statusLine = "";
    // Never goes past here
    while ((line = fromServer.readLine()) != null) {
        if (line.isEmpty()) {
            break;
        }

        if (line.toLowerCase().contains("status")) {
            statusLine = line;
        }

        response.append(line);
    }

    if (!response.toString().isEmpty()) {
        getDataAndHeadersFromResponse(response.toString());
        System.out.println("\n\nHTTP Response:\n");
        System.out.println("Status Line: " + statusLine);
        System.out.println("Header Lines: " + headerLines + "\n\n");
        System.out.println("Data: " + data);
    }

}

I suspect it has something to do with how I am creating the sockets... not calling close() on ServerSocket gives off a Address already in use: JVM_Bind exception. I also don't seem to get the serverSocket parameters right. As you can tell by now I'm not very versed in socket programming. What is wrong here?

8
  • Almost everything is wrong. If you're going to implement HTTP proxying you need a good knowledge of RFC 2616, especially the parts about content length. You're trying to read HTTPS with a plaintext Socket. Your general architecture is already wrong to use aReader. A ServerSocket is not a 'client'. You need a new thread per accepted connection, and a loop that accepts them. Etc etc etc. Commented Feb 21, 2016 at 22:58
  • Apparently it shouldn't be that complicated. This is the exercise. It's not for me, but I'm helping out a friend: s000.tinyupload.com/?file_id=86822892327719350011 Commented Feb 21, 2016 at 23:05
  • A terrible assignment. A class called ProxyCache that doesn't cache anything but that listens for and accepts requests? An HTTP proxy that uses BufferedReader? Why a BufferedReader to read from the client and a DataInputStream to read from the server? Nothing mentioned about content-length? It's not even how you write a real proxy. Students should complain. There's not enough information provided here and some of the code structure is positively useless. In the meantime one of you should have a good look at the Custom Networking section of the Oracle Java Tutorial. Too broad. Commented Feb 21, 2016 at 23:57
  • NB The basic problem is insoluble without a knowledge of content-length, and without knowing that the line terminator in HTTP is \r\n, not \n. Commented Feb 21, 2016 at 23:58
  • Other than that those static fields made me cringe Commented Feb 21, 2016 at 23:58

1 Answer 1

1
  • You need to listen on port 80: nothing in the assignment about HTTPS.
  • The request body won't be terminated by end of stream, because the client still has the socket open to read the response.
  • You need to read the Content-length header from the client and then read exactly that many bytes of request body.
  • You therefore cannot solve this problem with a BufferedReader, as you have to count bytes, not chars.
  • Having sent the request on to the server, all you really need to do afterwards is copy the response bytes directly from the server to the client: not what it says in the assignment.
  • To stick with what the assignment says, you would similarly have to read the Content-Length header from the server, and all the other headers, and the blank line, and exactly content-length bytes of response from the server, and copy them all to the client. You can see this is a waste of time compared to just copying bytes.
  • The line terminator in HTTP is \r\n, not \n.

The assignment is deficient in:

  • specifying the infeasible BufferedReader
  • then inconsistently specifying DataInputStream for reading from the server
  • there is no reason to use DataInputStream at all: InputStream would suffice
  • not referring to RFC 2616 or its predecessors or successors
  • not specifying whether HTTP 1.0 or 1.1
  • not saying more about 'to cache Web pages', which is only mentioned on page 2 and never thereafter.

Students should complain.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.