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_file.rb DELETED
@@ -1,264 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/file'
3
- require 'rack/lint'
4
- require 'rack/mock'
5
-
6
- describe Rack::File do
7
- DOCROOT = File.expand_path(File.dirname(__FILE__)) unless defined? DOCROOT
8
-
9
- def file(*args)
10
- Rack::Lint.new Rack::File.new(*args)
11
- end
12
-
13
- it 'serves files with + in the file name' do
14
- Dir.mktmpdir do |dir|
15
- File.write File.join(dir, "you+me.txt"), "hello world"
16
- app = file(dir)
17
- env = Rack::MockRequest.env_for("/you+me.txt")
18
- status,_,body = app.call env
19
-
20
- assert_equal 200, status
21
-
22
- str = ''
23
- body.each { |x| str << x }
24
- assert_match "hello world", str
25
- end
26
- end
27
-
28
- it "serve files" do
29
- res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/test")
30
-
31
- res.must_be :ok?
32
- assert_match(res, /ruby/)
33
- end
34
-
35
- it "set Last-Modified header" do
36
- res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/test")
37
-
38
- path = File.join(DOCROOT, "/cgi/test")
39
-
40
- res.must_be :ok?
41
- res["Last-Modified"].must_equal File.mtime(path).httpdate
42
- end
43
-
44
- it "return 304 if file isn't modified since last serve" do
45
- path = File.join(DOCROOT, "/cgi/test")
46
- res = Rack::MockRequest.new(file(DOCROOT)).
47
- get("/cgi/test", 'HTTP_IF_MODIFIED_SINCE' => File.mtime(path).httpdate)
48
-
49
- res.status.must_equal 304
50
- res.body.must_be :empty?
51
- end
52
-
53
- it "return the file if it's modified since last serve" do
54
- path = File.join(DOCROOT, "/cgi/test")
55
- res = Rack::MockRequest.new(file(DOCROOT)).
56
- get("/cgi/test", 'HTTP_IF_MODIFIED_SINCE' => (File.mtime(path) - 100).httpdate)
57
-
58
- res.must_be :ok?
59
- end
60
-
61
- it "serve files with URL encoded filenames" do
62
- res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/%74%65%73%74") # "/cgi/test"
63
-
64
- res.must_be :ok?
65
- # res.must_match(/ruby/) # nope
66
- # (/ruby/).must_match res # This is wierd, but an oddity of minitest
67
- # assert_match(/ruby/, res) # nope
68
- assert_match(res, /ruby/)
69
- end
70
-
71
- it "serve uri with URL encoded null byte (%00) in filenames" do
72
- res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/test%00")
73
- res.must_be :bad_request?
74
- end
75
-
76
- it "allow safe directory traversal" do
77
- req = Rack::MockRequest.new(file(DOCROOT))
78
-
79
- res = req.get('/cgi/../cgi/test')
80
- res.must_be :successful?
81
-
82
- res = req.get('.')
83
- res.must_be :not_found?
84
-
85
- res = req.get("test/..")
86
- res.must_be :not_found?
87
- end
88
-
89
- it "not allow unsafe directory traversal" do
90
- req = Rack::MockRequest.new(file(DOCROOT))
91
-
92
- res = req.get("/../README.rdoc")
93
- res.must_be :client_error?
94
-
95
- res = req.get("../test/spec_file.rb")
96
- res.must_be :client_error?
97
-
98
- res = req.get("../README.rdoc")
99
- res.must_be :client_error?
100
-
101
- res.must_be :not_found?
102
- end
103
-
104
- it "allow files with .. in their name" do
105
- req = Rack::MockRequest.new(file(DOCROOT))
106
- res = req.get("/cgi/..test")
107
- res.must_be :not_found?
108
-
109
- res = req.get("/cgi/test..")
110
- res.must_be :not_found?
111
-
112
- res = req.get("/cgi../test..")
113
- res.must_be :not_found?
114
- end
115
-
116
- it "not allow unsafe directory traversal with encoded periods" do
117
- res = Rack::MockRequest.new(file(DOCROOT)).get("/%2E%2E/README")
118
-
119
- res.must_be :client_error?
120
- res.must_be :not_found?
121
- end
122
-
123
- it "allow safe directory traversal with encoded periods" do
124
- res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/%2E%2E/cgi/test")
125
-
126
- res.must_be :successful?
127
- end
128
-
129
- it "404 if it can't find the file" do
130
- res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi/blubb")
131
-
132
- res.must_be :not_found?
133
- end
134
-
135
- it "detect SystemCallErrors" do
136
- res = Rack::MockRequest.new(file(DOCROOT)).get("/cgi")
137
-
138
- res.must_be :not_found?
139
- end
140
-
141
- it "return bodies that respond to #to_path" do
142
- env = Rack::MockRequest.env_for("/cgi/test")
143
- status, _, body = Rack::File.new(DOCROOT).call(env)
144
-
145
- path = File.join(DOCROOT, "/cgi/test")
146
-
147
- status.must_equal 200
148
- body.must_respond_to :to_path
149
- body.to_path.must_equal path
150
- end
151
-
152
- it "return correct byte range in body" do
153
- env = Rack::MockRequest.env_for("/cgi/test")
154
- env["HTTP_RANGE"] = "bytes=22-33"
155
- res = Rack::MockResponse.new(*file(DOCROOT).call(env))
156
-
157
- res.status.must_equal 206
158
- res["Content-Length"].must_equal "12"
159
- res["Content-Range"].must_equal "bytes 22-33/193"
160
- res.body.must_equal "-*- ruby -*-"
161
- end
162
-
163
- it "return error for unsatisfiable byte range" do
164
- env = Rack::MockRequest.env_for("/cgi/test")
165
- env["HTTP_RANGE"] = "bytes=1234-5678"
166
- res = Rack::MockResponse.new(*file(DOCROOT).call(env))
167
-
168
- res.status.must_equal 416
169
- res["Content-Range"].must_equal "bytes */193"
170
- end
171
-
172
- it "support custom http headers" do
173
- env = Rack::MockRequest.env_for("/cgi/test")
174
- status, heads, _ = file(DOCROOT, 'Cache-Control' => 'public, max-age=38',
175
- 'Access-Control-Allow-Origin' => '*').call(env)
176
-
177
- status.must_equal 200
178
- heads['Cache-Control'].must_equal 'public, max-age=38'
179
- heads['Access-Control-Allow-Origin'].must_equal '*'
180
- end
181
-
182
- it "support not add custom http headers if none are supplied" do
183
- env = Rack::MockRequest.env_for("/cgi/test")
184
- status, heads, _ = file(DOCROOT).call(env)
185
-
186
- status.must_equal 200
187
- heads['Cache-Control'].must_be_nil
188
- heads['Access-Control-Allow-Origin'].must_be_nil
189
- end
190
-
191
- it "only support GET, HEAD, and OPTIONS requests" do
192
- req = Rack::MockRequest.new(file(DOCROOT))
193
-
194
- forbidden = %w[post put patch delete]
195
- forbidden.each do |method|
196
- res = req.send(method, "/cgi/test")
197
- res.must_be :client_error?
198
- res.must_be :method_not_allowed?
199
- res.headers['Allow'].split(/, */).sort.must_equal %w(GET HEAD OPTIONS)
200
- end
201
-
202
- allowed = %w[get head options]
203
- allowed.each do |method|
204
- res = req.send(method, "/cgi/test")
205
- res.must_be :successful?
206
- end
207
- end
208
-
209
- it "set Allow correctly for OPTIONS requests" do
210
- req = Rack::MockRequest.new(file(DOCROOT))
211
- res = req.options('/cgi/test')
212
- res.must_be :successful?
213
- res.headers['Allow'].wont_equal nil
214
- res.headers['Allow'].split(/, */).sort.must_equal %w(GET HEAD OPTIONS)
215
- end
216
-
217
- it "set Content-Length correctly for HEAD requests" do
218
- req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT)))
219
- res = req.head "/cgi/test"
220
- res.must_be :successful?
221
- res['Content-Length'].must_equal "193"
222
- end
223
-
224
- it "default to a mime type of text/plain" do
225
- req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT)))
226
- res = req.get "/cgi/test"
227
- res.must_be :successful?
228
- res['Content-Type'].must_equal "text/plain"
229
- end
230
-
231
- it "allow the default mime type to be set" do
232
- req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT, nil, 'application/octet-stream')))
233
- res = req.get "/cgi/test"
234
- res.must_be :successful?
235
- res['Content-Type'].must_equal "application/octet-stream"
236
- end
237
-
238
- it "not set Content-Type if the mime type is not set" do
239
- req = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT, nil, nil)))
240
- res = req.get "/cgi/test"
241
- res.must_be :successful?
242
- res['Content-Type'].must_be_nil
243
- end
244
-
245
- it "return error when file not found for head request" do
246
- res = Rack::MockRequest.new(file(DOCROOT)).head("/cgi/missing")
247
- res.must_be :not_found?
248
- res.body.must_be :empty?
249
- end
250
-
251
- class MyFile < Rack::File
252
- def response_body
253
- "hello world"
254
- end
255
- end
256
-
257
- it "behaves gracefully if response_body is present" do
258
- file = Rack::Lint.new MyFile.new(DOCROOT)
259
- res = Rack::MockRequest.new(file).get("/cgi/test")
260
-
261
- res.must_be :ok?
262
- end
263
-
264
- end
data/test/spec_handler.rb DELETED
@@ -1,57 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/handler'
3
-
4
- class Rack::Handler::Lobster; end
5
- class RockLobster; end
6
-
7
- describe Rack::Handler do
8
- it "has registered default handlers" do
9
- Rack::Handler.get('cgi').must_equal Rack::Handler::CGI
10
- Rack::Handler.get('webrick').must_equal Rack::Handler::WEBrick
11
-
12
- begin
13
- Rack::Handler.get('fastcgi').must_equal Rack::Handler::FastCGI
14
- rescue LoadError
15
- end
16
- end
17
-
18
- it "raise LoadError if handler doesn't exist" do
19
- lambda {
20
- Rack::Handler.get('boom')
21
- }.must_raise(LoadError)
22
-
23
- lambda {
24
- Rack::Handler.get('Object')
25
- }.must_raise(LoadError)
26
- end
27
-
28
- it "get unregistered, but already required, handler by name" do
29
- Rack::Handler.get('Lobster').must_equal Rack::Handler::Lobster
30
- end
31
-
32
- it "register custom handler" do
33
- Rack::Handler.register('rock_lobster', 'RockLobster')
34
- Rack::Handler.get('rock_lobster').must_equal RockLobster
35
- end
36
-
37
- it "not need registration for properly coded handlers even if not already required" do
38
- begin
39
- $LOAD_PATH.push File.expand_path('../unregistered_handler', __FILE__)
40
- Rack::Handler.get('Unregistered').must_equal Rack::Handler::Unregistered
41
- lambda { Rack::Handler.get('UnRegistered') }.must_raise LoadError
42
- Rack::Handler.get('UnregisteredLongOne').must_equal Rack::Handler::UnregisteredLongOne
43
- ensure
44
- $LOAD_PATH.delete File.expand_path('../unregistered_handler', __FILE__)
45
- end
46
- end
47
-
48
- it "allow autoloaded handlers to be registered properly while being loaded" do
49
- path = File.expand_path('../registering_handler', __FILE__)
50
- begin
51
- $LOAD_PATH.push path
52
- Rack::Handler.get('registering_myself').must_equal Rack::Handler::RegisteringMyself
53
- ensure
54
- $LOAD_PATH.delete path
55
- end
56
- end
57
- end
data/test/spec_head.rb DELETED
@@ -1,46 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/head'
3
- require 'rack/lint'
4
- require 'rack/mock'
5
-
6
- describe Rack::Head do
7
-
8
- def test_response(headers = {})
9
- body = StringIO.new "foo"
10
- app = lambda do |env|
11
- [200, {"Content-type" => "test/plain", "Content-length" => "3"}, body]
12
- end
13
- request = Rack::MockRequest.env_for("/", headers)
14
- response = Rack::Lint.new(Rack::Head.new(app)).call(request)
15
-
16
- return response, body
17
- end
18
-
19
- it "pass GET, POST, PUT, DELETE, OPTIONS, TRACE requests" do
20
- %w[GET POST PUT DELETE OPTIONS TRACE].each do |type|
21
- resp, _ = test_response("REQUEST_METHOD" => type)
22
-
23
- resp[0].must_equal 200
24
- resp[1].must_equal "Content-type" => "test/plain", "Content-length" => "3"
25
- resp[2].to_enum.to_a.must_equal ["foo"]
26
- end
27
- end
28
-
29
- it "remove body from HEAD requests" do
30
- resp, _ = test_response("REQUEST_METHOD" => "HEAD")
31
-
32
- resp[0].must_equal 200
33
- resp[1].must_equal "Content-type" => "test/plain", "Content-length" => "3"
34
- resp[2].to_enum.to_a.must_equal []
35
- end
36
-
37
- it "close the body when it is removed" do
38
- resp, body = test_response("REQUEST_METHOD" => "HEAD")
39
- resp[0].must_equal 200
40
- resp[1].must_equal "Content-type" => "test/plain", "Content-length" => "3"
41
- resp[2].to_enum.to_a.must_equal []
42
- body.wont_be :closed?
43
- resp[2].close
44
- body.must_be :closed?
45
- end
46
- end