Project

General

Profile

Feature #15657 ยป remove-webrick.patch

hsbt (Hiroshi SHIBATA), 03/22/2019 10:09 AM

View differences:

gems/bundled_gems
power_assert 1.1.3 https://github.com/k-tsj/power_assert
rake 12.3.2 https://github.com/ruby/rake
test-unit 3.2.9 https://github.com/test-unit/test-unit
webrick 1.4.2 https://github.com/ruby/webrick
xmlrpc 0.3.0 https://github.com/ruby/xmlrpc
/dev/null
this file should not be published.
/dev/null
# coding: US-ASCII
# frozen_string_literal: false
require_relative "utils"
require "webrick"
require "test/unit"
class TestWEBrickCGI < Test::Unit::TestCase
CRLF = "\r\n"
def teardown
WEBrick::Utils::TimeoutHandler.terminate
super
end
def start_cgi_server(log_tester=TestWEBrick::DefaultLogTester, &block)
config = {
:CGIInterpreter => TestWEBrick::RubyBin,
:DocumentRoot => File.dirname(__FILE__),
:DirectoryIndex => ["webrick.cgi"],
:RequestCallback => Proc.new{|req, res|
def req.meta_vars
meta = super
meta["RUBYLIB"] = $:.join(File::PATH_SEPARATOR)
meta[RbConfig::CONFIG['LIBPATHENV']] = ENV[RbConfig::CONFIG['LIBPATHENV']] if RbConfig::CONFIG['LIBPATHENV']
return meta
end
},
}
if RUBY_PLATFORM =~ /mswin|mingw|cygwin|bccwin32/
config[:CGIPathEnv] = ENV['PATH'] # runtime dll may not be in system dir.
end
TestWEBrick.start_httpserver(config, log_tester){|server, addr, port, log|
block.call(server, addr, port, log)
}
end
def test_cgi
start_cgi_server{|server, addr, port, log|
http = Net::HTTP.new(addr, port)
req = Net::HTTP::Get.new("/webrick.cgi")
http.request(req){|res| assert_equal("/webrick.cgi", res.body, log.call)}
req = Net::HTTP::Get.new("/webrick.cgi/path/info")
http.request(req){|res| assert_equal("/path/info", res.body, log.call)}
req = Net::HTTP::Get.new("/webrick.cgi/%3F%3F%3F?foo=bar")
http.request(req){|res| assert_equal("/???", res.body, log.call)}
unless RUBY_PLATFORM =~ /mswin|mingw|cygwin|bccwin32/
# Path info of res.body is passed via ENV.
# ENV[] returns different value on Windows depending on locale.
req = Net::HTTP::Get.new("/webrick.cgi/%A4%DB%A4%B2/%A4%DB%A4%B2")
http.request(req){|res|
assert_equal("/\xA4\xDB\xA4\xB2/\xA4\xDB\xA4\xB2", res.body, log.call)}
end
req = Net::HTTP::Get.new("/webrick.cgi?a=1;a=2;b=x")
http.request(req){|res| assert_equal("a=1, a=2, b=x", res.body, log.call)}
req = Net::HTTP::Get.new("/webrick.cgi?a=1&a=2&b=x")
http.request(req){|res| assert_equal("a=1, a=2, b=x", res.body, log.call)}
req = Net::HTTP::Post.new("/webrick.cgi?a=x;a=y;b=1")
req["Content-Type"] = "application/x-www-form-urlencoded"
http.request(req, "a=1;a=2;b=x"){|res|
assert_equal("a=1, a=2, b=x", res.body, log.call)}
req = Net::HTTP::Post.new("/webrick.cgi?a=x&a=y&b=1")
req["Content-Type"] = "application/x-www-form-urlencoded"
http.request(req, "a=1&a=2&b=x"){|res|
assert_equal("a=1, a=2, b=x", res.body, log.call)}
req = Net::HTTP::Get.new("/")
http.request(req){|res|
ary = res.body.lines.to_a
assert_match(%r{/$}, ary[0], log.call)
assert_match(%r{/webrick.cgi$}, ary[1], log.call)
}
req = Net::HTTP::Get.new("/webrick.cgi")
req["Cookie"] = "CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001"
http.request(req){|res|
assert_equal(
"CUSTOMER=WILE_E_COYOTE\nPART_NUMBER=ROCKET_LAUNCHER_0001\n",
res.body, log.call)
}
req = Net::HTTP::Get.new("/webrick.cgi")
cookie = %{$Version="1"; }
cookie << %{Customer="WILE_E_COYOTE"; $Path="/acme"; }
cookie << %{Part_Number="Rocket_Launcher_0001"; $Path="/acme"; }
cookie << %{Shipping="FedEx"; $Path="/acme"}
req["Cookie"] = cookie
http.request(req){|res|
assert_equal("Customer=WILE_E_COYOTE, Shipping=FedEx",
res["Set-Cookie"], log.call)
assert_equal("Customer=WILE_E_COYOTE\n" +
"Part_Number=Rocket_Launcher_0001\n" +
"Shipping=FedEx\n", res.body, log.call)
}
}
end
def test_bad_request
log_tester = lambda {|log, access_log|
assert_match(/BadRequest/, log.join)
}
start_cgi_server(log_tester) {|server, addr, port, log|
sock = TCPSocket.new(addr, port)
begin
sock << "POST /webrick.cgi HTTP/1.0" << CRLF
sock << "Content-Type: application/x-www-form-urlencoded" << CRLF
sock << "Content-Length: 1024" << CRLF
sock << CRLF
sock << "a=1&a=2&b=x"
sock.close_write
assert_match(%r{\AHTTP/\d.\d 400 Bad Request}, sock.read, log.call)
ensure
sock.close
end
}
end
def test_cgi_env
start_cgi_server do |server, addr, port, log|
http = Net::HTTP.new(addr, port)
req = Net::HTTP::Get.new("/webrick.cgi/dumpenv")
req['proxy'] = 'http://example.com/'
req['hello'] = 'world'
http.request(req) do |res|
env = Marshal.load(res.body)
assert_equal 'world', env['HTTP_HELLO']
assert_not_operator env, :include?, 'HTTP_PROXY'
end
end
end
CtrlSeq = [0x7f, *(1..31)].pack("C*").gsub(/\s+/, '')
CtrlPat = /#{Regexp.quote(CtrlSeq)}/o
DumpPat = /#{Regexp.quote(CtrlSeq.dump[1...-1])}/o
def test_bad_uri
log_tester = lambda {|log, access_log|
assert_equal(1, log.length)
assert_match(/ERROR bad URI/, log[0])
}
start_cgi_server(log_tester) {|server, addr, port, log|
res = TCPSocket.open(addr, port) {|sock|
sock << "GET /#{CtrlSeq}#{CRLF}#{CRLF}"
sock.close_write
sock.read
}
assert_match(%r{\AHTTP/\d.\d 400 Bad Request}, res)
s = log.call.each_line.grep(/ERROR bad URI/)[0]
assert_match(DumpPat, s)
assert_not_match(CtrlPat, s)
}
end
def test_bad_header
log_tester = lambda {|log, access_log|
assert_equal(1, log.length)
assert_match(/ERROR bad header/, log[0])
}
start_cgi_server(log_tester) {|server, addr, port, log|
res = TCPSocket.open(addr, port) {|sock|
sock << "GET / HTTP/1.0#{CRLF}#{CtrlSeq}#{CRLF}#{CRLF}"
sock.close_write
sock.read
}
assert_match(%r{\AHTTP/\d.\d 400 Bad Request}, res)
s = log.call.each_line.grep(/ERROR bad header/)[0]
assert_match(DumpPat, s)
assert_not_match(CtrlPat, s)
}
end
end
/dev/null
# frozen_string_literal: false
require "test/unit"
require "webrick/config"
class TestWEBrickConfig < Test::Unit::TestCase
def test_server_name_default
config = WEBrick::Config::General.dup
assert_equal(false, config.key?(:ServerName))
assert_equal(WEBrick::Utils.getservername, config[:ServerName])
assert_equal(true, config.key?(:ServerName))
end
def test_server_name_set_nil
config = WEBrick::Config::General.dup.update(ServerName: nil)
assert_equal(nil, config[:ServerName])
end
end
/dev/null
# frozen_string_literal: false
require "test/unit"
require "webrick/cookie"
class TestWEBrickCookie < Test::Unit::TestCase
def test_new
cookie = WEBrick::Cookie.new("foo","bar")
assert_equal("foo", cookie.name)
assert_equal("bar", cookie.value)
assert_equal("foo=bar", cookie.to_s)
end
def test_time
cookie = WEBrick::Cookie.new("foo","bar")
t = 1000000000
cookie.max_age = t
assert_match(t.to_s, cookie.to_s)
cookie = WEBrick::Cookie.new("foo","bar")
t = Time.at(1000000000)
cookie.expires = t
assert_equal(Time, cookie.expires.class)
assert_equal(t, cookie.expires)
ts = t.httpdate
cookie.expires = ts
assert_equal(Time, cookie.expires.class)
assert_equal(t, cookie.expires)
assert_match(ts, cookie.to_s)
end
def test_parse
data = ""
data << '$Version="1"; '
data << 'Customer="WILE_E_COYOTE"; $Path="/acme"; '
data << 'Part_Number="Rocket_Launcher_0001"; $Path="/acme"; '
data << 'Shipping="FedEx"; $Path="/acme"'
cookies = WEBrick::Cookie.parse(data)
assert_equal(3, cookies.size)
assert_equal(1, cookies[0].version)
assert_equal("Customer", cookies[0].name)
assert_equal("WILE_E_COYOTE", cookies[0].value)
assert_equal("/acme", cookies[0].path)
assert_equal(1, cookies[1].version)
assert_equal("Part_Number", cookies[1].name)
assert_equal("Rocket_Launcher_0001", cookies[1].value)
assert_equal(1, cookies[2].version)
assert_equal("Shipping", cookies[2].name)
assert_equal("FedEx", cookies[2].value)
data = "hoge=moge; __div__session=9865ecfd514be7f7"
cookies = WEBrick::Cookie.parse(data)
assert_equal(2, cookies.size)
assert_equal(0, cookies[0].version)
assert_equal("hoge", cookies[0].name)
assert_equal("moge", cookies[0].value)
assert_equal("__div__session", cookies[1].name)
assert_equal("9865ecfd514be7f7", cookies[1].value)
# don't allow ,-separator
data = "hoge=moge, __div__session=9865ecfd514be7f7"
cookies = WEBrick::Cookie.parse(data)
assert_equal(1, cookies.size)
assert_equal(0, cookies[0].version)
assert_equal("hoge", cookies[0].name)
assert_equal("moge, __div__session=9865ecfd514be7f7", cookies[0].value)
end
def test_parse_no_whitespace
data = [
'$Version="1"; ',
'Customer="WILE_E_COYOTE";$Path="/acme";', # no SP between cookie-string
'Part_Number="Rocket_Launcher_0001";$Path="/acme";', # no SP between cookie-string
'Shipping="FedEx";$Path="/acme"'
].join
cookies = WEBrick::Cookie.parse(data)
assert_equal(1, cookies.size)
end
def test_parse_too_much_whitespaces
# According to RFC6265,
# cookie-string = cookie-pair *( ";" SP cookie-pair )
# So single 0x20 is needed after ';'. We allow multiple spaces here for
# compatibility with older WEBrick versions.
data = [
'$Version="1"; ',
'Customer="WILE_E_COYOTE";$Path="/acme"; ', # no SP between cookie-string
'Part_Number="Rocket_Launcher_0001";$Path="/acme"; ', # no SP between cookie-string
'Shipping="FedEx";$Path="/acme"'
].join
cookies = WEBrick::Cookie.parse(data)
assert_equal(3, cookies.size)
end
def test_parse_set_cookie
data = %(Customer="WILE_E_COYOTE"; Version="1"; Path="/acme")
cookie = WEBrick::Cookie.parse_set_cookie(data)
assert_equal("Customer", cookie.name)
assert_equal("WILE_E_COYOTE", cookie.value)
assert_equal(1, cookie.version)
assert_equal("/acme", cookie.path)
data = %(Shipping="FedEx"; Version="1"; Path="/acme"; Secure)
cookie = WEBrick::Cookie.parse_set_cookie(data)
assert_equal("Shipping", cookie.name)
assert_equal("FedEx", cookie.value)
assert_equal(1, cookie.version)
assert_equal("/acme", cookie.path)
assert_equal(true, cookie.secure)
end
def test_parse_set_cookies
data = %(Shipping="FedEx"; Version="1"; Path="/acme"; Secure)
data << %(, CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT; path=/; Secure)
data << %(, name="Aaron"; Version="1"; path="/acme")
cookies = WEBrick::Cookie.parse_set_cookies(data)
assert_equal(3, cookies.length)
fed_ex = cookies.find { |c| c.name == 'Shipping' }
assert_not_nil(fed_ex)
assert_equal("Shipping", fed_ex.name)
assert_equal("FedEx", fed_ex.value)
assert_equal(1, fed_ex.version)
assert_equal("/acme", fed_ex.path)
assert_equal(true, fed_ex.secure)
name = cookies.find { |c| c.name == 'name' }
assert_not_nil(name)
assert_equal("name", name.name)
assert_equal("Aaron", name.value)
assert_equal(1, name.version)
assert_equal("/acme", name.path)
customer = cookies.find { |c| c.name == 'CUSTOMER' }
assert_not_nil(customer)
assert_equal("CUSTOMER", customer.name)
assert_equal("WILE_E_COYOTE", customer.value)
assert_equal(0, customer.version)
assert_equal("/", customer.path)
assert_equal(Time.utc(1999, 11, 9, 23, 12, 40), customer.expires)
end
end
/dev/null
# frozen_string_literal: false
require "test/unit"
require "webrick"
require_relative "utils"
class TestDoNotReverseLookup < Test::Unit::TestCase
class DNRL < WEBrick::GenericServer
def run(sock)
sock << sock.do_not_reverse_lookup.to_s
end
end
@@original_do_not_reverse_lookup_value = Socket.do_not_reverse_lookup
def teardown
Socket.do_not_reverse_lookup = @@original_do_not_reverse_lookup_value
end
def do_not_reverse_lookup?(config)
result = nil
TestWEBrick.start_server(DNRL, config) do |server, addr, port, log|
TCPSocket.open(addr, port) do |sock|
result = {'true' => true, 'false' => false}[sock.gets]
end
end
result
end
# +--------------------------------------------------------------------------+
# | Expected interaction between Socket.do_not_reverse_lookup |
# | and WEBrick::Config::General[:DoNotReverseLookup] |
# +----------------------------+---------------------------------------------+
# | |WEBrick::Config::General[:DoNotReverseLookup]|
# +----------------------------+--------------+---------------+--------------+
# |Socket.do_not_reverse_lookup| TRUE | FALSE | NIL |
# +----------------------------+--------------+---------------+--------------+
# | TRUE | true | false | true |
# +----------------------------+--------------+---------------+--------------+
# | FALSE | true | false | false |
# +----------------------------+--------------+---------------+--------------+
def test_socket_dnrl_true_server_dnrl_true
Socket.do_not_reverse_lookup = true
assert_equal(true, do_not_reverse_lookup?(:DoNotReverseLookup => true))
end
def test_socket_dnrl_true_server_dnrl_false
Socket.do_not_reverse_lookup = true
assert_equal(false, do_not_reverse_lookup?(:DoNotReverseLookup => false))
end
def test_socket_dnrl_true_server_dnrl_nil
Socket.do_not_reverse_lookup = true
assert_equal(true, do_not_reverse_lookup?(:DoNotReverseLookup => nil))
end
def test_socket_dnrl_false_server_dnrl_true
Socket.do_not_reverse_lookup = false
assert_equal(true, do_not_reverse_lookup?(:DoNotReverseLookup => true))
end
def test_socket_dnrl_false_server_dnrl_false
Socket.do_not_reverse_lookup = false
assert_equal(false, do_not_reverse_lookup?(:DoNotReverseLookup => false))
end
def test_socket_dnrl_false_server_dnrl_nil
Socket.do_not_reverse_lookup = false
assert_equal(false, do_not_reverse_lookup?(:DoNotReverseLookup => nil))
end
end
/dev/null
# frozen_string_literal: false
require "test/unit"
require_relative "utils.rb"
require "webrick"
require "stringio"
class WEBrick::TestFileHandler < Test::Unit::TestCase
def teardown
WEBrick::Utils::TimeoutHandler.terminate
super
end
def default_file_handler(filename)
klass = WEBrick::HTTPServlet::DefaultFileHandler
klass.new(WEBrick::Config::HTTP, filename)
end
def windows?
File.directory?("\\")
end
def get_res_body(res)
sio = StringIO.new
sio.binmode
res.send_body(sio)
sio.string
end
def make_range_request(range_spec)
msg = <<-END_OF_REQUEST
GET / HTTP/1.0
Range: #{range_spec}
END_OF_REQUEST
return StringIO.new(msg.gsub(/^ {6}/, ""))
end
def make_range_response(file, range_spec)
req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
req.parse(make_range_request(range_spec))
res = WEBrick::HTTPResponse.new(WEBrick::Config::HTTP)
size = File.size(file)
handler = default_file_handler(file)
handler.make_partial_content(req, res, file, size)
return res
end
def test_make_partial_content
filename = __FILE__
filesize = File.size(filename)
res = make_range_response(filename, "bytes=#{filesize-100}-")
assert_match(%r{^text/plain}, res["content-type"])
assert_equal(100, get_res_body(res).size)
res = make_range_response(filename, "bytes=-100")
assert_match(%r{^text/plain}, res["content-type"])
assert_equal(100, get_res_body(res).size)
res = make_range_response(filename, "bytes=0-99")
assert_match(%r{^text/plain}, res["content-type"])
assert_equal(100, get_res_body(res).size)
res = make_range_response(filename, "bytes=100-199")
assert_match(%r{^text/plain}, res["content-type"])
assert_equal(100, get_res_body(res).size)
res = make_range_response(filename, "bytes=0-0")
assert_match(%r{^text/plain}, res["content-type"])
assert_equal(1, get_res_body(res).size)
res = make_range_response(filename, "bytes=-1")
assert_match(%r{^text/plain}, res["content-type"])
assert_equal(1, get_res_body(res).size)
res = make_range_response(filename, "bytes=0-0, -2")
assert_match(%r{^multipart/byteranges}, res["content-type"])
body = get_res_body(res)
boundary = /; boundary=(.+)/.match(res['content-type'])[1]
off = filesize - 2
last = filesize - 1
exp = "--#{boundary}\r\n" \
"Content-Type: text/plain\r\n" \
"Content-Range: bytes 0-0/#{filesize}\r\n" \
"\r\n" \
"#{IO.read(__FILE__, 1)}\r\n" \
"--#{boundary}\r\n" \
"Content-Type: text/plain\r\n" \
"Content-Range: bytes #{off}-#{last}/#{filesize}\r\n" \
"\r\n" \
"#{IO.read(__FILE__, 2, off)}\r\n" \
"--#{boundary}--\r\n"
assert_equal exp, body
end
def test_filehandler
config = { :DocumentRoot => File.dirname(__FILE__), }
this_file = File.basename(__FILE__)
filesize = File.size(__FILE__)
this_data = File.binread(__FILE__)
range = nil
bug2593 = '[ruby-dev:40030]'
TestWEBrick.start_httpserver(config) do |server, addr, port, log|
http = Net::HTTP.new(addr, port)
req = Net::HTTP::Get.new("/")
http.request(req){|res|
assert_equal("200", res.code, log.call)
assert_equal("text/html", res.content_type, log.call)
assert_match(/HREF="#{this_file}"/, res.body, log.call)
}
req = Net::HTTP::Get.new("/#{this_file}")
http.request(req){|res|
assert_equal("200", res.code, log.call)
assert_equal("text/plain", res.content_type, log.call)
assert_equal(this_data, res.body, log.call)
}
req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=#{filesize-100}-")
http.request(req){|res|
assert_equal("206", res.code, log.call)
assert_equal("text/plain", res.content_type, log.call)
assert_nothing_raised(bug2593) {range = res.content_range}
assert_equal((filesize-100)..(filesize-1), range, log.call)
assert_equal(this_data[-100..-1], res.body, log.call)
}
req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=-100")
http.request(req){|res|
assert_equal("206", res.code, log.call)
assert_equal("text/plain", res.content_type, log.call)
assert_nothing_raised(bug2593) {range = res.content_range}
assert_equal((filesize-100)..(filesize-1), range, log.call)
assert_equal(this_data[-100..-1], res.body, log.call)
}
req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=0-99")
http.request(req){|res|
assert_equal("206", res.code, log.call)
assert_equal("text/plain", res.content_type, log.call)
assert_nothing_raised(bug2593) {range = res.content_range}
assert_equal(0..99, range, log.call)
assert_equal(this_data[0..99], res.body, log.call)
}
req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=100-199")
http.request(req){|res|
assert_equal("206", res.code, log.call)
assert_equal("text/plain", res.content_type, log.call)
assert_nothing_raised(bug2593) {range = res.content_range}
assert_equal(100..199, range, log.call)
assert_equal(this_data[100..199], res.body, log.call)
}
req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=0-0")
http.request(req){|res|
assert_equal("206", res.code, log.call)
assert_equal("text/plain", res.content_type, log.call)
assert_nothing_raised(bug2593) {range = res.content_range}
assert_equal(0..0, range, log.call)
assert_equal(this_data[0..0], res.body, log.call)
}
req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=-1")
http.request(req){|res|
assert_equal("206", res.code, log.call)
assert_equal("text/plain", res.content_type, log.call)
assert_nothing_raised(bug2593) {range = res.content_range}
assert_equal((filesize-1)..(filesize-1), range, log.call)
assert_equal(this_data[-1, 1], res.body, log.call)
}
req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=0-0, -2")
http.request(req){|res|
assert_equal("206", res.code, log.call)
assert_equal("multipart/byteranges", res.content_type, log.call)
}
end
end
def test_non_disclosure_name
config = { :DocumentRoot => File.dirname(__FILE__), }
log_tester = lambda {|log, access_log|
log = log.reject {|s| /ERROR `.*\' not found\./ =~ s }
log = log.reject {|s| /WARN the request refers nondisclosure name/ =~ s }
assert_equal([], log)
}
this_file = File.basename(__FILE__)
TestWEBrick.start_httpserver(config, log_tester) do |server, addr, port, log|
http = Net::HTTP.new(addr, port)
doc_root_opts = server[:DocumentRootOptions]
doc_root_opts[:NondisclosureName] = %w(.ht* *~ test_*)
req = Net::HTTP::Get.new("/")
http.request(req){|res|
assert_equal("200", res.code, log.call)
assert_equal("text/html", res.content_type, log.call)
assert_no_match(/HREF="#{File.basename(__FILE__)}"/, res.body)
}
req = Net::HTTP::Get.new("/#{this_file}")
http.request(req){|res|
assert_equal("404", res.code, log.call)
}
doc_root_opts[:NondisclosureName] = %w(.ht* *~ TEST_*)
http.request(req){|res|
assert_equal("404", res.code, log.call)
}
end
end
def test_directory_traversal
return if File.executable?(__FILE__) # skip on strange file system
config = { :DocumentRoot => File.dirname(__FILE__), }
log_tester = lambda {|log, access_log|
log = log.reject {|s| /ERROR bad URI/ =~ s }
log = log.reject {|s| /ERROR `.*\' not found\./ =~ s }
assert_equal([], log)
}
TestWEBrick.start_httpserver(config, log_tester) do |server, addr, port, log|
http = Net::HTTP.new(addr, port)
req = Net::HTTP::Get.new("/../../")
http.request(req){|res| assert_equal("400", res.code, log.call) }
req = Net::HTTP::Get.new("/..%5c../#{File.basename(__FILE__)}")
http.request(req){|res| assert_equal(windows? ? "200" : "404", res.code, log.call) }
req = Net::HTTP::Get.new("/..%5c..%5cruby.c")
http.request(req){|res| assert_equal("404", res.code, log.call) }
end
end
def test_unwise_in_path
if windows?
config = { :DocumentRoot => File.dirname(__FILE__), }
TestWEBrick.start_httpserver(config) do |server, addr, port, log|
http = Net::HTTP.new(addr, port)
req = Net::HTTP::Get.new("/..%5c..")
http.request(req){|res| assert_equal("301", res.code, log.call) }
end
end
end
def test_short_filename
return if File.executable?(__FILE__) # skip on strange file system
config = {
:CGIInterpreter => TestWEBrick::RubyBin,
:DocumentRoot => File.dirname(__FILE__),
:CGIPathEnv => ENV['PATH'],
}
log_tester = lambda {|log, access_log|
log = log.reject {|s| /ERROR `.*\' not found\./ =~ s }
log = log.reject {|s| /WARN the request refers nondisclosure name/ =~ s }
assert_equal([], log)
}
TestWEBrick.start_httpserver(config, log_tester) do |server, addr, port, log|
http = Net::HTTP.new(addr, port)
if windows?
root = config[:DocumentRoot].tr("/", "\\")
fname = IO.popen(%W[dir /x #{root}\\webrick_long_filename.cgi], &:read)
fname.sub!(/\A.*$^$.*$^$/m, '')
if fname
fname = fname[/\s(w.+?cgi)\s/i, 1]
fname.downcase!
end
else
fname = "webric~1.cgi"
end
req = Net::HTTP::Get.new("/#{fname}/test")
http.request(req) do |res|
if windows?
assert_equal("200", res.code, log.call)
assert_equal("/test", res.body, log.call)
else
assert_equal("404", res.code, log.call)
end
end
req = Net::HTTP::Get.new("/.htaccess")
http.request(req) {|res| assert_equal("404", res.code, log.call) }
req = Net::HTTP::Get.new("/htacce~1")
http.request(req) {|res| assert_equal("404", res.code, log.call) }
req = Net::HTTP::Get.new("/HTACCE~1")
http.request(req) {|res| assert_equal("404", res.code, log.call) }
end
end
def test_script_disclosure
return if File.executable?(__FILE__) # skip on strange file system
config = {
:CGIInterpreter => TestWEBrick::RubyBin,
:DocumentRoot => File.dirname(__FILE__),
:CGIPathEnv => ENV['PATH'],
:RequestCallback => Proc.new{|req, res|
def req.meta_vars
meta = super
meta["RUBYLIB"] = $:.join(File::PATH_SEPARATOR)
meta[RbConfig::CONFIG['LIBPATHENV']] = ENV[RbConfig::CONFIG['LIBPATHENV']] if RbConfig::CONFIG['LIBPATHENV']
return meta
end
},
}
log_tester = lambda {|log, access_log|
log = log.reject {|s| /ERROR `.*\' not found\./ =~ s }
assert_equal([], log)
}
TestWEBrick.start_httpserver(config, log_tester) do |server, addr, port, log|
http = Net::HTTP.new(addr, port)
req = Net::HTTP::Get.new("/webrick.cgi/test")
http.request(req) do |res|
assert_equal("200", res.code, log.call)
assert_equal("/test", res.body, log.call)
end
resok = windows?
response_assertion = Proc.new do |res|
if resok
assert_equal("200", res.code, log.call)
assert_equal("/test", res.body, log.call)
else
assert_equal("404", res.code, log.call)
end
end
req = Net::HTTP::Get.new("/webrick.cgi%20/test")
http.request(req, &response_assertion)
req = Net::HTTP::Get.new("/webrick.cgi./test")
http.request(req, &response_assertion)
resok &&= File.exist?(__FILE__+"::$DATA")
req = Net::HTTP::Get.new("/webrick.cgi::$DATA/test")
http.request(req, &response_assertion)
end
end
def test_erbhandler
config = { :DocumentRoot => File.dirname(__FILE__) }
log_tester = lambda {|log, access_log|
log = log.reject {|s| /ERROR `.*\' not found\./ =~ s }
assert_equal([], log)
}
TestWEBrick.start_httpserver(config, log_tester) do |server, addr, port, log|
http = Net::HTTP.new(addr, port)
req = Net::HTTP::Get.new("/webrick.rhtml")
http.request(req) do |res|
assert_equal("200", res.code, log.call)
assert_match %r!\Areq to http://[^/]+/webrick\.rhtml {}\n!, res.body
end
end
end
end
/dev/null
require "tempfile"
require "test/unit"
require "webrick/httpauth/htgroup"
class TestHtgroup < Test::Unit::TestCase
def test_htgroup
Tempfile.create('test_htgroup') do |tmpfile|
tmpfile.close
tmp_group = WEBrick::HTTPAuth::Htgroup.new(tmpfile.path)
tmp_group.add 'superheroes', %w[spiderman batman]
tmp_group.add 'supervillains', %w[joker]
tmp_group.flush
htgroup = WEBrick::HTTPAuth::Htgroup.new(tmpfile.path)
assert_equal(htgroup.members('superheroes'), %w[spiderman batman])
assert_equal(htgroup.members('supervillains'), %w[joker])
end
end
end
/dev/null
# frozen_string_literal: false
require "test/unit"
require "webrick/htmlutils"
class TestWEBrickHTMLUtils < Test::Unit::TestCase
include WEBrick::HTMLUtils
def test_escape
assert_equal("foo", escape("foo"))
assert_equal("foo bar", escape("foo bar"))
assert_equal("foo&amp;bar", escape("foo&bar"))
assert_equal("foo&quot;bar", escape("foo\"bar"))
assert_equal("foo&gt;bar", escape("foo>bar"))
assert_equal("foo&lt;bar", escape("foo<bar"))
assert_equal("\u{3053 3093 306B 3061 306F}", escape("\u{3053 3093 306B 3061 306F}"))
bug8425 = '[Bug #8425] [ruby-core:55052]'
assert_nothing_raised(ArgumentError, Encoding::CompatibilityError, bug8425) {
assert_equal("\u{3053 3093 306B}\xff&lt;", escape("\u{3053 3093 306B}\xff<"))
}
end
end
/dev/null
# frozen_string_literal: false
require "test/unit"
require "net/http"
require "tempfile"
require "webrick"
require "webrick/httpauth/basicauth"
require "stringio"
require_relative "utils"
class TestWEBrickHTTPAuth < Test::Unit::TestCase
def teardown
WEBrick::Utils::TimeoutHandler.terminate
super
end
def test_basic_auth
log_tester = lambda {|log, access_log|
assert_equal(1, log.length)
assert_match(/ERROR WEBrick::HTTPStatus::Unauthorized/, log[0])
}
TestWEBrick.start_httpserver({}, log_tester) {|server, addr, port, log|
realm = "WEBrick's realm"
path = "/basic_auth"
server.mount_proc(path){|req, res|
WEBrick::HTTPAuth.basic_auth(req, res, realm){|user, pass|
user == "webrick" && pass == "supersecretpassword"
}
res.body = "hoge"
}
http = Net::HTTP.new(addr, port)
g = Net::HTTP::Get.new(path)
g.basic_auth("webrick", "supersecretpassword")
http.request(g){|res| assert_equal("hoge", res.body, log.call)}
g.basic_auth("webrick", "not super")
http.request(g){|res| assert_not_equal("hoge", res.body, log.call)}
}
end
def test_basic_auth_sha
Tempfile.create("test_webrick_auth") {|tmpfile|
tmpfile.puts("webrick:{SHA}GJYFRpBbdchp595jlh3Bhfmgp8k=")
tmpfile.flush
assert_raise(NotImplementedError){
WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path)
}
}
end
def test_basic_auth_md5
Tempfile.create("test_webrick_auth") {|tmpfile|
tmpfile.puts("webrick:$apr1$IOVMD/..$rmnOSPXr0.wwrLPZHBQZy0")
tmpfile.flush
assert_raise(NotImplementedError){
WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path)
}
}
end
[nil, :crypt, :bcrypt].each do |hash_algo|
begin
case hash_algo
when :crypt
# require 'string/crypt'
when :bcrypt
require 'bcrypt'
end
rescue LoadError
next
end
define_method(:"test_basic_auth_htpasswd_#{hash_algo}") do
log_tester = lambda {|log, access_log|
log.reject! {|line| /\A\s*\z/ =~ line }
pats = [
/ERROR Basic WEBrick's realm: webrick: password unmatch\./,
/ERROR WEBrick::HTTPStatus::Unauthorized/
]
pats.each {|pat|
assert(!log.grep(pat).empty?, "webrick log doesn't have expected error: #{pat.inspect}")
log.reject! {|line| pat =~ line }
}
assert_equal([], log)
}
TestWEBrick.start_httpserver({}, log_tester) {|server, addr, port, log|
realm = "WEBrick's realm"
path = "/basic_auth2"
Tempfile.create("test_webrick_auth") {|tmpfile|
tmpfile.close
tmp_pass = WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path, password_hash: hash_algo)
tmp_pass.set_passwd(realm, "webrick", "supersecretpassword")
tmp_pass.set_passwd(realm, "foo", "supersecretpassword")
tmp_pass.flush
htpasswd = WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path, password_hash: hash_algo)
users = []
htpasswd.each{|user, pass| users << user }
assert_equal(2, users.size, log.call)
assert(users.member?("webrick"), log.call)
assert(users.member?("foo"), log.call)
server.mount_proc(path){|req, res|
auth = WEBrick::HTTPAuth::BasicAuth.new(
:Realm => realm, :UserDB => htpasswd,
:Logger => server.logger
)
auth.authenticate(req, res)
res.body = "hoge"
}
http = Net::HTTP.new(addr, port)
g = Net::HTTP::Get.new(path)
g.basic_auth("webrick", "supersecretpassword")
http.request(g){|res| assert_equal("hoge", res.body, log.call)}
g.basic_auth("webrick", "not super")
http.request(g){|res| assert_not_equal("hoge", res.body, log.call)}
}
}
end
define_method(:"test_basic_auth_bad_username_htpasswd_#{hash_algo}") do
log_tester = lambda {|log, access_log|
assert_equal(2, log.length)
assert_match(/ERROR Basic WEBrick's realm: foo\\ebar: the user is not allowed\./, log[0])
assert_match(/ERROR WEBrick::HTTPStatus::Unauthorized/, log[1])
}
TestWEBrick.start_httpserver({}, log_tester) {|server, addr, port, log|
realm = "WEBrick's realm"
path = "/basic_auth"
Tempfile.create("test_webrick_auth") {|tmpfile|
tmpfile.close
tmp_pass = WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path, password_hash: hash_algo)
tmp_pass.set_passwd(realm, "webrick", "supersecretpassword")
tmp_pass.set_passwd(realm, "foo", "supersecretpassword")
tmp_pass.flush
htpasswd = WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path, password_hash: hash_algo)
users = []
htpasswd.each{|user, pass| users << user }
server.mount_proc(path){|req, res|
auth = WEBrick::HTTPAuth::BasicAuth.new(
:Realm => realm, :UserDB => htpasswd,
:Logger => server.logger
)
auth.authenticate(req, res)
res.body = "hoge"
}
http = Net::HTTP.new(addr, port)
g = Net::HTTP::Get.new(path)
g.basic_auth("foo\ebar", "passwd")
http.request(g){|res| assert_not_equal("hoge", res.body, log.call) }
}
}
end
end
DIGESTRES_ = /
([a-zA-Z\-]+)
[ \t]*(?:\r\n[ \t]*)*
=
[ \t]*(?:\r\n[ \t]*)*
(?:
"((?:[^"]+|\\[\x00-\x7F])*)" |
([!\#$%&'*+\-.0-9A-Z^_`a-z|~]+)
)/x
def test_digest_auth
log_tester = lambda {|log, access_log|
log.reject! {|line| /\A\s*\z/ =~ line }
pats = [
/ERROR Digest WEBrick's realm: no credentials in the request\./,
/ERROR WEBrick::HTTPStatus::Unauthorized/,
/ERROR Digest WEBrick's realm: webrick: digest unmatch\./
]
pats.each {|pat|
assert(!log.grep(pat).empty?, "webrick log doesn't have expected error: #{pat.inspect}")
log.reject! {|line| pat =~ line }
}
assert_equal([], log)
}
TestWEBrick.start_httpserver({}, log_tester) {|server, addr, port, log|
realm = "WEBrick's realm"
path = "/digest_auth"
Tempfile.create("test_webrick_auth") {|tmpfile|
tmpfile.close
tmp_pass = WEBrick::HTTPAuth::Htdigest.new(tmpfile.path)
tmp_pass.set_passwd(realm, "webrick", "supersecretpassword")
tmp_pass.set_passwd(realm, "foo", "supersecretpassword")
tmp_pass.flush
htdigest = WEBrick::HTTPAuth::Htdigest.new(tmpfile.path)
users = []
htdigest.each{|user, pass| users << user }
assert_equal(2, users.size, log.call)
assert(users.member?("webrick"), log.call)
assert(users.member?("foo"), log.call)
auth = WEBrick::HTTPAuth::DigestAuth.new(
:Realm => realm, :UserDB => htdigest,
:Algorithm => 'MD5',
:Logger => server.logger
)
server.mount_proc(path){|req, res|
auth.authenticate(req, res)
res.body = "hoge"
}
Net::HTTP.start(addr, port) do |http|
g = Net::HTTP::Get.new(path)
params = {}
http.request(g) do |res|
assert_equal('401', res.code, log.call)
res["www-authenticate"].scan(DIGESTRES_) do |key, quoted, token|
params[key.downcase] = token || quoted.delete('\\')
end
params['uri'] = "http://#{addr}:#{port}#{path}"
end
g['Authorization'] = credentials_for_request('webrick', "supersecretpassword", params)
http.request(g){|res| assert_equal("hoge", res.body, log.call)}
params['algorithm'].downcase! #4936
g['Authorization'] = credentials_for_request('webrick', "supersecretpassword", params)
http.request(g){|res| assert_equal("hoge", res.body, log.call)}
g['Authorization'] = credentials_for_request('webrick', "not super", params)
http.request(g){|res| assert_not_equal("hoge", res.body, log.call)}
end
}
}
end
def test_digest_auth_int
log_tester = lambda {|log, access_log|
log.reject! {|line| /\A\s*\z/ =~ line }
pats = [
/ERROR Digest wb auth-int realm: no credentials in the request\./,
/ERROR WEBrick::HTTPStatus::Unauthorized/,
/ERROR Digest wb auth-int realm: foo: digest unmatch\./
]
pats.each {|pat|
assert(!log.grep(pat).empty?, "webrick log doesn't have expected error: #{pat.inspect}")
log.reject! {|line| pat =~ line }
}
assert_equal([], log)
}
TestWEBrick.start_httpserver({}, log_tester) {|server, addr, port, log|
realm = "wb auth-int realm"
path = "/digest_auth_int"
Tempfile.create("test_webrick_auth_int") {|tmpfile|
tmpfile.close
tmp_pass = WEBrick::HTTPAuth::Htdigest.new(tmpfile.path)
tmp_pass.set_passwd(realm, "foo", "Hunter2")
tmp_pass.flush
htdigest = WEBrick::HTTPAuth::Htdigest.new(tmpfile.path)
users = []
htdigest.each{|user, pass| users << user }
assert_equal %w(foo), users
auth = WEBrick::HTTPAuth::DigestAuth.new(
:Realm => realm, :UserDB => htdigest,
:Algorithm => 'MD5',
:Logger => server.logger,
:Qop => %w(auth-int),
)
server.mount_proc(path){|req, res|
auth.authenticate(req, res)
res.body = "bbb"
}
Net::HTTP.start(addr, port) do |http|
post = Net::HTTP::Post.new(path)
params = {}
data = 'hello=world'
body = StringIO.new(data)
post.content_length = data.bytesize
post['Content-Type'] = 'application/x-www-form-urlencoded'
post.body_stream = body
http.request(post) do |res|
assert_equal('401', res.code, log.call)
res["www-authenticate"].scan(DIGESTRES_) do |key, quoted, token|
params[key.downcase] = token || quoted.delete('\\')
end
params['uri'] = "http://#{addr}:#{port}#{path}"
end
body.rewind
cred = credentials_for_request('foo', 'Hunter3', params, body)
post['Authorization'] = cred
post.body_stream = body
http.request(post){|res|
assert_equal('401', res.code, log.call)
assert_not_equal("bbb", res.body, log.call)
}
body.rewind
cred = credentials_for_request('foo', 'Hunter2', params, body)
post['Authorization'] = cred
post.body_stream = body
http.request(post){|res| assert_equal("bbb", res.body, log.call)}
end
}
}
end
private
def credentials_for_request(user, password, params, body = nil)
cnonce = "hoge"
nonce_count = 1
ha1 = "#{user}:#{params['realm']}:#{password}"
if body
dig = Digest::MD5.new
while buf = body.read(16384)
dig.update(buf)
end
body.rewind
ha2 = "POST:#{params['uri']}:#{dig.hexdigest}"
else
ha2 = "GET:#{params['uri']}"
end
request_digest =
"#{Digest::MD5.hexdigest(ha1)}:" \
"#{params['nonce']}:#{'%08x' % nonce_count}:#{cnonce}:#{params['qop']}:" \
"#{Digest::MD5.hexdigest(ha2)}"
"Digest username=\"#{user}\"" \
", realm=\"#{params['realm']}\"" \
", nonce=\"#{params['nonce']}\"" \
", uri=\"#{params['uri']}\"" \
", qop=#{params['qop']}" \
", nc=#{'%08x' % nonce_count}" \
", cnonce=\"#{cnonce}\"" \
", response=\"#{Digest::MD5.hexdigest(request_digest)}\"" \
", opaque=\"#{params['opaque']}\"" \
", algorithm=#{params['algorithm']}"
end
end
/dev/null
# frozen_string_literal: false
require "test/unit"
require "net/http"
require "webrick"
require "webrick/httpproxy"
begin
require "webrick/ssl"
require "net/https"
rescue LoadError
# test_connect will be skipped
end
require File.expand_path("utils.rb", File.dirname(__FILE__))
class TestWEBrickHTTPProxy < Test::Unit::TestCase
def teardown
WEBrick::Utils::TimeoutHandler.terminate
super
end
def test_fake_proxy
assert_nil(WEBrick::FakeProxyURI.scheme)
assert_nil(WEBrick::FakeProxyURI.host)
assert_nil(WEBrick::FakeProxyURI.port)
assert_nil(WEBrick::FakeProxyURI.path)
assert_nil(WEBrick::FakeProxyURI.userinfo)
assert_raise(NoMethodError){ WEBrick::FakeProxyURI.foo }
end
def test_proxy
# Testing GET or POST to the proxy server
# Note that the proxy server works as the origin server.
# +------+
# V |
# client -------> proxy ---+
# GET / POST GET / POST
#
proxy_handler_called = request_handler_called = 0
config = {
:ServerName => "localhost.localdomain",
:ProxyContentHandler => Proc.new{|req, res| proxy_handler_called += 1 },
:RequestCallback => Proc.new{|req, res| request_handler_called += 1 }
}
TestWEBrick.start_httpproxy(config){|server, addr, port, log|
server.mount_proc("/"){|req, res|
res.body = "#{req.request_method} #{req.path} #{req.body}"
}
http = Net::HTTP.new(addr, port, addr, port)
req = Net::HTTP::Get.new("/")
http.request(req){|res|
assert_equal("1.1 localhost.localdomain:#{port}", res["via"], log.call)
assert_equal("GET / ", res.body, log.call)
}
assert_equal(1, proxy_handler_called, log.call)
assert_equal(2, request_handler_called, log.call)
req = Net::HTTP::Head.new("/")
http.request(req){|res|
assert_equal("1.1 localhost.localdomain:#{port}", res["via"], log.call)
assert_nil(res.body, log.call)
}
assert_equal(2, proxy_handler_called, log.call)
assert_equal(4, request_handler_called, log.call)
req = Net::HTTP::Post.new("/")
req.body = "post-data"
req.content_type = "application/x-www-form-urlencoded"
http.request(req){|res|
assert_equal("1.1 localhost.localdomain:#{port}", res["via"], log.call)
assert_equal("POST / post-data", res.body, log.call)
}
assert_equal(3, proxy_handler_called, log.call)
assert_equal(6, request_handler_called, log.call)
}
end
def test_no_proxy
# Testing GET or POST to the proxy server without proxy request.
#
# client -------> proxy
# GET / POST
#
proxy_handler_called = request_handler_called = 0
config = {
:ServerName => "localhost.localdomain",
:ProxyContentHandler => Proc.new{|req, res| proxy_handler_called += 1 },
:RequestCallback => Proc.new{|req, res| request_handler_called += 1 }
}
TestWEBrick.start_httpproxy(config){|server, addr, port, log|
server.mount_proc("/"){|req, res|
res.body = "#{req.request_method} #{req.path} #{req.body}"
}
http = Net::HTTP.new(addr, port)
req = Net::HTTP::Get.new("/")
http.request(req){|res|
assert_nil(res["via"], log.call)
assert_equal("GET / ", res.body, log.call)
}
assert_equal(0, proxy_handler_called, log.call)
assert_equal(1, request_handler_called, log.call)
req = Net::HTTP::Head.new("/")
http.request(req){|res|
assert_nil(res["via"], log.call)
assert_nil(res.body, log.call)
}
assert_equal(0, proxy_handler_called, log.call)
assert_equal(2, request_handler_called, log.call)
req = Net::HTTP::Post.new("/")
req.content_type = "application/x-www-form-urlencoded"
req.body = "post-data"
http.request(req){|res|
assert_nil(res["via"], log.call)
assert_equal("POST / post-data", res.body, log.call)
}
assert_equal(0, proxy_handler_called, log.call)
assert_equal(3, request_handler_called, log.call)
}
end
def test_big_bodies
require 'digest/md5'
rand_str = File.read(__FILE__)
rand_str.freeze
nr = 1024 ** 2 / rand_str.size # bigger works, too
exp = Digest::MD5.new
nr.times { exp.update(rand_str) }
exp = exp.hexdigest
TestWEBrick.start_httpserver do |o_server, o_addr, o_port, o_log|
o_server.mount_proc('/') do |req, res|
case req.request_method
when 'GET'
res['content-type'] = 'application/octet-stream'
if req.path == '/length'
res['content-length'] = (nr * rand_str.size).to_s
else
res.chunked = true
end
res.body = ->(socket) { nr.times { socket.write(rand_str) } }
when 'POST'
dig = Digest::MD5.new
req.body { |buf| dig.update(buf); buf.clear }
res['content-type'] = 'text/plain'
res['content-length'] = '32'
res.body = dig.hexdigest
end
end
http = Net::HTTP.new(o_addr, o_port)
... This diff was truncated because it exceeds the maximum size that can be displayed.
    (1-1/1)