rack 1.0.1 → 2.2.21

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 (147) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +829 -0
  3. data/CONTRIBUTING.md +136 -0
  4. data/{COPYING → MIT-LICENSE} +4 -2
  5. data/README.rdoc +355 -0
  6. data/Rakefile +64 -98
  7. data/SPEC.rdoc +292 -0
  8. data/bin/rackup +3 -174
  9. data/contrib/rack.png +0 -0
  10. data/contrib/rack.svg +150 -0
  11. data/contrib/rack_logo.svg +164 -111
  12. data/contrib/rdoc.css +412 -0
  13. data/example/lobster.ru +2 -0
  14. data/example/protectedlobster.rb +4 -2
  15. data/example/protectedlobster.ru +3 -1
  16. data/lib/rack/auth/abstract/handler.rb +7 -5
  17. data/lib/rack/auth/abstract/request.rb +12 -2
  18. data/lib/rack/auth/basic.rb +6 -4
  19. data/lib/rack/auth/digest/md5.rb +20 -13
  20. data/lib/rack/auth/digest/nonce.rb +6 -4
  21. data/lib/rack/auth/digest/params.rb +11 -12
  22. data/lib/rack/auth/digest/request.rb +15 -12
  23. data/lib/rack/body_proxy.rb +45 -0
  24. data/lib/rack/builder.rb +213 -19
  25. data/lib/rack/cascade.rb +50 -18
  26. data/lib/rack/chunked.rb +95 -27
  27. data/lib/rack/common_logger.rb +84 -0
  28. data/lib/rack/conditional_get.rb +83 -0
  29. data/lib/rack/config.rb +22 -0
  30. data/lib/rack/content_length.rb +19 -10
  31. data/lib/rack/content_type.rb +12 -5
  32. data/lib/rack/core_ext/regexp.rb +14 -0
  33. data/lib/rack/deflater.rb +90 -42
  34. data/lib/rack/directory.rb +118 -72
  35. data/lib/rack/etag.rb +77 -0
  36. data/lib/rack/events.rb +153 -0
  37. data/lib/rack/file.rb +4 -85
  38. data/lib/rack/files.rb +218 -0
  39. data/lib/rack/handler/cgi.rb +22 -24
  40. data/lib/rack/handler/fastcgi.rb +34 -24
  41. data/lib/rack/handler/lsws.rb +16 -15
  42. data/lib/rack/handler/scgi.rb +38 -29
  43. data/lib/rack/handler/thin.rb +23 -7
  44. data/lib/rack/handler/webrick.rb +95 -37
  45. data/lib/rack/handler.rb +49 -14
  46. data/lib/rack/head.rb +19 -13
  47. data/lib/rack/lint.rb +466 -217
  48. data/lib/rack/lobster.rb +19 -14
  49. data/lib/rack/lock.rb +24 -8
  50. data/lib/rack/logger.rb +20 -0
  51. data/lib/rack/media_type.rb +53 -0
  52. data/lib/rack/method_override.rb +52 -0
  53. data/lib/rack/mime.rb +652 -171
  54. data/lib/rack/mock.rb +203 -64
  55. data/lib/rack/multipart/generator.rb +97 -0
  56. data/lib/rack/multipart/parser.rb +440 -0
  57. data/lib/rack/multipart/uploaded_file.rb +41 -0
  58. data/lib/rack/multipart.rb +64 -0
  59. data/lib/rack/null_logger.rb +39 -0
  60. data/lib/rack/query_parser.rb +266 -0
  61. data/lib/rack/recursive.rb +18 -11
  62. data/lib/rack/reloader.rb +13 -5
  63. data/lib/rack/request.rb +607 -191
  64. data/lib/rack/response.rb +245 -110
  65. data/lib/rack/rewindable_input.rb +15 -21
  66. data/lib/rack/runtime.rb +34 -0
  67. data/lib/rack/sendfile.rb +192 -0
  68. data/lib/rack/server.rb +466 -0
  69. data/lib/rack/session/abstract/id.rb +449 -68
  70. data/lib/rack/session/cookie.rb +159 -47
  71. data/lib/rack/session/memcache.rb +4 -103
  72. data/lib/rack/session/pool.rb +39 -49
  73. data/lib/rack/show_exceptions.rb +390 -0
  74. data/lib/rack/{showstatus.rb → show_status.rb} +21 -14
  75. data/lib/rack/static.rb +164 -14
  76. data/lib/rack/tempfile_reaper.rb +22 -0
  77. data/lib/rack/urlmap.rb +60 -18
  78. data/lib/rack/utils.rb +508 -277
  79. data/lib/rack/version.rb +29 -0
  80. data/lib/rack.rb +85 -34
  81. data/rack.gemspec +43 -51
  82. metadata +119 -207
  83. data/KNOWN-ISSUES +0 -18
  84. data/RDOX +0 -428
  85. data/README +0 -364
  86. data/SPEC +0 -164
  87. data/lib/rack/adapter/camping.rb +0 -22
  88. data/lib/rack/auth/openid.rb +0 -480
  89. data/lib/rack/commonlogger.rb +0 -61
  90. data/lib/rack/conditionalget.rb +0 -47
  91. data/lib/rack/handler/evented_mongrel.rb +0 -8
  92. data/lib/rack/handler/mongrel.rb +0 -87
  93. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  94. data/lib/rack/methodoverride.rb +0 -27
  95. data/lib/rack/showexceptions.rb +0 -349
  96. data/test/cgi/lighttpd.conf +0 -20
  97. data/test/cgi/test +0 -9
  98. data/test/cgi/test.fcgi +0 -8
  99. data/test/cgi/test.ru +0 -7
  100. data/test/multipart/binary +0 -0
  101. data/test/multipart/empty +0 -10
  102. data/test/multipart/ie +0 -6
  103. data/test/multipart/nested +0 -10
  104. data/test/multipart/none +0 -9
  105. data/test/multipart/semicolon +0 -6
  106. data/test/multipart/text +0 -10
  107. data/test/spec_rack_auth_basic.rb +0 -73
  108. data/test/spec_rack_auth_digest.rb +0 -226
  109. data/test/spec_rack_auth_openid.rb +0 -84
  110. data/test/spec_rack_builder.rb +0 -84
  111. data/test/spec_rack_camping.rb +0 -51
  112. data/test/spec_rack_cascade.rb +0 -50
  113. data/test/spec_rack_cgi.rb +0 -89
  114. data/test/spec_rack_chunked.rb +0 -62
  115. data/test/spec_rack_commonlogger.rb +0 -32
  116. data/test/spec_rack_conditionalget.rb +0 -41
  117. data/test/spec_rack_content_length.rb +0 -43
  118. data/test/spec_rack_content_type.rb +0 -30
  119. data/test/spec_rack_deflater.rb +0 -127
  120. data/test/spec_rack_directory.rb +0 -61
  121. data/test/spec_rack_fastcgi.rb +0 -89
  122. data/test/spec_rack_file.rb +0 -75
  123. data/test/spec_rack_handler.rb +0 -43
  124. data/test/spec_rack_head.rb +0 -30
  125. data/test/spec_rack_lint.rb +0 -521
  126. data/test/spec_rack_lobster.rb +0 -45
  127. data/test/spec_rack_lock.rb +0 -38
  128. data/test/spec_rack_methodoverride.rb +0 -60
  129. data/test/spec_rack_mock.rb +0 -157
  130. data/test/spec_rack_mongrel.rb +0 -189
  131. data/test/spec_rack_recursive.rb +0 -77
  132. data/test/spec_rack_request.rb +0 -504
  133. data/test/spec_rack_response.rb +0 -218
  134. data/test/spec_rack_rewindable_input.rb +0 -118
  135. data/test/spec_rack_session_cookie.rb +0 -82
  136. data/test/spec_rack_session_memcache.rb +0 -240
  137. data/test/spec_rack_session_pool.rb +0 -172
  138. data/test/spec_rack_showexceptions.rb +0 -21
  139. data/test/spec_rack_showstatus.rb +0 -72
  140. data/test/spec_rack_static.rb +0 -37
  141. data/test/spec_rack_thin.rb +0 -91
  142. data/test/spec_rack_urlmap.rb +0 -185
  143. data/test/spec_rack_utils.rb +0 -387
  144. data/test/spec_rack_webrick.rb +0 -130
  145. data/test/testrequest.rb +0 -57
  146. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  147. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
