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