2010-03-10 3 views
5

Я хочу создать чрезвычайно простой веб-сервер для разработки в Ruby (нет, не хотите использовать готовые решения).Написание простого веб-сервера в Ruby

Вот код:

#!/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 

Идея заключается в том, чтобы запустить этот сценарий из командной строки, обеспечивая другой сценарий, который получит запрос на стандартный ввод и возвращает полный ответ на его стандартный выход.

До сих пор так хорошо, но это оказывается очень хрупким, так как она разрушает на второй запрос с ошибкой:

/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 

Любая идея, как улучшить код выше, чтобы быть достаточным для удобного использования ?

Версия: Ubuntu 9.10 (2.6.31-20-родовой), Ruby 1.8.7 (2009-06-12 174 номер патчи) [i486-Linux]

+0

Joó, Так как вы и я получаем такие разные результаты, возможно, вы должны добавить к своему вопросу свои версии Ruby и OS. –

+0

Я добавил версии. –

ответ

4

Проблема, как представляется, в детском сценарии, так как родительский сценарий в вашем вопросе работает на моем окне (Debian Squeeze, Ruby 1.8.7 249 номера патчей):

Я создал манекен ребенок сценарий bar.rb:

#!/usr/bin/ruby1.8 

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

Я побежал сценарий, передавая ему путь к вспомогательному сценария:

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

Я ударил его с Wget:

$ wget localhost:8080/index 

И увидел выход манекена сценария:

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 

Я также видел, что Wget получил то, что он послал:

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

Он работал то же самое, независимо от того, сколько раз я ударил его с помощью wget.

+0

Я попробовал свой сценарий для детей, и он выбросил ошибку для первого запуска. Возможно, здесь играет разница между уровнями ОС. –

+0

ОК, я нашел, где проблема. Это в дочернем скрипте: я просто распечатал базовый HTTP-ответ, в то время как вы сначала прочитали stdin. Теперь вопрос в том, почему это необходимо. –