summaryrefslogtreecommitdiff
path: root/lib/webrick/httprequest.rb
diff options
context:
space:
mode:
authornormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-03-28 08:06:55 +0000
committernormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-03-28 08:06:55 +0000
commit706c028909df2f9526c1cde1c2baa6bc0b4d318a (patch)
tree0d949ef750c32079b9220f0c8264e945535b75ad /lib/webrick/httprequest.rb
parent32e277acbf35de454befc1573aff1063a55403cf (diff)
webrick/httpproxy: stream request and response bodies
Reading entire request or response bodies into memory can lead to trivial denial-of-service attacks. Introduce Fibers in both cases to allow streaming. WEBrick::HTTPRequest gains a new body_reader method to prepare itself as a source for IO.copy_stream. This allows the WEBrick::HTTPRequest object to be used as the Net::HTTPGenericRequest#body_stream= arg for Net::HTTP. For HTTP proxy response bodies, we also use a Fiber to to make the HTTP request and read the response body. * lib/webrick/httprequest.rb (body_reader): new method (readpartial): ditto * lib/webrick/httpproxy.rb (perform_proxy_request): use Fiber to stream response body (do_GET, do_HEAD): adjust call (do_POST): adjust call and supply body_reader * test/webrick/test_httprequest.rb (test_chunked): test for IO.copy_stream compatibility * test/webrick/test_httpproxy.rb (test_big_bodies): new test git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62966 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/webrick/httprequest.rb')
-rw-r--r--lib/webrick/httprequest.rb26
1 files changed, 26 insertions, 0 deletions
diff --git a/lib/webrick/httprequest.rb b/lib/webrick/httprequest.rb
index b40bcb0d57..c40f7c16e4 100644
--- a/lib/webrick/httprequest.rb
+++ b/lib/webrick/httprequest.rb
@@ -258,6 +258,32 @@ module WEBrick
end
##
+ # Prepares the HTTPRequest object for use as the
+ # source for IO.copy_stream
+
+ def body_reader
+ @body_tmp = []
+ @body_rd = Fiber.new do
+ body do |buf|
+ @body_tmp << buf
+ Fiber.yield
+ end
+ end
+ @body_rd.resume # grab the first chunk and yield
+ self
+ end
+
+ # for IO.copy_stream. Note: we may return a larger string than +size+
+ # here; but IO.copy_stream does not care.
+ def readpartial(size, buf = ''.b) # :nodoc
+ res = @body_tmp.shift or raise EOFError, 'end of file reached'
+ buf.replace(res)
+ res.clear
+ @body_rd.resume # get more chunks
+ buf
+ end
+
+ ##
# Request query as a Hash
def query