Skip to content

Commit

Permalink
webrick: support Proc objects as body responses
Browse files Browse the repository at this point in the history
* lib/webrick/httpresponse.rb (send_body): call send_body_proc
  (send_body_proc): new method
  (class ChunkedWrapper): new class

* test/webrick/test_httpresponse.rb (test_send_body_proc): new test
  (test_send_body_proc_chunked): ditto
  [Feature #855]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60584 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information
normal committed Oct 30, 2017
1 parent 0b0e71b commit bb88b1a
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 0 deletions.
35 changes: 35 additions & 0 deletions lib/webrick/httpresponse.rb
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ def send_header(socket) # :nodoc:
def send_body(socket) # :nodoc:
if @body.respond_to? :readpartial then
send_body_io(socket)
elsif @body.respond_to?(:call) then
send_body_proc(socket)
else
send_body_string(socket)
end
Expand Down Expand Up @@ -440,6 +442,39 @@ def send_body_string(socket)
end
end

def send_body_proc(socket)
if @request_method == "HEAD"
# do nothing
elsif chunked?
@body.call(ChunkedWrapper.new(socket, self))
_write_data(socket, "0#{CRLF}#{CRLF}")
else
size = @header['content-length'].to_i
@body.call(socket)
@sent_size = size
end
end

class ChunkedWrapper
def initialize(socket, resp)
@socket = socket
@resp = resp
end

def write(buf)
return if buf.empty?
socket = @socket
@resp.instance_eval {
size = buf.bytesize
data = "#{size.to_s(16)}#{CRLF}#{buf}#{CRLF}"
_write_data(socket, data)
data.clear
@sent_size += size
}
end
alias :<< :write
end

def _send_file(output, input, offset, size)
while offset > 0
sz = @buffer_size < size ? @buffer_size : size
Expand Down
23 changes: 23 additions & 0 deletions test/webrick/test_httpresponse.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,29 @@ def test_send_body_string_io_chunked
assert_equal 0, logger.messages.length
end

def test_send_body_proc
@res.body = Proc.new { |out| out.write('hello') }
IO.pipe do |r, w|
@res.send_body(w)
w.close
r.binmode
assert_equal 'hello', r.read
end
assert_equal 0, logger.messages.length
end

def test_send_body_proc_chunked
@res.body = Proc.new { |out| out.write('hello') }
@res.chunked = true
IO.pipe do |r, w|
@res.send_body(w)
w.close
r.binmode
assert_equal "5\r\nhello\r\n0\r\n\r\n", r.read
end
assert_equal 0, logger.messages.length
end

def test_set_error
status = 400
message = 'missing attribute'
Expand Down

0 comments on commit bb88b1a

Please sign in to comment.