kastner-rack 0.3.171

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. data/AUTHORS +8 -0
  2. data/COPYING +18 -0
  3. data/KNOWN-ISSUES +18 -0
  4. data/README +273 -0
  5. data/Rakefile +185 -0
  6. data/bin/rackup +172 -0
  7. data/contrib/rack_logo.svg +111 -0
  8. data/example/lobster.ru +4 -0
  9. data/example/protectedlobster.rb +14 -0
  10. data/example/protectedlobster.ru +8 -0
  11. data/lib/rack.rb +85 -0
  12. data/lib/rack/adapter/camping.rb +22 -0
  13. data/lib/rack/auth/abstract/handler.rb +28 -0
  14. data/lib/rack/auth/abstract/request.rb +37 -0
  15. data/lib/rack/auth/basic.rb +58 -0
  16. data/lib/rack/auth/digest/md5.rb +124 -0
  17. data/lib/rack/auth/digest/nonce.rb +51 -0
  18. data/lib/rack/auth/digest/params.rb +55 -0
  19. data/lib/rack/auth/digest/request.rb +40 -0
  20. data/lib/rack/auth/openid.rb +437 -0
  21. data/lib/rack/builder.rb +67 -0
  22. data/lib/rack/cascade.rb +36 -0
  23. data/lib/rack/commonlogger.rb +61 -0
  24. data/lib/rack/conditionalget.rb +42 -0
  25. data/lib/rack/deflater.rb +63 -0
  26. data/lib/rack/directory.rb +149 -0
  27. data/lib/rack/file.rb +84 -0
  28. data/lib/rack/handler.rb +46 -0
  29. data/lib/rack/handler/cgi.rb +57 -0
  30. data/lib/rack/handler/evented_mongrel.rb +8 -0
  31. data/lib/rack/handler/fastcgi.rb +86 -0
  32. data/lib/rack/handler/lsws.rb +52 -0
  33. data/lib/rack/handler/mongrel.rb +78 -0
  34. data/lib/rack/handler/scgi.rb +57 -0
  35. data/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
  36. data/lib/rack/handler/webrick.rb +61 -0
  37. data/lib/rack/head.rb +19 -0
  38. data/lib/rack/lint.rb +463 -0
  39. data/lib/rack/lobster.rb +65 -0
  40. data/lib/rack/methodoverride.rb +21 -0
  41. data/lib/rack/mime.rb +204 -0
  42. data/lib/rack/mock.rb +160 -0
  43. data/lib/rack/recursive.rb +57 -0
  44. data/lib/rack/reloader.rb +64 -0
  45. data/lib/rack/request.rb +217 -0
  46. data/lib/rack/response.rb +171 -0
  47. data/lib/rack/session/abstract/id.rb +140 -0
  48. data/lib/rack/session/cookie.rb +89 -0
  49. data/lib/rack/session/memcache.rb +97 -0
  50. data/lib/rack/session/pool.rb +73 -0
  51. data/lib/rack/showexceptions.rb +348 -0
  52. data/lib/rack/showstatus.rb +105 -0
  53. data/lib/rack/static.rb +38 -0
  54. data/lib/rack/urlmap.rb +48 -0
  55. data/lib/rack/utils.rb +318 -0
  56. data/rack.gemspec +31 -0
  57. data/test/cgi/lighttpd.conf +20 -0
  58. data/test/cgi/test +9 -0
  59. data/test/cgi/test.fcgi +8 -0
  60. data/test/cgi/test.ru +7 -0
  61. data/test/spec_rack_auth_basic.rb +69 -0
  62. data/test/spec_rack_auth_digest.rb +169 -0
  63. data/test/spec_rack_auth_openid.rb +137 -0
  64. data/test/spec_rack_builder.rb +84 -0
  65. data/test/spec_rack_camping.rb +51 -0
  66. data/test/spec_rack_cascade.rb +50 -0
  67. data/test/spec_rack_cgi.rb +89 -0
  68. data/test/spec_rack_commonlogger.rb +32 -0
  69. data/test/spec_rack_conditionalget.rb +41 -0
  70. data/test/spec_rack_deflater.rb +70 -0
  71. data/test/spec_rack_directory.rb +56 -0
  72. data/test/spec_rack_fastcgi.rb +89 -0
  73. data/test/spec_rack_file.rb +57 -0
  74. data/test/spec_rack_handler.rb +24 -0
  75. data/test/spec_rack_head.rb +30 -0
  76. data/test/spec_rack_lint.rb +371 -0
  77. data/test/spec_rack_lobster.rb +45 -0
  78. data/test/spec_rack_methodoverride.rb +31 -0
  79. data/test/spec_rack_mock.rb +152 -0
  80. data/test/spec_rack_mongrel.rb +170 -0
  81. data/test/spec_rack_recursive.rb +77 -0
  82. data/test/spec_rack_request.rb +426 -0
  83. data/test/spec_rack_response.rb +173 -0
  84. data/test/spec_rack_session_cookie.rb +78 -0
  85. data/test/spec_rack_session_memcache.rb +132 -0
  86. data/test/spec_rack_session_pool.rb +84 -0
  87. data/test/spec_rack_showexceptions.rb +21 -0
  88. data/test/spec_rack_showstatus.rb +72 -0
  89. data/test/spec_rack_static.rb +37 -0
  90. data/test/spec_rack_urlmap.rb +175 -0
  91. data/test/spec_rack_utils.rb +174 -0
  92. data/test/spec_rack_webrick.rb +123 -0
  93. data/test/testrequest.rb +45 -0
  94. metadata +177 -0
