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.

Files changed (50) hide show
  1. data/AUTHORS +1 -0
  2. data/RDOX +61 -3
  3. data/README +94 -9
  4. data/Rakefile +36 -32
  5. data/SPEC +1 -7
  6. data/bin/rackup +31 -13
  7. data/lib/rack.rb +8 -19
  8. data/lib/rack/auth/digest/params.rb +2 -2
  9. data/lib/rack/auth/openid.rb +406 -80
  10. data/lib/rack/builder.rb +1 -1
  11. data/lib/rack/cascade.rb +10 -0
  12. data/lib/rack/commonlogger.rb +6 -1
  13. data/lib/rack/deflater.rb +63 -0
  14. data/lib/rack/directory.rb +158 -0
  15. data/lib/rack/file.rb +11 -5
  16. data/lib/rack/handler.rb +44 -0
  17. data/lib/rack/handler/evented_mongrel.rb +8 -0
  18. data/lib/rack/handler/fastcgi.rb +1 -0
  19. data/lib/rack/handler/mongrel.rb +21 -1
  20. data/lib/rack/lint.rb +20 -13
  21. data/lib/rack/mock.rb +1 -0
  22. data/lib/rack/request.rb +69 -2
  23. data/lib/rack/session/abstract/id.rb +140 -0
  24. data/lib/rack/session/memcache.rb +97 -0
  25. data/lib/rack/session/pool.rb +50 -59
  26. data/lib/rack/showstatus.rb +3 -1
  27. data/lib/rack/urlmap.rb +12 -12
  28. data/lib/rack/utils.rb +88 -9
  29. data/test/cgi/lighttpd.conf +1 -1
  30. data/test/cgi/test.fcgi +1 -2
  31. data/test/cgi/test.ru +2 -2
  32. data/test/spec_rack_auth_openid.rb +137 -0
  33. data/test/spec_rack_camping.rb +37 -33
  34. data/test/spec_rack_cascade.rb +15 -0
  35. data/test/spec_rack_cgi.rb +4 -3
  36. data/test/spec_rack_deflater.rb +70 -0
  37. data/test/spec_rack_directory.rb +56 -0
  38. data/test/spec_rack_fastcgi.rb +4 -3
  39. data/test/spec_rack_file.rb +11 -1
  40. data/test/spec_rack_handler.rb +24 -0
  41. data/test/spec_rack_lint.rb +19 -33
  42. data/test/spec_rack_mongrel.rb +71 -0
  43. data/test/spec_rack_request.rb +91 -1
  44. data/test/spec_rack_session_memcache.rb +132 -0
  45. data/test/spec_rack_session_pool.rb +48 -1
  46. data/test/spec_rack_showstatus.rb +5 -4
  47. data/test/spec_rack_urlmap.rb +60 -25
  48. data/test/spec_rack_utils.rb +118 -1
  49. data/test/testrequest.rb +3 -1
  50. metadata +67 -44
@@ -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
- [200, {"Content-Type" => "text/html"}, content]
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 "loads from a cookie" do
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/
@@ -5,47 +5,62 @@ require 'rack/mock'
5
5
 
6
6
  context "Rack::URLMap" do
7
7
  specify "dispatches paths correctly" do
8
- map = Rack::URLMap.new("/foo" => lambda { |env|
9
- [200,
10
- { "Content-Type" => "text/plain",
11
- "X-Position" => "/foo",
12
- "X-PathInfo" => env["PATH_INFO"],
13
- }, [""]]},
14
-
15
- "/bar" => lambda { |env|
16
- [200,
17
- { "Content-Type" => "text/plain",
18
- "X-Position" => "/bar",
19
- "X-PathInfo" => env["PATH_INFO"],
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("/").should.be.not_found
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-Position"].should.equal "/foo"
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-Position"].should.equal "/bar"
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-Position"].should.equal "/foo"
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("/foo/quux", "SCRIPT_NAME" => "/bleh")
52
+ res = Rack::MockRequest.new(map).get("/bar", 'HTTP_HOST' => 'foo.org')
44
53
  res.should.be.ok
45
- res["X-Position"].should.equal "/foo"
46
- res["X-PathInfo"].should.equal "/quux"
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