rack 1.3.10 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- data/COPYING +1 -1
- data/KNOWN-ISSUES +0 -9
- data/README.rdoc +4 -118
- data/Rakefile +15 -0
- data/SPEC +3 -5
- data/lib/rack.rb +0 -12
- data/lib/rack/auth/abstract/request.rb +1 -5
- data/lib/rack/auth/basic.rb +1 -1
- data/lib/rack/auth/digest/nonce.rb +1 -1
- data/lib/rack/backports/uri/common_18.rb +28 -14
- data/lib/rack/backports/uri/common_192.rb +17 -14
- data/lib/rack/body_proxy.rb +0 -10
- data/lib/rack/builder.rb +26 -18
- data/lib/rack/cascade.rb +1 -12
- data/lib/rack/chunked.rb +2 -0
- data/lib/rack/content_type.rb +7 -1
- data/lib/rack/deflater.rb +1 -5
- data/lib/rack/directory.rb +5 -1
- data/lib/rack/file.rb +26 -9
- data/lib/rack/handler.rb +2 -2
- data/lib/rack/head.rb +0 -1
- data/lib/rack/lint.rb +3 -5
- data/lib/rack/methodoverride.rb +10 -4
- data/lib/rack/mime.rb +606 -171
- data/lib/rack/mock.rb +2 -1
- data/lib/rack/multipart.rb +2 -2
- data/lib/rack/multipart/parser.rb +3 -10
- data/lib/rack/reloader.rb +1 -1
- data/lib/rack/request.rb +45 -13
- data/lib/rack/response.rb +15 -14
- data/lib/rack/sendfile.rb +8 -6
- data/lib/rack/server.rb +4 -30
- data/lib/rack/session/abstract/id.rb +25 -6
- data/lib/rack/session/cookie.rb +12 -16
- data/lib/rack/static.rb +21 -8
- data/lib/rack/urlmap.rb +28 -13
- data/lib/rack/utils.rb +22 -28
- data/rack.gemspec +5 -5
- data/test/builder/end.ru +2 -0
- data/test/cgi/lighttpd.conf +1 -0
- data/test/cgi/sample_rackup.ru +1 -1
- data/test/cgi/test+directory/test+file +1 -0
- data/test/cgi/test.ru +1 -1
- data/test/gemloader.rb +6 -2
- data/test/spec_auth_basic.rb +4 -9
- data/test/spec_auth_digest.rb +3 -16
- data/test/spec_body_proxy.rb +0 -4
- data/test/spec_builder.rb +63 -20
- data/test/spec_cascade.rb +10 -13
- data/test/spec_cgi.rb +1 -1
- data/test/spec_chunked.rb +39 -12
- data/test/spec_commonlogger.rb +4 -3
- data/test/spec_conditionalget.rb +16 -12
- data/test/spec_content_length.rb +1 -1
- data/test/spec_content_type.rb +6 -0
- data/test/spec_deflater.rb +2 -2
- data/test/spec_directory.rb +12 -0
- data/test/spec_fastcgi.rb +1 -1
- data/test/spec_file.rb +58 -8
- data/test/spec_head.rb +6 -18
- data/test/spec_lint.rb +2 -2
- data/test/spec_methodoverride.rb +15 -0
- data/test/spec_mock.rb +6 -2
- data/test/spec_mongrel.rb +8 -8
- data/test/spec_multipart.rb +10 -63
- data/test/spec_request.rb +94 -21
- data/test/spec_response.rb +22 -24
- data/test/spec_sendfile.rb +3 -0
- data/test/spec_server.rb +2 -49
- data/test/spec_session_cookie.rb +58 -22
- data/test/spec_session_memcache.rb +31 -1
- data/test/spec_session_pool.rb +10 -4
- data/test/spec_static.rb +8 -0
- data/test/spec_thin.rb +2 -2
- data/test/spec_utils.rb +38 -35
- data/test/spec_webrick.rb +5 -3
- data/test/static/index.html +1 -0
- metadata +13 -18
- data/contrib/rack.png +0 -0
- data/contrib/rack.svg +0 -150
- data/lib/rack/backports/uri/common_193.rb +0 -29
- data/test/builder/line.ru +0 -1
- data/test/spec_auth.rb +0 -57
data/test/spec_head.rb
CHANGED
@@ -2,41 +2,29 @@ require 'rack/head'
|
|
2
2
|
require 'rack/mock'
|
3
3
|
|
4
4
|
describe Rack::Head do
|
5
|
-
|
6
5
|
def test_response(headers = {})
|
7
|
-
|
8
|
-
app = lambda do |env|
|
9
|
-
[200, {"Content-type" => "test/plain", "Content-length" => "3"}, body]
|
10
|
-
end
|
6
|
+
app = lambda { |env| [200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]] }
|
11
7
|
request = Rack::MockRequest.env_for("/", headers)
|
12
8
|
response = Rack::Head.new(app).call(request)
|
13
9
|
|
14
|
-
return response
|
10
|
+
return response
|
15
11
|
end
|
16
12
|
|
17
13
|
should "pass GET, POST, PUT, DELETE, OPTIONS, TRACE requests" do
|
18
14
|
%w[GET POST PUT DELETE OPTIONS TRACE].each do |type|
|
19
|
-
resp
|
15
|
+
resp = test_response("REQUEST_METHOD" => type)
|
20
16
|
|
21
17
|
resp[0].should.equal(200)
|
22
18
|
resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"})
|
23
|
-
resp[2].
|
19
|
+
resp[2].should.equal(["foo"])
|
24
20
|
end
|
25
21
|
end
|
26
22
|
|
27
23
|
should "remove body from HEAD requests" do
|
28
|
-
resp
|
29
|
-
|
30
|
-
resp[0].should.equal(200)
|
31
|
-
resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"})
|
32
|
-
resp[2].each { |b| flunk "body should be empty" }
|
33
|
-
end
|
24
|
+
resp = test_response("REQUEST_METHOD" => "HEAD")
|
34
25
|
|
35
|
-
should "close the body when it is removed" do
|
36
|
-
resp, body = test_response("REQUEST_METHOD" => "HEAD")
|
37
26
|
resp[0].should.equal(200)
|
38
27
|
resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"})
|
39
|
-
resp[2].
|
40
|
-
body.should.be.closed
|
28
|
+
resp[2].should.equal([])
|
41
29
|
end
|
42
30
|
end
|
data/test/spec_lint.rb
CHANGED
@@ -241,7 +241,7 @@ describe Rack::Lint do
|
|
241
241
|
}.should.raise(Rack::Lint::LintError).
|
242
242
|
message.should.match(/No Content-Type/)
|
243
243
|
|
244
|
-
[100, 101, 204, 304].each do |status|
|
244
|
+
[100, 101, 204, 205, 304].each do |status|
|
245
245
|
lambda {
|
246
246
|
Rack::Lint.new(lambda { |env|
|
247
247
|
[status, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
@@ -252,7 +252,7 @@ describe Rack::Lint do
|
|
252
252
|
end
|
253
253
|
|
254
254
|
should "notice content-length errors" do
|
255
|
-
[100, 101, 204, 304].each do |status|
|
255
|
+
[100, 101, 204, 205, 304].each do |status|
|
256
256
|
lambda {
|
257
257
|
Rack::Lint.new(lambda { |env|
|
258
258
|
[status, {"Content-length" => "0"}, []]
|
data/test/spec_methodoverride.rb
CHANGED
@@ -55,4 +55,19 @@ describe Rack::MethodOverride do
|
|
55
55
|
|
56
56
|
req.env["rack.methodoverride.original_method"].should.equal "POST"
|
57
57
|
end
|
58
|
+
|
59
|
+
should "not modify REQUEST_METHOD when given invalid multipart form data" do
|
60
|
+
input = <<EOF
|
61
|
+
--AaB03x\r
|
62
|
+
content-disposition: form-data; name="huge"; filename="huge"\r
|
63
|
+
EOF
|
64
|
+
env = Rack::MockRequest.env_for("/",
|
65
|
+
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
66
|
+
"CONTENT_LENGTH" => input.size,
|
67
|
+
:method => "POST", :input => input)
|
68
|
+
app = Rack::MethodOverride.new(lambda{|envx| Rack::Request.new(envx) })
|
69
|
+
req = app.call(env)
|
70
|
+
|
71
|
+
req.env["REQUEST_METHOD"].should.equal "POST"
|
72
|
+
end
|
58
73
|
end
|
data/test/spec_mock.rb
CHANGED
@@ -42,7 +42,7 @@ describe Rack::MockRequest do
|
|
42
42
|
env["mock.postdata"].should.be.empty
|
43
43
|
end
|
44
44
|
|
45
|
-
should "allow GET/POST/PUT/DELETE" do
|
45
|
+
should "allow GET/POST/PUT/DELETE/HEAD" do
|
46
46
|
res = Rack::MockRequest.new(app).get("", :input => "foo")
|
47
47
|
env = YAML.load(res.body)
|
48
48
|
env["REQUEST_METHOD"].should.equal "GET"
|
@@ -59,6 +59,10 @@ describe Rack::MockRequest do
|
|
59
59
|
env = YAML.load(res.body)
|
60
60
|
env["REQUEST_METHOD"].should.equal "DELETE"
|
61
61
|
|
62
|
+
res = Rack::MockRequest.new(app).head("", :input => "foo")
|
63
|
+
env = YAML.load(res.body)
|
64
|
+
env["REQUEST_METHOD"].should.equal "HEAD"
|
65
|
+
|
62
66
|
Rack::MockRequest.env_for("/", :method => "OPTIONS")["REQUEST_METHOD"].
|
63
67
|
should.equal "OPTIONS"
|
64
68
|
end
|
@@ -189,7 +193,7 @@ describe Rack::MockRequest do
|
|
189
193
|
should "call close on the original body object" do
|
190
194
|
called = false
|
191
195
|
body = Rack::BodyProxy.new(['hi']) { called = true }
|
192
|
-
capp = proc { |e| [200, {'Content-Type' => 'text/plain
|
196
|
+
capp = proc { |e| [200, {'Content-Type' => 'text/plain'}, body] }
|
193
197
|
called.should.equal false
|
194
198
|
Rack::MockRequest.new(capp).get('/', :lint => true)
|
195
199
|
called.should.equal true
|
data/test/spec_mongrel.rb
CHANGED
@@ -11,7 +11,7 @@ $tcp_cork_opts = nil
|
|
11
11
|
describe Rack::Handler::Mongrel do
|
12
12
|
extend TestRequest::Helpers
|
13
13
|
|
14
|
-
@server = Mongrel::HttpServer.new(@host='
|
14
|
+
@server = Mongrel::HttpServer.new(@host='127.0.0.1', @port=9201)
|
15
15
|
@server.register('/test',
|
16
16
|
Rack::Handler::Mongrel.new(Rack::Lint.new(TestRequest.new)))
|
17
17
|
@server.register('/stream',
|
@@ -31,7 +31,7 @@ describe Rack::Handler::Mongrel do
|
|
31
31
|
response["HTTP_VERSION"].should.equal "HTTP/1.1"
|
32
32
|
response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
|
33
33
|
response["SERVER_PORT"].should.equal "9201"
|
34
|
-
response["SERVER_NAME"].should.equal "
|
34
|
+
response["SERVER_NAME"].should.equal "127.0.0.1"
|
35
35
|
end
|
36
36
|
|
37
37
|
should "have rack headers" do
|
@@ -84,7 +84,7 @@ describe Rack::Handler::Mongrel do
|
|
84
84
|
should "provide a .run" do
|
85
85
|
block_ran = false
|
86
86
|
Thread.new {
|
87
|
-
Rack::Handler::Mongrel.run(lambda {}, {:Port => 9211}) { |server|
|
87
|
+
Rack::Handler::Mongrel.run(lambda {}, {:Host => '127.0.0.1', :Port => 9211}) { |server|
|
88
88
|
server.should.be.kind_of Mongrel::HttpServer
|
89
89
|
block_ran = true
|
90
90
|
}
|
@@ -97,7 +97,7 @@ describe Rack::Handler::Mongrel do
|
|
97
97
|
block_ran = false
|
98
98
|
Thread.new {
|
99
99
|
map = {'/'=>lambda{},'/foo'=>lambda{}}
|
100
|
-
Rack::Handler::Mongrel.run(map, :map => true, :Port => 9221) { |server|
|
100
|
+
Rack::Handler::Mongrel.run(map, :map => true, :Host => '127.0.0.1', :Port => 9221) { |server|
|
101
101
|
server.should.be.kind_of Mongrel::HttpServer
|
102
102
|
server.classifier.uris.size.should.equal 2
|
103
103
|
server.classifier.uris.should.not.include '/arf'
|
@@ -114,7 +114,7 @@ describe Rack::Handler::Mongrel do
|
|
114
114
|
block_ran = false
|
115
115
|
Thread.new {
|
116
116
|
map = Rack::URLMap.new({'/'=>lambda{},'/bar'=>lambda{}})
|
117
|
-
Rack::Handler::Mongrel.run(map, {:map => true, :Port => 9231}) { |server|
|
117
|
+
Rack::Handler::Mongrel.run(map, {:map => true, :Host => '127.0.0.1', :Port => 9231}) { |server|
|
118
118
|
server.should.be.kind_of Mongrel::HttpServer
|
119
119
|
server.classifier.uris.size.should.equal 2
|
120
120
|
server.classifier.uris.should.not.include '/arf'
|
@@ -134,12 +134,12 @@ describe Rack::Handler::Mongrel do
|
|
134
134
|
'/' => lambda{},
|
135
135
|
'/foo' => lambda{},
|
136
136
|
'/bar' => lambda{},
|
137
|
-
'http://
|
138
|
-
'http://
|
137
|
+
'http://127.0.0.1/' => lambda{},
|
138
|
+
'http://127.0.0.1/bar' => lambda{},
|
139
139
|
'http://falsehost/arf' => lambda{},
|
140
140
|
'http://falsehost/qux' => lambda{}
|
141
141
|
})
|
142
|
-
opt = {:map => true, :Port => 9241, :Host => '
|
142
|
+
opt = {:map => true, :Port => 9241, :Host => '127.0.0.1'}
|
143
143
|
Rack::Handler::Mongrel.run(map, opt) { |server|
|
144
144
|
server.should.be.kind_of Mongrel::HttpServer
|
145
145
|
server.classifier.uris.should.include '/'
|
data/test/spec_multipart.rb
CHANGED
@@ -48,59 +48,6 @@ describe Rack::Multipart do
|
|
48
48
|
params['profile']['bio'].should.include 'hello'
|
49
49
|
end
|
50
50
|
|
51
|
-
should "reject insanely long boundaries" do
|
52
|
-
# using a pipe since a tempfile can use up too much space
|
53
|
-
rd, wr = IO.pipe
|
54
|
-
|
55
|
-
# we only call rewind once at start, so make sure it succeeds
|
56
|
-
# and doesn't hit ESPIPE
|
57
|
-
def rd.rewind; end
|
58
|
-
wr.sync = true
|
59
|
-
|
60
|
-
# mock out length to make this pipe look like a Tempfile
|
61
|
-
def rd.length
|
62
|
-
1024 * 1024 * 8
|
63
|
-
end
|
64
|
-
|
65
|
-
# write to a pipe in a background thread, this will write a lot
|
66
|
-
# unless Rack (properly) shuts down the read end
|
67
|
-
thr = Thread.new do
|
68
|
-
begin
|
69
|
-
wr.write("--AaB03x")
|
70
|
-
|
71
|
-
# make the initial boundary a few gigs long
|
72
|
-
longer = "0123456789" * 1024 * 1024
|
73
|
-
(1024 * 1024).times { wr.write(longer) }
|
74
|
-
|
75
|
-
wr.write("\r\n")
|
76
|
-
wr.write('Content-Disposition: form-data; name="a"; filename="a.txt"')
|
77
|
-
wr.write("\r\n")
|
78
|
-
wr.write("Content-Type: text/plain\r\n")
|
79
|
-
wr.write("\r\na")
|
80
|
-
wr.write("--AaB03x--\r\n")
|
81
|
-
wr.close
|
82
|
-
rescue => err # this is EPIPE if Rack shuts us down
|
83
|
-
err
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
fixture = {
|
88
|
-
"CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
|
89
|
-
"CONTENT_LENGTH" => rd.length.to_s,
|
90
|
-
:input => rd,
|
91
|
-
}
|
92
|
-
|
93
|
-
env = Rack::MockRequest.env_for '/', fixture
|
94
|
-
lambda {
|
95
|
-
Rack::Multipart.parse_multipart(env)
|
96
|
-
}.should.raise(EOFError)
|
97
|
-
rd.close
|
98
|
-
|
99
|
-
err = thr.value
|
100
|
-
err.should.be.instance_of Errno::EPIPE
|
101
|
-
wr.close
|
102
|
-
end
|
103
|
-
|
104
51
|
should "parse multipart upload with text file" do
|
105
52
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
|
106
53
|
params = Rack::Multipart.parse_multipart(env)
|
@@ -348,24 +295,24 @@ describe Rack::Multipart do
|
|
348
295
|
message.should.equal "value must be a Hash"
|
349
296
|
end
|
350
297
|
|
351
|
-
|
298
|
+
it "can parse fields with a content type" do
|
352
299
|
data = <<-EOF
|
353
|
-
--
|
354
|
-
Content-
|
355
|
-
Content-
|
300
|
+
--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon\r
|
301
|
+
Content-Disposition: form-data; name="description"\r
|
302
|
+
Content-Type: text/plain"\r
|
356
303
|
\r
|
357
|
-
|
358
|
-
--
|
359
|
-
|
360
|
-
|
304
|
+
Very very blue\r
|
305
|
+
--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon--\r
|
306
|
+
EOF
|
361
307
|
options = {
|
362
|
-
"CONTENT_TYPE" => "multipart/form-data; boundary=
|
308
|
+
"CONTENT_TYPE" => "multipart/form-data; boundary=1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon",
|
363
309
|
"CONTENT_LENGTH" => data.length.to_s,
|
364
310
|
:input => StringIO.new(data)
|
365
311
|
}
|
366
312
|
env = Rack::MockRequest.env_for("/", options)
|
367
313
|
params = Rack::Utils::Multipart.parse_multipart(env)
|
368
314
|
|
369
|
-
params
|
315
|
+
params.should.equal({"description"=>"Very very blue"})
|
370
316
|
end
|
317
|
+
|
371
318
|
end
|
data/test/spec_request.rb
CHANGED
@@ -359,13 +359,17 @@ describe Rack::Request do
|
|
359
359
|
request.scheme.should.equal "https"
|
360
360
|
request.should.be.ssl?
|
361
361
|
|
362
|
+
request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_SCHEME' => 'https'))
|
363
|
+
request.scheme.should.equal "https"
|
364
|
+
request.should.be.ssl?
|
365
|
+
|
362
366
|
request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_PROTO' => 'https'))
|
363
367
|
request.scheme.should.equal "https"
|
364
368
|
request.should.be.ssl?
|
365
369
|
|
366
370
|
request = Rack::Request.new(Rack::MockRequest.env_for("/", 'HTTP_X_FORWARDED_PROTO' => 'https, http, http'))
|
367
371
|
request.scheme.should.equal "https"
|
368
|
-
request.should.be.ssl
|
372
|
+
request.should.be.ssl?
|
369
373
|
end
|
370
374
|
|
371
375
|
should "parse cookies" do
|
@@ -383,6 +387,15 @@ describe Rack::Request do
|
|
383
387
|
hash = req.cookies
|
384
388
|
req.env.delete("HTTP_COOKIE")
|
385
389
|
req.cookies.should.equal(hash)
|
390
|
+
req.env["HTTP_COOKIE"] = "zoo=m"
|
391
|
+
req.cookies.should.equal(hash)
|
392
|
+
end
|
393
|
+
|
394
|
+
should "modify the cookies hash in place" do
|
395
|
+
req = Rack::Request.new(Rack::MockRequest.env_for(""))
|
396
|
+
req.cookies.should.equal({})
|
397
|
+
req.cookies['foo'] = 'bar'
|
398
|
+
req.cookies.should.equal 'foo' => 'bar'
|
386
399
|
end
|
387
400
|
|
388
401
|
should "raise any errors on every request" do
|
@@ -774,38 +787,98 @@ EOF
|
|
774
787
|
parser.call("compress;q=0.5, gzip;q=1.0").should.equal([["compress", 0.5], ["gzip", 1.0]])
|
775
788
|
parser.call("gzip;q=1.0, identity; q=0.5, *;q=0").should.equal([["gzip", 1.0], ["identity", 0.5], ["*", 0] ])
|
776
789
|
|
777
|
-
|
790
|
+
parser.call("gzip ; q=0.9").should.equal([["gzip", 0.9]])
|
791
|
+
parser.call("gzip ; deflate").should.equal([["gzip", 1.0]])
|
778
792
|
end
|
779
793
|
|
794
|
+
ip_app = lambda { |env|
|
795
|
+
request = Rack::Request.new(env)
|
796
|
+
response = Rack::Response.new
|
797
|
+
response.write request.ip
|
798
|
+
response.finish
|
799
|
+
}
|
800
|
+
|
780
801
|
should 'provide ip information' do
|
781
|
-
|
782
|
-
request = Rack::Request.new(env)
|
783
|
-
response = Rack::Response.new
|
784
|
-
response.write request.ip
|
785
|
-
response.finish
|
786
|
-
}
|
802
|
+
mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
|
787
803
|
|
788
|
-
|
789
|
-
res
|
790
|
-
res.body.should.equal '123.123.123.123'
|
804
|
+
res = mock.get '/', 'REMOTE_ADDR' => '1.2.3.4'
|
805
|
+
res.body.should.equal '1.2.3.4'
|
791
806
|
|
792
|
-
res = mock.get '/',
|
793
|
-
|
794
|
-
|
807
|
+
res = mock.get '/', 'REMOTE_ADDR' => 'fe80::202:b3ff:fe1e:8329'
|
808
|
+
res.body.should.equal 'fe80::202:b3ff:fe1e:8329'
|
809
|
+
|
810
|
+
res = mock.get '/', 'REMOTE_ADDR' => '1.2.3.4,3.4.5.6'
|
811
|
+
res.body.should.equal '1.2.3.4'
|
812
|
+
end
|
795
813
|
|
796
|
-
|
814
|
+
should 'deals with proxies' do
|
815
|
+
mock = Rack::MockRequest.new(Rack::Lint.new(ip_app))
|
797
816
|
|
798
817
|
res = mock.get '/',
|
799
|
-
'REMOTE_ADDR' => '
|
800
|
-
'HTTP_X_FORWARDED_FOR' => '
|
818
|
+
'REMOTE_ADDR' => '1.2.3.4',
|
819
|
+
'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
|
820
|
+
res.body.should.equal '1.2.3.4'
|
801
821
|
|
802
|
-
res.
|
822
|
+
res = mock.get '/',
|
823
|
+
'REMOTE_ADDR' => '127.0.0.1',
|
824
|
+
'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
|
825
|
+
res.body.should.equal '3.4.5.6'
|
826
|
+
|
827
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,3.4.5.6'
|
828
|
+
res.body.should.equal '3.4.5.6'
|
829
|
+
|
830
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,3.4.5.6'
|
831
|
+
res.body.should.equal '3.4.5.6'
|
832
|
+
|
833
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '10.0.0.1,3.4.5.6'
|
834
|
+
res.body.should.equal '3.4.5.6'
|
835
|
+
|
836
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '10.0.0.1, 10.0.0.1, 3.4.5.6'
|
837
|
+
res.body.should.equal '3.4.5.6'
|
838
|
+
|
839
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '127.0.0.1, 3.4.5.6'
|
840
|
+
res.body.should.equal '3.4.5.6'
|
841
|
+
|
842
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1'
|
843
|
+
res.body.should.equal 'unknown'
|
844
|
+
|
845
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'other,unknown,192.168.0.1'
|
846
|
+
res.body.should.equal 'unknown'
|
847
|
+
|
848
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'unknown,localhost,192.168.0.1'
|
849
|
+
res.body.should.equal 'unknown'
|
803
850
|
|
851
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4'
|
852
|
+
res.body.should.equal '3.4.5.6'
|
853
|
+
|
854
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '::1,2620:0:1c00:0:812c:9583:754b:ca11'
|
855
|
+
res.body.should.equal '2620:0:1c00:0:812c:9583:754b:ca11'
|
856
|
+
|
857
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '2620:0:1c00:0:812c:9583:754b:ca11,::1'
|
858
|
+
res.body.should.equal '2620:0:1c00:0:812c:9583:754b:ca11'
|
859
|
+
|
860
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => 'fd5b:982e:9130:247f:0000:0000:0000:0000,2620:0:1c00:0:812c:9583:754b:ca11'
|
861
|
+
res.body.should.equal '2620:0:1c00:0:812c:9583:754b:ca11'
|
862
|
+
|
863
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '2620:0:1c00:0:812c:9583:754b:ca11,fd5b:982e:9130:247f:0000:0000:0000:0000'
|
864
|
+
res.body.should.equal '2620:0:1c00:0:812c:9583:754b:ca11'
|
865
|
+
|
866
|
+
res = mock.get '/',
|
867
|
+
'HTTP_X_FORWARDED_FOR' => '1.1.1.1, 127.0.0.1',
|
868
|
+
'HTTP_CLIENT_IP' => '1.1.1.1'
|
869
|
+
res.body.should.equal '1.1.1.1'
|
870
|
+
|
871
|
+
# Spoofing attempt
|
804
872
|
res = mock.get '/',
|
805
|
-
'
|
806
|
-
'
|
873
|
+
'HTTP_X_FORWARDED_FOR' => '1.1.1.1',
|
874
|
+
'HTTP_CLIENT_IP' => '2.2.2.2'
|
875
|
+
res.body.should.equal '1.1.1.1'
|
876
|
+
|
877
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, 9.9.9.9'
|
878
|
+
res.body.should.equal '9.9.9.9'
|
807
879
|
|
808
|
-
res.
|
880
|
+
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, fe80::202:b3ff:fe1e:8329'
|
881
|
+
res.body.should.equal 'fe80::202:b3ff:fe1e:8329'
|
809
882
|
end
|
810
883
|
|
811
884
|
class MyRequest < Rack::Request
|
data/test/spec_response.rb
CHANGED
@@ -109,6 +109,18 @@ describe Rack::Response do
|
|
109
109
|
"foo=; domain=sample.example.com; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
|
110
110
|
end
|
111
111
|
|
112
|
+
it "can delete cookies with the same name with different paths" do
|
113
|
+
response = Rack::Response.new
|
114
|
+
response.set_cookie "foo", {:value => "bar", :path => "/"}
|
115
|
+
response.set_cookie "foo", {:value => "bar", :path => "/path"}
|
116
|
+
response["Set-Cookie"].should.equal ["foo=bar; path=/",
|
117
|
+
"foo=bar; path=/path"].join("\n")
|
118
|
+
|
119
|
+
response.delete_cookie "foo", :path => "/path"
|
120
|
+
response["Set-Cookie"].should.equal ["foo=bar; path=/",
|
121
|
+
"foo=; path=/path; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
|
122
|
+
end
|
123
|
+
|
112
124
|
it "can do redirects" do
|
113
125
|
response = Rack::Response.new
|
114
126
|
response.redirect "/foo"
|
@@ -196,11 +208,21 @@ describe Rack::Response do
|
|
196
208
|
res.should.be.successful
|
197
209
|
res.should.be.ok
|
198
210
|
|
211
|
+
res.status = 400
|
212
|
+
res.should.not.be.successful
|
213
|
+
res.should.be.client_error
|
214
|
+
res.should.be.bad_request
|
215
|
+
|
199
216
|
res.status = 404
|
200
217
|
res.should.not.be.successful
|
201
218
|
res.should.be.client_error
|
202
219
|
res.should.be.not_found
|
203
220
|
|
221
|
+
res.status = 422
|
222
|
+
res.should.not.be.successful
|
223
|
+
res.should.be.client_error
|
224
|
+
res.should.be.unprocessable
|
225
|
+
|
204
226
|
res.status = 501
|
205
227
|
res.should.not.be.successful
|
206
228
|
res.should.be.server_error
|
@@ -250,28 +272,4 @@ describe Rack::Response do
|
|
250
272
|
res.close
|
251
273
|
res.body.should.be.closed
|
252
274
|
end
|
253
|
-
|
254
|
-
it "calls close on #body when 204, 205, or 304" do
|
255
|
-
res = Rack::Response.new
|
256
|
-
res.body = StringIO.new
|
257
|
-
res.finish
|
258
|
-
res.body.should.not.be.closed
|
259
|
-
|
260
|
-
res.status = 204
|
261
|
-
_, _, b = res.finish
|
262
|
-
res.body.should.be.closed
|
263
|
-
b.should.not == res.body
|
264
|
-
|
265
|
-
res.body = StringIO.new
|
266
|
-
res.status = 304
|
267
|
-
_, _, b = res.finish
|
268
|
-
res.body.should.be.closed
|
269
|
-
b.should.not == res.body
|
270
|
-
end
|
271
|
-
|
272
|
-
it "wraps the body from #to_ary to prevent infinite loops" do
|
273
|
-
res = Rack::Response.new
|
274
|
-
res.finish.last.should.not.respond_to?(:to_ary)
|
275
|
-
lambda { res.finish.last.to_ary }.should.raise(NoMethodError)
|
276
|
-
end
|
277
275
|
end
|