rack 2.0.3 → 2.2.4

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

Potentially problematic release.


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

Files changed (190) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +708 -0
  3. data/CONTRIBUTING.md +136 -0
  4. data/{COPYING → MIT-LICENSE} +4 -2
  5. data/README.rdoc +152 -150
  6. data/Rakefile +37 -23
  7. data/{SPEC → SPEC.rdoc} +35 -10
  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 +36 -25
  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 +8 -5
  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 +3 -3
  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 +14 -4
  46. data/lib/rack/logger.rb +2 -0
  47. data/lib/rack/media_type.rb +10 -5
  48. data/lib/rack/method_override.rb +9 -3
  49. data/lib/rack/mime.rb +9 -1
  50. data/lib/rack/mock.rb +98 -21
  51. data/lib/rack/multipart/generator.rb +17 -13
  52. data/lib/rack/multipart/parser.rb +61 -63
  53. data/lib/rack/multipart/uploaded_file.rb +15 -7
  54. data/lib/rack/multipart.rb +5 -4
  55. data/lib/rack/null_logger.rb +2 -0
  56. data/lib/rack/query_parser.rb +59 -30
  57. data/lib/rack/recursive.rb +7 -5
  58. data/lib/rack/reloader.rb +8 -4
  59. data/lib/rack/request.rb +228 -56
  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 +100 -22
  66. data/lib/rack/session/cookie.rb +22 -14
  67. data/lib/rack/session/memcache.rb +4 -87
  68. data/lib/rack/session/pool.rb +18 -9
  69. data/lib/rack/show_exceptions.rb +22 -18
  70. data/lib/rack/show_status.rb +9 -9
  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 +107 -111
  75. data/lib/rack/version.rb +29 -0
  76. data/lib/rack.rb +67 -73
  77. data/rack.gemspec +40 -29
  78. metadata +25 -181
  79. data/HISTORY.md +0 -505
  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 -95
  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 -515
  155. data/test/spec_lobster.rb +0 -59
  156. data/test/spec_lock.rb +0 -194
  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 -96
  160. data/test/spec_mime.rb +0 -51
  161. data/test/spec_mock.rb +0 -359
  162. data/test/spec_multipart.rb +0 -722
  163. data/test/spec_null_logger.rb +0 -21
  164. data/test/spec_recursive.rb +0 -75
  165. data/test/spec_request.rb +0 -1393
  166. data/test/spec_response.rb +0 -510
  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 -320
  175. data/test/spec_session_pool.rb +0 -210
  176. data/test/spec_show_exceptions.rb +0 -80
  177. data/test/spec_show_status.rb +0 -104
  178. data/test/spec_static.rb +0 -184
  179. data/test/spec_tempfile_reaper.rb +0 -64
  180. data/test/spec_thin.rb +0 -96
  181. data/test/spec_urlmap.rb +0 -237
  182. data/test/spec_utils.rb +0 -742
  183. data/test/spec_version.rb +0 -11
  184. data/test/spec_webrick.rb +0 -209
  185. data/test/static/another/index.html +0 -1
  186. data/test/static/foo.html +0 -1
  187. data/test/static/index.html +0 -1
  188. data/test/testrequest.rb +0 -78
  189. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  190. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
