request_test.rb 29.7 KB
Newer Older
1
require 'abstract_unit'
2

3
class RequestTest < ActiveSupport::TestCase
4 5 6 7 8 9 10 11 12 13 14 15 16 17

  def url_for(options = {})
    options.reverse_merge!(:host => 'www.example.com')
    ActionDispatch::Http::URL.url_for(options)
  end

  test "url_for class method" do
    e = assert_raise(ArgumentError) { url_for(:host => nil) }
    assert_match(/Please provide the :host parameter/, e.message)

    assert_equal '/books', url_for(:only_path => true, :path => '/books')

    assert_equal 'http://www.example.com',  url_for
    assert_equal 'http://api.example.com',  url_for(:subdomain => 'api')
18
    assert_equal 'http://example.com',      url_for(:subdomain => false)
19 20 21 22 23 24 25 26 27 28 29
    assert_equal 'http://www.ror.com',      url_for(:domain => 'ror.com')
    assert_equal 'http://api.ror.co.uk',    url_for(:host => 'www.ror.co.uk', :subdomain => 'api', :tld_length => 2)
    assert_equal 'http://www.example.com:8080',   url_for(:port => 8080)
    assert_equal 'https://www.example.com',       url_for(:protocol => 'https')
    assert_equal 'http://www.example.com/docs',   url_for(:path => '/docs')
    assert_equal 'http://www.example.com#signup', url_for(:anchor => 'signup')
    assert_equal 'http://www.example.com/',       url_for(:trailing_slash => true)
    assert_equal 'http://dhh:supersecret@www.example.com', url_for(:user => 'dhh', :password => 'supersecret')
    assert_equal 'http://www.example.com?search=books',    url_for(:params => { :search => 'books' })
  end

30
  test "remote ip" do
31 32
    request = stub_request 'REMOTE_ADDR' => '1.2.3.4'
    assert_equal '1.2.3.4', request.remote_ip
33

34 35
    request = stub_request 'REMOTE_ADDR' => '1.2.3.4,3.4.5.6'
    assert_equal '1.2.3.4', request.remote_ip
36

37
    request = stub_request 'REMOTE_ADDR' => '1.2.3.4',
38
                           'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
39
    assert_equal '3.4.5.6', request.remote_ip
40

41
    request = stub_request 'REMOTE_ADDR' => '127.0.0.1',
42
                           'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
43
    assert_equal '3.4.5.6', request.remote_ip
J
Jeremy Kemper 已提交
44

45
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,unknown'
46
    assert_equal '3.4.5.6', request.remote_ip
47

48
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '172.16.0.1,3.4.5.6'
49
    assert_equal nil, request.remote_ip
J
Jeremy Kemper 已提交
50

51
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,3.4.5.6'
52
    assert_equal nil, request.remote_ip
53

54
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '10.0.0.1,3.4.5.6'
55
    assert_equal nil, request.remote_ip
56

57
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '10.0.0.1, 10.0.0.1, 3.4.5.6'
58
    assert_equal nil, request.remote_ip
59

60
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '127.0.0.1,3.4.5.6'
61
    assert_equal nil, request.remote_ip
62

63
    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1'
64
    assert_equal nil, request.remote_ip
65

66
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6, 9.9.9.9, 10.0.0.1, 172.31.4.4'
67
    assert_equal '3.4.5.6', request.remote_ip
68

69 70 71
    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'not_ip_address'
    assert_equal nil, request.remote_ip

72 73
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1',
                           'HTTP_CLIENT_IP'       => '2.2.2.2'
C
Carlhuda 已提交
74
    e = assert_raise(ActionDispatch::RemoteIp::IpSpoofAttackError) {
75
      request.remote_ip
J
Jeremy Kemper 已提交
76
    }
77 78 79
    assert_match(/IP spoofing attack/, e.message)
    assert_match(/HTTP_X_FORWARDED_FOR="1.1.1.1"/, e.message)
    assert_match(/HTTP_CLIENT_IP="2.2.2.2"/, e.message)
