Project

General

Profile

Feature #15657 ยป remove-webrick.patch

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

View differences:

gems/bundled_gems
4 4
power_assert 1.1.3 https://github.com/k-tsj/power_assert
5 5
rake 12.3.2 https://github.com/ruby/rake
6 6
test-unit 3.2.9 https://github.com/test-unit/test-unit
7
webrick 1.4.2 https://github.com/ruby/webrick
7 8
xmlrpc 0.3.0 https://github.com/ruby/xmlrpc
/dev/null
1
this file should not be published.
/dev/null
1
# coding: US-ASCII
2
# frozen_string_literal: false
3
require_relative "utils"
4
require "webrick"
5
require "test/unit"
6

  
7
class TestWEBrickCGI < Test::Unit::TestCase
8
  CRLF = "\r\n"
9

  
10
  def teardown
11
    WEBrick::Utils::TimeoutHandler.terminate
12
    super
13
  end
14

  
15
  def start_cgi_server(log_tester=TestWEBrick::DefaultLogTester, &block)
16
    config = {
17
      :CGIInterpreter => TestWEBrick::RubyBin,
18
      :DocumentRoot => File.dirname(__FILE__),
19
      :DirectoryIndex => ["webrick.cgi"],
20
      :RequestCallback => Proc.new{|req, res|
21
        def req.meta_vars
22
          meta = super
23
          meta["RUBYLIB"] = $:.join(File::PATH_SEPARATOR)
24
          meta[RbConfig::CONFIG['LIBPATHENV']] = ENV[RbConfig::CONFIG['LIBPATHENV']] if RbConfig::CONFIG['LIBPATHENV']
25
          return meta
26
        end
27
      },
28
    }
29
    if RUBY_PLATFORM =~ /mswin|mingw|cygwin|bccwin32/
30
      config[:CGIPathEnv] = ENV['PATH'] # runtime dll may not be in system dir.
31
    end
32
    TestWEBrick.start_httpserver(config, log_tester){|server, addr, port, log|
33
      block.call(server, addr, port, log)
34
    }
35
  end
36

  
37
  def test_cgi
38
    start_cgi_server{|server, addr, port, log|
39
      http = Net::HTTP.new(addr, port)
40
      req = Net::HTTP::Get.new("/webrick.cgi")
41
      http.request(req){|res| assert_equal("/webrick.cgi", res.body, log.call)}
42
      req = Net::HTTP::Get.new("/webrick.cgi/path/info")
43
      http.request(req){|res| assert_equal("/path/info", res.body, log.call)}
44
      req = Net::HTTP::Get.new("/webrick.cgi/%3F%3F%3F?foo=bar")
45
      http.request(req){|res| assert_equal("/???", res.body, log.call)}
46
      unless RUBY_PLATFORM =~ /mswin|mingw|cygwin|bccwin32/
47
        # Path info of res.body is passed via ENV.
48
        # ENV[] returns different value on Windows depending on locale.
49
        req = Net::HTTP::Get.new("/webrick.cgi/%A4%DB%A4%B2/%A4%DB%A4%B2")
50
        http.request(req){|res|
51
          assert_equal("/\xA4\xDB\xA4\xB2/\xA4\xDB\xA4\xB2", res.body, log.call)}
52
      end
53
      req = Net::HTTP::Get.new("/webrick.cgi?a=1;a=2;b=x")
54
      http.request(req){|res| assert_equal("a=1, a=2, b=x", res.body, log.call)}
55
      req = Net::HTTP::Get.new("/webrick.cgi?a=1&a=2&b=x")
56
      http.request(req){|res| assert_equal("a=1, a=2, b=x", res.body, log.call)}
57

  
58
      req = Net::HTTP::Post.new("/webrick.cgi?a=x;a=y;b=1")
59
      req["Content-Type"] = "application/x-www-form-urlencoded"
60
      http.request(req, "a=1;a=2;b=x"){|res|
61
        assert_equal("a=1, a=2, b=x", res.body, log.call)}
62
      req = Net::HTTP::Post.new("/webrick.cgi?a=x&a=y&b=1")
63
      req["Content-Type"] = "application/x-www-form-urlencoded"
64
      http.request(req, "a=1&a=2&b=x"){|res|
65
        assert_equal("a=1, a=2, b=x", res.body, log.call)}
66
      req = Net::HTTP::Get.new("/")
67
      http.request(req){|res|
68
        ary = res.body.lines.to_a
69
        assert_match(%r{/$}, ary[0], log.call)
70
        assert_match(%r{/webrick.cgi$}, ary[1], log.call)
71
      }
72

  
73
      req = Net::HTTP::Get.new("/webrick.cgi")
74
      req["Cookie"] = "CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001"
75
      http.request(req){|res|
76
        assert_equal(
77
          "CUSTOMER=WILE_E_COYOTE\nPART_NUMBER=ROCKET_LAUNCHER_0001\n",
78
          res.body, log.call)
79
      }
80

  
81
      req = Net::HTTP::Get.new("/webrick.cgi")
82
      cookie =  %{$Version="1"; }
83
      cookie << %{Customer="WILE_E_COYOTE"; $Path="/acme"; }
84
      cookie << %{Part_Number="Rocket_Launcher_0001"; $Path="/acme"; }
85
      cookie << %{Shipping="FedEx"; $Path="/acme"}
86
      req["Cookie"] = cookie
87
      http.request(req){|res|
88
        assert_equal("Customer=WILE_E_COYOTE, Shipping=FedEx",
89
                     res["Set-Cookie"], log.call)
90
        assert_equal("Customer=WILE_E_COYOTE\n" +
91
                     "Part_Number=Rocket_Launcher_0001\n" +
92
                     "Shipping=FedEx\n", res.body, log.call)
93
      }
94
    }
95
  end
96

  
97
  def test_bad_request
98
    log_tester = lambda {|log, access_log|
99
      assert_match(/BadRequest/, log.join)
100
    }
101
    start_cgi_server(log_tester) {|server, addr, port, log|
102
      sock = TCPSocket.new(addr, port)
103
      begin
104
        sock << "POST /webrick.cgi HTTP/1.0" << CRLF
105
        sock << "Content-Type: application/x-www-form-urlencoded" << CRLF
106
        sock << "Content-Length: 1024" << CRLF
107
        sock << CRLF
108
        sock << "a=1&a=2&b=x"
109
        sock.close_write
110
        assert_match(%r{\AHTTP/\d.\d 400 Bad Request}, sock.read, log.call)
111
      ensure
112
        sock.close
113
      end
114
    }
115
  end
116

  
117
  def test_cgi_env
118
    start_cgi_server do |server, addr, port, log|
119
      http = Net::HTTP.new(addr, port)
120
      req = Net::HTTP::Get.new("/webrick.cgi/dumpenv")
121
      req['proxy'] = 'http://example.com/'
122
      req['hello'] = 'world'
123
      http.request(req) do |res|
124
        env = Marshal.load(res.body)
125
        assert_equal 'world', env['HTTP_HELLO']
126
        assert_not_operator env, :include?, 'HTTP_PROXY'
127
      end
128
    end
129
  end
130

  
131
  CtrlSeq = [0x7f, *(1..31)].pack("C*").gsub(/\s+/, '')
