Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing a simple webserver in Ruby

Tags:

ruby

webserver

I want to create an extremely simple web server for development purposes in Ruby (no, don’t want to use ready solutions).

Here is the code:

#!/usr/bin/ruby

require 'socket'

server = TCPServer.new('127.0.0.1', 8080)

while connection = server.accept
  headers = []
  length  = 0

  while line = connection.gets
    headers << line

    if line =~ /^Content-Length:\s+(\d+)/i
      length = $1.to_i
    end

    break if line == "\r\n"
  end

  body = connection.readpartial(length)

  IO.popen(ARGV[0], 'r+') do |script|
    script.print(headers.join + body)
    script.close_write
    connection.print script.read
  end

  connection.close
end

The idea is to run this script from the command line, providing another script, which will get the request on its standard input, and gives back the complete response on its standard output.

So far so good, but this turns out to be really fragile, as it breaks on the second request with the error:

/usr/bin/serve:24:in `write': Broken pipe (Errno::EPIPE)
    from /usr/bin/serve:24:in `print'
    from /usr/bin/serve:24
    from /usr/bin/serve:23:in `popen'
    from /usr/bin/serve:23

Any idea how to improve the above code to be sufficient for easy use?

Versions: Ubuntu 9.10 (2.6.31-20-generic), Ruby 1.8.7 (2009-06-12 patchlevel 174) [i486-linux]

like image 750
Joó Ádám Avatar asked Mar 10 '10 13:03

Joó Ádám


2 Answers

The problem appears to be in the child script, since the parent script in your question runs on my box (Debian Squeeze, Ruby 1.8.7 patchlevel 249):

I created the dummy child script bar.rb:

#!/usr/bin/ruby1.8

s = $stdin.read
$stderr.puts s
print s

I then ran your script, passing it the path to the dummy script:

$ /tmp/foo.rb /tmp/bar.rb

The I hit it with wget:

$ wget localhost:8080/index

And saw the dummy script's output:

GET /index HTTP/1.0^M
User-Agent: Wget/1.12 (linux-gnu)^M
Accept: */*^M
Host: localhost:8080^M
Connection: Keep-Alive^M
^M

I also saw that wget received what it sent:

$ cat index
GET /index HTTP/1.0
User-Agent: Wget/1.12 (linux-gnu)
Accept: */*
Host: localhost:8080
Connection: Keep-Alive

It worked the same no matter how many times I hit it with wget.

like image 97
Wayne Conrad Avatar answered Nov 01 '22 03:11

Wayne Conrad


The Ruby Web Servers Booklet describes most of web server implementation strategies.

like image 34
clyfe Avatar answered Nov 01 '22 03:11

clyfe