J
Jeremy Kemper 已提交
80

81 82 83 84 85
    # turn IP Spoofing detection off.
    # This is useful for sites that are aimed at non-IP clients.  The typical
    # example is WAP.  Since the cellular network is not IP based, it's a
    # leap of faith to assume that their proxies are ever going to set the
    # HTTP_CLIENT_IP/HTTP_X_FORWARDED_FOR headers properly.
86
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1',
C
Carlhuda 已提交
87 88
                           'HTTP_CLIENT_IP'       => '2.2.2.2',
                           :ip_spoofing_check => false
89
    assert_equal '2.2.2.2', request.remote_ip
90

91
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 8.8.8.8'
92
    assert_equal '9.9.9.9', request.remote_ip
93 94
  end

95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
  test "remote ip v6" do
    request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334'
    assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip

    request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334,fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
    assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip

    request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
                           'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
    assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip

    request = stub_request 'REMOTE_ADDR' => '::1',
                           'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
    assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip

    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
    assert_equal nil, request.remote_ip

    request = stub_request 'HTTP_X_FORWARDED_FOR' => '::1,fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
    assert_equal nil, request.remote_ip

    request = stub_request 'HTTP_X_FORWARDED_FOR' => '::1,fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
    assert_equal nil, request.remote_ip

    request = stub_request 'HTTP_X_FORWARDED_FOR' => '::1,fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
    assert_equal nil, request.remote_ip

    request = stub_request 'HTTP_X_FORWARDED_FOR' => '::1, ::1, fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
    assert_equal nil, request.remote_ip

    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,::1'
    assert_equal nil, request.remote_ip

    request = stub_request 'HTTP_X_FORWARDED_FOR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334, fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, fc00::'
    assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip

    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'not_ip_address'
    assert_equal nil, request.remote_ip

    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329',
                           'HTTP_CLIENT_IP'       => '2001:0db8:85a3:0000:0000:8a2e:0370:7334'
    e = assert_raise(ActionDispatch::RemoteIp::IpSpoofAttackError) {
      request.remote_ip
    }
    assert_match(/IP spoofing attack/, e.message)
    assert_match(/HTTP_X_FORWARDED_FOR="fe80:0000:0000:0000:0202:b3ff:fe1e:8329"/, e.message)
    assert_match(/HTTP_CLIENT_IP="2001:0db8:85a3:0000:0000:8a2e:0370:7334"/, e.message)

    # Turn IP Spoofing detection off.
    # This is useful for sites that are aimed at non-IP clients.  The typical
    # example is WAP.  Since the cellular network is not IP based, it's a
    # leap of faith to assume that their proxies are ever going to set the
    # HTTP_CLIENT_IP/HTTP_X_FORWARDED_FOR headers properly.
    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329',
                           'HTTP_CLIENT_IP'       => '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
                           :ip_spoofing_check     => false
    assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip

    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329, 2001:0db8:85a3:0000:0000:8a2e:0370:7334'
    assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip
  end

A
Andre Arko 已提交
157 158 159 160 161
  test "remote ip when the remote ip middleware returns nil" do
    request = stub_request 'REMOTE_ADDR' => '127.0.0.1'
    assert_equal '127.0.0.1', request.remote_ip
  end

162 163
  test "remote ip with user specified trusted proxies String" do
    @trusted_proxies = "67.205.106.73"
164

165 166
    request = stub_request 'REMOTE_ADDR' => '3.4.5.6',
                           'HTTP_X_FORWARDED_FOR' => '67.205.106.73'
167 168 169
    assert_equal '3.4.5.6', request.remote_ip

    request = stub_request 'REMOTE_ADDR' => '172.16.0.1,67.205.106.73',
170 171
                           'HTTP_X_FORWARDED_FOR' => '67.205.106.73'
    assert_equal '172.16.0.1', request.remote_ip
172

173 174
    request = stub_request 'REMOTE_ADDR' => '67.205.106.73,3.4.5.6',
                           'HTTP_X_FORWARDED_FOR' => '67.205.106.73'
