actionpack 6.1.7.5 → 7.1.3.1
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 +355 -435
- data/MIT-LICENSE +2 -1
- data/README.rdoc +6 -7
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +33 -37
- data/lib/abstract_controller/caching/fragments.rb +4 -2
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +50 -11
- data/lib/abstract_controller/collector.rb +2 -2
- data/lib/abstract_controller/deprecator.rb +7 -0
- data/lib/abstract_controller/error.rb +1 -1
- data/lib/abstract_controller/helpers.rb +78 -30
- data/lib/abstract_controller/logger.rb +1 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +3 -16
- data/lib/abstract_controller/rendering.rb +12 -14
- data/lib/abstract_controller/translation.rb +26 -7
- data/lib/abstract_controller/url_for.rb +6 -6
- data/lib/abstract_controller.rb +6 -0
- data/lib/action_controller/api.rb +12 -10
- data/lib/action_controller/base.rb +8 -21
- data/lib/action_controller/caching.rb +2 -0
- data/lib/action_controller/deprecator.rb +7 -0
- data/lib/action_controller/form_builder.rb +4 -2
- data/lib/action_controller/log_subscriber.rb +20 -7
- data/lib/action_controller/metal/basic_implicit_render.rb +3 -1
- data/lib/action_controller/metal/conditional_get.rb +137 -102
- data/lib/action_controller/metal/content_security_policy.rb +37 -3
- data/lib/action_controller/metal/cookies.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +25 -31
- data/lib/action_controller/metal/default_headers.rb +2 -0
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
- data/lib/action_controller/metal/exceptions.rb +27 -30
- data/lib/action_controller/metal/flash.rb +6 -2
- data/lib/action_controller/metal/head.rb +9 -7
- data/lib/action_controller/metal/helpers.rb +5 -16
- data/lib/action_controller/metal/http_authentication.rb +78 -42
- data/lib/action_controller/metal/implicit_render.rb +5 -3
- data/lib/action_controller/metal/instrumentation.rb +62 -50
- data/lib/action_controller/metal/live.rb +67 -2
- data/lib/action_controller/metal/mime_responds.rb +5 -5
- data/lib/action_controller/metal/params_wrapper.rb +24 -13
- data/lib/action_controller/metal/permissions_policy.rb +20 -29
- data/lib/action_controller/metal/redirecting.rb +96 -23
- data/lib/action_controller/metal/renderers.rb +14 -15
- data/lib/action_controller/metal/rendering.rb +121 -16
- data/lib/action_controller/metal/request_forgery_protection.rb +208 -68
- data/lib/action_controller/metal/rescue.rb +7 -4
- data/lib/action_controller/metal/streaming.rb +74 -36
- data/lib/action_controller/metal/strong_parameters.rb +254 -151
- data/lib/action_controller/metal/testing.rb +9 -2
- data/lib/action_controller/metal/url_for.rb +10 -5
- data/lib/action_controller/metal.rb +89 -34
- data/lib/action_controller/railtie.rb +66 -9
- data/lib/action_controller/renderer.rb +99 -85
- data/lib/action_controller/test_case.rb +42 -11
- data/lib/action_controller.rb +10 -6
- data/lib/action_dispatch/constants.rb +32 -0
- data/lib/action_dispatch/deprecator.rb +7 -0
- data/lib/action_dispatch/http/cache.rb +21 -16
- data/lib/action_dispatch/http/content_security_policy.rb +122 -44
- data/lib/action_dispatch/http/filter_parameters.rb +14 -23
- data/lib/action_dispatch/http/headers.rb +3 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +25 -15
- data/lib/action_dispatch/http/mime_type.rb +43 -22
- data/lib/action_dispatch/http/mime_types.rb +3 -1
- data/lib/action_dispatch/http/parameters.rb +6 -6
- data/lib/action_dispatch/http/permissions_policy.rb +57 -19
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +75 -51
- data/lib/action_dispatch/http/response.rb +81 -77
- data/lib/action_dispatch/http/upload.rb +15 -2
- data/lib/action_dispatch/http/url.rb +11 -19
- data/lib/action_dispatch/journey/formatter.rb +8 -2
- 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 +36 -27
- data/lib/action_dispatch/journey/route.rb +8 -14
- data/lib/action_dispatch/journey/router/utils.rb +2 -2
- data/lib/action_dispatch/journey/router.rb +10 -9
- data/lib/action_dispatch/journey/routes.rb +5 -5
- 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/log_subscriber.rb +23 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -7
- data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -0
- data/lib/action_dispatch/middleware/cookies.rb +97 -107
- data/lib/action_dispatch/middleware/debug_exceptions.rb +31 -28
- data/lib/action_dispatch/middleware/debug_locks.rb +7 -4
- data/lib/action_dispatch/middleware/debug_view.rb +7 -2
- data/lib/action_dispatch/middleware/exception_wrapper.rb +190 -27
- data/lib/action_dispatch/middleware/executor.rb +3 -0
- data/lib/action_dispatch/middleware/flash.rb +24 -18
- data/lib/action_dispatch/middleware/host_authorization.rb +19 -20
- data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
- data/lib/action_dispatch/middleware/reloader.rb +7 -5
- data/lib/action_dispatch/middleware/remote_ip.rb +32 -19
- data/lib/action_dispatch/middleware/request_id.rb +5 -3
- data/lib/action_dispatch/middleware/server_timing.rb +76 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +6 -1
- data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +19 -13
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +30 -25
- data/lib/action_dispatch/middleware/ssl.rb +18 -6
- data/lib/action_dispatch/middleware/stack.rb +34 -11
- data/lib/action_dispatch/middleware/static.rb +16 -16
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +5 -5
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -11
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +10 -5
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +7 -3
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +9 -9
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +45 -18
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -15
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +6 -6
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -55
- data/lib/action_dispatch/railtie.rb +20 -4
- data/lib/action_dispatch/request/session.rb +59 -19
- data/lib/action_dispatch/request/utils.rb +8 -3
- data/lib/action_dispatch/routing/inspector.rb +55 -7
- data/lib/action_dispatch/routing/mapper.rb +117 -107
- data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
- data/lib/action_dispatch/routing/redirection.rb +20 -8
- data/lib/action_dispatch/routing/route_set.rb +67 -27
- data/lib/action_dispatch/routing/routes_proxy.rb +11 -16
- data/lib/action_dispatch/routing/url_for.rb +29 -26
- data/lib/action_dispatch/routing.rb +12 -13
- data/lib/action_dispatch/system_test_case.rb +8 -8
- data/lib/action_dispatch/system_testing/browser.rb +20 -29
- data/lib/action_dispatch/system_testing/driver.rb +34 -18
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +35 -20
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +0 -8
- data/lib/action_dispatch/testing/assertion_response.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +14 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +70 -30
- data/lib/action_dispatch/testing/assertions.rb +3 -4
- data/lib/action_dispatch/testing/integration.rb +33 -25
- data/lib/action_dispatch/testing/request_encoder.rb +4 -1
- data/lib/action_dispatch/testing/test_process.rb +5 -30
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +34 -2
- data/lib/action_dispatch.rb +38 -4
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_pack.rb +1 -1
- metadata +67 -30
@@ -16,12 +16,26 @@ module ActionDispatch
|
|
16
16
|
|
17
17
|
included do
|
18
18
|
mattr_accessor :ignore_accept_header, default: false
|
19
|
+
|
20
|
+
def return_only_media_type_on_content_type=(value)
|
21
|
+
ActionDispatch.deprecator.warn(
|
22
|
+
"`config.action_dispatch.return_only_request_media_type_on_content_type` is deprecated and will" \
|
23
|
+
" be removed in Rails 7.2."
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def return_only_media_type_on_content_type
|
28
|
+
ActionDispatch.deprecator.warn(
|
29
|
+
"`config.action_dispatch.return_only_request_media_type_on_content_type` is deprecated and will" \
|
30
|
+
" be removed in Rails 7.2."
|
31
|
+
)
|
32
|
+
end
|
19
33
|
end
|
20
34
|
|
21
35
|
# The MIME type of the HTTP request, such as Mime[:xml].
|
22
36
|
def content_mime_type
|
23
37
|
fetch_header("action_dispatch.request.content_type") do |k|
|
24
|
-
v = if get_header("CONTENT_TYPE") =~ /^([
|
38
|
+
v = if get_header("CONTENT_TYPE") =~ /^([^,;]*)/
|
25
39
|
Mime::Type.lookup($1.strip.downcase)
|
26
40
|
else
|
27
41
|
nil
|
@@ -32,10 +46,6 @@ module ActionDispatch
|
|
32
46
|
end
|
33
47
|
end
|
34
48
|
|
35
|
-
def content_type
|
36
|
-
content_mime_type && content_mime_type.to_s
|
37
|
-
end
|
38
|
-
|
39
49
|
def has_content_type? # :nodoc:
|
40
50
|
get_header "CONTENT_TYPE"
|
41
51
|
end
|
@@ -62,7 +72,7 @@ module ActionDispatch
|
|
62
72
|
# GET /posts/5.xhtml | request.format => Mime[:html]
|
63
73
|
# GET /posts/5 | request.format => Mime[:html] or Mime[:js], or request.accepts.first
|
64
74
|
#
|
65
|
-
def format(
|
75
|
+
def format(_view_path = nil)
|
66
76
|
formats.first || Mime::NullType.instance
|
67
77
|
end
|
68
78
|
|
@@ -71,7 +81,7 @@ module ActionDispatch
|
|
71
81
|
v = if params_readable?
|
72
82
|
Array(Mime[parameters[:format]])
|
73
83
|
elsif use_accept_header && valid_accept_header
|
74
|
-
accepts
|
84
|
+
accepts.dup
|
75
85
|
elsif extension_format = format_from_path_extension
|
76
86
|
[extension_format]
|
77
87
|
elsif xhr?
|
@@ -80,7 +90,7 @@ module ActionDispatch
|
|
80
90
|
[Mime[:html]]
|
81
91
|
end
|
82
92
|
|
83
|
-
v
|
93
|
+
v.select! do |format|
|
84
94
|
format.symbol || format.ref == "*/*"
|
85
95
|
end
|
86
96
|
|
@@ -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 fall back
|
136
|
+
# to the +:html+ format.
|
127
137
|
#
|
128
138
|
# class ApplicationController < ActionController::Base
|
129
139
|
# before_action :adjust_format_for_iphone_with_html_fallback
|
@@ -162,22 +172,22 @@ module ActionDispatch
|
|
162
172
|
# in which case we assume you're a browser and send HTML.
|
163
173
|
BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
|
164
174
|
|
165
|
-
def params_readable?
|
175
|
+
def params_readable?
|
166
176
|
parameters[:format]
|
167
177
|
rescue *RESCUABLE_MIME_FORMAT_ERRORS
|
168
178
|
false
|
169
179
|
end
|
170
180
|
|
171
|
-
def valid_accept_header
|
181
|
+
def valid_accept_header
|
172
182
|
(xhr? && (accept.present? || content_mime_type)) ||
|
173
183
|
(accept.present? && !accept.match?(BROWSER_LIKE_ACCEPTS))
|
174
184
|
end
|
175
185
|
|
176
|
-
def use_accept_header
|
186
|
+
def use_accept_header
|
177
187
|
!self.class.ignore_accept_header
|
178
188
|
end
|
179
189
|
|
180
|
-
def format_from_path_extension
|
190
|
+
def format_from_path_extension
|
181
191
|
path = get_header("action_dispatch.original_path") || get_header("PATH_INFO")
|
182
192
|
if match = path && path.match(/\.(\w+)\z/)
|
183
193
|
Mime[match.captures.first]
|
@@ -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
|
@@ -12,25 +11,34 @@ module Mime
|
|
12
11
|
def initialize
|
13
12
|
@mimes = []
|
14
13
|
@symbols = []
|
14
|
+
@symbols_set = Set.new
|
15
15
|
end
|
16
16
|
|
17
|
-
def each
|
18
|
-
@mimes.each
|
17
|
+
def each(&block)
|
18
|
+
@mimes.each(&block)
|
19
19
|
end
|
20
20
|
|
21
21
|
def <<(type)
|
22
22
|
@mimes << type
|
23
|
-
|
23
|
+
sym_type = type.to_sym
|
24
|
+
@symbols << sym_type
|
25
|
+
@symbols_set << sym_type
|
24
26
|
end
|
25
27
|
|
26
28
|
def delete_if
|
27
29
|
@mimes.delete_if do |x|
|
28
30
|
if yield x
|
29
|
-
|
31
|
+
sym_type = x.to_sym
|
32
|
+
@symbols.delete(sym_type)
|
33
|
+
@symbols_set.delete(sym_type)
|
30
34
|
true
|
31
35
|
end
|
32
36
|
end
|
33
37
|
end
|
38
|
+
|
39
|
+
def valid_symbols?(symbols) # :nodoc
|
40
|
+
symbols.all? { |s| @symbols_set.include?(s) }
|
41
|
+
end
|
34
42
|
end
|
35
43
|
|
36
44
|
SET = Mimes.new
|
@@ -43,9 +51,17 @@ module Mime
|
|
43
51
|
Type.lookup_by_extension(type)
|
44
52
|
end
|
45
53
|
|
46
|
-
def
|
54
|
+
def symbols
|
55
|
+
SET.symbols
|
56
|
+
end
|
57
|
+
|
58
|
+
def valid_symbols?(symbols) # :nodoc:
|
59
|
+
SET.valid_symbols?(symbols)
|
60
|
+
end
|
61
|
+
|
62
|
+
def fetch(type, &block)
|
47
63
|
return type if type.is_a?(Type)
|
48
|
-
EXTENSION_LOOKUP.fetch(type.to_s)
|
64
|
+
EXTENSION_LOOKUP.fetch(type.to_s, &block)
|
49
65
|
end
|
50
66
|
end
|
51
67
|
|
@@ -68,7 +84,7 @@ module Mime
|
|
68
84
|
@register_callbacks = []
|
69
85
|
|
70
86
|
# A simple helper class used in parsing the accept header.
|
71
|
-
class AcceptItem
|
87
|
+
class AcceptItem # :nodoc:
|
72
88
|
attr_accessor :index, :name, :q
|
73
89
|
alias :to_s :name
|
74
90
|
|
@@ -86,7 +102,7 @@ module Mime
|
|
86
102
|
end
|
87
103
|
end
|
88
104
|
|
89
|
-
class AcceptList
|
105
|
+
class AcceptList # :nodoc:
|
90
106
|
def self.sort!(list)
|
91
107
|
list.sort!
|
92
108
|
|
@@ -136,14 +152,18 @@ module Mime
|
|
136
152
|
|
137
153
|
class << self
|
138
154
|
TRAILING_STAR_REGEXP = /^(text|application)\/\*/
|
139
|
-
|
155
|
+
# all media-type parameters need to be before the q-parameter
|
156
|
+
# https://www.rfc-editor.org/rfc/rfc7231#section-5.3.2
|
157
|
+
PARAMETER_SEPARATOR_REGEXP = /;\s*q="?/
|
158
|
+
ACCEPT_HEADER_REGEXP = /[^,\s"](?:[^,"]|"[^"]*")*/
|
140
159
|
|
141
160
|
def register_callback(&block)
|
142
161
|
@register_callbacks << block
|
143
162
|
end
|
144
163
|
|
145
164
|
def lookup(string)
|
146
|
-
|
165
|
+
# fallback to the media-type without parameters if it was not found
|
166
|
+
LOOKUP[string] || LOOKUP[string.split(";", 2)[0]&.rstrip] || Type.new(string)
|
147
167
|
end
|
148
168
|
|
149
169
|
def lookup_by_extension(extension)
|
@@ -172,12 +192,14 @@ module Mime
|
|
172
192
|
|
173
193
|
def parse(accept_header)
|
174
194
|
if !accept_header.include?(",")
|
175
|
-
|
176
|
-
|
177
|
-
|
195
|
+
if (index = accept_header.index(PARAMETER_SEPARATOR_REGEXP))
|
196
|
+
accept_header = accept_header[0, index].strip
|
197
|
+
end
|
198
|
+
return [] if accept_header.blank?
|
199
|
+
parse_trailing_star(accept_header) || Array(Mime::Type.lookup(accept_header))
|
178
200
|
else
|
179
201
|
list, index = [], 0
|
180
|
-
accept_header.
|
202
|
+
accept_header.scan(ACCEPT_HEADER_REGEXP).each do |header|
|
181
203
|
params, q = header.split(PARAMETER_SEPARATOR_REGEXP)
|
182
204
|
|
183
205
|
next unless params
|
@@ -200,10 +222,10 @@ module Mime
|
|
200
222
|
end
|
201
223
|
|
202
224
|
# For an input of <tt>'text'</tt>, returns <tt>[Mime[:json], Mime[:xml], Mime[:ics],
|
203
|
-
# Mime[:html], Mime[:css], Mime[:csv], Mime[:js], Mime[:yaml], Mime[:text]</tt>.
|
225
|
+
# Mime[:html], Mime[:css], Mime[:csv], Mime[:js], Mime[:yaml], Mime[:text]]</tt>.
|
204
226
|
#
|
205
227
|
# For an input of <tt>'application'</tt>, returns <tt>[Mime[:html], Mime[:js],
|
206
|
-
# Mime[:xml], Mime[:yaml], Mime[:atom], Mime[:json], Mime[:rss], Mime[:url_encoded_form]</tt>.
|
228
|
+
# Mime[:xml], Mime[:yaml], Mime[:atom], Mime[:json], Mime[:rss], Mime[:url_encoded_form]]</tt>.
|
207
229
|
def parse_data_with_trailing_star(type)
|
208
230
|
Mime::SET.select { |m| m.match?(type) }
|
209
231
|
end
|
@@ -226,10 +248,9 @@ module Mime
|
|
226
248
|
attr_reader :hash
|
227
249
|
|
228
250
|
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/
|
251
|
+
MIME_PARAMETER_VALUE = "(?:#{MIME_NAME}|\"[^\"\r\\\\]*\")"
|
252
|
+
MIME_PARAMETER = "\s*;\s*#{MIME_NAME}(?:=#{MIME_PARAMETER_VALUE})?"
|
253
|
+
MIME_REGEXP = /\A(?:\*\/\*|#{MIME_NAME}\/(?:\*|#{MIME_NAME})(?>#{MIME_PARAMETER})*\s*)\z/
|
233
254
|
|
234
255
|
class InvalidMimeType < StandardError; end
|
235
256
|
|
@@ -293,7 +314,7 @@ module Mime
|
|
293
314
|
end
|
294
315
|
|
295
316
|
def html?
|
296
|
-
(symbol == :html) ||
|
317
|
+
(symbol == :html) || @string.include?("html")
|
297
318
|
end
|
298
319
|
|
299
320
|
def all?; false; end
|
@@ -18,6 +18,7 @@ Mime::Type.register "image/gif", :gif, [], %w(gif)
|
|
18
18
|
Mime::Type.register "image/bmp", :bmp, [], %w(bmp)
|
19
19
|
Mime::Type.register "image/tiff", :tiff, [], %w(tif tiff)
|
20
20
|
Mime::Type.register "image/svg+xml", :svg
|
21
|
+
Mime::Type.register "image/webp", :webp, [], %w(webp)
|
21
22
|
|
22
23
|
Mime::Type.register "video/mpeg", :mpeg, [], %w(mpg mpeg mpe)
|
23
24
|
|
@@ -43,7 +44,8 @@ Mime::Type.register "application/x-www-form-urlencoded", :url_encoded_form
|
|
43
44
|
|
44
45
|
# https://www.ietf.org/rfc/rfc4627.txt
|
45
46
|
# http://www.json.org/JSONRequest.html
|
46
|
-
|
47
|
+
# https://www.ietf.org/rfc/rfc7807.txt
|
48
|
+
Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest application/problem+json )
|
47
49
|
|
48
50
|
Mime::Type.register "application/pdf", :pdf, [], %w(pdf)
|
49
51
|
Mime::Type.register "application/zip", :zip, [], %w(zip)
|
@@ -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])
|
@@ -76,9 +76,9 @@ module ActionDispatch
|
|
76
76
|
end
|
77
77
|
|
78
78
|
# Returns a hash with the \parameters used to form the \path of the request.
|
79
|
-
# Returned hash keys are
|
79
|
+
# Returned hash keys are symbols:
|
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,34 +2,50 @@
|
|
2
2
|
|
3
3
|
require "active_support/core_ext/object/deep_dup"
|
4
4
|
|
5
|
-
module ActionDispatch
|
5
|
+
module ActionDispatch # :nodoc:
|
6
|
+
# = Action Dispatch \PermissionsPolicy
|
7
|
+
#
|
8
|
+
# Configures the HTTP
|
9
|
+
# {Feature-Policy}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy]
|
10
|
+
# response header to specify which browser features the current document and
|
11
|
+
# its iframes can use.
|
12
|
+
#
|
13
|
+
# Example global policy:
|
14
|
+
#
|
15
|
+
# Rails.application.config.permissions_policy do |policy|
|
16
|
+
# policy.camera :none
|
17
|
+
# policy.gyroscope :none
|
18
|
+
# policy.microphone :none
|
19
|
+
# policy.usb :none
|
20
|
+
# policy.fullscreen :self
|
21
|
+
# policy.payment :self, "https://secure.example.com"
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# The Feature-Policy header has been renamed to Permissions-Policy.
|
25
|
+
# The Permissions-Policy requires a different implementation and isn't
|
26
|
+
# yet supported by all browsers. To avoid having to rename this
|
27
|
+
# middleware in the future we use the new name for the middleware but
|
28
|
+
# keep the old header name and implementation for now.
|
6
29
|
class PermissionsPolicy
|
7
30
|
class Middleware
|
8
|
-
CONTENT_TYPE = "Content-Type"
|
9
|
-
# The Feature-Policy header has been renamed to Permissions-Policy.
|
10
|
-
# The Permissions-Policy requires a different implementation and isn't
|
11
|
-
# yet supported by all browsers. To avoid having to rename this
|
12
|
-
# middleware in the future we use the new name for the middleware but
|
13
|
-
# keep the old header name and implementation for now.
|
14
|
-
POLICY = "Feature-Policy"
|
15
|
-
|
16
31
|
def initialize(app)
|
17
32
|
@app = app
|
18
33
|
end
|
19
34
|
|
20
35
|
def call(env)
|
21
|
-
request = ActionDispatch::Request.new(env)
|
22
36
|
_, headers, _ = response = @app.call(env)
|
23
37
|
|
24
38
|
return response unless html_response?(headers)
|
25
39
|
return response if policy_present?(headers)
|
26
40
|
|
41
|
+
request = ActionDispatch::Request.new(env)
|
42
|
+
|
27
43
|
if policy = request.permissions_policy
|
28
|
-
headers[
|
44
|
+
headers[ActionDispatch::Constants::FEATURE_POLICY] = policy.build(request.controller_instance)
|
29
45
|
end
|
30
46
|
|
31
47
|
if policy_empty?(policy)
|
32
|
-
headers.delete(
|
48
|
+
headers.delete(ActionDispatch::Constants::FEATURE_POLICY)
|
33
49
|
end
|
34
50
|
|
35
51
|
response
|
@@ -37,13 +53,13 @@ module ActionDispatch #:nodoc:
|
|
37
53
|
|
38
54
|
private
|
39
55
|
def html_response?(headers)
|
40
|
-
if content_type = headers[CONTENT_TYPE]
|
41
|
-
|
56
|
+
if content_type = headers[Rack::CONTENT_TYPE]
|
57
|
+
content_type.include?("html")
|
42
58
|
end
|
43
59
|
end
|
44
60
|
|
45
61
|
def policy_present?(headers)
|
46
|
-
headers[
|
62
|
+
headers[ActionDispatch::Constants::FEATURE_POLICY]
|
47
63
|
end
|
48
64
|
|
49
65
|
def policy_empty?(policy)
|
@@ -69,7 +85,7 @@ module ActionDispatch #:nodoc:
|
|
69
85
|
}.freeze
|
70
86
|
|
71
87
|
# List of available permissions can be found at
|
72
|
-
# https://github.com/w3c/webappsec-permissions-policy/blob/
|
88
|
+
# https://github.com/w3c/webappsec-permissions-policy/blob/main/features.md#policy-controlled-features
|
73
89
|
DIRECTIVES = {
|
74
90
|
accelerometer: "accelerometer",
|
75
91
|
ambient_light_sensor: "ambient-light-sensor",
|
@@ -79,15 +95,18 @@ module ActionDispatch #:nodoc:
|
|
79
95
|
fullscreen: "fullscreen",
|
80
96
|
geolocation: "geolocation",
|
81
97
|
gyroscope: "gyroscope",
|
98
|
+
hid: "hid",
|
99
|
+
idle_detection: "idle_detection",
|
82
100
|
magnetometer: "magnetometer",
|
83
101
|
microphone: "microphone",
|
84
102
|
midi: "midi",
|
85
103
|
payment: "payment",
|
86
104
|
picture_in_picture: "picture-in-picture",
|
87
|
-
|
105
|
+
screen_wake_lock: "screen-wake-lock",
|
106
|
+
serial: "serial",
|
107
|
+
sync_xhr: "sync-xhr",
|
88
108
|
usb: "usb",
|
89
|
-
|
90
|
-
vr: "vr",
|
109
|
+
web_share: "web-share",
|
91
110
|
}.freeze
|
92
111
|
|
93
112
|
private_constant :MAPPINGS, :DIRECTIVES
|
@@ -113,6 +132,25 @@ module ActionDispatch #:nodoc:
|
|
113
132
|
end
|
114
133
|
end
|
115
134
|
|
135
|
+
%w[speaker vibrate vr].each do |directive|
|
136
|
+
define_method(directive) do |*sources|
|
137
|
+
ActionDispatch.deprecator.warn(<<~MSG)
|
138
|
+
The `#{directive}` permissions policy directive is deprecated
|
139
|
+
and will be removed in Rails 7.2.
|
140
|
+
|
141
|
+
There is no browser support for this directive, and no plan
|
142
|
+
for browser support in the future. You can just remove this
|
143
|
+
directive from your application.
|
144
|
+
MSG
|
145
|
+
|
146
|
+
if sources.first
|
147
|
+
@directives[directive] = apply_mappings(sources)
|
148
|
+
else
|
149
|
+
@directives.delete(directive)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
116
154
|
def build(context = nil)
|
117
155
|
build_directives(context).compact.join("; ")
|
118
156
|
end
|