@@ -0,0 +1,78 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/session/cookie'
4
+ require 'rack/mock'
5
+ require 'rack/response'
6
+
7
+ context "Rack::Session::Cookie" do
8
+ incrementor = lambda { |env|
9
+ env["rack.session"]["counter"] ||= 0
10
+ env["rack.session"]["counter"] += 1
11
+ Rack::Response.new(env["rack.session"].inspect).to_a
12
+ }
13
+
14
+ specify "creates a new cookie" do
15
+ res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).get("/")
16
+ res["Set-Cookie"].should.match("rack.session=")
17
+ res.body.should.equal '{"counter"=>1}'
18
+ end
19
+
20
+ specify "loads from a cookie" do
21
+ res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).get("/")
22
+ cookie = res["Set-Cookie"]
23
+ res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).
24
+ get("/", "HTTP_COOKIE" => cookie)
25
+ res.body.should.equal '{"counter"=>2}'
26
+ cookie = res["Set-Cookie"]
27
+ res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).
28
+ get("/", "HTTP_COOKIE" => cookie)
29
+ res.body.should.equal '{"counter"=>3}'
30
+ end
31
+
32
+ specify "survives broken cookies" do
33
+ res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).
34
+ get("/", "HTTP_COOKIE" => "rack.session=blarghfasel")
35
+ res.body.should.equal '{"counter"=>1}'
36
+ end
37
+
38
+ bigcookie = lambda { |env|
39
+ env["rack.session"]["cookie"] = "big" * 3000
40
+ Rack::Response.new(env["rack.session"].inspect).to_a
41
+ }
42
+
43
+ specify "barks on too big cookies" do
44
+ lambda {
45
+ Rack::MockRequest.new(Rack::Session::Cookie.new(bigcookie)).
46
+ get("/", :fatal => true)
47
+ }.should.raise(Rack::MockRequest::FatalWarning)
48
+ end
49
+
50
+ specify "creates a new cookie with integrity hash" do
51
+ res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).get("/")
52
+ res["Set-Cookie"].should.match("rack.session=BAh7BiIMY291bnRlcmkG%0A--1439b4d37b9d4b04c603848382f712d6fcd31088")
53
+ end
54
+
55
+ specify "loads from a cookie wih integrity hash" do
56
+ res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).get("/")
57
+ cookie = res["Set-Cookie"]
58
+ res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).
59
+ get("/", "HTTP_COOKIE" => cookie)
60
+ res.body.should.equal '{"counter"=>2}'
61
+ cookie = res["Set-Cookie"]
62
+ res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).
63
+ get("/", "HTTP_COOKIE" => cookie)
64
+ res.body.should.equal '{"counter"=>3}'
65
+ end
66
+
67
+ specify "ignores tampered with session cookies" do
68
+ app = Rack::Session::Cookie.new(incrementor, :secret => 'test')
69
+ response1 = Rack::MockRequest.new(app).get("/")
70
+ _, digest = response1["Set-Cookie"].split("--")
71
+ tampered_with_cookie = "hackerman-was-here" + "--" + digest
72
+ response2 = Rack::MockRequest.new(app).get("/", "HTTP_COOKIE" =>
73
+ tampered_with_cookie)
74
+
75
+ # The tampered-with cookie is ignored, so we get back an identical Set-Cookie
76
+ response2["Set-Cookie"].should.equal(response1["Set-Cookie"])
77
+ end
78
+ 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
@@ -0,0 +1,84 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/session/pool'
4
+ require 'rack/mock'
5
+ require 'rack/response'
6
+ require 'thread'
7
+
8
+ context "Rack::Session::Pool" do
9
+ incrementor = lambda { |env|
10
+ env["rack.session"]["counter"] ||= 0
11
+ env["rack.session"]["counter"] += 1
12
+ Rack::Response.new(env["rack.session"].inspect).to_a
13
+ }
14
+
15
+ specify "creates a new cookie" do
16
+ pool = Rack::Session::Pool.new(incrementor)
17
+ res = Rack::MockRequest.new(pool).get("/")
18
+ res["Set-Cookie"].should.match("rack.session=")
19
+ res.body.should.equal '{"counter"=>1}'
20
+ end
21
+
22
+ specify "determines session from a cookie" do
23
+ pool = Rack::Session::Pool.new(incrementor)
24
+ res = Rack::MockRequest.new(pool).get("/")
25
+ cookie = res["Set-Cookie"]
26
+ res = Rack::MockRequest.new(pool).get("/", "HTTP_COOKIE" => cookie)
27
+ res.body.should.equal '{"counter"=>2}'
28
+ res = Rack::MockRequest.new(pool).get("/", "HTTP_COOKIE" => cookie)
29
+ res.body.should.equal '{"counter"=>3}'
30
+ end
31
+
32
+ specify "survives broken cookies" do
33
+ pool = Rack::Session::Pool.new(incrementor)
34
+ res = Rack::MockRequest.new(pool).
35
+ get("/", "HTTP_COOKIE" => "rack.session=blarghfasel")
36
+ res.body.should.equal '{"counter"=>1}'
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
84
+ end
@@ -0,0 +1,21 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/showexceptions'
4
+ require 'rack/mock'
5
+
6
+ context "Rack::ShowExceptions" do
7
+ specify "catches exceptions" do
8
+ res = nil
9
+ req = Rack::MockRequest.new(Rack::ShowExceptions.new(lambda { |env|
10
+ raise RuntimeError
11
+ }))
12
+ lambda {
13
+ res = req.get("/")
14
+ }.should.not.raise
15
+ res.should.be.a.server_error
16
+ res.status.should.equal 500
17
+
18
+ res.should =~ /RuntimeError/
19
+ res.should =~ /ShowExceptions/
20
+ end
21
+ end
@@ -0,0 +1,72 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/showstatus'
4
+ require 'rack/mock'
5
+
6
+ context "Rack::ShowStatus" do
7
+ specify "should provide a default status message" do
8
+ req = Rack::MockRequest.new(Rack::ShowStatus.new(lambda { |env|
9
+ [404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, []]
10
+ }))
11
+
12
+ res = req.get("/", :lint => true)
13
+ res.should.be.not_found
14
+ res.should.be.not.empty
15
+
16
+ res["Content-Type"].should.equal("text/html")
17
+ res.should =~ /404/
18
+ res.should =~ /Not Found/
19
+ end
20
+
21
+ specify "should let the app provide additional information" do
22
+ req = Rack::MockRequest.new(Rack::ShowStatus.new(lambda { |env|
23
+ env["rack.showstatus.detail"] = "gone too meta."
24
+ [404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, []]
25
+ }))
26
+
27
+ res = req.get("/", :lint => true)
28
+ res.should.be.not_found
29
+ res.should.be.not.empty
30
+
31
+ res["Content-Type"].should.equal("text/html")
32
+ res.should =~ /404/
33
+ res.should =~ /Not Found/
34
+ res.should =~ /too meta/
35
+ end
36
+
37
+ specify "should not replace existing messages" do
38
+ req = Rack::MockRequest.new(Rack::ShowStatus.new(lambda { |env|
39
+ [404, {"Content-Type" => "text/plain", "Content-Length" => "4"}, ["foo!"]]
40
+ }))
41
+ res = req.get("/", :lint => true)
42
+ res.should.be.not_found
43
+
44
+ res.body.should == "foo!"
45
+ end
46
+
47
+ specify "should pass on original headers" do
48
+ headers = {"WWW-Authenticate" => "Basic blah"}
49
+
50
+ req = Rack::MockRequest.new(Rack::ShowStatus.new(lambda { |env| [401, headers, []] }))
51
+ res = req.get("/", :lint => true)
52
+
53
+ res["WWW-Authenticate"].should.equal("Basic blah")
54
+ end
55
+
56
+ specify "should replace existing messages if there is detail" do
57
+ req = Rack::MockRequest.new(Rack::ShowStatus.new(lambda { |env|
58
+ env["rack.showstatus.detail"] = "gone too meta."
59
+ [404, {"Content-Type" => "text/plain", "Content-Length" => "4"}, ["foo!"]]
60
+ }))
61
+
62
+ res = req.get("/", :lint => true)
63
+ res.should.be.not_found
64
+ res.should.be.not.empty
65
+
66
+ res["Content-Type"].should.equal("text/html")
67
+ res["Content-Length"].should.not.equal("4")
68
+ res.should =~ /404/
69
+ res.should =~ /too meta/
70
+ res.body.should.not =~ /foo/
71
+ end
72
+ end
@@ -0,0 +1,37 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/static'
4
+ require 'rack/mock'
5
+
6
+ class DummyApp
7
+ def call(env)
8
+ [200, {}, "Hello World"]
9
+ end
10
+ end
11
+
12
+ context "Rack::Static" do
13
+ root = File.expand_path(File.dirname(__FILE__))
14
+ OPTIONS = {:urls => ["/cgi"], :root => root}
15
+
16
+ setup do
17
+ @request = Rack::MockRequest.new(Rack::Static.new(DummyApp.new, OPTIONS))
18
+ end
19
+
20
+ specify "serves files" do
21
+ res = @request.get("/cgi/test")
22
+ res.should.be.ok
23
+ res.body.should =~ /ruby/
24
+ end
25
+
26
+ specify "404s if url root is known but it can't find the file" do
27
+ res = @request.get("/cgi/foo")
28
+ res.should.be.not_found
29
+ end
30
+
31
+ specify "calls down the chain if url root is not known" do
32
+ res = @request.get("/something/else")
33
+ res.should.be.ok
34
+ res.body.should == "Hello World"
35
+ end
36
+
37
+ end
@@ -0,0 +1,175 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/urlmap'
4
+ require 'rack/mock'
5
+
6
+ context "Rack::URLMap" do
7
+ specify "dispatches paths correctly" do
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
+ })
20
+
21
+ res = Rack::MockRequest.new(map).get("/")
22
+ res.should.be.not_found
23
+
24
+ res = Rack::MockRequest.new(map).get("/qux")
25
+ res.should.be.not_found
26
+
27
+ res = Rack::MockRequest.new(map).get("/foo")
28
+ res.should.be.ok
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"
35
+ res["X-PathInfo"].should.equal "/"
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 ""
41
+
42
+ res = Rack::MockRequest.new(map).get("/foo/bar/")
43
+ res.should.be.ok
44
+ res["X-ScriptName"].should.equal "/foo/bar"
45
+ res["X-PathInfo"].should.equal "/"
46
+
47
+ res = Rack::MockRequest.new(map).get("/foo/quux", "SCRIPT_NAME" => "/bleh")
48
+ res.should.be.ok
49
+ res["X-ScriptName"].should.equal "/bleh/foo"
50
+ res["X-PathInfo"].should.equal "/quux"
51
+
52
+ res = Rack::MockRequest.new(map).get("/bar", 'HTTP_HOST' => 'foo.org')
53
+ res.should.be.ok
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 '/'
61
+ end
62
+
63
+
64
+ specify "dispatches hosts correctly" do
65
+ map = Rack::URLMap.new("http://foo.org/" => lambda { |env|
66
+ [200,
67
+ { "Content-Type" => "text/plain",
68
+ "X-Position" => "foo.org",
69
+ "X-Host" => env["HTTP_HOST"] || env["SERVER_NAME"],
70
+ }, [""]]},
71
+ "http://bar.org/" => lambda { |env|
72
+ [200,
73
+ { "Content-Type" => "text/plain",
74
+ "X-Position" => "bar.org",
75
+ "X-Host" => env["HTTP_HOST"] || env["SERVER_NAME"],
76
+ }, [""]]},
77
+ "/" => lambda { |env|
78
+ [200,
79
+ { "Content-Type" => "text/plain",
80
+ "X-Position" => "default.org",
81
+ "X-Host" => env["HTTP_HOST"] || env["SERVER_NAME"],
82
+ }, [""]]}
83
+ )
84
+
85
+ res = Rack::MockRequest.new(map).get("/")
86
+ res.should.be.ok
87
+ res["X-Position"].should.equal "default.org"
88
+
89
+ res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "bar.org")
90
+ res.should.be.ok
91
+ res["X-Position"].should.equal "bar.org"
92
+
93
+ res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "foo.org")
94
+ res.should.be.ok
95
+ res["X-Position"].should.equal "foo.org"
96
+
97
+ res = Rack::MockRequest.new(map).get("http://foo.org/")
98
+ res.should.be.ok
99
+ res["X-Position"].should.equal "default.org"
100
+
101
+ res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "example.org")
102
+ res.should.be.ok
103
+ res["X-Position"].should.equal "default.org"
104
+
105
+ res = Rack::MockRequest.new(map).get("/",
106
+ "HTTP_HOST" => "example.org:9292",
107
+ "SERVER_PORT" => "9292")
108
+ res.should.be.ok
109
+ res["X-Position"].should.equal "default.org"
110
+ end
111
+
112
+ specify "should be nestable" do
113
+ map = Rack::URLMap.new("/foo" =>
114
+ Rack::URLMap.new("/bar" =>
115
+ Rack::URLMap.new("/quux" => lambda { |env|
116
+ [200,
117
+ { "Content-Type" => "text/plain",
118
+ "X-Position" => "/foo/bar/quux",
119
+ "X-PathInfo" => env["PATH_INFO"],
120
+ "X-ScriptName" => env["SCRIPT_NAME"],
121
+ }, [""]]}
122
+ )))
123
+
124
+ res = Rack::MockRequest.new(map).get("/foo/bar")
125
+ res.should.be.not_found
126
+
127
+ res = Rack::MockRequest.new(map).get("/foo/bar/quux")
128
+ res.should.be.ok
129
+ res["X-Position"].should.equal "/foo/bar/quux"
130
+ res["X-PathInfo"].should.equal ""
131
+ res["X-ScriptName"].should.equal "/foo/bar/quux"
132
+ end
133
+
134
+ specify "should route root apps correctly" do
135
+ map = Rack::URLMap.new("/" => lambda { |env|
136
+ [200,
137
+ { "Content-Type" => "text/plain",
138
+ "X-Position" => "root",
139
+ "X-PathInfo" => env["PATH_INFO"],
140
+ "X-ScriptName" => env["SCRIPT_NAME"]
141
+ }, [""]]},
142
+ "/foo" => lambda { |env|
143
+ [200,
144
+ { "Content-Type" => "text/plain",
145
+ "X-Position" => "foo",
146
+ "X-PathInfo" => env["PATH_INFO"],
147
+ "X-ScriptName" => env["SCRIPT_NAME"]
148
+ }, [""]]}
149
+ )
150
+
151
+ res = Rack::MockRequest.new(map).get("/foo/bar")
152
+ res.should.be.ok
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"
162
+
163
+ res = Rack::MockRequest.new(map).get("/bar")
164
+ res.should.be.ok
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 ""
174
+ end
175
+ end