rack 3.1.18 → 3.2.0

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.

data/lib/rack/sendfile.rb CHANGED
@@ -16,21 +16,21 @@ module Rack
16
16
  # delivery code.
17
17
  #
18
18
  # In order to take advantage of this middleware, the response body must
19
- # respond to +to_path+ and the request must include an `x-sendfile-type`
19
+ # respond to +to_path+ and the request must include an x-sendfile-type
20
20
  # header. Rack::Files and other components implement +to_path+ so there's
21
- # rarely anything you need to do in your application. The `x-sendfile-type`
21
+ # rarely anything you need to do in your application. The x-sendfile-type
22
22
  # header is typically set in your web servers configuration. The following
23
23
  # sections attempt to document
24
24
  #
25
25
  # === Nginx
26
26
  #
27
- # Nginx supports the `x-accel-redirect` header. This is similar to `x-sendfile`
27
+ # Nginx supports the x-accel-redirect header. This is similar to x-sendfile
28
28
  # but requires parts of the filesystem to be mapped into a private URL
29
29
  # hierarchy.
30
30
  #
31
31
  # The following example shows the Nginx configuration required to create
32
- # a private "/files/" area, enable `x-accel-redirect`, and pass the special
33
- # `x-accel-mapping` header to the backend:
32
+ # a private "/files/" area, enable x-accel-redirect, and pass the special
33
+ # x-sendfile-type and x-accel-mapping headers to the backend:
34
34
  #
35
35
  # location ~ /files/(.*) {
36
36
  # internal;
@@ -44,29 +44,24 @@ module Rack
44
44
  # proxy_set_header X-Real-IP $remote_addr;
45
45
  # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
46
46
  #
47
+ # proxy_set_header x-sendfile-type x-accel-redirect;
47
48
  # proxy_set_header x-accel-mapping /var/www/=/files/;
48
49
  #
49
50
  # proxy_pass http://127.0.0.1:8080/;
50
51
  # }
51
52
  #
52
- # The `x-accel-mapping` header should specify the location on the file system,
53
+ # Note that the x-sendfile-type header must be set exactly as shown above.
54
+ # The x-accel-mapping header should specify the location on the file system,
53
55
  # followed by an equals sign (=), followed name of the private URL pattern
54
56
  # that it maps to. The middleware performs a simple substitution on the
55
57
  # resulting path.
56
58
  #
57
- # To enable `x-accel-redirect`, you must configure the middleware explicitly:
58
- #
59
- # use Rack::Sendfile, "x-accel-redirect"
60
- #
61
- # For security reasons, the `x-sendfile-type` header from requests is ignored.
62
- # The sendfile variation must be set via the middleware constructor.
63
- #
64
59
  # See Also: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile
65
60
  #
66
61
  # === lighttpd
67
62
  #
68
- # Lighttpd has supported some variation of the `x-sendfile` header for some
69
- # time, although only recent version support `x-sendfile` in a reverse proxy
63
+ # Lighttpd has supported some variation of the x-sendfile header for some
64
+ # time, although only recent version support x-sendfile in a reverse proxy
70
65
  # configuration.
71
66
  #
72
67
  # $HTTP["host"] == "example.com" {
@@ -88,7 +83,7 @@ module Rack
88
83
  #
89
84
  # === Apache
90
85
  #
91
- # `x-sendfile` is supported under Apache 2.x using a separate module:
86
+ # x-sendfile is supported under Apache 2.x using a separate module:
92
87
  #
93
88
  # https://tn123.org/mod_xsendfile/
94
89
  #
@@ -102,28 +97,16 @@ module Rack
102
97
  # === Mapping parameter
103
98
  #
104
99
  # The third parameter allows for an overriding extension of the
105
- # `x-accel-mapping` header. Mappings should be provided in tuples of internal to
100
+ # x-accel-mapping header. Mappings should be provided in tuples of internal to
106
101
  # external. The internal values may contain regular expression syntax, they
107
102
  # will be matched with case indifference.
