actionpack 6.1.7 → 7.0.4.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +269 -406
- data/MIT-LICENSE +1 -0
- data/README.rdoc +2 -3
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +13 -26
- data/lib/abstract_controller/caching/fragments.rb +2 -2
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +21 -7
- data/lib/abstract_controller/collector.rb +2 -2
- data/lib/abstract_controller/error.rb +1 -1
- data/lib/abstract_controller/helpers.rb +4 -3
- data/lib/abstract_controller/logger.rb +1 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/translation.rb +3 -2
- data/lib/abstract_controller/url_for.rb +4 -6
- data/lib/action_controller/api.rb +6 -6
- data/lib/action_controller/base.rb +5 -4
- data/lib/action_controller/form_builder.rb +2 -2
- data/lib/action_controller/log_subscriber.rb +4 -3
- data/lib/action_controller/metal/conditional_get.rb +39 -2
- data/lib/action_controller/metal/content_security_policy.rb +36 -2
- data/lib/action_controller/metal/cookies.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +5 -13
- data/lib/action_controller/metal/exceptions.rb +19 -30
- data/lib/action_controller/metal/flash.rb +6 -2
- data/lib/action_controller/metal/helpers.rb +2 -2
- data/lib/action_controller/metal/http_authentication.rb +66 -39
- data/lib/action_controller/metal/instrumentation.rb +57 -52
- data/lib/action_controller/metal/live.rb +43 -2
- data/lib/action_controller/metal/mime_responds.rb +3 -3
- data/lib/action_controller/metal/params_wrapper.rb +20 -11
- data/lib/action_controller/metal/permissions_policy.rb +19 -28
- data/lib/action_controller/metal/redirecting.rb +93 -18
- data/lib/action_controller/metal/renderers.rb +10 -11
- data/lib/action_controller/metal/rendering.rb +8 -8
- data/lib/action_controller/metal/request_forgery_protection.rb +78 -29
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/streaming.rb +6 -8
- data/lib/action_controller/metal/strong_parameters.rb +100 -54
- data/lib/action_controller/metal/testing.rb +9 -2
- data/lib/action_controller/metal/url_for.rb +3 -3
- data/lib/action_controller/metal.rb +10 -13
- data/lib/action_controller/railtie.rb +49 -6
- data/lib/action_controller/renderer.rb +1 -1
- data/lib/action_controller/test_case.rb +28 -7
- data/lib/action_controller.rb +2 -5
- data/lib/action_dispatch/http/cache.rb +14 -7
- data/lib/action_dispatch/http/content_security_policy.rb +108 -35
- data/lib/action_dispatch/http/filter_parameters.rb +5 -0
- data/lib/action_dispatch/http/mime_negotiation.rb +15 -5
- data/lib/action_dispatch/http/mime_type.rb +9 -11
- data/lib/action_dispatch/http/parameters.rb +5 -5
- data/lib/action_dispatch/http/permissions_policy.rb +17 -1
- data/lib/action_dispatch/http/request.rb +12 -21
- data/lib/action_dispatch/http/response.rb +3 -16
- data/lib/action_dispatch/http/url.rb +11 -19
- data/lib/action_dispatch/journey/gtg/builder.rb +11 -12
- data/lib/action_dispatch/journey/gtg/simulator.rb +10 -4
- data/lib/action_dispatch/journey/gtg/transition_table.rb +77 -21
- data/lib/action_dispatch/journey/nodes/node.rb +70 -5
- data/lib/action_dispatch/journey/path/pattern.rb +22 -13
- data/lib/action_dispatch/journey/route.rb +6 -13
- data/lib/action_dispatch/journey/router/utils.rb +2 -2
- data/lib/action_dispatch/journey/router.rb +1 -1
- data/lib/action_dispatch/journey/routes.rb +3 -3
- data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
- data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +0 -1
- data/lib/action_dispatch/middleware/cookies.rb +42 -27
- data/lib/action_dispatch/middleware/debug_exceptions.rb +6 -4
- data/lib/action_dispatch/middleware/debug_locks.rb +3 -3
- data/lib/action_dispatch/middleware/exception_wrapper.rb +4 -0
- data/lib/action_dispatch/middleware/executor.rb +3 -0
- data/lib/action_dispatch/middleware/flash.rb +17 -18
- data/lib/action_dispatch/middleware/host_authorization.rb +1 -12
- data/lib/action_dispatch/middleware/remote_ip.rb +16 -4
- data/lib/action_dispatch/middleware/request_id.rb +1 -1
- data/lib/action_dispatch/middleware/server_timing.rb +76 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +1 -1
- data/lib/action_dispatch/middleware/session/cookie_store.rb +9 -9
- data/lib/action_dispatch/middleware/show_exceptions.rb +7 -9
- data/lib/action_dispatch/middleware/stack.rb +27 -9
- data/lib/action_dispatch/middleware/static.rb +2 -6
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -11
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +3 -2
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +2 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +28 -18
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +5 -14
- data/lib/action_dispatch/railtie.rb +8 -2
- data/lib/action_dispatch/request/session.rb +43 -13
- data/lib/action_dispatch/routing/inspector.rb +1 -1
- data/lib/action_dispatch/routing/mapper.rb +59 -83
- data/lib/action_dispatch/routing/redirection.rb +5 -2
- data/lib/action_dispatch/routing/route_set.rb +17 -7
- data/lib/action_dispatch/routing/routes_proxy.rb +1 -1
- data/lib/action_dispatch/routing/url_for.rb +4 -5
- data/lib/action_dispatch/routing.rb +5 -6
- data/lib/action_dispatch/system_test_case.rb +5 -5
- data/lib/action_dispatch/system_testing/browser.rb +2 -12
- data/lib/action_dispatch/system_testing/driver.rb +35 -11
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +11 -7
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +0 -8
- data/lib/action_dispatch/testing/assertions/routing.rb +3 -2
- data/lib/action_dispatch/testing/assertions.rb +2 -5
- data/lib/action_dispatch/testing/integration.rb +6 -8
- data/lib/action_dispatch/testing/test_process.rb +3 -29
- data/lib/action_dispatch/testing/test_response.rb +20 -2
- data/lib/action_dispatch.rb +1 -0
- data/lib/action_pack/gem_version.rb +5 -5
- data/lib/action_pack/version.rb +1 -1
- metadata +16 -15
data/lib/action_controller.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "abstract_controller"
|
4
4
|
require "action_dispatch"
|
5
5
|
require "action_controller/metal/strong_parameters"
|
6
|
+
require "action_controller/metal/exceptions"
|
6
7
|
|
7
8
|
module ActionController
|
8
9
|
extend ActiveSupport::Autoload
|
@@ -18,10 +19,6 @@ module ActionController
|
|
18
19
|
end
|
19
20
|
|
20
21
|
autoload_under "metal" do
|
21
|
-
eager_autoload do
|
22
|
-
autoload :Live
|
23
|
-
end
|
24
|
-
|
25
22
|
autoload :ConditionalGet
|
26
23
|
autoload :ContentSecurityPolicy
|
27
24
|
autoload :Cookies
|
@@ -37,6 +34,7 @@ module ActionController
|
|
37
34
|
autoload :BasicImplicitRender
|
38
35
|
autoload :ImplicitRender
|
39
36
|
autoload :Instrumentation
|
37
|
+
autoload :Live
|
40
38
|
autoload :Logging
|
41
39
|
autoload :MimeResponds
|
42
40
|
autoload :ParamsWrapper
|
@@ -65,5 +63,4 @@ require "active_support/core_ext/module/attribute_accessors"
|
|
65
63
|
require "active_support/core_ext/load_error"
|
66
64
|
require "active_support/core_ext/module/attr_internal"
|
67
65
|
require "active_support/core_ext/name_error"
|
68
|
-
require "active_support/core_ext/uri"
|
69
66
|
require "active_support/inflector"
|
@@ -18,7 +18,7 @@ module ActionDispatch
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def if_none_match_etags
|
21
|
-
if_none_match ? if_none_match.split(
|
21
|
+
if_none_match ? if_none_match.split(",").each(&:strip!) : []
|
22
22
|
end
|
23
23
|
|
24
24
|
def not_modified?(modified_at)
|
@@ -187,13 +187,20 @@ module ActionDispatch
|
|
187
187
|
|
188
188
|
return if control.empty? && cache_control.empty? # Let middleware handle default behavior
|
189
189
|
|
190
|
-
if
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
190
|
+
if cache_control.any?
|
191
|
+
# Any caching directive coming from a controller overrides
|
192
|
+
# no-cache/no-store in the default Cache-Control header.
|
193
|
+
control.delete(:no_cache)
|
194
|
+
control.delete(:no_store)
|
195
195
|
|
196
|
-
|
196
|
+
if extras = control.delete(:extras)
|
197
|
+
cache_control[:extras] ||= []
|
198
|
+
cache_control[:extras] += extras
|
199
|
+
cache_control[:extras].uniq!
|
200
|
+
end
|
201
|
+
|
202
|
+
control.merge! cache_control
|
203
|
+
end
|
197
204
|
|
198
205
|
options = []
|
199
206
|
|
@@ -3,7 +3,24 @@
|
|
3
3
|
require "active_support/core_ext/object/deep_dup"
|
4
4
|
require "active_support/core_ext/array/wrap"
|
5
5
|
|
6
|
-
module ActionDispatch
|
6
|
+
module ActionDispatch # :nodoc:
|
7
|
+
# Configures the HTTP
|
8
|
+
# {Content-Security-Policy}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy]
|
9
|
+
# response header to help protect against XSS and injection attacks.
|
10
|
+
#
|
11
|
+
# Example global policy:
|
12
|
+
#
|
13
|
+
# Rails.application.config.content_security_policy do |policy|
|
14
|
+
# policy.default_src :self, :https
|
15
|
+
# policy.font_src :self, :https, :data
|
16
|
+
# policy.img_src :self, :https, :data
|
17
|
+
# policy.object_src :none
|
18
|
+
# policy.script_src :self, :https
|
19
|
+
# policy.style_src :self, :https
|
20
|
+
#
|
21
|
+
# # Specify URI for violation reports
|
22
|
+
# policy.report_uri "/csp-violation-report-endpoint"
|
23
|
+
# end
|
7
24
|
class ContentSecurityPolicy
|
8
25
|
class Middleware
|
9
26
|
CONTENT_TYPE = "Content-Type"
|
@@ -100,43 +117,47 @@ module ActionDispatch #:nodoc:
|
|
100
117
|
end
|
101
118
|
|
102
119
|
MAPPINGS = {
|
103
|
-
self:
|
104
|
-
unsafe_eval:
|
105
|
-
unsafe_inline:
|
106
|
-
none:
|
107
|
-
http:
|
108
|
-
https:
|
109
|
-
data:
|
110
|
-
mediastream:
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
120
|
+
self: "'self'",
|
121
|
+
unsafe_eval: "'unsafe-eval'",
|
122
|
+
unsafe_inline: "'unsafe-inline'",
|
123
|
+
none: "'none'",
|
124
|
+
http: "http:",
|
125
|
+
https: "https:",
|
126
|
+
data: "data:",
|
127
|
+
mediastream: "mediastream:",
|
128
|
+
allow_duplicates: "'allow-duplicates'",
|
129
|
+
blob: "blob:",
|
130
|
+
filesystem: "filesystem:",
|
131
|
+
report_sample: "'report-sample'",
|
132
|
+
script: "'script'",
|
133
|
+
strict_dynamic: "'strict-dynamic'",
|
134
|
+
ws: "ws:",
|
135
|
+
wss: "wss:"
|
117
136
|
}.freeze
|
118
137
|
|
119
138
|
DIRECTIVES = {
|
120
|
-
base_uri:
|
121
|
-
child_src:
|
122
|
-
connect_src:
|
123
|
-
default_src:
|
124
|
-
font_src:
|
125
|
-
form_action:
|
126
|
-
frame_ancestors:
|
127
|
-
frame_src:
|
128
|
-
img_src:
|
129
|
-
manifest_src:
|
130
|
-
media_src:
|
131
|
-
object_src:
|
132
|
-
prefetch_src:
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
139
|
+
base_uri: "base-uri",
|
140
|
+
child_src: "child-src",
|
141
|
+
connect_src: "connect-src",
|
142
|
+
default_src: "default-src",
|
143
|
+
font_src: "font-src",
|
144
|
+
form_action: "form-action",
|
145
|
+
frame_ancestors: "frame-ancestors",
|
146
|
+
frame_src: "frame-src",
|
147
|
+
img_src: "img-src",
|
148
|
+
manifest_src: "manifest-src",
|
149
|
+
media_src: "media-src",
|
150
|
+
object_src: "object-src",
|
151
|
+
prefetch_src: "prefetch-src",
|
152
|
+
require_trusted_types_for: "require-trusted-types-for",
|
153
|
+
script_src: "script-src",
|
154
|
+
script_src_attr: "script-src-attr",
|
155
|
+
script_src_elem: "script-src-elem",
|
156
|
+
style_src: "style-src",
|
157
|
+
style_src_attr: "style-src-attr",
|
158
|
+
style_src_elem: "style-src-elem",
|
159
|
+
trusted_types: "trusted-types",
|
160
|
+
worker_src: "worker-src"
|
140
161
|
}.freeze
|
141
162
|
|
142
163
|
DEFAULT_NONCE_DIRECTIVES = %w[script-src style-src].freeze
|
@@ -164,6 +185,15 @@ module ActionDispatch #:nodoc:
|
|
164
185
|
end
|
165
186
|
end
|
166
187
|
|
188
|
+
# Specify whether to prevent the user agent from loading any assets over
|
189
|
+
# HTTP when the page uses HTTPS:
|
190
|
+
#
|
191
|
+
# policy.block_all_mixed_content
|
192
|
+
#
|
193
|
+
# Pass +false+ to allow it again:
|
194
|
+
#
|
195
|
+
# policy.block_all_mixed_content false
|
196
|
+
#
|
167
197
|
def block_all_mixed_content(enabled = true)
|
168
198
|
if enabled
|
169
199
|
@directives["block-all-mixed-content"] = true
|
@@ -172,6 +202,14 @@ module ActionDispatch #:nodoc:
|
|
172
202
|
end
|
173
203
|
end
|
174
204
|
|
205
|
+
# Restricts the set of plugins that can be embedded:
|
206
|
+
#
|
207
|
+
# policy.plugin_types "application/x-shockwave-flash"
|
208
|
+
#
|
209
|
+
# Leave empty to allow all plugins:
|
210
|
+
#
|
211
|
+
# policy.plugin_types
|
212
|
+
#
|
175
213
|
def plugin_types(*types)
|
176
214
|
if types.first
|
177
215
|
@directives["plugin-types"] = types
|
@@ -180,10 +218,24 @@ module ActionDispatch #:nodoc:
|
|
180
218
|
end
|
181
219
|
end
|
182
220
|
|
221
|
+
# Enable the {report-uri}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri]
|
222
|
+
# directive. Violation reports will be sent to the specified URI:
|
223
|
+
#
|
224
|
+
# policy.report_uri "/csp-violation-report-endpoint"
|
225
|
+
#
|
183
226
|
def report_uri(uri)
|
184
227
|
@directives["report-uri"] = [uri]
|
185
228
|
end
|
186
229
|
|
230
|
+
# Specify asset types for which {Subresource Integrity}[https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity]
|
231
|
+
# is required:
|
232
|
+
#
|
233
|
+
# policy.require_sri_for :script, :style
|
234
|
+
#
|
235
|
+
# Leave empty to not require Subresource Integrity:
|
236
|
+
#
|
237
|
+
# policy.require_sri_for
|
238
|
+
#
|
187
239
|
def require_sri_for(*types)
|
188
240
|
if types.first
|
189
241
|
@directives["require-sri-for"] = types
|
@@ -192,6 +244,19 @@ module ActionDispatch #:nodoc:
|
|
192
244
|
end
|
193
245
|
end
|
194
246
|
|
247
|
+
# Specify whether a {sandbox}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox]
|
248
|
+
# should be enabled for the requested resource:
|
249
|
+
#
|
250
|
+
# policy.sandbox
|
251
|
+
#
|
252
|
+
# Values can be passed as arguments:
|
253
|
+
#
|
254
|
+
# policy.sandbox "allow-scripts", "allow-modals"
|
255
|
+
#
|
256
|
+
# Pass +false+ to disable the sandbox:
|
257
|
+
#
|
258
|
+
# policy.sandbox false
|
259
|
+
#
|
195
260
|
def sandbox(*values)
|
196
261
|
if values.empty?
|
197
262
|
@directives["sandbox"] = true
|
@@ -202,6 +267,14 @@ module ActionDispatch #:nodoc:
|
|
202
267
|
end
|
203
268
|
end
|
204
269
|
|
270
|
+
# Specify whether user agents should treat any assets over HTTP as HTTPS:
|
271
|
+
#
|
272
|
+
# policy.upgrade_insecure_requests
|
273
|
+
#
|
274
|
+
# Pass +false+ to disable it:
|
275
|
+
#
|
276
|
+
# policy.upgrade_insecure_requests false
|
277
|
+
#
|
205
278
|
def upgrade_insecure_requests(enabled = true)
|
206
279
|
if enabled
|
207
280
|
@directives["upgrade-insecure-requests"] = true
|
@@ -18,6 +18,11 @@ module ActionDispatch
|
|
18
18
|
# env["action_dispatch.parameter_filter"] = [:foo, "bar"]
|
19
19
|
# => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
|
20
20
|
#
|
21
|
+
# env["action_dispatch.parameter_filter"] = [ /\Apin\z/i, /\Apin_/i ]
|
22
|
+
# => replaces the value for the exact (case-insensitive) key 'pin' and all
|
23
|
+
# (case-insensitive) keys beginning with 'pin_', with "[FILTERED]"
|
24
|
+
# Does not match keys with 'pin' as a substring, such as 'shipping_id'.
|
25
|
+
#
|
21
26
|
# env["action_dispatch.parameter_filter"] = [ "credit_card.code" ]
|
22
27
|
# => replaces { credit_card: {code: "xxxx"} } with "[FILTERED]", does not
|
23
28
|
# change { file: { code: "xxxx"} }
|
@@ -16,12 +16,13 @@ module ActionDispatch
|
|
16
16
|
|
17
17
|
included do
|
18
18
|
mattr_accessor :ignore_accept_header, default: false
|
19
|
+
cattr_accessor :return_only_media_type_on_content_type, default: false
|
19
20
|
end
|
20
21
|
|
21
22
|
# The MIME type of the HTTP request, such as Mime[:xml].
|
22
23
|
def content_mime_type
|
23
24
|
fetch_header("action_dispatch.request.content_type") do |k|
|
24
|
-
v = if get_header("CONTENT_TYPE") =~ /^([
|
25
|
+
v = if get_header("CONTENT_TYPE") =~ /^([^,;]*)/
|
25
26
|
Mime::Type.lookup($1.strip.downcase)
|
26
27
|
else
|
27
28
|
nil
|
@@ -33,7 +34,16 @@ module ActionDispatch
|
|
33
34
|
end
|
34
35
|
|
35
36
|
def content_type
|
36
|
-
|
37
|
+
if self.class.return_only_media_type_on_content_type
|
38
|
+
ActiveSupport::Deprecation.warn(
|
39
|
+
"Rails 7.1 will return Content-Type header without modification." \
|
40
|
+
" If you want just the MIME type, please use `#media_type` instead."
|
41
|
+
)
|
42
|
+
|
43
|
+
content_mime_type&.to_s
|
44
|
+
else
|
45
|
+
super
|
46
|
+
end
|
37
47
|
end
|
38
48
|
|
39
49
|
def has_content_type? # :nodoc:
|
@@ -92,7 +102,7 @@ module ActionDispatch
|
|
92
102
|
def variant=(variant)
|
93
103
|
variant = Array(variant)
|
94
104
|
|
95
|
-
if variant.all?
|
105
|
+
if variant.all?(Symbol)
|
96
106
|
@variant = ActiveSupport::ArrayInquirer.new(variant)
|
97
107
|
else
|
98
108
|
raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols."
|
@@ -122,8 +132,8 @@ module ActionDispatch
|
|
122
132
|
# Sets the \formats by string extensions. This differs from #format= by allowing you
|
123
133
|
# to set multiple, ordered formats, which is useful when you want to have a fallback.
|
124
134
|
#
|
125
|
-
# In this example, the
|
126
|
-
# to the
|
135
|
+
# In this example, the +:iphone+ format will be used if it's available, otherwise it'll fallback
|
136
|
+
# to the +:html+ format.
|
127
137
|
#
|
128
138
|
# class ApplicationController < ActionController::Base
|
129
139
|
# before_action :adjust_format_for_iphone_with_html_fallback
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "singleton"
|
4
|
-
require "active_support/core_ext/symbol/starts_ends_with"
|
5
4
|
|
6
5
|
module Mime
|
7
6
|
class Mimes
|
@@ -14,8 +13,8 @@ module Mime
|
|
14
13
|
@symbols = []
|
15
14
|
end
|
16
15
|
|
17
|
-
def each
|
18
|
-
@mimes.each
|
16
|
+
def each(&block)
|
17
|
+
@mimes.each(&block)
|
19
18
|
end
|
20
19
|
|
21
20
|
def <<(type)
|
@@ -43,9 +42,9 @@ module Mime
|
|
43
42
|
Type.lookup_by_extension(type)
|
44
43
|
end
|
45
44
|
|
46
|
-
def fetch(type)
|
45
|
+
def fetch(type, &block)
|
47
46
|
return type if type.is_a?(Type)
|
48
|
-
EXTENSION_LOOKUP.fetch(type.to_s)
|
47
|
+
EXTENSION_LOOKUP.fetch(type.to_s, &block)
|
49
48
|
end
|
50
49
|
end
|
51
50
|
|
@@ -68,7 +67,7 @@ module Mime
|
|
68
67
|
@register_callbacks = []
|
69
68
|
|
70
69
|
# A simple helper class used in parsing the accept header.
|
71
|
-
class AcceptItem
|
70
|
+
class AcceptItem # :nodoc:
|
72
71
|
attr_accessor :index, :name, :q
|
73
72
|
alias :to_s :name
|
74
73
|
|
@@ -86,7 +85,7 @@ module Mime
|
|
86
85
|
end
|
87
86
|
end
|
88
87
|
|
89
|
-
class AcceptList
|
88
|
+
class AcceptList # :nodoc:
|
90
89
|
def self.sort!(list)
|
91
90
|
list.sort!
|
92
91
|
|
@@ -226,10 +225,9 @@ module Mime
|
|
226
225
|
attr_reader :hash
|
227
226
|
|
228
227
|
MIME_NAME = "[a-zA-Z0-9][a-zA-Z0-9#{Regexp.escape('!#$&-^_.+')}]{0,126}"
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
MIME_REGEXP = /\A(?:\*\/\*|#{MIME_NAME}\/(?:\*|#{MIME_NAME})(?>\s*#{MIME_PARAMETER}\s*)*)\z/
|
228
|
+
MIME_PARAMETER_VALUE = "#{Regexp.escape('"')}?#{MIME_NAME}#{Regexp.escape('"')}?"
|
229
|
+
MIME_PARAMETER = "\s*;\s*#{MIME_NAME}(?:=#{MIME_PARAMETER_VALUE})?"
|
230
|
+
MIME_REGEXP = /\A(?:\*\/\*|#{MIME_NAME}\/(?:\*|#{MIME_NAME})(?>#{MIME_PARAMETER})*\s*)\z/
|
233
231
|
|
234
232
|
class InvalidMimeType < StandardError; end
|
235
233
|
|
@@ -17,8 +17,8 @@ module ActionDispatch
|
|
17
17
|
# Raised when raw data from the request cannot be parsed by the parser
|
18
18
|
# defined for request's content MIME type.
|
19
19
|
class ParseError < StandardError
|
20
|
-
def initialize
|
21
|
-
super(
|
20
|
+
def initialize(message = $!.message)
|
21
|
+
super(message)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -62,7 +62,7 @@ module ActionDispatch
|
|
62
62
|
end
|
63
63
|
alias :params :parameters
|
64
64
|
|
65
|
-
def path_parameters=(parameters)
|
65
|
+
def path_parameters=(parameters) # :nodoc:
|
66
66
|
delete_header("action_dispatch.request.parameters")
|
67
67
|
|
68
68
|
parameters = Request::Utils.set_binary_encoding(self, parameters, parameters[:controller], parameters[:action])
|
@@ -78,7 +78,7 @@ module ActionDispatch
|
|
78
78
|
# Returns a hash with the \parameters used to form the \path of the request.
|
79
79
|
# Returned hash keys are strings:
|
80
80
|
#
|
81
|
-
# {
|
81
|
+
# { action: "my_action", controller: "my_controller" }
|
82
82
|
def path_parameters
|
83
83
|
get_header(PARAMETERS_KEY) || set_header(PARAMETERS_KEY, {})
|
84
84
|
end
|
@@ -93,7 +93,7 @@ module ActionDispatch
|
|
93
93
|
strategy.call(raw_post)
|
94
94
|
rescue # JSON or Ruby code block errors.
|
95
95
|
log_parse_error_once
|
96
|
-
raise ParseError
|
96
|
+
raise ParseError, "Error occurred while parsing request parameters"
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
@@ -2,7 +2,23 @@
|
|
2
2
|
|
3
3
|
require "active_support/core_ext/object/deep_dup"
|
4
4
|
|
5
|
-
module ActionDispatch
|
5
|
+
module ActionDispatch # :nodoc:
|
6
|
+
# Configures the HTTP
|
7
|
+
# {Feature-Policy}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy]
|
8
|
+
# response header to specify which browser features the current document and
|
9
|
+
# its iframes can use.
|
10
|
+
#
|
11
|
+
# Example global policy:
|
12
|
+
#
|
13
|
+
# Rails.application.config.permissions_policy do |policy|
|
14
|
+
# policy.camera :none
|
15
|
+
# policy.gyroscope :none
|
16
|
+
# policy.microphone :none
|
17
|
+
# policy.usb :none
|
18
|
+
# policy.fullscreen :self
|
19
|
+
# policy.payment :self, "https://secure.example.com"
|
20
|
+
# end
|
21
|
+
#
|
6
22
|
class PermissionsPolicy
|
7
23
|
class Middleware
|
8
24
|
CONTENT_TYPE = "Content-Type"
|
@@ -42,11 +42,8 @@ module ActionDispatch
|
|
42
42
|
HTTP_NEGOTIATE HTTP_PRAGMA HTTP_CLIENT_IP
|
43
43
|
HTTP_X_FORWARDED_FOR HTTP_ORIGIN HTTP_VERSION
|
44
44
|
HTTP_X_CSRF_TOKEN HTTP_X_REQUEST_ID HTTP_X_FORWARDED_HOST
|
45
|
-
SERVER_ADDR
|
46
45
|
].freeze
|
47
46
|
|
48
|
-
# TODO: Remove SERVER_ADDR when we remove support to Rack 2.1.
|
49
|
-
# See https://github.com/rack/rack/commit/c173b188d81ee437b588c1e046a1c9f031dea550
|
50
47
|
ENV_METHODS.each do |env|
|
51
48
|
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
52
49
|
# frozen_string_literal: true
|
@@ -90,7 +87,7 @@ module ActionDispatch
|
|
90
87
|
controller_param = name.underscore
|
91
88
|
const_name = controller_param.camelize << "Controller"
|
92
89
|
begin
|
93
|
-
|
90
|
+
const_name.constantize
|
94
91
|
rescue NameError => error
|
95
92
|
if error.missing_name == const_name || const_name.start_with?("#{error.missing_name}::")
|
96
93
|
raise MissingController.new(error.message, error.name)
|
@@ -165,7 +162,7 @@ module ActionDispatch
|
|
165
162
|
set_header(routes.env_key, name.dup)
|
166
163
|
end
|
167
164
|
|
168
|
-
def request_method=(request_method)
|
165
|
+
def request_method=(request_method) # :nodoc:
|
169
166
|
if check_method(request_method)
|
170
167
|
@request_method = set_header("REQUEST_METHOD", request_method)
|
171
168
|
end
|
@@ -266,7 +263,7 @@ module ActionDispatch
|
|
266
263
|
# # get "/articles"
|
267
264
|
# request.media_type # => "application/x-www-form-urlencoded"
|
268
265
|
def media_type
|
269
|
-
content_mime_type
|
266
|
+
content_mime_type&.to_s
|
270
267
|
end
|
271
268
|
|
272
269
|
# Returns the content length of the request as an integer.
|
@@ -301,8 +298,8 @@ module ActionDispatch
|
|
301
298
|
ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
|
302
299
|
|
303
300
|
# Returns the unique request id, which is based on either the X-Request-Id header that can
|
304
|
-
# be generated by a firewall, load balancer, or web server or by the RequestId middleware
|
305
|
-
# (which sets the action_dispatch.request_id environment variable).
|
301
|
+
# be generated by a firewall, load balancer, or web server, or by the RequestId middleware
|
302
|
+
# (which sets the +action_dispatch.request_id+ environment variable).
|
306
303
|
#
|
307
304
|
# This unique ID is useful for tracing a request from end-to-end as part of logging or debugging.
|
308
305
|
# This relies on the Rack variable set by the ActionDispatch::RequestId middleware.
|
@@ -355,21 +352,15 @@ module ActionDispatch
|
|
355
352
|
FORM_DATA_MEDIA_TYPES.include?(media_type)
|
356
353
|
end
|
357
354
|
|
358
|
-
def body_stream
|
355
|
+
def body_stream # :nodoc:
|
359
356
|
get_header("rack.input")
|
360
357
|
end
|
361
358
|
|
362
|
-
# TODO This should be broken apart into AD::Request::Session and probably
|
363
|
-
# be included by the session middleware.
|
364
359
|
def reset_session
|
365
|
-
|
366
|
-
session.destroy
|
367
|
-
else
|
368
|
-
self.session = {}
|
369
|
-
end
|
360
|
+
session.destroy
|
370
361
|
end
|
371
362
|
|
372
|
-
def session=(session)
|
363
|
+
def session=(session) # :nodoc:
|
373
364
|
Session.set self, session
|
374
365
|
end
|
375
366
|
|
@@ -434,10 +425,6 @@ module ActionDispatch
|
|
434
425
|
def commit_flash
|
435
426
|
end
|
436
427
|
|
437
|
-
def ssl?
|
438
|
-
super || scheme == "wss"
|
439
|
-
end
|
440
|
-
|
441
428
|
def inspect # :nodoc:
|
442
429
|
"#<#{self.class.name} #{method} #{original_url.dump} for #{remote_ip}>"
|
443
430
|
end
|
@@ -447,6 +434,10 @@ module ActionDispatch
|
|
447
434
|
HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS[0...-1].join(', ')}, and #{HTTP_METHODS[-1]}")
|
448
435
|
name
|
449
436
|
end
|
437
|
+
|
438
|
+
def default_session
|
439
|
+
Session.disabled(self)
|
440
|
+
end
|
450
441
|
end
|
451
442
|
end
|
452
443
|
|
@@ -21,9 +21,8 @@ module ActionDispatch # :nodoc:
|
|
21
21
|
# Nevertheless, integration tests may want to inspect controller responses in
|
22
22
|
# more detail, and that's when \Response can be useful for application
|
23
23
|
# developers. Integration test methods such as
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# TestResponse (which are of course also of type \Response).
|
24
|
+
# Integration::RequestHelpers#get and Integration::RequestHelpers#post return
|
25
|
+
# objects of type TestResponse (which are of course also of type \Response).
|
27
26
|
#
|
28
27
|
# For example, the following demo integration test prints the body of the
|
29
28
|
# controller response to the console:
|
@@ -86,18 +85,6 @@ module ActionDispatch # :nodoc:
|
|
86
85
|
cattr_accessor :default_charset, default: "utf-8"
|
87
86
|
cattr_accessor :default_headers
|
88
87
|
|
89
|
-
def self.return_only_media_type_on_content_type=(*)
|
90
|
-
ActiveSupport::Deprecation.warn(
|
91
|
-
".return_only_media_type_on_content_type= is dreprecated with no replacement and will be removed in 7.0."
|
92
|
-
)
|
93
|
-
end
|
94
|
-
|
95
|
-
def self.return_only_media_type_on_content_type
|
96
|
-
ActiveSupport::Deprecation.warn(
|
97
|
-
".return_only_media_type_on_content_type is dreprecated with no replacement and will be removed in 7.0."
|
98
|
-
)
|
99
|
-
end
|
100
|
-
|
101
88
|
include Rack::Response::Helpers
|
102
89
|
# Aliasing these off because AD::Http::Cache::Response defines them.
|
103
90
|
alias :_cache_control :cache_control
|
@@ -336,7 +323,7 @@ module ActionDispatch # :nodoc:
|
|
336
323
|
# Avoid having to pass an open file handle as the response body.
|
337
324
|
# Rack::Sendfile will usually intercept the response and uses
|
338
325
|
# the path directly, so there is no reason to open the file.
|
339
|
-
class FileBody
|
326
|
+
class FileBody # :nodoc:
|
340
327
|
attr_reader :to_path
|
341
328
|
|
342
329
|
def initialize(path)
|
@@ -71,7 +71,8 @@ module ActionDispatch
|
|
71
71
|
path = options[:script_name].to_s.chomp("/")
|
72
72
|
path << options[:path] if options.key?(:path)
|
73
73
|
|
74
|
-
|
74
|
+
path = "/" if options[:trailing_slash] && path.blank?
|
75
|
+
|
75
76
|
add_params(path, options[:params]) if options.key?(:params)
|
76
77
|
add_anchor(path, options[:anchor]) if options.key?(:anchor)
|
77
78
|
|
@@ -101,14 +102,6 @@ module ActionDispatch
|
|
101
102
|
parts[0..-(tld_length + 2)]
|
102
103
|
end
|
103
104
|
|
104
|
-
def add_trailing_slash(path)
|
105
|
-
if path.include?("?")
|
106
|
-
path.sub!(/\?/, '/\&')
|
107
|
-
elsif !path.include?(".")
|
108
|
-
path.sub!(/[^\/]\z|\A\z/, '\&/')
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
105
|
def build_host_url(host, port, protocol, options, path)
|
113
106
|
if match = host.match(HOST_REGEXP)
|
114
107
|
protocol ||= match[1] unless protocol == false
|
@@ -222,7 +215,7 @@ module ActionDispatch
|
|
222
215
|
if forwarded = x_forwarded_host.presence
|
223
216
|
forwarded.split(/,\s?/).last
|
224
217
|
else
|
225
|
-
get_header("HTTP_HOST") || "#{server_name
|
218
|
+
get_header("HTTP_HOST") || "#{server_name}:#{get_header('SERVER_PORT')}"
|
226
219
|
end
|
227
220
|
end
|
228
221
|
|
@@ -258,12 +251,10 @@ module ActionDispatch
|
|
258
251
|
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
259
252
|
# req.port # => 8080
|
260
253
|
def port
|
261
|
-
@port ||=
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
standard_port
|
266
|
-
end
|
254
|
+
@port ||= if raw_host_with_port =~ /:(\d+)$/
|
255
|
+
$1.to_i
|
256
|
+
else
|
257
|
+
standard_port
|
267
258
|
end
|
268
259
|
end
|
269
260
|
|
@@ -272,9 +263,10 @@ module ActionDispatch
|
|
272
263
|
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
273
264
|
# req.standard_port # => 80
|
274
265
|
def standard_port
|
275
|
-
|
276
|
-
|
277
|
-
else
|
266
|
+
if "https://" == protocol
|
267
|
+
443
|
268
|
+
else
|
269
|
+
80
|
278
270
|
end
|
279
271
|
end
|
280
272
|
|