actionpack 7.2.3.2 → 8.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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +81 -195
  3. data/README.rdoc +1 -1
  4. data/lib/abstract_controller/base.rb +12 -1
  5. data/lib/abstract_controller/collector.rb +1 -1
  6. data/lib/abstract_controller/helpers.rb +1 -3
  7. data/lib/action_controller/metal/allow_browser.rb +1 -1
  8. data/lib/action_controller/metal/conditional_get.rb +5 -1
  9. data/lib/action_controller/metal/http_authentication.rb +4 -1
  10. data/lib/action_controller/metal/instrumentation.rb +1 -2
  11. data/lib/action_controller/metal/live.rb +11 -3
  12. data/lib/action_controller/metal/params_wrapper.rb +3 -3
  13. data/lib/action_controller/metal/rate_limiting.rb +13 -4
  14. data/lib/action_controller/metal/redirecting.rb +3 -4
  15. data/lib/action_controller/metal/renderers.rb +2 -1
  16. data/lib/action_controller/metal/rendering.rb +1 -1
  17. data/lib/action_controller/metal/request_forgery_protection.rb +1 -3
  18. data/lib/action_controller/metal/streaming.rb +5 -84
  19. data/lib/action_controller/metal/strong_parameters.rb +277 -73
  20. data/lib/action_controller/railtie.rb +1 -1
  21. data/lib/action_controller/renderer.rb +1 -0
  22. data/lib/action_controller/test_case.rb +2 -0
  23. data/lib/action_dispatch/constants.rb +0 -6
  24. data/lib/action_dispatch/http/cache.rb +27 -10
  25. data/lib/action_dispatch/http/content_security_policy.rb +13 -25
  26. data/lib/action_dispatch/http/filter_parameters.rb +4 -9
  27. data/lib/action_dispatch/http/filter_redirect.rb +2 -9
  28. data/lib/action_dispatch/http/mime_negotiation.rb +3 -8
  29. data/lib/action_dispatch/http/permissions_policy.rb +2 -0
  30. data/lib/action_dispatch/http/request.rb +7 -6
  31. data/lib/action_dispatch/http/response.rb +1 -15
  32. data/lib/action_dispatch/http/url.rb +2 -2
  33. data/lib/action_dispatch/journey/formatter.rb +3 -8
  34. data/lib/action_dispatch/journey/gtg/transition_table.rb +4 -4
  35. data/lib/action_dispatch/journey/parser.rb +99 -196
  36. data/lib/action_dispatch/journey/scanner.rb +40 -42
  37. data/lib/action_dispatch/middleware/cookies.rb +4 -2
  38. data/lib/action_dispatch/middleware/debug_exceptions.rb +17 -6
  39. data/lib/action_dispatch/middleware/exception_wrapper.rb +3 -3
  40. data/lib/action_dispatch/middleware/executor.rb +2 -5
  41. data/lib/action_dispatch/middleware/public_exceptions.rb +1 -5
  42. data/lib/action_dispatch/middleware/request_id.rb +2 -1
  43. data/lib/action_dispatch/middleware/ssl.rb +13 -3
  44. data/lib/action_dispatch/railtie.rb +2 -0
  45. data/lib/action_dispatch/routing/inspector.rb +1 -1
  46. data/lib/action_dispatch/routing/mapper.rb +30 -22
  47. data/lib/action_dispatch/routing/route_set.rb +18 -6
  48. data/lib/action_dispatch/system_testing/browser.rb +12 -21
  49. data/lib/action_dispatch/testing/assertion_response.rb +1 -1
  50. data/lib/action_dispatch/testing/integration.rb +3 -2
  51. data/lib/action_dispatch/testing/request_encoder.rb +9 -9
  52. data/lib/action_dispatch/testing/test_process.rb +2 -1
  53. data/lib/action_dispatch.rb +0 -4
  54. data/lib/action_pack/gem_version.rb +4 -4
  55. metadata +16 -49
  56. data/lib/action_dispatch/journey/parser.y +0 -50
  57. data/lib/action_dispatch/journey/parser_extras.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b4db283a47c7fd1c131bc94355af9d04693a87e369aa12804684c07502c1b178
