eac-rack 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. data/COPYING +18 -0
  2. data/KNOWN-ISSUES +21 -0
  3. data/README +399 -0
  4. data/bin/rackup +4 -0
  5. data/contrib/rack_logo.svg +111 -0
  6. data/example/lobster.ru +4 -0
  7. data/example/protectedlobster.rb +14 -0
  8. data/example/protectedlobster.ru +8 -0
  9. data/lib/rack.rb +92 -0
  10. data/lib/rack/adapter/camping.rb +22 -0
  11. data/lib/rack/auth/abstract/handler.rb +37 -0
  12. data/lib/rack/auth/abstract/request.rb +37 -0
  13. data/lib/rack/auth/basic.rb +58 -0
  14. data/lib/rack/auth/digest/md5.rb +124 -0
  15. data/lib/rack/auth/digest/nonce.rb +51 -0
  16. data/lib/rack/auth/digest/params.rb +55 -0
  17. data/lib/rack/auth/digest/request.rb +40 -0
  18. data/lib/rack/builder.rb +80 -0
  19. data/lib/rack/cascade.rb +41 -0
  20. data/lib/rack/chunked.rb +49 -0
  21. data/lib/rack/commonlogger.rb +49 -0
  22. data/lib/rack/conditionalget.rb +47 -0
  23. data/lib/rack/config.rb +15 -0
  24. data/lib/rack/content_length.rb +29 -0
  25. data/lib/rack/content_type.rb +23 -0
  26. data/lib/rack/deflater.rb +96 -0
  27. data/lib/rack/directory.rb +157 -0
  28. data/lib/rack/etag.rb +23 -0
  29. data/lib/rack/file.rb +90 -0
  30. data/lib/rack/handler.rb +88 -0
  31. data/lib/rack/handler/cgi.rb +61 -0
  32. data/lib/rack/handler/evented_mongrel.rb +8 -0
  33. data/lib/rack/handler/fastcgi.rb +89 -0
  34. data/lib/rack/handler/lsws.rb +63 -0
  35. data/lib/rack/handler/mongrel.rb +90 -0
  36. data/lib/rack/handler/scgi.rb +62 -0
  37. data/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
  38. data/lib/rack/handler/thin.rb +18 -0
  39. data/lib/rack/handler/webrick.rb +69 -0
  40. data/lib/rack/head.rb +19 -0
  41. data/lib/rack/lint.rb +575 -0
  42. data/lib/rack/lobster.rb +65 -0
  43. data/lib/rack/lock.rb +16 -0
  44. data/lib/rack/logger.rb +20 -0
  45. data/lib/rack/methodoverride.rb +27 -0
  46. data/lib/rack/mime.rb +206 -0
  47. data/lib/rack/mock.rb +189 -0
  48. data/lib/rack/nulllogger.rb +18 -0
  49. data/lib/rack/recursive.rb +57 -0
  50. data/lib/rack/reloader.rb +109 -0
  51. data/lib/rack/request.rb +271 -0
  52. data/lib/rack/response.rb +149 -0
  53. data/lib/rack/rewindable_input.rb +100 -0
  54. data/lib/rack/runtime.rb +27 -0
  55. data/lib/rack/sendfile.rb +142 -0
  56. data/lib/rack/server.rb +212 -0
  57. data/lib/rack/session/abstract/id.rb +140 -0
  58. data/lib/rack/session/cookie.rb +90 -0
  59. data/lib/rack/session/memcache.rb +119 -0
  60. data/lib/rack/session/pool.rb +100 -0
  61. data/lib/rack/showexceptions.rb +349 -0
  62. data/lib/rack/showstatus.rb +106 -0
  63. data/lib/rack/static.rb +38 -0
  64. data/lib/rack/urlmap.rb +56 -0
  65. data/lib/rack/utils.rb +614 -0
  66. data/rack.gemspec +38 -0
  67. data/test/spec_rack_auth_basic.rb +73 -0
  68. data/test/spec_rack_auth_digest.rb +226 -0
  69. data/test/spec_rack_builder.rb +84 -0
  70. data/test/spec_rack_camping.rb +51 -0
  71. data/test/spec_rack_cascade.rb +48 -0
  72. data/test/spec_rack_cgi.rb +89 -0
  73. data/test/spec_rack_chunked.rb +62 -0
  74. data/test/spec_rack_commonlogger.rb +61 -0
  75. data/test/spec_rack_conditionalget.rb +41 -0
  76. data/test/spec_rack_config.rb +24 -0
  77. data/test/spec_rack_content_length.rb +43 -0
  78. data/test/spec_rack_content_type.rb +30 -0
  79. data/test/spec_rack_deflater.rb +127 -0
  80. data/test/spec_rack_directory.rb +61 -0
  81. data/test/spec_rack_etag.rb +17 -0
  82. data/test/spec_rack_fastcgi.rb +89 -0
  83. data/test/spec_rack_file.rb +75 -0
  84. data/test/spec_rack_handler.rb +43 -0
  85. data/test/spec_rack_head.rb +30 -0
  86. data/test/spec_rack_lint.rb +528 -0
  87. data/test/spec_rack_lobster.rb +45 -0
  88. data/test/spec_rack_lock.rb +38 -0
  89. data/test/spec_rack_logger.rb +21 -0
  90. data/test/spec_rack_methodoverride.rb +60 -0
  91. data/test/spec_rack_mock.rb +243 -0
  92. data/test/spec_rack_mongrel.rb +189 -0
  93. data/test/spec_rack_nulllogger.rb +13 -0
  94. data/test/spec_rack_recursive.rb +77 -0
  95. data/test/spec_rack_request.rb +545 -0
  96. data/test/spec_rack_response.rb +221 -0
  97. data/test/spec_rack_rewindable_input.rb +118 -0
  98. data/test/spec_rack_runtime.rb +35 -0
  99. data/test/spec_rack_sendfile.rb +86 -0
  100. data/test/spec_rack_session_cookie.rb +73 -0
  101. data/test/spec_rack_session_memcache.rb +273 -0
  102. data/test/spec_rack_session_pool.rb +172 -0
  103. data/test/spec_rack_showexceptions.rb +21 -0
  104. data/test/spec_rack_showstatus.rb +72 -0
  105. data/test/spec_rack_static.rb +37 -0
  106. data/test/spec_rack_thin.rb +91 -0
  107. data/test/spec_rack_urlmap.rb +215 -0
  108. data/test/spec_rack_utils.rb +554 -0
  109. data/test/spec_rack_webrick.rb +130 -0
  110. data/test/spec_rackup.rb +154 -0
  111. metadata +311 -0
