1

Context

I'm trying to build a simple HTTP web proxy using Java. Right now all I have is something that listens on port 5041 for HTTP requests. Right now I have 2 classes. The Proxy class opens a ServerSocket on the port, I call this socket the welcomeSocket. After this port is opened Proxy starts a new Connection thread everytime welcomeSocket accepts a new socket. The Connection class has some simple logic to read the HTTP request header information. Later this class will be extended for further functionality. Thanks for any help.

Problems

When I run my proxy and configure my browser to point to the proxy I'm getting SocketException errors saying that my socket is closed. I'm not sure how these are coming about. Also it appears that Connection threads are being created but don't necessarily output HTTP header info. This is apparent because output shows repetetive NEW connection thread created prints but no header info after the print.

Proxy Class

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class Proxy {
    // Port is 5000 + 41
    private final int PORT;
    private ServerSocket welcomeSocket = null;
    private boolean listening = true;

    public Proxy(int port) {
        PORT = port; 

        try {
            welcomeSocket = new ServerSocket(PORT);
            listenForConnectionRequests();
        } catch (IOException e) {
            System.err.println("There was a problem while creating the welcome socket");
            e.printStackTrace();
            System.exit(-1);
        }
    }

    public void listenForConnectionRequests() {
        System.out.println("Listening for connection requests at " + PORT + "\n");

        while (listening) {
            try {
                new Connection(welcomeSocket.accept()).start();
            } catch (IOException e) {
                System.err.println("I/O error occured while waiting for a connection.");
                e.printStackTrace();
            }
        }
    }
}

Connection Class

public class Connection extends Thread {
    private Socket connectionSocket = null;
    private ArrayList<String> requestHeaders = new ArrayList<String>();
    private boolean running = true;
    private OutputStream os;
    private InputStream is;

    public Connection(Socket connectionSocket) {
        super("Proxy");
        System.out.println("NEW connection thread created");
        this.connectionSocket = connectionSocket;
    }

    public void run() {
        while (running) {
            readHttpHeader();
        }
    }

    private void stopRunning() {
        running = false;
        System.err.println("Stopping thread.");
        closeEverything();
    }

