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

3
class RequestTest < ActiveSupport::TestCase
4 5

  def url_for(options = {})
6
    options = { host: 'www.example.com' }.merge!(options)
7 8 9 10 11 12 13 14 15
    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')

Y
Yves Senn 已提交
16 17 18
    assert_equal 'http://www.example.com/books/?q=code', url_for(trailing_slash: true, path: '/books?q=code')
    assert_equal 'http://www.example.com/books/?spareslashes=////', url_for(trailing_slash: true, path: '/books?spareslashes=////')

19 20
    assert_equal 'http://www.example.com',  url_for
    assert_equal 'http://api.example.com',  url_for(:subdomain => 'api')
21
    assert_equal 'http://example.com',      url_for(:subdomain => false)
22 23 24 25 26 27 28 29 30
    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' })
31 32
    assert_equal 'http://www.example.com?params=',  url_for(:params => '')
    assert_equal 'http://www.example.com?params=1', url_for(:params => 1)
33 34
  end

35
  test "remote ip" do
36 37
    request = stub_request 'REMOTE_ADDR' => '1.2.3.4'
    assert_equal '1.2.3.4', request.remote_ip
38

39
    request = stub_request 'REMOTE_ADDR' => '1.2.3.4,3.4.5.6'
40
    assert_equal '3.4.5.6', request.remote_ip
41

42
    request = stub_request 'REMOTE_ADDR' => '1.2.3.4',
43
                           'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
44
    assert_equal '3.4.5.6', request.remote_ip
45

46
    request = stub_request 'REMOTE_ADDR' => '127.0.0.1',
47
                           'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
48
    assert_equal '3.4.5.6', request.remote_ip
J
Jeremy Kemper 已提交
49

50
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,unknown'
51
    assert_equal '3.4.5.6', request.remote_ip
52

53 54
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,172.16.0.1'
    assert_equal '3.4.5.6', request.remote_ip
J
Jeremy Kemper 已提交
55

56 57
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,192.168.0.1'
    assert_equal '3.4.5.6', request.remote_ip
58

59 60
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,10.0.0.1'
    assert_equal '3.4.5.6', request.remote_ip
61

62 63
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6, 10.0.0.1, 10.0.0.1'
    assert_equal '3.4.5.6', request.remote_ip
64

65 66
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,127.0.0.1'
    assert_equal '3.4.5.6', request.remote_ip
67

68
    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1'
69
    assert_equal nil, request.remote_ip
70

71
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 3.4.5.6, 172.31.4.4, 10.0.0.1'
72
    assert_equal '3.4.5.6', request.remote_ip
73

74 75
    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'not_ip_address'
    assert_equal nil, request.remote_ip
76
  end
77

78
  test "remote ip spoof detection" do
79 80
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1',
                           'HTTP_CLIENT_IP'       => '2.2.2.2'
C
Carlhuda 已提交
81
    e = assert_raise(ActionDispatch::RemoteIp::IpSpoofAttackError) {
82
      request.remote_ip
J
Jeremy Kemper 已提交
83
    }
84 85 86
    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)
87
  end
J
Jeremy Kemper 已提交
88

89
  test "remote ip with spoof detection disabled" do
90
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1',
C
Carlhuda 已提交
91 92
                           'HTTP_CLIENT_IP'       => '2.2.2.2',
                           :ip_spoofing_check => false
93
    assert_equal '1.1.1.1', request.remote_ip
94 95
  end

96 97 98 99 100 101 102 103
  test "remote ip spoof protection ignores private addresses" do
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '172.17.19.51',
                           'HTTP_CLIENT_IP'       => '172.17.19.51',
                           'REMOTE_ADDR'          => '1.1.1.1',
                           'HTTP_X_BLUECOAT_VIA'  => 'de462e07a2db325e'
    assert_equal '1.1.1.1', request.remote_ip
  end

104 105 106 107
  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

108
    request = stub_request 'REMOTE_ADDR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334'
109 110 111 112 113 114 115 116 117 118
    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

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

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

125 126
    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, ::1'
    assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip
127 128 129 130 131

    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::'
132
    assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip
133 134 135

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

138
  test "remote ip v6 spoof detection" do
139 140 141 142 143 144 145 146
    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)
147
  end
148

