rack 1.6.11 → 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 (190) 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 +157 -163
  6. data/Rakefile +38 -32
  7. data/{SPEC → SPEC.rdoc} +41 -13
  8. data/bin/rackup +1 -0
  9. data/contrib/rack_logo.svg +164 -111
  10. data/example/lobster.ru +2 -0
  11. data/example/protectedlobster.rb +4 -2
  12. data/example/protectedlobster.ru +3 -1
  13. data/lib/rack/auth/abstract/handler.rb +3 -1
  14. data/lib/rack/auth/abstract/request.rb +6 -2
  15. data/lib/rack/auth/basic.rb +7 -4
  16. data/lib/rack/auth/digest/md5.rb +13 -11
  17. data/lib/rack/auth/digest/nonce.rb +6 -3
  18. data/lib/rack/auth/digest/params.rb +5 -4
  19. data/lib/rack/auth/digest/request.rb +6 -4
  20. data/lib/rack/body_proxy.rb +21 -15
  21. data/lib/rack/builder.rb +119 -26
  22. data/lib/rack/cascade.rb +28 -12
  23. data/lib/rack/chunked.rb +70 -22
  24. data/lib/rack/common_logger.rb +80 -0
  25. data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -16
  26. data/lib/rack/config.rb +2 -0
  27. data/lib/rack/content_length.rb +9 -8
  28. data/lib/rack/content_type.rb +5 -4
  29. data/lib/rack/core_ext/regexp.rb +14 -0
  30. data/lib/rack/deflater.rb +60 -70
  31. data/lib/rack/directory.rb +117 -85
  32. data/lib/rack/etag.rb +9 -7
  33. data/lib/rack/events.rb +153 -0
  34. data/lib/rack/file.rb +4 -149
  35. data/lib/rack/files.rb +218 -0
  36. data/lib/rack/handler/cgi.rb +17 -19
  37. data/lib/rack/handler/fastcgi.rb +17 -18
  38. data/lib/rack/handler/lsws.rb +14 -14
  39. data/lib/rack/handler/scgi.rb +22 -21
  40. data/lib/rack/handler/thin.rb +20 -11
  41. data/lib/rack/handler/webrick.rb +39 -32
  42. data/lib/rack/handler.rb +9 -26
  43. data/lib/rack/head.rb +16 -18
  44. data/lib/rack/lint.rb +110 -64
  45. data/lib/rack/lobster.rb +10 -10
  46. data/lib/rack/lock.rb +17 -11
  47. data/lib/rack/logger.rb +4 -2
  48. data/lib/rack/media_type.rb +43 -0
  49. data/lib/rack/{methodoverride.rb → method_override.rb} +10 -8
  50. data/lib/rack/mime.rb +27 -6
  51. data/lib/rack/mock.rb +124 -65
  52. data/lib/rack/multipart/generator.rb +20 -16
  53. data/lib/rack/multipart/parser.rb +273 -162
  54. data/lib/rack/multipart/uploaded_file.rb +15 -8
  55. data/lib/rack/multipart.rb +39 -8
  56. data/lib/rack/{nulllogger.rb → null_logger.rb} +3 -1
  57. data/lib/rack/query_parser.rb +217 -0
  58. data/lib/rack/recursive.rb +11 -9
  59. data/lib/rack/reloader.rb +8 -4
  60. data/lib/rack/request.rb +543 -305
  61. data/lib/rack/response.rb +244 -88
  62. data/lib/rack/rewindable_input.rb +5 -15
  63. data/lib/rack/runtime.rb +12 -18
  64. data/lib/rack/sendfile.rb +17 -15
  65. data/lib/rack/server.rb +125 -47
  66. data/lib/rack/session/abstract/id.rb +216 -93
  67. data/lib/rack/session/cookie.rb +47 -31
  68. data/lib/rack/session/memcache.rb +4 -87
  69. data/lib/rack/session/pool.rb +26 -17
  70. data/lib/rack/show_exceptions.rb +390 -0
  71. data/lib/rack/{showstatus.rb → show_status.rb} +8 -8
  72. data/lib/rack/static.rb +48 -11
  73. data/lib/rack/tempfile_reaper.rb +3 -3
  74. data/lib/rack/urlmap.rb +26 -19
  75. data/lib/rack/utils.rb +208 -294
  76. data/lib/rack/version.rb +29 -0
  77. data/lib/rack.rb +76 -33
  78. data/rack.gemspec +43 -30
  79. metadata +62 -183
  80. data/HISTORY.md +0 -375
  81. data/KNOWN-ISSUES +0 -44
  82. data/lib/rack/backports/uri/common_18.rb +0 -56
  83. data/lib/rack/backports/uri/common_192.rb +0 -52
  84. data/lib/rack/backports/uri/common_193.rb +0 -29
  85. data/lib/rack/commonlogger.rb +0 -72
  86. data/lib/rack/handler/evented_mongrel.rb +0 -8
  87. data/lib/rack/handler/mongrel.rb +0 -106
  88. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  89. data/lib/rack/showexceptions.rb +0 -387
  90. data/lib/rack/utils/okjson.rb +0 -600
  91. data/test/builder/anything.rb +0 -5
  92. data/test/builder/comment.ru +0 -4
  93. data/test/builder/end.ru +0 -5
  94. data/test/builder/line.ru +0 -1
  95. data/test/builder/options.ru +0 -2
  96. data/test/cgi/assets/folder/test.js +0 -1
  97. data/test/cgi/assets/fonts/font.eot +0 -1
  98. data/test/cgi/assets/images/image.png +0 -1
  99. data/test/cgi/assets/index.html +0 -1
  100. data/test/cgi/assets/javascripts/app.js +0 -1
  101. data/test/cgi/assets/stylesheets/app.css +0 -1
  102. data/test/cgi/lighttpd.conf +0 -26
  103. data/test/cgi/rackup_stub.rb +0 -6
  104. data/test/cgi/sample_rackup.ru +0 -5
  105. data/test/cgi/test +0 -9
  106. data/test/cgi/test+directory/test+file +0 -1
  107. data/test/cgi/test.fcgi +0 -8
  108. data/test/cgi/test.ru +0 -5
  109. data/test/gemloader.rb +0 -10
  110. data/test/multipart/bad_robots +0 -259
  111. data/test/multipart/binary +0 -0
  112. data/test/multipart/content_type_and_no_filename +0 -6
  113. data/test/multipart/empty +0 -10
  114. data/test/multipart/fail_16384_nofile +0 -814
  115. data/test/multipart/file1.txt +0 -1
  116. data/test/multipart/filename_and_modification_param +0 -7
  117. data/test/multipart/filename_and_no_name +0 -6
  118. data/test/multipart/filename_with_escaped_quotes +0 -6
  119. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  120. data/test/multipart/filename_with_null_byte +0 -7
  121. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  122. data/test/multipart/filename_with_unescaped_percentages +0 -6
  123. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  124. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  125. data/test/multipart/filename_with_unescaped_quotes +0 -6
  126. data/test/multipart/ie +0 -6
  127. data/test/multipart/invalid_character +0 -6
  128. data/test/multipart/mixed_files +0 -21
  129. data/test/multipart/nested +0 -10
  130. data/test/multipart/none +0 -9
  131. data/test/multipart/semicolon +0 -6
  132. data/test/multipart/text +0 -15
  133. data/test/multipart/three_files_three_fields +0 -31
  134. data/test/multipart/webkit +0 -32
  135. data/test/rackup/config.ru +0 -31
  136. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  137. data/test/spec_auth_basic.rb +0 -81
  138. data/test/spec_auth_digest.rb +0 -259
  139. data/test/spec_body_proxy.rb +0 -85
  140. data/test/spec_builder.rb +0 -223
  141. data/test/spec_cascade.rb +0 -61
  142. data/test/spec_cgi.rb +0 -102
  143. data/test/spec_chunked.rb +0 -101
  144. data/test/spec_commonlogger.rb +0 -93
  145. data/test/spec_conditionalget.rb +0 -102
  146. data/test/spec_config.rb +0 -22
  147. data/test/spec_content_length.rb +0 -85
  148. data/test/spec_content_type.rb +0 -45
  149. data/test/spec_deflater.rb +0 -339
  150. data/test/spec_directory.rb +0 -88
  151. data/test/spec_etag.rb +0 -107
  152. data/test/spec_fastcgi.rb +0 -107
  153. data/test/spec_file.rb +0 -221
  154. data/test/spec_handler.rb +0 -72
  155. data/test/spec_head.rb +0 -45
  156. data/test/spec_lint.rb +0 -550
  157. data/test/spec_lobster.rb +0 -58
  158. data/test/spec_lock.rb +0 -164
  159. data/test/spec_logger.rb +0 -23
  160. data/test/spec_methodoverride.rb +0 -111
  161. data/test/spec_mime.rb +0 -51
  162. data/test/spec_mock.rb +0 -297
  163. data/test/spec_mongrel.rb +0 -182
  164. data/test/spec_multipart.rb +0 -600
  165. data/test/spec_nulllogger.rb +0 -20
  166. data/test/spec_recursive.rb +0 -72
  167. data/test/spec_request.rb +0 -1232
  168. data/test/spec_response.rb +0 -407
  169. data/test/spec_rewindable_input.rb +0 -118
  170. data/test/spec_runtime.rb +0 -49
  171. data/test/spec_sendfile.rb +0 -130
  172. data/test/spec_server.rb +0 -167
  173. data/test/spec_session_abstract_id.rb +0 -53
  174. data/test/spec_session_cookie.rb +0 -410
  175. data/test/spec_session_memcache.rb +0 -321
  176. data/test/spec_session_pool.rb +0 -209
  177. data/test/spec_showexceptions.rb +0 -98
  178. data/test/spec_showstatus.rb +0 -103
  179. data/test/spec_static.rb +0 -145
  180. data/test/spec_tempfile_reaper.rb +0 -63
  181. data/test/spec_thin.rb +0 -91
  182. data/test/spec_urlmap.rb +0 -236
  183. data/test/spec_utils.rb +0 -647
  184. data/test/spec_version.rb +0 -17
  185. data/test/spec_webrick.rb +0 -184
  186. data/test/static/another/index.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