175
    assert_equal '3.4.5.6', request.remote_ip
176 177

    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,67.205.106.73'
178
    assert_equal nil, request.remote_ip
179

180
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6, 9.9.9.9, 10.0.0.1, 67.205.106.73'
181 182 183
    assert_equal '3.4.5.6', request.remote_ip
  end

184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
  test "remote ip v6 with user specified trusted proxies String" do
    @trusted_proxies = 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329'

    request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
                           'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
    assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip

    request = stub_request 'REMOTE_ADDR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334',
                           'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
    assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip

    request = stub_request 'REMOTE_ADDR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,::1',
                           'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
    assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip

    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
    assert_equal nil, request.remote_ip

    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334'
    assert_equal nil, request.remote_ip
  end

206 207 208 209 210 211 212
  test "remote ip with user specified trusted proxies Regexp" do
    @trusted_proxies = /^67\.205\.106\.73$/i

    request = stub_request 'REMOTE_ADDR' => '67.205.106.73',
                           'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
    assert_equal '3.4.5.6', request.remote_ip

213
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '67.205.106.73, 10.0.0.1, 9.9.9.9, 3.4.5.6'
214 215 216 217 218 219 220 221 222 223 224 225
    assert_equal nil, request.remote_ip
  end

  test "remote ip v6 with user specified trusted proxies Regexp" do
    @trusted_proxies = /^fe80:0000:0000:0000:0202:b3ff:fe1e:8329$/i

    request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
                           'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
    assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip

    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329, 2001:0db8:85a3:0000:0000:8a2e:0370:7334'
    assert_equal nil, request.remote_ip
226 227
  end

228
  test "domains" do
229 230
    request = stub_request 'HTTP_HOST' => 'www.rubyonrails.org'
    assert_equal "rubyonrails.org", request.domain
231

232 233
    request = stub_request 'HTTP_HOST' => "www.rubyonrails.co.uk"
    assert_equal "rubyonrails.co.uk", request.domain(2)
234

235 236 237
    request = stub_request 'HTTP_HOST' => "www.rubyonrails.co.uk", :tld_length => 2
    assert_equal "rubyonrails.co.uk", request.domain

238 239
    request = stub_request 'HTTP_HOST' => "192.168.1.200"
    assert_nil request.domain
240

241 242
    request = stub_request 'HTTP_HOST' => "foo.192.168.1.200"
    assert_nil request.domain
243

244 245
    request = stub_request 'HTTP_HOST' => "192.168.1.200.com"
    assert_equal "200.com", request.domain
246 247
  end

248
  test "subdomains" do
249 250
    request = stub_request 'HTTP_HOST' => "www.rubyonrails.org"
    assert_equal %w( www ), request.subdomains
J
José Valim 已提交
251
    assert_equal "www", request.subdomain
252

253 254
    request = stub_request 'HTTP_HOST' => "www.rubyonrails.co.uk"
    assert_equal %w( www ), request.subdomains(2)
J
José Valim 已提交
255
    assert_equal "www", request.subdomain(2)
256

257 258
    request = stub_request 'HTTP_HOST' => "dev.www.rubyonrails.co.uk"
    assert_equal %w( dev www ), request.subdomains(2)
J
José Valim 已提交
259
    assert_equal "dev.www", request.subdomain(2)
260

261 262
    request = stub_request 'HTTP_HOST' => "dev.www.rubyonrails.co.uk", :tld_length => 2
    assert_equal %w( dev www ), request.subdomains
J
José Valim 已提交
263
    assert_equal "dev.www", request.subdomain
264

265 266
    request = stub_request 'HTTP_HOST' => "foobar.foobar.com"
    assert_equal %w( foobar ), request.subdomains
J
José Valim 已提交
267
    assert_equal "foobar", request.subdomain
268

269 270
    request = stub_request 'HTTP_HOST' => "192.168.1.200"
    assert_equal [], request.subdomains
J
José Valim 已提交
271
    assert_equal "", request.subdomain
