rack 2.0.9.3 → 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 (191) 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 +152 -162
  6. data/Rakefile +37 -23
  7. data/{SPEC → SPEC.rdoc} +44 -15
  8. data/bin/rackup +1 -0
  9. data/example/lobster.ru +2 -0
  10. data/example/protectedlobster.rb +3 -1
  11. data/example/protectedlobster.ru +2 -0
  12. data/lib/rack/auth/abstract/handler.rb +3 -1
  13. data/lib/rack/auth/abstract/request.rb +1 -1
  14. data/lib/rack/auth/basic.rb +7 -4
  15. data/lib/rack/auth/digest/md5.rb +13 -11
  16. data/lib/rack/auth/digest/nonce.rb +6 -3
  17. data/lib/rack/auth/digest/params.rb +4 -2
  18. data/lib/rack/auth/digest/request.rb +5 -3
  19. data/lib/rack/body_proxy.rb +15 -14
  20. data/lib/rack/builder.rb +116 -23
  21. data/lib/rack/cascade.rb +28 -12
  22. data/lib/rack/chunked.rb +68 -20
  23. data/lib/rack/common_logger.rb +33 -28
  24. data/lib/rack/conditional_get.rb +20 -16
  25. data/lib/rack/config.rb +2 -0
  26. data/lib/rack/content_length.rb +8 -7
  27. data/lib/rack/content_type.rb +5 -4
  28. data/lib/rack/core_ext/regexp.rb +14 -0
  29. data/lib/rack/deflater.rb +59 -34
  30. data/lib/rack/directory.rb +84 -64
  31. data/lib/rack/etag.rb +5 -4
  32. data/lib/rack/events.rb +19 -20
  33. data/lib/rack/file.rb +4 -173
  34. data/lib/rack/files.rb +218 -0
  35. data/lib/rack/handler/cgi.rb +2 -3
  36. data/lib/rack/handler/fastcgi.rb +4 -4
  37. data/lib/rack/handler/lsws.rb +3 -3
  38. data/lib/rack/handler/scgi.rb +9 -8
  39. data/lib/rack/handler/thin.rb +17 -11
  40. data/lib/rack/handler/webrick.rb +15 -6
  41. data/lib/rack/handler.rb +7 -2
  42. data/lib/rack/head.rb +1 -1
  43. data/lib/rack/lint.rb +72 -26
  44. data/lib/rack/lobster.rb +10 -10
  45. data/lib/rack/lock.rb +2 -1
  46. data/lib/rack/logger.rb +2 -0
  47. data/lib/rack/media_type.rb +10 -5
  48. data/lib/rack/method_override.rb +4 -2
  49. data/lib/rack/mime.rb +9 -1
  50. data/lib/rack/mock.rb +97 -20
  51. data/lib/rack/multipart/generator.rb +17 -13
  52. data/lib/rack/multipart/parser.rb +58 -73
  53. data/lib/rack/multipart/uploaded_file.rb +15 -7
  54. data/lib/rack/multipart.rb +7 -4
  55. data/lib/rack/null_logger.rb +2 -0
  56. data/lib/rack/query_parser.rb +53 -28
  57. data/lib/rack/recursive.rb +7 -5
  58. data/lib/rack/reloader.rb +8 -4
  59. data/lib/rack/request.rb +210 -61
  60. data/lib/rack/response.rb +127 -44
  61. data/lib/rack/rewindable_input.rb +4 -3
  62. data/lib/rack/runtime.rb +6 -4
  63. data/lib/rack/sendfile.rb +13 -9
  64. data/lib/rack/server.rb +95 -24
  65. data/lib/rack/session/abstract/id.rb +33 -21
  66. data/lib/rack/session/cookie.rb +12 -12
  67. data/lib/rack/session/memcache.rb +4 -93
  68. data/lib/rack/session/pool.rb +5 -3
  69. data/lib/rack/show_exceptions.rb +17 -13
  70. data/lib/rack/show_status.rb +5 -5
  71. data/lib/rack/static.rb +23 -11
  72. data/lib/rack/tempfile_reaper.rb +1 -1
  73. data/lib/rack/urlmap.rb +12 -6
  74. data/lib/rack/utils.rb +105 -130
  75. data/lib/rack/version.rb +29 -0
  76. data/lib/rack.rb +67 -73
  77. data/rack.gemspec +40 -28
  78. metadata +39 -182
  79. data/HISTORY.md +0 -520
  80. data/test/builder/an_underscore_app.rb +0 -5
  81. data/test/builder/anything.rb +0 -5
  82. data/test/builder/comment.ru +0 -4
  83. data/test/builder/end.ru +0 -5
  84. data/test/builder/line.ru +0 -1
  85. data/test/builder/options.ru +0 -2
  86. data/test/cgi/assets/folder/test.js +0 -1
  87. data/test/cgi/assets/fonts/font.eot +0 -1
  88. data/test/cgi/assets/images/image.png +0 -1
  89. data/test/cgi/assets/index.html +0 -1
  90. data/test/cgi/assets/javascripts/app.js +0 -1
  91. data/test/cgi/assets/stylesheets/app.css +0 -1
  92. data/test/cgi/lighttpd.conf +0 -26
  93. data/test/cgi/rackup_stub.rb +0 -6
  94. data/test/cgi/sample_rackup.ru +0 -5
  95. data/test/cgi/test +0 -9
  96. data/test/cgi/test+directory/test+file +0 -1
  97. data/test/cgi/test.fcgi +0 -9
  98. data/test/cgi/test.gz +0 -0
  99. data/test/cgi/test.ru +0 -5
  100. data/test/gemloader.rb +0 -10
  101. data/test/helper.rb +0 -34
  102. data/test/multipart/bad_robots +0 -259
  103. data/test/multipart/binary +0 -0
  104. data/test/multipart/content_type_and_no_filename +0 -6
  105. data/test/multipart/empty +0 -10
  106. data/test/multipart/fail_16384_nofile +0 -814
  107. data/test/multipart/file1.txt +0 -1
  108. data/test/multipart/filename_and_modification_param +0 -7
  109. data/test/multipart/filename_and_no_name +0 -6
  110. data/test/multipart/filename_with_encoded_words +0 -7
  111. data/test/multipart/filename_with_escaped_quotes +0 -6
  112. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  113. data/test/multipart/filename_with_null_byte +0 -7
  114. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  115. data/test/multipart/filename_with_single_quote +0 -7
  116. data/test/multipart/filename_with_unescaped_percentages +0 -6
  117. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  118. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  119. data/test/multipart/filename_with_unescaped_quotes +0 -6
  120. data/test/multipart/ie +0 -6
  121. data/test/multipart/invalid_character +0 -6
  122. data/test/multipart/mixed_files +0 -21
  123. data/test/multipart/nested +0 -10
  124. data/test/multipart/none +0 -9
  125. data/test/multipart/quoted +0 -15
  126. data/test/multipart/rack-logo.png +0 -0
  127. data/test/multipart/semicolon +0 -6
  128. data/test/multipart/text +0 -15
  129. data/test/multipart/three_files_three_fields +0 -31
  130. data/test/multipart/unity3d_wwwform +0 -11
  131. data/test/multipart/webkit +0 -32
  132. data/test/rackup/config.ru +0 -31
  133. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  134. data/test/spec_auth_basic.rb +0 -89
  135. data/test/spec_auth_digest.rb +0 -260
  136. data/test/spec_body_proxy.rb +0 -85
  137. data/test/spec_builder.rb +0 -233
  138. data/test/spec_cascade.rb +0 -63
  139. data/test/spec_cgi.rb +0 -84
  140. data/test/spec_chunked.rb +0 -103
  141. data/test/spec_common_logger.rb +0 -107
  142. data/test/spec_conditional_get.rb +0 -103
  143. data/test/spec_config.rb +0 -23
  144. data/test/spec_content_length.rb +0 -86
  145. data/test/spec_content_type.rb +0 -46
  146. data/test/spec_deflater.rb +0 -375
  147. data/test/spec_directory.rb +0 -148
  148. data/test/spec_etag.rb +0 -108
  149. data/test/spec_events.rb +0 -133
  150. data/test/spec_fastcgi.rb +0 -85
  151. data/test/spec_file.rb +0 -264
  152. data/test/spec_handler.rb +0 -57
  153. data/test/spec_head.rb +0 -46
  154. data/test/spec_lint.rb +0 -520
  155. data/test/spec_lobster.rb +0 -59
  156. data/test/spec_lock.rb +0 -204
  157. data/test/spec_logger.rb +0 -24
  158. data/test/spec_media_type.rb +0 -42
  159. data/test/spec_method_override.rb +0 -110
  160. data/test/spec_mime.rb +0 -51
  161. data/test/spec_mock.rb +0 -359
  162. data/test/spec_multipart.rb +0 -721
  163. data/test/spec_null_logger.rb +0 -21
  164. data/test/spec_recursive.rb +0 -75
  165. data/test/spec_request.rb +0 -1423
  166. data/test/spec_response.rb +0 -528
  167. data/test/spec_rewindable_input.rb +0 -128
  168. data/test/spec_runtime.rb +0 -50
  169. data/test/spec_sendfile.rb +0 -125
  170. data/test/spec_server.rb +0 -193
  171. data/test/spec_session_abstract_id.rb +0 -31
  172. data/test/spec_session_abstract_session_hash.rb +0 -45
  173. data/test/spec_session_cookie.rb +0 -442
  174. data/test/spec_session_memcache.rb +0 -357
  175. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  176. data/test/spec_session_pool.rb +0 -247
  177. data/test/spec_show_exceptions.rb +0 -93
  178. data/test/spec_show_status.rb +0 -104
  179. data/test/spec_static.rb +0 -184
  180. data/test/spec_tempfile_reaper.rb +0 -64
  181. data/test/spec_thin.rb +0 -96
  182. data/test/spec_urlmap.rb +0 -237
  183. data/test/spec_utils.rb +0 -742
  184. data/test/spec_version.rb +0 -11
  185. data/test/spec_webrick.rb +0 -206
  186. data/test/static/another/index.html +0 -1
  187. data/test/static/foo.html +0 -1
  188. data/test/static/index.html +0 -1
  189. data/test/testrequest.rb +0 -78
  190. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  191. 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