data/lib/rack/server.rb CHANGED
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'optparse'
2
4
  require 'fileutils'
3
5
 
4
-
5
6
  module Rack
6
7
 
7
8
  class Server
9
+ (require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4'
8
10
 
9
11
  class Options
10
12
  def parse!(args)
@@ -21,10 +23,6 @@ module Rack
21
23
  lineno += 1
22
24
  }
23
25
 
24
- opts.on("-b", "--builder BUILDER_LINE", "evaluate a BUILDER_LINE of code as a builder script") { |line|
25
- options[:builder] = line
26
- }
27
-
28
26
  opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") {
29
27
  options[:debug] = true
30
28
  }
@@ -42,12 +40,16 @@ module Rack
42
40
 
43
41
  opts.on("-r", "--require LIBRARY",
44
42
  "require the library, before executing your script") { |library|
45
- options[:require] = library
43
+ (options[:require] ||= []) << library
46
44
  }
47
45
 
48
46
  opts.separator ""
49
47
  opts.separator "Rack options:"
50
- opts.on("-s", "--server SERVER", "serve using SERVER (thin/puma/webrick/mongrel)") { |s|
48
+ opts.on("-b", "--builder BUILDER_LINE", "evaluate a BUILDER_LINE of code as a builder script") { |line|
49
+ options[:builder] = line
50
+ }
51
+
52
+ opts.on("-s", "--server SERVER", "serve using SERVER (thin/puma/webrick)") { |s|
51
53
  options[:server] = s
52
54
  }
53
55
 
@@ -77,6 +79,24 @@ module Rack
77
79
  options[:pid] = ::File.expand_path(f)
78
80
  }