272

273 274
    request = stub_request 'HTTP_HOST' => "foo.192.168.1.200"
    assert_equal [], request.subdomains
J
José Valim 已提交
275
    assert_equal "", request.subdomain
276

277 278
    request = stub_request 'HTTP_HOST' => "192.168.1.200.com"
    assert_equal %w( 192 168 1 ), request.subdomains
J
José Valim 已提交
279
    assert_equal "192.168.1", request.subdomain
280

281 282
    request = stub_request 'HTTP_HOST' => nil
    assert_equal [], request.subdomains
J
José Valim 已提交
283
    assert_equal "", request.subdomain
284
  end
285

286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
  test "standard_port" do
    request = stub_request
    assert_equal 80, request.standard_port

    request = stub_request 'HTTPS' => 'on'
    assert_equal 443, request.standard_port
  end

  test "standard_port?" do
    request = stub_request
    assert !request.ssl?
    assert request.standard_port?

    request = stub_request 'HTTPS' => 'on'
    assert request.ssl?
    assert request.standard_port?

    request = stub_request 'HTTP_HOST' => 'www.example.org:8080'
    assert !request.ssl?
    assert !request.standard_port?

    request = stub_request 'HTTP_HOST' => 'www.example.org:8443', 'HTTPS' => 'on'
    assert request.ssl?
    assert !request.standard_port?
  end

312
  test "optional port" do
313
    request = stub_request 'HTTP_HOST' => 'www.example.org:80'
314
    assert_equal nil, request.optional_port
315

316
    request = stub_request 'HTTP_HOST' => 'www.example.org:8080'
317
    assert_equal 8080, request.optional_port
318
  end
319

320 321 322 323 324 325 326 327
  test "port string" do
    request = stub_request 'HTTP_HOST' => 'www.example.org:80'
    assert_equal '', request.port_string

    request = stub_request 'HTTP_HOST' => 'www.example.org:8080'
    assert_equal ':8080', request.port_string
  end

328
  test "full path" do
329
    request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/path/of/some/uri', 'QUERY_STRING' => 'mapped=1'
330 331
    assert_equal "/path/of/some/uri?mapped=1", request.fullpath
    assert_equal "/path/of/some/uri",          request.path_info
332

333
    request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/path/of/some/uri'
334 335
    assert_equal "/path/of/some/uri", request.fullpath
    assert_equal "/path/of/some/uri", request.path_info
336

337
    request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/'
338 339
    assert_equal "/", request.fullpath
    assert_equal "/", request.path_info
340

341
    request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/', 'QUERY_STRING' => 'm=b'
342 343
    assert_equal "/?m=b", request.fullpath
    assert_equal "/",     request.path_info
344

345
    request = stub_request 'SCRIPT_NAME' => '/hieraki', 'PATH_INFO' => '/'
346 347
    assert_equal "/hieraki/", request.fullpath
    assert_equal "/",         request.path_info
348

349
    request = stub_request 'SCRIPT_NAME' => '/collaboration/hieraki', 'PATH_INFO' => '/books/edit/2'
350 351
    assert_equal "/collaboration/hieraki/books/edit/2", request.fullpath
    assert_equal "/books/edit/2",                       request.path_info
352

353
    request = stub_request 'SCRIPT_NAME' => '/path', 'PATH_INFO' => '/of/some/uri', 'QUERY_STRING' => 'mapped=1'
354 355
    assert_equal "/path/of/some/uri?mapped=1", request.fullpath
    assert_equal "/of/some/uri",               request.path_info
356
  end
357

358

359
  test "host with default port" do
360 361
    request = stub_request 'HTTP_HOST' => 'rubyonrails.org:80'
    assert_equal "rubyonrails.org", request.host_with_port
362
  end
363

364
  test "host with non default port" do
365 366
    request = stub_request 'HTTP_HOST' => 'rubyonrails.org:81'
    assert_equal "rubyonrails.org:81", request.host_with_port
367
  end
368

369
  test "server software" do
370 371
    request = stub_request
    assert_equal nil, request.server_software
