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