mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
2d41d88c4d
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
511 lines
19 KiB
Ruby
511 lines
19 KiB
Ruby
# frozen_string_literal: false
|
|
require "test/unit"
|
|
require "net/http"
|
|
require "webrick"
|
|
require_relative "utils"
|
|
|
|
class TestWEBrickHTTPServer < Test::Unit::TestCase
|
|
empty_log = Object.new
|
|
def empty_log.<<(str)
|
|
assert_equal('', str)
|
|
self
|
|
end
|
|
NoLog = WEBrick::Log.new(empty_log, WEBrick::BasicLog::WARN)
|
|
|
|
def teardown
|
|
WEBrick::Utils::TimeoutHandler.terminate
|
|
super
|
|
end
|
|
|
|
def test_mount
|
|
httpd = WEBrick::HTTPServer.new(
|
|
:Logger => NoLog,
|
|
:DoNotListen=>true
|
|
)
|
|
httpd.mount("/", :Root)
|
|
httpd.mount("/foo", :Foo)
|
|
httpd.mount("/foo/bar", :Bar, :bar1)
|
|
httpd.mount("/foo/bar/baz", :Baz, :baz1, :baz2)
|
|
|
|
serv, opts, script_name, path_info = httpd.search_servlet("/")
|
|
assert_equal(:Root, serv)
|
|
assert_equal([], opts)
|
|
assert_equal("", script_name)
|
|
assert_equal("/", path_info)
|
|
|
|
serv, opts, script_name, path_info = httpd.search_servlet("/sub")
|
|
assert_equal(:Root, serv)
|
|
assert_equal([], opts)
|
|
assert_equal("", script_name)
|
|
assert_equal("/sub", path_info)
|
|
|
|
serv, opts, script_name, path_info = httpd.search_servlet("/sub/")
|
|
assert_equal(:Root, serv)
|
|
assert_equal([], opts)
|
|
assert_equal("", script_name)
|
|
assert_equal("/sub/", path_info)
|
|
|
|
serv, opts, script_name, path_info = httpd.search_servlet("/foo")
|
|
assert_equal(:Foo, serv)
|
|
assert_equal([], opts)
|
|
assert_equal("/foo", script_name)
|
|
assert_equal("", path_info)
|
|
|
|
serv, opts, script_name, path_info = httpd.search_servlet("/foo/")
|
|
assert_equal(:Foo, serv)
|
|
assert_equal([], opts)
|
|
assert_equal("/foo", script_name)
|
|
assert_equal("/", path_info)
|
|
|
|
serv, opts, script_name, path_info = httpd.search_servlet("/foo/sub")
|
|
assert_equal(:Foo, serv)
|
|
assert_equal([], opts)
|
|
assert_equal("/foo", script_name)
|
|
assert_equal("/sub", path_info)
|
|
|
|
serv, opts, script_name, path_info = httpd.search_servlet("/foo/bar")
|
|
assert_equal(:Bar, serv)
|
|
assert_equal([:bar1], opts)
|
|
assert_equal("/foo/bar", script_name)
|
|
assert_equal("", path_info)
|
|
|
|
serv, opts, script_name, path_info = httpd.search_servlet("/foo/bar/baz")
|
|
assert_equal(:Baz, serv)
|
|
assert_equal([:baz1, :baz2], opts)
|
|
assert_equal("/foo/bar/baz", script_name)
|
|
assert_equal("", path_info)
|
|
end
|
|
|
|
class Req
|
|
attr_reader :port, :host
|
|
def initialize(addr, port, host)
|
|
@addr, @port, @host = addr, port, host
|
|
end
|
|
def addr
|
|
[0,0,0,@addr]
|
|
end
|
|
end
|
|
|
|
def httpd(addr, port, host, ali)
|
|
config ={
|
|
:Logger => NoLog,
|
|
:DoNotListen => true,
|
|
:BindAddress => addr,
|
|
:Port => port,
|
|
:ServerName => host,
|
|
:ServerAlias => ali,
|
|
}
|
|
return WEBrick::HTTPServer.new(config)
|
|
end
|
|
|
|
def assert_eql?(v1, v2)
|
|
assert_equal(v1.object_id, v2.object_id)
|
|
end
|
|
|
|
def test_lookup_server
|
|
addr1 = "192.168.100.1"
|
|
addr2 = "192.168.100.2"
|
|
addrz = "192.168.100.254"
|
|
local = "127.0.0.1"
|
|
port1 = 80
|
|
port2 = 8080
|
|
port3 = 10080
|
|
portz = 32767
|
|
name1 = "www.example.com"
|
|
name2 = "www2.example.com"
|
|
name3 = "www3.example.com"
|
|
namea = "www.example.co.jp"
|
|
nameb = "www.example.jp"
|
|
namec = "www2.example.co.jp"
|
|
named = "www2.example.jp"
|
|
namez = "foobar.example.com"
|
|
alias1 = [namea, nameb]
|
|
alias2 = [namec, named]
|
|
|
|
host1 = httpd(nil, port1, name1, nil)
|
|
hosts = [
|
|
host2 = httpd(addr1, port1, name1, nil),
|
|
host3 = httpd(addr1, port1, name2, alias1),
|
|
host4 = httpd(addr1, port2, name1, nil),
|
|
host5 = httpd(addr1, port2, name2, alias1),
|
|
httpd(addr1, port2, name3, alias2),
|
|
host7 = httpd(addr2, nil, name1, nil),
|
|
host8 = httpd(addr2, nil, name2, alias1),
|
|
httpd(addr2, nil, name3, alias2),
|
|
host10 = httpd(local, nil, nil, nil),
|
|
host11 = httpd(nil, port3, nil, nil),
|
|
].sort_by{ rand }
|
|
hosts.each{|h| host1.virtual_host(h) }
|
|
|
|
# connect to addr1
|
|
assert_eql?(host2, host1.lookup_server(Req.new(addr1, port1, name1)))
|
|
assert_eql?(host3, host1.lookup_server(Req.new(addr1, port1, name2)))
|
|
assert_eql?(host3, host1.lookup_server(Req.new(addr1, port1, namea)))
|
|
assert_eql?(host3, host1.lookup_server(Req.new(addr1, port1, nameb)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addr1, port1, namez)))
|
|
assert_eql?(host4, host1.lookup_server(Req.new(addr1, port2, name1)))
|
|
assert_eql?(host5, host1.lookup_server(Req.new(addr1, port2, name2)))
|
|
assert_eql?(host5, host1.lookup_server(Req.new(addr1, port2, namea)))
|
|
assert_eql?(host5, host1.lookup_server(Req.new(addr1, port2, nameb)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addr1, port2, namez)))
|
|
assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, name1)))
|
|
assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, name2)))
|
|
assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, namea)))
|
|
assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, nameb)))
|
|
assert_eql?(host11, host1.lookup_server(Req.new(addr1, port3, namez)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, name1)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, name2)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, namea)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, nameb)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addr1, portz, namez)))
|
|
|
|
# connect to addr2
|
|
assert_eql?(host7, host1.lookup_server(Req.new(addr2, port1, name1)))
|
|
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port1, name2)))
|
|
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port1, namea)))
|
|
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port1, nameb)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addr2, port1, namez)))
|
|
assert_eql?(host7, host1.lookup_server(Req.new(addr2, port2, name1)))
|
|
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port2, name2)))
|
|
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port2, namea)))
|
|
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port2, nameb)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addr2, port2, namez)))
|
|
assert_eql?(host7, host1.lookup_server(Req.new(addr2, port3, name1)))
|
|
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port3, name2)))
|
|
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port3, namea)))
|
|
assert_eql?(host8, host1.lookup_server(Req.new(addr2, port3, nameb)))
|
|
assert_eql?(host11, host1.lookup_server(Req.new(addr2, port3, namez)))
|
|
assert_eql?(host7, host1.lookup_server(Req.new(addr2, portz, name1)))
|
|
assert_eql?(host8, host1.lookup_server(Req.new(addr2, portz, name2)))
|
|
assert_eql?(host8, host1.lookup_server(Req.new(addr2, portz, namea)))
|
|
assert_eql?(host8, host1.lookup_server(Req.new(addr2, portz, nameb)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addr2, portz, namez)))
|
|
|
|
# connect to addrz
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, name1)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, name2)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, namea)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, nameb)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port1, namez)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, name1)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, name2)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, namea)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, nameb)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, port2, namez)))
|
|
assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, name1)))
|
|
assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, name2)))
|
|
assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, namea)))
|
|
assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, nameb)))
|
|
assert_eql?(host11, host1.lookup_server(Req.new(addrz, port3, namez)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, name1)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, name2)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, namea)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, nameb)))
|
|
assert_eql?(nil, host1.lookup_server(Req.new(addrz, portz, namez)))
|
|
|
|
# connect to localhost
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port1, name1)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port1, name2)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port1, namea)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port1, nameb)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port1, namez)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port2, name1)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port2, name2)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port2, namea)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port2, nameb)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port2, namez)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port3, name1)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port3, name2)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port3, namea)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port3, nameb)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, port3, namez)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, portz, name1)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, portz, name2)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, portz, namea)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, portz, nameb)))
|
|
assert_eql?(host10, host1.lookup_server(Req.new(local, portz, namez)))
|
|
end
|
|
|
|
def test_callbacks
|
|
accepted = started = stopped = 0
|
|
requested0 = requested1 = 0
|
|
config = {
|
|
:ServerName => "localhost",
|
|
:AcceptCallback => Proc.new{ accepted += 1 },
|
|
:StartCallback => Proc.new{ started += 1 },
|
|
:StopCallback => Proc.new{ stopped += 1 },
|
|
:RequestCallback => Proc.new{|req, res| requested0 += 1 },
|
|
}
|
|
log_tester = lambda {|log, access_log|
|
|
assert(log.find {|s| %r{ERROR `/' not found\.} =~ s })
|
|
assert_equal([], log.reject {|s| %r{ERROR `/' not found\.} =~ s })
|
|
}
|
|
TestWEBrick.start_httpserver(config, log_tester){|server, addr, port, log|
|
|
vhost_config = {
|
|
:ServerName => "myhostname",
|
|
:BindAddress => addr,
|
|
:Port => port,
|
|
:DoNotListen => true,
|
|
:Logger => NoLog,
|
|
:AccessLog => [],
|
|
:RequestCallback => Proc.new{|req, res| requested1 += 1 },
|
|
}
|
|
server.virtual_host(WEBrick::HTTPServer.new(vhost_config))
|
|
|
|
Thread.pass while server.status != :Running
|
|
sleep 1 if RubyVM::MJIT.enabled? # server.status behaves unexpectedly with --jit-wait
|
|
assert_equal(1, started, log.call)
|
|
assert_equal(0, stopped, log.call)
|
|
assert_equal(0, accepted, log.call)
|
|
|
|
http = Net::HTTP.new(addr, port)
|
|
req = Net::HTTP::Get.new("/")
|
|
req["Host"] = "myhostname:#{port}"
|
|
http.request(req){|res| assert_equal("404", res.code, log.call)}
|
|
http.request(req){|res| assert_equal("404", res.code, log.call)}
|
|
http.request(req){|res| assert_equal("404", res.code, log.call)}
|
|
req["Host"] = "localhost:#{port}"
|
|
http.request(req){|res| assert_equal("404", res.code, log.call)}
|
|
http.request(req){|res| assert_equal("404", res.code, log.call)}
|
|
http.request(req){|res| assert_equal("404", res.code, log.call)}
|
|
assert_equal(6, accepted, log.call)
|
|
assert_equal(3, requested0, log.call)
|
|
assert_equal(3, requested1, log.call)
|
|
}
|
|
assert_equal(started, 1)
|
|
assert_equal(stopped, 1)
|
|
end
|
|
|
|
# This class is needed by test_response_io_with_chunked_set method
|
|
class EventManagerForChunkedResponseTest
|
|
def initialize
|
|
@listeners = []
|
|
end
|
|
def add_listener( &block )
|
|
@listeners << block
|
|
end
|
|
def raise_str_event( str )
|
|
@listeners.each{ |e| e.call( :str, str ) }
|
|
end
|
|
def raise_close_event()
|
|
@listeners.each{ |e| e.call( :cls ) }
|
|
end
|
|
end
|
|
def test_response_io_with_chunked_set
|
|
evt_man = EventManagerForChunkedResponseTest.new
|
|
t = Thread.new do
|
|
begin
|
|
config = {
|
|
:ServerName => "localhost"
|
|
}
|
|
TestWEBrick.start_httpserver(config) do |server, addr, port, log|
|
|
body_strs = [ 'aaaaaa', 'bb', 'cccc' ]
|
|
server.mount_proc( "/", ->( req, res ){
|
|
# Test for setting chunked...
|
|
res.chunked = true
|
|
r,w = IO.pipe
|
|
evt_man.add_listener do |type,str|
|
|
type == :cls ? ( w.close ) : ( w << str )
|
|
end
|
|
res.body = r
|
|
} )
|
|
Thread.pass while server.status != :Running
|
|
http = Net::HTTP.new(addr, port)
|
|
req = Net::HTTP::Get.new("/")
|
|
http.request(req) do |res|
|
|
i = 0
|
|
evt_man.raise_str_event( body_strs[i] )
|
|
res.read_body do |s|
|
|
assert_equal( body_strs[i], s )
|
|
i += 1
|
|
if i < body_strs.length
|
|
evt_man.raise_str_event( body_strs[i] )
|
|
else
|
|
evt_man.raise_close_event()
|
|
end
|
|
end
|
|
assert_equal( body_strs.length, i )
|
|
end
|
|
end
|
|
rescue => err
|
|
flunk( 'exception raised in thread: ' + err.to_s )
|
|
end
|
|
end
|
|
if t.join( 3 ).nil?
|
|
evt_man.raise_close_event()
|
|
flunk( 'timeout' )
|
|
if t.join( 1 ).nil?
|
|
Thread.kill t
|
|
end
|
|
end
|
|
end
|
|
|
|
def test_response_io_without_chunked_set
|
|
config = {
|
|
:ServerName => "localhost"
|
|
}
|
|
log_tester = lambda {|log, access_log|
|
|
assert_equal(1, log.length)
|
|
assert_match(/WARN Could not determine content-length of response body./, log[0])
|
|
}
|
|
TestWEBrick.start_httpserver(config, log_tester){|server, addr, port, log|
|
|
server.mount_proc("/", lambda { |req, res|
|
|
r,w = IO.pipe
|
|
# Test for not setting chunked...
|
|
# res.chunked = true
|
|
res.body = r
|
|
w << "foo"
|
|
w.close
|
|
})
|
|
Thread.pass while server.status != :Running
|
|
http = Net::HTTP.new(addr, port)
|
|
req = Net::HTTP::Get.new("/")
|
|
req['Connection'] = 'Keep-Alive'
|
|
begin
|
|
Timeout.timeout(2) do
|
|
http.request(req){|res| assert_equal("foo", res.body) }
|
|
end
|
|
rescue Timeout::Error
|
|
flunk('corrupted response')
|
|
end
|
|
}
|
|
end
|
|
|
|
def test_request_handler_callback_is_deprecated
|
|
requested = 0
|
|
config = {
|
|
:ServerName => "localhost",
|
|
:RequestHandler => Proc.new{|req, res| requested += 1 },
|
|
}
|
|
log_tester = lambda {|log, access_log|
|
|
assert_equal(2, log.length)
|
|
assert_match(/WARN :RequestHandler is deprecated, please use :RequestCallback/, log[0])
|
|
assert_match(%r{ERROR `/' not found\.}, log[1])
|
|
}
|
|
TestWEBrick.start_httpserver(config, log_tester){|server, addr, port, log|
|
|
Thread.pass while server.status != :Running
|
|
|
|
http = Net::HTTP.new(addr, port)
|
|
req = Net::HTTP::Get.new("/")
|
|
req["Host"] = "localhost:#{port}"
|
|
http.request(req){|res| assert_equal("404", res.code, log.call)}
|
|
assert_match(%r{:RequestHandler is deprecated, please use :RequestCallback$}, log.call, log.call)
|
|
}
|
|
assert_equal(1, requested)
|
|
end
|
|
|
|
def test_shutdown_with_busy_keepalive_connection
|
|
requested = 0
|
|
config = {
|
|
:ServerName => "localhost",
|
|
}
|
|
TestWEBrick.start_httpserver(config){|server, addr, port, log|
|
|
server.mount_proc("/", lambda {|req, res| res.body = "heffalump" })
|
|
Thread.pass while server.status != :Running
|
|
|
|
Net::HTTP.start(addr, port) do |http|
|
|
req = Net::HTTP::Get.new("/")
|
|
http.request(req){|res| assert_equal('Keep-Alive', res['Connection'], log.call) }
|
|
server.shutdown
|
|
begin
|
|
10.times {|n| http.request(req); requested += 1 }
|
|
rescue
|
|
# Errno::ECONNREFUSED or similar
|
|
end
|
|
end
|
|
}
|
|
assert_equal(0, requested, "Server responded to #{requested} requests after shutdown")
|
|
end
|
|
|
|
def test_cntrl_in_path
|
|
log_ary = []
|
|
access_log_ary = []
|
|
config = {
|
|
:Port => 0,
|
|
:BindAddress => '127.0.0.1',
|
|
:Logger => WEBrick::Log.new(log_ary, WEBrick::BasicLog::WARN),
|
|
:AccessLog => [[access_log_ary, '']],
|
|
}
|
|
s = WEBrick::HTTPServer.new(config)
|
|
s.mount('/foo', WEBrick::HTTPServlet::FileHandler, __FILE__)
|
|
th = Thread.new { s.start }
|
|
addr = s.listeners[0].addr
|
|
|
|
http = Net::HTTP.new(addr[3], addr[1])
|
|
req = Net::HTTP::Get.new('/notexist%0a/foo')
|
|
http.request(req) { |res| assert_equal('404', res.code) }
|
|
exp = %Q(ERROR `/notexist\\n/foo' not found.\n)
|
|
assert_equal 1, log_ary.size
|
|
assert log_ary[0].include?(exp)
|
|
ensure
|
|
s&.shutdown
|
|
th&.join
|
|
end
|
|
|
|
def test_gigantic_request_header
|
|
log_tester = lambda {|log, access_log|
|
|
assert_equal 1, log.size
|
|
assert log[0].include?('ERROR headers too large')
|
|
}
|
|
TestWEBrick.start_httpserver({}, log_tester){|server, addr, port, log|
|
|
server.mount('/', WEBrick::HTTPServlet::FileHandler, __FILE__)
|
|
TCPSocket.open(addr, port) do |c|
|
|
c.write("GET / HTTP/1.0\r\n")
|
|
junk = -"X-Junk: #{' ' * 1024}\r\n"
|
|
assert_raise(Errno::ECONNRESET, Errno::EPIPE) do
|
|
loop { c.write(junk) }
|
|
end
|
|
end
|
|
}
|
|
end
|
|
|
|
def test_eof_in_chunk
|
|
log_tester = lambda do |log, access_log|
|
|
assert_equal 1, log.size
|
|
assert log[0].include?('ERROR bad chunk data size')
|
|
end
|
|
TestWEBrick.start_httpserver({}, log_tester){|server, addr, port, log|
|
|
server.mount_proc('/', ->(req, res) { res.body = req.body })
|
|
TCPSocket.open(addr, port) do |c|
|
|
c.write("POST / HTTP/1.1\r\nHost: example.com\r\n" \
|
|
"Transfer-Encoding: chunked\r\n\r\n5\r\na")
|
|
c.shutdown(Socket::SHUT_WR) # trigger EOF in server
|
|
res = c.read
|
|
assert_match %r{\AHTTP/1\.1 400 }, res
|
|
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
|