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

3
class RequestTest < ActiveSupport::TestCase
4
  test "remote ip" do
5 6
    request = stub_request 'REMOTE_ADDR' => '1.2.3.4'
    assert_equal '1.2.3.4', request.remote_ip
7

8 9
    request = stub_request 'REMOTE_ADDR' => '1.2.3.4,3.4.5.6'
    assert_equal '1.2.3.4', request.remote_ip
10

11 12 13
    request = stub_request 'REMOTE_ADDR' => '1.2.3.4',
      'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
    assert_equal '1.2.3.4', request.remote_ip
14

15 16 17
    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 已提交
18

19 20
    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,3.4.5.6'
    assert_equal '3.4.5.6', request.remote_ip
21

22 23
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '172.16.0.1,3.4.5.6'
    assert_equal '3.4.5.6', request.remote_ip
J
Jeremy Kemper 已提交
24

25 26
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,3.4.5.6'
    assert_equal '3.4.5.6', request.remote_ip
27

28 29
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '10.0.0.1,3.4.5.6'
    assert_equal '3.4.5.6', request.remote_ip
30

31 32
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '10.0.0.1, 10.0.0.1, 3.4.5.6'
    assert_equal '3.4.5.6', request.remote_ip
33

34 35
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '127.0.0.1,3.4.5.6'
    assert_equal '3.4.5.6', request.remote_ip
36

37 38
    request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1'
    assert_equal 'unknown', request.remote_ip
39

40 41
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4'
    assert_equal '3.4.5.6', request.remote_ip
42

43 44
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1',
                           'HTTP_CLIENT_IP'       => '2.2.2.2'
45
    e = assert_raise(ActionController::ActionControllerError) {
46
      request.remote_ip
J
Jeremy Kemper 已提交
47 48
    }
    assert_match /IP spoofing attack/, e.message
49 50
    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 已提交
51

52 53 54 55 56 57
    # 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.
    ActionController::Base.ip_spoofing_check = false
58 59 60
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1',
                           'HTTP_CLIENT_IP'       => '2.2.2.2'
    assert_equal '2.2.2.2', request.remote_ip
61 62
    ActionController::Base.ip_spoofing_check = true

63 64
    request = stub_request 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, 9.9.9.9'
    assert_equal '9.9.9.9', request.remote_ip
65 66
  end

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
  test "remote ip with user specified trusted proxies" do
    ActionController::Base.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

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

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

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

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

    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

    ActionController::Base.trusted_proxies = nil
  end

95
  test "domains" do
96 97
    request = stub_request 'HTTP_HOST' => 'www.rubyonrails.org'
    assert_equal "rubyonrails.org", request.domain
98

99 100
    request = stub_request 'HTTP_HOST' => "www.rubyonrails.co.uk"
    assert_equal "rubyonrails.co.uk", request.domain(2)
101

102 103
    request = stub_request 'HTTP_HOST' => "192.168.1.200"
    assert_nil request.domain
104

105 106
    request = stub_request 'HTTP_HOST' => "foo.192.168.1.200"
    assert_nil request.domain
107

108 109
    request = stub_request 'HTTP_HOST' => "192.168.1.200.com"
    assert_equal "200.com", request.domain
110 111
  end

112
  test "subdomains" do
113 114
    request = stub_request 'HTTP_HOST' => "www.rubyonrails.org"
    assert_equal %w( www ), request.subdomains
115

116 117
    request = stub_request 'HTTP_HOST' => "www.rubyonrails.co.uk"
    assert_equal %w( www ), request.subdomains(2)
118

119 120
    request = stub_request 'HTTP_HOST' => "dev.www.rubyonrails.co.uk"
    assert_equal %w( dev www ), request.subdomains(2)
121

122 123
    request = stub_request 'HTTP_HOST' => "foobar.foobar.com"
    assert_equal %w( foobar ), request.subdomains
124

125 126
    request = stub_request 'HTTP_HOST' => "192.168.1.200"
    assert_equal [], request.subdomains
127

128 129
    request = stub_request 'HTTP_HOST' => "foo.192.168.1.200"
    assert_equal [], request.subdomains
130

131 132
    request = stub_request 'HTTP_HOST' => "192.168.1.200.com"
    assert_equal %w( 192 168 1 ), request.subdomains
133

134 135
    request = stub_request 'HTTP_HOST' => nil
    assert_equal [], request.subdomains
136
  end
137

138
  test "port string" do
139 140
    request = stub_request 'HTTP_HOST' => 'www.example.org:80'
    assert_equal "", request.port_string
141

142 143
    request = stub_request 'HTTP_HOST' => 'www.example.org:8080'
    assert_equal ":8080", request.port_string
144
  end