372

373 374
    request = stub_request 'SERVER_SOFTWARE' => 'Apache3.422'
    assert_equal 'apache', request.server_software
375

376 377
    request = stub_request 'SERVER_SOFTWARE' => 'lighttpd(1.1.4)'
    assert_equal 'lighttpd', request.server_software
378
  end
379

380
  test "xml http request" do
381 382 383 384
    request = stub_request

    assert !request.xml_http_request?
    assert !request.xhr?
385

386 387 388
    request = stub_request 'HTTP_X_REQUESTED_WITH' => 'DefinitelyNotAjax1.0'
    assert !request.xml_http_request?
    assert !request.xhr?
389

390 391 392
    request = stub_request 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'
    assert request.xml_http_request?
    assert request.xhr?
393
  end
394

395
  test "reports ssl" do
396 397 398 399 400
    request = stub_request
    assert !request.ssl?

    request = stub_request 'HTTPS' => 'on'
    assert request.ssl?
401 402
  end

403
  test "reports ssl when proxied via lighttpd" do
404 405 406 407 408
    request = stub_request
    assert !request.ssl?

    request = stub_request 'HTTP_X_FORWARDED_PROTO' => 'https'
    assert request.ssl?
409
  end
410

411 412 413 414 415 416 417 418 419 420
  test "scheme returns https when proxied" do
    request = stub_request 'rack.url_scheme' => 'http'
    assert !request.ssl?
    assert_equal 'http', request.scheme

    request = stub_request 'rack.url_scheme' => 'http', 'HTTP_X_FORWARDED_PROTO' => 'https'
    assert request.ssl?
    assert_equal 'https', request.scheme
  end

421
  test "String request methods" do
422
    [:get, :post, :patch, :put, :delete].each do |method|
423
      request = stub_request 'REQUEST_METHOD' => method.to_s.upcase
424 425 426 427 428
      assert_equal method.to_s.upcase, request.method
    end
  end

  test "Symbol forms of request methods via method_symbol" do
429
    [:get, :post, :patch, :put, :delete].each do |method|
430 431
      request = stub_request 'REQUEST_METHOD' => method.to_s.upcase
      assert_equal method, request.method_symbol
432 433 434
    end
  end

435
  test "invalid http method raises exception" do
436
    assert_raise(ActionController::UnknownHttpMethod) do
437 438
      request = stub_request 'REQUEST_METHOD' => 'RANDOM_METHOD'
      request.request_method
439 440 441
    end
  end

442
  test "allow method hacking on post" do
443
    %w(GET OPTIONS PATCH PUT POST DELETE).each do |method|
444
      request = stub_request "REQUEST_METHOD" => method.to_s.upcase
445
      assert_equal(method == "HEAD" ? "GET" : method, request.method)
446 447 448
    end
  end

449
  test "invalid method hacking on post raises exception" do
450 451 452
    assert_raise(ActionController::UnknownHttpMethod) do
      request = stub_request "REQUEST_METHOD" => "_RANDOM_METHOD"
      request.request_method
453 454 455
    end
  end

456
  test "restrict method hacking" do
457
    [:get, :patch, :put, :delete].each do |method|
458
      request = stub_request 'REQUEST_METHOD' => method.to_s.upcase,
459
        'action_dispatch.request.request_parameters' => { :_method => 'put' }
460
      assert_equal method.to_s.upcase, request.method
461 462
    end
  end
463

464 465 466 467 468 469 470
  test "post masquerading as patch" do
    request = stub_request 'REQUEST_METHOD' => 'PATCH', "rack.methodoverride.original_method" => "POST"
    assert_equal "POST", request.method
    assert_equal "PATCH",  request.request_method
    assert request.patch?
  end

471 472 473 474 475 476 477
  test "post masquerading as put" do
    request = stub_request 'REQUEST_METHOD' => 'PUT', "rack.methodoverride.original_method" => "POST"
    assert_equal "POST", request.method
    assert_equal "PUT",  request.request_method
    assert request.put?
  end