132
  CtrlPat = /#{Regexp.quote(CtrlSeq)}/o
133
  DumpPat = /#{Regexp.quote(CtrlSeq.dump[1...-1])}/o
134

  
135
  def test_bad_uri
136
    log_tester = lambda {|log, access_log|
137
      assert_equal(1, log.length)
138
      assert_match(/ERROR bad URI/, log[0])
139
    }
140
    start_cgi_server(log_tester) {|server, addr, port, log|
141
      res = TCPSocket.open(addr, port) {|sock|
142
        sock << "GET /#{CtrlSeq}#{CRLF}#{CRLF}"
143
        sock.close_write
144
        sock.read
145
      }
146
      assert_match(%r{\AHTTP/\d.\d 400 Bad Request}, res)
147
      s = log.call.each_line.grep(/ERROR bad URI/)[0]
148
      assert_match(DumpPat, s)
149
      assert_not_match(CtrlPat, s)
150
    }
151
  end
152

  
153
  def test_bad_header
154
    log_tester = lambda {|log, access_log|
155
      assert_equal(1, log.length)
156
      assert_match(/ERROR bad header/, log[0])
157
    }
158
    start_cgi_server(log_tester) {|server, addr, port, log|
159
      res = TCPSocket.open(addr, port) {|sock|
160
        sock << "GET / HTTP/1.0#{CRLF}#{CtrlSeq}#{CRLF}#{CRLF}"
161
        sock.close_write
162
        sock.read
163
      }
164
      assert_match(%r{\AHTTP/\d.\d 400 Bad Request}, res)
165
      s = log.call.each_line.grep(/ERROR bad header/)[0]
166
      assert_match(DumpPat, s)
167
      assert_not_match(CtrlPat, s)
168
    }
169
  end
170
end
/dev/null
1
# frozen_string_literal: false
2
require "test/unit"
3
require "webrick/config"
4

  
5
class TestWEBrickConfig < Test::Unit::TestCase
6
  def test_server_name_default
7
    config = WEBrick::Config::General.dup
8
    assert_equal(false, config.key?(:ServerName))
9
    assert_equal(WEBrick::Utils.getservername, config[:ServerName])
10
    assert_equal(true, config.key?(:ServerName))
11
  end
12

  
13
  def test_server_name_set_nil
14
    config = WEBrick::Config::General.dup.update(ServerName: nil)
15
    assert_equal(nil, config[:ServerName])
16
  end
17
end
/dev/null
1
# frozen_string_literal: false
2
require "test/unit"
3
require "webrick/cookie"
4

  
5
class TestWEBrickCookie < Test::Unit::TestCase
6
  def test_new
7
    cookie = WEBrick::Cookie.new("foo","bar")
8
    assert_equal("foo", cookie.name)
9
    assert_equal("bar", cookie.value)
10
    assert_equal("foo=bar", cookie.to_s)
11
  end
12

  
13
  def test_time
14
    cookie = WEBrick::Cookie.new("foo","bar")
15
    t = 1000000000
16
    cookie.max_age = t
17
    assert_match(t.to_s, cookie.to_s)
18

  
19
    cookie = WEBrick::Cookie.new("foo","bar")
20
    t = Time.at(1000000000)
21
    cookie.expires = t
22
    assert_equal(Time, cookie.expires.class)
23
    assert_equal(t, cookie.expires)
24
    ts = t.httpdate
25
    cookie.expires = ts
26
    assert_equal(Time, cookie.expires.class)
27
    assert_equal(t, cookie.expires)
28
    assert_match(ts, cookie.to_s)
29
  end
30

  
31
  def test_parse
32
    data = ""
33
    data << '$Version="1"; '
34
    data << 'Customer="WILE_E_COYOTE"; $Path="/acme"; '
35
    data << 'Part_Number="Rocket_Launcher_0001"; $Path="/acme"; '
36
    data << 'Shipping="FedEx"; $Path="/acme"'
37
    cookies = WEBrick::Cookie.parse(data)
38
    assert_equal(3, cookies.size)
39
    assert_equal(1, cookies[0].version)
40
    assert_equal("Customer", cookies[0].name)
41
    assert_equal("WILE_E_COYOTE", cookies[0].value)
42
    assert_equal("/acme", cookies[0].path)
43
    assert_equal(1, cookies[1].version)
44
    assert_equal("Part_Number", cookies[1].name)
45
    assert_equal("Rocket_Launcher_0001", cookies[1].value)
46
    assert_equal(1, cookies[2].version)
47
    assert_equal("Shipping", cookies[2].name)
48
    assert_equal("FedEx", cookies[2].value)
49

  
50
    data = "hoge=moge; __div__session=9865ecfd514be7f7"
51
    cookies = WEBrick::Cookie.parse(data)
52
    assert_equal(2, cookies.size)
53
    assert_equal(0, cookies[0].version)
54
    assert_equal("hoge", cookies[0].name)
55
    assert_equal("moge", cookies[0].value)
56
    assert_equal("__div__session", cookies[1].name)
57
    assert_equal("9865ecfd514be7f7", cookies[1].value)
58

  
59
    # don't allow ,-separator
60
    data = "hoge=moge, __div__session=9865ecfd514be7f7"
61
    cookies = WEBrick::Cookie.parse(data)
62
    assert_equal(1, cookies.size)
63
    assert_equal(0, cookies[0].version)
64
    assert_equal("hoge", cookies[0].name)
65
    assert_equal("moge, __div__session=9865ecfd514be7f7", cookies[0].value)
66
  end
67

  
68
  def test_parse_no_whitespace
69
    data = [
70
      '$Version="1"; ',
71
      'Customer="WILE_E_COYOTE";$Path="/acme";', # no SP between cookie-string
72
      'Part_Number="Rocket_Launcher_0001";$Path="/acme";', # no SP between cookie-string
73
      'Shipping="FedEx";$Path="/acme"'
74
    ].join
75
    cookies = WEBrick::Cookie.parse(data)
76
    assert_equal(1, cookies.size)
77
  end
78

  
79
  def test_parse_too_much_whitespaces
80
    # According to RFC6265,
81
    #   cookie-string = cookie-pair *( ";" SP cookie-pair )
82
    # So single 0x20 is needed after ';'. We allow multiple spaces here for
83
    # compatibility with older WEBrick versions.
84
    data = [
85
      '$Version="1"; ',
86
      'Customer="WILE_E_COYOTE";$Path="/acme";     ', # no SP between cookie-string
87
      'Part_Number="Rocket_Launcher_0001";$Path="/acme";     ', # no SP between cookie-string
88
      'Shipping="FedEx";$Path="/acme"'
89
    ].join
90
    cookies = WEBrick::Cookie.parse(data)
91
    assert_equal(3, cookies.size)
92
  end
93

  
94
  def test_parse_set_cookie
95
    data = %(Customer="WILE_E_COYOTE"; Version="1"; Path="/acme")
96
    cookie = WEBrick::Cookie.parse_set_cookie(data)
97
    assert_equal("Customer", cookie.name)
98
    assert_equal("WILE_E_COYOTE", cookie.value)
99
    assert_equal(1, cookie.version)
100
    assert_equal("/acme", cookie.path)
