summaryrefslogtreecommitdiff
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 ()
tree0d949ef750c32079b9220f0c8264e945535b75ad
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 . 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
-rw-r--r--lib/webrick/httpproxy.rb74
-rw-r--r--lib/webrick/httprequest.rb26
-rw-r--r--test/webrick/test_httpproxy.rb94
-rw-r--r--test/webrick/test_httprequest.rb10
4 files changed, 172 insertions, 32 deletions
@@ -211,21 +211,15 @@ module WEBrick
end
def do_GET(req, res)
- perform_proxy_request(req, res) do |http, path, header|
- http.get(path, header)
- end
end
def do_HEAD(req, res)
- perform_proxy_request(req, res) do |http, path, header|
- http.head(path, header)
- end
end
def do_POST(req, res)
- perform_proxy_request(req, res) do |http, path, header|
- http.post(path, req.body || "", header)
- end
end
def do_OPTIONS(req, res)
@@ -301,38 +295,56 @@ module WEBrick
return FakeProxyURI
end
- def perform_proxy_request(req, res)
uri = req.request_uri
path = uri.path.dup
path << "?" << uri.query if uri.query
header = setup_proxy_header(req, res)
upstream = setup_upstream_proxy_authentication(req, res, header)
- response = nil
http = Net::HTTP.new(uri.host, uri.port, upstream.host, upstream.port)
- http.start do
- if @config[:ProxyTimeout]
- ################################## these issues are
- http.open_timeout = 30 # secs # necessary (maybe because
- http.read_timeout = 60 # secs # Ruby's bug, but why?)
- ##################################
end
- response = yield(http, path, header)
end
-
- # Persistent connection requirements are mysterious for me.
- # So I will close the connection in every response.
- res['proxy-connection'] = "close"
- res['connection'] = "close"
-
- # Convert Net::HTTP::HTTPResponse to WEBrick::HTTPResponse
- res.status = response.code.to_i
- choose_header(response, res)
- set_cookie(response, res)
- set_via(res)
- res.body = response.body
end
-
# :stopdoc:
end
end
@@ -258,6 +258,32 @@ module WEBrick
end
##
# Request query as a Hash
def query
@@ -118,6 +118,100 @@ class TestWEBrickHTTPProxy < Test::Unit::TestCase
}
end
def make_certificate(key, cn)
subject = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=#{cn}")
exts = [
@@ -237,6 +237,7 @@ GET /
def test_chunked
crlf = "\x0d\x0a"
msg = <<-_end_of_message_
POST /path HTTP/1.1
Host: test.ruby-lang.org:8080
@@ -253,7 +254,14 @@ GET /
msg << "0" << crlf
req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
req.parse(StringIO.new(msg))
- assert_equal(File.read(__FILE__), req.body)
end
def test_forwarded