mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* io.c (internal_write_func, internal_writev_func): retry at unexpected EPROTOTYPE on macOS, to get rid of a kernel bug. [ruby-core:86690] [Bug #14713] * ext/socket/init.c (rsock_{sendto,send,write}_blocking): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63304 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_include log_ary[0], exp
 | 
						|
  ensure
 | 
						|
    s&.shutdown
 | 
						|
    th&.join
 | 
						|
  end
 | 
						|
 | 
						|
  def test_gigantic_request_header
 | 
						|
    log_tester = lambda {|log, access_log|
 | 
						|
      assert_equal 1, log.size
 | 
						|
      assert_include log[0], '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_include log[0], '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
 |