request_test.rb 46.3 KB
Newer Older
1
require "abstract_unit"
2

3 4 5 6 7 8
class BaseRequestTest < ActiveSupport::TestCase
  def setup
    @env = {
      :ip_spoofing_check => true,
      "rack.input" => "foo"
    }
9 10 11 12 13
    @original_tld_length = ActionDispatch::Http::URL.tld_length
  end

  def teardown
    ActionDispatch::Http::URL.tld_length = @original_tld_length
14
  end
15 16

  def url_for(options = {})
17
    options = { host: "www.example.com" }.merge!(options)
18 19 20
    ActionDispatch::Http::URL.url_for(options)
  end

21
  private
22 23 24
    def stub_request(env = {})
      ip_spoofing_check = env.key?(:ip_spoofing_check) ? env.delete(:ip_spoofing_check) : true
      @trusted_proxies ||= nil
25
      ip_app = ActionDispatch::RemoteIp.new(Proc.new {}, ip_spoofing_check, @trusted_proxies)
26 27
      ActionDispatch::Http::URL.tld_length = env.delete(:tld_length) if env.key?(:tld_length)

28 29 30 31 32 33 34 35
      ip_app.call(env)

      env = @env.merge(env)
      ActionDispatch::Request.new(env)
    end
end

class RequestUrlFor < BaseRequestTest
36
  test "url_for class method" do
37
    e = assert_raise(ArgumentError) { url_for(host: nil) }
38 39
    assert_match(/Please provide the :host parameter/, e.message)

40
    assert_equal "/books", url_for(only_path: true, path: "/books")
41 42 43 44 45

    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=////")

    assert_equal "http://www.example.com",  url_for
46 47 48 49 50 51 52 53 54 55 56 57 58
    assert_equal "http://api.example.com",  url_for(subdomain: "api")
    assert_equal "http://example.com",      url_for(subdomain: false)
    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" })
    assert_equal "http://www.example.com?params=",  url_for(params: "")
    assert_equal "http://www.example.com?params=1", url_for(params: 1)
59
  end
60
end
61

62
class RequestIP < BaseRequestTest
63
  test "remote ip" do
64 65
    request = stub_request "REMOTE_ADDR" => "1.2.3.4"
    assert_equal "1.2.3.4", request.remote_ip
66

67 68
    request = stub_request "REMOTE_ADDR" => "1.2.3.4,3.4.5.6"
    assert_equal "3.4.5.6", request.remote_ip
69

70 71 72
    request = stub_request "REMOTE_ADDR" => "1.2.3.4",
                           "HTTP_X_FORWARDED_FOR" => "3.4.5.6"
    assert_equal "3.4.5.6", request.remote_ip
73

74 75 76
    request = stub_request "REMOTE_ADDR" => "127.0.0.1",
                           "HTTP_X_FORWARDED_FOR" => "3.4.5.6"
    assert_equal "3.4.5.6", request.remote_ip
J
Jeremy Kemper 已提交
77

78 79
    request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6,unknown"
    assert_equal "3.4.5.6", request.remote_ip
80

81 82
    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 已提交
83

84 85
    request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6,192.168.0.1"
    assert_equal "3.4.5.6", request.remote_ip
86

87 88
    request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6,10.0.0.1"
    assert_equal "3.4.5.6", request.remote_ip
89

90 91
    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
92

93 94
    request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6,127.0.0.1"
    assert_equal "3.4.5.6", request.remote_ip
95

96
    request = stub_request "HTTP_X_FORWARDED_FOR" => "unknown,192.168.0.1"
97
    assert_nil request.remote_ip
98

99 100
    request = stub_request "HTTP_X_FORWARDED_FOR" => "9.9.9.9, 3.4.5.6, 172.31.4.4, 10.0.0.1"
    assert_equal "3.4.5.6", request.remote_ip
101

102
    request = stub_request "HTTP_X_FORWARDED_FOR" => "not_ip_address"
103
    assert_nil request.remote_ip
104
  end
105

106
  test "remote ip spoof detection" do
107 108
    request = stub_request "HTTP_X_FORWARDED_FOR" => "1.1.1.1",
                           "HTTP_CLIENT_IP"       => "2.2.2.2"
C
Carlhuda 已提交
109
    e = assert_raise(ActionDispatch::RemoteIp::IpSpoofAttackError) {
110
      request.remote_ip
J
Jeremy Kemper 已提交
111
    }
112
    assert_match(/IP spoofing attack/, e.message)
113 114
    assert_match(/HTTP_X_FORWARDED_FOR="1\.1\.1\.1"/, e.message)
    assert_match(/HTTP_CLIENT_IP="2\.2\.2\.2"/, e.message)
115
  end
J
Jeremy Kemper 已提交
116

117
  test "remote ip with spoof detection disabled" do
118 119
    request = stub_request "HTTP_X_FORWARDED_FOR" => "1.1.1.1",
                           "HTTP_CLIENT_IP"       => "2.2.2.2",
C
Carlhuda 已提交
120
                           :ip_spoofing_check => false
121
    assert_equal "1.1.1.1", request.remote_ip
122 123
  end

124
  test "remote ip spoof protection ignores private addresses" do
125 126 127 128 129
    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
130 131
  end

132
  test "remote ip v6" do
133 134
    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
135

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

139 140 141
    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
142

143 144 145
    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
146

147 148
    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
149

150 151
    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
152

153 154
    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
155

156
    request = stub_request "HTTP_X_FORWARDED_FOR" => "unknown,::1"
157
    assert_nil request.remote_ip
158

159 160
    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::, fc01::, fdff"
    assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip
161

162 163
    request = stub_request "HTTP_X_FORWARDED_FOR" => "FE00::, FDFF::"
    assert_equal "FE00::", request.remote_ip
164

165
    request = stub_request "HTTP_X_FORWARDED_FOR" => "not_ip_address"
166
    assert_nil request.remote_ip
167
  end
168

169
  test "remote ip v6 spoof detection" do
170 171
    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"
172 173 174 175 176 177
    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)
178
  end
179

180
  test "remote ip v6 spoof detection disabled" do
181 182
    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",
183
                           :ip_spoofing_check     => false
184
    assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip
185 186
  end

187 188
  test "remote ip with user specified trusted proxies String" do
    @trusted_proxies = "67.205.106.73"
