Bug #6230
closed[WEBrick] WEBrick::HTTPResponse#body の IO オブジェクトの読み込みに read メソッドを使っているため必要以上にブロックされる
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