Ruby Web Server Hanging When Trying To Parse HTTP

2019-07-11 06:18发布

问题:

I am working on an assignment which requires me to implement a web server in Ruby without using any libraries. I have a basic server setup to return a "Hello World" response and I am ready to move onto the next step.

The next step is to generate HTTP Responses based on the HTTP Requests. This is where I am having trouble, it seems that the while loop in my program causes the server to hang.

The code for the web server:

require 'socket'

server = TCPServer.new('localhost', 2345)

http_request = ""

loop do

  socket = server.accept
  request = socket.gets

  while line = socket.gets
    puts line
    http_request << line
  end

  response = "Hello World!\n"

  socket.print "HTTP/1.1 200 OK\r\n" +
               "Content-Type: text/plain\r\n" +
               "Content-Length: #{response.bytesize}\r\n" +
               "Connection: close\r\n"

  socket.print "\r\n"

  socket.print response

  puts "DONE with while loop!"

  socket.close
end

In the code above, I am trying to put the HTTP request into a the string http_request and parse that to determine which HTTP response I want to generate. I have tested my code without the while loop and was able to reach the Hello World page in my browser using localhost:2345/test. However, with the addition of the while loop, I am no longer able to load the page and the string "DONE with while loop!" is never printed into the console.

Does anyone know why my web server is hanging? Am I approaching the problem entirely wrong?

回答1:

Your call to socket.gets will continue to wait for more data after all the request has been sent, blocking any further progress. It has no way of knowing that this is a HTTP call and the the request has finished.

A HTTP request consists of the headers and then a blank line indicating the end of the headers. Your code needs to look out for this blank line. You could do this by changing your loop to something like this:

while (line = socket.gets).chomp != ''

This will work for requests that don’t have a body, such as GETs, but things are more difficult when processing requests with bodies. In that case you will need to parse the headers for the Content-Length in order to know how much data to read from the socket. It is even more complex still for chunked requests, you may not need to go that far in your assignment.