145

146
  test "request uri" do
147
    request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/path/of/some/uri', 'QUERY_STRING' => 'mapped=1'
148 149
    assert_equal "/path/of/some/uri?mapped=1", request.request_uri
    assert_equal "/path/of/some/uri",          request.path
150

151
    request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/path/of/some/uri'
152 153
    assert_equal "/path/of/some/uri", request.request_uri
    assert_equal "/path/of/some/uri", request.path
154

155
    request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/'
156 157
    assert_equal "/", request.request_uri
    assert_equal "/", request.path
158

159
    request = stub_request 'SCRIPT_NAME' => '', 'PATH_INFO' => '/', 'QUERY_STRING' => 'm=b'
160 161
    assert_equal "/?m=b", request.request_uri
    assert_equal "/",     request.path
162

163
    request = stub_request 'SCRIPT_NAME' => '/hieraki', 'PATH_INFO' => '/'
164 165
    assert_equal "/hieraki/", request.request_uri
    assert_equal "/",         request.path
166

167
    request = stub_request 'SCRIPT_NAME' => '/collaboration/hieraki', 'PATH_INFO' => '/books/edit/2'
168 169
    assert_equal "/collaboration/hieraki/books/edit/2", request.request_uri
    assert_equal "/books/edit/2",                       request.path
170

171
    request = stub_request 'SCRIPT_NAME' => '/path', 'PATH_INFO' => '/of/some/uri', 'QUERY_STRING' => 'mapped=1'
172 173
    assert_equal "/path/of/some/uri?mapped=1", request.request_uri
    assert_equal "/of/some/uri",               request.path
174
  end
175

176

177
  test "host with default port" do
178 179
    request = stub_request 'HTTP_HOST' => 'rubyonrails.org:80'
    assert_equal "rubyonrails.org", request.host_with_port
180
  end
181

182
  test "host with non default port" do
183 184
    request = stub_request 'HTTP_HOST' => 'rubyonrails.org:81'
    assert_equal "rubyonrails.org:81", request.host_with_port
185
  end
186

187
  test "server software" do
188 189
    request = stub_request
    assert_equal nil, request.server_software
190

191 192
    request = stub_request 'SERVER_SOFTWARE' => 'Apache3.422'
    assert_equal 'apache', request.server_software
193

194 195
    request = stub_request 'SERVER_SOFTWARE' => 'lighttpd(1.1.4)'
    assert_equal 'lighttpd', request.server_software
196
  end
197

198
  test "xml http request" do
199 200 201 202
    request = stub_request

    assert !request.xml_http_request?
    assert !request.xhr?
203

204 205 206
    request = stub_request 'HTTP_X_REQUESTED_WITH' => 'DefinitelyNotAjax1.0'
    assert !request.xml_http_request?
    assert !request.xhr?
207

208 209 210
    request = stub_request 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'
    assert request.xml_http_request?
    assert request.xhr?
211
  end
212

213
  test "reports ssl" do
214 215 216 217 218
    request = stub_request
    assert !request.ssl?

    request = stub_request 'HTTPS' => 'on'
    assert request.ssl?
219 220
  end

221
  test "reports ssl when proxied via lighttpd" do
222 223 224 225 226
    request = stub_request
    assert !request.ssl?

    request = stub_request 'HTTP_X_FORWARDED_PROTO' => 'https'
    assert request.ssl?
227
  end
228

229
  test "symbolized request methods" do
230
    [:get, :post, :put, :delete].each do |method|
231 232
      request = stub_request 'REQUEST_METHOD' => method.to_s.upcase
      assert_equal method, request.method
233 234 235
    end
  end

236
  test "invalid http method raises exception" do
237
    assert_raise(ActionController::UnknownHttpMethod) do
238 239
      request = stub_request 'REQUEST_METHOD' => 'RANDOM_METHOD'
      request.request_method
240 241 242
    end
  end

243
  test "allow method hacking on post" do
244
    [:get, :options, :put, :post, :delete].each do |method|
245
      request = stub_request "REQUEST_METHOD" => method.to_s.upcase
246
      assert_equal(method == :head ? :get : method, request.method)
247 248 249
    end
  end

250
  test "invalid method hacking on post raises exception" do
251 252 253
    assert_raise(ActionController::UnknownHttpMethod) do
      request = stub_request "REQUEST_METHOD" => "_RANDOM_METHOD"
      request.request_method
254 255 256
    end
  end

257
  test "restrict method hacking" do
258
    [:get, :put, :delete].each do |method|
259
      request = stub_request 'REQUEST_METHOD' => method.to_s.upcase,
260
        'action_dispatch.request.request_parameters' => { :_method => 'put' }
261
      assert_equal method, request.method
