From: "nobuoka (yu nobuoka)" <nobuoka@...> Date: 2012-03-31T03:58:33+09:00 Subject: [ruby-dev:45471] [ruby-trunk - Bug #6230][Open] [WEBrick] WEBrick::HTTPResponse#body の IO オブジェクトの読み込みに read メソッドを使っているため必要以上にブロックされる Issue #6230 has been reported by nobuoka (yu nobuoka). ---------------------------------------- Bug #6230: [WEBrick] WEBrick::HTTPResponse#body の IO オブジェクトの読み込みに read メソッドを使っているため必要以上にブロックされる https://bugs.ruby-lang.org/issues/6230 Author: nobuoka (yu nobuoka) Status: Open Priority: Normal Assignee: Category: Target version: ruby -v: ruby 1.9.3p125 (2012-02-16 revision 34643) [x86_64-linux] 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 -- http://bugs.ruby-lang.org/