4
- data.tar.gz: 5535526e4111326ce7f45e12ed01766c18f4ac7519a71db3dd061e0b40591577
3
+ metadata.gz: 4392b60cf6c4af7ed943daf2c4e438440689b8f869a859510b1e0e5808204cf2
4
+ data.tar.gz: ee9993b25b397af527f1730dc439a0425a81d4b03afb148e310dac8862003261
5
5
  SHA512:
6
- metadata.gz: 659a67074d71add87550dfc628c01a21e3c09ea8792d6d9fd11249ceb1bec9ab399587bd59b69504fef218dfffbaa26d45ab0022ecd97d9769aeab41324b23f2
7
- data.tar.gz: 10af8e140e458f9c917c3298a8408e53cfbbdcb788e3d73057784f9d2b382c5be502db2d5ebc01adb0f78f97723685c7ca5cd3a4ec00dc54da679826db154445
6
+ metadata.gz: 2063ad6ca3243b066226af6a1d1ad616d808c48a18f80df374d02b064ad4839a971e4eff804321621d910111829b0c1130b5a05f5a44afabb380ec9f7d5985b7
7
+ data.tar.gz: f3f1e1ce84c47654f69cf3f3ada2afa48e412dac1b7a5abd10c4d0fc34b66b7574f2454410c323cfa26a000005da585815db8a27dc3f1e9c2a71a504b0f3021d
data/CHANGELOG.md CHANGED
@@ -1,249 +1,135 @@
1
- ## Rails 7.2.3.2 (July 29, 2026) ##
1
+ ## Rails 8.0.0.beta1 (September 26, 2024) ##
2
2
 
3
- * No changes.
4
-
5
-
6
- ## Rails 7.2.3.1 (March 23, 2026) ##
7
-
8
- * No changes.
3
+ * Fix non-GET requests not updating cookies in `ActionController::TestCase`.
9
4
 
5
+ *Jon Moss*, *Hartley McGuire*
10
6
 
11
- ## Rails 7.2.3 (October 28, 2025) ##
7
+ * Update `ActionController::Live` to use a thread-pool to reuse threads across requests.
12
8
 
13
- * Submit test requests using `as: :html` with `Content-Type: x-www-form-urlencoded`
9
+ *Adam Renberg Tamm*
14
10
 
15
- *Sean Doyle*
11
+ * Introduce safer, more explicit params handling method with `params#expect` such that
12
+ `params.expect(table: [ :attr ])` replaces `params.require(:table).permit(:attr)`
16
13
 
17
- * Address `rack 3.2` deprecations warnings.
14
+ Ensures params are filtered with consideration for the expected
15
+ types of values, improving handling of params and avoiding ignorable
16
+ errors caused by params tampering.
18
17
 
18
+ ```ruby
19
+ # If the url is altered to ?person=hacked
20
+ # Before
21
+ params.require(:person).permit(:name, :age, pets: [:name])
22
+ # raises NoMethodError, causing a 500 and potential error reporting
23
+
24
+ # After
25
+ params.expect(person: [ :name, :age, pets: [[:name]] ])
26
+ # raises ActionController::ParameterMissing, correctly returning a 400 error
19
27
  ```
20
- warning: Status code :unprocessable_entity is deprecated and will be removed in a future version of Rack.
21
- Please use :unprocessable_content instead.
22
- ```
23
-
24
- Rails API will transparently convert one into the other for the forseable future.
25
28
 
26
- *Earlopain*, *Jean Boussier*
29
+ You may also notice the new double array `[[:name]]`. In order to
30
+ declare when a param is expected to be an array of parameter hashes,
31
+ this new double array syntax is used to explicitly declare an array.
32
+ `expect` requires you to declare expected arrays in this way, and will
33
+ ignore arrays that are passed when, for example, `pet: [:name]` is used.
27
34
 
28
- * Always return empty body for HEAD requests in `PublicExceptions` and
29
- `DebugExceptions`.
35
+ In order to preserve compatibility, `permit` does not adopt the new
36
+ double array syntax and is therefore more permissive about unexpected
37
+ types. Using `expect` everywhere is recommended.
30
38
 
31
- This is required by `Rack::Lint` (per RFC9110).
39
+ We suggest replacing `params.require(:person).permit(:name, :age)`
40
+ with the direct replacement `params.expect(person: [:name, :age])`
41
+ to prevent external users from manipulating params to trigger 500
42
+ errors. A 400 error will be returned instead, using public/400.html
32
43
 
33
- *Hartley McGuire*
44
+ Usage of `params.require(:id)` should likewise be replaced with
45
+ `params.expect(:id)` which is designed to ensure that `params[:id]`
46
+ is a scalar and not an array or hash, also requiring the param.
34
47
 
35
- * Fix `url_for` to handle `:path_params` gracefully when it's not a `Hash`.
48
+ ```ruby
49
+ # Before
50
+ User.find(params.require(:id)) # allows an array, altering behavior
36
51
 
