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?
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:
This will work for requests that don’t have a body, such as
GET
s, but things are more difficult when processing requests with bodies. In that case you will need to parse the headers for theContent-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.