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,426 @@
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
+ size = content.respond_to?(:bytesize) ? content.bytesize : content.size
363
+ [200, {"Content-Type" => "text/html", "Content-Length" => size.to_s}, content]
364
+ }
365
+
366
+ input = <<EOF
367
+ --AaB03x\r
368
+ content-disposition: form-data; name="reply"\r
369
+ \r
370
+ yes\r
371
+ --AaB03x\r
372
+ content-disposition: form-data; name="fileupload"; filename="dj.jpg"\r
373
+ Content-Type: image/jpeg\r
374
+ Content-Transfer-Encoding: base64\r
375
+ \r
376
+ /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r
377
+ --AaB03x--\r
378
+ EOF
379
+ res = Rack::MockRequest.new(Rack::Lint.new(app)).get "/",
380
+ "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
381
+ "CONTENT_LENGTH" => input.size.to_s, "rack.input" => StringIO.new(input)
382
+
383
+ res.should.be.ok
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
401
+
402
+ specify 'should provide ip information' do
403
+ app = lambda { |env|
404
+ request = Rack::Request.new(env)
405
+ response = Rack::Response.new
406
+ response.write request.ip
407
+ response.finish
408
+ }
409
+
410
+ mock = Rack::MockRequest.new(Rack::Lint.new(app))
411
+ res = mock.get '/', 'REMOTE_ADDR' => '123.123.123.123'
412
+ res.body.should == '123.123.123.123'
413
+
414
+ res = mock.get '/',
415
+ 'REMOTE_ADDR' => '123.123.123.123',
416
+ 'HTTP_X_FORWARDED_FOR' => '234.234.234.234'
417
+
418
+ res.body.should == '234.234.234.234'
419
+
420
+ res = mock.get '/',
421
+ 'REMOTE_ADDR' => '123.123.123.123',
422
+ 'HTTP_X_FORWARDED_FOR' => '234.234.234.234,212.212.212.212'
423
+
424
+ res.body.should == '212.212.212.212'
425
+ end
426
+ end
@@ -0,0 +1,173 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/response'
4
+
5
+ context "Rack::Response" do
6
+ specify "has sensible default values" do
7
+ response = Rack::Response.new
8
+ status, header, body = response.finish
9
+ status.should.equal 200
10
+ header.should.equal "Content-Type" => "text/html", "Content-Length" => "0"
11
+ body.each { |part|
12
+ part.should.equal ""
13
+ }
14
+
15
+ response = Rack::Response.new
16
+ status, header, body = *response
17
+ status.should.equal 200
18
+ header.should.equal "Content-Type" => "text/html", "Content-Length" => "0"
19
+ body.each { |part|
20
+ part.should.equal ""
21
+ }
22
+ end
23
+
24
+ specify "can be written to" do
25
+ response = Rack::Response.new
26
+
27
+ status, header, body = response.finish do
28
+ response.write "foo"
29
+ response.write "bar"
30
+ response.write "baz"
31
+ end
32
+
33
+ parts = []
34
+ body.each { |part| parts << part }
35
+
36
+ parts.should.equal ["foo", "bar", "baz"]
37
+ end
38
+
39
+ specify "can set and read headers" do
40
+ response = Rack::Response.new
41
+ response["Content-Type"].should.equal "text/html"
42
+ response["Content-Type"] = "text/plain"
43
+ response["Content-Type"].should.equal "text/plain"
44
+ end
45
+
46
+ specify "can set cookies" do
47
+ response = Rack::Response.new
48
+
49
+ response.set_cookie "foo", "bar"
50
+ response["Set-Cookie"].should.equal "foo=bar"
51
+ response.set_cookie "foo2", "bar2"
52
+ response["Set-Cookie"].should.equal ["foo=bar", "foo2=bar2"]
53
+ response.set_cookie "foo3", "bar3"
54
+ response["Set-Cookie"].should.equal ["foo=bar", "foo2=bar2", "foo3=bar3"]
55
+ end
56
+
57
+ specify "formats the Cookie expiration date accordingly to RFC 2109" do
58
+ response = Rack::Response.new
59
+
60
+ response.set_cookie "foo", {:value => "bar", :expires => Time.now+10}
61
+ response["Set-Cookie"].should.match(
62
+ /expires=..., \d\d-...-\d\d\d\d \d\d:\d\d:\d\d .../)
63
+ end
64
+
65
+ specify "can set secure cookies" do
66
+ response = Rack::Response.new
67
+ response.set_cookie "foo", {:value => "bar", :secure => true}
68
+ response["Set-Cookie"].should.equal "foo=bar; secure"
69
+ end
70
+
71
+ specify "can delete cookies" do
72
+ response = Rack::Response.new
73
+ response.set_cookie "foo", "bar"
74
+ response.set_cookie "foo2", "bar2"
75
+ response.delete_cookie "foo"
76
+ response["Set-Cookie"].should.equal ["foo2=bar2",
77
+ "foo=; expires=Thu, 01-Jan-1970 00:00:00 GMT"]
78
+ end
79
+
80
+ specify "has a useful constructor" do
81
+ r = Rack::Response.new("foo")
82
+ status, header, body = r.finish
83
+ str = ""; body.each { |part| str << part }
84
+ str.should.equal "foo"
85
+
86
+ r = Rack::Response.new(["foo", "bar"])
87
+ status, header, body = r.finish
88
+ str = ""; body.each { |part| str << part }
89
+ str.should.equal "foobar"
90
+
91
+ r = Rack::Response.new({"foo", "bar"})
92
+ r.write "foo"
93
+ status, header, body = r.finish
94
+ str = ""; body.each { |part| str << part }
95
+ str.should.equal "foobarfoo"
96
+
97
+ r = Rack::Response.new([], 500)
98
+ r.status.should.equal 500
99
+ end
100
+
101
+ specify "has a constructor that can take a block" do
102
+ r = Rack::Response.new { |res|
103
+ res.status = 404
104
+ res.write "foo"
105
+ }
106
+ status, header, body = r.finish
107
+ str = ""; body.each { |part| str << part }
108
+ str.should.equal "foo"
109
+ status.should.equal 404
110
+ end
111
+
112
+ specify "doesn't return invalid responses" do
113
+ r = Rack::Response.new(["foo", "bar"], 204)
114
+ status, header, body = r.finish
115
+ str = ""; body.each { |part| str << part }
116
+ str.should.be.empty
117
+ header["Content-Type"].should.equal nil
118
+
119
+ lambda {
120
+ Rack::Response.new(Object.new)
121
+ }.should.raise(TypeError).
122
+ message.should =~ /stringable or iterable required/
123
+ end
124
+
125
+ specify "knows if it's empty" do
126
+ r = Rack::Response.new
127
+ r.should.be.empty
128
+ r.write "foo"
129
+ r.should.not.be.empty
130
+
131
+ r = Rack::Response.new
132
+ r.should.be.empty
133
+ r.finish
134
+ r.should.be.empty
135
+
136
+ r = Rack::Response.new
137
+ r.should.be.empty
138
+ r.finish { }
139
+ r.should.not.be.empty
140
+ end
141
+
142
+ specify "should provide access to the HTTP status" do
143
+ res = Rack::Response.new
144
+ res.status = 200
145
+ res.should.be.successful
146
+ res.should.be.ok
147
+
148
+ res.status = 404
149
+ res.should.not.be.successful
150
+ res.should.be.client_error
151
+ res.should.be.not_found
152
+
153
+ res.status = 501
154
+ res.should.not.be.successful
155
+ res.should.be.server_error
156
+
157
+ res.status = 307
158
+ res.should.be.redirect
159
+ end
160
+
161
+ specify "should provide access to the HTTP headers" do
162
+ res = Rack::Response.new
163
+ res["Content-Type"] = "text/yaml"
164
+
165
+ res.should.include "Content-Type"
166
+ res.headers["Content-Type"].should.equal "text/yaml"
167
+ res["Content-Type"].should.equal "text/yaml"
168
+ res.content_type.should.equal "text/yaml"
169
+ res.content_length.should.be.nil
170
+ res.location.should.be.nil
171
+ end
172
+
173
+ end