sinatra 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sinatra might be problematic. Click here for more details.

Files changed (83) hide show
  1. data/CHANGELOG +1 -0
  2. data/LICENSE +22 -0
  3. data/Manifest +78 -1
  4. data/lib/sinatra.rb +12 -1
  5. data/sinatra.gemspec +7 -14
  6. data/vendor/rack/AUTHORS +7 -0
  7. data/vendor/rack/COPYING +18 -0
  8. data/vendor/rack/KNOWN-ISSUES +18 -0
  9. data/vendor/rack/README +242 -0
  10. data/vendor/rack/Rakefile +174 -0
  11. data/vendor/rack/bin/rackup +153 -0
  12. data/vendor/rack/contrib/rack_logo.svg +111 -0
  13. data/vendor/rack/example/lobster.ru +4 -0
  14. data/vendor/rack/example/protectedlobster.rb +14 -0
  15. data/vendor/rack/example/protectedlobster.ru +8 -0
  16. data/vendor/rack/lib/rack.rb +92 -0
  17. data/vendor/rack/lib/rack/adapter/camping.rb +22 -0
  18. data/vendor/rack/lib/rack/auth/abstract/handler.rb +28 -0
  19. data/vendor/rack/lib/rack/auth/abstract/request.rb +37 -0
  20. data/vendor/rack/lib/rack/auth/basic.rb +58 -0
  21. data/vendor/rack/lib/rack/auth/digest/md5.rb +124 -0
  22. data/vendor/rack/lib/rack/auth/digest/nonce.rb +51 -0
  23. data/vendor/rack/lib/rack/auth/digest/params.rb +55 -0
  24. data/vendor/rack/lib/rack/auth/digest/request.rb +40 -0
  25. data/vendor/rack/lib/rack/auth/openid.rb +116 -0
  26. data/vendor/rack/lib/rack/builder.rb +56 -0
  27. data/vendor/rack/lib/rack/cascade.rb +36 -0
  28. data/vendor/rack/lib/rack/commonlogger.rb +56 -0
  29. data/vendor/rack/lib/rack/file.rb +112 -0
  30. data/vendor/rack/lib/rack/handler/cgi.rb +57 -0
  31. data/vendor/rack/lib/rack/handler/fastcgi.rb +83 -0
  32. data/vendor/rack/lib/rack/handler/lsws.rb +52 -0
  33. data/vendor/rack/lib/rack/handler/mongrel.rb +78 -0
  34. data/vendor/rack/lib/rack/handler/scgi.rb +57 -0
  35. data/vendor/rack/lib/rack/handler/webrick.rb +57 -0
  36. data/vendor/rack/lib/rack/lint.rb +394 -0
  37. data/vendor/rack/lib/rack/lobster.rb +65 -0
  38. data/vendor/rack/lib/rack/mock.rb +160 -0
  39. data/vendor/rack/lib/rack/recursive.rb +57 -0
  40. data/vendor/rack/lib/rack/reloader.rb +64 -0
  41. data/vendor/rack/lib/rack/request.rb +197 -0
  42. data/vendor/rack/lib/rack/response.rb +166 -0
  43. data/vendor/rack/lib/rack/session/abstract/id.rb +126 -0
  44. data/vendor/rack/lib/rack/session/cookie.rb +71 -0
  45. data/vendor/rack/lib/rack/session/memcache.rb +83 -0
  46. data/vendor/rack/lib/rack/session/pool.rb +67 -0
  47. data/vendor/rack/lib/rack/showexceptions.rb +344 -0
  48. data/vendor/rack/lib/rack/showstatus.rb +103 -0
  49. data/vendor/rack/lib/rack/static.rb +38 -0
  50. data/vendor/rack/lib/rack/urlmap.rb +48 -0
  51. data/vendor/rack/lib/rack/utils.rb +240 -0
  52. data/vendor/rack/test/cgi/lighttpd.conf +20 -0
  53. data/vendor/rack/test/cgi/test +9 -0
  54. data/vendor/rack/test/cgi/test.fcgi +7 -0
  55. data/vendor/rack/test/cgi/test.ru +7 -0
  56. data/vendor/rack/test/spec_rack_auth_basic.rb +69 -0
  57. data/vendor/rack/test/spec_rack_auth_digest.rb +169 -0
  58. data/vendor/rack/test/spec_rack_builder.rb +50 -0
  59. data/vendor/rack/test/spec_rack_camping.rb +47 -0
  60. data/vendor/rack/test/spec_rack_cascade.rb +50 -0
  61. data/vendor/rack/test/spec_rack_cgi.rb +91 -0
  62. data/vendor/rack/test/spec_rack_commonlogger.rb +32 -0
  63. data/vendor/rack/test/spec_rack_fastcgi.rb +91 -0
  64. data/vendor/rack/test/spec_rack_file.rb +40 -0
  65. data/vendor/rack/test/spec_rack_lint.rb +317 -0
  66. data/vendor/rack/test/spec_rack_lobster.rb +45 -0
  67. data/vendor/rack/test/spec_rack_mock.rb +152 -0
  68. data/vendor/rack/test/spec_rack_mongrel.rb +165 -0
  69. data/vendor/rack/test/spec_rack_recursive.rb +77 -0
  70. data/vendor/rack/test/spec_rack_request.rb +384 -0
  71. data/vendor/rack/test/spec_rack_response.rb +167 -0
  72. data/vendor/rack/test/spec_rack_session_cookie.rb +49 -0
  73. data/vendor/rack/test/spec_rack_session_memcache.rb +100 -0
  74. data/vendor/rack/test/spec_rack_session_pool.rb +84 -0
  75. data/vendor/rack/test/spec_rack_showexceptions.rb +21 -0
  76. data/vendor/rack/test/spec_rack_showstatus.rb +71 -0
  77. data/vendor/rack/test/spec_rack_static.rb +37 -0
  78. data/vendor/rack/test/spec_rack_urlmap.rb +175 -0
  79. data/vendor/rack/test/spec_rack_utils.rb +57 -0
  80. data/vendor/rack/test/spec_rack_webrick.rb +106 -0
  81. data/vendor/rack/test/testrequest.rb +43 -0
  82. metadata +81 -4
  83. data/Rakefile +0 -24