@@ -0,0 +1,13 @@
1
+ require 'rack/nulllogger'
2
+ require 'rack/lint'
3
+ require 'rack/mock'
4
+
5
+ context "Rack::NullLogger" do
6
+ specify "acks as a nop logger" do
7
+ app = lambda { |env|
8
+ env['rack.logger'].warn "b00m"
9
+ [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]]
10
+ }
11
+ Rack::NullLogger.new(app).call({})
12
+ end
13
+ 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,545 @@
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.equal "0"
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", "SERVER_PORT" => "9292")
39
+ req.host.should.equal "example.org"
40
+
41
+ req = Rack::Request.new \
42
+ Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292")
43
+ req.host.should.equal "example.org"
44
+
45
+ env = Rack::MockRequest.env_for("/", "SERVER_ADDR" => "192.168.1.1", "SERVER_PORT" => "9292")
46
+ env.delete("SERVER_NAME")
47
+ req = Rack::Request.new(env)
48
+ req.host.should.equal "192.168.1.1"
49
+
50
+ env = Rack::MockRequest.env_for("/")
51
+ env.delete("SERVER_NAME")
52
+ req = Rack::Request.new(env)
53
+ req.host.should.equal ""
54
+ end
55
+
56
+ specify "can parse the query string" do
57
+ req = Rack::Request.new(Rack::MockRequest.env_for("/?foo=bar&quux=bla"))
58
+ req.query_string.should.equal "foo=bar&quux=bla"
59
+ req.GET.should.equal "foo" => "bar", "quux" => "bla"
60
+ req.POST.should.be.empty
61
+ req.params.should.equal "foo" => "bar", "quux" => "bla"
62
+ end
63
+
64
+ specify "raises if rack.input is missing" do
65
+ req = Rack::Request.new({})
66
+ lambda { req.POST }.should.raise(RuntimeError)
67
+ end
68
+
69
+ specify "can parse POST data when method is POST and no Content-Type given" do
70
+ req = Rack::Request.new \
71
+ Rack::MockRequest.env_for("/?foo=quux",
72
+ "REQUEST_METHOD" => 'POST',
73
+ :input => "foo=bar&quux=bla")
74
+ req.content_type.should.be.nil
75
+ req.media_type.should.be.nil
76
+ req.query_string.should.equal "foo=quux"
77
+ req.GET.should.equal "foo" => "quux"
78
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
79
+ req.params.should.equal "foo" => "bar", "quux" => "bla"
80
+ end
81
+
82
+ specify "can parse POST data with explicit content type regardless of method" do
83
+ req = Rack::Request.new \
84
+ Rack::MockRequest.env_for("/",
85
+ "CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
86
+ :input => "foo=bar&quux=bla")
87
+ req.content_type.should.equal 'application/x-www-form-urlencoded;foo=bar'
88
+ req.media_type.should.equal 'application/x-www-form-urlencoded'
89
+ req.media_type_params['foo'].should.equal 'bar'
90
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
91
+ req.params.should.equal "foo" => "bar", "quux" => "bla"
92
+ end
93
+
94
+ specify "does not parse POST data when media type is not form-data" do
95
+ req = Rack::Request.new \
96
+ Rack::MockRequest.env_for("/?foo=quux",
97
+ "REQUEST_METHOD" => 'POST',
98
+ "CONTENT_TYPE" => 'text/plain;charset=utf-8',
99
+ :input => "foo=bar&quux=bla")
100
+ req.content_type.should.equal 'text/plain;charset=utf-8'
101
+ req.media_type.should.equal 'text/plain'
102
+ req.media_type_params['charset'].should.equal 'utf-8'
103
+ req.POST.should.be.empty
104
+ req.params.should.equal "foo" => "quux"
105
+ req.body.read.should.equal "foo=bar&quux=bla"
106
+ end
107
+
108
+ specify "can parse POST data on PUT when media type is form-data" do
109
+ req = Rack::Request.new \
110
+ Rack::MockRequest.env_for("/?foo=quux",
111
+ "REQUEST_METHOD" => 'PUT',
112
+ "CONTENT_TYPE" => 'application/x-www-form-urlencoded',
113
+ :input => "foo=bar&quux=bla")
114
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
115
+ req.body.read.should.equal "foo=bar&quux=bla"
116
+ end
117
+
118
+ specify "rewinds input after parsing POST data" do
119
+ input = StringIO.new("foo=bar&quux=bla")
120
+ req = Rack::Request.new \
121
+ Rack::MockRequest.env_for("/",
122
+ "CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
123
+ :input => input)
124
+ req.params.should.equal "foo" => "bar", "quux" => "bla"
125
+ input.read.should.equal "foo=bar&quux=bla"
126
+ end
127
+
128
+ specify "cleans up Safari's ajax POST body" do
129
+ req = Rack::Request.new \
130
+ Rack::MockRequest.env_for("/",
131
+ 'REQUEST_METHOD' => 'POST', :input => "foo=bar&quux=bla\0")
132
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
133
+ end
134
+
135
+ specify "can get value by key from params with #[]" do
136
+ req = Rack::Request.new \
137
+ Rack::MockRequest.env_for("?foo=quux")
138
+ req['foo'].should.equal 'quux'
139
+ req[:foo].should.equal 'quux'
140
+ end
141
+
142
+ specify "can set value to key on params with #[]=" do
143
+ req = Rack::Request.new \
144
+ Rack::MockRequest.env_for("?foo=duh")
145
+ req['foo'].should.equal 'duh'
146
+ req[:foo].should.equal 'duh'
147
+ req.params.should.equal 'foo' => 'duh'
148
+
149
+ req['foo'] = 'bar'
150
+ req.params.should.equal 'foo' => 'bar'
151
+ req['foo'].should.equal 'bar'
152
+ req[:foo].should.equal 'bar'
153
+
154
+ req[:foo] = 'jaz'
155
+ req.params.should.equal 'foo' => 'jaz'
156
+ req['foo'].should.equal 'jaz'
157
+ req[:foo].should.equal 'jaz'
158
+ end
159
+
160
+ specify "values_at answers values by keys in order given" do
161
+ req = Rack::Request.new \
162
+ Rack::MockRequest.env_for("?foo=baz&wun=der&bar=ful")
163
+ req.values_at('foo').should.equal ['baz']
164
+ req.values_at('foo', 'wun').should.equal ['baz', 'der']
165
+ req.values_at('bar', 'foo', 'wun').should.equal ['ful', 'baz', 'der']
166
+ end
167
+
168
+ specify "referrer should be extracted correct" do
169
+ req = Rack::Request.new \
170
+ Rack::MockRequest.env_for("/", "HTTP_REFERER" => "/some/path")
171
+ req.referer.should.equal "/some/path"
172
+
173
+ req = Rack::Request.new \
174
+ Rack::MockRequest.env_for("/")
175
+ req.referer.should.equal "/"
176
+ end
177
+
178
+ specify "user agent should be extracted correct" do
179
+ req = Rack::Request.new \
180
+ Rack::MockRequest.env_for("/", "HTTP_USER_AGENT" => "Mozilla/4.0 (compatible)")
181
+ req.user_agent.should.equal "Mozilla/4.0 (compatible)"
182
+
183
+ req = Rack::Request.new \
184
+ Rack::MockRequest.env_for("/")
185
+ req.user_agent.should.equal nil
186
+ end
187
+
188
+ specify "can cache, but invalidates the cache" do
189
+ req = Rack::Request.new \
190
+ Rack::MockRequest.env_for("/?foo=quux",
191
+ "CONTENT_TYPE" => "application/x-www-form-urlencoded",
192
+ :input => "foo=bar&quux=bla")
193
+ req.GET.should.equal "foo" => "quux"
194
+ req.GET.should.equal "foo" => "quux"
195
+ req.env["QUERY_STRING"] = "bla=foo"
196
+ req.GET.should.equal "bla" => "foo"
197
+ req.GET.should.equal "bla" => "foo"
198
+
199
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
200
+ req.POST.should.equal "foo" => "bar", "quux" => "bla"
201
+ req.env["rack.input"] = StringIO.new("foo=bla&quux=bar")
202
+ req.POST.should.equal "foo" => "bla", "quux" => "bar"
203
+ req.POST.should.equal "foo" => "bla", "quux" => "bar"
204
+ end
205
+
206
+ specify "can figure out if called via XHR" do
207
+ req = Rack::Request.new(Rack::MockRequest.env_for(""))
208
+ req.should.not.be.xhr
209
+
210
+ req = Rack::Request.new \
211
+ Rack::MockRequest.env_for("", "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest")
212
+ req.should.be.xhr
213
+ end
214
+
215
+ specify "can parse cookies" do
216
+ req = Rack::Request.new \
217
+ Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
218
+ req.cookies.should.equal "foo" => "bar", "quux" => "h&m"
219
+ req.cookies.should.equal "foo" => "bar", "quux" => "h&m"
220
+ req.env.delete("HTTP_COOKIE")
221
+ req.cookies.should.equal({})
222
+ end
223
+
224
+ specify "parses cookies according to RFC 2109" do
225
+ req = Rack::Request.new \
226
+ Rack::MockRequest.env_for('', 'HTTP_COOKIE' => 'foo=bar;foo=car')
227
+ req.cookies.should.equal 'foo' => 'bar'
228
+ end
229
+
230
+ specify "provides setters" do
231
+ req = Rack::Request.new(e=Rack::MockRequest.env_for(""))
232
+ req.script_name.should.equal ""
233
+ req.script_name = "/foo"
234
+ req.script_name.should.equal "/foo"
235
+ e["SCRIPT_NAME"].should.equal "/foo"
236
+
237
+ req.path_info.should.equal "/"
238
+ req.path_info = "/foo"
239
+ req.path_info.should.equal "/foo"
240
+ e["PATH_INFO"].should.equal "/foo"
241
+ end
242
+
243
+ specify "provides the original env" do
244
+ req = Rack::Request.new(e=Rack::MockRequest.env_for(""))
245
+ req.env.should.be e
246
+ end
247
+
248
+ specify "can restore the URL" do
249
+ Rack::Request.new(Rack::MockRequest.env_for("")).url.
250
+ should.equal "http://example.org/"
251
+ Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).url.
252
+ should.equal "http://example.org/foo/"
253
+ Rack::Request.new(Rack::MockRequest.env_for("/foo")).url.
254
+ should.equal "http://example.org/foo"
255
+ Rack::Request.new(Rack::MockRequest.env_for("?foo")).url.
256
+ should.equal "http://example.org/?foo"
257
+ Rack::Request.new(Rack::MockRequest.env_for("http://example.org:8080/")).url.
258
+ should.equal "http://example.org:8080/"
259
+ Rack::Request.new(Rack::MockRequest.env_for("https://example.org/")).url.
260
+ should.equal "https://example.org/"
261
+
262
+ Rack::Request.new(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).url.
263
+ should.equal "https://example.com:8080/foo?foo"
264
+ end
265
+
266
+ specify "can restore the full path" do
267
+ Rack::Request.new(Rack::MockRequest.env_for("")).fullpath.
268
+ should.equal "/"
269
+ Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).fullpath.
270
+ should.equal "/foo/"
271
+ Rack::Request.new(Rack::MockRequest.env_for("/foo")).fullpath.
272
+ should.equal "/foo"
273
+ Rack::Request.new(Rack::MockRequest.env_for("?foo")).fullpath.
274
+ should.equal "/?foo"
275
+ Rack::Request.new(Rack::MockRequest.env_for("http://example.org:8080/")).fullpath.
276
+ should.equal "/"
277
+ Rack::Request.new(Rack::MockRequest.env_for("https://example.org/")).fullpath.
278
+ should.equal "/"
279
+
280
+ Rack::Request.new(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).fullpath.
281
+ should.equal "/foo?foo"
282
+ end
283
+
284
+ specify "can handle multiple media type parameters" do
285
+ req = Rack::Request.new \
286
+ Rack::MockRequest.env_for("/",
287
+ "CONTENT_TYPE" => 'text/plain; foo=BAR,baz=bizzle dizzle;BLING=bam')
288
+ req.should.not.be.form_data
289
+ req.media_type_params.should.include 'foo'
290
+ req.media_type_params['foo'].should.equal 'BAR'
291
+ req.media_type_params.should.include 'baz'
292
+ req.media_type_params['baz'].should.equal 'bizzle dizzle'
293
+ req.media_type_params.should.not.include 'BLING'
294
+ req.media_type_params.should.include 'bling'
295
+ req.media_type_params['bling'].should.equal 'bam'
296
+ end
297
+
298
+ specify "can parse multipart form data" do
299
+ # Adapted from RFC 1867.
300
+ input = <<EOF
301
+ --AaB03x\r
302
+ content-disposition: form-data; name="reply"\r
303
+ \r
304
+ yes\r
305
+ --AaB03x\r
306
+ content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
307
+ Content-Type: image/jpeg\r
308
+ Content-Transfer-Encoding: base64\r
309
+ \r
310
+ /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
311
+ --AaB03x--\r
312
+ EOF
313
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
314
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
315
+ "CONTENT_LENGTH" => input.size,
316
+ :input => input)
317
+
318
+ req.POST.should.include "fileupload"
319
+ req.POST.should.include "reply"
320
+
321
+ req.should.be.form_data
322
+ req.content_length.should.equal input.size
323
+ req.media_type.should.equal 'multipart/form-data'
324
+ req.media_type_params.should.include 'boundary'
325
+ req.media_type_params['boundary'].should.equal 'AaB03x'
326
+
327
+ req.POST["reply"].should.equal "yes"
328
+
329
+ f = req.POST["fileupload"]
330
+ f.should.be.kind_of Hash
331
+ f[:type].should.equal "image/jpeg"
332
+ f[:filename].should.equal "dj.jpg"
333
+ f.should.include :tempfile
334
+ f[:tempfile].size.should.equal 76
335
+ end
336
+
337
+ specify "can parse big multipart form data" do
338
+ input = <<EOF
339
+ --AaB03x\r
340
+ content-disposition: form-data; name="huge"; filename="huge"\r
341
+ \r
342
+ #{"x"*32768}\r
343
+ --AaB03x\r
344
+ content-disposition: form-data; name="mean"; filename="mean"\r
345
+ \r
346
+ --AaB03xha\r
347
+ --AaB03x--\r
348
+ EOF
349
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
350
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
351
+ "CONTENT_LENGTH" => input.size,
352
+ :input => input)
353
+
354
+ req.POST["huge"][:tempfile].size.should.equal 32768
355
+ req.POST["mean"][:tempfile].size.should.equal 10
356
+ req.POST["mean"][:tempfile].read.should.equal "--AaB03xha"
357
+ end
358
+
359
+ specify "can detect invalid multipart form data" do
360
+ input = <<EOF
361
+ --AaB03x\r
362
+ content-disposition: form-data; name="huge"; filename="huge"\r
363
+ EOF
364
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
365
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
366
+ "CONTENT_LENGTH" => input.size,
367
+ :input => input)
368
+
369
+ lambda { req.POST }.should.raise(EOFError)
370
+
371
+ input = <<EOF
372
+ --AaB03x\r
373
+ content-disposition: form-data; name="huge"; filename="huge"\r
374
+ \r
375
+ foo\r
376
+ EOF
377
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
378
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
379
+ "CONTENT_LENGTH" => input.size,
380
+ :input => input)
381
+
382
+ lambda { req.POST }.should.raise(EOFError)
383
+
384
+ input = <<EOF
385
+ --AaB03x\r
386
+ content-disposition: form-data; name="huge"; filename="huge"\r
387
+ \r
388
+ foo\r
389
+ EOF
390
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
391
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
392
+ "CONTENT_LENGTH" => input.size,
393
+ :input => input)
394
+
395
+ lambda { req.POST }.should.raise(EOFError)
396
+ end
397
+
398
+ specify "shouldn't try to interpret binary as utf8" do
399
+ begin
400
+ original_kcode = $KCODE
401
+ $KCODE='UTF8'
402
+
403
+ input = <<EOF
404
+ --AaB03x\r
405
+ content-disposition: form-data; name="fileupload"; filename="junk.a"\r
406
+ content-type: application/octet-stream\r
407
+ \r
408
+ #{[0x36,0xCF,0x0A,0xF8].pack('c*')}\r
409
+ --AaB03x--\r
410
+ EOF
411
+
412
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
413
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
414
+ "CONTENT_LENGTH" => input.size,
415
+ :input => input)
416
+
417
+ lambda{req.POST}.should.not.raise(EOFError)
418
+ req.POST["fileupload"][:tempfile].size.should.equal 4
419
+ ensure
420
+ $KCODE = original_kcode
421
+ end
422
+ end
423
+
424
+
425
+ specify "should work around buggy 1.8.* Tempfile equality" do
426
+ input = <<EOF
427
+ --AaB03x\r
428
+ content-disposition: form-data; name="huge"; filename="huge"\r
429
+ \r
430
+ foo\r
431
+ --AaB03x--
432
+ EOF
433
+
434
+ rack_input = Tempfile.new("rackspec")
435
+ rack_input.write(input)
436
+ rack_input.rewind
437
+
438
+ req = Rack::Request.new Rack::MockRequest.env_for("/",
439
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
440
+ "CONTENT_LENGTH" => input.size,
441
+ :input => rack_input)
442
+
443
+ lambda {req.POST}.should.not.raise
444
+ lambda {req.POST}.should.blaming("input re-processed!").not.raise
445
+ end
446
+
447
+ specify "does conform to the Rack spec" do
448
+ app = lambda { |env|
449
+ content = Rack::Request.new(env).POST["file"].inspect
450
+ size = content.respond_to?(:bytesize) ? content.bytesize : content.size
451
+ [200, {"Content-Type" => "text/html", "Content-Length" => size.to_s}, [content]]
452
+ }
453
+
454
+ input = <<EOF
455
+ --AaB03x\r
456
+ content-disposition: form-data; name="reply"\r
457
+ \r
458
+ yes\r
459
+ --AaB03x\r
460
+ content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
461
+ Content-Type: image/jpeg\r
462
+ Content-Transfer-Encoding: base64\r
463
+ \r
464
+ /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
465
+ --AaB03x--\r
466
+ EOF
467
+ input.force_encoding("ASCII-8BIT") if input.respond_to? :force_encoding
468
+ res = Rack::MockRequest.new(Rack::Lint.new(app)).get "/",
469
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
470
+ "CONTENT_LENGTH" => input.size.to_s, "rack.input" => StringIO.new(input)
471
+
472
+ res.should.be.ok
473
+ end
474
+
475
+ specify "should parse Accept-Encoding correctly" do
476
+ parser = lambda do |x|
477
+ Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => x)).accept_encoding
478
+ end
479
+
480
+ parser.call(nil).should.equal([])
481
+
482
+ parser.call("compress, gzip").should.equal([["compress", 1.0], ["gzip", 1.0]])
483
+ parser.call("").should.equal([])
484
+ parser.call("*").should.equal([["*", 1.0]])
485
+ parser.call("compress;q=0.5, gzip;q=1.0").should.equal([["compress", 0.5], ["gzip", 1.0]])
486
+ parser.call("gzip;q=1.0, identity; q=0.5, *;q=0").should.equal([["gzip", 1.0], ["identity", 0.5], ["*", 0] ])
487
+
488
+ lambda { parser.call("gzip ; q=1.0") }.should.raise(RuntimeError)
489
+ end
490
+
491
+ specify 'should provide ip information' do
492
+ app = lambda { |env|
493
+ request = Rack::Request.new(env)
494
+ response = Rack::Response.new
495
+ response.write request.ip
496
+ response.finish
497
+ }
498
+
499
+ mock = Rack::MockRequest.new(Rack::Lint.new(app))
500
+ res = mock.get '/', 'REMOTE_ADDR' => '123.123.123.123'
501
+ res.body.should.equal '123.123.123.123'
502
+
503
+ res = mock.get '/',
504
+ 'REMOTE_ADDR' => '123.123.123.123',
505
+ 'HTTP_X_FORWARDED_FOR' => '234.234.234.234'
506
+
507
+ res.body.should.equal '234.234.234.234'
508
+
509
+ res = mock.get '/',
510
+ 'REMOTE_ADDR' => '123.123.123.123',
511
+ 'HTTP_X_FORWARDED_FOR' => '234.234.234.234,212.212.212.212'
512
+
513
+ res.body.should.equal '212.212.212.212'
514
+ end
515
+
516
+ class MyRequest < Rack::Request
517
+ def params
518
+ {:foo => "bar"}
519
+ end
520
+ end
521
+
522
+ specify "should allow subclass request to be instantiated after parent request" do
523
+ env = Rack::MockRequest.env_for("/?foo=bar")
524
+
525
+ req1 = Rack::Request.new(env)
526
+ req1.GET.should.equal "foo" => "bar"
527
+ req1.params.should.equal "foo" => "bar"
528
+
529
+ req2 = MyRequest.new(env)
530
+ req2.GET.should.equal "foo" => "bar"
531
+ req2.params.should.equal :foo => "bar"
532
+ end
533
+
534
+ specify "should allow parent request to be instantiated after subclass request" do
535
+ env = Rack::MockRequest.env_for("/?foo=bar")
536
+
537
+ req1 = MyRequest.new(env)
538
+ req1.GET.should.equal "foo" => "bar"
539
+ req1.params.should.equal :foo => "bar"
540
+
541
+ req2 = Rack::Request.new(env)
542
+ req2.GET.should.equal "foo" => "bar"
543
+ req2.params.should.equal "foo" => "bar"
544
+ end
545
+ end