189

190 191 192
    request = stub_request "REMOTE_ADDR" => "3.4.5.6",
                           "HTTP_X_FORWARDED_FOR" => "67.205.106.73"
    assert_equal "3.4.5.6", request.remote_ip
193

194 195 196
    request = stub_request "REMOTE_ADDR" => "172.16.0.1,67.205.106.73",
                           "HTTP_X_FORWARDED_FOR" => "67.205.106.73"
    assert_equal "67.205.106.73", request.remote_ip
197

198 199 200
    request = stub_request "REMOTE_ADDR" => "67.205.106.73,3.4.5.6",
                           "HTTP_X_FORWARDED_FOR" => "67.205.106.73"
    assert_equal "3.4.5.6", request.remote_ip
201

202
    request = stub_request "HTTP_X_FORWARDED_FOR" => "67.205.106.73,unknown"
203
    assert_nil request.remote_ip
204

205 206
    request = stub_request "HTTP_X_FORWARDED_FOR" => "9.9.9.9, 3.4.5.6, 10.0.0.1, 67.205.106.73"
    assert_equal "3.4.5.6", request.remote_ip
207 208
  end

209
  test "remote ip v6 with user specified trusted proxies String" do
210
    @trusted_proxies = "fe80:0000:0000:0000:0202:b3ff:fe1e:8329"
211

212 213 214
    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
215

216 217 218
    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
219

220 221 222
    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 "::1", request.remote_ip
223

224
    request = stub_request "HTTP_X_FORWARDED_FOR" => "unknown,fe80:0000:0000:0000:0202:b3ff:fe1e:8329"
225
    assert_nil request.remote_ip
226

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

231 232 233
  test "remote ip with user specified trusted proxies Regexp" do
    @trusted_proxies = /^67\.205\.106\.73$/i

234 235 236
    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
237

238 239
    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
240 241 242 243 244
  end

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

245 246 247
    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
248

249 250
    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
251 252 253
  end

  test "remote ip middleware not present still returns an IP" do
254 255
    request = stub_request("REMOTE_ADDR" => "127.0.0.1")
    assert_equal "127.0.0.1", request.remote_ip
256
  end
257
end
258

259
class RequestDomain < BaseRequestTest
260
  test "domains" do
261
    request = stub_request "HTTP_HOST" => "192.168.1.200"
262
    assert_nil request.domain
263

264
    request = stub_request "HTTP_HOST" => "foo.192.168.1.200"
265
    assert_nil request.domain
266

267
    request = stub_request "HTTP_HOST" => "192.168.1.200.com"
268
    assert_equal "200.com", request.domain
269

270
    request = stub_request "HTTP_HOST" => "www.rubyonrails.org"
271
    assert_equal "rubyonrails.org", request.domain
272

273
    request = stub_request "HTTP_HOST" => "www.rubyonrails.co.uk"
274
    assert_equal "rubyonrails.co.uk", request.domain(2)
275

276
    request = stub_request "HTTP_HOST" => "www.rubyonrails.co.uk", :tld_length => 2
277 278
    assert_equal "rubyonrails.co.uk", request.domain
  end
279

280
  test "subdomains" do
281
    request = stub_request "HTTP_HOST" => "foobar.foobar.com"
282
    assert_equal %w( foobar ), request.subdomains
J
José Valim 已提交
283
    assert_equal "foobar", request.subdomain
284

285
    request = stub_request "HTTP_HOST" => "192.168.1.200"
286
    assert_equal [], request.subdomains
J
José Valim 已提交
287
    assert_equal "", request.subdomain
288

289
    request = stub_request "HTTP_HOST" => "foo.192.168.1.200"
290
    assert_equal [], request.subdomains
J
José Valim 已提交
291
    assert_equal "", request.subdomain
292

293
    request = stub_request "HTTP_HOST" => "192.168.1.200.com"
294
    assert_equal %w( 192 168 1 ), request.subdomains
J
José Valim 已提交
295
    assert_equal "192.168.1", request.subdomain
296

297
    request = stub_request "HTTP_HOST" => nil
298
    assert_equal [], request.subdomains
J
José Valim 已提交
299
    assert_equal "", request.subdomain
300

301
    request = stub_request "HTTP_HOST" => "www.rubyonrails.org"
302 303 304
    assert_equal %w( www ), request.subdomains
    assert_equal "www", request.subdomain

305
    request = stub_request "HTTP_HOST" => "www.rubyonrails.co.uk"
306 307 308
    assert_equal %w( www ), request.subdomains(2)
    assert_equal "www", request.subdomain(2)

309
    request = stub_request "HTTP_HOST" => "dev.www.rubyonrails.co.uk"
310 311 312
    assert_equal %w( dev www ), request.subdomains(2)
    assert_equal "dev.www", request.subdomain(2)

313
    request = stub_request "HTTP_HOST" => "dev.www.rubyonrails.co.uk", :tld_length => 2
314 315
    assert_equal %w( dev www ), request.subdomains
    assert_equal "dev.www", request.subdomain
316
  end
317
end
318

319
class RequestPort < BaseRequestTest
320 321 322 323
  test "standard_port" do
    request = stub_request
    assert_equal 80, request.standard_port

324
    request = stub_request "HTTPS" => "on"
325 326 327 328 329 330 331 332
    assert_equal 443, request.standard_port
  end

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

333
    request = stub_request "HTTPS" => "on"
334 335 336
    assert request.ssl?
    assert request.standard_port?

337
    request = stub_request "HTTP_HOST" => "www.example.org:8080"
338 339 340
    assert !request.ssl?
    assert !request.standard_port?

341
    request = stub_request "HTTP_HOST" => "www.example.org:8443", "HTTPS" => "on"
342 343 344 345
    assert request.ssl?
    assert !request.standard_port?
  end

346
  test "optional port" do
347
    request = stub_request "HTTP_HOST" => "www.example.org:80"
348
    assert_nil request.optional_port
349

350
    request = stub_request "HTTP_HOST" => "www.example.org:8080"
351
    assert_equal 8080, request.optional_port
352
  end
353

354
  test "port string" do
355 356
    request = stub_request "HTTP_HOST" => "www.example.org:80"
    assert_equal "", request.port_string
357