@@ -1,85 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/body_proxy'
3
- require 'stringio'
4
-
5
- describe Rack::BodyProxy do
6
- it 'call each on the wrapped body' do
7
- called = false
8
- proxy = Rack::BodyProxy.new(['foo']) { }
9
- proxy.each do |str|
10
- called = true
11
- str.must_equal 'foo'
12
- end
13
- called.must_equal true
14
- end
15
-
16
- it 'call close on the wrapped body' do
17
- body = StringIO.new
18
- proxy = Rack::BodyProxy.new(body) { }
19
- proxy.close
20
- body.must_be :closed?
21
- end
22
-
23
- it 'only call close on the wrapped body if it responds to close' do
24
- body = []
25
- proxy = Rack::BodyProxy.new(body) { }
26
- proxy.close.must_be_nil
27
- end
28
-
29
- it 'call the passed block on close' do
30
- called = false
31
- proxy = Rack::BodyProxy.new([]) { called = true }
32
- called.must_equal false
33
- proxy.close
34
- called.must_equal true
35
- end
36
-
37
- it 'call the passed block on close even if there is an exception' do
38
- object = Object.new
39
- def object.close() raise "No!" end
40
- called = false
41
-
42
- begin
43
- proxy = Rack::BodyProxy.new(object) { called = true }
44
- called.must_equal false
45
- proxy.close
46
- rescue RuntimeError => e
47
- end
48
-
49
- raise "Expected exception to have been raised" unless e
50
- called.must_equal true
51
- end
52
-
53
- it 'allow multiple arguments in respond_to?' do
54
- body = []
55
- proxy = Rack::BodyProxy.new(body) { }
56
- proxy.respond_to?(:foo, false).must_equal false
57
- end
58
-
59
- it 'not respond to :to_ary' do
60
- body = Object.new.tap { |o| def o.to_ary() end }
61
- body.respond_to?(:to_ary).must_equal true
62
-
63
- proxy = Rack::BodyProxy.new(body) { }
64
- proxy.respond_to?(:to_ary).must_equal false
65
- proxy.respond_to?("to_ary").must_equal false
66
- end
67
-
68
- it 'not close more than one time' do
69
- count = 0
70
- proxy = Rack::BodyProxy.new([]) { count += 1; raise "Block invoked more than 1 time!" if count > 1 }
71
- 2.times { proxy.close }
72
- count.must_equal 1
73
- end
74
-
75
- it 'be closed when the callback is triggered' do
76
- closed = false
77
- proxy = Rack::BodyProxy.new([]) { closed = proxy.closed? }
78
- proxy.close
79
- closed.must_equal true
80
- end
81
-
82
- it 'provide an #each method' do
83
- Rack::BodyProxy.method_defined?(:each).must_equal true
84
- end
85
- end
data/test/spec_builder.rb DELETED
@@ -1,233 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/builder'
3
- require 'rack/lint'
4
- require 'rack/mock'
5
- require 'rack/show_exceptions'
6
- require 'rack/urlmap'
7
-
8
- class NothingMiddleware
9
- def initialize(app)
10
- @app = app
11
- end
12
- def call(env)
13
- @@env = env
14
- response = @app.call(env)
15
- response
16
- end
17
- def self.env
18
- @@env
19
- end
20
- end
21
-
22
- describe Rack::Builder do
23
- def builder(&block)
24
- Rack::Lint.new Rack::Builder.new(&block)
25
- end
26
-
27
- def builder_to_app(&block)
28
- Rack::Lint.new Rack::Builder.new(&block).to_app
29
- end
30
-
31
- it "supports mapping" do
32
- app = builder_to_app do
33
- map '/' do |outer_env|
34
- run lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, ['root']] }
35
- end
36
- map '/sub' do
37
- run lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, ['sub']] }
38
- end
39
- end
40
- Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'root'
41
- Rack::MockRequest.new(app).get("/sub").body.to_s.must_equal 'sub'
42
- end
43
-
44
- it "doesn't dupe env even when mapping" do
45
- app = builder_to_app do
46
- use NothingMiddleware
47
- map '/' do |outer_env|
48
- run lambda { |inner_env|
49
- inner_env['new_key'] = 'new_value'
50
- [200, {"Content-Type" => "text/plain"}, ['root']]
51
- }
52
- end
53
- end
54
- Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'root'
55
- NothingMiddleware.env['new_key'].must_equal 'new_value'
56
- end
57
-
58
- it "chains apps by default" do
59
- app = builder_to_app do
60
- use Rack::ShowExceptions
61
- run lambda { |env| raise "bzzzt" }
62
- end
63
-
64
- Rack::MockRequest.new(app).get("/").must_be :server_error?
65
- Rack::MockRequest.new(app).get("/").must_be :server_error?
66
- Rack::MockRequest.new(app).get("/").must_be :server_error?
67
- end
68
-
69
- it "has implicit #to_app" do
70
- app = builder do
71
- use Rack::ShowExceptions
72
- run lambda { |env| raise "bzzzt" }
73
- end
74
-
75
- Rack::MockRequest.new(app).get("/").must_be :server_error?
76
- Rack::MockRequest.new(app).get("/").must_be :server_error?
77
- Rack::MockRequest.new(app).get("/").must_be :server_error?
78
- end
79
-
80
- it "supports blocks on use" do
81
- app = builder do
82
- use Rack::ShowExceptions
83
- use Rack::Auth::Basic do |username, password|
84
- 'secret' == password
85
- end
86
-
87
- run lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hi Boss']] }
88
- end
89
-
90
- response = Rack::MockRequest.new(app).get("/")
91
- response.must_be :client_error?
92
- response.status.must_equal 401
93
-
94
- # with auth...
95
- response = Rack::MockRequest.new(app).get("/",
96
- 'HTTP_AUTHORIZATION' => 'Basic ' + ["joe:secret"].pack("m*"))
97
- response.status.must_equal 200
98
- response.body.to_s.must_equal 'Hi Boss'
99
- end
100
-
101
- it "has explicit #to_app" do
102
- app = builder do
103
- use Rack::ShowExceptions
104
- run lambda { |env| raise "bzzzt" }
105
- end
106
-
107
- Rack::MockRequest.new(app).get("/").must_be :server_error?
108
- Rack::MockRequest.new(app).get("/").must_be :server_error?
109
- Rack::MockRequest.new(app).get("/").must_be :server_error?
110
- end
111
-
112
- it "can mix map and run for endpoints" do
113
- app = builder do
114
- map '/sub' do
115
- run lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, ['sub']] }
116
- end
117
- run lambda { |inner_env| [200, {"Content-Type" => "text/plain"}, ['root']] }
118
- end
119
-
120
- Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'root'
121
- Rack::MockRequest.new(app).get("/sub").body.to_s.must_equal 'sub'
122
- end
123
-
124
- it "accepts middleware-only map blocks" do
125
- app = builder do
126
- map('/foo') { use Rack::ShowExceptions }
127
- run lambda { |env| raise "bzzzt" }
128
- end
129
-
130
- proc { Rack::MockRequest.new(app).get("/") }.must_raise(RuntimeError)
131
- Rack::MockRequest.new(app).get("/foo").must_be :server_error?
132
- end
133
-
134
- it "yields the generated app to a block for warmup" do
135
- warmed_up_app = nil
136
-
137
- app = Rack::Builder.new do
138
- warmup { |a| warmed_up_app = a }
139
- run lambda { |env| [200, {}, []] }
140
- end.to_app
141
-
142
- warmed_up_app.must_equal app
143
- end
144
-
145
- it "initialize apps once" do
146
- app = builder do
147
- class AppClass
148
- def initialize
149
- @called = 0
150
- end
151
- def call(env)
152
- raise "bzzzt" if @called > 0
153
- @called += 1
154
- [200, {'Content-Type' => 'text/plain'}, ['OK']]
155
- end
156
- end
157
-
158
- use Rack::ShowExceptions
159
- run AppClass.new
160
- end
161
-
162
- Rack::MockRequest.new(app).get("/").status.must_equal 200
163
- Rack::MockRequest.new(app).get("/").must_be :server_error?
164
- end
165
-
166
- it "allows use after run" do
167
- app = builder do
168
- run lambda { |env| raise "bzzzt" }
169
- use Rack::ShowExceptions
170
- end
171
-
172
- Rack::MockRequest.new(app).get("/").must_be :server_error?
173
- Rack::MockRequest.new(app).get("/").must_be :server_error?
174
- Rack::MockRequest.new(app).get("/").must_be :server_error?
175
- end
176
-
177
- it 'complains about a missing run' do
178
- proc do
179
- Rack::Lint.new Rack::Builder.app { use Rack::ShowExceptions }
180
- end.must_raise(RuntimeError)
181
- end
182
-
183
- describe "parse_file" do
184
- def config_file(name)
185
- File.join(File.dirname(__FILE__), 'builder', name)
186
- end
187
-
188
- it "parses commented options" do
189
- app, options = Rack::Builder.parse_file config_file('options.ru')
190
- options[:debug].must_equal true
191
- options[:environment].must_equal 'test'
192
- options[:Port].must_equal '2929'
193
- Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'OK'
194
- end
195
-
196
- it "removes __END__ before evaluating app" do
197
- app, _ = Rack::Builder.parse_file config_file('end.ru')
198
- Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'OK'
199
- end
200
-
201
- it "supports multi-line comments" do
202
- proc, env = Rack::Builder.parse_file(config_file('comment.ru'))
203
- proc.must_be_kind_of Proc
204
- env.must_equal({})
205
- end
206
-
207
- it "requires anything not ending in .ru" do
208
- $: << File.dirname(__FILE__)
209
- app, * = Rack::Builder.parse_file 'builder/anything'
210
- Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'OK'
211
- $:.pop
212
- end
213
-
214
- it 'requires an_underscore_app not ending in .ru' do
215
- $: << File.dirname(__FILE__)
216
- app, * = Rack::Builder.parse_file 'builder/an_underscore_app'
217
- Rack::MockRequest.new(app).get('/').body.to_s.must_equal 'OK'
218
- $:.pop
219
- end
220
-
221
- it "sets __LINE__ correctly" do
222
- app, _ = Rack::Builder.parse_file config_file('line.ru')
223
- Rack::MockRequest.new(app).get("/").body.to_s.must_equal '1'
224
- end
225
- end
226
-
227
- describe 'new_from_string' do
228
- it "builds a rack app from string" do
229
- app, = Rack::Builder.new_from_string "run lambda{|env| [200, {'Content-Type' => 'text/plane'}, ['OK']] }"
230
- Rack::MockRequest.new(app).get("/").body.to_s.must_equal 'OK'
231
- end
232
- end
233
- end
data/test/spec_cascade.rb DELETED
@@ -1,63 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack'
3
- require 'rack/cascade'
4
- require 'rack/file'
5
- require 'rack/lint'
6
- require 'rack/urlmap'
7
- require 'rack/mock'
8
-
9
- describe Rack::Cascade do
10
- def cascade(*args)
11
- Rack::Lint.new Rack::Cascade.new(*args)
12
- end
13
-
14
- docroot = File.expand_path(File.dirname(__FILE__))
15
- app1 = Rack::File.new(docroot)
16
-
17
- app2 = Rack::URLMap.new("/crash" => lambda { |env| raise "boom" })
18
-
19
- app3 = Rack::URLMap.new("/foo" => lambda { |env|
20
- [200, { "Content-Type" => "text/plain"}, [""]]})
21
-
22
- it "dispatch onward on 404 and 405 by default" do
23
- cascade = cascade([app1, app2, app3])
24
- Rack::MockRequest.new(cascade).get("/cgi/test").must_be :ok?
25
- Rack::MockRequest.new(cascade).get("/foo").must_be :ok?
26
- Rack::MockRequest.new(cascade).get("/toobad").must_be :not_found?
27
- Rack::MockRequest.new(cascade).get("/cgi/../..").must_be :client_error?
28
-
29
- # Put is not allowed by Rack::File so it'll 405.
30
- Rack::MockRequest.new(cascade).put("/foo").must_be :ok?
31
- end
32
-
33
- it "dispatch onward on whatever is passed" do
34
- cascade = cascade([app1, app2, app3], [404, 403])
35
- Rack::MockRequest.new(cascade).get("/cgi/../bla").must_be :not_found?
36
- end
37
-
38
- it "return 404 if empty" do
39
- Rack::MockRequest.new(cascade([])).get('/').must_be :not_found?
40
- end
41
-
42
- it "append new app" do
43
- cascade = Rack::Cascade.new([], [404, 403])
44
- Rack::MockRequest.new(cascade).get('/').must_be :not_found?
45
- cascade << app2
46
- Rack::MockRequest.new(cascade).get('/cgi/test').must_be :not_found?
47
- Rack::MockRequest.new(cascade).get('/cgi/../bla').must_be :not_found?
48
- cascade << app1
49
- Rack::MockRequest.new(cascade).get('/cgi/test').must_be :ok?
50
- Rack::MockRequest.new(cascade).get('/cgi/../..').must_be :client_error?
51
- Rack::MockRequest.new(cascade).get('/foo').must_be :not_found?
52
- cascade << app3
53
- Rack::MockRequest.new(cascade).get('/foo').must_be :ok?
54
- end
55
-
56
- it "close the body on cascade" do
57
- body = StringIO.new
58
- closer = lambda { |env| [404, {}, body] }
59
- cascade = Rack::Cascade.new([closer, app3], [404])
60
- Rack::MockRequest.new(cascade).get("/foo").must_be :ok?
61
- body.must_be :closed?
62
- end
63
- end
data/test/spec_cgi.rb DELETED
@@ -1,84 +0,0 @@
1
- require 'helper'
2
-
3
- if defined? LIGHTTPD_PID
4
-
5
- require File.expand_path('../testrequest', __FILE__)
6
- require 'rack/handler/cgi'
7
-
8
- describe Rack::Handler::CGI do
9
- include TestRequest::Helpers
10
-
11
- before do
12
- @host = '127.0.0.1'
13
- @port = 9203
14
- end
15
-
16
- if `which lighttpd` && !$?.success?
17
- raise "lighttpd not found"
18
- end
19
-
20
- it "respond" do
21
- sleep 1
22
- GET("/test")
23
- response.wont_be :nil?
24
- end
25
-
26
- it "be a lighttpd" do
27
- GET("/test")
28
- status.must_equal 200
29
- response["SERVER_SOFTWARE"].must_match(/lighttpd/)
30
- response["HTTP_VERSION"].must_equal "HTTP/1.1"
31
- response["SERVER_PROTOCOL"].must_equal "HTTP/1.1"
32
- response["SERVER_PORT"].must_equal @port.to_s
33
- response["SERVER_NAME"].must_equal @host
34
- end
35
-
36
- it "have rack headers" do
37
- GET("/test")
38
- response["rack.version"].must_equal [1,3]
39
- assert_equal false, response["rack.multithread"]
40
- assert_equal true, response["rack.multiprocess"]
41
- assert_equal true, response["rack.run_once"]
42
- end
43
-
44
- it "have CGI headers on GET" do
45
- GET("/test")
46
- response["REQUEST_METHOD"].must_equal "GET"
47
- response["SCRIPT_NAME"].must_equal "/test"
48
- response["REQUEST_PATH"].must_equal "/"
49
- response["PATH_INFO"].must_be_nil
50
- response["QUERY_STRING"].must_equal ""
51
- response["test.postdata"].must_equal ""
52
-
53
- GET("/test/foo?quux=1")
54
- response["REQUEST_METHOD"].must_equal "GET"
55
- response["SCRIPT_NAME"].must_equal "/test"
56
- response["REQUEST_PATH"].must_equal "/"
57
- response["PATH_INFO"].must_equal "/foo"
58
- response["QUERY_STRING"].must_equal "quux=1"
59
- end
60
-
61
- it "have CGI headers on POST" do
62
- POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
63
- status.must_equal 200
64
- response["REQUEST_METHOD"].must_equal "POST"
65
- response["SCRIPT_NAME"].must_equal "/test"
66
- response["REQUEST_PATH"].must_equal "/"
67
- response["QUERY_STRING"].must_equal ""
68
- response["HTTP_X_TEST_HEADER"].must_equal "42"
69
- response["test.postdata"].must_equal "rack-form-data=23"
70
- end
71
-
72
- it "support HTTP auth" do
73
- GET("/test", {:user => "ruth", :passwd => "secret"})
74
- response["HTTP_AUTHORIZATION"].must_equal "Basic cnV0aDpzZWNyZXQ="
75
- end
76
-
77
- it "set status" do
78
- GET("/test?secret")
79
- status.must_equal 403
80
- response["rack.url_scheme"].must_equal "http"
81
- end
82
- end
83
-
84
- end # if defined? LIGHTTPD_PID
data/test/spec_chunked.rb DELETED
@@ -1,103 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/chunked'
3
- require 'rack/lint'
4
- require 'rack/mock'
5
-
6
- describe Rack::Chunked do
7
- def chunked(app)
8
- proc do |env|
9
- app = Rack::Chunked.new(app)
10
- response = Rack::Lint.new(app).call(env)
11
- # we want to use body like an array, but it only has #each
12
- response[2] = response[2].to_enum.to_a
13
- response
14
- end
15
- end
16
-
17
- before do
18
- @env = Rack::MockRequest.
19
- env_for('/', 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => 'GET')
20
- end
21
-
22
- it 'chunk responses with no Content-Length' do
23
- app = lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hello', ' ', 'World!']] }
24
- response = Rack::MockResponse.new(*chunked(app).call(@env))
25
- response.headers.wont_include 'Content-Length'
26
- response.headers['Transfer-Encoding'].must_equal 'chunked'
27
- response.body.must_equal "5\r\nHello\r\n1\r\n \r\n6\r\nWorld!\r\n0\r\n\r\n"
28
- end
29
-
30
- it 'chunks empty bodies properly' do
31
- app = lambda { |env| [200, {"Content-Type" => "text/plain"}, []] }
32
- response = Rack::MockResponse.new(*chunked(app).call(@env))
33
- response.headers.wont_include 'Content-Length'
34
- response.headers['Transfer-Encoding'].must_equal 'chunked'
35
- response.body.must_equal "0\r\n\r\n"
36
- end
37
-
38
- it 'chunks encoded bodies properly' do
39
- body = ["\uFFFEHello", " ", "World"].map {|t| t.encode("UTF-16LE") }
40
- app = lambda { |env| [200, {"Content-Type" => "text/plain"}, body] }
41
- response = Rack::MockResponse.new(*chunked(app).call(@env))
42
- response.headers.wont_include 'Content-Length'
43
- response.headers['Transfer-Encoding'].must_equal 'chunked'
44
- response.body.encoding.to_s.must_equal "ASCII-8BIT"
45
- response.body.must_equal "c\r\n\xFE\xFFH\x00e\x00l\x00l\x00o\x00\r\n2\r\n \x00\r\na\r\nW\x00o\x00r\x00l\x00d\x00\r\n0\r\n\r\n".force_encoding("BINARY")
46
- response.body.must_equal "c\r\n\xFE\xFFH\x00e\x00l\x00l\x00o\x00\r\n2\r\n \x00\r\na\r\nW\x00o\x00r\x00l\x00d\x00\r\n0\r\n\r\n".force_encoding(Encoding::BINARY)
47
- end
48
-
49
- it 'not modify response when Content-Length header present' do
50
- app = lambda { |env|
51
- [200, {"Content-Type" => "text/plain", 'Content-Length'=>'12'}, ['Hello', ' ', 'World!']]
52
- }
53
- status, headers, body = chunked(app).call(@env)
54
- status.must_equal 200
55
- headers.wont_include 'Transfer-Encoding'
56
- headers.must_include 'Content-Length'
57
- body.join.must_equal 'Hello World!'
58
- end
59
-
60
- it 'not modify response when client is HTTP/1.0' do
61
- app = lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hello', ' ', 'World!']] }
62
- @env['HTTP_VERSION'] = 'HTTP/1.0'
63
- status, headers, body = chunked(app).call(@env)
64
- status.must_equal 200
65
- headers.wont_include 'Transfer-Encoding'
66
- body.join.must_equal 'Hello World!'
67
- end
68
-
69
- it 'not modify response when client is ancient, pre-HTTP/1.0' do
70
- app = lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hello', ' ', 'World!']] }
71
- check = lambda do
72
- status, headers, body = chunked(app).call(@env.dup)
73
- status.must_equal 200
74
- headers.wont_include 'Transfer-Encoding'
75
- body.join.must_equal 'Hello World!'
76
- end
77
-
78
- @env.delete('HTTP_VERSION') # unicorn will do this on pre-HTTP/1.0 requests
79
- check.call
80
-
81
- @env['HTTP_VERSION'] = 'HTTP/0.9' # not sure if this happens in practice
82
- check.call
83
- end
84
-
85
- it 'not modify response when Transfer-Encoding header already present' do
86
- app = lambda { |env|
87
- [200, {"Content-Type" => "text/plain", 'Transfer-Encoding' => 'identity'}, ['Hello', ' ', 'World!']]
88
- }
89
- status, headers, body = chunked(app).call(@env)
90
- status.must_equal 200
91
- headers['Transfer-Encoding'].must_equal 'identity'
92
- body.join.must_equal 'Hello World!'
93
- end
94
-
95
- [100, 204, 304].each do |status_code|
96
- it "not modify response when status code is #{status_code}" do
97
- app = lambda { |env| [status_code, {}, []] }
98
- status, headers, _ = chunked(app).call(@env)
99
- status.must_equal status_code
100
- headers.wont_include 'Transfer-Encoding'
101
- end
102
- end
103
- end
@@ -1,95 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/common_logger'
3
- require 'rack/lint'
4
- require 'rack/mock'
5
-
6
- require 'logger'
7
-
8
- describe Rack::CommonLogger do
9
- obj = 'foobar'
10
- length = obj.size
11
-
12
- app = Rack::Lint.new lambda { |env|
13
- [200,
14
- {"Content-Type" => "text/html", "Content-Length" => length.to_s},
15
- [obj]]}
16
- app_without_length = Rack::Lint.new lambda { |env|
17
- [200,
18
- {"Content-Type" => "text/html"},
19
- []]}
20
- app_with_zero_length = Rack::Lint.new lambda { |env|
21
- [200,
22
- {"Content-Type" => "text/html", "Content-Length" => "0"},
23
- []]}
24
-
25
- it "log to rack.errors by default" do
26
- res = Rack::MockRequest.new(Rack::CommonLogger.new(app)).get("/")
27
-
28
- res.errors.wont_be :empty?
29
- res.errors.must_match(/"GET \/ " 200 #{length} /)
30
- end
31
-
32
- it "log to anything with +write+" do
33
- log = StringIO.new
34
- Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/")
35
-
36
- log.string.must_match(/"GET \/ " 200 #{length} /)
37
- end
38
-
39
- it "work with standartd library logger" do
40
- logdev = StringIO.new
41
- log = Logger.new(logdev)
42
- Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/")
43
-
44
- logdev.string.must_match(/"GET \/ " 200 #{length} /)
45
- end
46
-
47
- it "log - content length if header is missing" do
48
- res = Rack::MockRequest.new(Rack::CommonLogger.new(app_without_length)).get("/")
49
-
50
- res.errors.wont_be :empty?
51
- res.errors.must_match(/"GET \/ " 200 - /)
52
- end
53
-
54
- it "log - content length if header is zero" do
55
- res = Rack::MockRequest.new(Rack::CommonLogger.new(app_with_zero_length)).get("/")
56
-
57
- res.errors.wont_be :empty?
58
- res.errors.must_match(/"GET \/ " 200 - /)
59
- end
60
-
61
- def with_mock_time(t = 0)
62
- mc = class << Time; self; end
63
- mc.send :alias_method, :old_now, :now
64
- mc.send :define_method, :now do
65
- at(t)
66
- end
67
- yield
68
- ensure
69
- mc.send :undef_method, :now
70
- mc.send :alias_method, :now, :old_now
71
- end
72
-
73
- it "log in common log format" do
74
- log = StringIO.new
75
- with_mock_time do
76
- Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/")
77
- end
78
-
79
- md = /- - - \[([^\]]+)\] "(\w+) \/ " (\d{3}) \d+ ([\d\.]+)/.match(log.string)
80
- md.wont_equal nil
81
- time, method, status, duration = *md.captures
82
- time.must_equal Time.at(0).strftime("%d/%b/%Y:%H:%M:%S %z")
83
- method.must_equal "GET"
84
- status.must_equal "200"
85
- (0..1).must_include duration.to_f
86
- end
87
-
88
- def length
89
- 123
90
- end
91
-
92
- def self.obj
93
- "hello world"
94
- end
95
- end