108
- #
109
- # When `x-accel-redirect` is explicitly enabled via the variation parameter,
110
- # and no application-level mappings are provided, the middleware will read
111
- # the `x-accel-mapping` header from the proxy. This allows nginx to control
112
- # the path mapping without requiring application-level configuration.
113
- #
114
- # === Security
115
- #
116
- # For security reasons, the `x-sendfile-type` header from HTTP requests is
117
- # ignored. The sendfile variation must be explicitly configured via the
118
- # middleware constructor to prevent information disclosure vulnerabilities
119
- # where attackers could bypass proxy restrictions.
120
103
 
121
104
  class Sendfile
122
105
  def initialize(app, variation = nil, mappings = [])
123
106
  @app = app
124
107
  @variation = variation
125
108
  @mappings = mappings.map do |internal, external|
126
- [/\A#{internal}/i, external]
109
+ [/^#{internal}/i, external]
127
110
  end
128
111
  end
129
112
 
@@ -162,35 +145,22 @@ module Rack
162
145
  end
163
146
 
164
147
  private
165
-
166
148
  def variation(env)
167
- # Note: HTTP_X_SENDFILE_TYPE is intentionally NOT read for security reasons.
168
- # Attackers could use this header to enable x-accel-redirect and bypass proxy restrictions.
169
- @variation || env['sendfile.type']
170
- end
171
-
172
- def x_accel_mapping(env)
173
- # Only allow header when:
174
- # 1. `x-accel-redirect` is explicitly enabled via constructor.
175
- # 2. No application-level mappings are configured.
176
- return nil unless @variation =~ /x-accel-redirect/i
177
- return nil if @mappings.any?
178
-
179
- env['HTTP_X_ACCEL_MAPPING']
149
+ @variation ||
150
+ env['sendfile.type'] ||
151
+ env['HTTP_X_SENDFILE_TYPE']
180
152
  end
181
153
 
182
154
  def map_accel_path(env, path)
183
155
  if mapping = @mappings.find { |internal, _| internal =~ path }
184
- return path.sub(*mapping)
185
- elsif mapping = x_accel_mapping(env)
186
- # Safe to use header: explicit config + no app mappings:
156
+ path.sub(*mapping)
157
+ elsif mapping = env['HTTP_X_ACCEL_MAPPING']
187
158
  mapping.split(',').map(&:strip).each do |m|
188
159
  internal, external = m.split('=', 2).map(&:strip)
189
- new_path = path.sub(/\A#{internal}/i, external)
160
+ new_path = path.sub(/^#{internal}/i, external)
190
161
  return new_path unless path == new_path
191
162
  end
192
-
193
- return path
163
+ path
194
164
  end
195
165
  end
196
166
  end
@@ -65,8 +65,12 @@ module Rack
65
65
  def dump_exception(exception)
66
66
  if exception.respond_to?(:detailed_message)
67
67
  message = exception.detailed_message(highlight: false)
68
+ # :nocov:
69
+ # Ruby 3.2 added Exception#detailed_message, so the else
70
+ # branch cannot be hit on the current Ruby version.
68
71
  else
69
72
  message = exception.message
73
+ # :nocov:
70
74
  end
71
75
  string = "#{exception.class}: #{message}\n".dup
72
76
  string << exception.backtrace.map { |l| "\t#{l}" }.join("\n")
@@ -401,7 +405,5 @@ module Rack
401
405
  </body>
402
406
  </html>
403
407
  HTML
404
-
405
- # :startdoc:
406
408
  end
407
409
  end
@@ -117,7 +117,5 @@ TEMPLATE = <<'HTML'
117
117
  </body>
118
118
  </html>
119
119
  HTML
120
-
121
- # :startdoc:
122
120
  end
123
121
  end
data/lib/rack/utils.rb CHANGED
@@ -181,12 +181,16 @@ module Rack
181
181
  # doesn't get monkey-patched by rails
182
182
  if defined?(ERB::Escape) && ERB::Escape.instance_method(:html_escape)
183
183
  define_method(:escape_html, ERB::Escape.instance_method(:html_escape))
184
+ # :nocov:
185
+ # Ruby 3.2/ERB 4.0 added ERB::Escape#html_escape, so the else
186
+ # branch cannot be hit on the current Ruby version.
184
187
  else
185
188
  require 'cgi/escape'
186
189
  # Escape ampersands, brackets and quotes to their HTML/XML entities.
187
190
  def escape_html(string)
188
191
  CGI.escapeHTML(string.to_s)
189
192
  end
193
+ # :nocov:
190
194
  end
191
195
 
192
196
  def select_best_encoding(available_encodings, accept_encoding)
@@ -254,26 +258,18 @@ module Rack
254
258
  parse_cookies_header env[HTTP_COOKIE]
255
259
  end
256
260
 
257
- # A valid cookie key according to RFC2616.
261
+ # A valid cookie key according to RFC6265 and RFC2616.
258
262
  # A <cookie-name> can be any US-ASCII characters, except control characters, spaces, or tabs. It also must not contain a separator character like the following: ( ) < > @ , ; : \ " / [ ] ? = { }.
259
263
  VALID_COOKIE_KEY = /\A[!#$%&'*+\-\.\^_`|~0-9a-zA-Z]+\z/.freeze
260
264
  private_constant :VALID_COOKIE_KEY
261
265
 
262
- private def escape_cookie_key(key)
263
- if key =~ VALID_COOKIE_KEY
264
- key
265
- else
266
- warn "Cookie key #{key.inspect} is not valid according to RFC2616; it will be escaped. This behaviour is deprecated and will be removed in a future version of Rack.", uplevel: 2
267
- escape(key)
268
- end
269
- end
270
-
271
266
  # :call-seq:
272
267
  # set_cookie_header(key, value) -> encoded string
273
268
  #
274
269
  # Generate an encoded string using the provided +key+ and +value+ suitable
275
270
  # for the +set-cookie+ header according to RFC6265. The +value+ may be an
276
- # instance of either +String+ or +Hash+.
271
+ # instance of either +String+ or +Hash+. If the cookie key is invalid (as
272
+ # defined by RFC6265), an +ArgumentError+ will be raised.
277
273
  #
278
274
  # If the cookie +value+ is an instance of +Hash+, it considers the following
279
275
  # cookie attribute keys: +domain+, +max_age+, +expires+ (must be instance
@@ -281,10 +277,6 @@ module Rack
281
277
  # details about the interpretation of these fields, consult
282
278
  # [RFC6265 Section 5.2](https://datatracker.ietf.org/doc/html/rfc6265#section-5.2).
283
279
  #
284
- # An extra cookie attribute +escape_key+ can be provided to control whether
285
- # or not the cookie key is URL encoded. If explicitly set to +false+, the
286
- # cookie key name will not be url encoded (escaped). The default is +true+.
287
- #
288
280
  # set_cookie_header("myname", "myvalue")
289
281
  # # => "myname=myvalue"
290
282
  #
@@ -292,9 +284,12 @@ module Rack
292
284
  # # => "myname=myvalue; max-age=10"
293
285
  #
294
286
  def set_cookie_header(key, value)
287
+ unless key =~ VALID_COOKIE_KEY
288
+ raise ArgumentError, "invalid cookie key: #{key.inspect}"
289
+ end
290
+
295
291
  case value
296
292
  when Hash
297
- key = escape_cookie_key(key) unless value[:escape_key] == false
298
293
  domain = "; domain=#{value[:domain]}" if value[:domain]
299
294
  path = "; path=#{value[:path]}" if value[:path]
300
295
  max_age = "; max-age=#{value[:max_age]}" if value[:max_age]
@@ -316,8 +311,6 @@ module Rack
316
311
  end
317
312
  partitioned = "; partitioned" if value[:partitioned]
318
313
  value = value[:value]
319
- else
320
- key = escape_cookie_key(key)
321
314
  end
322
315
 
323
316
  value = [value] unless Array === value
@@ -416,7 +409,7 @@ module Rack
416
409
  return nil if size.zero?
417
410
  return nil unless http_range && http_range =~ /bytes=([^;]+)/
418
411
  ranges = []
419
- $1.split(/,\s*/).each do |range_spec|
412
+ $1.split(/,[ \t]*/).each do |range_spec|
420
413
  return nil unless range_spec.include?('-')
421
414
  range = range_spec.split('-')
422
415
  r0, r1 = range[0], range[1]
@@ -592,11 +585,9 @@ module Rack
592
585
  fallback_code = OBSOLETE_SYMBOLS_TO_STATUS_CODES.fetch(status) { raise ArgumentError, "Unrecognized status code #{status.inspect}" }
593
586
  message = "Status code #{status.inspect} is deprecated and will be removed in a future version of Rack."
594
587
  if canonical_symbol = OBSOLETE_SYMBOL_MAPPINGS[status]
595
- # message = "#{message} Please use #{canonical_symbol.inspect} instead."
596
- # For now, let's not emit any warning when there is a mapping.
597
- else
598
- warn message, uplevel: 3
588
+ message = "#{message} Please use #{canonical_symbol.inspect} instead."
599
589
  end
590
+ warn message, uplevel: 3
600
591
  fallback_code
601
592
  end
602
593
  else
data/lib/rack/version.rb CHANGED
@@ -5,17 +5,13 @@
5
5
  # Rack is freely distributable under the terms of an MIT-style license.
6
6
  # See MIT-LICENSE or https://opensource.org/licenses/MIT.
7
7
 
8
- # The Rack main module, serving as a namespace for all core Rack
9
- # modules and classes.
10
- #
11
- # All modules meant for use in your application are <tt>autoload</tt>ed here,
12
- # so it should be enough just to <tt>require 'rack'</tt> in your code.
13
-
14
8
  module Rack
15
- RELEASE = "3.1.18"
9
+ VERSION = "3.2.0"
10
+
11
+ RELEASE = VERSION
16
12
 
17
13
  # Return the Rack release as a dotted string.
18
14
  def self.release
19
- RELEASE
15
+ VERSION
20
16
  end
21
17
  end
data/lib/rack.rb CHANGED
@@ -34,7 +34,6 @@ module Rack
34
34
  autoload :Headers, "rack/headers"
35
35
  autoload :Lint, "rack/lint"
36
36
  autoload :Lock, "rack/lock"
37
- autoload :Logger, "rack/logger"
38
37
  autoload :MediaType, "rack/media_type"
39
38
  autoload :MethodOverride, "rack/method_override"
40
39
  autoload :Mime, "rack/mime"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.18
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leah Neukirchen
@@ -107,7 +107,6 @@ files:
107
107
  - lib/rack/headers.rb
108
108
  - lib/rack/lint.rb
109
109
  - lib/rack/lock.rb
110
- - lib/rack/logger.rb
111
110
  - lib/rack/media_type.rb
112
111
  - lib/rack/method_override.rb
113
112
  - lib/rack/mime.rb
@@ -142,6 +141,7 @@ metadata:
142
141
  changelog_uri: https://github.com/rack/rack/blob/main/CHANGELOG.md
143
142
  documentation_uri: https://rubydoc.info/github/rack/rack
144
143
  source_code_uri: https://github.com/rack/rack
144
+ rubygems_mfa_required: 'true'
145
145
  rdoc_options: []
146
146
  require_paths:
147
147
  - lib
@@ -156,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
156
156
  - !ruby/object:Gem::Version
157
157
  version: '0'
158
158
  requirements: []
159
- rubygems_version: 3.6.9
159
+ rubygems_version: 3.6.7
160
160
  specification_version: 4
161
161
  summary: A modular Ruby webserver interface.
162
162
  test_files: []
data/lib/rack/logger.rb DELETED
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'logger'
4
- require_relative 'constants'
5
-
6
- warn "Rack::Logger is deprecated and will be removed in Rack 3.2.", uplevel: 1
7
-
8
- module Rack
9
- # Sets up rack.logger to write to rack.errors stream
10
- class Logger
11
- def initialize(app, level = ::Logger::INFO)
12
- @app, @level = app, level
13
- end
14
-
15
- def call(env)
16
- logger = ::Logger.new(env[RACK_ERRORS])
17
- logger.level = @level
18
-
19
- env[RACK_LOGGER] = logger
20
- @app.call(env)
21
- end
22
- end
23
- end