478
  test "xml format" do
479 480 481
    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => 'xml' })
    assert_equal Mime::XML, request.format
482
  end
483

484
  test "xhtml format" do
485 486 487
    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => 'xhtml' })
    assert_equal Mime::HTML, request.format
488
  end
489

490
  test "txt format" do
491 492 493
    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => 'txt' })
    assert_equal Mime::TEXT, request.format
494
  end
495

496
  test "XMLHttpRequest" do
497 498 499 500 501 502
    request = stub_request 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest',
                           'HTTP_ACCEPT' =>
                             [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(",")
    request.expects(:parameters).at_least_once.returns({})
    assert request.xhr?
    assert_equal Mime::JS, request.format
503
  end
504

505
  test "content type" do
506
    request = stub_request 'CONTENT_TYPE' => 'text/html'
507
    assert_equal Mime::HTML, request.content_mime_type
508 509
  end

510
  test "can override format with parameter" do
511 512 513 514 515 516 517
    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => :txt })
    assert !request.format.xml?

    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => :xml })
    assert request.format.xml?
518 519
  end

520
  test "no content type" do
521
    request = stub_request
522
    assert_equal nil, request.content_mime_type
523
  end
524

525
  test "content type is XML" do
526
    request = stub_request 'CONTENT_TYPE' => 'application/xml'
527
    assert_equal Mime::XML, request.content_mime_type
528 529
  end

530
  test "content type with charset" do
531
    request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8'
532
    assert_equal Mime::XML, request.content_mime_type
533
  end
534

535
  test "user agent" do
536 537
    request = stub_request 'HTTP_USER_AGENT' => 'TestAgent'
    assert_equal 'TestAgent', request.user_agent
538
  end
539

540
  test "parameters" do
541 542 543
    request = stub_request
    request.stubs(:request_parameters).returns({ "foo" => 1 })
    request.stubs(:query_parameters).returns({ "bar" => 2 })
544

545 546 547 548 549
    assert_equal({"foo" => 1, "bar" => 2}, request.parameters)
    assert_equal({"foo" => 1}, request.request_parameters)
    assert_equal({"bar" => 2}, request.query_parameters)
  end

550 551 552 553
  test "parameters still accessible after rack parse error" do
    mock_rack_env = { "QUERY_STRING" => "x[y]=1&x[y][][w]=2", "rack.input" => "foo" }
    request = nil
    begin
554
      request = stub_request(mock_rack_env)
555
      request.parameters
556
    rescue ActionController::BadRequest
557 558 559 560 561
      # rack will raise a TypeError when parsing this query string
    end
    assert_equal({}, request.parameters)
  end

562
  test "formats with accept header" do
563 564 565
    request = stub_request 'HTTP_ACCEPT' => 'text/html'
    request.expects(:parameters).at_least_once.returns({})
    assert_equal [ Mime::HTML ], request.formats
566

567 568 569 570 571 572 573 574
    request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8',
                           'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
    request.expects(:parameters).at_least_once.returns({})
    assert_equal with_set(Mime::XML), request.formats

    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => :txt })
    assert_equal with_set(Mime::TEXT), request.formats
575 576 577 578

    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => :unknown })
    assert request.formats.empty?
579 580
  end

581 582 583 584 585 586
  test "formats with xhr request" do
    request = stub_request 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
    request.expects(:parameters).at_least_once.returns({})
    assert_equal [Mime::JS], request.formats
  end

587 588 589 590 591 592 593 594
  test "ignore_accept_header" do
    ActionDispatch::Request.ignore_accept_header = true

    begin
      request = stub_request 'HTTP_ACCEPT' => 'application/xml'
      request.expects(:parameters).at_least_once.returns({})
      assert_equal [ Mime::HTML ], request.formats