149
  test "remote ip v6 spoof detection disabled" do
150 151 152 153 154 155
    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 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip
  end

156 157
  test "remote ip with user specified trusted proxies String" do
    @trusted_proxies = "67.205.106.73"
158

159 160
    request = stub_request 'REMOTE_ADDR' => '3.4.5.6',
                           'HTTP_X_FORWARDED_FOR' => '67.205.106.73'
161 162 163
    assert_equal '3.4.5.6', request.remote_ip

    request = stub_request 'REMOTE_ADDR' => '172.16.0.1,67.205.106.73',
164
                           'HTTP_X_FORWARDED_FOR' => '67.205.106.73'
165
    assert_equal '67.205.106.73', request.remote_ip
166

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

171
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '67.205.106.73,unknown'
172
    assert_equal nil, request.remote_ip
173

174
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 3.4.5.6, 10.0.0.1, 67.205.106.73'
175 176 177
    assert_equal '3.4.5.6', request.remote_ip
  end

178 179 180 181 182 183 184 185 186 187 188 189 190
  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'
191
    assert_equal '::1', request.remote_ip
192 193 194 195 196

    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'
197
    assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip
198 199
  end

200 201 202 203 204 205 206
  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

207 208
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '10.0.0.1, 9.9.9.9, 3.4.5.6, 67.205.106.73'
    assert_equal '3.4.5.6', request.remote_ip
209 210 211 212 213 214 215 216 217
  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

218 219 220 221 222 223 224
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '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
  end

  test "remote ip middleware not present still returns an IP" do
    request = ActionDispatch::Request.new({'REMOTE_ADDR' => '127.0.0.1'})
    assert_equal '127.0.0.1', request.remote_ip
225 226
  end

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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
  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

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

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

319 320 321 322 323 324 325 326
  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

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

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

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

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

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

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

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

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

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

367
  test "server software" do
368 369
    request = stub_request
    assert_equal nil, request.server_software
370

371 372
    request = stub_request 'SERVER_SOFTWARE' => 'Apache3.422'
    assert_equal 'apache', request.server_software
373

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

378
  test "xml http request" do
379 380 381 382
    request = stub_request

    assert !request.xml_http_request?
    assert !request.xhr?
383

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

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

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

    request = stub_request 'HTTPS' => 'on'
    assert request.ssl?
399 400
  end

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

    request = stub_request 'HTTP_X_FORWARDED_PROTO' => 'https'
    assert request.ssl?
407
  end
408

409 410 411 412 413 414 415 416 417 418
  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

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

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

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

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

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

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

462 463 464 465 466 467 468
  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

469 470 471 472 473 474 475
  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

476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
  test "post uneffected by local inflections" do
    existing_acrnoyms = ActiveSupport::Inflector.inflections.acronyms.dup
    existing_acrnoym_regex = ActiveSupport::Inflector.inflections.acronym_regex.dup
    begin
      ActiveSupport::Inflector.inflections do |inflect|
        inflect.acronym "POS"
      end
      assert_equal "pos_t", "POST".underscore
      request = stub_request "REQUEST_METHOD" => "POST"
      assert_equal :post, ActionDispatch::Request::HTTP_METHOD_LOOKUP["POST"]
      assert_equal :post, request.method_symbol
      assert request.post?
    ensure
      # Reset original acronym set
      ActiveSupport::Inflector.inflections do |inflect|
        inflect.send(:instance_variable_set,"@acronyms",existing_acrnoyms)
        inflect.send(:instance_variable_set,"@acronym_regex",existing_acrnoym_regex)
      end
    end
  end

497
  test "xml format" do
498 499 500
    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => 'xml' })
    assert_equal Mime::XML, request.format
501
  end
502

503
  test "xhtml format" do
504 505 506
    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => 'xhtml' })
    assert_equal Mime::HTML, request.format
507
  end
508

509
  test "txt format" do
510 511 512
    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => 'txt' })
    assert_equal Mime::TEXT, request.format
513
  end
514

515
  test "XMLHttpRequest" do
516 517 518 519 520 521
    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
522
  end
523

524
  test "content type" do
525
    request = stub_request 'CONTENT_TYPE' => 'text/html'
526
    assert_equal Mime::HTML, request.content_mime_type