37
- Prevents various security scanners from causing exceptions.
52
+ # After
53
+ User.find(params.expect(:id)) # expect only returns non-blank permitted scalars (excludes Hash, Array, nil, "", etc)
54
+ ```
38
55
 
39
56
  *Martin Emde*
40
57
 
41
- * Fix `ActionDispatch::Executor` to unwrap exceptions like other error reporting middlewares.
58
+ * System Testing: Disable Chrome's search engine choice by default in system tests.
42
59
 
43
- *Jean Boussier*
60
+ *glaszig*
44
61
 
45
- * Fix NoMethodError when a non-string CSRF token is passed through headers.
46
-
47
- *Ryan Heneise*
48
-
49
- * Fix invalid response when rescuing `ActionController::Redirecting::UnsafeRedirectError` in a controller.
50
-
51
- *Alex Ghiculescu*
52
-
53
-
54
- ## Rails 7.2.2.2 (August 13, 2025) ##
55
-
56
- * No changes.
57
-
58
-
59
- ## Rails 7.2.2.1 (December 10, 2024) ##
62
+ * Fix `Request#raw_post` raising `NoMethodError` when `rack.input` is `nil`.
60
63
 
61
- * Add validation to content security policies to disallow spaces and semicolons.
62
- Developers should use multiple arguments, and different directive methods instead.
64
+ *Hartley McGuire*
63
65
 
64
- [CVE-2024-54133]
66
+ * Remove `racc` dependency by manually writing `ActionDispatch::Journey::Scanner`.
65
67
 
66
68
  *Gannon McGibbon*
67
69
 
70
+ * Speed up `ActionDispatch::Routing::Mapper::Scope#[]` by merging frame hashes.
68
71
 
69
- ## Rails 7.2.2 (October 30, 2024) ##
70
-
71
- * Fix non-GET requests not updating cookies in `ActionController::TestCase`.
72
-
73
- *Jon Moss*, *Hartley McGuire*
74
-
75
-
76
- ## Rails 7.2.1.2 (October 23, 2024) ##
77
-
78
- * No changes.
79
-
80
-
81
- ## Rails 7.2.1.1 (October 15, 2024) ##
82
-
83
- * Avoid regex backtracking in HTTP Token authentication
84
-
85
- [CVE-2024-47887]
86
-
87
- *John Hawthorn*
88
-
89
- * Avoid regex backtracking in query parameter filtering
90
-
91
- [CVE-2024-41128]
92
-
93
- *John Hawthorn*
94
-
95
-
96
- ## Rails 7.2.1 (August 22, 2024) ##
97
-
98
- * Fix `Request#raw_post` raising `NoMethodError` when `rack.input` is `nil`.
99
-
100
- *Hartley McGuire*
101
-
102
-
103
- ## Rails 7.2.0 (August 09, 2024) ##
72
+ *Gannon McGibbon*
104
73
 
105
74
  * Allow bots to ignore `allow_browser`.
106
75
 
107
76
  *Matthew Nguyen*
108
77
 