J
José Valim 已提交
595 596 597 598 599 600 601 602 603 604 605 606
      request = stub_request 'HTTP_ACCEPT' => 'koz-asked/something-crazy'
      request.expects(:parameters).at_least_once.returns({})
      assert_equal [ Mime::HTML ], request.formats

      request = stub_request 'HTTP_ACCEPT' => '*/*;q=0.1'
      request.expects(:parameters).at_least_once.returns({})
      assert_equal [ Mime::HTML ], request.formats

      request = stub_request 'HTTP_ACCEPT' => 'application/jxw'
      request.expects(:parameters).at_least_once.returns({})
      assert_equal [ Mime::HTML ], request.formats

607 608 609 610 611 612 613 614 615 616 617 618 619 620
      request = stub_request 'HTTP_ACCEPT' => 'application/xml',
                             'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
      request.expects(:parameters).at_least_once.returns({})
      assert_equal [ Mime::JS ], request.formats

      request = stub_request 'HTTP_ACCEPT' => 'application/xml',
                             'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
      request.expects(:parameters).at_least_once.returns({:format => :json})
      assert_equal [ Mime::JSON ], request.formats
    ensure
      ActionDispatch::Request.ignore_accept_header = false
    end
  end

621
  test "negotiate_mime" do
622 623 624 625 626 627 628 629 630 631 632 633 634
    request = stub_request 'HTTP_ACCEPT' => 'text/html',
                           'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"

    request.expects(:parameters).at_least_once.returns({})

    assert_equal nil, request.negotiate_mime([Mime::XML, Mime::JSON])
    assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::HTML])
    assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::ALL])

    request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8',
                           'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
    request.expects(:parameters).at_least_once.returns({})
    assert_equal Mime::XML, request.negotiate_mime([Mime::XML, Mime::CSV])
635
  end
636 637

  test "process parameter filter" do
638 639 640 641 642 643 644
    test_hashes = [
    [{'foo'=>'bar'},{'foo'=>'bar'},%w'food'],
    [{'foo'=>'bar'},{'foo'=>'[FILTERED]'},%w'foo'],
    [{'foo'=>'bar', 'bar'=>'foo'},{'foo'=>'[FILTERED]', 'bar'=>'foo'},%w'foo baz'],
    [{'foo'=>'bar', 'baz'=>'foo'},{'foo'=>'[FILTERED]', 'baz'=>'[FILTERED]'},%w'foo baz'],
    [{'bar'=>{'foo'=>'bar','bar'=>'foo'}},{'bar'=>{'foo'=>'[FILTERED]','bar'=>'foo'}},%w'fo'],
    [{'foo'=>{'foo'=>'bar','bar'=>'foo'}},{'foo'=>'[FILTERED]'},%w'f banana'],
645
    [{'baz'=>[{'foo'=>'baz'}, "1"]}, {'baz'=>[{'foo'=>'[FILTERED]'}, "1"]}, [/foo/]]]
646 647

    test_hashes.each do |before_filter, after_filter, filter_words|
648 649
      parameter_filter = ActionDispatch::Http::ParameterFilter.new(filter_words)
      assert_equal after_filter, parameter_filter.filter(before_filter)
650

651 652
      filter_words << 'blah'
      filter_words << lambda { |key, value|
653
        value.reverse! if key =~ /bargain/
654
      }
655

656
      parameter_filter = ActionDispatch::Http::ParameterFilter.new(filter_words)
657
      before_filter['barg'] = {'bargain'=>'gain', 'blah'=>'bar', 'bar'=>{'bargain'=>{'blah'=>'foo'}}}
658
      after_filter['barg']  = {'bargain'=>'niag', 'blah'=>'[FILTERED]', 'bar'=>{'bargain'=>{'blah'=>'[FILTERED]'}}}
659

660
      assert_equal after_filter, parameter_filter.filter(before_filter)
661 662
    end
  end
663

664
  test "filtered_parameters returns params filtered" do
665 666 667
    request = stub_request('action_dispatch.request.parameters' =>
      { 'lifo' => 'Pratik', 'amount' => '420', 'step' => '1' },
      'action_dispatch.parameter_filter' => [:lifo, :amount])
