rack 2.2.20 → 3.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +134 -161
  3. data/CONTRIBUTING.md +53 -47
  4. data/MIT-LICENSE +1 -1
  5. data/README.md +287 -0
  6. data/Rakefile +40 -7
  7. data/SPEC.rdoc +166 -125
  8. data/contrib/LICENSE.md +7 -0
  9. data/contrib/logo.webp +0 -0
  10. data/lib/rack/auth/abstract/handler.rb +3 -1
  11. data/lib/rack/auth/abstract/request.rb +3 -1
  12. data/lib/rack/auth/basic.rb +2 -1
  13. data/lib/rack/auth/digest/md5.rb +1 -131
  14. data/lib/rack/auth/digest/nonce.rb +1 -53
  15. data/lib/rack/auth/digest/params.rb +1 -54
  16. data/lib/rack/auth/digest/request.rb +1 -43
  17. data/lib/rack/auth/digest.rb +256 -0
  18. data/lib/rack/body_proxy.rb +3 -1
  19. data/lib/rack/builder.rb +60 -42
  20. data/lib/rack/cascade.rb +2 -0
  21. data/lib/rack/chunked.rb +16 -13
  22. data/lib/rack/common_logger.rb +24 -20
  23. data/lib/rack/conditional_get.rb +18 -15
  24. data/lib/rack/constants.rb +62 -0
  25. data/lib/rack/content_length.rb +12 -16
  26. data/lib/rack/content_type.rb +8 -5
  27. data/lib/rack/deflater.rb +40 -26
  28. data/lib/rack/directory.rb +9 -3
  29. data/lib/rack/etag.rb +14 -23
  30. data/lib/rack/events.rb +4 -0
  31. data/lib/rack/file.rb +2 -0
  32. data/lib/rack/files.rb +15 -17
  33. data/lib/rack/head.rb +9 -8
  34. data/lib/rack/headers.rb +154 -0
  35. data/lib/rack/lint.rb +740 -649
  36. data/lib/rack/lock.rb +2 -5
  37. data/lib/rack/logger.rb +2 -0
  38. data/lib/rack/media_type.rb +7 -17
  39. data/lib/rack/method_override.rb +5 -1
  40. data/lib/rack/mime.rb +8 -0
  41. data/lib/rack/mock.rb +1 -300
  42. data/lib/rack/mock_request.rb +166 -0
  43. data/lib/rack/mock_response.rb +124 -0
  44. data/lib/rack/multipart/generator.rb +7 -5
  45. data/lib/rack/multipart/parser.rb +121 -139
  46. data/lib/rack/multipart/uploaded_file.rb +4 -0
  47. data/lib/rack/multipart.rb +20 -40
  48. data/lib/rack/null_logger.rb +9 -0
  49. data/lib/rack/query_parser.rb +78 -91
  50. data/lib/rack/recursive.rb +2 -0
  51. data/lib/rack/reloader.rb +0 -2
  52. data/lib/rack/request.rb +190 -95
  53. data/lib/rack/response.rb +131 -61
  54. data/lib/rack/rewindable_input.rb +24 -5
  55. data/lib/rack/runtime.rb +7 -6
  56. data/lib/rack/sendfile.rb +39 -64
  57. data/lib/rack/show_exceptions.rb +15 -2
  58. data/lib/rack/show_status.rb +17 -7
  59. data/lib/rack/static.rb +9 -10
  60. data/lib/rack/tempfile_reaper.rb +15 -4
  61. data/lib/rack/urlmap.rb +4 -2
  62. data/lib/rack/utils.rb +212 -202
  63. data/lib/rack/version.rb +9 -4
  64. data/lib/rack.rb +5 -76
  65. data/rack.gemspec +6 -6
  66. metadata +22 -31
  67. data/README.rdoc +0 -355
  68. data/bin/rackup +0 -5
  69. data/contrib/rack.png +0 -0
  70. data/contrib/rack.svg +0 -150
  71. data/contrib/rack_logo.svg +0 -164
  72. data/lib/rack/core_ext/regexp.rb +0 -14
  73. data/lib/rack/handler/cgi.rb +0 -59
  74. data/lib/rack/handler/fastcgi.rb +0 -100
  75. data/lib/rack/handler/lsws.rb +0 -61
  76. data/lib/rack/handler/scgi.rb +0 -71
  77. data/lib/rack/handler/thin.rb +0 -34
  78. data/lib/rack/handler/webrick.rb +0 -129
  79. data/lib/rack/handler.rb +0 -104
  80. data/lib/rack/lobster.rb +0 -70
  81. data/lib/rack/server.rb +0 -466
  82. data/lib/rack/session/abstract/id.rb +0 -523
  83. data/lib/rack/session/cookie.rb +0 -203
  84. data/lib/rack/session/memcache.rb +0 -10
  85. data/lib/rack/session/pool.rb +0 -90
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'constants'
4
+
3
5
  module Rack