    private void readHttpHeader() {
        try {
            os = connectionSocket.getOutputStream();
        } catch (IOException e) {
            System.err.println("Problem getting output stream from connection socket.");
            e.printStackTrace();
            stopRunning();
        }

        try {
            is = connectionSocket.getInputStream();
        } catch (IOException e) {
            System.err.println("Problem getting input stream from connection socket.");
            e.printStackTrace();
            stopRunning();
        }

        String input;
        BufferedReader in = null;
        DataOutputStream out = null;
        try {
            in = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
            out = new DataOutputStream(connectionSocket.getOutputStream());

            while ((input = in.readLine()) != null) {
                requestHeaders.add(input);
                System.out.println(input);
            }

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (in != null)
                    in.close();
                if (out != null)
                    out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void closeEverything() {
        try {
            connectionSocket.close();
            is.close();
            os.close();
        } catch (IOException e) {
            System.err.println("Problem closing connection or streams");
            e.printStackTrace();
            stopRunning();
        }
    }
}

Output after testing some webpages

Listening for connection requests at 5041

NEW connection thread created
GET http://127.0.0.1:63342/browserConnection/buildInfo HTTP/1.1
Host: 127.0.0.1:63342
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
Accept: */*
DNT: 1
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

NEW connection thread created
NEW connection thread created
GET http://google.com/ HTTP/1.1
Host: google.com
Proxy-Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
X-Client-Data: CKK2yQEIwbbJAQj9lcoB
DNT: 1
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Cookie: OGP=-5061574:; SID=DQAAAMoCAACmU0EuiAZrQAuo8mgssp5cukiLvNn13ryGL2GeGswaF8Cmv2NIxyW_nnC7ihLpQRaY0gdlYg4K91TStT2aPHo3PWFhExCr5zD0yywqgMwsXuWgQedtdi8Lc6tsL0Nz2WSt8j1Is6Dw53SYpWw-Ukis9d386YATJRYdsDUhVsb3h-pe-QrKNBL3deaxIlMIb5itaAWVTSVkRUVcocns6S-mAopRFT-k8YMKXKVeouztBQhblI1YQUKAtMCqv55ZllmFyfZSQcqmbcsJx19ofBLnl6u2KByIwBLwMMa1DrK1YketAgvgxUzlrfanvTm94VQ7Lie9rppG-up1cNlDsu4XbXrIOkG2bdbD7J2SdjwmI_Hf9IrLl3IelDvdCfQol3CT8rdAMk1p7zBMQq5L_JfiiCLmjNd9VA0CiadcB-6dIBWnGGThNYEOkrU11i2qeiEPtvJqDx_7kyuphkFuQh8b5GI7f5xg-uVmLfjaO4Q7q5EiV7BTt5jacajRibvPsqK77lEw9_UTnPvXOkW1jmfJOKx85rAztVpV2vymO_dGMiG_ehiD4R6CO6ifCnHjij5TKUeWeSEzQdtdDsKGL3MAMSg1bZVKcmc3Veq77AwWZa996gUkyEdD1dJ5c4eTodTEjTx8KiUDEufPGxQtjyOEuT8rnY_MWvDTFUx0os-aMZfcYsLrTmJ6mWpYzKa5wnCvFHKnjBL24UddbBmhhaklLcOghJEH8kcVEVWvNuKC145OIzxwZA2CmTCfEDzymOd6pTGlwl9P7VInl2ro_SkoNmEn6VqUWLRC0zH1jEWZhpkNf9kbpLmWBS-xLWMBpvgPu7ysVBf7qR8_YlzyVprCdRDAR4mrciRaOaswHvWCWgU8EJk_gF8PgiP_D2WEtw8uJR6b4IL_ggxpmckGdHM7yUvkel9jWeFQxrazmF1f1c6SHBooSO6t-tCW7-Hw44A; HSID=A_KCc1Le4o6JlU760; APISID=hE0OzriLy98RcM4M/ALgi7Gky2rmmyyiDE; NID=77=dmymZT8yk5KfHAaIyzxhzvKfG_fvBjPwDpg-yTfz_5cBDKAsqL9n010br6xg1dSRrSKhS--_RYLoCuDodOzAHiaWS11pBB-4Npc9eQbqwkLnaf-nzeqNC_fwNSDElB7qfUmmvnZSHX1mowllXfpIM8cLm-ewYD0tGdHbpfvbAxkfH_jIwQKj-pS0f6ZkcodJ2CEEeoDhMUbZDAOfBKUUhM5qvLxE3curLhef6pftojQo0QpTumhoky2_pWR1lWP-5W0lPN29lMDSdeYrW5Umz_3jNHPRyMiGFwzNMIV9r9RUoyO50JreK057mDnzNygESvk_fBHlt49b2U6tesQ5NAtaAmL4VaWsAuj3jKEvjWTxSgSVrUeWwPC84hjn3liuGlBulWg; OGPC=5061900-22:5061918-27:5061934-15:5061921-40:5061937-46:5061933-25:5061941-6:5061574-1:5061940-57:5061952-26:5061975-14:5061983-7:

Problem getting output stream from connection socket.
java.net.SocketException: Socket is closed
    at java.net.Socket.getOutputStream(Socket.java:916)
    at Connection.readHttpHeader(Connection.java:46)
    at Connection.run(Connection.java:34)
Stopping thread.
Problem getting input stream from connection socket.
java.net.SocketException: Socket is closed
    at java.net.Socket.getInputStream(Socket.java:876)
    at Connection.readHttpHeader(Connection.java:54)
    at Connection.run(Connection.java:34)
Stopping thread.
java.net.SocketException: Socket is closed
    at java.net.Socket.getInputStream(Socket.java:876)
    at Connection.readHttpHeader(Connection.java:65)
    at Connection.run(Connection.java:34)
Problem getting output stream from connection socket.
java.net.SocketException: Socket is closed
    at java.net.Socket.getOutputStream(Socket.java:916)
    at Connection.readHttpHeader(Connection.java:46)
    at Connection.run(Connection.java:34)
Stopping thread.
Problem getting input stream from connection socket.
java.net.SocketException: Socket is closed
    at java.net.Socket.getInputStream(Socket.java:876)
    at Connection.readHttpHeader(Connection.java:54)
    at Connection.run(Connection.java:34)
Stopping thread.
java.net.SocketException: Socket is closed
    at java.net.Socket.getInputStream(Socket.java:876)
    at Connection.readHttpHeader(Connection.java:65)
    at Connection.run(Connection.java:34)
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
NEW connection thread created
GET http://www.yelp.com/ HTTP/1.1
Host: www.yelp.com
Proxy-Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
DNT: 1
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Cookie: __cfduid=dd3ccfb39916d84ca8053ba95c0ca89fe1457229239; yuv=pOdmTZnrxWdr1NhFcLyF8cCB7Pj5l2tN3CSqNp0fiz0yKun0fbD0MHFrIo4K432S0pKC_-Sl9QijvKAX5u1iUJMmwZ2EnL4p; hl=en_US; fd=0; D_SID=172.250.60.189:SscPaGXtn/I/Skx3ISxQZOtF5qtsm+TmywEwnqXsiuo; qntcst=D%2CT%2C43606%2C43604%2C43602%2C43597%2C43596%2C43595%2C43583%2C43582%2C43581%2C37336%2C34588%2C34585%2C27425%2C27424%2C20052%2C20047%2C20040%2C20021%2C20020%2C20015%2C19991%2C19989%2C19958%2C19948%2C19947%2C19945%2C19944%2C19942%2C19941%2C19939%2C19936%2C19934%2C19932; __qca=P0-1476739725-1457229248633; fbm_97534753161=base_domain=.yelp.com; location=%7B%22city%22%3A+%22Seattle%22%2C+%22zip%22%3A+%22%22%2C+%22country%22%3A+%22US%22%2C+%22address2%22%3A+%22%22%2C+%22address3%22%3A+%22%22%2C+%22state%22%3A+%22WA%22%2C+%22address1%22%3A+%22%22%2C+%22unformatted%22%3A+%22seattle%22%7D; bse=b955bbc7020253479a51b278e343d766; __utma=165223479.439363298.1457229244.1457383227.1457394139.4; __utmc=165223479; __utmz=165223479.1457383227.3.3.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided); __utmv=165223479.|4=account%20level=anon=1; _ga=GA1.2.C1BEB9B4D17FEEDD; D_PID=469F0452-18FF-3E05-8072-566D9785BE96; D_IID=EC337894-ADD2-36A6-848D-AA87DA4B1407; D_UID=6E67A9C8-F999-33A6-8838-4EBFBC9B943E; D_HID=qXtXeOzvXZDnGT33GPaUewyWk7KgXdgunNy1mqdkX7g

Problem getting output stream from connection socket.
Problem getting output stream from connection socket.
Problem getting output stream from connection socket.
Problem getting output stream from connection socket.
Daniel Kobe
  • 9,376
  • 15
  • 62
  • 109
  • Not yet read all your code, but I'm wondering if this is related: http://stackoverflow.com/questions/15856890/why-my-java-server-close-sockets ? – Kon Mar 08 '16 at 20:44

1 Answers1

2

You are closing the socket, and then trying to read from it.

The following code will call readHttpHeader twice ...

while (running) {
    readHttpHeader();
}

The first time it is successful:

try {
    in = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));

    while ((input = in.readLine()) != null) {
        requestHeaders.add(input);
        System.out.println(input);
    }

And then you close the input stream ...

} finally {
    try {
        if (in != null)
            in.close();

Which closes the stream it wraps (the InputStreamReader) which in turn closes the socket's input stream.

And then you loop around for the second call to readHttpHeader(), which finds the stream closed. Several try-catch blocks catch some errors, report them to stderr, and then muddle on, arriving at the read loop (failing), and finally the stream closing. Finally, since running is false, the readHttpHeader() is not called a third time.

AJNeufeld
  • 8,526
  • 1
  • 25
  • 44
  • Great thanks! I'll try setting running to false in the finally block. What about the threads that get created but don't print any HTTP request info? – Daniel Kobe Mar 08 '16 at 21:28
  • You are printing to both `System.out` and `System.err` ... you're output may not be appearing in the order you think it is. More over, you are doing so from a `Thread`, of which you are creating many. Trying to determine what exactly is happening from the log is nigh impossible. You will need to use more advanced logging techniques for a hope of determining what is happening in what order. Sorry. – AJNeufeld Mar 08 '16 at 21:40
  • Why reinvent the wheel? Googling "java proxy server example" results in many examples, which you could study/adapt as required. – AJNeufeld Mar 08 '16 at 21:46