@@ -0,0 +1,45 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/lobster'
4
+ require 'rack/mock'
5
+
6
+ context "Rack::Lobster::LambdaLobster" do
7
+ specify "should be a single lambda" do
8
+ Rack::Lobster::LambdaLobster.should.be.kind_of Proc
9
+ end
10
+
11
+ specify "should look like a lobster" do
12
+ res = Rack::MockRequest.new(Rack::Lobster::LambdaLobster).get("/")
13
+ res.should.be.ok
14
+ res.body.should.include "(,(,,(,,,("
15
+ res.body.should.include "?flip"
16
+ end
17
+
18
+ specify "should be flippable" do
19
+ res = Rack::MockRequest.new(Rack::Lobster::LambdaLobster).get("/?flip")
20
+ res.should.be.ok
21
+ res.body.should.include "(,,,(,,(,("
22
+ end
23
+ end
24
+
25
+ context "Rack::Lobster" do
26
+ specify "should look like a lobster" do
27
+ res = Rack::MockRequest.new(Rack::Lobster.new).get("/")
28
+ res.should.be.ok
29
+ res.body.should.include "(,(,,(,,,("
30
+ res.body.should.include "?flip"
31
+ res.body.should.include "crash"
32
+ end
33
+
34
+ specify "should be flippable" do
35
+ res = Rack::MockRequest.new(Rack::Lobster.new).get("/?flip=left")
36
+ res.should.be.ok
37
+ res.body.should.include "(,,,(,,(,("
38
+ end
39
+
40
+ specify "should provide crashing for testing purposes" do
41
+ lambda {
42
+ Rack::MockRequest.new(Rack::Lobster.new).get("/?flip=crash")
43
+ }.should.raise
44
+ end
45
+ end
@@ -0,0 +1,152 @@
1
+ require 'yaml'
2
+ require 'rack/mock'
3
+ require 'rack/request'
4
+ require 'rack/response'
5
+
6
+ app = lambda { |env|
7
+ req = Rack::Request.new(env)
8
+
9
+ env["mock.postdata"] = env["rack.input"].read
10
+ if req.GET["error"]
11
+ env["rack.errors"].puts req.GET["error"]
12
+ env["rack.errors"].flush
13
+ end
14
+
15
+ Rack::Response.new(env.to_yaml,
16
+ req.GET["status"] || 200,
17
+ "Content-Type" => "text/yaml").finish
18
+ }
19
+
20
+ context "Rack::MockRequest" do
21
+ specify "should return a MockResponse" do
22
+ res = Rack::MockRequest.new(app).get("")
23
+ res.should.be.kind_of Rack::MockResponse
24
+ end
25
+
26
+ specify "should be able to only return the environment" do
27
+ env = Rack::MockRequest.env_for("")
28
+ env.should.be.kind_of Hash
29
+ env.should.include "rack.version"
30
+ end
31
+
32
+ specify "should provide sensible defaults" do
33
+ res = Rack::MockRequest.new(app).request
34
+
35
+ env = YAML.load(res.body)
36
+ env["REQUEST_METHOD"].should.equal "GET"
37
+ env["SERVER_NAME"].should.equal "example.org"
38
+ env["SERVER_PORT"].should.equal "80"
39
+ env["QUERY_STRING"].should.equal ""
40
+ env["PATH_INFO"].should.equal "/"
41
+ env["SCRIPT_NAME"].should.equal ""
42
+ env["rack.url_scheme"].should.equal "http"
43
+ env["mock.postdata"].should.be.empty
44
+ end
45
+
46
+ specify "should allow GET/POST/PUT/DELETE" do
47
+ res = Rack::MockRequest.new(app).get("", :input => "foo")
48
+ env = YAML.load(res.body)
49
+ env["REQUEST_METHOD"].should.equal "GET"
50
+
51
+ res = Rack::MockRequest.new(app).post("", :input => "foo")
52
+ env = YAML.load(res.body)
53
+ env["REQUEST_METHOD"].should.equal "POST"
54
+
55
+ res = Rack::MockRequest.new(app).put("", :input => "foo")
56
+ env = YAML.load(res.body)
57
+ env["REQUEST_METHOD"].should.equal "PUT"
58
+
59
+ res = Rack::MockRequest.new(app).delete("", :input => "foo")
60
+ env = YAML.load(res.body)
61
+ env["REQUEST_METHOD"].should.equal "DELETE"
62
+
63
+ Rack::MockRequest.env_for("/", :method => "OPTIONS")["REQUEST_METHOD"].
64
+ should.equal "OPTIONS"
65
+ end
66
+
67
+ specify "should allow posting" do
68
+ res = Rack::MockRequest.new(app).get("", :input => "foo")
69
+ env = YAML.load(res.body)
70
+ env["mock.postdata"].should.equal "foo"
71
+
72
+ res = Rack::MockRequest.new(app).post("", :input => StringIO.new("foo"))
73
+ env = YAML.load(res.body)
74
+ env["mock.postdata"].should.equal "foo"
75
+ end
76
+
77
+ specify "should use all parts of an URL" do
78
+ res = Rack::MockRequest.new(app).
79
+ get("https://bla.example.org:9292/meh/foo?bar")
80
+ res.should.be.kind_of Rack::MockResponse
81
+
82
+ env = YAML.load(res.body)
83
+ env["REQUEST_METHOD"].should.equal "GET"
84
+ env["SERVER_NAME"].should.equal "bla.example.org"
85
+ env["SERVER_PORT"].should.equal "9292"
86
+ env["QUERY_STRING"].should.equal "bar"
87
+ env["PATH_INFO"].should.equal "/meh/foo"
88
+ env["rack.url_scheme"].should.equal "https"
89
+ end
90
+
91
+ specify "should behave valid according to the Rack spec" do
92
+ lambda {
93
+ res = Rack::MockRequest.new(app).
94
+ get("https://bla.example.org:9292/meh/foo?bar", :lint => true)
95
+ }.should.not.raise(Rack::Lint::LintError)
96
+ end
97
+ end
98
+
99
+ context "Rack::MockResponse" do
100
+ specify "should provide access to the HTTP status" do
101
+ res = Rack::MockRequest.new(app).get("")
102
+ res.should.be.successful
103
+ res.should.be.ok
104
+
105
+ res = Rack::MockRequest.new(app).get("/?status=404")
106
+ res.should.not.be.successful
107
+ res.should.be.client_error
108
+ res.should.be.not_found
109
+
110
+ res = Rack::MockRequest.new(app).get("/?status=501")
111
+ res.should.not.be.successful
112
+ res.should.be.server_error
113
+
114
+ res = Rack::MockRequest.new(app).get("/?status=307")
115
+ res.should.be.redirect
116
+
117
+ res = Rack::MockRequest.new(app).get("/?status=201", :lint => true)
118
+ res.should.be.empty
119
+ end
120
+
121
+ specify "should provide access to the HTTP headers" do
122
+ res = Rack::MockRequest.new(app).get("")
123
+ res.should.include "Content-Type"
124
+ res.headers["Content-Type"].should.equal "text/yaml"
125
+ res.original_headers["Content-Type"].should.equal "text/yaml"
126
+ res["Content-Type"].should.equal "text/yaml"
127
+ res.content_type.should.equal "text/yaml"
128
+ res.content_length.should.be.nil
129
+ res.location.should.be.nil
130
+ end
131
+
132
+ specify "should provide access to the HTTP body" do
133
+ res = Rack::MockRequest.new(app).get("")
134
+ res.body.should =~ /rack/
135
+ res.should =~ /rack/
136
+ res.should.match(/rack/)
137
+ res.should.satisfy { |r| r.match(/rack/) }
138
+ end
139
+
140
+ specify "should provide access to the Rack errors" do
141
+ res = Rack::MockRequest.new(app).get("/?error=foo", :lint => true)
142
+ res.should.be.ok
143
+ res.errors.should.not.be.empty
144
+ res.errors.should.include "foo"
145
+ end
146
+
147
+ specify "should optionally make Rack errors fatal" do
148
+ lambda {
149
+ Rack::MockRequest.new(app).get("/?error=foo", :fatal => true)
150
+ }.should.raise(Rack::MockRequest::FatalWarning)
151
+ end
152
+ end
@@ -0,0 +1,165 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/handler/mongrel'
4
+ require 'rack/urlmap'
5
+ require 'rack/lint'
6
+ require 'testrequest'
7
+
8
+ Thread.abort_on_exception = true
9
+ $tcp_defer_accept_opts = nil
10
+ $tcp_cork_opts = nil
11
+
12
+ context "Rack::Handler::Mongrel" do
13
+ include TestRequest::Helpers
14
+
15
+ setup do
16
+ server = Mongrel::HttpServer.new(@host='0.0.0.0', @port=9201)
17
+ server.register('/test',
18
+ Rack::Handler::Mongrel.new(Rack::Lint.new(TestRequest.new)))
19
+ @acc = server.run
20
+ end
21
+
22
+ specify "should respond" do
23
+ lambda {
24
+ GET("/test")
25
+ }.should.not.raise
26
+ end
27
+
28
+ specify "should be a Mongrel" do
29
+ GET("/test")
30
+ status.should.be 200
31
+ response["SERVER_SOFTWARE"].should =~ /Mongrel/
32
+ response["HTTP_VERSION"].should.equal "HTTP/1.1"
33
+ response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
34
+ response["SERVER_PORT"].should.equal "9201"
35
+ response["SERVER_NAME"].should.equal "0.0.0.0"
36
+ end
37
+
38
+ specify "should have rack headers" do
39
+ GET("/test")
40
+ response["rack.version"].should.equal [0,1]
41
+ response["rack.multithread"].should.be true
42
+ response["rack.multiprocess"].should.be false
43
+ response["rack.run_once"].should.be false
44
+ end
45
+
46
+ specify "should have CGI headers on GET" do
47
+ GET("/test")
48
+ response["REQUEST_METHOD"].should.equal "GET"
49
+ response["SCRIPT_NAME"].should.equal "/test"
50
+ response["REQUEST_PATH"].should.equal "/test"
51
+ response["PATH_INFO"].should.be.nil
52
+ response["QUERY_STRING"].should.equal ""
53
+ response["test.postdata"].should.equal ""
54
+
55
+ GET("/test/foo?quux=1")
56
+ response["REQUEST_METHOD"].should.equal "GET"
57
+ response["SCRIPT_NAME"].should.equal "/test"
58
+ response["REQUEST_PATH"].should.equal "/test/foo"
59
+ response["PATH_INFO"].should.equal "/foo"
60
+ response["QUERY_STRING"].should.equal "quux=1"
61
+ end
62
+
63
+ specify "should have CGI headers on POST" do
64
+ POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
65
+ status.should.equal 200
66
+ response["REQUEST_METHOD"].should.equal "POST"
67
+ response["SCRIPT_NAME"].should.equal "/test"
68
+ response["REQUEST_PATH"].should.equal "/test"
69
+ response["QUERY_STRING"].should.equal ""
70
+ response["HTTP_X_TEST_HEADER"].should.equal "42"
71
+ response["test.postdata"].should.equal "rack-form-data=23"
72
+ end
73
+
74
+ specify "should support HTTP auth" do
75
+ GET("/test", {:user => "ruth", :passwd => "secret"})
76
+ response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
77
+ end
78
+
79
+ specify "should set status" do
80
+ GET("/test?secret")
81
+ status.should.equal 403
82
+ response["rack.url_scheme"].should.equal "http"
83
+ end
84
+
85
+ specify "should provide a .run" do
86
+ block_ran = false
87
+ Thread.new {
88
+ Rack::Handler::Mongrel.run(lambda {}, {:Port => 9211}) { |server|
89
+ server.should.be.kind_of Mongrel::HttpServer
90
+ block_ran = true
91
+ }
92
+ }
93
+ sleep 1
94
+ block_ran.should.be true
95
+ end
96
+
97
+ specify "should provide a .run that maps a hash" do
98
+ block_ran = false
99
+ Thread.new {
100
+ map = {'/'=>lambda{},'/foo'=>lambda{}}
101
+ Rack::Handler::Mongrel.run(map, :map => true, :Port => 9221) { |server|
102
+ server.should.be.kind_of Mongrel::HttpServer
103
+ server.classifier.uris.size.should.be 2
104
+ server.classifier.uris.should.not.include '/arf'
105
+ server.classifier.uris.should.include '/'
106
+ server.classifier.uris.should.include '/foo'
107
+ block_ran = true
108
+ }
109
+ }
110
+ sleep 1
111
+ block_ran.should.be true
112
+ end
113
+
114
+ specify "should provide a .run that maps a urlmap" do
115
+ block_ran = false
116
+ Thread.new {
117
+ map = Rack::URLMap.new({'/'=>lambda{},'/bar'=>lambda{}})
118
+ Rack::Handler::Mongrel.run(map, {:map => true, :Port => 9231}) { |server|
119
+ server.should.be.kind_of Mongrel::HttpServer
120
+ server.classifier.uris.size.should.be 2
121
+ server.classifier.uris.should.not.include '/arf'
122
+ server.classifier.uris.should.include '/'
123
+ server.classifier.uris.should.include '/bar'
124
+ block_ran = true
125
+ }
126
+ }
127
+ sleep 1
128
+ block_ran.should.be true
129
+ end
130
+
131
+ specify "should provide a .run that maps a urlmap restricting by host" do
132
+ block_ran = false
133
+ Thread.new {
134
+ map = Rack::URLMap.new({
135
+ '/' => lambda{},
136
+ '/foo' => lambda{},
137
+ '/bar' => lambda{},
138
+ 'http://localhost/' => lambda{},
139
+ 'http://localhost/bar' => lambda{},
140
+ 'http://falsehost/arf' => lambda{},
141
+ 'http://falsehost/qux' => lambda{}
142
+ })
143
+ opt = {:map => true, :Port => 9241, :Host => 'localhost'}
144
+ Rack::Handler::Mongrel.run(map, opt) { |server|
145
+ server.should.be.kind_of Mongrel::HttpServer
146
+ server.classifier.uris.should.include '/'
147
+ server.classifier.handler_map['/'].size.should.be 2
148
+ server.classifier.uris.should.include '/foo'
149
+ server.classifier.handler_map['/foo'].size.should.be 1
150
+ server.classifier.uris.should.include '/bar'
151
+ server.classifier.handler_map['/bar'].size.should.be 2
152
+ server.classifier.uris.should.not.include '/qux'
153
+ server.classifier.uris.should.not.include '/arf'
154
+ server.classifier.uris.size.should.be 3
155
+ block_ran = true
156
+ }
157
+ }
158
+ sleep 1
159
+ block_ran.should.be true
160
+ end
161
+
162
+ teardown do
163
+ @acc.raise Mongrel::StopServer
164
+ end
165
+ end
@@ -0,0 +1,77 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/recursive'
4
+ require 'rack/urlmap'
5
+ require 'rack/response'
6
+ require 'rack/mock'
7
+
8
+ context "Rack::Recursive" do
9
+ setup do
10
+
11
+ @app1 = lambda { |env|
12
+ res = Rack::Response.new
13
+ res["X-Path-Info"] = env["PATH_INFO"]
14
+ res["X-Query-String"] = env["QUERY_STRING"]
15
+ res.finish do |res|
16
+ res.write "App1"
17
+ end
18
+ }
19
+
20
+ @app2 = lambda { |env|
21
+ Rack::Response.new.finish do |res|
22
+ res.write "App2"
23
+ _, _, body = env['rack.recursive.include'].call(env, "/app1")
24
+ body.each { |b|
25
+ res.write b
26
+ }
27
+ end
28
+ }
29
+
30
+ @app3 = lambda { |env|
31
+ raise Rack::ForwardRequest.new("/app1")
32
+ }
33
+
34
+ @app4 = lambda { |env|
35
+ raise Rack::ForwardRequest.new("http://example.org/app1/quux?meh")
36
+ }
37
+
38
+ end
39
+
40
+ specify "should allow for subrequests" do
41
+ res = Rack::MockRequest.new(Rack::Recursive.new(
42
+ Rack::URLMap.new("/app1" => @app1,
43
+ "/app2" => @app2))).
44
+ get("/app2")
45
+
46
+ res.should.be.ok
47
+ res.body.should.equal "App2App1"
48
+ end
49
+
50
+ specify "should raise error on requests not below the app" do
51
+ app = Rack::URLMap.new("/app1" => @app1,
52
+ "/app" => Rack::Recursive.new(
53
+ Rack::URLMap.new("/1" => @app1,
54
+ "/2" => @app2)))
55
+
56
+ lambda {
57
+ Rack::MockRequest.new(app).get("/app/2")
58
+ }.should.raise(ArgumentError).
59
+ message.should =~ /can only include below/
60
+ end
61
+
62
+ specify "should support forwarding" do
63
+ app = Rack::Recursive.new(Rack::URLMap.new("/app1" => @app1,
64
+ "/app3" => @app3,
65
+ "/app4" => @app4))
66
+
67
+ res = Rack::MockRequest.new(app).get("/app3")
68
+ res.should.be.ok
69
+ res.body.should.equal "App1"
70
+
71
+ res = Rack::MockRequest.new(app).get("/app4")
72
+ res.should.be.ok
73
+ res.body.should.equal "App1"
74
+ res["X-Path-Info"].should.equal "/quux"
75
+ res["X-Query-String"].should.equal "meh"
76
+ end
77
+ end
@@ -0,0 +1,384 @@
1
+ require 'test/spec'
2
+ require 'stringio'
3
+
4
+ require 'rack/request'
5
+ require 'rack/mock'
6
+
7
+ context "Rack::Request" do
8
+ specify "wraps the rack variables" do
9
+ req = Rack::Request.new(Rack::MockRequest.env_for("http://example.com:8080/"))
10
+
11
+ req.body.should.respond_to? :gets
12
+ req.scheme.should.equal "http"
13
+ req.request_method.should.equal "GET"
14
+
15
+ req.should.be.get
16
+ req.should.not.be.post
17
+ req.should.not.be.put
18
+ req.should.not.be.delete
19
+ req.should.not.be.head
20
+
21
+ req.script_name.should.equal ""
22
+ req.path_info.should.equal "/"
23
+ req.query_string.should.equal ""
24
+
25
+ req.host.should.equal "example.com"
26
+ req.port.should.equal 8080
27
+
28
+ req.content_length.should.be.nil
29
+ req.content_type.should.be.nil
30
+ end
31
+
32
+ specify "can figure out the correct host" do
33
+ req = Rack::Request.new \
34
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org")
35
+ req.host.should.equal "www2.example.org"
36
+
37
+ req = Rack::Request.new \
38
+ Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org:9292")
39
+ req.host.should.equal "example.org"
40
+ end
41
+
42
+ specify "can parse the query string" do
43
+ req = Rack::Request.new(Rack::MockRequest.env_for("/?foo=bar&quux=bla"))
44
+ req.query_string.should.equal "foo=bar&quux=bla"
45
+ req.GET.should.equal "foo" => "bar", "quux" => "bla"
46
+ req.POST.should.be.empty
47
+ req.params.should.equal "foo" => "bar", "quux" => "bla"
48
+ end
49
+
50
+ specify "can parse POST data" do
51
+ req = Rack::Request.new \
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
55
+ req.query_string.should.equal "foo=quux"
56
+ req.GET.should.equal "foo" => "quux"
57
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
58
+ req.params.should.equal "foo" => "bar", "quux" => "bla"
59
+ end
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
+
86
+ specify "can get value by key from params with #[]" do
87
+ req = Rack::Request.new \
88
+ Rack::MockRequest.env_for("?foo=quux")
89
+ req['foo'].should.equal 'quux'
90
+ req[:foo].should.equal 'quux'
91
+ end
92
+
93
+ specify "can set value to key on params with #[]=" do
94
+ req = Rack::Request.new \
95
+ Rack::MockRequest.env_for("?foo=duh")
96
+ req['foo'].should.equal 'duh'
97
+ req[:foo].should.equal 'duh'
98
+ req.params.should.equal 'foo' => 'duh'
99
+
100
+ req['foo'] = 'bar'
101
+ req.params.should.equal 'foo' => 'bar'
102
+ req['foo'].should.equal 'bar'
103
+ req[:foo].should.equal 'bar'
104
+
105
+ req[:foo] = 'jaz'
106
+ req.params.should.equal 'foo' => 'jaz'
107
+ req['foo'].should.equal 'jaz'
108
+ req[:foo].should.equal 'jaz'
109
+ end
110
+
111
+ specify "values_at answers values by keys in order given" do
112
+ req = Rack::Request.new \
113
+ Rack::MockRequest.env_for("?foo=baz&wun=der&bar=ful")
114
+ req.values_at('foo').should.equal ['baz']
115
+ req.values_at('foo', 'wun').should.equal ['baz', 'der']
116
+ req.values_at('bar', 'foo', 'wun').should.equal ['ful', 'baz', 'der']
117
+ end
118
+
119
+ specify "referrer should be extracted correct" do
120
+ req = Rack::Request.new \
121
+ Rack::MockRequest.env_for("/", "HTTP_REFERER" => "/some/path")
122
+ req.referer.should.equal "/some/path"
123
+
124
+ req = Rack::Request.new \
125
+ Rack::MockRequest.env_for("/")
126
+ req.referer.should.equal "/"
127
+ end
128
+
129
+ specify "can cache, but invalidates the cache" do
130
+ req = Rack::Request.new \
131
+ Rack::MockRequest.env_for("/?foo=quux", :input => "foo=bar&quux=bla")
132
+ req.GET.should.equal "foo" => "quux"
133
+ req.GET.should.equal "foo" => "quux"
134
+ req.env["QUERY_STRING"] = "bla=foo"
135
+ req.GET.should.equal "bla" => "foo"
136
+ req.GET.should.equal "bla" => "foo"
137
+
138
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
139
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
140
+ req.env["rack.input"] = StringIO.new("foo=bla&quux=bar")
141
+ req.POST.should.equal "foo" => "bla", "quux" => "bar"
142
+ req.POST.should.equal "foo" => "bla", "quux" => "bar"
143
+ end
144
+
145
+ specify "can figure out if called via XHR" do
146
+ req = Rack::Request.new(Rack::MockRequest.env_for(""))
147
+ req.should.not.be.xhr
148
+
149
+ req = Rack::Request.new \
150
+ Rack::MockRequest.env_for("", "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest")
151
+ req.should.be.xhr
152
+ end
153
+
154
+ specify "can parse cookies" do
155
+ req = Rack::Request.new \
156
+ Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
157
+ req.cookies.should.equal "foo" => "bar", "quux" => "h&m"
158
+ req.cookies.should.equal "foo" => "bar", "quux" => "h&m"
159
+ req.env.delete("HTTP_COOKIE")
160
+ req.cookies.should.equal({})
161
+ end
162
+
163
+ specify "parses cookies according to RFC 2109" do
164
+ req = Rack::Request.new \
165
+ Rack::MockRequest.env_for('', 'HTTP_COOKIE' => 'foo=bar;foo=car')
166
+ req.cookies.should.equal 'foo' => 'bar'
167
+ end
168
+
169
+ specify "provides setters" do
170
+ req = Rack::Request.new(e=Rack::MockRequest.env_for(""))
171
+ req.script_name.should.equal ""
172
+ req.script_name = "/foo"
173
+ req.script_name.should.equal "/foo"
174
+ e["SCRIPT_NAME"].should.equal "/foo"
175
+
176
+ req.path_info.should.equal "/"
177
+ req.path_info = "/foo"
178
+ req.path_info.should.equal "/foo"
179
+ e["PATH_INFO"].should.equal "/foo"
180
+ end
181
+
182
+ specify "provides the original env" do
183
+ req = Rack::Request.new(e=Rack::MockRequest.env_for(""))
184
+ req.env.should.be e
185
+ end
186
+
187
+ specify "can restore the URL" do
188
+ Rack::Request.new(Rack::MockRequest.env_for("")).url.
189
+ should.equal "http://example.org/"
190
+ Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).url.
191
+ should.equal "http://example.org/foo/"
192
+ Rack::Request.new(Rack::MockRequest.env_for("/foo")).url.
193
+ should.equal "http://example.org/foo"
194
+ Rack::Request.new(Rack::MockRequest.env_for("?foo")).url.
195
+ should.equal "http://example.org/?foo"
196
+ Rack::Request.new(Rack::MockRequest.env_for("http://example.org:8080/")).url.
197
+ should.equal "http://example.org:8080/"
198
+ Rack::Request.new(Rack::MockRequest.env_for("https://example.org/")).url.
199
+ should.equal "https://example.org/"
200
+
201
+ Rack::Request.new(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).url.
202
+ should.equal "https://example.com:8080/foo?foo"
203
+ end
204
+
205
+ specify "can restore the full path" do
206
+ Rack::Request.new(Rack::MockRequest.env_for("")).fullpath.
207
+ should.equal "/"
208
+ Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).fullpath.
209
+ should.equal "/foo/"
210
+ Rack::Request.new(Rack::MockRequest.env_for("/foo")).fullpath.
211
+ should.equal "/foo"
212
+ Rack::Request.new(Rack::MockRequest.env_for("?foo")).fullpath.
213
+ should.equal "/?foo"
214
+ Rack::Request.new(Rack::MockRequest.env_for("http://example.org:8080/")).fullpath.
215
+ should.equal "/"
216
+ Rack::Request.new(Rack::MockRequest.env_for("https://example.org/")).fullpath.
217
+ should.equal "/"
218
+
219
+ Rack::Request.new(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).fullpath.
220
+ should.equal "/foo?foo"
221
+ end
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
+
237
+ specify "can parse multipart form data" do
238
+ # Adapted from RFC 1867.
239
+ input = <<EOF
240
+ --AaB03x\r
241
+ content-disposition: form-data; name="reply"\r
242
+ \r
243
+ yes\r
244
+ --AaB03x\r
245
+ content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
246
+ Content-Type: image/jpeg\r
247
+ Content-Transfer-Encoding: base64\r
248
+ \r
249
+ /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
250
+ --AaB03x--\r
251
+ EOF
252
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
253
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
254
+ "CONTENT_LENGTH" => input.size,
255
+ :input => input)
256
+
257
+ req.POST.should.include "fileupload"
258
+ req.POST.should.include "reply"
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
+
266
+ req.POST["reply"].should.equal "yes"
267
+
268
+ f = req.POST["fileupload"]
269
+ f.should.be.kind_of Hash
270
+ f[:type].should.equal "image/jpeg"
271
+ f[:filename].should.equal "dj.jpg"
272
+ f.should.include :tempfile
273
+ f[:tempfile].size.should.equal 76
274
+ end
275
+
276
+ specify "can parse big multipart form data" do
277
+ input = <<EOF
278
+ --AaB03x\r
279
+ content-disposition: form-data; name="huge"; filename="huge"\r
280
+ \r
281
+ #{"x"*32768}\r
282
+ --AaB03x\r
283
+ content-disposition: form-data; name="mean"; filename="mean"\r
284
+ \r
285
+ --AaB03xha\r
286
+ --AaB03x--\r
287
+ EOF
288
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
289
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
290
+ "CONTENT_LENGTH" => input.size,
291
+ :input => input)
292
+
293
+ req.POST["huge"][:tempfile].size.should.equal 32768
294
+ req.POST["mean"][:tempfile].size.should.equal 10
295
+ req.POST["mean"][:tempfile].read.should.equal "--AaB03xha"
296
+ end
297
+
298
+ specify "can detect invalid multipart form data" do
299
+ input = <<EOF
300
+ --AaB03x\r
301
+ content-disposition: form-data; name="huge"; filename="huge"\r
302
+ EOF
303
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
304
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
305
+ "CONTENT_LENGTH" => input.size,
306
+ :input => input)
307
+
308
+ lambda { req.POST }.should.raise(EOFError)
309
+
310
+ input = <<EOF
311
+ --AaB03x\r
312
+ content-disposition: form-data; name="huge"; filename="huge"\r
313
+ \r
314
+ foo\r
315
+ EOF
316
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
317
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
318
+ "CONTENT_LENGTH" => input.size,
319
+ :input => input)
320
+
321
+ lambda { req.POST }.should.raise(EOFError)
322
+
323
+ input = <<EOF
324
+ --AaB03x\r
325
+ content-disposition: form-data; name="huge"; filename="huge"\r
326
+ \r
327
+ foo\r
328
+ EOF
329
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
330
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
331
+ "CONTENT_LENGTH" => input.size,
332
+ :input => input)
333
+
334
+ lambda { req.POST }.should.raise(EOFError)
335
+ end
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
+
359
+ specify "does conform to the Rack spec" do
360
+ app = lambda { |env|
361
+ content = Rack::Request.new(env).POST["file"].inspect
362
+ [200, {"Content-Type" => "text/html"}, content]
363
+ }
364
+
365
+ input = <<EOF
366
+ --AaB03x\r
367
+ content-disposition: form-data; name="reply"\r
368
+ \r
369
+ yes\r
370
+ --AaB03x\r
371
+ content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
372
+ Content-Type: image/jpeg\r
373
+ Content-Transfer-Encoding: base64\r
374
+ \r
375
+ /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
376
+ --AaB03x--\r
377
+ EOF
378
+ res = Rack::MockRequest.new(Rack::Lint.new(app)).get "/",
379
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
380
+ "CONTENT_LENGTH" => input.size.to_s, "rack.input" => StringIO.new(input)
381
+
382
+ res.should.be.ok
383
+ end
384
+ end