4
6
  class NullLogger
5
7
  def initialize(app)
@@ -22,6 +24,11 @@ module Rack
22
24
  def warn? ; end
23
25
  def error? ; end
24
26
  def fatal? ; end
27
+ def debug! ; end
28
+ def error! ; end
29
+ def fatal! ; end
30
+ def info! ; end
31
+ def warn! ; end
25
32
  def level ; end
26
33
  def progname ; end
27
34
  def datetime_format ; end
@@ -34,6 +41,8 @@ module Rack
34
41
  def sev_threshold=(sev_threshold); end
35
42
  def close ; end
36
43
  def add(severity, message = nil, progname = nil, &block); end
44
+ def log(severity, message = nil, progname = nil, &block); end
37
45
  def <<(msg); end
46
+ def reopen(logdev = nil); end
38
47
  end
39
48
  end
@@ -2,9 +2,7 @@
2
2
 
3
3
  module Rack
4
4
  class QueryParser
5
- (require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4'
6
-
7
- DEFAULT_SEP = /[&;] */n
5
+ DEFAULT_SEP = /[&] */n
8
6
  COMMON_SEP = { ";" => /[;] */n, ";," => /[;,] */n, "&" => /[&] */n }
9
7
 
10
8
  # ParameterTypeError is the error that is raised when incoming structural
@@ -16,62 +14,39 @@ module Rack
16
14
  # sequence.
17
15
  class InvalidParameterError < ArgumentError; end
18
16
 
19
- # QueryLimitError is for errors raised when the query provided exceeds one
20
- # of the query parser limits.
21
- class QueryLimitError < RangeError
22
- end
23
-
24
- # ParamsTooDeepError is the old name for the error that is raised when params
25
- # are recursively nested over the specified limit. Make it the same as
26
- # as QueryLimitError, so that code that rescues ParamsTooDeepError error
27
- # to handle bad query strings also now handles other limits.
28
- ParamsTooDeepError = QueryLimitError
17
+ # ParamsTooDeepError is the error that is raised when params are recursively
18
+ # nested over the specified limit.
19
+ class ParamsTooDeepError < RangeError; end
29
20
 
30
- def self.make_default(key_space_limit, param_depth_limit, **options)
31
- new(Params, key_space_limit, param_depth_limit, **options)
32
- end
33
-
34
- attr_reader :key_space_limit, :param_depth_limit
35
-
36
- env_int = lambda do |key, val|
37
- if str_val = ENV[key]
38
- begin
39
- val = Integer(str_val, 10)
40
- rescue ArgumentError
41
- raise ArgumentError, "non-integer value provided for environment variable #{key}"
42
- end
21
+ def self.make_default(_key_space_limit=(not_deprecated = true; nil), param_depth_limit)
22
+ unless not_deprecated
23
+ warn("`first argument `key_space limit` is deprecated and no longer has an effect. Please call with only one argument, which will be required in a future version of Rack", uplevel: 1)
43
24
  end
44
25
 
45
- val
26
+ new Params, param_depth_limit
46
27
  end
47
28
 
48
- BYTESIZE_LIMIT = env_int.call("RACK_QUERY_PARSER_BYTESIZE_LIMIT", 4194304)
49
- private_constant :BYTESIZE_LIMIT
29
+ attr_reader :param_depth_limit
50
30
 
51
- PARAMS_LIMIT = env_int.call("RACK_QUERY_PARSER_PARAMS_LIMIT", 4096)
52
- private_constant :PARAMS_LIMIT
53
-
54
- attr_reader :bytesize_limit
31
+ def initialize(params_class, _key_space_limit=(not_deprecated = true; nil), param_depth_limit)
32
+ unless not_deprecated
33
+ warn("`second argument `key_space limit` is deprecated and no longer has an effect. Please call with only two arguments, which will be required in a future version of Rack", uplevel: 1)
34
+ end
55
35
 
56
- def initialize(params_class, key_space_limit, param_depth_limit, bytesize_limit: BYTESIZE_LIMIT, params_limit: PARAMS_LIMIT)
57
36
  @params_class = params_class
58
- @key_space_limit = key_space_limit
59
37
  @param_depth_limit = param_depth_limit
60
- @bytesize_limit = bytesize_limit
61
- @params_limit = params_limit
62
38
  end
63
39
 
64
40
  # Stolen from Mongrel, with some small modifications:
65
- # Parses a query string by breaking it up at the '&'
66
- # and ';' characters. You can also use this to parse
67
- # cookies by changing the characters used in the second
68
- # parameter (which defaults to '&;').
69
- def parse_query(qs, d = nil, &unescaper)
41
+ # Parses a query string by breaking it up at the '&'. You can also use this
42
+ # to parse cookies by changing the characters used in the second parameter
43
+ # (which defaults to '&').
44
+ def parse_query(qs, separator = nil, &unescaper)
70
45
  unescaper ||= method(:unescape)
71
46
 
72
47
  params = make_params
73
48
 
74
- check_query_string(qs, d).split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
49
+ (qs || '').split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p|
75
50
  next if p.empty?
76
51
  k, v = p.split('=', 2).map!(&unescaper)
77
52
 
@@ -94,14 +69,14 @@ module Rack
94
69
  # query strings with parameters of conflicting types, in this case a
95
70
  # ParameterTypeError is raised. Users are encouraged to return a 400 in this
96
71
  # case.
97
- def parse_nested_query(qs, d = nil)
72
+ def parse_nested_query(qs, separator = nil)
98
73
  params = make_params
99
74
 
100
75
  unless qs.nil? || qs.empty?
101
- check_query_string(qs, d).split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
76
+ (qs || '').split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p|
102
77
  k, v = p.split('=', 2).map! { |s| unescape(s) }
103
78
 
104
- normalize_params(params, k, v, param_depth_limit)
79
+ _normalize_params(params, k, v, 0)
105
80
  end
106
81
  end
107
82
 
@@ -112,58 +87,89 @@ module Rack
112
87
 
113
88
  # normalize_params recursively expands parameters into structural types. If
114
89
  # the structural types represented by two different parameter names are in
115
- # conflict, a ParameterTypeError is raised.
116
- def normalize_params(params, name, v, depth)
117
- raise ParamsTooDeepError if depth <= 0
118
-
119
- name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
120
- k = $1 || ''
121
- after = $' || ''
90
+ # conflict, a ParameterTypeError is raised. The depth argument is deprecated
91
+ # and should no longer be used, it is kept for backwards compatibility with
92
+ # earlier versions of rack.
93
+ def normalize_params(params, name, v, _depth=nil)
94
+ _normalize_params(params, name, v, 0)
95
+ end
122
96
 
123
- if k.empty?
124
- if !v.nil? && name == "[]"
125
- return Array(v)
97
+ private def _normalize_params(params, name, v, depth)
98
+ raise ParamsTooDeepError if depth >= param_depth_limit
99
+
100
+ if !name
101
+ # nil name, treat same as empty string (required by tests)
102
+ k = after = ''
103
+ elsif depth == 0
104
+ # Start of parsing, don't treat [] or [ at start of string specially
105
+ if start = name.index('[', 1)
106
+ # Start of parameter nesting, use part before brackets as key
107
+ k = name[0, start]
108
+ after = name[start, name.length]
126
109
  else
127
- return
110
+ # Plain parameter with no nesting
111
+ k = name
112
+ after = ''
128
113
  end
114
+ elsif name.start_with?('[]')
115
+ # Array nesting
116
+ k = '[]'
117
+ after = name[2, name.length]
118
+ elsif name.start_with?('[') && (start = name.index(']', 1))
119
+ # Hash nesting, use the part inside brackets as the key
120
+ k = name[1, start-1]
121
+ after = name[start+1, name.length]
122
+ else
123
+ # Probably malformed input, nested but not starting with [
124
+ # treat full name as key for backwards compatibility.
125
+ k = name
126
+ after = ''
129
127
  end
130
128
 
129
+ return if k.empty?
130
+
131
+ v ||= String.new
132
+
131
133
  if after == ''
132
- params[k] = v
134
+ if k == '[]' && depth != 0
135
+ return [v]
136
+ else
137
+ params[k] = v
138
+ end
133
139
  elsif after == "["
134
140
  params[name] = v
135
141
  elsif after == "[]"
136
142
  params[k] ||= []
137
143
  raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
138
144
  params[k] << v
139
- elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
140
- child_key = $1
145
+ elsif after.start_with?('[]')
146
+ # Recognize x[][y] (hash inside array) parameters
147
+ unless after[2] == '[' && after.end_with?(']') && (child_key = after[3, after.length-4]) && !child_key.empty? && !child_key.index('[') && !child_key.index(']')
148
+ # Handle other nested array parameters
149
+ child_key = after[2, after.length]
150
+ end
141
151
  params[k] ||= []
142
152
  raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
143
153
  if params_hash_type?(params[k].last) && !params_hash_has_key?(params[k].last, child_key)
144
- normalize_params(params[k].last, child_key, v, depth - 1)
154
+ _normalize_params(params[k].last, child_key, v, depth + 1)
145
155
  else
146
- params[k] << normalize_params(make_params, child_key, v, depth - 1)
156
+ params[k] << _normalize_params(make_params, child_key, v, depth + 1)
147
157
  end
148
158
  else
149
159
  params[k] ||= make_params
150
160
  raise ParameterTypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k])
