Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the proper way to listen to HTTP requests?

I've written a very simple, rather low level HTTP (well, part of HTTP) server as an exercise to get more familiar with this whole web thing I've been avoiding all the time. It works reasonably well for a first attempt (not so much that I would recommend anyone to actually use it, but it does what I tell it to). Now the problem is that the GET operation fails a lot (refreshing helps, but it's not very nice - details below), I assume this is because of the way I read requests (I am fairly certain my routes work):

void start()
{
    //...
    try(ServerSocket webSock = new ServerSocket(47000) {
    //...
        while(running) {
           try {
               Socket sock = webSock.accept();
               //read/write from/to sock 
           }
           //...
           Thread.sleep(10);
        }
    } 
}

(full code here: http://pastebin.com/5B1ZuusH )

I am not sure exactly what I'm doing wrong though.

I do get the error:

This webpage is not available
The webpage at http://localhost:47000/ might be temporarily down or it may have moved permanently to a new web address.
Error 15 (net::ERR_SOCKET_NOT_CONNECTED): Unknown error.

quite a bit (entire page doesn't load), sometimes scripts or images don't load either. If required, I could post the entire code, but the rest is mostly boilerplate.

like image 761
Cubic Avatar asked Nov 25 '12 14:11

Cubic


1 Answers

[another update]

OK to clarify my response, here is a trivial web server that shows how to read GET requests. Note that it handles multiple requests in the same connection. If the connection closes, the program exits. Typically though I can send a number of request from the same web browser before the connection closes and the program exits. This means you cannot use end-of-stream as a signal the the message is over.

Please note that I never use a hand-written web-server for anything real. My favorite is Tomcat, but the other frameworks are fine too.

public class MyWebServer
{
   public static void main(String[] args) throws Exception
   {
      ServerSocket server = new ServerSocket(47000);
      Socket conn = server.accept();
      BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));

      // don't use buffered writer because we need to write both "text" and "binary"
      OutputStream out = conn.getOutputStream();
      int count = 0;
      while (true)
      {
         count++;
         String line = reader.readLine();
         if (line == null)
         {
            System.out.println("Connection closed");
            break;
         }
         System.out.println("" + count + ": " + line);
         if (line.equals(""))
         {
            System.out.println("Writing response...");

            // need to construct response bytes first
            byte [] response = "<html><body>Hello World</body></html>".getBytes("ASCII");

            String statusLine = "HTTP/1.1 200 OK\r\n";
            out.write(statusLine.getBytes("ASCII"));

            String contentLength = "Content-Length: " + response.length + "\r\n";
            out.write(contentLength.getBytes("ASCII"));

            // signal end of headers
            out.write( "\r\n".getBytes("ASCII"));

            // write actual response and flush
            out.write(response);
            out.flush();
         }
      }
   }
}

[origin response]

What is the proper way to listen to HTTP requests?

For most of us, the proper way is to use a well designed web server framework such as Tomcat, Jetty, or Netty

as an exercise to get more familiar with this whole web thing

However if this is an academic exercise to learn about HTTP, then the first thing to do is study the HTTP protocol (see http://www.w3.org/Protocols/rfc2616/rfc2616.html). I'm pretty sure you have not done this because you code is making no attempt to identify the start line, headers etc to figure out when the GET request is complete and it make sense to send a response.

[update]

Cool. You've learned about how TCP is stream oriented and does not preserve message boundaries. Yes the application has to handle that. Here is a final thought - you could probably get your experiment to work fairly reliably - only for GET requests mind you- if you used readLine to read the start line and headers. When you get a blank line, the request is done. This will cause the buffered reader to block at the right times so you get all your content.

This will not work for POST etc because you would then need to parse the Content-Length header and read some number of bytes.

Hopefully this experiment will make you appreciate Jetty more when you realize how much is involved in doing this correctly and reliably - so I think it's a worthwhile effort.

like image 57
Guido Simone Avatar answered Oct 11 '22 20:10

Guido Simone