Project

General

Profile

Actions

Bug #6230

closed

[WEBrick] WEBrick::HTTPResponse#body の IO オブジェクトの読み込みに read メソッドを使っているため必要以上にブロックされる

Added by nobuoka (yu nobuoka) over 12 years ago. Updated over 12 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 1.9.3p125 (2012-02-16 revision 34643) [x86_64-linux]
Backport:
[ruby-dev:45471]

Description

WEBrick::HTTPResponse の @body には IO オブジェクトを設定できますが、@body に設定された IO オブジェクトからの読み出しの際に IO#read( @buffer_size ) で行われるため、@buffer_size よりも小さなデータを定期的に送りたい場合などに、必要以上にブロックされてしまいます。 IO#read メソッドの代わりに IO#readpartial メソッドを使用するとよいかと思うのですがどうでしょうか。

patch を添付します。

diff --git a/lib/webrick/httpresponse.rb b/lib/webrick/httpresponse.rb
index 0d36c07..4942588 100644
--- a/lib/webrick/httpresponse.rb
+++ b/lib/webrick/httpresponse.rb
@@ -330,13 +330,17 @@ module WEBrick
if @request_method == "HEAD"

do nothing

elsif chunked?

  •      while buf = @body.read(@buffer_size)
    
  •        next if buf.empty?
    
  •        data = ""
    
  •        data << format("%x", buf.bytesize) << CRLF
    
  •        data << buf << CRLF
    
  •        _write_data(socket, data)
    
  •        @sent_size += buf.bytesize
    
  •      begin
    
  •        while true
    
  •          buf = @body.readpartial( @buffer_size )
    
  •          next if buf.empty?
    
  •          data = ""
    
  •          data << format("%x", buf.bytesize) << CRLF
    
  •          data << buf << CRLF
    
  •          _write_data(socket, data)
    
  •          @sent_size += buf.bytesize
    
  •        end
    
  •      resuce EOFError # do nothing
         end
         _write_data(socket, "0#{CRLF}#{CRLF}")
       else
    

具体的に困る状況は、例えば以下のように Server-Sent Events で応答するサーバーを実現するような場合です。

require 'webrick'

server = WEBrick::HTTPServer.new( Port: 8000 )
server.mount_proc( '/time_stream' ) do |req, res|
res.content_type = 'text/event-stream'
r,w = IO.pipe
res.body = r
res.chunked = true
t = Thread.new do
10.times do
Thread.pass
w << 'data: ' << Time.now.to_s << "\x0D\x0A"
w << "\x0D\x0A"
sleep 1
end
w.close()
end
end

trap :INT do server.shutdown end
server.start

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0