109
- * Include the HTTP Permissions-Policy on non-HTML Content-Types
110
- [CVE-2024-28103]
111
-
112
- *Aaron Patterson*, *Zack Deveau*
113
-
114
- * Fix `Mime::Type.parse` handling type parameters for HTTP Accept headers.
115
-
116
- *Taylor Chaparro*
117
-
118
- * Fix the error page that is displayed when a view template is missing to account for nested controller paths in the
119
- suggested correct location for the missing template.
120
-
121
- *Joshua Young*
122
-
123
- * Add `save_and_open_page` helper to `IntegrationTest`.
124
-
125
- `save_and_open_page` is a helpful helper to keep a short feedback loop when working on system tests.
126
- A similar helper with matching signature has been added to integration tests.
127
-
128
- *Joé Dupuis*
129
-
130
- * Fix a regression in 7.1.3 passing a `to:` option without a controller when the controller is already defined by a scope.
131
-
132
- ```ruby
133
- Rails.application.routes.draw do
134
- controller :home do
135
- get "recent", to: "recent_posts"
136
- end
137
- end
138
- ```
139
-
140
- *Étienne Barrié*
141
-
142
- * Request Forgery takes relative paths into account.
143
-
144
- *Stefan Wienert*
145
-
146
- * Add ".test" as a default allowed host in development to ensure smooth golden-path setup with puma.dev.
147
-
148
- *DHH*
149
-
150
- * Add `allow_browser` to set minimum browser versions for the application.
151
-
152
- A browser that's blocked will by default be served the file in `public/406-unsupported-browser.html` with a HTTP status code of "406 Not Acceptable".
78
+ * Deprecate drawing routes with multiple paths to make routing faster.
79
+ You may use `with_options` or a loop to make drawing multiple paths easier.
153
80
 
154
81
  ```ruby
155
- class ApplicationController < ActionController::Base
156
- # Allow only browsers natively supporting webp images, web push, badges, import maps, CSS nesting + :has
157
- allow_browser versions: :modern
158
- end
159
-
160
- class ApplicationController < ActionController::Base
161
- # All versions of Chrome and Opera will be allowed, but no versions of "internet explorer" (ie). Safari needs to be 16.4+ and Firefox 121+.
162
- allow_browser versions: { safari: 16.4, firefox: 121, ie: false }
163
- end
164
-
165
- class MessagesController < ApplicationController
166
- # In addition to the browsers blocked by ApplicationController, also block Opera below 104 and Chrome below 119 for the show action.
167
- allow_browser versions: { opera: 104, chrome: 119 }, only: :show
168
- end
169
- ```
170
-
171
- *DHH*
172
-
173
- * Add rate limiting API.
82
+ # Before
83
+ get "/users", "/other_path", to: "users#index"
174
84
 
175
- ```ruby
176
- class SessionsController < ApplicationController
177
- rate_limit to: 10, within: 3.minutes, only: :create
178
- end
179
-
180
- class SignupsController < ApplicationController
181
- rate_limit to: 1000, within: 10.seconds,
182
- by: -> { request.domain }, with: -> { redirect_to busy_controller_url, alert: "Too many signups!" }, only: :new
183
- end
85
+ # After
86
+ get "/users", to: "users#index"
87
+ get "/other_path", to: "users#index"
184
88
  ```
185
89
 
186
- *DHH*, *Jean Boussier*
187
-
188
- * Add `image/svg+xml` to the compressible content types of `ActionDispatch::Static`.
189
-
190
- *Georg Ledermann*
191
-
192
- * Add instrumentation for `ActionController::Live#send_stream`.
193
-
194
- Allows subscribing to `send_stream` events. The event payload contains the filename, disposition, and type.
195
-
196
- *Hannah Ramadan*
197
-
198
- * Add support for `with_routing` test helper in `ActionDispatch::IntegrationTest`.
199
-
200
90
  *Gannon McGibbon*
201
91
 
202
- * Remove deprecated support to set `Rails.application.config.action_dispatch.show_exceptions` to `true` and `false`.
92
+ * Make `http_cache_forever` use `immutable: true`
203
93
 
204
- *Rafael Mendonça França*
94
+ *Nate Matykiewicz*
205
95
 
206
- * Remove deprecated `speaker`, `vibrate`, and `vr` permissions policy directives.
96
+ * Add `config.action_dispatch.strict_freshness`.
207
97
 
208
- *Rafael Mendonça França*
98
+ When set to `true`, the `ETag` header takes precedence over the `Last-Modified` header when both are present,
99
+ as specified by RFC 7232, Section 6.
209
100
 
210
- * Remove deprecated `Rails.application.config.action_dispatch.return_only_request_media_type_on_content_type`.
101
+ Defaults to `false` to maintain compatibility with previous versions of Rails, but is enabled as part of
102
+ Rails 8.0 defaults.
211
103
 
212
- *Rafael Mendonça França*
104
+ *heka1024*
213
105
 
214
- * Deprecate `Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality`.
106
+ * Support `immutable` directive in Cache-Control
215
107
 