358 359
    request = stub_request "HTTP_HOST" => "www.example.org:8080"
    assert_equal ":8080", request.port_string
360
  end
361 362

  test "server port" do
363
    request = stub_request "SERVER_PORT" => "8080"
364 365
    assert_equal 8080, request.server_port

366
    request = stub_request "SERVER_PORT" => "80"
367 368
    assert_equal 80, request.server_port

369
    request = stub_request "SERVER_PORT" => ""
370 371
    assert_equal 0, request.server_port
  end
372
end
373

374
class RequestPath < BaseRequestTest
375
  test "full path" do
376
    request = stub_request "SCRIPT_NAME" => "", "PATH_INFO" => "/path/of/some/uri", "QUERY_STRING" => "mapped=1"
377 378
    assert_equal "/path/of/some/uri?mapped=1", request.fullpath
    assert_equal "/path/of/some/uri",          request.path_info
379

380
    request = stub_request "SCRIPT_NAME" => "", "PATH_INFO" => "/path/of/some/uri"
381 382
    assert_equal "/path/of/some/uri", request.fullpath
    assert_equal "/path/of/some/uri", request.path_info
383

384
    request = stub_request "SCRIPT_NAME" => "", "PATH_INFO" => "/"
385 386
    assert_equal "/", request.fullpath
    assert_equal "/", request.path_info
387

388
    request = stub_request "SCRIPT_NAME" => "", "PATH_INFO" => "/", "QUERY_STRING" => "m=b"
389 390
    assert_equal "/?m=b", request.fullpath
    assert_equal "/",     request.path_info
391

392
    request = stub_request "SCRIPT_NAME" => "/hieraki", "PATH_INFO" => "/"
393 394
    assert_equal "/hieraki/", request.fullpath
    assert_equal "/",         request.path_info
395

396
    request = stub_request "SCRIPT_NAME" => "/collaboration/hieraki", "PATH_INFO" => "/books/edit/2"
397 398
    assert_equal "/collaboration/hieraki/books/edit/2", request.fullpath
    assert_equal "/books/edit/2",                       request.path_info
399

400
    request = stub_request "SCRIPT_NAME" => "/path", "PATH_INFO" => "/of/some/uri", "QUERY_STRING" => "mapped=1"
401 402
    assert_equal "/path/of/some/uri?mapped=1", request.fullpath
    assert_equal "/of/some/uri",               request.path_info
403
  end
404

405
  test "original_fullpath returns ORIGINAL_FULLPATH" do
406
    request = stub_request("ORIGINAL_FULLPATH" => "/foo?bar")
407 408 409 410 411 412

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

  test "original_url returns url built using ORIGINAL_FULLPATH" do
413 414 415
    request = stub_request("ORIGINAL_FULLPATH" => "/foo?bar",
                           "HTTP_HOST"         => "example.org",
                           "rack.url_scheme"   => "http")
416 417 418 419 420 421

    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
422 423
    request = stub_request("PATH_INFO"    => "/foo",
                           "QUERY_STRING" => "bar")
424 425 426 427 428 429 430

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

class RequestHost < BaseRequestTest
431
  test "host without specifying port" do
432
    request = stub_request "HTTP_HOST" => "rubyonrails.org"
433 434 435
    assert_equal "rubyonrails.org", request.host_with_port
  end

436
  test "host with default port" do
437
    request = stub_request "HTTP_HOST" => "rubyonrails.org:80"
438
    assert_equal "rubyonrails.org", request.host_with_port
439
  end
440

441
  test "host with non default port" do
442
    request = stub_request "HTTP_HOST" => "rubyonrails.org:81"
443
    assert_equal "rubyonrails.org:81", request.host_with_port
444
  end
445

446
  test "raw without specifying port" do
447
    request = stub_request "HTTP_HOST" => "rubyonrails.org"
448 449 450 451
    assert_equal "rubyonrails.org", request.raw_host_with_port
  end

  test "raw host with default port" do
452
    request = stub_request "HTTP_HOST" => "rubyonrails.org:80"
453 454 455 456
    assert_equal "rubyonrails.org:80", request.raw_host_with_port
  end

  test "raw host with non default port" do
457
    request = stub_request "HTTP_HOST" => "rubyonrails.org:81"
458 459 460
    assert_equal "rubyonrails.org:81", request.raw_host_with_port
  end

461
  test "proxy request" do
462
    request = stub_request "HTTP_HOST" => "glu.ttono.us:80"
463 464 465 466
    assert_equal "glu.ttono.us", request.host_with_port
  end

  test "http host" do
467
    request = stub_request "HTTP_HOST" => "rubyonrails.org:8080"
468 469 470
    assert_equal "rubyonrails.org", request.host
    assert_equal "rubyonrails.org:8080", request.host_with_port

471
    request = stub_request "HTTP_X_FORWARDED_HOST" => "www.firsthost.org, www.secondhost.org"
472
    assert_equal "www.secondhost.org", request.host
473

474
    request = stub_request "HTTP_X_FORWARDED_HOST" => "", "HTTP_HOST" => "rubyonrails.org"
475
    assert_equal "rubyonrails.org", request.host
476 477 478
  end

  test "http host with default port overrides server port" do
479
    request = stub_request "HTTP_HOST" => "rubyonrails.org"
480 481 482 483
    assert_equal "rubyonrails.org", request.host_with_port
  end

  test "host with port if http standard port is specified" do
484
    request = stub_request "HTTP_X_FORWARDED_HOST" => "glu.ttono.us:80"
485 486 487 488 489
    assert_equal "glu.ttono.us", request.host_with_port
  end

  test "host with port if https standard port is specified" do
    request = stub_request(
490 491
      "HTTP_X_FORWARDED_PROTO" => "https",
      "HTTP_X_FORWARDED_HOST" => "glu.ttono.us:443"
492 493 494 495 496
    )
    assert_equal "glu.ttono.us", request.host_with_port
  end

  test "host if ipv6 reference" do
497
    request = stub_request "HTTP_HOST" => "[2001:1234:5678:9abc:def0::dead:beef]"
498 499 500 501
    assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", request.host
  end

  test "host if ipv6 reference with port" do
502
    request = stub_request "HTTP_HOST" => "[2001:1234:5678:9abc:def0::dead:beef]:8008"
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
    assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", request.host
  end
