actionpack 7.1.3 → 7.2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +82 -501
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +102 -98
- data/lib/abstract_controller/caching/fragments.rb +50 -53
- data/lib/abstract_controller/caching.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +66 -64
- data/lib/abstract_controller/collector.rb +6 -6
- data/lib/abstract_controller/deprecator.rb +2 -0
- data/lib/abstract_controller/error.rb +2 -0
- data/lib/abstract_controller/helpers.rb +70 -85
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +13 -12
- data/lib/abstract_controller/translation.rb +15 -7
- data/lib/abstract_controller/url_for.rb +8 -6
- data/lib/abstract_controller.rb +2 -0
- data/lib/action_controller/api/api_rendering.rb +2 -0
- data/lib/action_controller/api.rb +74 -72
- data/lib/action_controller/base.rb +198 -126
- data/lib/action_controller/caching.rb +15 -12
- data/lib/action_controller/deprecator.rb +2 -0
- data/lib/action_controller/form_builder.rb +20 -17
- data/lib/action_controller/log_subscriber.rb +3 -1
- data/lib/action_controller/metal/allow_browser.rb +123 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
- data/lib/action_controller/metal/conditional_get.rb +188 -174
- data/lib/action_controller/metal/content_security_policy.rb +25 -24
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +64 -55
- data/lib/action_controller/metal/default_headers.rb +5 -3
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
- data/lib/action_controller/metal/exceptions.rb +11 -9
- data/lib/action_controller/metal/flash.rb +12 -10
- data/lib/action_controller/metal/head.rb +12 -10
- data/lib/action_controller/metal/helpers.rb +63 -55
- data/lib/action_controller/metal/http_authentication.rb +210 -205
- data/lib/action_controller/metal/implicit_render.rb +17 -15
- data/lib/action_controller/metal/instrumentation.rb +15 -12
- data/lib/action_controller/metal/live.rb +113 -107
- data/lib/action_controller/metal/logging.rb +6 -4
- data/lib/action_controller/metal/mime_responds.rb +151 -142
- data/lib/action_controller/metal/parameter_encoding.rb +34 -32
- data/lib/action_controller/metal/params_wrapper.rb +57 -59
- data/lib/action_controller/metal/permissions_policy.rb +13 -12
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +108 -82
- data/lib/action_controller/metal/renderers.rb +50 -49
- data/lib/action_controller/metal/rendering.rb +103 -75
- data/lib/action_controller/metal/request_forgery_protection.rb +162 -133
- data/lib/action_controller/metal/rescue.rb +11 -9
- data/lib/action_controller/metal/streaming.rb +138 -136
- data/lib/action_controller/metal/strong_parameters.rb +525 -480
- data/lib/action_controller/metal/testing.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +17 -15
- data/lib/action_controller/metal.rb +86 -60
- data/lib/action_controller/railtie.rb +3 -0
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +42 -36
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +146 -126
- data/lib/action_controller.rb +10 -3
- data/lib/action_dispatch/constants.rb +2 -0
- data/lib/action_dispatch/deprecator.rb +2 -0
- data/lib/action_dispatch/http/cache.rb +27 -26
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +44 -38
- data/lib/action_dispatch/http/filter_parameters.rb +18 -9
- data/lib/action_dispatch/http/filter_redirect.rb +22 -1
- data/lib/action_dispatch/http/headers.rb +22 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +30 -41
- data/lib/action_dispatch/http/mime_type.rb +31 -24
- data/lib/action_dispatch/http/mime_types.rb +2 -0
- data/lib/action_dispatch/http/parameters.rb +11 -9
- data/lib/action_dispatch/http/permissions_policy.rb +20 -44
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +94 -75
- data/lib/action_dispatch/http/response.rb +73 -61
- data/lib/action_dispatch/http/upload.rb +18 -16
- data/lib/action_dispatch/http/url.rb +75 -73
- data/lib/action_dispatch/journey/formatter.rb +13 -6
- data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +2 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +10 -8
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
- data/lib/action_dispatch/journey/nodes/node.rb +6 -5
- data/lib/action_dispatch/journey/parser.rb +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +2 -0
- data/lib/action_dispatch/journey/path/pattern.rb +4 -1
- data/lib/action_dispatch/journey/route.rb +9 -7
- data/lib/action_dispatch/journey/router/utils.rb +16 -15
- data/lib/action_dispatch/journey/router.rb +4 -2
- data/lib/action_dispatch/journey/routes.rb +4 -2
- data/lib/action_dispatch/journey/scanner.rb +4 -2
- data/lib/action_dispatch/journey/visitors.rb +2 -0
- data/lib/action_dispatch/journey.rb +2 -0
- data/lib/action_dispatch/log_subscriber.rb +2 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
- data/lib/action_dispatch/middleware/callbacks.rb +3 -1
- data/lib/action_dispatch/middleware/cookies.rb +119 -104
- data/lib/action_dispatch/middleware/debug_exceptions.rb +13 -5
- data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
- data/lib/action_dispatch/middleware/debug_view.rb +2 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +6 -11
- data/lib/action_dispatch/middleware/executor.rb +8 -0
- data/lib/action_dispatch/middleware/flash.rb +63 -51
- data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
- data/lib/action_dispatch/middleware/public_exceptions.rb +8 -6
- data/lib/action_dispatch/middleware/reloader.rb +5 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +77 -72
- data/lib/action_dispatch/middleware/request_id.rb +14 -9
- data/lib/action_dispatch/middleware/server_timing.rb +4 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +13 -8
- data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +31 -21
- data/lib/action_dispatch/middleware/ssl.rb +43 -40
- data/lib/action_dispatch/middleware/stack.rb +11 -10
- data/lib/action_dispatch/middleware/static.rb +33 -31
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
- data/lib/action_dispatch/railtie.rb +2 -4
- data/lib/action_dispatch/request/session.rb +23 -21
- data/lib/action_dispatch/request/utils.rb +2 -0
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +5 -3
- data/lib/action_dispatch/routing/mapper.rb +671 -636
- data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
- data/lib/action_dispatch/routing/redirection.rb +37 -32
- data/lib/action_dispatch/routing/route_set.rb +59 -45
- data/lib/action_dispatch/routing/routes_proxy.rb +6 -4
- data/lib/action_dispatch/routing/url_for.rb +130 -125
- data/lib/action_dispatch/routing.rb +150 -148
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +10 -3
- data/lib/action_dispatch/system_testing/driver.rb +3 -1
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +32 -21
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
- data/lib/action_dispatch/testing/assertion_response.rb +8 -6
- data/lib/action_dispatch/testing/assertions/response.rb +26 -23
- data/lib/action_dispatch/testing/assertions/routing.rb +153 -84
- data/lib/action_dispatch/testing/assertions.rb +2 -0
- data/lib/action_dispatch/testing/integration.rb +223 -222
- data/lib/action_dispatch/testing/request_encoder.rb +2 -0
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +12 -8
- data/lib/action_dispatch/testing/test_request.rb +3 -1
- data/lib/action_dispatch/testing/test_response.rb +27 -26
- data/lib/action_dispatch.rb +22 -28
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +17 -16
- metadata +39 -16
@@ -1,28 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
require "active_support/core_ext/object/deep_dup"
|
4
6
|
require "active_support/core_ext/array/wrap"
|
5
7
|
|
6
8
|
module ActionDispatch # :nodoc:
|
7
|
-
#
|
9
|
+
# # Action Dispatch Content Security Policy
|
8
10
|
#
|
9
|
-
# Configures the HTTP
|
10
|
-
#
|
11
|
-
# response header to help protect against XSS and
|
11
|
+
# Configures the HTTP [Content-Security-Policy]
|
12
|
+
# (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)
|
13
|
+
# response header to help protect against XSS and
|
14
|
+
# injection attacks.
|
12
15
|
#
|
13
16
|
# Example global policy:
|
14
17
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
18
|
+
# Rails.application.config.content_security_policy do |policy|
|
19
|
+
# policy.default_src :self, :https
|
20
|
+
# policy.font_src :self, :https, :data
|
21
|
+
# policy.img_src :self, :https, :data
|
22
|
+
# policy.object_src :none
|
23
|
+
# policy.script_src :self, :https
|
24
|
+
# policy.style_src :self, :https
|
22
25
|
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
+
# # Specify URI for violation reports
|
27
|
+
# policy.report_uri "/csp-violation-report-endpoint"
|
28
|
+
# end
|
26
29
|
class ContentSecurityPolicy
|
27
30
|
class Middleware
|
28
31
|
def initialize(app)
|
@@ -32,8 +35,8 @@ module ActionDispatch # :nodoc:
|
|
32
35
|
def call(env)
|
33
36
|
status, headers, _ = response = @app.call(env)
|
34
37
|
|
35
|
-
# Returning CSP headers with a 304 Not Modified is harmful, since nonces in the
|
36
|
-
# CSP headers might not match nonces in the cached HTML.
|
38
|
+
# Returning CSP headers with a 304 Not Modified is harmful, since nonces in the
|
39
|
+
# new CSP headers might not match nonces in the cached HTML.
|
37
40
|
return response if status == 304
|
38
41
|
|
39
42
|
return response if policy_present?(headers)
|
@@ -190,14 +193,14 @@ module ActionDispatch # :nodoc:
|
|
190
193
|
end
|
191
194
|
end
|
192
195
|
|
193
|
-
# Specify whether to prevent the user agent from loading any assets over
|
194
|
-
#
|
196
|
+
# Specify whether to prevent the user agent from loading any assets over HTTP
|
197
|
+
# when the page uses HTTPS:
|
195
198
|
#
|
196
|
-
#
|
199
|
+
# policy.block_all_mixed_content
|
197
200
|
#
|
198
|
-
# Pass
|
201
|
+
# Pass `false` to allow it again:
|
199
202
|
#
|
200
|
-
#
|
203
|
+
# policy.block_all_mixed_content false
|
201
204
|
#
|
202
205
|
def block_all_mixed_content(enabled = true)
|
203
206
|
if enabled
|
@@ -209,11 +212,11 @@ module ActionDispatch # :nodoc:
|
|
209
212
|
|
210
213
|
# Restricts the set of plugins that can be embedded:
|
211
214
|
#
|
212
|
-
#
|
215
|
+
# policy.plugin_types "application/x-shockwave-flash"
|
213
216
|
#
|
214
217
|
# Leave empty to allow all plugins:
|
215
218
|
#
|
216
|
-
#
|
219
|
+
# policy.plugin_types
|
217
220
|
#
|
218
221
|
def plugin_types(*types)
|
219
222
|
if types.first
|
@@ -223,23 +226,25 @@ module ActionDispatch # :nodoc:
|
|
223
226
|
end
|
224
227
|
end
|
225
228
|
|
226
|
-
# Enable the
|
227
|
-
#
|
229
|
+
# Enable the [report-uri]
|
230
|
+
# (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri)
|
231
|
+
# directive. Violation reports will be sent to the
|
232
|
+
# specified URI:
|
228
233
|
#
|
229
|
-
#
|
234
|
+
# policy.report_uri "/csp-violation-report-endpoint"
|
230
235
|
#
|
231
236
|
def report_uri(uri)
|
232
237
|
@directives["report-uri"] = [uri]
|
233
238
|
end
|
234
239
|
|
235
|
-
# Specify asset types for which
|
236
|
-
# is required:
|
240
|
+
# Specify asset types for which [Subresource Integrity]
|
241
|
+
# (https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) is required:
|
237
242
|
#
|
238
|
-
#
|
243
|
+
# policy.require_sri_for :script, :style
|
239
244
|
#
|
240
245
|
# Leave empty to not require Subresource Integrity:
|
241
246
|
#
|
242
|
-
#
|
247
|
+
# policy.require_sri_for
|
243
248
|
#
|
244
249
|
def require_sri_for(*types)
|
245
250
|
if types.first
|
@@ -249,18 +254,19 @@ module ActionDispatch # :nodoc:
|
|
249
254
|
end
|
250
255
|
end
|
251
256
|
|
252
|
-
# Specify whether a
|
257
|
+
# Specify whether a [sandbox]
|
258
|
+
# (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox)
|
253
259
|
# should be enabled for the requested resource:
|
254
260
|
#
|
255
|
-
#
|
261
|
+
# policy.sandbox
|
256
262
|
#
|
257
263
|
# Values can be passed as arguments:
|
258
264
|
#
|
259
|
-
#
|
265
|
+
# policy.sandbox "allow-scripts", "allow-modals"
|
260
266
|
#
|
261
|
-
# Pass
|
267
|
+
# Pass `false` to disable the sandbox:
|
262
268
|
#
|
263
|
-
#
|
269
|
+
# policy.sandbox false
|
264
270
|
#
|
265
271
|
def sandbox(*values)
|
266
272
|
if values.empty?
|
@@ -274,11 +280,11 @@ module ActionDispatch # :nodoc:
|
|
274
280
|
|
275
281
|
# Specify whether user agents should treat any assets over HTTP as HTTPS:
|
276
282
|
#
|
277
|
-
#
|
283
|
+
# policy.upgrade_insecure_requests
|
278
284
|
#
|
279
|
-
# Pass
|
285
|
+
# Pass `false` to disable it:
|
280
286
|
#
|
281
|
-
#
|
287
|
+
# policy.upgrade_insecure_requests false
|
282
288
|
#
|
283
289
|
def upgrade_insecure_requests(enabled = true)
|
284
290
|
if enabled
|
@@ -1,18 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
require "active_support/parameter_filter"
|
4
6
|
|
5
7
|
module ActionDispatch
|
6
8
|
module Http
|
7
|
-
#
|
9
|
+
# # Action Dispatch HTTP Filter Parameters
|
8
10
|
#
|
9
11
|
# Allows you to specify sensitive query string and POST parameters to filter
|
10
12
|
# from the request log.
|
11
13
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
+
# # Replaces values with "[FILTERED]" for keys that match /foo|bar/i.
|
15
|
+
# env["action_dispatch.parameter_filter"] = [:foo, "bar"]
|
14
16
|
#
|
15
|
-
# For more information about filter behavior, see
|
17
|
+
# For more information about filter behavior, see
|
18
|
+
# ActiveSupport::ParameterFilter.
|
16
19
|
module FilterParameters
|
17
20
|
ENV_MATCH = [/RAW_POST_DATA/, "rack.request.form_vars"] # :nodoc:
|
18
21
|
NULL_PARAM_FILTER = ActiveSupport::ParameterFilter.new # :nodoc:
|
@@ -43,7 +46,8 @@ module ActionDispatch
|
|
43
46
|
@filtered_path ||= query_string.empty? ? path : "#{path}?#{filtered_query_string}"
|
44
47
|
end
|
45
48
|
|
46
|
-
# Returns the
|
49
|
+
# Returns the `ActiveSupport::ParameterFilter` object used to filter in this
|
50
|
+
# request.
|
47
51
|
def parameter_filter
|
48
52
|
@parameter_filter ||= if has_header?("action_dispatch.parameter_filter")
|
49
53
|
parameter_filter_for get_header("action_dispatch.parameter_filter")
|
@@ -64,12 +68,17 @@ module ActionDispatch
|
|
64
68
|
ActiveSupport::ParameterFilter.new(filters)
|
65
69
|
end
|
66
70
|
|
67
|
-
KV_RE = "[^&;=]+"
|
68
|
-
PAIR_RE = %r{(#{KV_RE})=(#{KV_RE})}
|
69
71
|
def filtered_query_string # :doc:
|
70
|
-
query_string.
|
71
|
-
|
72
|
+
parts = query_string.split(/([&;])/)
|
73
|
+
filtered_parts = parts.map do |part|
|
74
|
+
if part.include?("=")
|
75
|
+
key, value = part.split("=", 2)
|
76
|
+
parameter_filter.filter(key => value).first.join("=")
|
77
|
+
else
|
78
|
+
part
|
79
|
+
end
|
72
80
|
end
|
81
|
+
filtered_parts.join("")
|
73
82
|
end
|
74
83
|
end
|
75
84
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionDispatch
|
4
6
|
module Http
|
5
7
|
module FilterRedirect
|
@@ -9,7 +11,7 @@ module ActionDispatch
|
|
9
11
|
if location_filter_match?
|
10
12
|
FILTERED
|
11
13
|
else
|
12
|
-
|
14
|
+
parameter_filtered_location
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
@@ -31,6 +33,25 @@ module ActionDispatch
|
|
31
33
|
end
|
32
34
|
end
|
33
35
|
end
|
36
|
+
|
37
|
+
def parameter_filtered_location
|
38
|
+
uri = URI.parse(location)
|
39
|
+
unless uri.query.nil? || uri.query.empty?
|
40
|
+
parts = uri.query.split(/([&;])/)
|
41
|
+
filtered_parts = parts.map do |part|
|
42
|
+
if part.include?("=")
|
43
|
+
key, value = part.split("=", 2)
|
44
|
+
request.parameter_filter.filter(key => value).first.join("=")
|
45
|
+
else
|
46
|
+
part
|
47
|
+
end
|
48
|
+
end
|
49
|
+
uri.query = filtered_parts.join("")
|
50
|
+
end
|
51
|
+
uri.to_s
|
52
|
+
rescue URI::Error
|
53
|
+
FILTERED
|
54
|
+
end
|
34
55
|
end
|
35
56
|
end
|
36
57
|
end
|
@@ -1,28 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionDispatch
|
4
6
|
module Http
|
5
|
-
#
|
7
|
+
# # Action Dispatch HTTP Headers
|
6
8
|
#
|
7
9
|
# Provides access to the request's HTTP headers from the environment.
|
8
10
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
11
|
+
# env = { "CONTENT_TYPE" => "text/plain", "HTTP_USER_AGENT" => "curl/7.43.0" }
|
12
|
+
# headers = ActionDispatch::Http::Headers.from_hash(env)
|
13
|
+
# headers["Content-Type"] # => "text/plain"
|
14
|
+
# headers["User-Agent"] # => "curl/7.43.0"
|
13
15
|
#
|
14
16
|
# Also note that when headers are mapped to CGI-like variables by the Rack
|
15
17
|
# server, both dashes and underscores are converted to underscores. This
|
16
18
|
# ambiguity cannot be resolved at this stage anymore. Both underscores and
|
17
19
|
# dashes have to be interpreted as if they were originally sent as dashes.
|
18
20
|
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
21
|
+
# # GET / HTTP/1.1
|
22
|
+
# # ...
|
23
|
+
# # User-Agent: curl/7.43.0
|
24
|
+
# # X_Custom_Header: token
|
23
25
|
#
|
24
|
-
#
|
25
|
-
#
|
26
|
+
# headers["X_Custom_Header"] # => nil
|
27
|
+
# headers["X-Custom-Header"] # => "token"
|
26
28
|
class Headers
|
27
29
|
CGI_VARIABLES = Set.new(%W[
|
28
30
|
AUTH_TYPE
|
@@ -67,7 +69,7 @@ module ActionDispatch
|
|
67
69
|
@req.set_header env_name(key), value
|
68
70
|
end
|
69
71
|
|
70
|
-
# Add a value to a multivalued header like
|
72
|
+
# Add a value to a multivalued header like `Vary` or `Accept-Encoding`.
|
71
73
|
def add(key, value)
|
72
74
|
@req.add_header env_name(key), value
|
73
75
|
end
|
@@ -81,11 +83,10 @@ module ActionDispatch
|
|
81
83
|
|
82
84
|
# Returns the value for the given key mapped to @env.
|
83
85
|
#
|
84
|
-
# If the key is not found and an optional code block is not provided,
|
85
|
-
#
|
86
|
+
# If the key is not found and an optional code block is not provided, raises a
|
87
|
+
# `KeyError` exception.
|
86
88
|
#
|
87
|
-
# If the code block is provided, then it will be run and
|
88
|
-
# its result returned.
|
89
|
+
# If the code block is provided, then it will be run and its result returned.
|
89
90
|
def fetch(key, default = DEFAULT)
|
90
91
|
@req.fetch_header(env_name(key)) do
|
91
92
|
return default unless default == DEFAULT
|
@@ -99,16 +100,15 @@ module ActionDispatch
|
|
99
100
|
end
|
100
101
|
|
101
102
|
# Returns a new Http::Headers instance containing the contents of
|
102
|
-
#
|
103
|
+
# `headers_or_env` and the original instance.
|
103
104
|
def merge(headers_or_env)
|
104
105
|
headers = @req.dup.headers
|
105
106
|
headers.merge!(headers_or_env)
|
106
107
|
headers
|
107
108
|
end
|
108
109
|
|
109
|
-
# Adds the contents of
|
110
|
-
#
|
111
|
-
# <tt>headers_or_env</tt>.
|
110
|
+
# Adds the contents of `headers_or_env` to original instance entries; duplicate
|
111
|
+
# keys are overwritten with the values from `headers_or_env`.
|
112
112
|
def merge!(headers_or_env)
|
113
113
|
headers_or_env.each do |key, value|
|
114
114
|
@req.set_header env_name(key), value
|
@@ -118,8 +118,8 @@ module ActionDispatch
|
|
118
118
|
def env; @req.env.dup; end
|
119
119
|
|
120
120
|
private
|
121
|
-
# Converts an HTTP header name to an environment variable name if it is
|
122
|
-
#
|
121
|
+
# Converts an HTTP header name to an environment variable name if it is not
|
122
|
+
# contained within the headers hash.
|
123
123
|
def env_name(key)
|
124
124
|
key = key.to_s
|
125
125
|
if HTTP_HEADER.match?(key)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
require "active_support/core_ext/module/attribute_accessors"
|
4
6
|
|
5
7
|
module ActionDispatch
|
@@ -16,23 +18,9 @@ module ActionDispatch
|
|
16
18
|
|
17
19
|
included do
|
18
20
|
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
|
33
21
|
end
|
34
22
|
|
35
|
-
# The MIME type of the HTTP request, such as Mime
|
23
|
+
# The MIME type of the HTTP request, such as [Mime](:xml).
|
36
24
|
def content_mime_type
|
37
25
|
fetch_header("action_dispatch.request.content_type") do |k|
|
38
26
|
v = if get_header("CONTENT_TYPE") =~ /^([^,;]*)/
|
@@ -66,11 +54,11 @@ module ActionDispatch
|
|
66
54
|
end
|
67
55
|
end
|
68
56
|
|
69
|
-
# Returns the MIME type for the
|
57
|
+
# Returns the MIME type for the format used in the request.
|
70
58
|
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
59
|
+
# GET /posts/5.xml | request.format => Mime[:xml]
|
60
|
+
# GET /posts/5.xhtml | request.format => Mime[:html]
|
61
|
+
# GET /posts/5 | request.format => Mime[:html] or Mime[:js], or request.accepts.first
|
74
62
|
#
|
75
63
|
def format(_view_path = nil)
|
76
64
|
formats.first || Mime::NullType.instance
|
@@ -98,7 +86,7 @@ module ActionDispatch
|
|
98
86
|
end
|
99
87
|
end
|
100
88
|
|
101
|
-
# Sets the
|
89
|
+
# Sets the variant for template.
|
102
90
|
def variant=(variant)
|
103
91
|
variant = Array(variant)
|
104
92
|
|
@@ -113,36 +101,37 @@ module ActionDispatch
|
|
113
101
|
@variant ||= ActiveSupport::ArrayInquirer.new
|
114
102
|
end
|
115
103
|
|
116
|
-
# Sets the
|
104
|
+
# Sets the format by string extension, which can be used to force custom formats
|
117
105
|
# that are not controlled by the extension.
|
118
106
|
#
|
119
|
-
#
|
120
|
-
#
|
107
|
+
# class ApplicationController < ActionController::Base
|
108
|
+
# before_action :adjust_format_for_iphone
|
121
109
|
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
110
|
+
# private
|
111
|
+
# def adjust_format_for_iphone
|
112
|
+
# request.format = :iphone if request.env["HTTP_USER_AGENT"][/iPhone/]
|
113
|
+
# end
|
114
|
+
# end
|
127
115
|
def format=(extension)
|
128
116
|
parameters[:format] = extension.to_s
|
129
117
|
set_header "action_dispatch.request.formats", [Mime::Type.lookup_by_extension(parameters[:format])]
|
130
118
|
end
|
131
119
|
|
132
|
-
# Sets the
|
133
|
-
# to set multiple, ordered formats, which is useful when you want to have a
|
120
|
+
# Sets the formats by string extensions. This differs from #format= by allowing
|
121
|
+
# you to set multiple, ordered formats, which is useful when you want to have a
|
122
|
+
# fallback.
|
134
123
|
#
|
135
|
-
# In this example, the
|
136
|
-
# to the
|
124
|
+
# In this example, the `:iphone` format will be used if it's available,
|
125
|
+
# otherwise it'll fall back to the `:html` format.
|
137
126
|
#
|
138
|
-
#
|
139
|
-
#
|
127
|
+
# class ApplicationController < ActionController::Base
|
128
|
+
# before_action :adjust_format_for_iphone_with_html_fallback
|
140
129
|
#
|
141
|
-
#
|
142
|
-
#
|
143
|
-
#
|
144
|
-
#
|
145
|
-
#
|
130
|
+
# private
|
131
|
+
# def adjust_format_for_iphone_with_html_fallback
|
132
|
+
# request.formats = [ :iphone, :html ] if request.env["HTTP_USER_AGENT"][/iPhone/]
|
133
|
+
# end
|
134
|
+
# end
|
146
135
|
def formats=(extensions)
|
147
136
|
parameters[:format] = extensions.first.to_s
|
148
137
|
set_header "action_dispatch.request.formats", extensions.collect { |extension|
|
@@ -168,8 +157,8 @@ module ActionDispatch
|
|
168
157
|
end
|
169
158
|
|
170
159
|
private
|
171
|
-
# We use normal content negotiation unless you include
|
172
|
-
#
|
160
|
+
# We use normal content negotiation unless you include **/** in your list, in
|
161
|
+
# which case we assume you're a browser and send HTML.
|
173
162
|
BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
|
174
163
|
|
175
164
|
def params_readable?
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
require "singleton"
|
4
6
|
|
5
7
|
module Mime
|
@@ -65,19 +67,20 @@ module Mime
|
|
65
67
|
end
|
66
68
|
end
|
67
69
|
|
68
|
-
# Encapsulates the notion of a MIME type. Can be used at render time, for
|
70
|
+
# Encapsulates the notion of a MIME type. Can be used at render time, for
|
71
|
+
# example, with:
|
69
72
|
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
+
# class PostsController < ActionController::Base
|
74
|
+
# def show
|
75
|
+
# @post = Post.find(params[:id])
|
73
76
|
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
77
|
+
# respond_to do |format|
|
78
|
+
# format.html
|
79
|
+
# format.ics { render body: @post.to_ics, mime_type: Mime::Type.lookup("text/calendar") }
|
80
|
+
# format.xml { render xml: @post }
|
81
|
+
# end
|
78
82
|
# end
|
79
83
|
# end
|
80
|
-
# end
|
81
84
|
class Type
|
82
85
|
attr_reader :symbol
|
83
86
|
|
@@ -154,7 +157,7 @@ module Mime
|
|
154
157
|
TRAILING_STAR_REGEXP = /^(text|application)\/\*/
|
155
158
|
# all media-type parameters need to be before the q-parameter
|
156
159
|
# https://www.rfc-editor.org/rfc/rfc7231#section-5.3.2
|
157
|
-
PARAMETER_SEPARATOR_REGEXP =
|
160
|
+
PARAMETER_SEPARATOR_REGEXP = /;\s*q="?/
|
158
161
|
ACCEPT_HEADER_REGEXP = /[^,\s"](?:[^,"]|"[^"]*")*/
|
159
162
|
|
160
163
|
def register_callback(&block)
|
@@ -162,16 +165,20 @@ module Mime
|
|
162
165
|
end
|
163
166
|
|
164
167
|
def lookup(string)
|
168
|
+
return LOOKUP[string] if LOOKUP.key?(string)
|
169
|
+
|
165
170
|
# fallback to the media-type without parameters if it was not found
|
166
|
-
|
171
|
+
string = string.split(";", 2)[0]&.rstrip
|
172
|
+
LOOKUP[string] || Type.new(string)
|
167
173
|
end
|
168
174
|
|
169
175
|
def lookup_by_extension(extension)
|
170
176
|
EXTENSION_LOOKUP[extension.to_s]
|
171
177
|
end
|
172
178
|
|
173
|
-
# Registers an alias that's not used on MIME type lookup, but can be referenced
|
174
|
-
# rendering different HTML versions depending on
|
179
|
+
# Registers an alias that's not used on MIME type lookup, but can be referenced
|
180
|
+
# directly. Especially useful for rendering different HTML versions depending on
|
181
|
+
# the user agent, like an iPhone.
|
175
182
|
def register_alias(string, symbol, extension_synonyms = [])
|
176
183
|
register(string, symbol, [], extension_synonyms, true)
|
177
184
|
end
|
@@ -193,7 +200,7 @@ module Mime
|
|
193
200
|
def parse(accept_header)
|
194
201
|
if !accept_header.include?(",")
|
195
202
|
if (index = accept_header.index(PARAMETER_SEPARATOR_REGEXP))
|
196
|
-
accept_header = accept_header[0, index]
|
203
|
+
accept_header = accept_header[0, index].strip
|
197
204
|
end
|
198
205
|
return [] if accept_header.blank?
|
199
206
|
parse_trailing_star(accept_header) || Array(Mime::Type.lookup(accept_header))
|
@@ -221,11 +228,11 @@ module Mime
|
|
221
228
|
parse_data_with_trailing_star($1) if accept_header =~ TRAILING_STAR_REGEXP
|
222
229
|
end
|
223
230
|
|
224
|
-
# For an input of
|
225
|
-
# Mime[:html], Mime[:css], Mime[:csv], Mime[:js], Mime[:yaml], Mime[:text]]
|
231
|
+
# For an input of `'text'`, returns `[Mime[:json], Mime[:xml], Mime[:ics],
|
232
|
+
# Mime[:html], Mime[:css], Mime[:csv], Mime[:js], Mime[:yaml], Mime[:text]]`.
|
226
233
|
#
|
227
|
-
# For an input of
|
228
|
-
# Mime[:
|
234
|
+
# For an input of `'application'`, returns `[Mime[:html], Mime[:js], Mime[:xml],
|
235
|
+
# Mime[:yaml], Mime[:atom], Mime[:json], Mime[:rss], Mime[:url_encoded_form]]`.
|
229
236
|
def parse_data_with_trailing_star(type)
|
230
237
|
Mime::SET.select { |m| m.match?(type) }
|
231
238
|
end
|
@@ -234,7 +241,7 @@ module Mime
|
|
234
241
|
#
|
235
242
|
# To unregister a MIME type:
|
236
243
|
#
|
237
|
-
#
|
244
|
+
# Mime::Type.unregister(:mobile)
|
238
245
|
def unregister(symbol)
|
239
246
|
symbol = symbol.downcase
|
240
247
|
if mime = Mime[symbol]
|
@@ -326,7 +333,7 @@ module Mime
|
|
326
333
|
def to_ary; end
|
327
334
|
def to_a; end
|
328
335
|
|
329
|
-
def method_missing(method,
|
336
|
+
def method_missing(method, ...)
|
330
337
|
if method.end_with?("?")
|
331
338
|
method[0..-2].downcase.to_sym == to_sym
|
332
339
|
else
|
@@ -350,9 +357,9 @@ module Mime
|
|
350
357
|
def html?; true; end
|
351
358
|
end
|
352
359
|
|
353
|
-
# ALL isn't a real MIME type, so we don't register it for lookup with the
|
354
|
-
#
|
355
|
-
#
|
360
|
+
# ALL isn't a real MIME type, so we don't register it for lookup with the other
|
361
|
+
# concrete types. It's a wildcard match that we use for `respond_to` negotiation
|
362
|
+
# internals.
|
356
363
|
ALL = AllType.instance
|
357
364
|
|
358
365
|
class NullType
|
@@ -373,7 +380,7 @@ module Mime
|
|
373
380
|
method.end_with?("?")
|
374
381
|
end
|
375
382
|
|
376
|
-
def method_missing(method,
|
383
|
+
def method_missing(method, ...)
|
377
384
|
false if method.end_with?("?")
|
378
385
|
end
|
379
386
|
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
# Build list of Mime types for HTTP responses
|
4
4
|
# https://www.iana.org/assignments/media-types/
|
5
5
|
|
6
|
+
# :markup: markdown
|
7
|
+
|
6
8
|
Mime::Type.register "text/html", :html, %w( application/xhtml+xml ), %w( xhtml )
|
7
9
|
Mime::Type.register "text/plain", :text, [], %w(txt)
|
8
10
|
Mime::Type.register "text/javascript", :js, %w( application/javascript application/x-javascript )
|