I am wondering if the following is a bug in WEBrick.

If you return an open IO object as the response body, and the client
requests HTTP/1.1, then the response is unterminated - so the client hangs
around forever waiting for the end of the response (or at least, until the
HTTP/1.1 connection times out)

You can demonstrate it like this:

  require 'webrick'

  s = WEBrick::HTTPServer.new(:Port => 1234)
  s.mount_proc("/test") { |req,resp| resp.body = File.open("/etc/motd") }

  trap('INT') { s.stop; s.shutdown }
  s.start

Then in another window,

  $ wget http://localhost:1234/test
  --17:51:25--  http://localhost:1234/test
             => `test'
  Resolving localhost... 127.0.0.1
  Connecting to localhost|127.0.0.1|:1234... connected.
  HTTP request sent, awaiting response... 200 OK
  Length: unspecified

      [       <=>                           ] 410           --.--K/s            

It just sits here.

Looking at the raw headers using telnet, all you get is:

  HTTP/1.1 200 OK 
  Date: Thu, 04 Sep 2008 16:41:20 GMT
  Server: WEBrick/1.3.1 (Ruby/1.8.6/2008-03-03)

Now if I understand correctly, with HTTP/1.1 the server should either set
content-length, or use chunked transfer encoding, or set connection: close
and drop the connection after the transfer.

We can't send content-length here because the size of the I/O object is
unknown. So I think WEBrick should set connection: close if chunking hasn't
been enabled.

There is logic in webrick/httpresponse.rb which seems to deal with this sort
of thing, e.g.

      if @status == 304 || @status == 204 || HTTPStatus::info?(@status)
        @header.delete('content-length')
        @body = ""
      elsif chunked?
        @header["transfer-encoding"] = "chunked"
        @header.delete('content-length')
      elsif %r{^multipart/byteranges} =~ @header['content-type']
        @header.delete('content-length')
      elsif @header['content-length'].nil?
        unless @body.is_a?(IO)
          @header['content-length'] = @body ? @body.size : 0
        end
      end

      # Keep-Alive connection.
      if @header['connection'] == "close"
         @keep_alive = false
      elsif keep_alive?
        if chunked? || @header['content-length']
          @header['connection'] = "Keep-Alive"
        end
      else
        @header['connection'] = "close"
      end

but is it incomplete? I can force suitable behaviour by setting
resp.keep_alive = false, but I would have thought this could have been
determined automatically in this case.

I am running 1.8.6p114 but branches/ruby_1_8 is identical bar a spelling
correction in a comment.

Thanks,

Brian.