101

  
102
    data = %(Shipping="FedEx"; Version="1"; Path="/acme"; Secure)
103
    cookie = WEBrick::Cookie.parse_set_cookie(data)
104
    assert_equal("Shipping", cookie.name)
105
    assert_equal("FedEx", cookie.value)
106
    assert_equal(1, cookie.version)
107
    assert_equal("/acme", cookie.path)
108
    assert_equal(true, cookie.secure)
109
  end
110

  
111
  def test_parse_set_cookies
112
    data = %(Shipping="FedEx"; Version="1"; Path="/acme"; Secure)
113
    data << %(, CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT; path=/; Secure)
114
    data << %(, name="Aaron"; Version="1"; path="/acme")
115
    cookies = WEBrick::Cookie.parse_set_cookies(data)
116
    assert_equal(3, cookies.length)
117

  
118
    fed_ex = cookies.find { |c| c.name == 'Shipping' }
119
    assert_not_nil(fed_ex)
120
    assert_equal("Shipping", fed_ex.name)
121
    assert_equal("FedEx", fed_ex.value)
122
    assert_equal(1, fed_ex.version)
123
    assert_equal("/acme", fed_ex.path)
124
    assert_equal(true, fed_ex.secure)
125

  
126
    name = cookies.find { |c| c.name == 'name' }
127
    assert_not_nil(name)
128
    assert_equal("name", name.name)
129
    assert_equal("Aaron", name.value)
130
    assert_equal(1, name.version)
131
    assert_equal("/acme", name.path)
132

  
133
    customer = cookies.find { |c| c.name == 'CUSTOMER' }
134
    assert_not_nil(customer)
135
    assert_equal("CUSTOMER", customer.name)
136
    assert_equal("WILE_E_COYOTE", customer.value)
137
    assert_equal(0, customer.version)
138
    assert_equal("/", customer.path)
139
    assert_equal(Time.utc(1999, 11, 9, 23, 12, 40), customer.expires)
140
  end
141
end
/dev/null
1
# frozen_string_literal: false
2
require "test/unit"
3
require "webrick"
4
require_relative "utils"
5

  
6
class TestDoNotReverseLookup < Test::Unit::TestCase
7
  class DNRL < WEBrick::GenericServer
8
    def run(sock)
9
      sock << sock.do_not_reverse_lookup.to_s
10
    end
11
  end
12

  
13
  @@original_do_not_reverse_lookup_value = Socket.do_not_reverse_lookup
14

  
15
  def teardown
16
    Socket.do_not_reverse_lookup = @@original_do_not_reverse_lookup_value
17
  end
18

  
19
  def do_not_reverse_lookup?(config)
20
    result = nil
21
    TestWEBrick.start_server(DNRL, config) do |server, addr, port, log|
22
      TCPSocket.open(addr, port) do |sock|
23
        result = {'true' => true, 'false' => false}[sock.gets]
24
      end
25
    end
26
    result
27
  end
28

  
29
  # +--------------------------------------------------------------------------+
30
  # |        Expected interaction between Socket.do_not_reverse_lookup         |
31
  # |            and WEBrick::Config::General[:DoNotReverseLookup]             |
32
  # +----------------------------+---------------------------------------------+
33
  # |                            |WEBrick::Config::General[:DoNotReverseLookup]|
34
  # +----------------------------+--------------+---------------+--------------+
35
  # |Socket.do_not_reverse_lookup|     TRUE     |     FALSE     |     NIL      |
36
  # +----------------------------+--------------+---------------+--------------+
37
  # |            TRUE            |     true     |     false     |     true     |
38
  # +----------------------------+--------------+---------------+--------------+
39
  # |            FALSE           |     true     |     false     |     false    |
40
  # +----------------------------+--------------+---------------+--------------+
41

  
42
  def test_socket_dnrl_true_server_dnrl_true
43
    Socket.do_not_reverse_lookup = true
44
    assert_equal(true, do_not_reverse_lookup?(:DoNotReverseLookup => true))
45
  end
46

  
47
  def test_socket_dnrl_true_server_dnrl_false
48
    Socket.do_not_reverse_lookup = true
49
    assert_equal(false, do_not_reverse_lookup?(:DoNotReverseLookup => false))
50
  end
51

  
52
  def test_socket_dnrl_true_server_dnrl_nil
53
    Socket.do_not_reverse_lookup = true
54
    assert_equal(true, do_not_reverse_lookup?(:DoNotReverseLookup => nil))
55
  end
56

  
57
  def test_socket_dnrl_false_server_dnrl_true
58
    Socket.do_not_reverse_lookup = false
59
    assert_equal(true, do_not_reverse_lookup?(:DoNotReverseLookup => true))
60
  end
61

  
62
  def test_socket_dnrl_false_server_dnrl_false
63
    Socket.do_not_reverse_lookup = false
64
    assert_equal(false, do_not_reverse_lookup?(:DoNotReverseLookup => false))
65
  end
66

  
67
  def test_socket_dnrl_false_server_dnrl_nil
68
    Socket.do_not_reverse_lookup = false
69
    assert_equal(false, do_not_reverse_lookup?(:DoNotReverseLookup => nil))
70
  end
71
end
/dev/null
1
# frozen_string_literal: false
2
require "test/unit"
3
require_relative "utils.rb"
4
require "webrick"
5
require "stringio"
6

  
7
class WEBrick::TestFileHandler < Test::Unit::TestCase
8
  def teardown
9
    WEBrick::Utils::TimeoutHandler.terminate
10
    super
11
  end
12

  
13
  def default_file_handler(filename)
14
    klass = WEBrick::HTTPServlet::DefaultFileHandler
15
    klass.new(WEBrick::Config::HTTP, filename)
16
  end
17

  
18
  def windows?
19
    File.directory?("\\")
20
  end
21

  
22
  def get_res_body(res)
23
    sio = StringIO.new
24
    sio.binmode
25
    res.send_body(sio)
26
    sio.string
27
  end
28

  
29
  def make_range_request(range_spec)
30
    msg = <<-END_OF_REQUEST
31
      GET / HTTP/1.0
32
      Range: #{range_spec}
33

  
34
    END_OF_REQUEST
35
    return StringIO.new(msg.gsub(/^ {6}/, ""))
36
  end
37

  
38
  def make_range_response(file, range_spec)
39
    req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
40
    req.parse(make_range_request(range_spec))
41
    res = WEBrick::HTTPResponse.new(WEBrick::Config::HTTP)
42
    size = File.size(file)
43
    handler = default_file_handler(file)
44
    handler.make_partial_content(req, res, file, size)
45
    return res
46
  end
47

  
48
  def test_make_partial_content
49
    filename = __FILE__
50
    filesize = File.size(filename)
51

  
52
    res = make_range_response(filename, "bytes=#{filesize-100}-")
53
    assert_match(%r{^text/plain}, res["content-type"])
54
    assert_equal(100, get_res_body(res).size)
55

  
56
    res = make_range_response(filename, "bytes=-100")
57
    assert_match(%r{^text/plain}, res["content-type"])
58
    assert_equal(100, get_res_body(res).size)
59

  
60
    res = make_range_response(filename, "bytes=0-99")
61
    assert_match(%r{^text/plain}, res["content-type"])
