actionpack 7.2.3 → 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.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +83 -187
- data/README.rdoc +1 -1
- data/lib/abstract_controller/base.rb +12 -1
- data/lib/abstract_controller/collector.rb +1 -1
- data/lib/abstract_controller/helpers.rb +1 -3
- data/lib/action_controller/metal/allow_browser.rb +1 -1
- data/lib/action_controller/metal/conditional_get.rb +5 -1
- data/lib/action_controller/metal/http_authentication.rb +4 -1
- data/lib/action_controller/metal/instrumentation.rb +1 -2
- data/lib/action_controller/metal/live.rb +11 -3
- data/lib/action_controller/metal/params_wrapper.rb +3 -3
- data/lib/action_controller/metal/rate_limiting.rb +13 -4
- data/lib/action_controller/metal/redirecting.rb +3 -4
- data/lib/action_controller/metal/renderers.rb +2 -1
- data/lib/action_controller/metal/rendering.rb +1 -1
- data/lib/action_controller/metal/request_forgery_protection.rb +1 -3
- data/lib/action_controller/metal/streaming.rb +5 -84
- data/lib/action_controller/metal/strong_parameters.rb +277 -73
- data/lib/action_controller/railtie.rb +1 -1
- data/lib/action_controller/renderer.rb +1 -0
- data/lib/action_controller/test_case.rb +2 -0
- data/lib/action_dispatch/constants.rb +0 -6
- data/lib/action_dispatch/http/cache.rb +27 -10
- data/lib/action_dispatch/http/content_security_policy.rb +13 -25
- data/lib/action_dispatch/http/filter_parameters.rb +4 -9
- data/lib/action_dispatch/http/filter_redirect.rb +2 -9
- data/lib/action_dispatch/http/mime_negotiation.rb +3 -8
- data/lib/action_dispatch/http/permissions_policy.rb +2 -0
- data/lib/action_dispatch/http/request.rb +7 -6
- data/lib/action_dispatch/http/response.rb +1 -15
- data/lib/action_dispatch/http/url.rb +2 -2
- data/lib/action_dispatch/journey/formatter.rb +3 -8
- data/lib/action_dispatch/journey/gtg/transition_table.rb +4 -4
- data/lib/action_dispatch/journey/parser.rb +99 -196
- data/lib/action_dispatch/journey/scanner.rb +40 -42
- data/lib/action_dispatch/middleware/cookies.rb +4 -2
- data/lib/action_dispatch/middleware/debug_exceptions.rb +17 -6
- data/lib/action_dispatch/middleware/exception_wrapper.rb +3 -3
- data/lib/action_dispatch/middleware/executor.rb +2 -5
- data/lib/action_dispatch/middleware/public_exceptions.rb +1 -5
- data/lib/action_dispatch/middleware/request_id.rb +2 -1
- data/lib/action_dispatch/middleware/ssl.rb +13 -3
- data/lib/action_dispatch/railtie.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +1 -1
- data/lib/action_dispatch/routing/mapper.rb +30 -22
- data/lib/action_dispatch/routing/route_set.rb +18 -6
- data/lib/action_dispatch/system_testing/browser.rb +12 -21
- data/lib/action_dispatch/testing/assertion_response.rb +1 -1
- data/lib/action_dispatch/testing/integration.rb +3 -2
- data/lib/action_dispatch/testing/request_encoder.rb +9 -9
- data/lib/action_dispatch/testing/test_process.rb +2 -1
- data/lib/action_dispatch.rb +0 -4
- data/lib/action_pack/gem_version.rb +4 -4
- metadata +16 -49
- data/lib/action_dispatch/journey/parser.y +0 -50
- 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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4392b60cf6c4af7ed943daf2c4e438440689b8f869a859510b1e0e5808204cf2
|
|
4
|
+
data.tar.gz: ee9993b25b397af527f1730dc439a0425a81d4b03afb148e310dac8862003261
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2063ad6ca3243b066226af6a1d1ad616d808c48a18f80df374d02b064ad4839a971e4eff804321621d910111829b0c1130b5a05f5a44afabb380ec9f7d5985b7
|
|
7
|
+
data.tar.gz: f3f1e1ce84c47654f69cf3f3ada2afa48e412dac1b7a5abd10c4d0fc34b66b7574f2454410c323cfa26a000005da585815db8a27dc3f1e9c2a71a504b0f3021d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,239 +1,135 @@
|
|
|
1
|
-
## Rails
|
|
2
|
-
|
|
3
|
-
* Submit test requests using `as: :html` with `Content-Type: x-www-form-urlencoded`
|
|
4
|
-
|
|
5
|
-
*Sean Doyle*
|
|
6
|
-
|
|
7
|
-
* Address `rack 3.2` deprecations warnings.
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
warning: Status code :unprocessable_entity is deprecated and will be removed in a future version of Rack.
|
|
11
|
-
Please use :unprocessable_content instead.
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
Rails API will transparently convert one into the other for the forseable future.
|
|
15
|
-
|
|
16
|
-
*Earlopain*, *Jean Boussier*
|
|
17
|
-
|
|
18
|
-
* Always return empty body for HEAD requests in `PublicExceptions` and
|
|
19
|
-
`DebugExceptions`.
|
|
20
|
-
|
|
21
|
-
This is required by `Rack::Lint` (per RFC9110).
|
|
22
|
-
|
|
23
|
-
*Hartley McGuire*
|
|
24
|
-
|
|
25
|
-
* Fix `url_for` to handle `:path_params` gracefully when it's not a `Hash`.
|
|
26
|
-
|
|
27
|
-
Prevents various security scanners from causing exceptions.
|
|
28
|
-
|
|
29
|
-
*Martin Emde*
|
|
30
|
-
|
|
31
|
-
* Fix `ActionDispatch::Executor` to unwrap exceptions like other error reporting middlewares.
|
|
32
|
-
|
|
33
|
-
*Jean Boussier*
|
|
34
|
-
|
|
35
|
-
* Fix NoMethodError when a non-string CSRF token is passed through headers.
|
|
36
|
-
|
|
37
|
-
*Ryan Heneise*
|
|
38
|
-
|
|
39
|
-
* Fix invalid response when rescuing `ActionController::Redirecting::UnsafeRedirectError` in a controller.
|
|
40
|
-
|
|
41
|
-
*Alex Ghiculescu*
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
## Rails 7.2.2.2 (August 13, 2025) ##
|
|
45
|
-
|
|
46
|
-
* No changes.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
## Rails 7.2.2.1 (December 10, 2024) ##
|
|
50
|
-
|
|
51
|
-
* Add validation to content security policies to disallow spaces and semicolons.
|
|
52
|
-
Developers should use multiple arguments, and different directive methods instead.
|
|
53
|
-
|
|
54
|
-
[CVE-2024-54133]
|
|
55
|
-
|
|
56
|
-
*Gannon McGibbon*
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
## Rails 7.2.2 (October 30, 2024) ##
|
|
1
|
+
## Rails 8.0.0.beta1 (September 26, 2024) ##
|
|
60
2
|
|
|
61
3
|
* Fix non-GET requests not updating cookies in `ActionController::TestCase`.
|
|
62
4
|
|
|
63
5
|
*Jon Moss*, *Hartley McGuire*
|
|
64
6
|
|
|
7
|
+
* Update `ActionController::Live` to use a thread-pool to reuse threads across requests.
|
|
65
8
|
|
|
66
|
-
|
|
9
|
+
*Adam Renberg Tamm*
|
|
67
10
|
|
|
68
|
-
*
|
|
11
|
+
* Introduce safer, more explicit params handling method with `params#expect` such that
|
|
12
|
+
`params.expect(table: [ :attr ])` replaces `params.require(:table).permit(:attr)`
|
|
69
13
|
|
|
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.
|
|
70
17
|
|
|
71
|
-
|
|
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
|
|
27
|
+
```
|
|
72
28
|
|
|
73
|
-
|
|
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.
|
|
74
34
|
|
|
75
|
-
|
|
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.
|
|
76
38
|
|
|
77
|
-
|
|
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
|
|
78
43
|
|
|
79
|
-
|
|
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.
|
|
47
|
+
|
|
48
|
+
```ruby
|
|
49
|
+
# Before
|
|
50
|
+
User.find(params.require(:id)) # allows an array, altering behavior
|
|
80
51
|
|
|
81
|
-
|
|
52
|
+
# After
|
|
53
|
+
User.find(params.expect(:id)) # expect only returns non-blank permitted scalars (excludes Hash, Array, nil, "", etc)
|
|
54
|
+
```
|
|
82
55
|
|
|
83
|
-
*
|
|
56
|
+
*Martin Emde*
|
|
84
57
|
|
|
58
|
+
* System Testing: Disable Chrome's search engine choice by default in system tests.
|
|
85
59
|
|
|
86
|
-
|
|
60
|
+
*glaszig*
|
|
87
61
|
|
|
88
62
|
* Fix `Request#raw_post` raising `NoMethodError` when `rack.input` is `nil`.
|
|
89
63
|
|
|
90
64
|
*Hartley McGuire*
|
|
91
65
|
|
|
66
|
+
* Remove `racc` dependency by manually writing `ActionDispatch::Journey::Scanner`.
|
|
92
67
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
* Allow bots to ignore `allow_browser`.
|
|
96
|
-
|
|
97
|
-
*Matthew Nguyen*
|
|
98
|
-
|
|
99
|
-
* Include the HTTP Permissions-Policy on non-HTML Content-Types
|
|
100
|
-
[CVE-2024-28103]
|
|
101
|
-
|
|
102
|
-
*Aaron Patterson*, *Zack Deveau*
|
|
103
|
-
|
|
104
|
-
* Fix `Mime::Type.parse` handling type parameters for HTTP Accept headers.
|
|
105
|
-
|
|
106
|
-
*Taylor Chaparro*
|
|
107
|
-
|
|
108
|
-
* Fix the error page that is displayed when a view template is missing to account for nested controller paths in the
|
|
109
|
-
suggested correct location for the missing template.
|
|
68
|
+
*Gannon McGibbon*
|
|
110
69
|
|
|
111
|
-
|
|
70
|
+
* Speed up `ActionDispatch::Routing::Mapper::Scope#[]` by merging frame hashes.
|
|
112
71
|
|
|
113
|
-
*
|
|
72
|
+
*Gannon McGibbon*
|
|
114
73
|
|
|
115
|
-
|
|
116
|
-
A similar helper with matching signature has been added to integration tests.
|
|
74
|
+
* Allow bots to ignore `allow_browser`.
|
|
117
75
|
|
|
118
|
-
*
|
|
76
|
+
*Matthew Nguyen*
|
|
119
77
|
|
|
120
|
-
*
|
|
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.
|
|
121
80
|
|
|
122
81
|
```ruby
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
get "recent", to: "recent_posts"
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
```
|
|
82
|
+
# Before
|
|
83
|
+
get "/users", "/other_path", to: "users#index"
|
|
129
84
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
*Stefan Wienert*
|
|
135
|
-
|
|
136
|
-
* Add ".test" as a default allowed host in development to ensure smooth golden-path setup with puma.dev.
|
|
137
|
-
|
|
138
|
-
*DHH*
|
|
139
|
-
|
|
140
|
-
* Add `allow_browser` to set minimum browser versions for the application.
|
|
141
|
-
|
|
142
|
-
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".
|
|
143
|
-
|
|
144
|
-
```ruby
|
|
145
|
-
class ApplicationController < ActionController::Base
|
|
146
|
-
# Allow only browsers natively supporting webp images, web push, badges, import maps, CSS nesting + :has
|
|
147
|
-
allow_browser versions: :modern
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
class ApplicationController < ActionController::Base
|
|
151
|
-
# 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+.
|
|
152
|
-
allow_browser versions: { safari: 16.4, firefox: 121, ie: false }
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
class MessagesController < ApplicationController
|
|
156
|
-
# In addition to the browsers blocked by ApplicationController, also block Opera below 104 and Chrome below 119 for the show action.
|
|
157
|
-
allow_browser versions: { opera: 104, chrome: 119 }, only: :show
|
|
158
|
-
end
|
|
85
|
+
# After
|
|
86
|
+
get "/users", to: "users#index"
|
|
87
|
+
get "/other_path", to: "users#index"
|
|
159
88
|
```
|
|
160
89
|
|
|
161
|
-
*DHH*
|
|
162
|
-
|
|
163
|
-
* Add rate limiting API.
|
|
164
|
-
|
|
165
|
-
```ruby
|
|
166
|
-
class SessionsController < ApplicationController
|
|
167
|
-
rate_limit to: 10, within: 3.minutes, only: :create
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
class SignupsController < ApplicationController
|
|
171
|
-
rate_limit to: 1000, within: 10.seconds,
|
|
172
|
-
by: -> { request.domain }, with: -> { redirect_to busy_controller_url, alert: "Too many signups!" }, only: :new
|
|
173
|
-
end
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
*DHH*, *Jean Boussier*
|
|
177
|
-
|
|
178
|
-
* Add `image/svg+xml` to the compressible content types of `ActionDispatch::Static`.
|
|
179
|
-
|
|
180
|
-
*Georg Ledermann*
|
|
181
|
-
|
|
182
|
-
* Add instrumentation for `ActionController::Live#send_stream`.
|
|
183
|
-
|
|
184
|
-
Allows subscribing to `send_stream` events. The event payload contains the filename, disposition, and type.
|
|
185
|
-
|
|
186
|
-
*Hannah Ramadan*
|
|
187
|
-
|
|
188
|
-
* Add support for `with_routing` test helper in `ActionDispatch::IntegrationTest`.
|
|
189
|
-
|
|
190
90
|
*Gannon McGibbon*
|
|
191
91
|
|
|
192
|
-
*
|
|
92
|
+
* Make `http_cache_forever` use `immutable: true`
|
|
193
93
|
|
|
194
|
-
*
|
|
94
|
+
*Nate Matykiewicz*
|
|
195
95
|
|
|
196
|
-
*
|
|
96
|
+
* Add `config.action_dispatch.strict_freshness`.
|
|
197
97
|
|
|
198
|
-
|
|
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.
|
|
199
100
|
|
|
200
|
-
|
|
101
|
+
Defaults to `false` to maintain compatibility with previous versions of Rails, but is enabled as part of
|
|
102
|
+
Rails 8.0 defaults.
|
|
201
103
|
|
|
202
|
-
*
|
|
104
|
+
*heka1024*
|
|
203
105
|
|
|
204
|
-
*
|
|
106
|
+
* Support `immutable` directive in Cache-Control
|
|
205
107
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
*Rafael Mendonça França*
|
|
211
|
-
|
|
212
|
-
* Remove deprecated constant `AbstractController::Helpers::MissingHelperError`.
|
|
213
|
-
|
|
214
|
-
*Rafael Mendonça França*
|
|
215
|
-
|
|
216
|
-
* Fix a race condition that could cause a `Text file busy - chromedriver`
|
|
217
|
-
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
|
+
```
|
|
218
112
|
|
|
219
|
-
*
|
|
113
|
+
*heka1024*
|
|
220
114
|
|
|
221
|
-
* Add `
|
|
115
|
+
* Add `:wasm_unsafe_eval` mapping for `content_security_policy`
|
|
222
116
|
|
|
223
|
-
|
|
224
|
-
|
|
117
|
+
```ruby
|
|
118
|
+
# Before
|
|
119
|
+
policy.script_src "'wasm-unsafe-eval'"
|
|
225
120
|
|
|
226
|
-
|
|
121
|
+
# After
|
|
122
|
+
policy.script_src :wasm_unsafe_eval
|
|
123
|
+
```
|
|
227
124
|
|
|
228
|
-
*
|
|
125
|
+
*Joe Haig*
|
|
229
126
|
|
|
230
|
-
|
|
231
|
-
The result would be like this:
|
|
127
|
+
* Add `display_capture` and `keyboard_map` in `permissions_policy`
|
|
232
128
|
|
|
233
|
-
|
|
129
|
+
*Cyril Blaecke*
|
|
234
130
|
|
|
235
|
-
|
|
131
|
+
* Add `connect` route helper.
|
|
236
132
|
|
|
237
|
-
*
|
|
133
|
+
*Samuel Williams*
|
|
238
134
|
|
|
239
|
-
Please check [7-
|
|
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
|
|
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
|
|
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/
|
|
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
|
|
@@ -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(
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
# # (
|
|
205
|
+
# # (+person+, in this case) and the list of attribute names
|
|
206
206
|
#
|
|
207
207
|
# wrap_parameters include: [:username, :title]
|
|
208
|
-
# # wraps only
|
|
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
|
-
|
|
48
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
214
|
+
Rack::Utils.status_code(options.delete(:status))
|
|
216
215
|
elsif response_options.key?(:status)
|
|
217
|
-
|
|
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
|
-
|
|
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]
|
|
@@ -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
|
|
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
|
|