527 528
  end

529
  test "can override format with parameter" do
530 531 532 533 534 535 536
    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?
537 538
  end

539
  test "no content type" do
540
    request = stub_request
541
    assert_equal nil, request.content_mime_type
542
  end
543

544
  test "content type is XML" do
545
    request = stub_request 'CONTENT_TYPE' => 'application/xml'
546
    assert_equal Mime::XML, request.content_mime_type
547 548
  end

549
  test "content type with charset" do
550
    request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8'
551
    assert_equal Mime::XML, request.content_mime_type
552
  end
553

554
  test "user agent" do
555 556
    request = stub_request 'HTTP_USER_AGENT' => 'TestAgent'
    assert_equal 'TestAgent', request.user_agent
557
  end
558

559
  test "parameters" do
560 561 562
    request = stub_request
    request.stubs(:request_parameters).returns({ "foo" => 1 })
    request.stubs(:query_parameters).returns({ "bar" => 2 })
563

564 565 566 567 568
    assert_equal({"foo" => 1, "bar" => 2}, request.parameters)
    assert_equal({"foo" => 1}, request.request_parameters)
    assert_equal({"bar" => 2}, request.query_parameters)
  end

569 570 571
  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
572 573 574
    request = stub_request(mock_rack_env)

    assert_raises(ActionController::BadRequest) do
575
      # rack will raise a TypeError when parsing this query string
576
      request.parameters
577
    end
578

579 580 581
    assert_equal({}, request.parameters)
  end

582 583 584 585 586 587 588 589 590 591 592 593 594 595
  test "we have access to the original exception" do
    mock_rack_env = { "QUERY_STRING" => "x[y]=1&x[y][][w]=2", "rack.input" => "foo" }
    request = nil
    request = stub_request(mock_rack_env)

    e = assert_raises(ActionController::BadRequest) do
      # rack will raise a TypeError when parsing this query string
      request.parameters
    end

    assert e.original_exception
    assert_equal e.original_exception.backtrace, e.backtrace
  end

596
  test "formats with accept header" do
597 598
    request = stub_request 'HTTP_ACCEPT' => 'text/html'
    request.expects(:parameters).at_least_once.returns({})
599
    assert_equal [Mime::HTML], request.formats
600

601 602 603 604
    request = stub_request 'HTTP_ACCEPT' => ''
    request.expects(:parameters).at_least_once.returns({})
    assert_equal [Mime::HTML], request.formats

605 606 607 608
    request = stub_request 'HTTP_ACCEPT' => '',
                           'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
    request.expects(:parameters).at_least_once.returns({})
    assert_equal [Mime::JS], request.formats
609

610 611 612
    request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8',
                           'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest"
    request.expects(:parameters).at_least_once.returns({})
613
    assert_equal [Mime::XML], request.formats
614 615 616

    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => :txt })
617
    assert_equal [Mime::TEXT], request.formats
618 619 620

    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => :unknown })
621
    assert_instance_of Mime::NullType, request.format
622 623
  end

624 625 626
  test "format is not nil with unknown format" do
    request = stub_request
    request.expects(:parameters).at_least_once.returns({ format: :hello })
627 628 629 630
    assert request.format.nil?
    assert_not request.format.html?
    assert_not request.format.xml?
    assert_not request.format.json?
631
  end
632

633 634 635 636 637 638
  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

639 640 641 642 643 644 645 646
  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 已提交
647 648 649 650 651 652 653 654 655 656 657 658
      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

659 660 661 662 663 664 665 666 667 668 669 670 671 672
      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

673
  test "negotiate_mime" do
674 675 676 677 678 679 680 681 682 683 684 685 686
    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])
687
  end
688

689 690 691 692 693 694 695
  test "raw_post rewinds rack.input if RAW_POST_DATA is nil" do
    request = stub_request('rack.input' => StringIO.new("foo"),
                           'CONTENT_LENGTH' => 3)
    assert_equal "foo", request.raw_post
    assert_equal "foo", request.env['rack.input'].read
  end

696
  test "process parameter filter" do
697 698 699 700 701 702 703
    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'],
704
    [{'baz'=>[{'foo'=>'baz'}, "1"]}, {'baz'=>[{'foo'=>'[FILTERED]'}, "1"]}, [/foo/]]]