@@ -1,387 +0,0 @@
1
- require 'test/spec'
2
-
3
- require 'rack/utils'
4
- require 'rack/lint'
5
- require 'rack/mock'
6
-
7
- context "Rack::Utils" do
8
- specify "should escape correctly" do
9
- Rack::Utils.escape("fo<o>bar").should.equal "fo%3Co%3Ebar"
10
- Rack::Utils.escape("a space").should.equal "a+space"
11
- Rack::Utils.escape("q1!2\"'w$5&7/z8)?\\").
12
- should.equal "q1%212%22%27w%245%267%2Fz8%29%3F%5C"
13
- end
14
-
15
- specify "should escape correctly for multibyte characters" do
16
- matz_name = "\xE3\x81\xBE\xE3\x81\xA4\xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsumoto
17
- matz_name.force_encoding("UTF-8") if matz_name.respond_to? :force_encoding
18
- Rack::Utils.escape(matz_name).should.equal '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8'
19
- matz_name_sep = "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsu moto
20
- matz_name_sep.force_encoding("UTF-8") if matz_name_sep.respond_to? :force_encoding
21
- Rack::Utils.escape(matz_name_sep).should.equal '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8'
22
- end
23
-
24
- specify "should unescape correctly" do
25
- Rack::Utils.unescape("fo%3Co%3Ebar").should.equal "fo<o>bar"
26
- Rack::Utils.unescape("a+space").should.equal "a space"
27
- Rack::Utils.unescape("a%20space").should.equal "a space"
28
- Rack::Utils.unescape("q1%212%22%27w%245%267%2Fz8%29%3F%5C").
29
- should.equal "q1!2\"'w$5&7/z8)?\\"
30
- end
31
-
32
- specify "should parse query strings correctly" do
33
- Rack::Utils.parse_query("foo=bar").should.equal "foo" => "bar"
34
- Rack::Utils.parse_query("foo=bar&foo=quux").
35
- should.equal "foo" => ["bar", "quux"]
36
- Rack::Utils.parse_query("foo=1&bar=2").
37
- should.equal "foo" => "1", "bar" => "2"
38
- Rack::Utils.parse_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F").
39
- should.equal "my weird field" => "q1!2\"'w$5&7/z8)?"
40
- Rack::Utils.parse_query("foo%3Dbaz=bar").should.equal "foo=baz" => "bar"
41
- end
42
-
43
- specify "should parse nested query strings correctly" do
44
- Rack::Utils.parse_nested_query("foo").
45
- should.equal "foo" => nil
46
- Rack::Utils.parse_nested_query("foo=").
47
- should.equal "foo" => ""
48
- Rack::Utils.parse_nested_query("foo=bar").
49
- should.equal "foo" => "bar"
50
-
51
- Rack::Utils.parse_nested_query("foo=bar&foo=quux").
52
- should.equal "foo" => "quux"
53
- Rack::Utils.parse_nested_query("foo&foo=").
54
- should.equal "foo" => ""
55
- Rack::Utils.parse_nested_query("foo=1&bar=2").
56
- should.equal "foo" => "1", "bar" => "2"
57
- Rack::Utils.parse_nested_query("&foo=1&&bar=2").
58
- should.equal "foo" => "1", "bar" => "2"
59
- Rack::Utils.parse_nested_query("foo&bar=").
60
- should.equal "foo" => nil, "bar" => ""
61
- Rack::Utils.parse_nested_query("foo=bar&baz=").
62
- should.equal "foo" => "bar", "baz" => ""
63
- Rack::Utils.parse_nested_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F").
64
- should.equal "my weird field" => "q1!2\"'w$5&7/z8)?"
65
-
66
- Rack::Utils.parse_nested_query("foo[]").
67
- should.equal "foo" => [nil]
68
- Rack::Utils.parse_nested_query("foo[]=").
69
- should.equal "foo" => [""]
70
- Rack::Utils.parse_nested_query("foo[]=bar").
71
- should.equal "foo" => ["bar"]
72
-
73
- Rack::Utils.parse_nested_query("foo[]=1&foo[]=2").
74
- should.equal "foo" => ["1", "2"]
75
- Rack::Utils.parse_nested_query("foo=bar&baz[]=1&baz[]=2&baz[]=3").
76
- should.equal "foo" => "bar", "baz" => ["1", "2", "3"]
77
- Rack::Utils.parse_nested_query("foo[]=bar&baz[]=1&baz[]=2&baz[]=3").
78
- should.equal "foo" => ["bar"], "baz" => ["1", "2", "3"]
79
-
80
- Rack::Utils.parse_nested_query("x[y][z]=1").
81
- should.equal "x" => {"y" => {"z" => "1"}}
82
- Rack::Utils.parse_nested_query("x[y][z][]=1").
83
- should.equal "x" => {"y" => {"z" => ["1"]}}
84
- Rack::Utils.parse_nested_query("x[y][z]=1&x[y][z]=2").
85
- should.equal "x" => {"y" => {"z" => "2"}}
86
- Rack::Utils.parse_nested_query("x[y][z][]=1&x[y][z][]=2").
87
- should.equal "x" => {"y" => {"z" => ["1", "2"]}}
88
-
89
- Rack::Utils.parse_nested_query("x[y][][z]=1").
90
- should.equal "x" => {"y" => [{"z" => "1"}]}
91
- Rack::Utils.parse_nested_query("x[y][][z][]=1").
92
- should.equal "x" => {"y" => [{"z" => ["1"]}]}
93
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][w]=2").
94
- should.equal "x" => {"y" => [{"z" => "1", "w" => "2"}]}
95
-
96
- Rack::Utils.parse_nested_query("x[y][][v][w]=1").
97
- should.equal "x" => {"y" => [{"v" => {"w" => "1"}}]}
98
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][v][w]=2").
99
- should.equal "x" => {"y" => [{"z" => "1", "v" => {"w" => "2"}}]}
100
-
101
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][z]=2").
102
- should.equal "x" => {"y" => [{"z" => "1"}, {"z" => "2"}]}
103
- Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][w]=a&x[y][][z]=2&x[y][][w]=3").
104
- should.equal "x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}
105
-
106
- lambda { Rack::Utils.parse_nested_query("x[y]=1&x[y]z=2") }.
107
- should.raise(TypeError).
108
- message.should.equal "expected Hash (got String) for param `y'"
109
-
110
- lambda { Rack::Utils.parse_nested_query("x[y]=1&x[]=1") }.
111
- should.raise(TypeError).
112
- message.should.equal "expected Array (got Hash) for param `x'"
113
-
114
- lambda { Rack::Utils.parse_nested_query("x[y]=1&x[y][][w]=2") }.
115
- should.raise(TypeError).
116
- message.should.equal "expected Array (got String) for param `y'"
117
- end
118
-
119
- specify "should build query strings correctly" do
120
- Rack::Utils.build_query("foo" => "bar").should.equal "foo=bar"
121
- Rack::Utils.build_query("foo" => ["bar", "quux"]).
122
- should.equal "foo=bar&foo=quux"
123
- Rack::Utils.build_query("foo" => "1", "bar" => "2").
124
- should.equal "foo=1&bar=2"
125
- Rack::Utils.build_query("my weird field" => "q1!2\"'w$5&7/z8)?").
126
- should.equal "my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F"
127
- end
128
-
129
- specify "should figure out which encodings are acceptable" do
130
- helper = lambda do |a, b|
131
- request = Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => a))
132
- Rack::Utils.select_best_encoding(a, b)
133
- end
134
-
135
- helper.call(%w(), [["x", 1]]).should.equal(nil)
136
- helper.call(%w(identity), [["identity", 0.0]]).should.equal(nil)
137
- helper.call(%w(identity), [["*", 0.0]]).should.equal(nil)
138
-
139
- helper.call(%w(identity), [["compress", 1.0], ["gzip", 1.0]]).should.equal("identity")
140
-
141
- helper.call(%w(compress gzip identity), [["compress", 1.0], ["gzip", 1.0]]).should.equal("compress")
142
- helper.call(%w(compress gzip identity), [["compress", 0.5], ["gzip", 1.0]]).should.equal("gzip")
143
-
144
- helper.call(%w(foo bar identity), []).should.equal("identity")
145
- helper.call(%w(foo bar identity), [["*", 1.0]]).should.equal("foo")
146
- helper.call(%w(foo bar identity), [["*", 1.0], ["foo", 0.9]]).should.equal("bar")
147
-
148
- helper.call(%w(foo bar identity), [["foo", 0], ["bar", 0]]).should.equal("identity")
149
- helper.call(%w(foo bar baz identity), [["*", 0], ["identity", 0.1]]).should.equal("identity")
150
- end
151
-
152
- specify "should return the bytesize of String" do
153
- Rack::Utils.bytesize("FOO\xE2\x82\xAC").should.equal 6
154
- end
155
- end
156
-
157
- context "Rack::Utils::HeaderHash" do
158
- specify "should retain header case" do
159
- h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
160
- h['ETag'] = 'Boo!'
161
- h.to_hash.should.equal "Content-MD5" => "d5ff4e2a0 ...", "ETag" => 'Boo!'
162
- end
163
-
164
- specify "should check existence of keys case insensitively" do
165
- h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
166
- h.should.include 'content-md5'
167
- h.should.not.include 'ETag'
168
- end
169
-
170
- specify "should merge case-insensitively" do
171
- h = Rack::Utils::HeaderHash.new("ETag" => 'HELLO', "content-length" => '123')
172
- merged = h.merge("Etag" => 'WORLD', 'Content-Length' => '321', "Foo" => 'BAR')
173
- merged.should.equal "Etag"=>'WORLD', "Content-Length"=>'321', "Foo"=>'BAR'
174
- end
175
-
176
- specify "should overwrite case insensitively and assume the new key's case" do
177
- h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz")
178
- h["foo-bar"] = "bizzle"
179
- h["FOO-BAR"].should.equal "bizzle"
180
- h.length.should.equal 1
181
- h.to_hash.should.equal "foo-bar" => "bizzle"
182
- end
183
-
184
- specify "should be converted to real Hash" do
185
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
186
- h.to_hash.should.be.instance_of Hash
187
- end
188
-
189
- specify "should convert Array values to Strings when converting to Hash" do
190
- h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"])
191
- h.to_hash.should.equal({ "foo" => "bar\nbaz" })
192
- end
193
-
194
- specify "should be able to delete the given key case-sensitively" do
195
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
196
- h.delete("foo")
197
- h["foo"].should.be.nil
198
- h["FOO"].should.be.nil
199
- end
200
-
201
- specify "should be able to delete the given key case-insensitively" do
202
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
203
- h.delete("FOO")
204
- h["foo"].should.be.nil
205
- h["FOO"].should.be.nil
206
- end
207
-
208
- specify "should return the deleted value when #delete is called on an existing key" do
209
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
210
- h.delete("Foo").should.equal("bar")
211
- end
212
-
213
- specify "should return nil when #delete is called on a non-existant key" do
214
- h = Rack::Utils::HeaderHash.new("foo" => "bar")
215
- h.delete("Hello").should.be.nil
216
- end
217
- end
218
-
219
- context "Rack::Utils::Context" do
220
- class ContextTest
221
- attr_reader :app
222
- def initialize app; @app=app; end
223
- def call env; context env; end
224
- def context env, app=@app; app.call(env); end
225
- end
226
- test_target1 = proc{|e| e.to_s+' world' }
227
- test_target2 = proc{|e| e.to_i+2 }
228
- test_target3 = proc{|e| nil }
229
- test_target4 = proc{|e| [200,{'Content-Type'=>'text/plain', 'Content-Length'=>'0'},['']] }
230
- test_app = ContextTest.new test_target4
231
-
232
- specify "should set context correctly" do
233
- test_app.app.should.equal test_target4
234
- c1 = Rack::Utils::Context.new(test_app, test_target1)
235
- c1.for.should.equal test_app
236
- c1.app.should.equal test_target1
237
- c2 = Rack::Utils::Context.new(test_app, test_target2)
238
- c2.for.should.equal test_app
239
- c2.app.should.equal test_target2
240
- end
241
-
242
- specify "should alter app on recontexting" do
243
- c1 = Rack::Utils::Context.new(test_app, test_target1)
244
- c2 = c1.recontext(test_target2)
245
- c2.for.should.equal test_app
246
- c2.app.should.equal test_target2
247
- c3 = c2.recontext(test_target3)
248
- c3.for.should.equal test_app
249
- c3.app.should.equal test_target3
250
- end
251
-
252
- specify "should run different apps" do
253
- c1 = Rack::Utils::Context.new test_app, test_target1
254
- c2 = c1.recontext test_target2
255
- c3 = c2.recontext test_target3
256
- c4 = c3.recontext test_target4
257
- a4 = Rack::Lint.new c4
258
- a5 = Rack::Lint.new test_app
259
- r1 = c1.call('hello')
260
- r1.should.equal 'hello world'
261
- r2 = c2.call(2)
262
- r2.should.equal 4
263
- r3 = c3.call(:misc_symbol)
264
- r3.should.be.nil
265
- r4 = Rack::MockRequest.new(a4).get('/')
266
- r4.status.should.be 200
267
- r5 = Rack::MockRequest.new(a5).get('/')
268
- r5.status.should.be 200
269
- r4.body.should.equal r5.body
270
- end
271
- end
272
-
273
- context "Rack::Utils::Multipart" do
274
- specify "should return nil if content type is not multipart" do
275
- env = Rack::MockRequest.env_for("/",
276
- "CONTENT_TYPE" => 'application/x-www-form-urlencoded')
277
- Rack::Utils::Multipart.parse_multipart(env).should.equal nil
278
- end
279
-
280
- specify "should parse multipart upload with text file" do
281
- env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
282
- params = Rack::Utils::Multipart.parse_multipart(env)
283
- params["submit-name"].should.equal "Larry"
284
- params["files"][:type].should.equal "text/plain"
285
- params["files"][:filename].should.equal "file1.txt"
286
- params["files"][:head].should.equal "Content-Disposition: form-data; " +
287
- "name=\"files\"; filename=\"file1.txt\"\r\n" +
288
- "Content-Type: text/plain\r\n"
289
- params["files"][:name].should.equal "files"
290
- params["files"][:tempfile].read.should.equal "contents"
291
- end
292
-
293
- specify "should parse multipart upload with nested parameters" do
294
- env = Rack::MockRequest.env_for("/", multipart_fixture(:nested))
295
- params = Rack::Utils::Multipart.parse_multipart(env)
296
- params["foo"]["submit-name"].should.equal "Larry"
297
- params["foo"]["files"][:type].should.equal "text/plain"
298
- params["foo"]["files"][:filename].should.equal "file1.txt"
299
- params["foo"]["files"][:head].should.equal "Content-Disposition: form-data; " +
300
- "name=\"foo[files]\"; filename=\"file1.txt\"\r\n" +
301
- "Content-Type: text/plain\r\n"
302
- params["foo"]["files"][:name].should.equal "foo[files]"
303
- params["foo"]["files"][:tempfile].read.should.equal "contents"
304
- end
305
-
306
- specify "should parse multipart upload with binary file" do
307
- env = Rack::MockRequest.env_for("/", multipart_fixture(:binary))
308
- params = Rack::Utils::Multipart.parse_multipart(env)
309
- params["submit-name"].should.equal "Larry"
310
- params["files"][:type].should.equal "image/png"
311
- params["files"][:filename].should.equal "rack-logo.png"
312
- params["files"][:head].should.equal "Content-Disposition: form-data; " +
313
- "name=\"files\"; filename=\"rack-logo.png\"\r\n" +
314
- "Content-Type: image/png\r\n"
315
- params["files"][:name].should.equal "files"
316
- params["files"][:tempfile].read.length.should.equal 26473
317
- end
318
-
319
- specify "should parse multipart upload with empty file" do
320
- env = Rack::MockRequest.env_for("/", multipart_fixture(:empty))
321
- params = Rack::Utils::Multipart.parse_multipart(env)
322
- params["submit-name"].should.equal "Larry"
323
- params["files"][:type].should.equal "text/plain"
324
- params["files"][:filename].should.equal "file1.txt"
325
- params["files"][:head].should.equal "Content-Disposition: form-data; " +
326
- "name=\"files\"; filename=\"file1.txt\"\r\n" +
327
- "Content-Type: text/plain\r\n"
328
- params["files"][:name].should.equal "files"
329
- params["files"][:tempfile].read.should.equal ""
330
- end
331
-
332
- specify "should parse multipart upload with filename with semicolons" do
333
- env = Rack::MockRequest.env_for("/", multipart_fixture(:semicolon))
334
- params = Rack::Utils::Multipart.parse_multipart(env)
335
- params["files"][:type].should.equal "text/plain"
336
- params["files"][:filename].should.equal "fi;le1.txt"
337
- params["files"][:head].should.equal "Content-Disposition: form-data; " +
338
- "name=\"files\"; filename=\"fi;le1.txt\"\r\n" +
339
- "Content-Type: text/plain\r\n"
340
- params["files"][:name].should.equal "files"
341
- params["files"][:tempfile].read.should.equal "contents"
342
- end
343
-
344
- specify "should not include file params if no file was selected" do
345
- env = Rack::MockRequest.env_for("/", multipart_fixture(:none))
346
- params = Rack::Utils::Multipart.parse_multipart(env)
347
- params["submit-name"].should.equal "Larry"
348
- params["files"].should.equal nil
349
- params.keys.should.not.include "files"
350
- end
351
-
352
- specify "should parse IE multipart upload and clean up filename" do
353
- env = Rack::MockRequest.env_for("/", multipart_fixture(:ie))
354
- params = Rack::Utils::Multipart.parse_multipart(env)
355
- params["files"][:type].should.equal "text/plain"
356
- params["files"][:filename].should.equal "file1.txt"
357
- params["files"][:head].should.equal "Content-Disposition: form-data; " +
358
- "name=\"files\"; " +
359
- 'filename="C:\Documents and Settings\Administrator\Desktop\file1.txt"' +
360
- "\r\nContent-Type: text/plain\r\n"
361
- params["files"][:name].should.equal "files"
362
- params["files"][:tempfile].read.should.equal "contents"
363
- end
364
-
365
- specify "rewinds input after parsing upload" do
366
- options = multipart_fixture(:text)
367
- input = options[:input]
368
- env = Rack::MockRequest.env_for("/", options)
369
- params = Rack::Utils::Multipart.parse_multipart(env)
370
- params["submit-name"].should.equal "Larry"
371
- params["files"][:filename].should.equal "file1.txt"
372
- input.read.length.should.equal 197
373
- end
374
-
375
- private
376
- def multipart_fixture(name)
377
- file = File.join(File.dirname(__FILE__), "multipart", name.to_s)
378
- data = File.open(file, 'rb') { |io| io.read }
379
-
380
- type = "multipart/form-data; boundary=AaB03x"
381
- length = data.respond_to?(:bytesize) ? data.bytesize : data.size
382
-
383
- { "CONTENT_TYPE" => type,
384
- "CONTENT_LENGTH" => length.to_s,
385
- :input => StringIO.new(data) }
386
- end
387
- end
@@ -1,130 +0,0 @@
1
- require 'test/spec'
2
-
3
- require 'rack/handler/webrick'
4
- require 'rack/lint'
5
- require 'rack/response'
6
- require 'testrequest'
7
-
8
- Thread.abort_on_exception = true
9
-
10
- context "Rack::Handler::WEBrick" do
11
- include TestRequest::Helpers
12
-
13
- setup do
14
- @server = WEBrick::HTTPServer.new(:Host => @host='0.0.0.0',
15
- :Port => @port=9202,
16
- :Logger => WEBrick::Log.new(nil, WEBrick::BasicLog::WARN),
17
- :AccessLog => [])
18
- @server.mount "/test", Rack::Handler::WEBrick,
19
- Rack::Lint.new(TestRequest.new)
20
- Thread.new { @server.start }
21
- trap(:INT) { @server.shutdown }
22
- end
23
-
24
- specify "should respond" do
25
- lambda {
26
- GET("/test")
27
- }.should.not.raise
28
- end
29
-
30
- specify "should be a WEBrick" do
31
- GET("/test")
32
- status.should.be 200
33
- response["SERVER_SOFTWARE"].should =~ /WEBrick/
34
- response["HTTP_VERSION"].should.equal "HTTP/1.1"
35
- response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
36
- response["SERVER_PORT"].should.equal "9202"
37
- response["SERVER_NAME"].should.equal "0.0.0.0"
38
- end
39
-
40
- specify "should have rack headers" do
41
- GET("/test")
42
- response["rack.version"].should.equal [1,0]
43
- response["rack.multithread"].should.be true
44
- response["rack.multiprocess"].should.be false
45
- response["rack.run_once"].should.be false
46
- end
47
-
48
- specify "should have CGI headers on GET" do
49
- GET("/test")
50
- response["REQUEST_METHOD"].should.equal "GET"
51
- response["SCRIPT_NAME"].should.equal "/test"
52
- response["REQUEST_PATH"].should.equal "/"
53
- response["PATH_INFO"].should.be.nil
54
- response["QUERY_STRING"].should.equal ""
55
- response["test.postdata"].should.equal ""
56
-
57
- GET("/test/foo?quux=1")
58
- response["REQUEST_METHOD"].should.equal "GET"
59
- response["SCRIPT_NAME"].should.equal "/test"
60
- response["REQUEST_PATH"].should.equal "/"
61
- response["PATH_INFO"].should.equal "/foo"
62
- response["QUERY_STRING"].should.equal "quux=1"
63
-
64
- GET("/test/foo%25encoding?quux=1")
65
- response["REQUEST_METHOD"].should.equal "GET"
66
- response["SCRIPT_NAME"].should.equal "/test"
67
- response["REQUEST_PATH"].should.equal "/"
68
- response["PATH_INFO"].should.equal "/foo%25encoding"
69
- response["QUERY_STRING"].should.equal "quux=1"
70
- end
71
-
72
- specify "should have CGI headers on POST" do
73
- POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
74
- status.should.equal 200
75
- response["REQUEST_METHOD"].should.equal "POST"
76
- response["SCRIPT_NAME"].should.equal "/test"
77
- response["REQUEST_PATH"].should.equal "/"
78
- response["QUERY_STRING"].should.equal ""
79
- response["HTTP_X_TEST_HEADER"].should.equal "42"
80
- response["test.postdata"].should.equal "rack-form-data=23"
81
- end
82
-
83
- specify "should support HTTP auth" do
84
- GET("/test", {:user => "ruth", :passwd => "secret"})
85
- response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
86
- end
87
-
88
- specify "should set status" do
89
- GET("/test?secret")
90
- status.should.equal 403
91
- response["rack.url_scheme"].should.equal "http"
92
- end
93
-
94
- specify "should correctly set cookies" do
95
- @server.mount "/cookie-test", Rack::Handler::WEBrick,
96
- Rack::Lint.new(lambda { |req|
97
- res = Rack::Response.new
98
- res.set_cookie "one", "1"
99
- res.set_cookie "two", "2"
100
- res.finish
101
- })
102
-
103
- Net::HTTP.start(@host, @port) { |http|
104
- res = http.get("/cookie-test")
105
- res.code.to_i.should.equal 200
106
- res.get_fields("set-cookie").should.equal ["one=1", "two=2"]
107
- }
108
- end
109
-
110
- specify "should provide a .run" do
111
- block_ran = false
112
- catch(:done) {
113
- Rack::Handler::WEBrick.run(lambda {},
114
- {:Port => 9210,
115
- :Logger => WEBrick::Log.new(nil, WEBrick::BasicLog::WARN),
116
- :AccessLog => []}) { |server|
117
- block_ran = true
118
- server.should.be.kind_of WEBrick::HTTPServer
119
- @s = server
120
- throw :done
121
- }
122
- }
123
- block_ran.should.be true
124
- @s.shutdown
125
- end
126
-
127
- teardown do
128
- @server.shutdown
129
- end
130
- end
data/test/testrequest.rb DELETED
@@ -1,57 +0,0 @@
1
- require 'yaml'
2
- require 'net/http'
3
-
4
- class TestRequest
5
- def call(env)
6
- status = env["QUERY_STRING"] =~ /secret/ ? 403 : 200
7
- env["test.postdata"] = env["rack.input"].read
8
- body = env.to_yaml
9
- size = body.respond_to?(:bytesize) ? body.bytesize : body.size
10
- [status, {"Content-Type" => "text/yaml", "Content-Length" => size.to_s}, [body]]
11
- end
12
-
13
- module Helpers
14
- attr_reader :status, :response
15
-
16
- def GET(path, header={})
17
- Net::HTTP.start(@host, @port) { |http|
18
- user = header.delete(:user)
19
- passwd = header.delete(:passwd)
20
-
21
- get = Net::HTTP::Get.new(path, header)
22
- get.basic_auth user, passwd if user && passwd
23
- http.request(get) { |response|
24
- @status = response.code.to_i
25
- @response = YAML.load(response.body)
26
- }
27
- }
28
- end
29
-
30
- def POST(path, formdata={}, header={})
31
- Net::HTTP.start(@host, @port) { |http|
32
- user = header.delete(:user)
33
- passwd = header.delete(:passwd)
34
-
35
- post = Net::HTTP::Post.new(path, header)
36
- post.form_data = formdata
37
- post.basic_auth user, passwd if user && passwd
38
- http.request(post) { |response|
39
- @status = response.code.to_i
40
- @response = YAML.load(response.body)
41
- }
42
- }
43
- end
44
- end
45
- end
46
-
47
- class StreamingRequest
48
- def self.call(env)
49
- [200, {"Content-Type" => "text/plain"}, new]
50
- end
51
-
52
- def each
53
- yield "hello there!\n"
54
- sleep 5
55
- yield "that is all.\n"
56
- end
57
- end
@@ -1,7 +0,0 @@
1
- module Rack
2
- module Handler
3
- # this class doesn't do anything, we're just seeing if we get it.
4
- class Unregistered
5
- end
6
- end
7
- end
@@ -1,7 +0,0 @@
1
- module Rack
2
- module Handler
3
- # this class doesn't do anything, we're just seeing if we get it.
4
- class UnregisteredLongOne
5
- end
6
- end
7
- end