2010-03-10 26 views
5

Quiero crear un servidor web extremadamente simple para fines de desarrollo en Ruby (no, no quiero usar soluciones listas).Escribir un servidor web simple en Ruby

Aquí está el código:

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

La idea es ejecutar este script desde la línea de comandos, proporcionando otro guión, que conseguirá la solicitud en su entrada estándar, y devuelve la respuesta completa en su salida estándar.

Hasta aquí todo bien, pero esto resulta ser muy frágil, ya que se rompe en la segunda solicitud con el 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 

alguna idea de cómo mejorar el código anterior para ser suficiente para un uso sencillo ?

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

+0

Joó, dado que usted y yo estamos obteniendo resultados tan diferentes, tal vez debería agregar a su pregunta sus versiones de Ruby y OS. –

+0

He agregado las versiones. –

Respuesta

4

El problema parece estar en el guión niño, ya que el guión de los padres en su pregunta se ejecuta en mi caja (Debian Squeeze, Ruby 1.8.7 Patchlevel 249):

creé el simulado bar.rb escritura infantil:

#!/usr/bin/ruby1.8 

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

entonces me encontré con la secuencia de comandos, pasándole la ruta a la secuencia ficticia:

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

El golpeo con wget:

$ wget localhost:8080/index 

Y vi la salida del script básico:

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 

También vi que wget recibió lo que envió:

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

Funcionó lo mismo no importa cuántas veces lo golpeé con wget.

+0

Probé la secuencia de comandos de tu hijo y arrojó un error la primera vez. Quizás alguna diferencia de nivel de SO juega aquí. –

+0

Bien, encontré el problema. Está en el script secundario: simplemente imprimí una respuesta HTTP básica, mientras que primero has leído stdin. Ahora la pregunta es por qué es necesario hacerlo. –