diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/webrick/test_httpauth.rb | 90 | ||||
-rw-r--r-- | test/webrick/test_httpserver.rb | 67 |
2 files changed, 155 insertions, 2 deletions
diff --git a/test/webrick/test_httpauth.rb b/test/webrick/test_httpauth.rb index 2ee492db7a..ff539f06c7 100644 --- a/test/webrick/test_httpauth.rb +++ b/test/webrick/test_httpauth.rb @@ -4,6 +4,7 @@ require "net/http" require "tempfile" require "webrick" require "webrick/httpauth/basicauth" +require "stringio" require_relative "utils" class TestWEBrickHTTPAuth < Test::Unit::TestCase @@ -216,12 +217,97 @@ class TestWEBrickHTTPAuth < Test::Unit::TestCase } 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) + def credentials_for_request(user, password, params, body = nil) cnonce = "hoge" nonce_count = 1 ha1 = "#{user}:#{params['realm']}:#{password}" - ha2 = "GET:#{params['uri']}" + 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']}:" \ diff --git a/test/webrick/test_httpserver.rb b/test/webrick/test_httpserver.rb index daeb7b955e..024c0c510f 100644 --- a/test/webrick/test_httpserver.rb +++ b/test/webrick/test_httpserver.rb @@ -440,4 +440,71 @@ class TestWEBrickHTTPServer < Test::Unit::TestCase 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 |