79
81
 
82
+ opts.separator ""
83
+ opts.separator "Profiling options:"
84
+
85
+ opts.on("--heap HEAPFILE", "Build the application, then dump the heap to HEAPFILE") do |e|
86
+ options[:heapfile] = e
87
+ end
88
+
89
+ opts.on("--profile PROFILE", "Dump CPU or Memory profile to PROFILE (defaults to a tempfile)") do |e|
90
+ options[:profile_file] = e
91
+ end
92
+
93
+ opts.on("--profile-mode MODE", "Profile mode (cpu|wall|object)") do |e|
94
+ { cpu: true, wall: true, object: true }.fetch(e.to_sym) do
95
+ raise OptionParser::InvalidOption, "unknown profile mode: #{e}"
96
+ end
97
+ options[:profile_mode] = e.to_sym
98
+ end
99
+
80
100
  opts.separator ""
81
101
  opts.separator "Common options:"
82
102
 
@@ -100,28 +120,28 @@ module Rack
100
120
  abort opt_parser.to_s
101
121
  end
102
122
 
103
- options[:config] = args.last if args.last
123
+ options[:config] = args.last if args.last && !args.last.empty?
104
124
  options
105
125
  end
106
126
 
107
127
  def handler_opts(options)
108
128
  begin
109
129
  info = []