262 263
    end
  end
264

265
  test "head masquerading as get" do
266
    request = stub_request 'REQUEST_METHOD' => 'GET', "rack.methodoverride.original_method" => "HEAD"
267 268 269
    assert_equal :get, request.method
    assert request.get?
    assert request.head?
270
  end
271

272
  test "xml format" do
273 274 275
    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => 'xml' })
    assert_equal Mime::XML, request.format
276
  end
277

278
  test "xhtml format" do
279 280 281
    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => 'xhtml' })
    assert_equal Mime::HTML, request.format
282
  end
283

284
  test "txt format" do
285 286 287
    request = stub_request
    request.expects(:parameters).at_least_once.returns({ :format => 'txt' })
    assert_equal Mime::TEXT, request.format
288
  end
289

290
  test "XMLHttpRequest" do
291 292 293 294 295 296
    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
297
  end
298

299
  test "content type" do
300 301
    request = stub_request 'CONTENT_TYPE' => 'text/html'
    assert_equal Mime::HTML, request.content_type
302 303
  end

304
  test "can override format with parameter" do
305 306 307 308 309 310 311
    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?
312 313
  end

314
  test "no content type" do
315 316
    request = stub_request
    assert_equal nil, request.content_type
317
  end
318

319
  test "content type is XML" do
320 321
    request = stub_request 'CONTENT_TYPE' => 'application/xml'
    assert_equal Mime::XML, request.content_type
322 323
  end

324
  test "content type with charset" do
325 326
    request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8'
    assert_equal Mime::XML, request.content_type
327
  end
328

329
  test "user agent" do
330 331
    request = stub_request 'HTTP_USER_AGENT' => 'TestAgent'
    assert_equal 'TestAgent', request.user_agent
332
  end
333

334
  test "parameters" do
335 336 337
    request = stub_request
    request.stubs(:request_parameters).returns({ "foo" => 1 })
    request.stubs(:query_parameters).returns({ "bar" => 2 })
338

339 340 341 342 343
    assert_equal({"foo" => 1, "bar" => 2}, request.parameters)
    assert_equal({"foo" => 1}, request.request_parameters)
    assert_equal({"bar" => 2}, request.query_parameters)
  end

344
  test "formats with accept header" do
345 346 347
    request = stub_request 'HTTP_ACCEPT' => 'text/html'
    request.expects(:parameters).at_least_once.returns({})
    assert_equal [ Mime::HTML ], request.formats
348

349 350 351 352 353 354 355 356
    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
357 358 359 360

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

  test "negotiate_mime" do
364 365 366 367 368 369 370 371 372 373 374 375 376
    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])
377
  end
378 379

  test "process parameter filter" do
380 381 382 383 384 385 386
    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'],
387
    [{'baz'=>[{'foo'=>'baz'}, "1"]}, {'baz'=>[{'foo'=>'[FILTERED]'}, "1"]}, [/foo/]]]
388 389

    test_hashes.each do |before_filter, after_filter, filter_words|
390
      request = stub_request('action_dispatch.parameter_filter' => filter_words)
391
      assert_equal after_filter, request.send(:process_parameter_filter, before_filter)
392

393 394
      filter_words << 'blah'
      filter_words << lambda { |key, value|
395
        value.reverse! if key =~ /bargain/
396
      }
397

398
      request = stub_request('action_dispatch.parameter_filter' => filter_words)
399
      before_filter['barg'] = {'bargain'=>'gain', 'blah'=>'bar', 'bar'=>{'bargain'=>{'blah'=>'foo'}}}
400
      after_filter['barg']  = {'bargain'=>'niag', 'blah'=>'[FILTERED]', 'bar'=>{'bargain'=>{'blah'=>'[FILTERED]'}}}
401

402
      assert_equal after_filter, request.send(:process_parameter_filter, before_filter)
403 404
    end
  end
405

406
  test "filtered_parameters returns params filtered" do
407 408 409
    request = stub_request('action_dispatch.request.parameters' =>
      { 'lifo' => 'Pratik', 'amount' => '420', 'step' => '1' },
      'action_dispatch.parameter_filter' => [:lifo, :amount])
410 411 412 413 414 415 416 417

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

422
    request = stub_request(request.filtered_env)
423 424 425 426 427 428

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

429 430
protected

431
  def stub_request(env = {})
432
    ActionDispatch::Request.new(env)
433
  end
434

435
  def with_set(*args)
436
    args
437 438
  end

439 440 441 442 443 444
  def with_accept_header(value)
    ActionController::Base.use_accept_header, old = value, ActionController::Base.use_accept_header
    yield
  ensure
    ActionController::Base.use_accept_header = old
  end
445
end