rack 1.6.11 → 2.2.0

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

Potentially problematic release.


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

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