rack 1.4.7 → 2.1.4

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 (183) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +77 -0
  3. data/{COPYING → MIT-LICENSE} +4 -2
  4. data/README.rdoc +122 -456
  5. data/Rakefile +32 -31
  6. data/SPEC +119 -29
  7. data/bin/rackup +1 -0
  8. data/contrib/rack_logo.svg +164 -111
  9. data/example/lobster.ru +2 -0
  10. data/example/protectedlobster.rb +4 -2
  11. data/example/protectedlobster.ru +3 -1
  12. data/lib/rack/auth/abstract/handler.rb +7 -5
  13. data/lib/rack/auth/abstract/request.rb +8 -6
  14. data/lib/rack/auth/basic.rb +5 -2
  15. data/lib/rack/auth/digest/md5.rb +10 -8
  16. data/lib/rack/auth/digest/nonce.rb +6 -3
  17. data/lib/rack/auth/digest/params.rb +5 -4
  18. data/lib/rack/auth/digest/request.rb +4 -2
  19. data/lib/rack/body_proxy.rb +11 -9
  20. data/lib/rack/builder.rb +63 -20
  21. data/lib/rack/cascade.rb +10 -9
  22. data/lib/rack/chunked.rb +45 -11
  23. data/lib/rack/{commonlogger.rb → common_logger.rb} +24 -15
  24. data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -6
  25. data/lib/rack/config.rb +7 -0
  26. data/lib/rack/content_length.rb +12 -6
  27. data/lib/rack/content_type.rb +4 -2
  28. data/lib/rack/core_ext/regexp.rb +14 -0
  29. data/lib/rack/deflater.rb +73 -42
  30. data/lib/rack/directory.rb +77 -56
  31. data/lib/rack/etag.rb +25 -13
  32. data/lib/rack/events.rb +156 -0
  33. data/lib/rack/file.rb +4 -143
  34. data/lib/rack/files.rb +178 -0
  35. data/lib/rack/handler/cgi.rb +18 -17
  36. data/lib/rack/handler/fastcgi.rb +21 -17
  37. data/lib/rack/handler/lsws.rb +14 -12
  38. data/lib/rack/handler/scgi.rb +27 -21
  39. data/lib/rack/handler/thin.rb +19 -5
  40. data/lib/rack/handler/webrick.rb +66 -24
  41. data/lib/rack/handler.rb +29 -19
  42. data/lib/rack/head.rb +21 -14
  43. data/lib/rack/lint.rb +259 -65
  44. data/lib/rack/lobster.rb +17 -10
  45. data/lib/rack/lock.rb +19 -10
  46. data/lib/rack/logger.rb +4 -2
  47. data/lib/rack/media_type.rb +43 -0
  48. data/lib/rack/method_override.rb +52 -0
  49. data/lib/rack/mime.rb +43 -6
  50. data/lib/rack/mock.rb +109 -44
  51. data/lib/rack/multipart/generator.rb +11 -12
  52. data/lib/rack/multipart/parser.rb +302 -115
  53. data/lib/rack/multipart/uploaded_file.rb +4 -3
  54. data/lib/rack/multipart.rb +40 -9
  55. data/lib/rack/null_logger.rb +39 -0
  56. data/lib/rack/query_parser.rb +218 -0
  57. data/lib/rack/recursive.rb +14 -11
  58. data/lib/rack/reloader.rb +12 -5
  59. data/lib/rack/request.rb +484 -270
  60. data/lib/rack/response.rb +196 -77
  61. data/lib/rack/rewindable_input.rb +5 -14
  62. data/lib/rack/runtime.rb +13 -6
  63. data/lib/rack/sendfile.rb +44 -20
  64. data/lib/rack/server.rb +175 -61
  65. data/lib/rack/session/abstract/id.rb +276 -133
  66. data/lib/rack/session/cookie.rb +75 -40
  67. data/lib/rack/session/memcache.rb +4 -87
  68. data/lib/rack/session/pool.rb +24 -18
  69. data/lib/rack/show_exceptions.rb +392 -0
  70. data/lib/rack/{showstatus.rb → show_status.rb} +11 -9
  71. data/lib/rack/static.rb +65 -38
  72. data/lib/rack/tempfile_reaper.rb +24 -0
  73. data/lib/rack/urlmap.rb +40 -15
  74. data/lib/rack/utils.rb +316 -285
  75. data/lib/rack.rb +78 -23
  76. data/rack.gemspec +26 -19
  77. metadata +44 -209
  78. data/KNOWN-ISSUES +0 -30
  79. data/lib/rack/backports/uri/common_18.rb +0 -56
  80. data/lib/rack/backports/uri/common_192.rb +0 -52
  81. data/lib/rack/backports/uri/common_193.rb +0 -29
  82. data/lib/rack/handler/evented_mongrel.rb +0 -8
  83. data/lib/rack/handler/mongrel.rb +0 -100
  84. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  85. data/lib/rack/methodoverride.rb +0 -33
  86. data/lib/rack/nulllogger.rb +0 -18
  87. data/lib/rack/showexceptions.rb +0 -378
  88. data/test/builder/anything.rb +0 -5
  89. data/test/builder/comment.ru +0 -4
  90. data/test/builder/end.ru +0 -5
  91. data/test/builder/line.ru +0 -1
  92. data/test/builder/options.ru +0 -2
  93. data/test/cgi/assets/folder/test.js +0 -1
  94. data/test/cgi/assets/fonts/font.eot +0 -1
  95. data/test/cgi/assets/images/image.png +0 -1
  96. data/test/cgi/assets/index.html +0 -1
  97. data/test/cgi/assets/javascripts/app.js +0 -1
  98. data/test/cgi/assets/stylesheets/app.css +0 -1
  99. data/test/cgi/lighttpd.conf +0 -26
  100. data/test/cgi/lighttpd.errors +0 -1
  101. data/test/cgi/rackup_stub.rb +0 -6
  102. data/test/cgi/sample_rackup.ru +0 -5
  103. data/test/cgi/test +0 -9
  104. data/test/cgi/test+directory/test+file +0 -1
  105. data/test/cgi/test.fcgi +0 -8
  106. data/test/cgi/test.ru +0 -5
  107. data/test/gemloader.rb +0 -10
  108. data/test/multipart/bad_robots +0 -259
  109. data/test/multipart/binary +0 -0
  110. data/test/multipart/content_type_and_no_filename +0 -6
  111. data/test/multipart/empty +0 -10
  112. data/test/multipart/fail_16384_nofile +0 -814
  113. data/test/multipart/file1.txt +0 -1
  114. data/test/multipart/filename_and_modification_param +0 -7
  115. data/test/multipart/filename_with_escaped_quotes +0 -6
  116. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  117. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  118. data/test/multipart/filename_with_unescaped_percentages +0 -6
  119. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  120. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  121. data/test/multipart/filename_with_unescaped_quotes +0 -6
  122. data/test/multipart/ie +0 -6
  123. data/test/multipart/mixed_files +0 -21
  124. data/test/multipart/nested +0 -10
  125. data/test/multipart/none +0 -9
  126. data/test/multipart/semicolon +0 -6
  127. data/test/multipart/text +0 -15
  128. data/test/multipart/three_files_three_fields +0 -31
  129. data/test/multipart/webkit +0 -32
  130. data/test/rackup/config.ru +0 -31
  131. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  132. data/test/spec_auth.rb +0 -57
  133. data/test/spec_auth_basic.rb +0 -81
  134. data/test/spec_auth_digest.rb +0 -259
  135. data/test/spec_body_proxy.rb +0 -69
  136. data/test/spec_builder.rb +0 -207
  137. data/test/spec_cascade.rb +0 -61
  138. data/test/spec_cgi.rb +0 -102
  139. data/test/spec_chunked.rb +0 -87
  140. data/test/spec_commonlogger.rb +0 -57
  141. data/test/spec_conditionalget.rb +0 -102
  142. data/test/spec_config.rb +0 -22
  143. data/test/spec_content_length.rb +0 -86
  144. data/test/spec_content_type.rb +0 -45
  145. data/test/spec_deflater.rb +0 -187
  146. data/test/spec_directory.rb +0 -88
  147. data/test/spec_etag.rb +0 -98
  148. data/test/spec_fastcgi.rb +0 -107
  149. data/test/spec_file.rb +0 -200
  150. data/test/spec_handler.rb +0 -59
  151. data/test/spec_head.rb +0 -48
  152. data/test/spec_lint.rb +0 -515
  153. data/test/spec_lobster.rb +0 -58
  154. data/test/spec_lock.rb +0 -167
  155. data/test/spec_logger.rb +0 -23
  156. data/test/spec_methodoverride.rb +0 -72
  157. data/test/spec_mock.rb +0 -269
  158. data/test/spec_mongrel.rb +0 -182
  159. data/test/spec_multipart.rb +0 -479
  160. data/test/spec_nulllogger.rb +0 -23
  161. data/test/spec_recursive.rb +0 -72
  162. data/test/spec_request.rb +0 -955
  163. data/test/spec_response.rb +0 -313
  164. data/test/spec_rewindable_input.rb +0 -118
  165. data/test/spec_runtime.rb +0 -49
  166. data/test/spec_sendfile.rb +0 -90
  167. data/test/spec_server.rb +0 -121
  168. data/test/spec_session_abstract_id.rb +0 -43
  169. data/test/spec_session_cookie.rb +0 -361
  170. data/test/spec_session_memcache.rb +0 -321
  171. data/test/spec_session_pool.rb +0 -209
  172. data/test/spec_showexceptions.rb +0 -92
  173. data/test/spec_showstatus.rb +0 -84
  174. data/test/spec_static.rb +0 -145
  175. data/test/spec_thin.rb +0 -86
  176. data/test/spec_urlmap.rb +0 -213
  177. data/test/spec_utils.rb +0 -554
  178. data/test/spec_webrick.rb +0 -143
  179. data/test/static/another/index.html +0 -1
  180. data/test/static/index.html +0 -1
  181. data/test/testrequest.rb +0 -78
  182. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  183. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/test/spec_lint.rb DELETED
