rack 0.3.0 → 0.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/AUTHORS +1 -0
- data/RDOX +61 -3
- data/README +94 -9
- data/Rakefile +36 -32
- data/SPEC +1 -7
- data/bin/rackup +31 -13
- data/lib/rack.rb +8 -19
- data/lib/rack/auth/digest/params.rb +2 -2
- data/lib/rack/auth/openid.rb +406 -80
- data/lib/rack/builder.rb +1 -1
- data/lib/rack/cascade.rb +10 -0
- data/lib/rack/commonlogger.rb +6 -1
- data/lib/rack/deflater.rb +63 -0
- data/lib/rack/directory.rb +158 -0
- data/lib/rack/file.rb +11 -5
- data/lib/rack/handler.rb +44 -0
- data/lib/rack/handler/evented_mongrel.rb +8 -0
- data/lib/rack/handler/fastcgi.rb +1 -0
- data/lib/rack/handler/mongrel.rb +21 -1
- data/lib/rack/lint.rb +20 -13
- data/lib/rack/mock.rb +1 -0
- data/lib/rack/request.rb +69 -2
- data/lib/rack/session/abstract/id.rb +140 -0
- data/lib/rack/session/memcache.rb +97 -0
- data/lib/rack/session/pool.rb +50 -59
- data/lib/rack/showstatus.rb +3 -1
- data/lib/rack/urlmap.rb +12 -12
- data/lib/rack/utils.rb +88 -9
- data/test/cgi/lighttpd.conf +1 -1
- data/test/cgi/test.fcgi +1 -2
- data/test/cgi/test.ru +2 -2
- data/test/spec_rack_auth_openid.rb +137 -0
- data/test/spec_rack_camping.rb +37 -33
- data/test/spec_rack_cascade.rb +15 -0
- data/test/spec_rack_cgi.rb +4 -3
- data/test/spec_rack_deflater.rb +70 -0
- data/test/spec_rack_directory.rb +56 -0
- data/test/spec_rack_fastcgi.rb +4 -3
- data/test/spec_rack_file.rb +11 -1
- data/test/spec_rack_handler.rb +24 -0
- data/test/spec_rack_lint.rb +19 -33
- data/test/spec_rack_mongrel.rb +71 -0
- data/test/spec_rack_request.rb +91 -1
- data/test/spec_rack_session_memcache.rb +132 -0
- data/test/spec_rack_session_pool.rb +48 -1
- data/test/spec_rack_showstatus.rb +5 -4
- data/test/spec_rack_urlmap.rb +60 -25
- data/test/spec_rack_utils.rb +118 -1
- data/test/testrequest.rb +3 -1
- metadata +67 -44
data/test/spec_rack_request.rb
CHANGED
@@ -16,6 +16,7 @@ context "Rack::Request" do
|
|
16
16
|
req.should.not.be.post
|
17
17
|
req.should.not.be.put
|
18
18
|
req.should.not.be.delete
|
19
|
+
req.should.not.be.head
|
19
20
|
|
20
21
|
req.script_name.should.equal ""
|
21
22
|
req.path_info.should.equal "/"
|
@@ -23,6 +24,9 @@ context "Rack::Request" do
|
|
23
24
|
|
24
25
|
req.host.should.equal "example.com"
|
25
26
|
req.port.should.equal 8080
|
27
|
+
|
28
|
+
req.content_length.should.be.nil
|
29
|
+
req.content_type.should.be.nil
|
26
30
|
end
|
27
31
|
|
28
32
|
specify "can figure out the correct host" do
|
@@ -46,12 +50,39 @@ context "Rack::Request" do
|
|
46
50
|
specify "can parse POST data" do
|
47
51
|
req = Rack::Request.new \
|
48
52
|
Rack::MockRequest.env_for("/?foo=quux", :input => "foo=bar&quux=bla")
|
53
|
+
req.content_type.should.be.nil
|
54
|
+
req.media_type.should.be.nil
|
49
55
|
req.query_string.should.equal "foo=quux"
|
50
56
|
req.GET.should.equal "foo" => "quux"
|
51
57
|
req.POST.should.equal "foo" => "bar", "quux" => "bla"
|
52
58
|
req.params.should.equal "foo" => "bar", "quux" => "bla"
|
53
59
|
end
|
54
60
|
|
61
|
+
specify "can parse POST data with explicit content type" do
|
62
|
+
req = Rack::Request.new \
|
63
|
+
Rack::MockRequest.env_for("/",
|
64
|
+
"CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
|
65
|
+
:input => "foo=bar&quux=bla")
|
66
|
+
req.content_type.should.equal 'application/x-www-form-urlencoded;foo=bar'
|
67
|
+
req.media_type.should.equal 'application/x-www-form-urlencoded'
|
68
|
+
req.media_type_params['foo'].should.equal 'bar'
|
69
|
+
req.POST.should.equal "foo" => "bar", "quux" => "bla"
|
70
|
+
req.params.should.equal "foo" => "bar", "quux" => "bla"
|
71
|
+
end
|
72
|
+
|
73
|
+
specify "does not parse POST data when media type is not form-data" do
|
74
|
+
req = Rack::Request.new \
|
75
|
+
Rack::MockRequest.env_for("/?foo=quux",
|
76
|
+
"CONTENT_TYPE" => 'text/plain;charset=utf-8',
|
77
|
+
:input => "foo=bar&quux=bla")
|
78
|
+
req.content_type.should.equal 'text/plain;charset=utf-8'
|
79
|
+
req.media_type.should.equal 'text/plain'
|
80
|
+
req.media_type_params['charset'].should.equal 'utf-8'
|
81
|
+
req.POST.should.be.empty
|
82
|
+
req.params.should.equal "foo" => "quux"
|
83
|
+
req.body.read.should.equal "foo=bar&quux=bla"
|
84
|
+
end
|
85
|
+
|
55
86
|
specify "can get value by key from params with #[]" do
|
56
87
|
req = Rack::Request.new \
|
57
88
|
Rack::MockRequest.env_for("?foo=quux")
|
@@ -189,6 +220,20 @@ context "Rack::Request" do
|
|
189
220
|
should.equal "/foo?foo"
|
190
221
|
end
|
191
222
|
|
223
|
+
specify "can handle multiple media type parameters" do
|
224
|
+
req = Rack::Request.new \
|
225
|
+
Rack::MockRequest.env_for("/",
|
226
|
+
"CONTENT_TYPE" => 'text/plain; foo=BAR,baz=bizzle dizzle;BLING=bam')
|
227
|
+
req.should.not.be.form_data
|
228
|
+
req.media_type_params.should.include 'foo'
|
229
|
+
req.media_type_params['foo'].should.equal 'BAR'
|
230
|
+
req.media_type_params.should.include 'baz'
|
231
|
+
req.media_type_params['baz'].should.equal 'bizzle dizzle'
|
232
|
+
req.media_type_params.should.not.include 'BLING'
|
233
|
+
req.media_type_params.should.include 'bling'
|
234
|
+
req.media_type_params['bling'].should.equal 'bam'
|
235
|
+
end
|
236
|
+
|
192
237
|
specify "can parse multipart form data" do
|
193
238
|
# Adapted from RFC 1867.
|
194
239
|
input = <<EOF
|
@@ -212,6 +257,12 @@ EOF
|
|
212
257
|
req.POST.should.include "fileupload"
|
213
258
|
req.POST.should.include "reply"
|
214
259
|
|
260
|
+
req.should.be.form_data
|
261
|
+
req.content_length.should.equal input.size
|
262
|
+
req.media_type.should.equal 'multipart/form-data'
|
263
|
+
req.media_type_params.should.include 'boundary'
|
264
|
+
req.media_type_params['boundary'].should.equal 'AaB03x'
|
265
|
+
|
215
266
|
req.POST["reply"].should.equal "yes"
|
216
267
|
|
217
268
|
f = req.POST["fileupload"]
|
@@ -283,10 +334,33 @@ EOF
|
|
283
334
|
lambda { req.POST }.should.raise(EOFError)
|
284
335
|
end
|
285
336
|
|
337
|
+
specify "should work around buggy 1.8.* Tempfile equality" do
|
338
|
+
input = <<EOF
|
339
|
+
--AaB03x\r
|
340
|
+
content-disposition: form-data; name="huge"; filename="huge"\r
|
341
|
+
\r
|
342
|
+
foo\r
|
343
|
+
--AaB03x--
|
344
|
+
EOF
|
345
|
+
|
346
|
+
rack_input = Tempfile.new("rackspec")
|
347
|
+
rack_input.write(input)
|
348
|
+
rack_input.rewind
|
349
|
+
|
350
|
+
req = Rack::Request.new Rack::MockRequest.env_for("/",
|
351
|
+
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
352
|
+
"CONTENT_LENGTH" => input.size,
|
353
|
+
:input => rack_input)
|
354
|
+
|
355
|
+
lambda {req.POST}.should.not.raise
|
356
|
+
lambda {req.POST}.should.blaming("input re-processed!").not.raise
|
357
|
+
end
|
358
|
+
|
286
359
|
specify "does conform to the Rack spec" do
|
287
360
|
app = lambda { |env|
|
288
361
|
content = Rack::Request.new(env).POST["file"].inspect
|
289
|
-
|
362
|
+
size = content.respond_to?(:bytesize) ? content.bytesize : content.size
|
363
|
+
[200, {"Content-Type" => "text/html", "Content-Length" => size.to_s}, content]
|
290
364
|
}
|
291
365
|
|
292
366
|
input = <<EOF
|
@@ -308,4 +382,20 @@ EOF
|
|
308
382
|
|
309
383
|
res.should.be.ok
|
310
384
|
end
|
385
|
+
|
386
|
+
specify "should parse Accept-Encoding correctly" do
|
387
|
+
parser = lambda do |x|
|
388
|
+
Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => x)).accept_encoding
|
389
|
+
end
|
390
|
+
|
391
|
+
parser.call(nil).should.equal([])
|
392
|
+
|
393
|
+
parser.call("compress, gzip").should.equal([["compress", 1.0], ["gzip", 1.0]])
|
394
|
+
parser.call("").should.equal([])
|
395
|
+
parser.call("*").should.equal([["*", 1.0]])
|
396
|
+
parser.call("compress;q=0.5, gzip;q=1.0").should.equal([["compress", 0.5], ["gzip", 1.0]])
|
397
|
+
parser.call("gzip;q=1.0, identity; q=0.5, *;q=0").should.equal([["gzip", 1.0], ["identity", 0.5], ["*", 0] ])
|
398
|
+
|
399
|
+
lambda { parser.call("gzip ; q=1.0") }.should.raise(RuntimeError)
|
400
|
+
end
|
311
401
|
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'test/spec'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rack/session/memcache'
|
5
|
+
require 'rack/mock'
|
6
|
+
require 'rack/response'
|
7
|
+
require 'thread'
|
8
|
+
|
9
|
+
context "Rack::Session::Memcache" do
|
10
|
+
incrementor = lambda { |env|
|
11
|
+
env["rack.session"]["counter"] ||= 0
|
12
|
+
env["rack.session"]["counter"] += 1
|
13
|
+
Rack::Response.new(env["rack.session"].inspect).to_a
|
14
|
+
}
|
15
|
+
|
16
|
+
# Keep this first.
|
17
|
+
specify "startup" do
|
18
|
+
$pid = fork {
|
19
|
+
exec "memcached"
|
20
|
+
}
|
21
|
+
sleep 1
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "faults on no connection" do
|
25
|
+
lambda do
|
26
|
+
Rack::Session::Memcache.new(incrementor, :memcache_server => '')
|
27
|
+
end.should.raise
|
28
|
+
end
|
29
|
+
|
30
|
+
specify "creates a new cookie" do
|
31
|
+
cache = Rack::Session::Memcache.new(incrementor)
|
32
|
+
res = Rack::MockRequest.new(cache).get("/")
|
33
|
+
res["Set-Cookie"].should.match("rack.session=")
|
34
|
+
res.body.should.equal '{"counter"=>1}'
|
35
|
+
end
|
36
|
+
|
37
|
+
specify "determines session from a cookie" do
|
38
|
+
cache = Rack::Session::Memcache.new(incrementor)
|
39
|
+
res = Rack::MockRequest.new(cache).get("/")
|
40
|
+
cookie = res["Set-Cookie"]
|
41
|
+
res = Rack::MockRequest.new(cache).get("/", "HTTP_COOKIE" => cookie)
|
42
|
+
res.body.should.equal '{"counter"=>2}'
|
43
|
+
res = Rack::MockRequest.new(cache).get("/", "HTTP_COOKIE" => cookie)
|
44
|
+
res.body.should.equal '{"counter"=>3}'
|
45
|
+
end
|
46
|
+
|
47
|
+
specify "survives broken cookies" do
|
48
|
+
cache = Rack::Session::Memcache.new(incrementor)
|
49
|
+
res = Rack::MockRequest.new(cache).
|
50
|
+
get("/", "HTTP_COOKIE" => "rack.session=blarghfasel")
|
51
|
+
res.body.should.equal '{"counter"=>1}'
|
52
|
+
end
|
53
|
+
|
54
|
+
specify "maintains freshness" do
|
55
|
+
cache = Rack::Session::Memcache.new(incrementor, :expire_after => 3)
|
56
|
+
res = Rack::MockRequest.new(cache).get('/')
|
57
|
+
res.body.should.include '"counter"=>1'
|
58
|
+
cookie = res["Set-Cookie"]
|
59
|
+
res = Rack::MockRequest.new(cache).get('/', "HTTP_COOKIE" => cookie)
|
60
|
+
res["Set-Cookie"].should.equal cookie
|
61
|
+
res.body.should.include '"counter"=>2'
|
62
|
+
puts 'Sleeping to expire session' if $DEBUG
|
63
|
+
sleep 4
|
64
|
+
res = Rack::MockRequest.new(cache).get('/', "HTTP_COOKIE" => cookie)
|
65
|
+
res["Set-Cookie"].should.not.equal cookie
|
66
|
+
res.body.should.include '"counter"=>1'
|
67
|
+
end
|
68
|
+
|
69
|
+
specify "multithread: should cleanly merge sessions" do
|
70
|
+
cache = Rack::Session::Memcache.new(incrementor)
|
71
|
+
drop_counter = Rack::Session::Memcache.new(proc do |env|
|
72
|
+
env['rack.session'].delete 'counter'
|
73
|
+
env['rack.session']['foo'] = 'bar'
|
74
|
+
[200, {'Content-Type'=>'text/plain'}, env['rack.session'].inspect]
|
75
|
+
end)
|
76
|
+
|
77
|
+
res = Rack::MockRequest.new(cache).get('/')
|
78
|
+
res.body.should.equal '{"counter"=>1}'
|
79
|
+
cookie = res["Set-Cookie"]
|
80
|
+
sess_id = cookie[/#{cache.key}=([^,;]+)/, 1]
|
81
|
+
|
82
|
+
res = Rack::MockRequest.new(cache).get('/', "HTTP_COOKIE" => cookie)
|
83
|
+
res.body.should.equal '{"counter"=>2}'
|
84
|
+
|
85
|
+
r = Array.new(rand(7).to_i+2) do |i|
|
86
|
+
app = proc do |env|
|
87
|
+
env['rack.session'][i] = Time.now
|
88
|
+
sleep 2
|
89
|
+
env['rack.session'] = env['rack.session'].dup
|
90
|
+
env['rack.session'][i] -= Time.now
|
91
|
+
incrementor.call(env)
|
92
|
+
end
|
93
|
+
Thread.new(cache.context(app)) do |run|
|
94
|
+
Rack::MockRequest.new(run).
|
95
|
+
get('/', "HTTP_COOKIE" => cookie, 'rack.multithread' => true)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
r.reverse!
|
100
|
+
|
101
|
+
r.map! do |t|
|
102
|
+
p t if $DEBUG
|
103
|
+
t.join.value
|
104
|
+
end
|
105
|
+
|
106
|
+
r.each do |res|
|
107
|
+
res['Set-Cookie'].should.equal cookie
|
108
|
+
res.body.should.include '"counter"=>3'
|
109
|
+
end
|
110
|
+
|
111
|
+
session = cache.pool[sess_id]
|
112
|
+
session.size.should.be r.size+1
|
113
|
+
session['counter'].should.be 3
|
114
|
+
|
115
|
+
res = Rack::MockRequest.new(drop_counter).get('/', "HTTP_COOKIE" => cookie)
|
116
|
+
res.body.should.include '"foo"=>"bar"'
|
117
|
+
|
118
|
+
session = cache.pool[sess_id]
|
119
|
+
session.size.should.be r.size+1
|
120
|
+
session['counter'].should.be.nil?
|
121
|
+
session['foo'].should.equal 'bar'
|
122
|
+
end
|
123
|
+
|
124
|
+
# Keep this last.
|
125
|
+
specify "shutdown" do
|
126
|
+
Process.kill 15, $pid
|
127
|
+
Process.wait($pid).should.equal $pid
|
128
|
+
end
|
129
|
+
end
|
130
|
+
rescue LoadError
|
131
|
+
$stderr.puts "Skipping Rack::Session::Memcache tests (Memcache is required). `gem install memcache-client` and try again."
|
132
|
+
end
|
@@ -3,6 +3,7 @@ require 'test/spec'
|
|
3
3
|
require 'rack/session/pool'
|
4
4
|
require 'rack/mock'
|
5
5
|
require 'rack/response'
|
6
|
+
require 'thread'
|
6
7
|
|
7
8
|
context "Rack::Session::Pool" do
|
8
9
|
incrementor = lambda { |env|
|
@@ -18,7 +19,7 @@ context "Rack::Session::Pool" do
|
|
18
19
|
res.body.should.equal '{"counter"=>1}'
|
19
20
|
end
|
20
21
|
|
21
|
-
specify "
|
22
|
+
specify "determines session from a cookie" do
|
22
23
|
pool = Rack::Session::Pool.new(incrementor)
|
23
24
|
res = Rack::MockRequest.new(pool).get("/")
|
24
25
|
cookie = res["Set-Cookie"]
|
@@ -34,4 +35,50 @@ context "Rack::Session::Pool" do
|
|
34
35
|
get("/", "HTTP_COOKIE" => "rack.session=blarghfasel")
|
35
36
|
res.body.should.equal '{"counter"=>1}'
|
36
37
|
end
|
38
|
+
|
39
|
+
specify "maintains freshness" do
|
40
|
+
pool = Rack::Session::Pool.new(incrementor, :expire_after => 3)
|
41
|
+
res = Rack::MockRequest.new(pool).get('/')
|
42
|
+
res.body.should.include '"counter"=>1'
|
43
|
+
cookie = res["Set-Cookie"]
|
44
|
+
res = Rack::MockRequest.new(pool).get('/', "HTTP_COOKIE" => cookie)
|
45
|
+
res["Set-Cookie"].should.equal cookie
|
46
|
+
res.body.should.include '"counter"=>2'
|
47
|
+
sleep 4
|
48
|
+
res = Rack::MockRequest.new(pool).get('/', "HTTP_COOKIE" => cookie)
|
49
|
+
res["Set-Cookie"].should.not.equal cookie
|
50
|
+
res.body.should.include '"counter"=>1'
|
51
|
+
end
|
52
|
+
|
53
|
+
specify "multithread: should merge sessions" do
|
54
|
+
delta_incrementor = lambda do |env|
|
55
|
+
# emulate disconjoinment of threading
|
56
|
+
env['rack.session'] = env['rack.session'].dup
|
57
|
+
Thread.stop
|
58
|
+
env['rack.session'][(Time.now.usec*rand).to_i] = true
|
59
|
+
incrementor.call(env)
|
60
|
+
end
|
61
|
+
pool = Rack::Session::Pool.new(incrementor)
|
62
|
+
res = Rack::MockRequest.new(pool).get('/')
|
63
|
+
res.body.should.equal '{"counter"=>1}'
|
64
|
+
cookie = res["Set-Cookie"]
|
65
|
+
sess_id = cookie[/#{pool.key}=([^,;]+)/,1]
|
66
|
+
|
67
|
+
pool = pool.context(delta_incrementor)
|
68
|
+
r = Array.new(rand(7).to_i+3).
|
69
|
+
map! do
|
70
|
+
Thread.new do
|
71
|
+
Rack::MockRequest.new(pool).get('/', "HTTP_COOKIE" => cookie)
|
72
|
+
end
|
73
|
+
end.
|
74
|
+
reverse!.
|
75
|
+
map!{|t| t.run.join.value }
|
76
|
+
session = pool.for.pool[sess_id] # for is needed by Utils::Context
|
77
|
+
session.size.should.be r.size+1 # counter
|
78
|
+
session['counter'].should.be 2 # meeeh
|
79
|
+
r.each do |res|
|
80
|
+
res['Set-Cookie'].should.equal cookie
|
81
|
+
res.body.should.include '"counter"=>2'
|
82
|
+
end
|
83
|
+
end
|
37
84
|
end
|
@@ -6,7 +6,7 @@ require 'rack/mock'
|
|
6
6
|
context "Rack::ShowStatus" do
|
7
7
|
specify "should provide a default status message" do
|
8
8
|
req = Rack::MockRequest.new(Rack::ShowStatus.new(lambda { |env|
|
9
|
-
[404, {"Content-Type" => "text/plain"}, []]
|
9
|
+
[404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, []]
|
10
10
|
}))
|
11
11
|
|
12
12
|
res = req.get("/", :lint => true)
|
@@ -21,7 +21,7 @@ context "Rack::ShowStatus" do
|
|
21
21
|
specify "should let the app provide additional information" do
|
22
22
|
req = Rack::MockRequest.new(Rack::ShowStatus.new(lambda { |env|
|
23
23
|
env["rack.showstatus.detail"] = "gone too meta."
|
24
|
-
[404, {"Content-Type" => "text/plain"}, []]
|
24
|
+
[404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, []]
|
25
25
|
}))
|
26
26
|
|
27
27
|
res = req.get("/", :lint => true)
|
@@ -36,7 +36,7 @@ context "Rack::ShowStatus" do
|
|
36
36
|
|
37
37
|
specify "should not replace existing messages" do
|
38
38
|
req = Rack::MockRequest.new(Rack::ShowStatus.new(lambda { |env|
|
39
|
-
[404, {"Content-Type" => "text/plain"}, ["foo!"]]
|
39
|
+
[404, {"Content-Type" => "text/plain", "Content-Length" => "4"}, ["foo!"]]
|
40
40
|
}))
|
41
41
|
res = req.get("/", :lint => true)
|
42
42
|
res.should.be.not_found
|
@@ -56,7 +56,7 @@ context "Rack::ShowStatus" do
|
|
56
56
|
specify "should replace existing messages if there is detail" do
|
57
57
|
req = Rack::MockRequest.new(Rack::ShowStatus.new(lambda { |env|
|
58
58
|
env["rack.showstatus.detail"] = "gone too meta."
|
59
|
-
[404, {"Content-Type" => "text/plain"}, ["foo!"]]
|
59
|
+
[404, {"Content-Type" => "text/plain", "Content-Length" => "4"}, ["foo!"]]
|
60
60
|
}))
|
61
61
|
|
62
62
|
res = req.get("/", :lint => true)
|
@@ -64,6 +64,7 @@ context "Rack::ShowStatus" do
|
|
64
64
|
res.should.be.not.empty
|
65
65
|
|
66
66
|
res["Content-Type"].should.equal("text/html")
|
67
|
+
res["Content-Length"].should.not.equal("4")
|
67
68
|
res.should =~ /404/
|
68
69
|
res.should =~ /too meta/
|
69
70
|
res.body.should.not =~ /foo/
|
data/test/spec_rack_urlmap.rb
CHANGED
@@ -5,47 +5,62 @@ require 'rack/mock'
|
|
5
5
|
|
6
6
|
context "Rack::URLMap" do
|
7
7
|
specify "dispatches paths correctly" do
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
}, [""]]}
|
21
|
-
|
22
|
-
)
|
8
|
+
app = lambda { |env|
|
9
|
+
[200, {
|
10
|
+
'X-ScriptName' => env['SCRIPT_NAME'],
|
11
|
+
'X-PathInfo' => env['PATH_INFO'],
|
12
|
+
'Content-Type' => 'text/plain'
|
13
|
+
}, [""]]
|
14
|
+
}
|
15
|
+
map = Rack::URLMap.new({
|
16
|
+
'http://foo.org/bar' => app,
|
17
|
+
'/foo' => app,
|
18
|
+
'/foo/bar' => app
|
19
|
+
})
|
23
20
|
|
21
|
+
res = Rack::MockRequest.new(map).get("/")
|
22
|
+
res.should.be.not_found
|
24
23
|
|
25
|
-
Rack::MockRequest.new(map).get("/")
|
24
|
+
res = Rack::MockRequest.new(map).get("/qux")
|
25
|
+
res.should.be.not_found
|
26
26
|
|
27
27
|
res = Rack::MockRequest.new(map).get("/foo")
|
28
28
|
res.should.be.ok
|
29
|
-
res["X-
|
29
|
+
res["X-ScriptName"].should.equal "/foo"
|
30
|
+
res["X-PathInfo"].should.equal ""
|
31
|
+
|
32
|
+
res = Rack::MockRequest.new(map).get("/foo/")
|
33
|
+
res.should.be.ok
|
34
|
+
res["X-ScriptName"].should.equal "/foo"
|
30
35
|
res["X-PathInfo"].should.equal "/"
|
31
36
|
|
37
|
+
res = Rack::MockRequest.new(map).get("/foo/bar")
|
38
|
+
res.should.be.ok
|
39
|
+
res["X-ScriptName"].should.equal "/foo/bar"
|
40
|
+
res["X-PathInfo"].should.equal ""
|
32
41
|
|
33
|
-
res = Rack::MockRequest.new(map).get("/bar")
|
42
|
+
res = Rack::MockRequest.new(map).get("/foo/bar/")
|
34
43
|
res.should.be.ok
|
35
|
-
res["X-
|
44
|
+
res["X-ScriptName"].should.equal "/foo/bar"
|
36
45
|
res["X-PathInfo"].should.equal "/"
|
37
46
|
|
38
|
-
res = Rack::MockRequest.new(map).get("/foo/quux")
|
47
|
+
res = Rack::MockRequest.new(map).get("/foo/quux", "SCRIPT_NAME" => "/bleh")
|
39
48
|
res.should.be.ok
|
40
|
-
res["X-
|
49
|
+
res["X-ScriptName"].should.equal "/bleh/foo"
|
41
50
|
res["X-PathInfo"].should.equal "/quux"
|
42
51
|
|
43
|
-
res = Rack::MockRequest.new(map).get("/
|
52
|
+
res = Rack::MockRequest.new(map).get("/bar", 'HTTP_HOST' => 'foo.org')
|
44
53
|
res.should.be.ok
|
45
|
-
res["X-
|
46
|
-
res["X-PathInfo"].should.
|
54
|
+
res["X-ScriptName"].should.equal "/bar"
|
55
|
+
res["X-PathInfo"].should.be.empty
|
56
|
+
|
57
|
+
res = Rack::MockRequest.new(map).get("/bar/", 'HTTP_HOST' => 'foo.org')
|
58
|
+
res.should.be.ok
|
59
|
+
res["X-ScriptName"].should.equal "/bar"
|
60
|
+
res["X-PathInfo"].should.equal '/'
|
47
61
|
end
|
48
62
|
|
63
|
+
|
49
64
|
specify "dispatches hosts correctly" do
|
50
65
|
map = Rack::URLMap.new("http://foo.org/" => lambda { |env|
|
51
66
|
[200,
|
@@ -112,7 +127,7 @@ context "Rack::URLMap" do
|
|
112
127
|
res = Rack::MockRequest.new(map).get("/foo/bar/quux")
|
113
128
|
res.should.be.ok
|
114
129
|
res["X-Position"].should.equal "/foo/bar/quux"
|
115
|
-
res["X-PathInfo"].should.equal "
|
130
|
+
res["X-PathInfo"].should.equal ""
|
116
131
|
res["X-ScriptName"].should.equal "/foo/bar/quux"
|
117
132
|
end
|
118
133
|
|
@@ -121,20 +136,40 @@ context "Rack::URLMap" do
|
|
121
136
|
[200,
|
122
137
|
{ "Content-Type" => "text/plain",
|
123
138
|
"X-Position" => "root",
|
139
|
+
"X-PathInfo" => env["PATH_INFO"],
|
140
|
+
"X-ScriptName" => env["SCRIPT_NAME"]
|
124
141
|
}, [""]]},
|
125
142
|
"/foo" => lambda { |env|
|
126
143
|
[200,
|
127
144
|
{ "Content-Type" => "text/plain",
|
128
145
|
"X-Position" => "foo",
|
146
|
+
"X-PathInfo" => env["PATH_INFO"],
|
147
|
+
"X-ScriptName" => env["SCRIPT_NAME"]
|
129
148
|
}, [""]]}
|
130
149
|
)
|
131
150
|
|
132
151
|
res = Rack::MockRequest.new(map).get("/foo/bar")
|
133
152
|
res.should.be.ok
|
134
153
|
res["X-Position"].should.equal "foo"
|
154
|
+
res["X-PathInfo"].should.equal "/bar"
|
155
|
+
res["X-ScriptName"].should.equal "/foo"
|
156
|
+
|
157
|
+
res = Rack::MockRequest.new(map).get("/foo")
|
158
|
+
res.should.be.ok
|
159
|
+
res["X-Position"].should.equal "foo"
|
160
|
+
res["X-PathInfo"].should.equal ""
|
161
|
+
res["X-ScriptName"].should.equal "/foo"
|
135
162
|
|
136
163
|
res = Rack::MockRequest.new(map).get("/bar")
|
137
164
|
res.should.be.ok
|
138
165
|
res["X-Position"].should.equal "root"
|
166
|
+
res["X-PathInfo"].should.equal "/bar"
|
167
|
+
res["X-ScriptName"].should.equal ""
|
168
|
+
|
169
|
+
res = Rack::MockRequest.new(map).get("")
|
170
|
+
res.should.be.ok
|
171
|
+
res["X-Position"].should.equal "root"
|
172
|
+
res["X-PathInfo"].should.equal "/"
|
173
|
+
res["X-ScriptName"].should.equal ""
|
139
174
|
end
|
140
175
|
end
|