diff options
author | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2018-03-28 08:06:39 +0000 |
---|---|---|
committer | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2018-03-28 08:06:39 +0000 |
commit | 2d41d88c4d213f56cd8cefe368699cee896129f1 (patch) | |
tree | 39719e1b0b961d9364d8e49a01fe5bb1db2b0761 | |
parent | 6db6eb572b512998ccfde31610fe18f522d9ba86 (diff) |
webrick/httprequest: use InputBufferSize for chunked requests
While WEBrick::HTTPRequest#body provides a Proc interface
for streaming large request bodies, clients must not force
the server to use an excessively large chunk size.
* lib/webrick/httprequest.rb (read_chunk_size): limit each
read and block.call to :InputBufferSize in config.
* test/webrick/test_httpserver.rb (test_big_chunks): new test
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62963 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | lib/webrick/httprequest.rb | 14 | ||||
-rw-r--r-- | test/webrick/test_httpserver.rb | 33 |
2 files changed, 42 insertions, 5 deletions
diff --git a/lib/webrick/httprequest.rb b/lib/webrick/httprequest.rb index 44d605c58f..b40bcb0d57 100644 --- a/lib/webrick/httprequest.rb +++ b/lib/webrick/httprequest.rb @@ -509,12 +509,16 @@ module WEBrick def read_chunked(socket, block) chunk_size, = read_chunk_size(socket) while chunk_size > 0 - data = read_data(socket, chunk_size) # read chunk-data - if data.nil? || data.bytesize != chunk_size - raise HTTPStatus::BadRequest, "bad chunk data size." - end + begin + sz = [ chunk_size, @buffer_size ].min + data = read_data(socket, sz) # read chunk-data + if data.nil? || data.bytesize != sz + raise HTTPStatus::BadRequest, "bad chunk data size." + end + block.call(data) + end while (chunk_size -= sz) > 0 + read_line(socket) # skip CRLF - block.call(data) chunk_size, = read_chunk_size(socket) end read_header(socket) # trailer + CRLF diff --git a/test/webrick/test_httpserver.rb b/test/webrick/test_httpserver.rb index 0697e073f7..99adcbb52f 100644 --- a/test/webrick/test_httpserver.rb +++ b/test/webrick/test_httpserver.rb @@ -475,4 +475,37 @@ class TestWEBrickHTTPServer < Test::Unit::TestCase end } end + + def test_big_chunks + nr_out = 3 + buf = 'big' # 3 bytes is bigger than 2! + config = { :InputBufferSize => 2 }.freeze + total = 0 + all = '' + TestWEBrick.start_httpserver(config){|server, addr, port, log| + server.mount_proc('/', ->(req, res) { + err = [] + ret = req.body do |chunk| + n = chunk.bytesize + n > config[:InputBufferSize] and err << "#{n} > :InputBufferSize" + total += n + all << chunk + end + ret.nil? or err << 'req.body should return nil' + (buf * nr_out) == all or err << 'input body does not match expected' + res.header['connection'] = 'close' + res.body = err.join("\n") + }) + TCPSocket.open(addr, port) do |c| + c.write("POST / HTTP/1.1\r\nHost: example.com\r\n" \ + "Transfer-Encoding: chunked\r\n\r\n") + chunk = "#{buf.bytesize.to_s(16)}\r\n#{buf}\r\n" + nr_out.times { c.write(chunk) } + c.write("0\r\n\r\n") + head, body = c.read.split("\r\n\r\n") + assert_match %r{\AHTTP/1\.1 200 OK}, head + assert_nil body + end + } + end end |