216
- *Rafael Mendonça França*
217
-
218
- * Remove deprecated comparison between `ActionController::Parameters` and `Hash`.
219
-
220
- *Rafael Mendonça França*
221
-
222
- * Remove deprecated constant `AbstractController::Helpers::MissingHelperError`.
223
-
224
- *Rafael Mendonça França*
225
-
226
- * Fix a race condition that could cause a `Text file busy - chromedriver`
227
- error with parallel system tests.
108
+ ```ruby
109
+ expires_in 1.minute, public: true, immutable: true
110
+ # Cache-Control: public, max-age=60, immutable
111
+ ```
228
112
 
229
- *Matt Brictson*
113
+ *heka1024*
230
114
 
231
- * Add `racc` as a dependency since it will become a bundled gem in Ruby 3.4.0
115
+ * Add `:wasm_unsafe_eval` mapping for `content_security_policy`
232
116
 
233
- *Hartley McGuire*
234
- * Remove deprecated constant `ActionDispatch::IllegalStateError`.
117
+ ```ruby
118
+ # Before
119
+ policy.script_src "'wasm-unsafe-eval'"
235
120
 
236
- *Rafael Mendonça França*
121
+ # After
122
+ policy.script_src :wasm_unsafe_eval
123
+ ```
237
124
 
238
- * Add parameter filter capability for redirect locations.
125
+ *Joe Haig*
239
126
 
240
- It uses the `config.filter_parameters` to match what needs to be filtered.
241
- The result would be like this:
127
+ * Add `display_capture` and `keyboard_map` in `permissions_policy`
242
128
 
243
- Redirected to http://secret.foo.bar?username=roque&password=[FILTERED]
129
+ *Cyril Blaecke*
244
130
 
245
- Fixes #14055.
131
+ * Add `connect` route helper.
246
132
 
247
- *Roque Pinel*, *Trevor Turk*, *tonytonyjan*
133
+ *Samuel Williams*
248
134
 