705 706

    test_hashes.each do |before_filter, after_filter, filter_words|
707 708
      parameter_filter = ActionDispatch::Http::ParameterFilter.new(filter_words)
      assert_equal after_filter, parameter_filter.filter(before_filter)
709

710 711
      filter_words << 'blah'
      filter_words << lambda { |key, value|
712
        value.reverse! if key =~ /bargain/
713
      }
714

715
      parameter_filter = ActionDispatch::Http::ParameterFilter.new(filter_words)
716
      before_filter['barg'] = {'bargain'=>'gain', 'blah'=>'bar', 'bar'=>{'bargain'=>{'blah'=>'foo'}}}
717
      after_filter['barg']  = {'bargain'=>'niag', 'blah'=>'[FILTERED]', 'bar'=>{'bargain'=>{'blah'=>'[FILTERED]'}}}
718

719
      assert_equal after_filter, parameter_filter.filter(before_filter)
720 721
    end
  end
722

723
  test "filtered_parameters returns params filtered" do
724 725 726
    request = stub_request('action_dispatch.request.parameters' =>
      { 'lifo' => 'Pratik', 'amount' => '420', 'step' => '1' },
      'action_dispatch.parameter_filter' => [:lifo, :amount])
727 728 729 730 731 732 733 734

    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
735 736 737
    request = stub_request('action_dispatch.request.parameters' =>
      { 'amount' => '420', 'step' => '1' }, "RAW_POST_DATA" => "yada yada",
      'action_dispatch.parameter_filter' => [:lifo, :amount])
738

739
    request = stub_request(request.filtered_env)
740 741 742

    assert_equal "[FILTERED]", request.raw_post
    assert_equal "[FILTERED]", request.params["amount"]
743
    assert_equal "1", request.params["step"]
744 745
  end

746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
  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

784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
  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

808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
  test "if_none_match_etags none" do
    request = stub_request

    assert_equal nil, request.if_none_match
    assert_equal [], request.if_none_match_etags
    assert !request.etag_matches?("foo")
    assert !request.etag_matches?(nil)
  end

  test "if_none_match_etags single" do
    header = 'the-etag'
    request = stub_request('HTTP_IF_NONE_MATCH' => header)

    assert_equal header, request.if_none_match
    assert_equal [header], request.if_none_match_etags
    assert request.etag_matches?("the-etag")
  end

  test "if_none_match_etags quoted single" do
    header = '"the-etag"'
    request = stub_request('HTTP_IF_NONE_MATCH' => header)

    assert_equal header, request.if_none_match
    assert_equal ['the-etag'], request.if_none_match_etags
    assert request.etag_matches?("the-etag")
  end

  test "if_none_match_etags multiple" do
    header = 'etag1, etag2, "third etag", "etag4"'
    expected = ['etag1', 'etag2', 'third etag', 'etag4']
    request = stub_request('HTTP_IF_NONE_MATCH' => header)

    assert_equal header, request.if_none_match
    assert_equal expected, request.if_none_match_etags
    expected.each do |etag|
      assert request.etag_matches?(etag), etag
    end
  end

Ł
Łukasz Strzałkowski 已提交
847 848 849 850 851 852 853 854 855 856 857 858 859
  test "setting variant" do
    request = stub_request
    request.variant = :mobile
    assert_equal :mobile, request.variant
  end

  test "setting variant with non symbol value" do
    request = stub_request
    assert_raise ArgumentError do
      request.variant = "mobile"
    end
  end

860 861
protected

862
  def stub_request(env = {})
C
Carlhuda 已提交
863
    ip_spoofing_check = env.key?(:ip_spoofing_check) ? env.delete(:ip_spoofing_check) : true
E
Emilio Tagua 已提交
864
    @trusted_proxies ||= nil
C
Carlhuda 已提交
865
    ip_app = ActionDispatch::RemoteIp.new(Proc.new { }, ip_spoofing_check, @trusted_proxies)
866
    tld_length = env.key?(:tld_length) ? env.delete(:tld_length) : 1
C
Carlhuda 已提交
867
    ip_app.call(env)
868
    ActionDispatch::Http::URL.tld_length = tld_length
869
    ActionDispatch::Request.new(env)
870
  end
871
end