62
    assert_equal(100, get_res_body(res).size)
63

  
64
    res = make_range_response(filename, "bytes=100-199")
65
    assert_match(%r{^text/plain}, res["content-type"])
66
    assert_equal(100, get_res_body(res).size)
67

  
68
    res = make_range_response(filename, "bytes=0-0")
69
    assert_match(%r{^text/plain}, res["content-type"])
70
    assert_equal(1, get_res_body(res).size)
71

  
72
    res = make_range_response(filename, "bytes=-1")
73
    assert_match(%r{^text/plain}, res["content-type"])
74
    assert_equal(1, get_res_body(res).size)
75

  
76
    res = make_range_response(filename, "bytes=0-0, -2")
77
    assert_match(%r{^multipart/byteranges}, res["content-type"])
78
    body = get_res_body(res)
79
    boundary = /; boundary=(.+)/.match(res['content-type'])[1]
80
    off = filesize - 2
81
    last = filesize - 1
82

  
83
    exp = "--#{boundary}\r\n" \
84
          "Content-Type: text/plain\r\n" \
85
          "Content-Range: bytes 0-0/#{filesize}\r\n" \
86
          "\r\n" \
87
          "#{IO.read(__FILE__, 1)}\r\n" \
88
          "--#{boundary}\r\n" \
89
          "Content-Type: text/plain\r\n" \
90
          "Content-Range: bytes #{off}-#{last}/#{filesize}\r\n" \
91
          "\r\n" \
92
          "#{IO.read(__FILE__, 2, off)}\r\n" \
93
          "--#{boundary}--\r\n"
94
    assert_equal exp, body
95
  end
96

  
97
  def test_filehandler
98
    config = { :DocumentRoot => File.dirname(__FILE__), }
99
    this_file = File.basename(__FILE__)
100
    filesize = File.size(__FILE__)
101
    this_data = File.binread(__FILE__)
102
    range = nil
103
    bug2593 = '[ruby-dev:40030]'
104

  
105
    TestWEBrick.start_httpserver(config) do |server, addr, port, log|
106
      http = Net::HTTP.new(addr, port)
107
      req = Net::HTTP::Get.new("/")
108
      http.request(req){|res|
109
        assert_equal("200", res.code, log.call)
110
        assert_equal("text/html", res.content_type, log.call)
111
        assert_match(/HREF="#{this_file}"/, res.body, log.call)
112
      }
113
      req = Net::HTTP::Get.new("/#{this_file}")
114
      http.request(req){|res|
115
        assert_equal("200", res.code, log.call)
116
        assert_equal("text/plain", res.content_type, log.call)
117
        assert_equal(this_data, res.body, log.call)
118
      }
119

  
120
      req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=#{filesize-100}-")
121
      http.request(req){|res|
122
        assert_equal("206", res.code, log.call)
123
        assert_equal("text/plain", res.content_type, log.call)
124
        assert_nothing_raised(bug2593) {range = res.content_range}
125
        assert_equal((filesize-100)..(filesize-1), range, log.call)
126
        assert_equal(this_data[-100..-1], res.body, log.call)
127
      }
128

  
129
      req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=-100")
130
      http.request(req){|res|
131
        assert_equal("206", res.code, log.call)
132
        assert_equal("text/plain", res.content_type, log.call)
133
        assert_nothing_raised(bug2593) {range = res.content_range}
134
        assert_equal((filesize-100)..(filesize-1), range, log.call)
135
        assert_equal(this_data[-100..-1], res.body, log.call)
136
      }
137

  
138
      req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=0-99")
139
      http.request(req){|res|
140
        assert_equal("206", res.code, log.call)
141
        assert_equal("text/plain", res.content_type, log.call)
142
        assert_nothing_raised(bug2593) {range = res.content_range}
143
        assert_equal(0..99, range, log.call)
144
        assert_equal(this_data[0..99], res.body, log.call)
145
      }
146

  
147
      req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=100-199")
148
      http.request(req){|res|
149
        assert_equal("206", res.code, log.call)
150
        assert_equal("text/plain", res.content_type, log.call)
151
        assert_nothing_raised(bug2593) {range = res.content_range}
152
        assert_equal(100..199, range, log.call)
153
        assert_equal(this_data[100..199], res.body, log.call)
154
      }
155

  
156
      req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=0-0")
157
      http.request(req){|res|
158
        assert_equal("206", res.code, log.call)
159
        assert_equal("text/plain", res.content_type, log.call)
160
        assert_nothing_raised(bug2593) {range = res.content_range}
161
        assert_equal(0..0, range, log.call)
162
        assert_equal(this_data[0..0], res.body, log.call)
163
      }
164

  
165
      req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=-1")
166
      http.request(req){|res|
167
        assert_equal("206", res.code, log.call)
168
        assert_equal("text/plain", res.content_type, log.call)
169
        assert_nothing_raised(bug2593) {range = res.content_range}
170
        assert_equal((filesize-1)..(filesize-1), range, log.call)
171
        assert_equal(this_data[-1, 1], res.body, log.call)
172
      }
173

  
174
      req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=0-0, -2")
175
      http.request(req){|res|
176
        assert_equal("206", res.code, log.call)
177
        assert_equal("multipart/byteranges", res.content_type, log.call)
178
      }
179

  
180
    end
181
  end
182

  
183
  def test_non_disclosure_name
184
    config = { :DocumentRoot => File.dirname(__FILE__), }