end

class RequestCGI < BaseRequestTest
  test "CGI environment variables" do
    request = stub_request(
      "AUTH_TYPE" => "Basic",
      "GATEWAY_INTERFACE" => "CGI/1.1",
      "HTTP_ACCEPT" => "*/*",
      "HTTP_ACCEPT_CHARSET" => "UTF-8",
      "HTTP_ACCEPT_ENCODING" => "gzip, deflate",
      "HTTP_ACCEPT_LANGUAGE" => "en",
      "HTTP_CACHE_CONTROL" => "no-cache, max-age=0",
      "HTTP_FROM" => "googlebot",
      "HTTP_HOST" => "glu.ttono.us:8007",
      "HTTP_NEGOTIATE" => "trans",
      "HTTP_PRAGMA" => "no-cache",
      "HTTP_REFERER" => "http://www.google.com/search?q=glu.ttono.us",
      "HTTP_USER_AGENT" => "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)",
      "PATH_INFO" => "/homepage/",
      "PATH_TRANSLATED" => "/home/kevinc/sites/typo/public/homepage/",
      "QUERY_STRING" => "",
      "REMOTE_ADDR" => "207.7.108.53",
      "REMOTE_HOST" => "google.com",
      "REMOTE_IDENT" => "kevin",
      "REMOTE_USER" => "kevin",
      "REQUEST_METHOD" => "GET",
      "SCRIPT_NAME" => "/dispatch.fcgi",
      "SERVER_NAME" => "glu.ttono.us",
      "SERVER_PORT" => "8007",
      "SERVER_PROTOCOL" => "HTTP/1.1",
      "SERVER_SOFTWARE" => "lighttpd/1.4.5",
    )

    assert_equal "Basic", request.auth_type
    assert_equal 0, request.content_length
540
    assert_nil request.content_mime_type
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
    assert_equal "CGI/1.1", request.gateway_interface
    assert_equal "*/*", request.accept
    assert_equal "UTF-8", request.accept_charset
    assert_equal "gzip, deflate", request.accept_encoding
    assert_equal "en", request.accept_language
    assert_equal "no-cache, max-age=0", request.cache_control
    assert_equal "googlebot", request.from
    assert_equal "glu.ttono.us", request.host
    assert_equal "trans", request.negotiate
    assert_equal "no-cache", request.pragma
    assert_equal "http://www.google.com/search?q=glu.ttono.us", request.referer
    assert_equal "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)", request.user_agent
    assert_equal "/homepage/", request.path_info
    assert_equal "/home/kevinc/sites/typo/public/homepage/", request.path_translated
    assert_equal "", request.query_string
    assert_equal "207.7.108.53", request.remote_addr
    assert_equal "google.com", request.remote_host
    assert_equal "kevin", request.remote_ident
    assert_equal "kevin", request.remote_user
    assert_equal "GET", request.request_method
    assert_equal "/dispatch.fcgi", request.script_name
    assert_equal "glu.ttono.us", request.server_name
    assert_equal 8007, request.server_port
    assert_equal "HTTP/1.1", request.server_protocol
    assert_equal "lighttpd", request.server_software
  end
end

569 570 571
class LocalhostTest < BaseRequestTest
  test "IPs that match localhost" do
    request = stub_request("REMOTE_IP" => "127.1.1.1", "REMOTE_ADDR" => "127.1.1.1")
A
Arthur Neves 已提交
572
    assert request.local?
573 574 575
  end
end

576 577 578 579 580 581 582 583
class RequestCookie < BaseRequestTest
  test "cookie syntax resilience" do
    request = stub_request("HTTP_COOKIE" => "_session_id=c84ace84796670c052c6ceb2451fb0f2; is_admin=yes")
    assert_equal "c84ace84796670c052c6ceb2451fb0f2", request.cookies["_session_id"], request.cookies.inspect
    assert_equal "yes", request.cookies["is_admin"], request.cookies.inspect

    # some Nokia phone browsers omit the space after the semicolon separator.
    # some developers have grown accustomed to using comma in cookie values.
584
    request = stub_request("HTTP_COOKIE" => "_session_id=c84ace847,96670c052c6ceb2451fb0f2;is_admin=yes")
585 586 587 588 589 590 591 592
    assert_equal "c84ace847", request.cookies["_session_id"], request.cookies.inspect
    assert_equal "yes", request.cookies["is_admin"], request.cookies.inspect
  end
end

class RequestParamsParsing < BaseRequestTest
  test "doesnt break when content type has charset" do
    request = stub_request(
593 594 595 596
      "REQUEST_METHOD" => "POST",
      "CONTENT_LENGTH" => "flamenco=love".length,
      "CONTENT_TYPE" => "application/x-www-form-urlencoded; charset=utf-8",
      "rack.input" => StringIO.new("flamenco=love")
597 598
    )

599
    assert_equal({ "flamenco" => "love" }, request.request_parameters)
600 601 602
  end

  test "doesnt interpret request uri as query string when missing" do
603
    request = stub_request("REQUEST_URI" => "foo")
604 605 606
    assert_equal({}, request.query_parameters)
  end
end
607

608 609
class RequestRewind < BaseRequestTest
  test "body should be rewound" do
610
    data = "rewind"
611
    env = {
612 613 614
      "rack.input" => StringIO.new(data),
      "CONTENT_LENGTH" => data.length,
      "CONTENT_TYPE" => "application/x-www-form-urlencoded; charset=utf-8"
615 616 617 618 619 620 621 622 623 624 625 626
    }

    # Read the request body by parsing params.
    request = stub_request(env)
    request.request_parameters

    # Should have rewound the body.
    assert_equal 0, request.body.pos
  end

  test "raw_post rewinds rack.input if RAW_POST_DATA is nil" do
    request = stub_request(
627 628
      "rack.input" => StringIO.new("raw"),
      "CONTENT_LENGTH" => 3
629 630
    )
    assert_equal "raw", request.raw_post
631
    assert_equal "raw", request.env["rack.input"].read
632 633
  end
end
634

635 636
class RequestProtocol < BaseRequestTest
  test "server software" do
637 638
    assert_equal "lighttpd", stub_request("SERVER_SOFTWARE" => "lighttpd/1.4.5").server_software
    assert_equal "apache", stub_request("SERVER_SOFTWARE" => "Apache3.422").server_software