110
- server = Rack::Handler.get(options[:server]) || Rack::Handler.default(options)
130
+ server = Rack::Handler.get(options[:server]) || Rack::Handler.default
111
131
  if server && server.respond_to?(:valid_options)
112
132
  info << ""
113
133
  info << "Server-specific options for #{server.name}:"
114
134
 
115
135
  has_options = false
116
136
  server.valid_options.each do |name, description|
117
- next if name.to_s.match(/^(Host|Port)[^a-zA-Z]/) # ignore handler's host and port options, we do our own.
137
+ next if /^(Host|Port)[^a-zA-Z]/.match?(name.to_s) # ignore handler's host and port options, we do our own.
118
138
  info << " -O %-21s %s" % [name, description]
119
139
  has_options = true
120
140
  end
121
141
  return "" if !has_options
122
142
  end
123
143
  info.join("\n")
124
- rescue NameError
144
+ rescue NameError, LoadError
125
145
  return "Warning: Could not find handler specified (#{options[:server] || 'default'}) to determine handler-specific options"
126
146
  end
127
147
  end
@@ -152,7 +172,9 @@ module Rack
152
172
 
153
173
  # Options may include:
154
174
  # * :app
155
- # a rack application to run (overrides :config)
175
+ # a rack application to run (overrides :config and :builder)
176
+ # * :builder
177
+ # a string to evaluate a Rack::Builder from
156
178
  # * :config
157
179
  # a rackup configuration file path to load (.ru)
158
180
  # * :environment
@@ -182,13 +204,31 @@ module Rack
182
204
  # add given paths to $LOAD_PATH
183
205
  # * :require
184
206
  # require the given libraries
207
+ #
208
+ # Additional options for profiling app initialization include:
209
+ # * :heapfile
210
+ # location for ObjectSpace.dump_all to write the output to
211
+ # * :profile_file
212
+ # location for CPU/Memory (StackProf) profile output (defaults to a tempfile)
213
+ # * :profile_mode
214
+ # StackProf profile mode (cpu|wall|object)
185
215
  def initialize(options = nil)
186
- @options = options
187
- @app = options[:app] if options && options[:app]
216
+ @ignore_options = []
217
+
218
+ if options
219
+ @use_default_options = false
220
+ @options = options
221
+ @app = options[:app] if options[:app]
222
+ else
223
+ argv = defined?(SPEC_ARGV) ? SPEC_ARGV : ARGV
224
+ @use_default_options = true
225
+ @options = parse_options(argv)
226
+ end
188
227
  end
189
228
 
190
229
  def options
191
- @options ||= parse_options(ARGV)
230
+ merged_options = @use_default_options ? default_options.merge(@options) : @options
231
+ merged_options.reject { |k, v| @ignore_options.include?(k) }
192
232
  end
193
233
 
194
234
  def default_options
@@ -196,12 +236,12 @@ module Rack
196
236
  default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
197
237
 
198
238
  {
199
- :environment => environment,
200
- :pid => nil,
201
- :Port => 9292,
202
- :Host => default_host,
203
- :AccessLog => [],
204
- :config => "config.ru"
239
+ environment: environment,
240
+ pid: nil,
241
+ Port: 9292,
242
+ Host: default_host,
243
+ AccessLog: [],
244
+ config: "config.ru"
205
245
  }
206
246
  end
207
247
 
@@ -212,21 +252,19 @@ module Rack
212
252
  class << self
213
253
  def logging_middleware
214
254
  lambda { |server|
215
- server.server.name =~ /CGI/ || server.options[:quiet] ? nil : [Rack::CommonLogger, $stderr]
255
+ /CGI/.match?(server.server.name) || server.options[:quiet] ? nil : [Rack::CommonLogger, $stderr]
216
256
  }
217
257
  end
218
258
 
219
259
  def default_middleware_by_environment
220
- m = Hash.new {|h,k| h[k] = []}
260
+ m = Hash.new {|h, k| h[k] = []}
221
261
  m["deployment"] = [
222
262
  [Rack::ContentLength],
223
- [Rack::Chunked],
224
263
  logging_middleware,
225
264
  [Rack::TempfileReaper]
226
265
  ]