185
    log_tester = lambda {|log, access_log|
186
      log = log.reject {|s| /ERROR `.*\' not found\./ =~ s }
187
      log = log.reject {|s| /WARN  the request refers nondisclosure name/ =~ s }
188
      assert_equal([], log)
189
    }
190
    this_file = File.basename(__FILE__)
191
    TestWEBrick.start_httpserver(config, log_tester) do |server, addr, port, log|
192
      http = Net::HTTP.new(addr, port)
193
      doc_root_opts = server[:DocumentRootOptions]
194
      doc_root_opts[:NondisclosureName] = %w(.ht* *~ test_*)
195
      req = Net::HTTP::Get.new("/")
196
      http.request(req){|res|
197
        assert_equal("200", res.code, log.call)
198
        assert_equal("text/html", res.content_type, log.call)
199
        assert_no_match(/HREF="#{File.basename(__FILE__)}"/, res.body)
200
      }
201
      req = Net::HTTP::Get.new("/#{this_file}")
202
      http.request(req){|res|
203
        assert_equal("404", res.code, log.call)
204
      }
205
      doc_root_opts[:NondisclosureName] = %w(.ht* *~ TEST_*)
206
      http.request(req){|res|
207
        assert_equal("404", res.code, log.call)
208
      }
209
    end
210
  end
211

  
212
  def test_directory_traversal
213
    return if File.executable?(__FILE__) # skip on strange file system
214

  
215
    config = { :DocumentRoot => File.dirname(__FILE__), }
216
    log_tester = lambda {|log, access_log|
217
      log = log.reject {|s| /ERROR bad URI/ =~ s }
218
      log = log.reject {|s| /ERROR `.*\' not found\./ =~ s }
219
      assert_equal([], log)
220
    }
221
    TestWEBrick.start_httpserver(config, log_tester) do |server, addr, port, log|
222
      http = Net::HTTP.new(addr, port)
223
      req = Net::HTTP::Get.new("/../../")
224
      http.request(req){|res| assert_equal("400", res.code, log.call) }
225
      req = Net::HTTP::Get.new("/..%5c../#{File.basename(__FILE__)}")
226
      http.request(req){|res| assert_equal(windows? ? "200" : "404", res.code, log.call) }
227
      req = Net::HTTP::Get.new("/..%5c..%5cruby.c")
228
      http.request(req){|res| assert_equal("404", res.code, log.call) }
229
    end
230
  end
231

  
232
  def test_unwise_in_path
233
    if windows?
234
      config = { :DocumentRoot => File.dirname(__FILE__), }
235
      TestWEBrick.start_httpserver(config) do |server, addr, port, log|
236
        http = Net::HTTP.new(addr, port)
237
        req = Net::HTTP::Get.new("/..%5c..")
238
        http.request(req){|res| assert_equal("301", res.code, log.call) }
239
      end
240
    end
241
  end
242

  
243
  def test_short_filename
244
    return if File.executable?(__FILE__) # skip on strange file system
245

  
246
    config = {
247
      :CGIInterpreter => TestWEBrick::RubyBin,
248
      :DocumentRoot => File.dirname(__FILE__),
249
      :CGIPathEnv => ENV['PATH'],
250
    }
251
    log_tester = lambda {|log, access_log|
252
      log = log.reject {|s| /ERROR `.*\' not found\./ =~ s }
253
      log = log.reject {|s| /WARN  the request refers nondisclosure name/ =~ s }
254
      assert_equal([], log)
255
    }
256
    TestWEBrick.start_httpserver(config, log_tester) do |server, addr, port, log|
257
      http = Net::HTTP.new(addr, port)
258
      if windows?
259
        root = config[:DocumentRoot].tr("/", "\\")
260
        fname = IO.popen(%W[dir /x #{root}\\webrick_long_filename.cgi], &:read)
261
        fname.sub!(/\A.*$^$.*$^$/m, '')
262
        if fname
263
          fname = fname[/\s(w.+?cgi)\s/i, 1]
264
          fname.downcase!
265
        end
266
      else
267
        fname = "webric~1.cgi"
268
      end
269
      req = Net::HTTP::Get.new("/#{fname}/test")
270
      http.request(req) do |res|
271
        if windows?
272
          assert_equal("200", res.code, log.call)
273
          assert_equal("/test", res.body, log.call)
274
        else
275
          assert_equal("404", res.code, log.call)
276
        end
277
      end
278

  
279
      req = Net::HTTP::Get.new("/.htaccess")
280
      http.request(req) {|res| assert_equal("404", res.code, log.call) }
281
      req = Net::HTTP::Get.new("/htacce~1")
282
      http.request(req) {|res| assert_equal("404", res.code, log.call) }
283
      req = Net::HTTP::Get.new("/HTACCE~1")
284
      http.request(req) {|res| assert_equal("404", res.code, log.call) }
285
    end
286
  end
287

  
288
  def test_script_disclosure
289
    return if File.executable?(__FILE__) # skip on strange file system
290

  
291
    config = {
292
      :CGIInterpreter => TestWEBrick::RubyBin,
293
      :DocumentRoot => File.dirname(__FILE__),
294
      :CGIPathEnv => ENV['PATH'],
295
      :RequestCallback => Proc.new{|req, res|
296
        def req.meta_vars
297
          meta = super
298
          meta["RUBYLIB"] = $:.join(File::PATH_SEPARATOR)
299
          meta[RbConfig::CONFIG['LIBPATHENV']] = ENV[RbConfig::CONFIG['LIBPATHENV']] if RbConfig::CONFIG['LIBPATHENV']
300
          return meta
301
        end
302
      },
303
    }
304
    log_tester = lambda {|log, access_log|
305
      log = log.reject {|s| /ERROR `.*\' not found\./ =~ s }
306
      assert_equal([], log)
307
    }
308
    TestWEBrick.start_httpserver(config, log_tester) do |server, addr, port, log|
309
      http = Net::HTTP.new(addr, port)
310

  
311
      req = Net::HTTP::Get.new("/webrick.cgi/test")
312
      http.request(req) do |res|
313
        assert_equal("200", res.code, log.call)
314
        assert_equal("/test", res.body, log.call)
315
      end
316

  
317
      resok = windows?
318
      response_assertion = Proc.new do |res|
319
        if resok
320
          assert_equal("200", res.code, log.call)
321
          assert_equal("/test", res.body, log.call)
322
        else
323
          assert_equal("404", res.code, log.call)
324
        end
325
      end
326
      req = Net::HTTP::Get.new("/webrick.cgi%20/test")
327
      http.request(req, &response_assertion)
328
      req = Net::HTTP::Get.new("/webrick.cgi./test")
329
      http.request(req, &response_assertion)
330
      resok &&= File.exist?(__FILE__+"::$DATA")
331
      req = Net::HTTP::Get.new("/webrick.cgi::$DATA/test")
332
      http.request(req, &response_assertion)
333
    end
334
  end
335

  
336
  def test_erbhandler
337
    config = { :DocumentRoot => File.dirname(__FILE__) }
338
    log_tester = lambda {|log, access_log|
339
      log = log.reject {|s| /ERROR `.*\' not found\./ =~ s }
340
      assert_equal([], log)
341
    }
342
    TestWEBrick.start_httpserver(config, log_tester) do |server, addr, port, log|
343
      http = Net::HTTP.new(addr, port)
344
      req = Net::HTTP::Get.new("/webrick.rhtml")
345
      http.request(req) do |res|
346
        assert_equal("200", res.code, log.call)
347
        assert_match %r!\Areq to http://[^/]+/webrick\.rhtml {}\n!, res.body
348
      end
349
    end
350
  end
351
end
/dev/null
1
require "tempfile"
2
require "test/unit"
3
require "webrick/httpauth/htgroup"
4

  
5
class TestHtgroup < Test::Unit::TestCase
6
  def test_htgroup
7
    Tempfile.create('test_htgroup') do |tmpfile|
8
      tmpfile.close
9
      tmp_group = WEBrick::HTTPAuth::Htgroup.new(tmpfile.path)
10
      tmp_group.add 'superheroes', %w[spiderman batman]
11
      tmp_group.add 'supervillains', %w[joker]
12
      tmp_group.flush
13

  
14
      htgroup = WEBrick::HTTPAuth::Htgroup.new(tmpfile.path)
15
      assert_equal(htgroup.members('superheroes'), %w[spiderman batman])
16
      assert_equal(htgroup.members('supervillains'), %w[joker])
17
    end
18
  end
19
end
/dev/null
1
# frozen_string_literal: false
2
require "test/unit"
3
require "webrick/htmlutils"
4

  
5
class TestWEBrickHTMLUtils < Test::Unit::TestCase
6
  include WEBrick::HTMLUtils
7

  
8
  def test_escape
9
    assert_equal("foo", escape("foo"))
10
    assert_equal("foo bar", escape("foo bar"))
11
    assert_equal("foo&amp;bar", escape("foo&bar"))
12
    assert_equal("foo&quot;bar", escape("foo\"bar"))
13
    assert_equal("foo&gt;bar", escape("foo>bar"))
14
    assert_equal("foo&lt;bar", escape("foo<bar"))
15
    assert_equal("\u{3053 3093 306B 3061 306F}", escape("\u{3053 3093 306B 3061 306F}"))
16
    bug8425 = '[Bug #8425] [ruby-core:55052]'
17
    assert_nothing_raised(ArgumentError, Encoding::CompatibilityError, bug8425) {
18
      assert_equal("\u{3053 3093 306B}\xff&lt;", escape("\u{3053 3093 306B}\xff<"))
19
    }
20
  end
21
end
/dev/null
1
# frozen_string_literal: false
2
require "test/unit"
3
require "net/http"
4
require "tempfile"
5
require "webrick"
6
require "webrick/httpauth/basicauth"
7
require "stringio"
8
require_relative "utils"
9

  
10
class TestWEBrickHTTPAuth < Test::Unit::TestCase
11
  def teardown
12
    WEBrick::Utils::TimeoutHandler.terminate
13
    super
14
  end
15

  
16
  def test_basic_auth
17
    log_tester = lambda {|log, access_log|
18
      assert_equal(1, log.length)
19
      assert_match(/ERROR WEBrick::HTTPStatus::Unauthorized/, log[0])
20
    }
21
    TestWEBrick.start_httpserver({}, log_tester) {|server, addr, port, log|
22
      realm = "WEBrick's realm"
23
      path = "/basic_auth"
24

  
25
      server.mount_proc(path){|req, res|
26
        WEBrick::HTTPAuth.basic_auth(req, res, realm){|user, pass|
27
          user == "webrick" && pass == "supersecretpassword"
28
        }
29
        res.body = "hoge"
30
      }
31
      http = Net::HTTP.new(addr, port)
32
      g = Net::HTTP::Get.new(path)
33
      g.basic_auth("webrick", "supersecretpassword")
34
      http.request(g){|res| assert_equal("hoge", res.body, log.call)}
35
      g.basic_auth("webrick", "not super")
36
      http.request(g){|res| assert_not_equal("hoge", res.body, log.call)}
37
    }
38
  end
39

  
40
  def test_basic_auth_sha
41
    Tempfile.create("test_webrick_auth") {|tmpfile|
42
      tmpfile.puts("webrick:{SHA}GJYFRpBbdchp595jlh3Bhfmgp8k=")
43
      tmpfile.flush
44
      assert_raise(NotImplementedError){
45
        WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path)
46
      }
47
    }
48
  end
49

  
50
  def test_basic_auth_md5
51
    Tempfile.create("test_webrick_auth") {|tmpfile|
52
      tmpfile.puts("webrick:$apr1$IOVMD/..$rmnOSPXr0.wwrLPZHBQZy0")
53
      tmpfile.flush
54
      assert_raise(NotImplementedError){
55
        WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path)
56
      }
57
    }
58
  end
59

  
60
  [nil, :crypt, :bcrypt].each do |hash_algo|
61
    begin
62
      case hash_algo
63
      when :crypt
64
        # require 'string/crypt'
65
      when :bcrypt
66
        require 'bcrypt'
67
      end
68
    rescue LoadError
69
      next
70
    end
71

  
72
    define_method(:"test_basic_auth_htpasswd_#{hash_algo}") do
73
      log_tester = lambda {|log, access_log|
74
        log.reject! {|line| /\A\s*\z/ =~ line }
75
        pats = [
76
          /ERROR Basic WEBrick's realm: webrick: password unmatch\./,
77
          /ERROR WEBrick::HTTPStatus::Unauthorized/
78
        ]
79
        pats.each {|pat|
80
          assert(!log.grep(pat).empty?, "webrick log doesn't have expected error: #{pat.inspect}")
81
          log.reject! {|line| pat =~ line }
82
        }
83
        assert_equal([], log)
84
      }
85
      TestWEBrick.start_httpserver({}, log_tester) {|server, addr, port, log|
86
        realm = "WEBrick's realm"
87
        path = "/basic_auth2"
88

  
89
        Tempfile.create("test_webrick_auth") {|tmpfile|
90
          tmpfile.close
91
          tmp_pass = WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path, password_hash: hash_algo)
92
          tmp_pass.set_passwd(realm, "webrick", "supersecretpassword")
93
          tmp_pass.set_passwd(realm, "foo", "supersecretpassword")
94
          tmp_pass.flush
95

  
96
          htpasswd = WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path, password_hash: hash_algo)
97
          users = []
98
          htpasswd.each{|user, pass| users << user }
99
          assert_equal(2, users.size, log.call)
100
          assert(users.member?("webrick"), log.call)
101
          assert(users.member?("foo"), log.call)
102

  
103
          server.mount_proc(path){|req, res|
104
            auth = WEBrick::HTTPAuth::BasicAuth.new(
105
              :Realm => realm, :UserDB => htpasswd,
106
              :Logger => server.logger
107
            )
108
            auth.authenticate(req, res)
109
            res.body = "hoge"
110
          }
111
          http = Net::HTTP.new(addr, port)
112
          g = Net::HTTP::Get.new(path)
113
          g.basic_auth("webrick", "supersecretpassword")
114
          http.request(g){|res| assert_equal("hoge", res.body, log.call)}
115
          g.basic_auth("webrick", "not super")
116
          http.request(g){|res| assert_not_equal("hoge", res.body, log.call)}
117
        }
118
      }
119
    end
120

  
121
    define_method(:"test_basic_auth_bad_username_htpasswd_#{hash_algo}") do
122
      log_tester = lambda {|log, access_log|
123
        assert_equal(2, log.length)
124
        assert_match(/ERROR Basic WEBrick's realm: foo\\ebar: the user is not allowed\./, log[0])
125
        assert_match(/ERROR WEBrick::HTTPStatus::Unauthorized/, log[1])
126
      }
127
      TestWEBrick.start_httpserver({}, log_tester) {|server, addr, port, log|
128
        realm = "WEBrick's realm"
129
        path = "/basic_auth"
130

  
131
        Tempfile.create("test_webrick_auth") {|tmpfile|
132
          tmpfile.close
133
          tmp_pass = WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path, password_hash: hash_algo)
134
          tmp_pass.set_passwd(realm, "webrick", "supersecretpassword")
135
          tmp_pass.set_passwd(realm, "foo", "supersecretpassword")
136
          tmp_pass.flush
137

  
138
          htpasswd = WEBrick::HTTPAuth::Htpasswd.new(tmpfile.path, password_hash: hash_algo)
139
          users = []
140
          htpasswd.each{|user, pass| users << user }
141
          server.mount_proc(path){|req, res|
142
            auth = WEBrick::HTTPAuth::BasicAuth.new(
143
              :Realm => realm, :UserDB => htpasswd,
144
              :Logger => server.logger
145
            )
146
            auth.authenticate(req, res)
147
            res.body = "hoge"
148
          }
149
          http = Net::HTTP.new(addr, port)
150
          g = Net::HTTP::Get.new(path)
151
          g.basic_auth("foo\ebar", "passwd")
152
          http.request(g){|res| assert_not_equal("hoge", res.body, log.call) }
153
        }
154
      }
155
    end
156
  end
157

  
158
  DIGESTRES_ = /
159
    ([a-zA-Z\-]+)
160
      [ \t]*(?:\r\n[ \t]*)*
161
      =
162
      [ \t]*(?:\r\n[ \t]*)*
163
      (?:
164
       "((?:[^"]+|\\[\x00-\x7F])*)" |
165
       ([!\#$%&'*+\-.0-9A-Z^_`a-z|~]+)
166
      )/x
167

  
168
  def test_digest_auth
169
    log_tester = lambda {|log, access_log|
170
      log.reject! {|line| /\A\s*\z/ =~ line }
171
      pats = [
172
        /ERROR Digest WEBrick's realm: no credentials in the request\./,
173
        /ERROR WEBrick::HTTPStatus::Unauthorized/,
174
        /ERROR Digest WEBrick's realm: webrick: digest unmatch\./
175
      ]
176
      pats.each {|pat|
177
        assert(!log.grep(pat).empty?, "webrick log doesn't have expected error: #{pat.inspect}")
178
        log.reject! {|line| pat =~ line }
179
      }
180
      assert_equal([], log)
181
    }
182
    TestWEBrick.start_httpserver({}, log_tester) {|server, addr, port, log|
183
      realm = "WEBrick's realm"
184
      path = "/digest_auth"
185

  
186
      Tempfile.create("test_webrick_auth") {|tmpfile|
187
        tmpfile.close
188
        tmp_pass = WEBrick::HTTPAuth::Htdigest.new(tmpfile.path)
189
        tmp_pass.set_passwd(realm, "webrick", "supersecretpassword")
190
        tmp_pass.set_passwd(realm, "foo", "supersecretpassword")
191
        tmp_pass.flush
192

  
193
        htdigest = WEBrick::HTTPAuth::Htdigest.new(tmpfile.path)
194
        users = []
195
        htdigest.each{|user, pass| users << user }
196
        assert_equal(2, users.size, log.call)
197
        assert(users.member?("webrick"), log.call)
198
        assert(users.member?("foo"), log.call)
199

  
200
        auth = WEBrick::HTTPAuth::DigestAuth.new(
201
          :Realm => realm, :UserDB => htdigest,
202
          :Algorithm => 'MD5',
203
          :Logger => server.logger
204
        )
205
        server.mount_proc(path){|req, res|
206
          auth.authenticate(req, res)
207
          res.body = "hoge"
208
        }
209

  
210
        Net::HTTP.start(addr, port) do |http|
211
          g = Net::HTTP::Get.new(path)
212
          params = {}
213
          http.request(g) do |res|
214
            assert_equal('401', res.code, log.call)
215
            res["www-authenticate"].scan(DIGESTRES_) do |key, quoted, token|
216
              params[key.downcase] = token || quoted.delete('\\')
217
            end
218
             params['uri'] = "http://#{addr}:#{port}#{path}"
219
          end
220

  
221
          g['Authorization'] = credentials_for_request('webrick', "supersecretpassword", params)
222
          http.request(g){|res| assert_equal("hoge", res.body, log.call)}
223

  
224
          params['algorithm'].downcase! #4936
225
          g['Authorization'] = credentials_for_request('webrick', "supersecretpassword", params)
226
          http.request(g){|res| assert_equal("hoge", res.body, log.call)}
227

  
228
          g['Authorization'] = credentials_for_request('webrick', "not super", params)
229
          http.request(g){|res| assert_not_equal("hoge", res.body, log.call)}
230
        end
231
      }
232
    }
233
  end
234

  
235
  def test_digest_auth_int
236
    log_tester = lambda {|log, access_log|
237
      log.reject! {|line| /\A\s*\z/ =~ line }
238
      pats = [
239
        /ERROR Digest wb auth-int realm: no credentials in the request\./,
240
        /ERROR WEBrick::HTTPStatus::Unauthorized/,
241
        /ERROR Digest wb auth-int realm: foo: digest unmatch\./
242
      ]
243
      pats.each {|pat|
244
        assert(!log.grep(pat).empty?, "webrick log doesn't have expected error: #{pat.inspect}")
245
        log.reject! {|line| pat =~ line }
246
      }
247
      assert_equal([], log)
248
    }
249
    TestWEBrick.start_httpserver({}, log_tester) {|server, addr, port, log|
250
      realm = "wb auth-int realm"
251
      path = "/digest_auth_int"
252

  
253
      Tempfile.create("test_webrick_auth_int") {|tmpfile|
254
        tmpfile.close
255
        tmp_pass = WEBrick::HTTPAuth::Htdigest.new(tmpfile.path)
256
        tmp_pass.set_passwd(realm, "foo", "Hunter2")
257
        tmp_pass.flush
258

  
259
        htdigest = WEBrick::HTTPAuth::Htdigest.new(tmpfile.path)
260
        users = []
261
        htdigest.each{|user, pass| users << user }
262
        assert_equal %w(foo), users
263

  
264
        auth = WEBrick::HTTPAuth::DigestAuth.new(
265
          :Realm => realm, :UserDB => htdigest,
266
          :Algorithm => 'MD5',
267
          :Logger => server.logger,
268
          :Qop => %w(auth-int),
269
        )
270
        server.mount_proc(path){|req, res|
271
          auth.authenticate(req, res)
272
          res.body = "bbb"
273
        }
274
        Net::HTTP.start(addr, port) do |http|
275
          post = Net::HTTP::Post.new(path)
276
          params = {}
277
          data = 'hello=world'
278
          body = StringIO.new(data)
279
          post.content_length = data.bytesize
280
          post['Content-Type'] = 'application/x-www-form-urlencoded'
281
          post.body_stream = body
282

  
283
          http.request(post) do |res|
284
            assert_equal('401', res.code, log.call)
285
            res["www-authenticate"].scan(DIGESTRES_) do |key, quoted, token|
286
              params[key.downcase] = token || quoted.delete('\\')
287
            end
288
             params['uri'] = "http://#{addr}:#{port}#{path}"
289
          end
290

  
291
          body.rewind
292
          cred = credentials_for_request('foo', 'Hunter3', params, body)
293
          post['Authorization'] = cred
294
          post.body_stream = body
295
          http.request(post){|res|
296
            assert_equal('401', res.code, log.call)
297
            assert_not_equal("bbb", res.body, log.call)
298
          }
299

  
300
          body.rewind
301
          cred = credentials_for_request('foo', 'Hunter2', params, body)
302
          post['Authorization'] = cred
303
          post.body_stream = body
304
          http.request(post){|res| assert_equal("bbb", res.body, log.call)}
305
        end
306
      }
307
    }
308
  end
309

  
310
  private
311
  def credentials_for_request(user, password, params, body = nil)
312
    cnonce = "hoge"
313
    nonce_count = 1
314
    ha1 = "#{user}:#{params['realm']}:#{password}"
315
    if body
316
      dig = Digest::MD5.new
317
      while buf = body.read(16384)
318
        dig.update(buf)
319
      end
320
      body.rewind
321
      ha2 = "POST:#{params['uri']}:#{dig.hexdigest}"
322
    else
323
      ha2 = "GET:#{params['uri']}"
324
    end
325

  
326
    request_digest =
327
      "#{Digest::MD5.hexdigest(ha1)}:" \
328
      "#{params['nonce']}:#{'%08x' % nonce_count}:#{cnonce}:#{params['qop']}:" \
329
      "#{Digest::MD5.hexdigest(ha2)}"
330
    "Digest username=\"#{user}\"" \
331
      ", realm=\"#{params['realm']}\"" \
332
      ", nonce=\"#{params['nonce']}\"" \
333
      ", uri=\"#{params['uri']}\"" \
334
      ", qop=#{params['qop']}" \
335
      ", nc=#{'%08x' % nonce_count}" \
336
      ", cnonce=\"#{cnonce}\"" \
337
      ", response=\"#{Digest::MD5.hexdigest(request_digest)}\"" \
338
      ", opaque=\"#{params['opaque']}\"" \
339
      ", algorithm=#{params['algorithm']}"
340
  end
341
end
/dev/null
1
# frozen_string_literal: false
2
require "test/unit"
3
require "net/http"
4
require "webrick"
5
require "webrick/httpproxy"
6
begin
7
  require "webrick/ssl"
8
  require "net/https"
9
rescue LoadError
10
  # test_connect will be skipped
11
end
12
require File.expand_path("utils.rb", File.dirname(__FILE__))
13

  
14
class TestWEBrickHTTPProxy < Test::Unit::TestCase
15
  def teardown
16
    WEBrick::Utils::TimeoutHandler.terminate
17
    super
18
  end
19

  
20
  def test_fake_proxy
21
    assert_nil(WEBrick::FakeProxyURI.scheme)
22
    assert_nil(WEBrick::FakeProxyURI.host)
23
    assert_nil(WEBrick::FakeProxyURI.port)
24
    assert_nil(WEBrick::FakeProxyURI.path)
25
    assert_nil(WEBrick::FakeProxyURI.userinfo)
26
    assert_raise(NoMethodError){ WEBrick::FakeProxyURI.foo }
27
  end
28

  
29
  def test_proxy
30
    # Testing GET or POST to the proxy server
31
    # Note that the proxy server works as the origin server.
32
    #                    +------+
33
    #                    V      |
34
    #  client -------> proxy ---+
35
    #        GET / POST     GET / POST
36
    #
37
    proxy_handler_called = request_handler_called = 0
38
    config = {
39
      :ServerName => "localhost.localdomain",
40
      :ProxyContentHandler => Proc.new{|req, res| proxy_handler_called += 1 },
41
      :RequestCallback => Proc.new{|req, res| request_handler_called += 1 }
42
    }
43
    TestWEBrick.start_httpproxy(config){|server, addr, port, log|
44
      server.mount_proc("/"){|req, res|
45
        res.body = "#{req.request_method} #{req.path} #{req.body}"
46
      }
47
      http = Net::HTTP.new(addr, port, addr, port)
48

  
49
      req = Net::HTTP::Get.new("/")
50
      http.request(req){|res|
51
        assert_equal("1.1 localhost.localdomain:#{port}", res["via"], log.call)
52
        assert_equal("GET / ", res.body, log.call)
53
      }
54
      assert_equal(1, proxy_handler_called, log.call)
55
      assert_equal(2, request_handler_called, log.call)
56

  
57
      req = Net::HTTP::Head.new("/")
58
      http.request(req){|res|
59
        assert_equal("1.1 localhost.localdomain:#{port}", res["via"], log.call)
60
        assert_nil(res.body, log.call)
61
      }
62
      assert_equal(2, proxy_handler_called, log.call)
63
      assert_equal(4, request_handler_called, log.call)
64

  
65
      req = Net::HTTP::Post.new("/")
66
      req.body = "post-data"
67
      req.content_type = "application/x-www-form-urlencoded"
68
      http.request(req){|res|
69
        assert_equal("1.1 localhost.localdomain:#{port}", res["via"], log.call)
70
        assert_equal("POST / post-data", res.body, log.call)
71
      }
72
      assert_equal(3, proxy_handler_called, log.call)
73
      assert_equal(6, request_handler_called, log.call)
74
    }
75
  end
76

  
77
  def test_no_proxy
78
    # Testing GET or POST to the proxy server without proxy request.
79
    #
80
    #  client -------> proxy
81
    #        GET / POST
82
    #
83
    proxy_handler_called = request_handler_called = 0
84
    config = {
85
      :ServerName => "localhost.localdomain",
86
      :ProxyContentHandler => Proc.new{|req, res| proxy_handler_called += 1 },
87
      :RequestCallback => Proc.new{|req, res| request_handler_called += 1 }
88
    }
89
    TestWEBrick.start_httpproxy(config){|server, addr, port, log|
90
      server.mount_proc("/"){|req, res|
91
        res.body = "#{req.request_method} #{req.path} #{req.body}"
92
      }
93
      http = Net::HTTP.new(addr, port)
94

  
95
      req = Net::HTTP::Get.new("/")
96
      http.request(req){|res|
97
        assert_nil(res["via"], log.call)
98
        assert_equal("GET / ", res.body, log.call)
99
      }
100
      assert_equal(0, proxy_handler_called, log.call)
101
      assert_equal(1, request_handler_called, log.call)
102

  
103
      req = Net::HTTP::Head.new("/")
104
      http.request(req){|res|
105
        assert_nil(res["via"], log.call)
106
        assert_nil(res.body, log.call)
107
      }
108
      assert_equal(0, proxy_handler_called, log.call)
109
      assert_equal(2, request_handler_called, log.call)
110

  
111
      req = Net::HTTP::Post.new("/")
112
      req.content_type = "application/x-www-form-urlencoded"
113
      req.body = "post-data"
114
      http.request(req){|res|
115
        assert_nil(res["via"], log.call)
116
        assert_equal("POST / post-data", res.body, log.call)
117
      }
118
      assert_equal(0, proxy_handler_called, log.call)
119
      assert_equal(3, request_handler_called, log.call)
120
    }
121
  end
122

  
123
  def test_big_bodies
124
    require 'digest/md5'
125
    rand_str = File.read(__FILE__)
126
    rand_str.freeze
127
    nr = 1024 ** 2 / rand_str.size # bigger works, too
128
    exp = Digest::MD5.new
129
    nr.times { exp.update(rand_str) }
130
    exp = exp.hexdigest
131
    TestWEBrick.start_httpserver do |o_server, o_addr, o_port, o_log|
132
      o_server.mount_proc('/') do |req, res|
133
        case req.request_method
134
        when 'GET'
135
          res['content-type'] = 'application/octet-stream'
136
          if req.path == '/length'
137
            res['content-length'] = (nr * rand_str.size).to_s
138
          else
139
            res.chunked = true
140
          end
141
          res.body = ->(socket) { nr.times { socket.write(rand_str) } }
142
        when 'POST'
143
          dig = Digest::MD5.new
144
          req.body { |buf| dig.update(buf); buf.clear }
145
          res['content-type'] = 'text/plain'
146
          res['content-length'] = '32'
147
          res.body = dig.hexdigest
148
        end
149
      end
150

  
151
      http = Net::HTTP.new(o_addr, o_port)
... This diff was truncated because it exceeds the maximum size that can be displayed.