151
- params[k] = normalize_params(params[k], after, v, depth - 1)
161
+ params[k] = _normalize_params(params[k], after, v, depth + 1)
152
162
  end
153
163
 
154
164
  params
155
165
  end
156
166
 
157
167
  def make_params
158
- @params_class.new @key_space_limit
159
- end
160
-
161
- def new_space_limit(key_space_limit)
162
- self.class.new @params_class, key_space_limit, param_depth_limit
168
+ @params_class.new
163
169
  end
164
170
 
165
171
  def new_depth_limit(param_depth_limit)
166
- self.class.new @params_class, key_space_limit, param_depth_limit
172
+ self.class.new @params_class, param_depth_limit
167
173
  end
168
174
 
169
175
  private
@@ -184,29 +190,12 @@ module Rack
184
190
  true
185
191
  end
186
192
 
187
- def check_query_string(qs, sep)
188
- if qs
189
- if qs.bytesize > @bytesize_limit
190
- raise QueryLimitError, "total query size exceeds limit (#{@bytesize_limit})"
191
- end
192
-
193
- if (param_count = qs.count(sep.is_a?(String) ? sep : '&;')) >= @params_limit
194
- raise QueryLimitError, "total number of query parameters (#{param_count+1}) exceeds limit (#{@params_limit})"
195
- end
196
-
197
- qs
198
- else
199
- ''
200
- end
201
- end
202
-
203
- def unescape(string)
204
- Utils.unescape(string)
193
+ def unescape(s)
194
+ Utils.unescape(s)
205
195
  end
206
196
 
207
197
  class Params
208
- def initialize(limit)
209
- @limit = limit
198
+ def initialize
210
199
  @size = 0
211
200
  @params = {}
212
201
  end
@@ -216,8 +205,6 @@ module Rack
216
205
  end
217
206
 
218
207
  def []=(key, value)
219
- @size += key.size if key && !@params.key?(key)
220
- raise ParamsTooDeepError, 'exceeded available parameter key space' if @size > @limit
221
208
  @params[key] = value
222
209
  end
223
210
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'uri'
4
4
 
5
+ require_relative 'constants'
6
+
5
7
  module Rack
6
8
  # Rack::ForwardRequest gets caught by Rack::Recursive and redirects
7
9
  # the current request to the app at +url+.
data/lib/rack/reloader.rb CHANGED
@@ -22,8 +22,6 @@ module Rack
22
22
  # It is performing a check/reload cycle at the start of every request, but
23
23
  # also respects a cool down time, during which nothing will be done.
24
24
  class Reloader
25
- (require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4'
26
-
27
25
  def initialize(app, cooldown = 10, backend = Stat)
28
26
  @app = app
29
27
  @cooldown = cooldown