249
- Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/actionpack/CHANGELOG.md) for previous changes.
135
+ Please check [7-2-stable](https://github.com/rails/rails/blob/7-2-stable/actionpack/CHANGELOG.md) for previous changes.
data/README.rdoc CHANGED
@@ -52,6 +52,6 @@ Bug reports for the Ruby on \Rails project can be filed here:
52
52
 
53
53
  * https://github.com/rails/rails/issues
54
54
 
55
- Feature requests should be discussed on the rubyonrails-core forum here:
55
+ Feature requests should be discussed on the rails-core mailing list here:
56
56
 
57
57
  * https://discuss.rubyonrails.org/c/rubyonrails-core
@@ -86,10 +86,14 @@ module AbstractController
86
86
  controller.public_instance_methods(true) - methods
87
87
  end
88
88
 
89
- # A `Set` of method names that should be considered actions. This includes all
89
+ # A list of method names that should be considered actions. This includes all
90
90
  # public instance methods on a controller, less any internal methods (see
91
91
  # internal_methods), adding back in any methods that are internal, but still
92
92
  # exist on the class itself.
93
+ #
94
+ # #### Returns
95
+ # * `Set` - A set of all methods that should be considered actions.
96
+ #
93
97
  def action_methods
94
98
  @action_methods ||= begin
95
99
  # All public instance methods of this class, including ancestors except for
@@ -117,6 +121,9 @@ module AbstractController
117
121
  #
118
122
  # MyApp::MyPostsController.controller_path # => "my_app/my_posts"
119
123
  #
124
+ # #### Returns
125
+ # * `String`
126
+ #
120
127
  def controller_path
121
128
  @controller_path ||= name.delete_suffix("Controller").underscore unless anonymous?
122
129
  end
@@ -140,6 +147,10 @@ module AbstractController
140
147
  # The actual method that is called is determined by calling #method_for_action.
141
148
  # If no method can handle the action, then an AbstractController::ActionNotFound
142
149
  # error is raised.
150
+ #
151
+ # #### Returns
152
+ # * `self`
153
+ #
143
154
  def process(action, ...)
144
155
  @_action_name = action.to_s
145
156
 
@@ -27,7 +27,7 @@ module AbstractController
27
27
  def method_missing(symbol, ...)
28
28
  unless mime_constant = Mime[symbol]
29
29
  raise NoMethodError, "To respond to a custom format, register it as a MIME type first: " \
30
- "https://guides.rubyonrails.org/action_controller_advanced_topics.html#restful-downloads. " \
30
+ "https://guides.rubyonrails.org/action_controller_overview.html#restful-downloads. " \
31
31
  "If you meant to respond to a variant like :tablet or :phone, not a custom format, " \
32
32
  "be sure to nest your variant response within a format response: " \
33
33
  "format.html { |html| html.tablet { ... } }"
@@ -90,7 +90,7 @@ module AbstractController
90
90
  #--
91
91
  # Implemented by Resolution#modules_for_helpers.
92
92
 
93
- # :method: all_helpers_from_path
93
+ # :method: # all_helpers_from_path
94
94
  # :call-seq: all_helpers_from_path(path)
95
95
  #
96
96
  # Returns a list of helper names in a given path.
@@ -104,7 +104,6 @@ module AbstractController
104
104
  # Declare a controller method as a helper. For example, the following
105
105
  # makes the `current_user` and `logged_in?` controller methods available
106
106
  # to the view:
107
- #
108
107
  # class ApplicationController < ActionController::Base
109
108
  # helper_method :current_user, :logged_in?
110
109
  #
@@ -119,7 +118,6 @@ module AbstractController
119
118
  # end
120
119
  #
121
120
  # In a view:
122
- #
123
121
  # <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
124
122
  #
125
123
  # #### Parameters
@@ -60,7 +60,7 @@ module ActionController # :nodoc:
60
60
  end
61
61
  end
62
62
 
63
- class BrowserBlocker # :nodoc:
63
+ class BrowserBlocker
64
64
  SETS = {
65
65
  modern: { safari: 17.2, chrome: 120, firefox: 121, opera: 106, ie: false }
66
66
  }
@@ -259,6 +259,9 @@ module ActionController
259
259
  # `:stale_if_error`
260
260
  # : Sets the value of the `stale-if-error` directive.
261
261
  #
262
+ # `:immutable`
263
+ # : If true, adds the `immutable` directive.
264
+ #
262
265
  #
263
266
  # Any additional key-value pairs are concatenated as directives. For a list of
264
267
  # supported `Cache-Control` directives, see the [article on
@@ -292,6 +295,7 @@ module ActionController
292
295
  must_revalidate: options.delete(:must_revalidate),
293
296
  stale_while_revalidate: options.delete(:stale_while_revalidate),
294
297
  stale_if_error: options.delete(:stale_if_error),
298
+ immutable: options.delete(:immutable),
295
299
  )
296
300
  options.delete(:private)
297
301
 
@@ -315,7 +319,7 @@ module ActionController
315
319
  # user's web browser. To allow proxies to cache the response, set `true` to
316
320
  # indicate that they can serve the cached response to all users.
317
321
  def http_cache_forever(public: false)
318
- expires_in 100.years, public: public
322
+ expires_in 100.years, public: public, immutable: true
319
323
 
