|
|
f70500 |
From ae0065be15b3253042b65baa54f2953f3a6e6926 Mon Sep 17 00:00:00 2001
|
|
|
f70500 |
From: usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
|
|
|
f70500 |
Date: Wed, 28 Mar 2018 14:47:30 +0000
|
|
|
f70500 |
Subject: [PATCH] merge revision(s) 62960-62965:
|
|
|
f70500 |
MIME-Version: 1.0
|
|
|
f70500 |
Content-Type: text/plain; charset=UTF-8
|
|
|
f70500 |
Content-Transfer-Encoding: 8bit
|
|
|
f70500 |
|
|
|
f70500 |
webrick: use IO.copy_stream for multipart response
|
|
|
f70500 |
|
|
|
f70500 |
Use the new Proc response body feature to generate a multipart
|
|
|
f70500 |
range response dynamically. We use a flat array to minimize
|
|
|
f70500 |
object overhead as much as possible; as many ranges may fit
|
|
|
f70500 |
into an HTTP request header.
|
|
|
f70500 |
|
|
|
f70500 |
* lib/webrick/httpservlet/filehandler.rb (multipart_body): new method
|
|
|
f70500 |
(make_partial_content): use multipart_body
|
|
|
f70500 |
------------------------------------------------------------------------
|
|
|
f70500 |
r62960 | normal | 2018-03-28 17:06:23 +0900 (水, 28 3 2018) | 13 lines
|
|
|
f70500 |
|
|
|
f70500 |
webrick/httprequest: limit request headers size
|
|
|
f70500 |
|
|
|
f70500 |
We use the same 112 KB limit started (AFAIK) by Mongrel, Thin,
|
|
|
f70500 |
and Puma to prevent malicious users from using up all the memory
|
|
|
f70500 |
with a single request. This also limits the damage done by
|
|
|
f70500 |
excessive ranges in multipart Range: requests.
|
|
|
f70500 |
|
|
|
f70500 |
Due to the way we rely on IO#gets and the desire to keep
|
|
|
f70500 |
the code simple, the actual maximum header may be 4093 bytes
|
|
|
f70500 |
larger than 112 KB, but we're splitting hairs at that point.
|
|
|
f70500 |
|
|
|
f70500 |
* lib/webrick/httprequest.rb: define MAX_HEADER_LENGTH
|
|
|
f70500 |
(read_header): raise when headers exceed max length
|
|
|
f70500 |
------------------------------------------------------------------------
|
|
|
f70500 |
r62961 | normal | 2018-03-28 17:06:28 +0900 (水, 28 3 2018) | 9 lines
|
|
|
f70500 |
|
|
|
f70500 |
webrick/httpservlet/cgihandler: reduce memory use
|
|
|
f70500 |
|
|
|
f70500 |
WEBrick::HTTPRequest#body can be passed a block to process the
|
|
|
f70500 |
body in chunks. Use this feature to avoid building a giant
|
|
|
f70500 |
string in memory.
|
|
|
f70500 |
|
|
|
f70500 |
* lib/webrick/httpservlet/cgihandler.rb (do_GET):
|
|
|
f70500 |
avoid reading entire request body into memory
|
|
|
f70500 |
(do_POST is aliased to do_GET, so it handles bodies)
|
|
|
f70500 |
------------------------------------------------------------------------
|
|
|
f70500 |
r62962 | normal | 2018-03-28 17:06:34 +0900 (水, 28 3 2018) | 7 lines
|
|
|
f70500 |
|
|
|
f70500 |
webrick/httprequest: raise correct exception
|
|
|
f70500 |
|
|
|
f70500 |
"BadRequest" alone does not resolve correctly, it is in the
|
|
|
f70500 |
HTTPStatus namespace.
|
|
|
f70500 |
|
|
|
f70500 |
* lib/webrick/httprequest.rb (read_chunked): use correct exception
|
|
|
f70500 |
* test/webrick/test_httpserver.rb (test_eof_in_chunk): new test
|
|
|
f70500 |
------------------------------------------------------------------------
|
|
|
f70500 |
r62963 | normal | 2018-03-28 17:06:39 +0900 (水, 28 3 2018) | 9 lines
|
|
|
f70500 |
|
|
|
f70500 |
webrick/httprequest: use InputBufferSize for chunked requests
|
|
|
f70500 |
|
|
|
f70500 |
While WEBrick::HTTPRequest#body provides a Proc interface
|
|
|
f70500 |
for streaming large request bodies, clients must not force
|
|
|
f70500 |
the server to use an excessively large chunk size.
|
|
|
f70500 |
|
|
|
f70500 |
* lib/webrick/httprequest.rb (read_chunk_size): limit each
|
|
|
f70500 |
read and block.call to :InputBufferSize in config.
|
|
|
f70500 |
* test/webrick/test_httpserver.rb (test_big_chunks): new test
|
|
|
f70500 |
------------------------------------------------------------------------
|
|
|
f70500 |
r62964 | normal | 2018-03-28 17:06:44 +0900 (水, 28 3 2018) | 9 lines
|
|
|
f70500 |
|
|
|
f70500 |
webrick: add test for Digest auth-int
|
|
|
f70500 |
|
|
|
f70500 |
No changes to the actual code, this is a new test for
|
|
|
f70500 |
a feature for which no tests existed. I don't understand
|
|
|
f70500 |
the Digest authentication code well at all, but this is
|
|
|
f70500 |
necessary for the subsequent change.
|
|
|
f70500 |
|
|
|
f70500 |
* test/webrick/test_httpauth.rb (test_digest_auth_int): new test
|
|
|
f70500 |
(credentials_for_request): support bodies with POST
|
|
|
f70500 |
------------------------------------------------------------------------
|
|
|
f70500 |
r62965 | normal | 2018-03-28 17:06:49 +0900 (水, 28 3 2018) | 18 lines
|
|
|
f70500 |
|
|
|
f70500 |
webrick/httpauth/digestauth: stream req.body
|
|
|
f70500 |
|
|
|
f70500 |
WARNING! WARNING! WARNING! LIKELY BROKEN CHANGE
|
|
|
f70500 |
|
|
|
f70500 |
Pass a proc to WEBrick::HTTPRequest#body to avoid reading a
|
|
|
f70500 |
potentially large request body into memory during
|
|
|
f70500 |
authentication.
|
|
|
f70500 |
|
|
|
f70500 |
WARNING! this will break apps completely which want to do
|
|
|
f70500 |
something with the body besides calculating the MD5 digest
|
|
|
f70500 |
of it.
|
|
|
f70500 |
|
|
|
f70500 |
Also, keep in mind that probably nobody uses "auth-int".
|
|
|
f70500 |
Servers such as Apache, lighttpd, nginx don't seem to
|
|
|
f70500 |
support it; nor does curl when using POST/PUT bodies;
|
|
|
f70500 |
and we didn't have tests for it until now...
|
|
|
f70500 |
|
|
|
f70500 |
* lib/webrick/httpauth/digestauth.rb (_authenticate): stream req.body
|
|
|
f70500 |
|
|
|
f70500 |
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_2@63021 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
f70500 |
---
|
|
|
f70500 |
lib/webrick/httpauth/digestauth.rb | 8 ++-
|
|
|
f70500 |
lib/webrick/httprequest.rb | 23 +++++--
|
|
|
f70500 |
lib/webrick/httpservlet/cgihandler.rb | 4 +-
|
|
|
f70500 |
test/webrick/test_httpauth.rb | 90 ++++++++++++++++++++++++++-
|
|
|
f70500 |
test/webrick/test_httpserver.rb | 67 ++++++++++++++++++++
|
|
|
f70500 |
5 files changed, 178 insertions(+), 14 deletions(-)
|
|
|
f70500 |
|
|
|
f70500 |
diff --git a/lib/webrick/httpauth/digestauth.rb b/lib/webrick/httpauth/digestauth.rb
|
|
|
f70500 |
index 78ad45b233..2a2319e9b1 100644
|
|
|
f70500 |
--- a/lib/webrick/httpauth/digestauth.rb
|
|
|
f70500 |
+++ b/lib/webrick/httpauth/digestauth.rb
|
|
|
f70500 |
@@ -235,9 +235,11 @@ module WEBrick
|
|
|
f70500 |
ha2 = hexdigest(req.request_method, auth_req['uri'])
|
|
|
f70500 |
ha2_res = hexdigest("", auth_req['uri'])
|
|
|
f70500 |
elsif auth_req['qop'] == "auth-int"
|
|
|
f70500 |
- ha2 = hexdigest(req.request_method, auth_req['uri'],
|
|
|
f70500 |
- hexdigest(req.body))
|
|
|
f70500 |
- ha2_res = hexdigest("", auth_req['uri'], hexdigest(res.body))
|
|
|
f70500 |
+ body_digest = @h.new
|
|
|
f70500 |
+ req.body { |chunk| body_digest.update(chunk) }
|
|
|
f70500 |
+ body_digest = body_digest.hexdigest
|
|
|
f70500 |
+ ha2 = hexdigest(req.request_method, auth_req['uri'], body_digest)
|
|
|
f70500 |
+ ha2_res = hexdigest("", auth_req['uri'], body_digest)
|
|
|
f70500 |
end
|
|
|
f70500 |
|
|
|
f70500 |
if auth_req['qop'] == "auth" || auth_req['qop'] == "auth-int"
|
|
|
f70500 |
diff --git a/lib/webrick/httprequest.rb b/lib/webrick/httprequest.rb
|
|
|
f70500 |
index 76420730b1..b3bcea7b3d 100644
|
|
|
f70500 |
--- a/lib/webrick/httprequest.rb
|
|
|
f70500 |
+++ b/lib/webrick/httprequest.rb
|
|
|
f70500 |
@@ -412,9 +412,13 @@ module WEBrick
|
|
|
f70500 |
|
|
|
f70500 |
MAX_URI_LENGTH = 2083 # :nodoc:
|
|
|
f70500 |
|
|
|
f70500 |
+ # same as Mongrel, Thin and Puma
|
|
|
f70500 |
+ MAX_HEADER_LENGTH = (112 * 1024) # :nodoc:
|
|
|
f70500 |
+
|
|
|
f70500 |
def read_request_line(socket)
|
|
|
f70500 |
@request_line = read_line(socket, MAX_URI_LENGTH) if socket
|
|
|
f70500 |
- if @request_line.bytesize >= MAX_URI_LENGTH and @request_line[-1, 1] != LF
|
|
|
f70500 |
+ @request_bytes = @request_line.bytesize
|
|
|
f70500 |
+ if @request_bytes >= MAX_URI_LENGTH and @request_line[-1, 1] != LF
|
|
|
f70500 |
raise HTTPStatus::RequestURITooLarge
|
|
|
f70500 |
end
|
|
|
f70500 |
@request_time = Time.now
|
|
|
f70500 |
@@ -433,6 +437,9 @@ module WEBrick
|
|
|
f70500 |
if socket
|
|
|
f70500 |
while line = read_line(socket)
|
|
|
f70500 |
break if /\A(#{CRLF}|#{LF})\z/om =~ line
|
|
|
f70500 |
+ if (@request_bytes += line.bytesize) > MAX_HEADER_LENGTH
|
|
|
f70500 |
+ raise HTTPStatus::RequestEntityTooLarge, 'headers too large'
|
|
|
f70500 |
+ end
|
|
|
f70500 |
@raw_header << line
|
|
|
f70500 |
end
|
|
|
f70500 |
end
|
|
|
f70500 |
@@ -500,12 +507,16 @@ module WEBrick
|
|
|
f70500 |
def read_chunked(socket, block)
|
|
|
f70500 |
chunk_size, = read_chunk_size(socket)
|
|
|
f70500 |
while chunk_size > 0
|
|
|
f70500 |
- data = read_data(socket, chunk_size) # read chunk-data
|
|
|
f70500 |
- if data.nil? || data.bytesize != chunk_size
|
|
|
f70500 |
- raise BadRequest, "bad chunk data size."
|
|
|
f70500 |
- end
|
|
|
f70500 |
+ begin
|
|
|
f70500 |
+ sz = [ chunk_size, @buffer_size ].min
|
|
|
f70500 |
+ data = read_data(socket, sz) # read chunk-data
|
|
|
f70500 |
+ if data.nil? || data.bytesize != sz
|
|
|
f70500 |
+ raise HTTPStatus::BadRequest, "bad chunk data size."
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+ block.call(data)
|
|
|
f70500 |
+ end while (chunk_size -= sz) > 0
|
|
|
f70500 |
+
|
|
|
f70500 |
read_line(socket) # skip CRLF
|
|
|
f70500 |
- block.call(data)
|
|
|
f70500 |
chunk_size, = read_chunk_size(socket)
|
|
|
f70500 |
end
|
|
|
f70500 |
read_header(socket) # trailer + CRLF
|
|
|
f70500 |
diff --git a/lib/webrick/httpservlet/cgihandler.rb b/lib/webrick/httpservlet/cgihandler.rb
|
|
|
f70500 |
index 7c012ca64b..d5ba756437 100644
|
|
|
f70500 |
--- a/lib/webrick/httpservlet/cgihandler.rb
|
|
|
f70500 |
+++ b/lib/webrick/httpservlet/cgihandler.rb
|
|
|
f70500 |
@@ -66,9 +66,7 @@ module WEBrick
|
|
|
f70500 |
cgi_in.write("%8d" % dump.bytesize)
|
|
|
f70500 |
cgi_in.write(dump)
|
|
|
f70500 |
|
|
|
f70500 |
- if req.body and req.body.bytesize > 0
|
|
|
f70500 |
- cgi_in.write(req.body)
|
|
|
f70500 |
- end
|
|
|
f70500 |
+ req.body { |chunk| cgi_in.write(chunk) }
|
|
|
f70500 |
ensure
|
|
|
f70500 |
cgi_in.close
|
|
|
f70500 |
status = $?.exitstatus
|
|
|
f70500 |
diff --git a/test/webrick/test_httpauth.rb b/test/webrick/test_httpauth.rb
|
|
|
f70500 |
index 2414be9096..842668f54e 100644
|
|
|
f70500 |
--- a/test/webrick/test_httpauth.rb
|
|
|
f70500 |
+++ b/test/webrick/test_httpauth.rb
|
|
|
f70500 |
@@ -3,6 +3,7 @@ require "net/http"
|
|
|
f70500 |
require "tempfile"
|
|
|
f70500 |
require "webrick"
|
|
|
f70500 |
require "webrick/httpauth/basicauth"
|
|
|
f70500 |
+require "stringio"
|
|
|
f70500 |
require_relative "utils"
|
|
|
f70500 |
|
|
|
f70500 |
class TestWEBrickHTTPAuth < Test::Unit::TestCase
|
|
|
f70500 |
@@ -182,12 +183,97 @@ class TestWEBrickHTTPAuth < Test::Unit::TestCase
|
|
|
f70500 |
}
|
|
|
f70500 |
end
|
|
|
f70500 |
|
|
|
f70500 |
+ def test_digest_auth_int
|
|
|
f70500 |
+ log_tester = lambda {|log, access_log|
|
|
|
f70500 |
+ log.reject! {|line| /\A\s*\z/ =~ line }
|
|
|
f70500 |
+ pats = [
|
|
|
f70500 |
+ /ERROR Digest wb auth-int realm: no credentials in the request\./,
|
|
|
f70500 |
+ /ERROR WEBrick::HTTPStatus::Unauthorized/,
|
|
|
f70500 |
+ /ERROR Digest wb auth-int realm: foo: digest unmatch\./
|
|
|
f70500 |
+ ]
|
|
|
f70500 |
+ pats.each {|pat|
|
|
|
f70500 |
+ assert(!log.grep(pat).empty?, "webrick log doesn't have expected error: #{pat.inspect}")
|
|
|
f70500 |
+ log.reject! {|line| pat =~ line }
|
|
|
f70500 |
+ }
|
|
|
f70500 |
+ assert_equal([], log)
|
|
|
f70500 |
+ }
|
|
|
f70500 |
+ TestWEBrick.start_httpserver({}, log_tester) {|server, addr, port, log|
|
|
|
f70500 |
+ realm = "wb auth-int realm"
|
|
|
f70500 |
+ path = "/digest_auth_int"
|
|
|
f70500 |
+
|
|
|
f70500 |
+ Tempfile.create("test_webrick_auth_int") {|tmpfile|
|
|
|
f70500 |
+ tmpfile.close
|
|
|
f70500 |
+ tmp_pass = WEBrick::HTTPAuth::Htdigest.new(tmpfile.path)
|
|
|
f70500 |
+ tmp_pass.set_passwd(realm, "foo", "Hunter2")
|
|
|
f70500 |
+ tmp_pass.flush
|
|
|
f70500 |
+
|
|
|
f70500 |
+ htdigest = WEBrick::HTTPAuth::Htdigest.new(tmpfile.path)
|
|
|
f70500 |
+ users = []
|
|
|
f70500 |
+ htdigest.each{|user, pass| users << user }
|
|
|
f70500 |
+ assert_equal %w(foo), users
|
|
|
f70500 |
+
|
|
|
f70500 |
+ auth = WEBrick::HTTPAuth::DigestAuth.new(
|
|
|
f70500 |
+ :Realm => realm, :UserDB => htdigest,
|
|
|
f70500 |
+ :Algorithm => 'MD5',
|
|
|
f70500 |
+ :Logger => server.logger,
|
|
|
f70500 |
+ :Qop => %w(auth-int),
|
|
|
f70500 |
+ )
|
|
|
f70500 |
+ server.mount_proc(path){|req, res|
|
|
|
f70500 |
+ auth.authenticate(req, res)
|
|
|
f70500 |
+ res.body = "bbb"
|
|
|
f70500 |
+ }
|
|
|
f70500 |
+ Net::HTTP.start(addr, port) do |http|
|
|
|
f70500 |
+ post = Net::HTTP::Post.new(path)
|
|
|
f70500 |
+ params = {}
|
|
|
f70500 |
+ data = 'hello=world'
|
|
|
f70500 |
+ body = StringIO.new(data)
|
|
|
f70500 |
+ post.content_length = data.bytesize
|
|
|
f70500 |
+ post['Content-Type'] = 'application/x-www-form-urlencoded'
|
|
|
f70500 |
+ post.body_stream = body
|
|
|
f70500 |
+
|
|
|
f70500 |
+ http.request(post) do |res|
|
|
|
f70500 |
+ assert_equal('401', res.code, log.call)
|
|
|
f70500 |
+ res["www-authenticate"].scan(DIGESTRES_) do |key, quoted, token|
|
|
|
f70500 |
+ params[key.downcase] = token || quoted.delete('\\')
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+ params['uri'] = "http://#{addr}:#{port}#{path}"
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+
|
|
|
f70500 |
+ body.rewind
|
|
|
f70500 |
+ cred = credentials_for_request('foo', 'Hunter3', params, body)
|
|
|
f70500 |
+ post['Authorization'] = cred
|
|
|
f70500 |
+ post.body_stream = body
|
|
|
f70500 |
+ http.request(post){|res|
|
|
|
f70500 |
+ assert_equal('401', res.code, log.call)
|
|
|
f70500 |
+ assert_not_equal("bbb", res.body, log.call)
|
|
|
f70500 |
+ }
|
|
|
f70500 |
+
|
|
|
f70500 |
+ body.rewind
|
|
|
f70500 |
+ cred = credentials_for_request('foo', 'Hunter2', params, body)
|
|
|
f70500 |
+ post['Authorization'] = cred
|
|
|
f70500 |
+ post.body_stream = body
|
|
|
f70500 |
+ http.request(post){|res| assert_equal("bbb", res.body, log.call)}
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+ }
|
|
|
f70500 |
+ }
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+
|
|
|
f70500 |
private
|
|
|
f70500 |
- def credentials_for_request(user, password, params)
|
|
|
f70500 |
+ def credentials_for_request(user, password, params, body = nil)
|
|
|
f70500 |
cnonce = "hoge"
|
|
|
f70500 |
nonce_count = 1
|
|
|
f70500 |
ha1 = "#{user}:#{params['realm']}:#{password}"
|
|
|
f70500 |
- ha2 = "GET:#{params['uri']}"
|
|
|
f70500 |
+ if body
|
|
|
f70500 |
+ dig = Digest::MD5.new
|
|
|
f70500 |
+ while buf = body.read(16384)
|
|
|
f70500 |
+ dig.update(buf)
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+ body.rewind
|
|
|
f70500 |
+ ha2 = "POST:#{params['uri']}:#{dig.hexdigest}"
|
|
|
f70500 |
+ else
|
|
|
f70500 |
+ ha2 = "GET:#{params['uri']}"
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+
|
|
|
f70500 |
request_digest =
|
|
|
f70500 |
"#{Digest::MD5.hexdigest(ha1)}:" \
|
|
|
f70500 |
"#{params['nonce']}:#{'%08x' % nonce_count}:#{cnonce}:#{params['qop']}:" \
|
|
|
f70500 |
diff --git a/test/webrick/test_httpserver.rb b/test/webrick/test_httpserver.rb
|
|
|
f70500 |
index ffebf7e843..f1d58b40f5 100644
|
|
|
f70500 |
--- a/test/webrick/test_httpserver.rb
|
|
|
f70500 |
+++ b/test/webrick/test_httpserver.rb
|
|
|
f70500 |
@@ -366,4 +366,71 @@ class TestWEBrickHTTPServer < Test::Unit::TestCase
|
|
|
f70500 |
}
|
|
|
f70500 |
assert_equal(requested, 1)
|
|
|
f70500 |
end
|
|
|
f70500 |
+
|
|
|
f70500 |
+ def test_gigantic_request_header
|
|
|
f70500 |
+ log_tester = lambda {|log, access_log|
|
|
|
f70500 |
+ assert_equal 1, log.size
|
|
|
f70500 |
+ assert log[0].include?('ERROR headers too large')
|
|
|
f70500 |
+ }
|
|
|
f70500 |
+ TestWEBrick.start_httpserver({}, log_tester){|server, addr, port, log|
|
|
|
f70500 |
+ server.mount('/', WEBrick::HTTPServlet::FileHandler, __FILE__)
|
|
|
f70500 |
+ TCPSocket.open(addr, port) do |c|
|
|
|
f70500 |
+ c.write("GET / HTTP/1.0\r\n")
|
|
|
f70500 |
+ junk = "X-Junk: #{' ' * 1024}\r\n"
|
|
|
f70500 |
+ assert_raise(Errno::ECONNRESET, Errno::EPIPE) do
|
|
|
f70500 |
+ loop { c.write(junk) }
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+ }
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+
|
|
|
f70500 |
+ def test_eof_in_chunk
|
|
|
f70500 |
+ log_tester = lambda do |log, access_log|
|
|
|
f70500 |
+ assert_equal 1, log.size
|
|
|
f70500 |
+ assert log[0].include?('ERROR bad chunk data size')
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+ TestWEBrick.start_httpserver({}, log_tester){|server, addr, port, log|
|
|
|
f70500 |
+ server.mount_proc('/', ->(req, res) { res.body = req.body })
|
|
|
f70500 |
+ TCPSocket.open(addr, port) do |c|
|
|
|
f70500 |
+ c.write("POST / HTTP/1.1\r\nHost: example.com\r\n" \
|
|
|
f70500 |
+ "Transfer-Encoding: chunked\r\n\r\n5\r\na")
|
|
|
f70500 |
+ c.shutdown(Socket::SHUT_WR) # trigger EOF in server
|
|
|
f70500 |
+ res = c.read
|
|
|
f70500 |
+ assert_match %r{\AHTTP/1\.1 400 }, res
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+ }
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+
|
|
|
f70500 |
+ def test_big_chunks
|
|
|
f70500 |
+ nr_out = 3
|
|
|
f70500 |
+ buf = 'big' # 3 bytes is bigger than 2!
|
|
|
f70500 |
+ config = { :InputBufferSize => 2 }.freeze
|
|
|
f70500 |
+ total = 0
|
|
|
f70500 |
+ all = ''
|
|
|
f70500 |
+ TestWEBrick.start_httpserver(config){|server, addr, port, log|
|
|
|
f70500 |
+ server.mount_proc('/', ->(req, res) {
|
|
|
f70500 |
+ err = []
|
|
|
f70500 |
+ ret = req.body do |chunk|
|
|
|
f70500 |
+ n = chunk.bytesize
|
|
|
f70500 |
+ n > config[:InputBufferSize] and err << "#{n} > :InputBufferSize"
|
|
|
f70500 |
+ total += n
|
|
|
f70500 |
+ all << chunk
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+ ret.nil? or err << 'req.body should return nil'
|
|
|
f70500 |
+ (buf * nr_out) == all or err << 'input body does not match expected'
|
|
|
f70500 |
+ res.header['connection'] = 'close'
|
|
|
f70500 |
+ res.body = err.join("\n")
|
|
|
f70500 |
+ })
|
|
|
f70500 |
+ TCPSocket.open(addr, port) do |c|
|
|
|
f70500 |
+ c.write("POST / HTTP/1.1\r\nHost: example.com\r\n" \
|
|
|
f70500 |
+ "Transfer-Encoding: chunked\r\n\r\n")
|
|
|
f70500 |
+ chunk = "#{buf.bytesize.to_s(16)}\r\n#{buf}\r\n"
|
|
|
f70500 |
+ nr_out.times { c.write(chunk) }
|
|
|
f70500 |
+ c.write("0\r\n\r\n")
|
|
|
f70500 |
+ head, body = c.read.split("\r\n\r\n")
|
|
|
f70500 |
+ assert_match %r{\AHTTP/1\.1 200 OK}, head
|
|
|
f70500 |
+ assert_nil body
|
|
|
f70500 |
+ end
|
|
|
f70500 |
+ }
|
|
|
f70500 |
+ end
|
|
|
f70500 |
end
|
|
|
f70500 |
--
|
|
|
f70500 |
2.17.1
|
|
|
f70500 |
|