@@ -1,515 +0,0 @@
1
- require 'stringio'
2
- require 'rack/lint'
3
- require 'rack/mock'
4
-
5
- describe Rack::Lint do
6
- def env(*args)
7
- Rack::MockRequest.env_for("/", *args)
8
- end
9
-
10
- should "pass valid request" do
11
- lambda {
12
- Rack::Lint.new(lambda { |env|
13
- [200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]]
14
- }).call(env({}))
15
- }.should.not.raise
16
- end
17
-
18
- should "notice fatal errors" do
19
- lambda { Rack::Lint.new(nil).call }.should.raise(Rack::Lint::LintError).
20
- message.should.match(/No env given/)
21
- end
22
-
23
- should "notice environment errors" do
24
- lambda { Rack::Lint.new(nil).call 5 }.should.raise(Rack::Lint::LintError).
25
- message.should.match(/not a Hash/)
26
-
27
- lambda {
28
- e = env
29
- e.delete("REQUEST_METHOD")
30
- Rack::Lint.new(nil).call(e)
31
- }.should.raise(Rack::Lint::LintError).
32
- message.should.match(/missing required key REQUEST_METHOD/)
33
-
34
- lambda {
35
- e = env
36
- e.delete("SERVER_NAME")
37
- Rack::Lint.new(nil).call(e)
38
- }.should.raise(Rack::Lint::LintError).
39
- message.should.match(/missing required key SERVER_NAME/)
40
-
41
-
42
- lambda {
43
- Rack::Lint.new(nil).call(env("HTTP_CONTENT_TYPE" => "text/plain"))
44
- }.should.raise(Rack::Lint::LintError).
45
- message.should.match(/contains HTTP_CONTENT_TYPE/)
46
-
47
- lambda {
48
- Rack::Lint.new(nil).call(env("HTTP_CONTENT_LENGTH" => "42"))
49
- }.should.raise(Rack::Lint::LintError).
50
- message.should.match(/contains HTTP_CONTENT_LENGTH/)
51
-
52
- lambda {
53
- Rack::Lint.new(nil).call(env("FOO" => Object.new))
54
- }.should.raise(Rack::Lint::LintError).
55
- message.should.match(/non-string value/)
56
-
57
- lambda {
58
- Rack::Lint.new(nil).call(env("rack.version" => "0.2"))
59
- }.should.raise(Rack::Lint::LintError).
60
- message.should.match(/must be an Array/)
61
-
62
- lambda {
63
- Rack::Lint.new(nil).call(env("rack.url_scheme" => "gopher"))
64
- }.should.raise(Rack::Lint::LintError).
65
- message.should.match(/url_scheme unknown/)
66
-
67
- lambda {
68
- Rack::Lint.new(nil).call(env("rack.session" => []))
69
- }.should.raise(Rack::Lint::LintError).
70
- message.should.equal("session [] must respond to store and []=")
71
-
72
- lambda {
73
- Rack::Lint.new(nil).call(env("rack.logger" => []))
74
- }.should.raise(Rack::Lint::LintError).
75
- message.should.equal("logger [] must respond to info")
76
-
77
- lambda {
78
- Rack::Lint.new(nil).call(env("REQUEST_METHOD" => "FUCKUP?"))
79
- }.should.raise(Rack::Lint::LintError).
80
- message.should.match(/REQUEST_METHOD/)
81
-
82
- lambda {
83
- Rack::Lint.new(nil).call(env("SCRIPT_NAME" => "howdy"))
84
- }.should.raise(Rack::Lint::LintError).
85
- message.should.match(/must start with/)
86
-
87
- lambda {
88
- Rack::Lint.new(nil).call(env("PATH_INFO" => "../foo"))
89
- }.should.raise(Rack::Lint::LintError).
90
- message.should.match(/must start with/)
91
-
92
- lambda {
93
- Rack::Lint.new(nil).call(env("CONTENT_LENGTH" => "xcii"))
94
- }.should.raise(Rack::Lint::LintError).
95
- message.should.match(/Invalid CONTENT_LENGTH/)
96
-
97
- lambda {
98
- e = env
99
- e.delete("PATH_INFO")
100
- e.delete("SCRIPT_NAME")
101
- Rack::Lint.new(nil).call(e)
102
- }.should.raise(Rack::Lint::LintError).
103
- message.should.match(/One of .* must be set/)
104
-
105
- lambda {
106
- Rack::Lint.new(nil).call(env("SCRIPT_NAME" => "/"))
107
- }.should.raise(Rack::Lint::LintError).
108
- message.should.match(/cannot be .* make it ''/)
109
- end
110
-
111
- should "notice input errors" do
112
- lambda {
113
- Rack::Lint.new(nil).call(env("rack.input" => ""))
114
- }.should.raise(Rack::Lint::LintError).
115
- message.should.match(/does not respond to #gets/)
116
-
117
- lambda {
118
- input = Object.new
119
- def input.binmode?
120
- false
121
- end
122
- Rack::Lint.new(nil).call(env("rack.input" => input))
123
- }.should.raise(Rack::Lint::LintError).
124
- message.should.match(/is not opened in binary mode/)
125
-
126
- lambda {
127
- input = Object.new
128
- def input.external_encoding
129
- result = Object.new
130
- def result.name
131
- "US-ASCII"
132
- end
133
- result
134
- end
135
- Rack::Lint.new(nil).call(env("rack.input" => input))
136
- }.should.raise(Rack::Lint::LintError).
137
- message.should.match(/does not have ASCII-8BIT as its external encoding/)
138
- end
139
-
140
- should "notice error errors" do
141
- lambda {
142
- Rack::Lint.new(nil).call(env("rack.errors" => ""))
143
- }.should.raise(Rack::Lint::LintError).
144
- message.should.match(/does not respond to #puts/)
145
- end
146
-
147
- should "notice status errors" do
148
- lambda {
149
- Rack::Lint.new(lambda { |env|
150
- ["cc", {}, ""]
151
- }).call(env({}))
152
- }.should.raise(Rack::Lint::LintError).
153
- message.should.match(/must be >=100 seen as integer/)
154
-
155
- lambda {
156
- Rack::Lint.new(lambda { |env|
157
- [42, {}, ""]
158
- }).call(env({}))
159
- }.should.raise(Rack::Lint::LintError).
160
- message.should.match(/must be >=100 seen as integer/)
161
- end
162
-
163
- should "notice header errors" do
164
- lambda {
165
- Rack::Lint.new(lambda { |env|
166
- [200, Object.new, []]
167
- }).call(env({}))
168
- }.should.raise(Rack::Lint::LintError).
169
- message.should.equal("headers object should respond to #each, but doesn't (got Object as headers)")
170
-
171
- lambda {
172
- Rack::Lint.new(lambda { |env|
173
- [200, {true=>false}, []]
174
- }).call(env({}))
175
- }.should.raise(Rack::Lint::LintError).
176
- message.should.equal("header key must be a string, was TrueClass")
177
-
178
- lambda {
179
- Rack::Lint.new(lambda { |env|
180
- [200, {"Status" => "404"}, []]
181
- }).call(env({}))
182
- }.should.raise(Rack::Lint::LintError).
183
- message.should.match(/must not contain Status/)
184
-
185
- lambda {
186
- Rack::Lint.new(lambda { |env|
187
- [200, {"Content-Type:" => "text/plain"}, []]
188
- }).call(env({}))
189
- }.should.raise(Rack::Lint::LintError).
190
- message.should.match(/must not contain :/)
191
-
192
- lambda {
193
- Rack::Lint.new(lambda { |env|
194
- [200, {"Content-" => "text/plain"}, []]
195
- }).call(env({}))
196
- }.should.raise(Rack::Lint::LintError).
197
- message.should.match(/must not end/)
198
-
199
- lambda {
200
- Rack::Lint.new(lambda { |env|
201
- [200, {"..%%quark%%.." => "text/plain"}, []]
202
- }).call(env({}))
203
- }.should.raise(Rack::Lint::LintError).
204
- message.should.equal("invalid header name: ..%%quark%%..")
205
-
206
- lambda {
207
- Rack::Lint.new(lambda { |env|
208
- [200, {"Foo" => Object.new}, []]
209
- }).call(env({}))
210
- }.should.raise(Rack::Lint::LintError).
211
- message.should.equal("a header value must be a String, but the value of 'Foo' is a Object")
212
-
213
- lambda {
214
- Rack::Lint.new(lambda { |env|
215
- [200, {"Foo" => [1, 2, 3]}, []]
216
- }).call(env({}))
217
- }.should.raise(Rack::Lint::LintError).
218
- message.should.equal("a header value must be a String, but the value of 'Foo' is a Array")
219
-
220
-
221
- lambda {
222
- Rack::Lint.new(lambda { |env|
223
- [200, {"Foo-Bar" => "text\000plain"}, []]
224
- }).call(env({}))
225
- }.should.raise(Rack::Lint::LintError).
226
- message.should.match(/invalid header/)
227
-
228
- # line ends (010) should be allowed in header values.
229
- lambda {
230
- Rack::Lint.new(lambda { |env|
231
- [200, {"Foo-Bar" => "one\ntwo\nthree", "Content-Length" => "0", "Content-Type" => "text/plain" }, []]
232
- }).call(env({}))
233
- }.should.not.raise(Rack::Lint::LintError)
234
- end
235
-
236
- should "notice content-type errors" do
237
- lambda {
238
- Rack::Lint.new(lambda { |env|
239
- [200, {"Content-length" => "0"}, []]
240
- }).call(env({}))
241
- }.should.raise(Rack::Lint::LintError).
242
- message.should.match(/No Content-Type/)
243
-
244
- [100, 101, 204, 205, 304].each do |status|
245
- lambda {
246
- Rack::Lint.new(lambda { |env|
247
- [status, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
248
- }).call(env({}))
249
- }.should.raise(Rack::Lint::LintError).
250
- message.should.match(/Content-Type header found/)
251
- end
252
- end
253
-
254
- should "notice content-length errors" do
255
- [100, 101, 204, 205, 304].each do |status|
256
- lambda {
257
- Rack::Lint.new(lambda { |env|
258
- [status, {"Content-length" => "0"}, []]
259
- }).call(env({}))
260
- }.should.raise(Rack::Lint::LintError).
261
- message.should.match(/Content-Length header found/)
262
- end
263
-
264
- lambda {
265
- Rack::Lint.new(lambda { |env|
266
- [200, {"Content-type" => "text/plain", "Content-Length" => "1"}, []]
267
- }).call(env({}))[2].each { }
268
- }.should.raise(Rack::Lint::LintError).
269
- message.should.match(/Content-Length header was 1, but should be 0/)
270
- end
271
-
272
- should "notice body errors" do
273
- lambda {
274
- body = Rack::Lint.new(lambda { |env|
275
- [200, {"Content-type" => "text/plain","Content-length" => "3"}, [1,2,3]]
276
- }).call(env({}))[2]
277
- body.each { |part| }
278
- }.should.raise(Rack::Lint::LintError).
279
- message.should.match(/yielded non-string/)
280
- end
281
-
282
- should "notice input handling errors" do
283
- lambda {
284
- Rack::Lint.new(lambda { |env|
285
- env["rack.input"].gets("\r\n")
286
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
287
- }).call(env({}))
288
- }.should.raise(Rack::Lint::LintError).
289
- message.should.match(/gets called with arguments/)
290
-
291
- lambda {
292
- Rack::Lint.new(lambda { |env|
293
- env["rack.input"].read(1, 2, 3)
294
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
295
- }).call(env({}))
296
- }.should.raise(Rack::Lint::LintError).
297
- message.should.match(/read called with too many arguments/)
298
-
299
- lambda {
300
- Rack::Lint.new(lambda { |env|
301
- env["rack.input"].read("foo")
302
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
303
- }).call(env({}))
304
- }.should.raise(Rack::Lint::LintError).
305
- message.should.match(/read called with non-integer and non-nil length/)
306
-
307
- lambda {
308
- Rack::Lint.new(lambda { |env|
309
- env["rack.input"].read(-1)
310
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
311
- }).call(env({}))
312
- }.should.raise(Rack::Lint::LintError).
313
- message.should.match(/read called with a negative length/)
314
-
315
- lambda {
316
- Rack::Lint.new(lambda { |env|
317
- env["rack.input"].read(nil, nil)
318
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
319
- }).call(env({}))
320
- }.should.raise(Rack::Lint::LintError).
321
- message.should.match(/read called with non-String buffer/)
322
-
323
- lambda {
324
- Rack::Lint.new(lambda { |env|
325
- env["rack.input"].read(nil, 1)
326
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
327
- }).call(env({}))
328
- }.should.raise(Rack::Lint::LintError).
329
- message.should.match(/read called with non-String buffer/)
330
-
331
- lambda {
332
- Rack::Lint.new(lambda { |env|
333
- env["rack.input"].rewind(0)
334
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
335
- }).call(env({}))
336
- }.should.raise(Rack::Lint::LintError).
337
- message.should.match(/rewind called with arguments/)
338
-
339
- weirdio = Object.new
340
- class << weirdio
341
- def gets
342
- 42
343
- end
344
-
345
- def read
346
- 23
347
- end
348
-
349
- def each
350
- yield 23
351
- yield 42
352
- end
353
-
354
- def rewind
355
- raise Errno::ESPIPE, "Errno::ESPIPE"
356
- end
357
- end
358
-
359
- eof_weirdio = Object.new
360
- class << eof_weirdio
361
- def gets
362
- nil
363
- end
364
-
365
- def read(*args)
366
- nil
367
- end
368
-
369
- def each
370
- end
371
-
372
- def rewind
373
- end
374
- end
375
-
376
- lambda {
377
- Rack::Lint.new(lambda { |env|
378
- env["rack.input"].gets
379
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
380
- }).call(env("rack.input" => weirdio))
381
- }.should.raise(Rack::Lint::LintError).
382
- message.should.match(/gets didn't return a String/)
383
-
384
- lambda {
385
- Rack::Lint.new(lambda { |env|
386
- env["rack.input"].each { |x| }
387
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
388
- }).call(env("rack.input" => weirdio))
389
- }.should.raise(Rack::Lint::LintError).
390
- message.should.match(/each didn't yield a String/)
391
-
392
- lambda {
393
- Rack::Lint.new(lambda { |env|
394
- env["rack.input"].read
395
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
396
- }).call(env("rack.input" => weirdio))
397
- }.should.raise(Rack::Lint::LintError).
398
- message.should.match(/read didn't return nil or a String/)
399
-
400
- lambda {
401
- Rack::Lint.new(lambda { |env|
402
- env["rack.input"].read
403
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
404
- }).call(env("rack.input" => eof_weirdio))
405
- }.should.raise(Rack::Lint::LintError).
406
- message.should.match(/read\(nil\) returned nil on EOF/)
407
-
408
- lambda {
409
- Rack::Lint.new(lambda { |env|
410
- env["rack.input"].rewind
411
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
412
- }).call(env("rack.input" => weirdio))
413
- }.should.raise(Rack::Lint::LintError).
414
- message.should.match(/rewind raised Errno::ESPIPE/)
415
-
416
-
417
- lambda {
418
- Rack::Lint.new(lambda { |env|
419
- env["rack.input"].close
420
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
421
- }).call(env({}))
422
- }.should.raise(Rack::Lint::LintError).
423
- message.should.match(/close must not be called/)
424
- end
425
-
426
- should "notice error handling errors" do
427
- lambda {
428
- Rack::Lint.new(lambda { |env|
429
- env["rack.errors"].write(42)
430
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
431
- }).call(env({}))
432
- }.should.raise(Rack::Lint::LintError).
433
- message.should.match(/write not called with a String/)
434
-
435
- lambda {
436
- Rack::Lint.new(lambda { |env|
437
- env["rack.errors"].close
438
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
439
- }).call(env({}))
440
- }.should.raise(Rack::Lint::LintError).
441
- message.should.match(/close must not be called/)
442
- end
443
-
444
- should "notice HEAD errors" do
445
- lambda {
446
- Rack::Lint.new(lambda { |env|
447
- [200, {"Content-type" => "test/plain", "Content-length" => "3"}, []]
448
- }).call(env({"REQUEST_METHOD" => "HEAD"}))
449
- }.should.not.raise
450
-
451
- lambda {
452
- Rack::Lint.new(lambda { |env|
453
- [200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]]
454
- }).call(env({"REQUEST_METHOD" => "HEAD"}))[2].each { }
455
- }.should.raise(Rack::Lint::LintError).
456
- message.should.match(/body was given for HEAD/)
457
- end
458
-
459
- should "pass valid read calls" do
460
- hello_str = "hello world"
461
- hello_str.force_encoding("ASCII-8BIT") if hello_str.respond_to? :force_encoding
462
- lambda {
463
- Rack::Lint.new(lambda { |env|
464
- env["rack.input"].read
465
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
466
- }).call(env({"rack.input" => StringIO.new(hello_str)}))
467
- }.should.not.raise(Rack::Lint::LintError)
468
-
469
- lambda {
470
- Rack::Lint.new(lambda { |env|
471
- env["rack.input"].read(0)
472
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
473
- }).call(env({"rack.input" => StringIO.new(hello_str)}))
474
- }.should.not.raise(Rack::Lint::LintError)
475
-
476
- lambda {
477
- Rack::Lint.new(lambda { |env|
478
- env["rack.input"].read(1)
479
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
480
- }).call(env({"rack.input" => StringIO.new(hello_str)}))
481
- }.should.not.raise(Rack::Lint::LintError)
482
-
483
- lambda {
484
- Rack::Lint.new(lambda { |env|
485
- env["rack.input"].read(nil)
486
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
487
- }).call(env({"rack.input" => StringIO.new(hello_str)}))
488
- }.should.not.raise(Rack::Lint::LintError)
489
-
490
- lambda {
491
- Rack::Lint.new(lambda { |env|
492
- env["rack.input"].read(nil, '')
493
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
494
- }).call(env({"rack.input" => StringIO.new(hello_str)}))
495
- }.should.not.raise(Rack::Lint::LintError)
496
-
497
- lambda {
498
- Rack::Lint.new(lambda { |env|
499
- env["rack.input"].read(1, '')
500
- [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
501
- }).call(env({"rack.input" => StringIO.new(hello_str)}))
502
- }.should.not.raise(Rack::Lint::LintError)
503
- end
504
- end
505
-
506
- describe "Rack::Lint::InputWrapper" do
507
- should "delegate :rewind to underlying IO object" do
508
- io = StringIO.new("123")
509
- wrapper = Rack::Lint::InputWrapper.new(io)
510
- wrapper.read.should.equal "123"
511
- wrapper.read.should.equal ""
512
- wrapper.rewind
513
- wrapper.read.should.equal "123"
514
- end
515
- end
data/test/spec_lobster.rb DELETED
@@ -1,58 +0,0 @@
1
- require 'rack/lobster'
2
- require 'rack/lint'
3
- require 'rack/mock'
4
-
5
- module LobsterHelpers
6
- def lobster
7
- Rack::MockRequest.new Rack::Lint.new(Rack::Lobster.new)
8
- end
9
-
10
- def lambda_lobster
11
- Rack::MockRequest.new Rack::Lint.new(Rack::Lobster::LambdaLobster)
12
- end
13
- end
14
-
15
- describe Rack::Lobster::LambdaLobster do
16
- extend LobsterHelpers
17
-
18
- should "be a single lambda" do
19
- Rack::Lobster::LambdaLobster.should.be.kind_of Proc
20
- end
21
-
22
- should "look like a lobster" do
23
- res = lambda_lobster.get("/")
24
- res.should.be.ok
25
- res.body.should.include "(,(,,(,,,("
26
- res.body.should.include "?flip"
27
- end
28
-
29
- should "be flippable" do
30
- res = lambda_lobster.get("/?flip")
31
- res.should.be.ok
32
- res.body.should.include "(,,,(,,(,("
33
- end
34
- end
35
-
36
- describe Rack::Lobster do
37
- extend LobsterHelpers
38
-
39
- should "look like a lobster" do
40
- res = lobster.get("/")
41
- res.should.be.ok
42
- res.body.should.include "(,(,,(,,,("
43
- res.body.should.include "?flip"
44
- res.body.should.include "crash"
45
- end
46
-
47
- should "be flippable" do
48
- res = lobster.get("/?flip=left")
49
- res.should.be.ok
50
- res.body.should.include "(,,,(,,(,("
51
- end
52
-
53
- should "provide crashing for testing purposes" do
54
- lambda {
55
- lobster.get("/?flip=crash")
56
- }.should.raise
57
- end
58
- end