639
  end
640

641
  test "xml http request" do
642 643 644 645
    request = stub_request

    assert !request.xml_http_request?
    assert !request.xhr?
646

647
    request = stub_request "HTTP_X_REQUESTED_WITH" => "DefinitelyNotAjax1.0"
648 649
    assert !request.xml_http_request?
    assert !request.xhr?
650

651
    request = stub_request "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"
652 653
    assert request.xml_http_request?
    assert request.xhr?
654
  end
655

656
  test "reports ssl" do
657
    assert !stub_request.ssl?
658
    assert stub_request("HTTPS" => "on").ssl?
659 660
  end

661
  test "reports ssl when proxied via lighttpd" do
662
    assert stub_request("HTTP_X_FORWARDED_PROTO" => "https").ssl?
663
  end
664

665
  test "scheme returns https when proxied" do
666
    request = stub_request "rack.url_scheme" => "http"
667
    assert !request.ssl?
668
    assert_equal "http", request.scheme
669

670
    request = stub_request(
671 672
      "rack.url_scheme" => "http",
      "HTTP_X_FORWARDED_PROTO" => "https"
673
    )
674
    assert request.ssl?
675
    assert_equal "https", request.scheme
676
  end
677
end
678

679
class RequestMethod < BaseRequestTest
680
  test "method returns environment's request method when it has not been
681
    overridden by middleware".squish do
682

683
    ActionDispatch::Request::HTTP_METHODS.each do |method|
684
      request = stub_request("REQUEST_METHOD" => method)
685 686 687

      assert_equal method, request.method
      assert_equal method.underscore.to_sym, request.method_symbol
688 689 690
    end
  end

691
  test "allow request method hacking" do
692
    request = stub_request("REQUEST_METHOD" => "POST")
693

694 695
    assert_equal "POST", request.request_method
    assert_equal "POST", request.env["REQUEST_METHOD"]
696

697
    request.request_method = "GET"
698

699 700
    assert_equal "GET", request.request_method
    assert_equal "GET", request.env["REQUEST_METHOD"]
701
    assert request.get?
702 703
  end

704
  test "invalid http method raises exception" do
705
    assert_raise(ActionController::UnknownHttpMethod) do
706
      stub_request("REQUEST_METHOD" => "RANDOM_METHOD").request_method
707 708 709
    end
  end

G
Guo Xiang Tan 已提交
710
  test "method returns original value of environment request method on POST" do
711 712
    request = stub_request("rack.methodoverride.original_method" => "POST")
    assert_equal "POST", request.method
713 714
  end

G
Guo Xiang Tan 已提交
715
  test "method raises exception on invalid HTTP method" do
716
    assert_raise(ActionController::UnknownHttpMethod) do
717
      stub_request("rack.methodoverride.original_method" => "_RANDOM_METHOD").method
718
    end
719

G
Guo Xiang Tan 已提交
720
    assert_raise(ActionController::UnknownHttpMethod) do
721
      stub_request("REQUEST_METHOD" => "_RANDOM_METHOD").method
722 723
    end
  end
724

725 726 727 728 729 730 731 732
  test "exception on invalid HTTP method unaffected by I18n settings" do
    old_locales = I18n.available_locales
    old_enforce = I18n.config.enforce_available_locales

    begin
      I18n.available_locales = [:nl]
      I18n.config.enforce_available_locales = true
      assert_raise(ActionController::UnknownHttpMethod) do
733
        stub_request("REQUEST_METHOD" => "_RANDOM_METHOD").method
734 735 736 737 738 739 740
      end
    ensure
      I18n.available_locales = old_locales
      I18n.config.enforce_available_locales = old_enforce
    end
  end

741
  test "post masquerading as patch" do
742
    request = stub_request(
743
      "REQUEST_METHOD" => "PATCH",
744 745 746
      "rack.methodoverride.original_method" => "POST"
    )

747 748 749 750 751
    assert_equal "POST", request.method
    assert_equal "PATCH",  request.request_method
    assert request.patch?
  end

752
  test "post masquerading as put" do
753
    request = stub_request(
754
      "REQUEST_METHOD" => "PUT",
755 756
      "rack.methodoverride.original_method" => "POST"
    )
757 758 759 760 761
    assert_equal "POST", request.method
    assert_equal "PUT",  request.request_method
    assert request.put?
  end

762
  test "post uneffected by local inflections" do
L
Lachlan Priest 已提交
763 764
    existing_acronyms = ActiveSupport::Inflector.inflections.acronyms.dup
    existing_acronym_regex = ActiveSupport::Inflector.inflections.acronym_regex.dup
765 766 767 768 769 770 771 772 773 774 775 776
    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|
L
Lachlan Priest 已提交
777 778
        inflect.send(:instance_variable_set, "@acronyms", existing_acronyms)
        inflect.send(:instance_variable_set, "@acronym_regex", existing_acronym_regex)
779 780 781
      end
    end
  end
782
end
783

784
class RequestFormat < BaseRequestTest
785
  test "xml format" do
786
    request = stub_request
787
    assert_called(request, :parameters, times: 2, returns: { format: :xml }) do
788
      assert_equal Mime[:xml], request.format
789
    end
790
  end
791

792
  test "xhtml format" do
793
    request = stub_request
794
    assert_called(request, :parameters, times: 2, returns: { format: :xhtml }) do
795
      assert_equal Mime[:html], request.format
796
    end
797
  end
798

799
  test "txt format" do
800
    request = stub_request
801
    assert_called(request, :parameters, times: 2, returns: { format: :txt }) do
802
      assert_equal Mime[:text], request.format
803
    end
804
  end
805

806
  test "XMLHttpRequest" do