320
324
  yield if stale?(etag: request.fullpath,
321
325
  last_modified: Time.new(2011, 1, 1).utc,
@@ -513,11 +513,14 @@ module ActionController
513
513
  array_params.each { |param| (param[1] || +"").gsub! %r/^"|"$/, "" }
514
514
  end
515
515
 
516
+ WHITESPACED_AUTHN_PAIR_DELIMITERS = /\s*#{AUTHN_PAIR_DELIMITERS}\s*/
517
+ private_constant :WHITESPACED_AUTHN_PAIR_DELIMITERS
518
+
516
519
  # This method takes an authorization body and splits up the key-value pairs by
517
520
  # the standardized `:`, `;`, or `\t` delimiters defined in
518
521
  # `AUTHN_PAIR_DELIMITERS`.
519
522
  def raw_params(auth)
520
- _raw_params = auth.sub(TOKEN_REGEX, "").split(AUTHN_PAIR_DELIMITERS).map(&:strip)
523
+ _raw_params = auth.sub(TOKEN_REGEX, "").split(WHITESPACED_AUTHN_PAIR_DELIMITERS)
521
524
  _raw_params.reject!(&:empty?)
522
525
 
523
526
  if !_raw_params.first&.start_with?(TOKEN_KEY)
@@ -2,7 +2,6 @@
2
2
 
3
3
  # :markup: markdown
4
4
 
5
- require "benchmark"
6
5
  require "abstract_controller/logger"
7
6
 
8
7
  module ActionController
@@ -29,7 +28,7 @@ module ActionController
29
28
  def render(*)
30
29
  render_output = nil
31
30
  self.view_runtime = cleanup_view_runtime do
32
- Benchmark.ms { render_output = super }
31
+ ActiveSupport::Benchmark.realtime(:float_millisecond) { render_output = super }
33
32
  end
34
33
  render_output
35
34
  end
@@ -58,7 +58,7 @@ module ActionController
58
58
 
59
59
  module ClassMethods
60
60
  def make_response!(request)
61
- if (request.get_header("SERVER_PROTOCOL") || request.get_header("HTTP_VERSION")) == "HTTP/1.0"
61
+ if request.get_header("HTTP_VERSION") == "HTTP/1.0"
62
62
  super
63
63
  else
64
64
  Live::Response.new.tap do |res|
@@ -307,6 +307,10 @@ module ActionController
307
307
  error = e
308
308
  end
309
309
  ensure
310
+ # Ensure we clean up any thread locals we copied so that the thread can reused.
311
+ ActiveSupport::IsolatedExecutionState.clear
312
+ locals.each { |k, _| t2[k] = nil }
313
+
310
314
  @_response.commit!
311
315
  end
312
316
  end
@@ -371,11 +375,15 @@ module ActionController
371
375
  # data from the response bodies. Nobody should call this method except in Rails
372
376
  # internals. Seriously!
373
377
  def new_controller_thread # :nodoc:
374
- Thread.new {
378
+ ActionController::Live.live_thread_pool_executor.post do
375
379
  t2 = Thread.current
376
380
  t2.abort_on_exception = true
377
381
  yield
378
- }
382
+ end
383
+ end
384
+
385
+ def self.live_thread_pool_executor
386
+ @live_thread_pool_executor ||= Concurrent::CachedThreadPool.new(name: "action_controller.live")
379
387
  end
380
388
 
381
389
  def log_error(exception)
@@ -198,14 +198,14 @@ module ActionController
198
198
  # # enables the parameter wrapper for XML format
199
199
  #
200
200
  # wrap_parameters :person
201
- # # wraps parameters into params[:person] hash
201
+ # # wraps parameters into +params[:person]+ hash
202
202
  #
203
203
  # wrap_parameters Person
204
204
  # # wraps parameters by determining the wrapper key from Person class
205
- # # (:person, in this case) and the list of attribute names
205
+ # # (+person+, in this case) and the list of attribute names
206
206
  #
207
207
  # wrap_parameters include: [:username, :title]
208
- # # wraps only :username and :title attributes from parameters.
208
+ # # wraps only +:username+ and +:title+ attributes from parameters.
209
209
  #
210
210
  # wrap_parameters false
211
211
  # # disables parameters wrapping for this controller altogether.
@@ -29,6 +29,9 @@ module ActionController # :nodoc:
29
29
  # datastore as your general caches, you can pass a custom store in the `store`
30
30
  # parameter.
31
31
  #
32
+ # If you want to use multiple rate limits per controller, you need to give each of
33
+ # them and explicit name via the `name:` option.
34
+ #
32
35
  # Examples:
33
36
  #
34
37
  # class SessionsController < ApplicationController
@@ -44,14 +47,20 @@ module ActionController # :nodoc:
44
47
  # RATE_LIMIT_STORE = ActiveSupport::Cache::RedisCacheStore.new(url: ENV["REDIS_URL"])
45
48
  # rate_limit to: 10, within: 3.minutes, store: RATE_LIMIT_STORE
46
49
  # end
47
- def rate_limit(to:, within:, by: -> { request.remote_ip }, with: -> { head :too_many_requests }, store: cache_store, **options)
48
- before_action -> { rate_limiting(to: to, within: within, by: by, with: with, store: store) }, **options
50
+ #
51
+ # class SessionsController < ApplicationController
52
+ # rate_limit to: 3, within: 2.seconds, name: "short-term"
53
+ # rate_limit to: 10, within: 5.minutes, name: "long-term"
54
+ # end
55
+ def rate_limit(to:, within:, by: -> { request.remote_ip }, with: -> { head :too_many_requests }, store: cache_store, name: nil, **options)
56
+ before_action -> { rate_limiting(to: to, within: within, by: by, with: with, store: store, name: name) }, **options
49
57
  end
50
58
  end
51
59
 
52
60
  private
53
- def rate_limiting(to:, within:, by:, with:, store:)
54
- count = store.increment("rate-limit:#{controller_path}:#{instance_exec(&by)}", 1, expires_in: within)
61
+ def rate_limiting(to:, within:, by:, with:, store:, name:)
62
+ cache_key = ["rate-limit", controller_path, name, instance_exec(&by)].compact.join(":")
63
+ count = store.increment(cache_key, 1, expires_in: within)
55
64
  if count && count > to
56
65
  ActiveSupport::Notifications.instrument("rate_limit.action_controller", request: request) do
57
66
  instance_exec(&with)
@@ -106,14 +106,13 @@ module ActionController
106
106
 
107
107
  allow_other_host = response_options.delete(:allow_other_host) { _allow_other_host }
108
108
 
109
- proposed_status = _extract_redirect_to_status(options, response_options)
109
+ self.status = _extract_redirect_to_status(options, response_options)
110
110
 
111
111
  redirect_to_location = _compute_redirect_to_location(request, options)
112
112
  _ensure_url_is_http_header_safe(redirect_to_location)
113
113
 
114
114
  self.location = _enforce_open_redirect_protection(redirect_to_location, allow_other_host: allow_other_host)
115
115
  self.response_body = ""
116
- self.status = proposed_status
117
116
  end
118
117
 
119
118
  # Soft deprecated alias for #redirect_back_or_to where the `fallback_location`
@@ -212,9 +211,9 @@ module ActionController
212
211
 
213
212
  def _extract_redirect_to_status(options, response_options)
214
213
  if options.is_a?(Hash) && options.key?(:status)
215
- ActionDispatch::Response.rack_status_code(options.delete(:status))
214
+ Rack::Utils.status_code(options.delete(:status))
216
215
  elsif response_options.key?(:status)
217
- ActionDispatch::Response.rack_status_code(response_options[:status])
216
+ Rack::Utils.status_code(response_options[:status])
218
217
  else
219
218
  302
220
219
  end
@@ -154,7 +154,8 @@ module ActionController
154
154
  end
155
155
 
156
156
  add :json do |json, options|
157
- json = json.to_json(options) unless json.kind_of?(String)
157
+ json_options = options.except(:callback, :content_type, :status)
158
+ json = json.to_json(json_options) unless json.kind_of?(String)
158
159
 
159
160
  if options[:callback].present?
160
161
  if media_type.nil? || media_type == Mime[:json]
@@ -232,7 +232,7 @@ module ActionController
232
232
  end
233
233
 
234
234
  if options[:status]
235
- options[:status] = ActionDispatch::Response.rack_status_code(options[:status])
235
+ options[:status] = Rack::Utils.status_code(options[:status])
236
236
  end
237
237
 
238
238
  super
@@ -142,7 +142,6 @@ module ActionController # :nodoc:
142
142
  #
143
143
  #
144
144
  # Built-in unverified request handling methods are:
145
- #
146
145
  # * `:exception` - Raises ActionController::InvalidAuthenticityToken
147
146
  # exception.
148
147
  # * `:reset_session` - Resets the session.
@@ -171,7 +170,6 @@ module ActionController # :nodoc:
171
170
  #
172
171
  #
173
172
  # Built-in session token strategies are:
174
- #
175
173
  # * `:session` - Store the CSRF token in the session. Used as default if
176
174
  # `:store` option is not specified.
177
175
  # * `:cookie` - Store the CSRF token in an encrypted cookie.
@@ -500,7 +498,7 @@ module ActionController # :nodoc:
500
498
  # Checks the client's masked token to see if it matches the session token.
501
499
  # Essentially the inverse of `masked_authenticity_token`.
502
500
  def valid_authenticity_token?(session, encoded_masked_token) # :doc:
503
- if !encoded_masked_token.is_a?(String) || encoded_masked_token.empty?
501
+ if encoded_masked_token.nil? || encoded_masked_token.empty? || !encoded_masked_token.is_a?(String)
504
502
  return false
505
503
  end
506
504