668 669 670 671 672 673 674 675

    params = request.filtered_parameters
    assert_equal "[FILTERED]", params["lifo"]
    assert_equal "[FILTERED]", params["amount"]
    assert_equal "1", params["step"]
  end

  test "filtered_env filters env as a whole" do
676 677 678
    request = stub_request('action_dispatch.request.parameters' =>
      { 'amount' => '420', 'step' => '1' }, "RAW_POST_DATA" => "yada yada",
      'action_dispatch.parameter_filter' => [:lifo, :amount])
679

680
    request = stub_request(request.filtered_env)
681 682 683

    assert_equal "[FILTERED]", request.raw_post
    assert_equal "[FILTERED]", request.params["amount"]
684
    assert_equal "1", request.params["step"]
685 686
  end

687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
  test "filtered_path returns path with filtered query string" do
    %w(; &).each do |sep|
      request = stub_request('QUERY_STRING' => %w(username=sikachu secret=bd4f21f api_key=b1bc3b3cd352f68d79d7).join(sep),
        'PATH_INFO' => '/authenticate',
        'action_dispatch.parameter_filter' => [:secret, :api_key])

      path = request.filtered_path
      assert_equal %w(/authenticate?username=sikachu secret=[FILTERED] api_key=[FILTERED]).join(sep), path
    end
  end

  test "filtered_path should not unescape a genuine '[FILTERED]' value" do
    request = stub_request('QUERY_STRING' => "secret=bd4f21f&genuine=%5BFILTERED%5D",
      'PATH_INFO' => '/authenticate',
      'action_dispatch.parameter_filter' => [:secret])

    path = request.filtered_path
    assert_equal "/authenticate?secret=[FILTERED]&genuine=%5BFILTERED%5D", path
  end

  test "filtered_path should preserve duplication of keys in query string" do
    request = stub_request('QUERY_STRING' => "username=sikachu&secret=bd4f21f&username=fxn",
      'PATH_INFO' => '/authenticate',
      'action_dispatch.parameter_filter' => [:secret])

    path = request.filtered_path
    assert_equal "/authenticate?username=sikachu&secret=[FILTERED]&username=fxn", path
  end

  test "filtered_path should ignore searchparts" do
    request = stub_request('QUERY_STRING' => "secret",
      'PATH_INFO' => '/authenticate',
      'action_dispatch.parameter_filter' => [:secret])

    path = request.filtered_path
    assert_equal "/authenticate?secret", path
  end

725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
  test "original_fullpath returns ORIGINAL_FULLPATH" do
    request = stub_request('ORIGINAL_FULLPATH' => "/foo?bar")

    path = request.original_fullpath
    assert_equal "/foo?bar", path
  end

  test "original_url returns url built using ORIGINAL_FULLPATH" do
    request = stub_request('ORIGINAL_FULLPATH' => "/foo?bar",
                           'HTTP_HOST'         => "example.org",
                           'rack.url_scheme'   => "http")

    url = request.original_url
    assert_equal "http://example.org/foo?bar", url
  end

  test "original_fullpath returns fullpath if ORIGINAL_FULLPATH is not present" do
    request = stub_request('PATH_INFO'    => "/foo",
                           'QUERY_STRING' => "bar")

    path = request.original_fullpath
    assert_equal "/foo?bar", path
  end

749 750
protected

751
  def stub_request(env = {})
C
Carlhuda 已提交
752
    ip_spoofing_check = env.key?(:ip_spoofing_check) ? env.delete(:ip_spoofing_check) : true
E
Emilio Tagua 已提交
753
    @trusted_proxies ||= nil
C
Carlhuda 已提交
754
    ip_app = ActionDispatch::RemoteIp.new(Proc.new { }, ip_spoofing_check, @trusted_proxies)
755
    tld_length = env.key?(:tld_length) ? env.delete(:tld_length) : 1
C
Carlhuda 已提交
756
    ip_app.call(env)
757
    ActionDispatch::Http::URL.tld_length = tld_length
758
    ActionDispatch::Request.new(env)
759
  end
760

761
  def with_set(*args)
762
    args
763
  end
764
end