807
    request = stub_request(
808 809
      "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
      "HTTP_ACCEPT" => [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(",")
810
    )
811 812 813

    assert_called(request, :parameters, times: 1, returns: {}) do
      assert request.xhr?
814
      assert_equal Mime[:js], request.format
815
    end
816
  end
817

818
  test "can override format with parameter negative" do
819
    request = stub_request
820
    assert_called(request, :parameters, times: 2, returns: { format: :txt }) do
821 822
      assert !request.format.xml?
    end
823
  end
824

825
  test "can override format with parameter positive" do
826
    request = stub_request
827
    assert_called(request, :parameters, times: 2, returns: { format: :xml }) do
828 829
      assert request.format.xml?
    end
830 831
  end

832
  test "formats text/html with accept header" do
833
    request = stub_request "HTTP_ACCEPT" => "text/html"
834
    assert_equal [Mime[:html]], request.formats
835
  end
836

837
  test "formats blank with accept header" do
838
    request = stub_request "HTTP_ACCEPT" => ""
839
    assert_equal [Mime[:html]], request.formats
840
  end
841

842
  test "formats XMLHttpRequest with accept header" do
843
    request = stub_request "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"
844
    assert_equal [Mime[:js]], request.formats
845
  end
846

847
  test "formats application/xml with accept header" do
848 849
    request = stub_request("CONTENT_TYPE" => "application/xml; charset=UTF-8",
                           "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest")
850
    assert_equal [Mime[:xml]], request.formats
851
  end
852

853
  test "formats format:text with accept header" do
854
    request = stub_request
855
    assert_called(request, :parameters, times: 2, returns: { format: :txt }) do
856
      assert_equal [Mime[:text]], request.formats
857
    end
858
  end
859

860
  test "formats format:unknown with accept header" do
861
    request = stub_request
862
    assert_called(request, :parameters, times: 2, returns: { format: :unknown }) do
863 864
      assert_instance_of Mime::NullType, request.format
    end
865 866
  end

867 868
  test "format is not nil with unknown format" do
    request = stub_request
869
    assert_called(request, :parameters, times: 2, returns: { format: :hello }) do
870 871 872 873 874
      assert request.format.nil?
      assert_not request.format.html?
      assert_not request.format.xml?
      assert_not request.format.json?
    end
875
  end
876

J
Jarmo Isotalo 已提交
877 878 879 880 881 882
  test "format does not throw exceptions when malformed parameters" do
    request = stub_request("QUERY_STRING" => "x[y]=1&x[y][][w]=2")
    assert request.formats
    assert request.format.html?
  end

883
  test "formats with xhr request" do
884
    request = stub_request "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"
885
    assert_called(request, :parameters, times: 1, returns: {}) do
886
      assert_equal [Mime[:js]], request.formats
887
    end
888 889
  end

890
  test "ignore_accept_header" do
891
    old_ignore_accept_header = ActionDispatch::Request.ignore_accept_header
892 893 894
    ActionDispatch::Request.ignore_accept_header = true

    begin
895
      request = stub_request "HTTP_ACCEPT" => "application/xml"
896
      assert_called(request, :parameters, times: 1, returns: {}) do
897
        assert_equal [ Mime[:html] ], request.formats
898
      end
899

900
      request = stub_request "HTTP_ACCEPT" => "koz-asked/something-crazy"
901
      assert_called(request, :parameters, times: 1, returns: {}) do
902
        assert_equal [ Mime[:html] ], request.formats
903
      end
J
José Valim 已提交
904

905
      request = stub_request "HTTP_ACCEPT" => "*/*;q=0.1"
906
      assert_called(request, :parameters, times: 1, returns: {}) do
907
        assert_equal [ Mime[:html] ], request.formats
908
      end
J
José Valim 已提交
909

910
      request = stub_request "HTTP_ACCEPT" => "application/jxw"
911
      assert_called(request, :parameters, times: 1, returns: {}) do
912
        assert_equal [ Mime[:html] ], request.formats
913
      end
J
José Valim 已提交
914

915 916
      request = stub_request "HTTP_ACCEPT" => "application/xml",
                             "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"
917 918

      assert_called(request, :parameters, times: 1, returns: {}) do
919
        assert_equal [ Mime[:js] ], request.formats
920
      end
921

922 923
      request = stub_request "HTTP_ACCEPT" => "application/xml",
                             "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"
924
      assert_called(request, :parameters, times: 2, returns: { format: :json }) do
925
        assert_equal [ Mime[:json] ], request.formats
926
      end
927
    ensure
928
      ActionDispatch::Request.ignore_accept_header = old_ignore_accept_header
929 930
    end
  end
931 932

  test "format taken from the path extension" do
933
    request = stub_request "PATH_INFO" => "/foo.xml"
934 935 936 937
    assert_called(request, :parameters, times: 1, returns: {}) do
      assert_equal [Mime[:xml]], request.formats
    end

938
    request = stub_request "PATH_INFO" => "/foo.123"
939 940 941 942
    assert_called(request, :parameters, times: 1, returns: {}) do
      assert_equal [Mime[:html]], request.formats
    end
  end
943 944

  test "formats from accept headers have higher precedence than path extension" do
945 946
    request = stub_request "HTTP_ACCEPT" => "application/json",
                           "PATH_INFO" => "/foo.xml"
947 948 949 950 951

    assert_called(request, :parameters, times: 1, returns: {}) do
      assert_equal [Mime[:json]], request.formats
    end
  end
952
end
953

954 955
class RequestMimeType < BaseRequestTest
  test "content type" do
956
    assert_equal Mime[:html], stub_request("CONTENT_TYPE" => "text/html").content_mime_type
957
  end
958

959
  test "no content type" do
960
    assert_nil stub_request.content_mime_type
961 962 963
  end

  test "content type is XML" do
964
    assert_equal Mime[:xml], stub_request("CONTENT_TYPE" => "application/xml").content_mime_type
965 966 967
  end

  test "content type with charset" do
968
    assert_equal Mime[:xml], stub_request("CONTENT_TYPE" => "application/xml; charset=UTF-8").content_mime_type
969 970 971
  end

  test "user agent" do
972
    assert_equal "TestAgent", stub_request("HTTP_USER_AGENT" => "TestAgent").user_agent
973 974 975 976
  end

  test "negotiate_mime" do
    request = stub_request(
977 978
      "HTTP_ACCEPT" => "text/html",
      "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"
979
    )
980

981
    assert_nil request.negotiate_mime([Mime[:xml], Mime[:json]])
982 983
    assert_equal Mime[:html], request.negotiate_mime([Mime[:xml], Mime[:html]])
    assert_equal Mime[:html], request.negotiate_mime([Mime[:xml], Mime::ALL])
984 985 986 987
  end

  test "negotiate_mime with content_type" do
    request = stub_request(
988 989
      "CONTENT_TYPE" => "application/xml; charset=UTF-8",
      "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"
990
    )
991

992
    assert_equal Mime[:xml], request.negotiate_mime([Mime[:xml], Mime[:csv]])
993
  end
994
end
995

996 997 998 999
class RequestParameters < BaseRequestTest
  test "parameters" do
    request = stub_request

1000 1001 1002 1003 1004
    assert_called(request, :request_parameters, times: 2, returns: { "foo" => 1 }) do
      assert_called(request, :query_parameters, times: 2, returns: { "bar" => 2 }) do
        assert_equal({ "foo" => 1, "bar" => 2 }, request.parameters)
        assert_equal({ "foo" => 1 }, request.request_parameters)
        assert_equal({ "bar" => 2 }, request.query_parameters)
1005 1006
      end
    end
1007 1008
  end

J
Jarmo Isotalo 已提交
1009
  test "parameters not accessible after rack parse error" do
1010 1011
    request = stub_request("QUERY_STRING" => "x[y]=1&x[y][][w]=2")

J
Jarmo Isotalo 已提交
1012 1013
    2.times do
      assert_raises(ActionController::BadRequest) do
1014
        # rack will raise a Rack::Utils::ParameterTypeError when parsing this query string
J
Jarmo Isotalo 已提交
1015 1016
        request.parameters
      end
1017
    end
1018 1019
  end

1020
  test "path parameters with invalid UTF8 encoding" do
1021
    request = stub_request
1022 1023

    err = assert_raises(ActionController::BadRequest) do
1024
      request.path_parameters = { foo: "\xBE" }
1025 1026
    end

1027
    assert_equal "Invalid path parameters: Non UTF-8 value: \xBE", err.message
1028 1029
  end

1030 1031
  test "parameters not accessible after rack parse error of invalid UTF8 character" do
    request = stub_request("QUERY_STRING" => "foo%81E=1")
1032 1033
    assert_raises(ActionController::BadRequest) { request.parameters }
  end
1034

1035 1036 1037 1038 1039 1040 1041 1042
  test "parameters containing an invalid UTF8 character" do
    request = stub_request("QUERY_STRING" => "foo=%81E")
    assert_raises(ActionController::BadRequest) { request.parameters }
  end

  test "parameters containing a deeply nested invalid UTF8 character" do
    request = stub_request("QUERY_STRING" => "foo[bar]=%81E")
    assert_raises(ActionController::BadRequest) { request.parameters }
1043 1044 1045 1046
  end

  test "parameters not accessible after rack parse error 1" do
    request = stub_request(
1047 1048 1049 1050
      "REQUEST_METHOD" => "POST",
      "CONTENT_LENGTH" => "a%=".length,
      "CONTENT_TYPE" => "application/x-www-form-urlencoded; charset=utf-8",
      "rack.input" => StringIO.new("a%=")
1051 1052 1053
    )

    assert_raises(ActionController::BadRequest) do
1054
      # rack will raise a Rack::Utils::ParameterTypeError when parsing this query string
1055 1056 1057 1058
      request.parameters
    end
  end

1059 1060 1061 1062
  test "we have access to the original exception" do
    request = stub_request("QUERY_STRING" => "x[y]=1&x[y][][w]=2")

    e = assert_raises(ActionController::BadRequest) do
1063
      # rack will raise a Rack::Utils::ParameterTypeError when parsing this query string
1064 1065 1066
      request.parameters
    end

1067 1068
    assert_not_nil e.cause
    assert_equal e.cause.backtrace, e.backtrace
1069 1070 1071 1072
  end
end

class RequestParameterFilter < BaseRequestTest
1073
  test "process parameter filter" do
1074
    test_hashes = [
1075 1076 1077 1078 1079 1080 1081 1082
    [{ "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'],
    [{ "deep" => { "cc" => { "code" => "bar", "bar" => "foo" }, "ss" => { "code" => "bar" } } }, { "deep" => { "cc" => { "code" => "[FILTERED]", "bar" => "foo" }, "ss" => { "code" => "bar" } } }, %w'deep.cc.code'],
    [{ "baz" => [{ "foo" => "baz" }, "1"] }, { "baz" => [{ "foo" => "[FILTERED]" }, "1"] }, [/foo/]]]
1083 1084

    test_hashes.each do |before_filter, after_filter, filter_words|
1085 1086
      parameter_filter = ActionDispatch::Http::ParameterFilter.new(filter_words)
      assert_equal after_filter, parameter_filter.filter(before_filter)
1087

1088
      filter_words << "blah"
1089
      filter_words << lambda { |key, value|
1090
        value.reverse! if key =~ /bargain/
1091
      }
1092

1093
      parameter_filter = ActionDispatch::Http::ParameterFilter.new(filter_words)
1094 1095
      before_filter["barg"] = { :bargain => "gain", "blah" => "bar", "bar" => { "bargain" => { "blah" => "foo" } } }
      after_filter["barg"]  = { :bargain => "niag", "blah" => "[FILTERED]", "bar" => { "bargain" => { "blah" => "[FILTERED]" } } }
1096

1097
      assert_equal after_filter, parameter_filter.filter(before_filter)
1098 1099
    end
  end
1100

1101
  test "filtered_parameters returns params filtered" do
1102
    request = stub_request(
1103 1104 1105 1106
      "action_dispatch.request.parameters" => {
        "lifo" => "Pratik",
        "amount" => "420",
        "step" => "1"
1107
      },
1108
      "action_dispatch.parameter_filter" => [:lifo, :amount]
1109
    )
1110 1111 1112 1113 1114 1115 1116 1117

    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
1118
    request = stub_request(
1119 1120 1121
      "action_dispatch.request.parameters" => {
        "amount" => "420",
        "step" => "1"
1122 1123
      },
      "RAW_POST_DATA" => "yada yada",
1124
      "action_dispatch.parameter_filter" => [:lifo, :amount]
1125
    )
1126
    request = stub_request(request.filtered_env)
1127 1128 1129

    assert_equal "[FILTERED]", request.raw_post
    assert_equal "[FILTERED]", request.params["amount"]
1130
    assert_equal "1", request.params["step"]
1131 1132
  end

1133 1134
  test "filtered_path returns path with filtered query string" do
    %w(; &).each do |sep|
1135
      request = stub_request(
1136 1137 1138
        "QUERY_STRING" => %w(username=sikachu secret=bd4f21f api_key=b1bc3b3cd352f68d79d7).join(sep),
        "PATH_INFO" => "/authenticate",
        "action_dispatch.parameter_filter" => [:secret, :api_key]
1139
      )
1140 1141 1142 1143 1144 1145 1146

      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
1147
    request = stub_request(
1148 1149 1150
      "QUERY_STRING" => "secret=bd4f21f&genuine=%5BFILTERED%5D",
      "PATH_INFO" => "/authenticate",
      "action_dispatch.parameter_filter" => [:secret]
1151
    )
1152 1153

    path = request.filtered_path
1154
    assert_equal request.script_name + "/authenticate?secret=[FILTERED]&genuine=%5BFILTERED%5D", path
1155 1156 1157
  end

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

    path = request.filtered_path
1165
    assert_equal request.script_name + "/authenticate?username=sikachu&secret=[FILTERED]&username=fxn", path
1166 1167 1168
  end

  test "filtered_path should ignore searchparts" do
1169
    request = stub_request(
1170 1171 1172
      "QUERY_STRING" => "secret",
      "PATH_INFO" => "/authenticate",
      "action_dispatch.parameter_filter" => [:secret]
1173
    )
1174 1175

    path = request.filtered_path
1176
    assert_equal request.script_name + "/authenticate?secret", path
1177
  end
1178
end
1179

1180
class RequestEtag < BaseRequestTest
J
Jeremy Daer 已提交
1181
  test "always matches *" do
1182
    request = stub_request("HTTP_IF_NONE_MATCH" => "*")
J
Jeremy Daer 已提交
1183

1184 1185
    assert_equal "*", request.if_none_match
    assert_equal ["*"], request.if_none_match_etags
J
Jeremy Daer 已提交
1186 1187 1188 1189 1190 1191 1192

    assert request.etag_matches?('"strong"')
    assert request.etag_matches?('W/"weak"')
    assert_not request.etag_matches?(nil)
  end

  test "doesn't match absent If-None-Match" do
1193 1194
    request = stub_request

1195
    assert_nil request.if_none_match
1196 1197
    assert_equal [], request.if_none_match_etags

J
Jeremy Daer 已提交
1198 1199
    assert_not request.etag_matches?("foo")
    assert_not request.etag_matches?(nil)
1200 1201
  end

J
Jeremy Daer 已提交
1202
  test "matches opaque ETag validators without unquoting" do
1203
    header = '"the-etag"'
1204
    request = stub_request("HTTP_IF_NONE_MATCH" => header)
1205 1206

    assert_equal header, request.if_none_match
J
Jeremy Daer 已提交
1207 1208 1209 1210
    assert_equal ['"the-etag"'], request.if_none_match_etags

    assert request.etag_matches?('"the-etag"')
    assert_not request.etag_matches?("the-etag")
1211 1212 1213 1214
  end

  test "if_none_match_etags multiple" do
    header = 'etag1, etag2, "third etag", "etag4"'
1215 1216
    expected = ["etag1", "etag2", '"third etag"', '"etag4"']
    request = stub_request("HTTP_IF_NONE_MATCH" => header)
1217 1218 1219 1220 1221 1222 1223

    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
1224
end
1225

R
Rafael Mendonça França 已提交
1226
class RequestVariant < BaseRequestTest
1227 1228
  def setup
    super
1229 1230
    @request = stub_request
  end
L
Lukasz Strzalkowski 已提交
1231

1232
  test "setting variant to a symbol" do
1233
    @request.variant = :phone
L
Lukasz Strzalkowski 已提交
1234

1235 1236 1237 1238 1239
    assert @request.variant.phone?
    assert_not @request.variant.tablet?
    assert @request.variant.any?(:phone, :tablet)
    assert_not @request.variant.any?(:tablet, :desktop)
  end
1240

1241
  test "setting variant to an array of symbols" do
1242
    @request.variant = [:phone, :tablet]
1243

1244 1245 1246 1247 1248
    assert @request.variant.phone?
    assert @request.variant.tablet?
    assert_not @request.variant.desktop?
    assert @request.variant.any?(:tablet, :desktop)
    assert_not @request.variant.any?(:desktop, :watch)
Ł
Łukasz Strzałkowski 已提交
1249 1250
  end

1251
  test "clearing variant" do
1252
    @request.variant = nil
1253

1254 1255 1256
    assert @request.variant.empty?
    assert_not @request.variant.phone?
    assert_not @request.variant.any?(:phone, :tablet)
1257 1258
  end

1259
  test "setting variant to a non-symbol value" do
1260
    assert_raise ArgumentError do
1261
      @request.variant = "phone"
1262 1263 1264
    end
  end

1265
  test "setting variant to an array containing a non-symbol value" do
Ł
Łukasz Strzałkowski 已提交
1266
    assert_raise ArgumentError do
1267
      @request.variant = [:phone, "tablet"]
Ł
Łukasz Strzałkowski 已提交
1268 1269
    end
  end
1270
end
S
Sergey Alekseev 已提交
1271 1272

class RequestFormData < BaseRequestTest
1273 1274 1275
  test "media_type is from the FORM_DATA_MEDIA_TYPES array" do
    assert stub_request("CONTENT_TYPE" => "application/x-www-form-urlencoded").form_data?
    assert stub_request("CONTENT_TYPE" => "multipart/form-data").form_data?
S
Sergey Alekseev 已提交
1276 1277
  end

1278 1279 1280
  test "media_type is not from the FORM_DATA_MEDIA_TYPES array" do
    assert !stub_request("CONTENT_TYPE" => "application/xml").form_data?
    assert !stub_request("CONTENT_TYPE" => "multipart/related").form_data?
S
Sergey Alekseev 已提交
1281 1282
  end

1283 1284
  test "no Content-Type header is provided and the request_method is POST" do
    request = stub_request("REQUEST_METHOD" => "POST")
S
Sergey Alekseev 已提交
1285

1286 1287
    assert_equal "", request.media_type
    assert_equal "POST", request.request_method
S
Sergey Alekseev 已提交
1288 1289 1290
    assert !request.form_data?
  end
end