227
266
  m["development"] = [
228
267
  [Rack::ContentLength],
229
- [Rack::Chunked],
230
268
  logging_middleware,
231
269
  [Rack::ShowExceptions],
232
270
  [Rack::Lint],
@@ -245,7 +283,7 @@ module Rack
245
283
  self.class.middleware
246
284
  end
247
285
 
248
- def start &blk
286
+ def start(&block)
249
287
  if options[:warn]
250
288
  $-w = true
251
289
  end
@@ -254,7 +292,7 @@ module Rack
254
292
  $LOAD_PATH.unshift(*includes)
255
293
  end
256
294
 
257
- if library = options[:require]
295
+ Array(options[:require]).each do |library|
258
296
  require library
259
297
  end
260
298
 
@@ -270,7 +308,9 @@ module Rack
270
308
 
271
309
  # Touch the wrapped app, so that the config.ru is loaded before
272
310
  # daemonization (i.e. before chdir, etc).
273
- wrapped_app
311
+ handle_profiling(options[:heapfile], options[:profile_mode], options[:profile_file]) do
312
+ wrapped_app
313
+ end
274
314
 
275
315
  daemonize_app if options[:daemonize]
276
316
 
@@ -284,11 +324,20 @@ module Rack
284
324
  end
285
325
  end
286
326
 
287
- server.run wrapped_app, options, &blk
327
+ server.run(wrapped_app, **options, &block)
288
328
  end
289
329
 
290
330
  def server
291
- @_server ||= Rack::Handler.get(options[:server]) || Rack::Handler.default(options)
331
+ @_server ||= Rack::Handler.get(options[:server])
332
+
333
+ unless @_server
334
+ @_server = Rack::Handler.default
335
+
336
+ # We already speak FastCGI
337
+ @ignore_options = [:File, :Port] if @_server.to_s == 'Rack::Handler::FastCGI'
338
+ end
339
+
340
+ @_server
292
341
  end
293
342
 
294
343
  private
@@ -298,25 +347,61 @@ module Rack
298
347
  end
299
348
 
300
349
  app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
301
- self.options.merge! options
350
+ @options.merge!(options) { |key, old, new| old }
302
351
  app
303
352
  end
304
353
 
354
+ def handle_profiling(heapfile, profile_mode, filename)
355
+ if heapfile
356
+ require "objspace"
357
+ ObjectSpace.trace_object_allocations_start
358
+ yield
359
+ GC.start
360
+ ::File.open(heapfile, "w") { |f| ObjectSpace.dump_all(output: f) }
361
+ exit
362
+ end
363
+
364
+ if profile_mode
365
+ require "stackprof"
366
+ require "tempfile"
367
+
368
+ make_profile_name(filename) do |filename|
369
+ ::File.open(filename, "w") do |f|
370
+ StackProf.run(mode: profile_mode, out: f) do
371
+ yield
372
+ end
373
+ puts "Profile written to: #{filename}"
374
+ end
375
+ end
376
+ exit
377
+ end
378
+
379
+ yield
380
+ end
381
+
382
+ def make_profile_name(filename)
383
+ if filename
384
+ yield filename
385
+ else
386
+ ::Dir::Tmpname.create("profile.dump") do |tmpname, _, _|
387
+ yield tmpname
388
+ end
389
+ end
390
+ end
391
+
305
392
  def build_app_from_string
306
393
  Rack::Builder.new_from_string(self.options[:builder])
307
394
  end
308
395
 
309
396
  def parse_options(args)
310
- options = default_options
311
-
312
397
  # Don't evaluate CGI ISINDEX parameters.
313
398
  # http://www.meb.uni-bonn.de/docs/cgi/cl.html
314
399
  args.clear if ENV.include?(REQUEST_METHOD)
315
400
 
316
- options.merge! opt_parser.parse!(args)
317
- options[:config] = ::File.expand_path(options[:config])
401
+ @options = opt_parser.parse!(args)
402
+ @options[:config] = ::File.expand_path(options[:config])
318
403
  ENV["RACK_ENV"] = options[:environment]
319
- options
404
+ @options
320
405
  end
321
406
 
322
407
  def opt_parser
@@ -338,17 +423,10 @@ module Rack
338
423
  end
339
424
 
340
425
  def daemonize_app
341
- if RUBY_VERSION < "1.9"
342
- exit if fork
343
- Process.setsid
344
- exit if fork
345
- Dir.chdir "/"
346
- STDIN.reopen "/dev/null"
347
- STDOUT.reopen "/dev/null", "a"
348
- STDERR.reopen "/dev/null", "a"
349
- else
350
- Process.daemon
351
- end
426
+ # Cannot be covered as it forks
427
+ # :nocov:
428
+ Process.daemon
429
+ # :nocov:
352
430
  end
353
431
 
354
432
  def write_pid