actionpack 7.1.5.1 → 7.2.0.beta1
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 +61 -642
- 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 +12 -13
- 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 +155 -117
- 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 +119 -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 +214 -203
- 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 +483 -478
- 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 +58 -57
- 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 +5 -1
- 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 +48 -59
- data/lib/action_dispatch/http/filter_parameters.rb +13 -14
- data/lib/action_dispatch/http/filter_redirect.rb +15 -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 +25 -21
- 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 +26 -36
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +75 -95
- data/lib/action_dispatch/http/response.rb +61 -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 +2 -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 +16 -16
- 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/routes/_table.html.erb +1 -1
- data/lib/action_dispatch/railtie.rb +2 -3
- 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 +6 -4
- data/lib/action_dispatch/routing/mapper.rb +623 -625
- 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 +60 -46
- 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 +4 -2
- data/lib/action_dispatch/system_testing/driver.rb +2 -0
- 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 -32
- 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 +33 -16
@@ -1,32 +1,32 @@
|
|
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
|
-
class InvalidDirectiveError < StandardError
|
28
|
-
end
|
29
|
-
|
30
30
|
class Middleware
|
31
31
|
def initialize(app)
|
32
32
|
@app = app
|
@@ -35,8 +35,8 @@ module ActionDispatch # :nodoc:
|
|
35
35
|
def call(env)
|
36
36
|
status, headers, _ = response = @app.call(env)
|
37
37
|
|
38
|
-
# Returning CSP headers with a 304 Not Modified is harmful, since nonces in the
|
39
|
-
# 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.
|
40
40
|
return response if status == 304
|
41
41
|
|
42
42
|
return response if policy_present?(headers)
|
@@ -193,14 +193,14 @@ module ActionDispatch # :nodoc:
|
|
193
193
|
end
|
194
194
|
end
|
195
195
|
|
196
|
-
# Specify whether to prevent the user agent from loading any assets over
|
197
|
-
#
|
196
|
+
# Specify whether to prevent the user agent from loading any assets over HTTP
|
197
|
+
# when the page uses HTTPS:
|
198
198
|
#
|
199
|
-
#
|
199
|
+
# policy.block_all_mixed_content
|
200
200
|
#
|
201
|
-
# Pass
|
201
|
+
# Pass `false` to allow it again:
|
202
202
|
#
|
203
|
-
#
|
203
|
+
# policy.block_all_mixed_content false
|
204
204
|
#
|
205
205
|
def block_all_mixed_content(enabled = true)
|
206
206
|
if enabled
|
@@ -212,11 +212,11 @@ module ActionDispatch # :nodoc:
|
|
212
212
|
|
213
213
|
# Restricts the set of plugins that can be embedded:
|
214
214
|
#
|
215
|
-
#
|
215
|
+
# policy.plugin_types "application/x-shockwave-flash"
|
216
216
|
#
|
217
217
|
# Leave empty to allow all plugins:
|
218
218
|
#
|
219
|
-
#
|
219
|
+
# policy.plugin_types
|
220
220
|
#
|
221
221
|
def plugin_types(*types)
|
222
222
|
if types.first
|
@@ -226,23 +226,25 @@ module ActionDispatch # :nodoc:
|
|
226
226
|
end
|
227
227
|
end
|
228
228
|
|
229
|
-
# Enable the
|
230
|
-
#
|
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:
|
231
233
|
#
|
232
|
-
#
|
234
|
+
# policy.report_uri "/csp-violation-report-endpoint"
|
233
235
|
#
|
234
236
|
def report_uri(uri)
|
235
237
|
@directives["report-uri"] = [uri]
|
236
238
|
end
|
237
239
|
|
238
|
-
# Specify asset types for which
|
239
|
-
# is required:
|
240
|
+
# Specify asset types for which [Subresource Integrity]
|
241
|
+
# (https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) is required:
|
240
242
|
#
|
241
|
-
#
|
243
|
+
# policy.require_sri_for :script, :style
|
242
244
|
#
|
243
245
|
# Leave empty to not require Subresource Integrity:
|
244
246
|
#
|
245
|
-
#
|
247
|
+
# policy.require_sri_for
|
246
248
|
#
|
247
249
|
def require_sri_for(*types)
|
248
250
|
if types.first
|
@@ -252,18 +254,19 @@ module ActionDispatch # :nodoc:
|
|
252
254
|
end
|
253
255
|
end
|
254
256
|
|
255
|
-
# Specify whether a
|
257
|
+
# Specify whether a [sandbox]
|
258
|
+
# (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox)
|
256
259
|
# should be enabled for the requested resource:
|
257
260
|
#
|
258
|
-
#
|
261
|
+
# policy.sandbox
|
259
262
|
#
|
260
263
|
# Values can be passed as arguments:
|
261
264
|
#
|
262
|
-
#
|
265
|
+
# policy.sandbox "allow-scripts", "allow-modals"
|
263
266
|
#
|
264
|
-
# Pass
|
267
|
+
# Pass `false` to disable the sandbox:
|
265
268
|
#
|
266
|
-
#
|
269
|
+
# policy.sandbox false
|
267
270
|
#
|
268
271
|
def sandbox(*values)
|
269
272
|
if values.empty?
|
@@ -277,11 +280,11 @@ module ActionDispatch # :nodoc:
|
|
277
280
|
|
278
281
|
# Specify whether user agents should treat any assets over HTTP as HTTPS:
|
279
282
|
#
|
280
|
-
#
|
283
|
+
# policy.upgrade_insecure_requests
|
281
284
|
#
|
282
|
-
# Pass
|
285
|
+
# Pass `false` to disable it:
|
283
286
|
#
|
284
|
-
#
|
287
|
+
# policy.upgrade_insecure_requests false
|
285
288
|
#
|
286
289
|
def upgrade_insecure_requests(enabled = true)
|
287
290
|
if enabled
|
@@ -320,9 +323,9 @@ module ActionDispatch # :nodoc:
|
|
320
323
|
@directives.map do |directive, sources|
|
321
324
|
if sources.is_a?(Array)
|
322
325
|
if nonce && nonce_directive?(directive, nonce_directives)
|
323
|
-
"#{directive} #{build_directive(
|
326
|
+
"#{directive} #{build_directive(sources, context).join(' ')} 'nonce-#{nonce}'"
|
324
327
|
else
|
325
|
-
"#{directive} #{build_directive(
|
328
|
+
"#{directive} #{build_directive(sources, context).join(' ')}"
|
326
329
|
end
|
327
330
|
elsif sources
|
328
331
|
directive
|
@@ -332,22 +335,8 @@ module ActionDispatch # :nodoc:
|
|
332
335
|
end
|
333
336
|
end
|
334
337
|
|
335
|
-
def
|
336
|
-
sources.
|
337
|
-
if source.include?(";") || source != source.gsub(/[[:space:]]/, "")
|
338
|
-
raise InvalidDirectiveError, <<~MSG.squish
|
339
|
-
Invalid Content Security Policy #{directive}: "#{source}".
|
340
|
-
Directive values must not contain whitespace or semicolons.
|
341
|
-
Please use multiple arguments or other directive methods instead.
|
342
|
-
MSG
|
343
|
-
end
|
344
|
-
end
|
345
|
-
end
|
346
|
-
|
347
|
-
def build_directive(directive, sources, context)
|
348
|
-
resolved_sources = sources.map { |source| resolve_source(source, context) }
|
349
|
-
|
350
|
-
validate(directive, resolved_sources)
|
338
|
+
def build_directive(sources, context)
|
339
|
+
sources.map { |source| resolve_source(source, context) }
|
351
340
|
end
|
352
341
|
|
353
342
|
def resolve_source(source, context)
|
@@ -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,17 +68,12 @@ module ActionDispatch
|
|
64
68
|
ActiveSupport::ParameterFilter.new(filters)
|
65
69
|
end
|
66
70
|
|
71
|
+
KV_RE = "[^&;=]+"
|
72
|
+
PAIR_RE = %r{(#{KV_RE})=(#{KV_RE})}
|
67
73
|
def filtered_query_string # :doc:
|
68
|
-
|
69
|
-
|
70
|
-
if part.include?("=")
|
71
|
-
key, value = part.split("=", 2)
|
72
|
-
parameter_filter.filter(key => value).first.join("=")
|
73
|
-
else
|
74
|
-
part
|
75
|
-
end
|
74
|
+
query_string.gsub(PAIR_RE) do |_|
|
75
|
+
parameter_filter.filter($1 => $2).first.join("=")
|
76
76
|
end
|
77
|
-
filtered_parts.join("")
|
78
77
|
end
|
79
78
|
end
|
80
79
|
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,18 @@ 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
|
+
uri.query.gsub!(FilterParameters::PAIR_RE) do
|
41
|
+
request.parameter_filter.filter($1 => $2).first.join("=")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
uri.to_s
|
45
|
+
rescue URI::Error
|
46
|
+
FILTERED
|
47
|
+
end
|
34
48
|
end
|
35
49
|
end
|
36
50
|
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
|
|
@@ -173,8 +176,9 @@ module Mime
|
|
173
176
|
EXTENSION_LOOKUP[extension.to_s]
|
174
177
|
end
|
175
178
|
|
176
|
-
# Registers an alias that's not used on MIME type lookup, but can be referenced
|
177
|
-
# 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.
|
178
182
|
def register_alias(string, symbol, extension_synonyms = [])
|
179
183
|
register(string, symbol, [], extension_synonyms, true)
|
180
184
|
end
|
@@ -224,11 +228,11 @@ module Mime
|
|
224
228
|
parse_data_with_trailing_star($1) if accept_header =~ TRAILING_STAR_REGEXP
|
225
229
|
end
|
226
230
|
|
227
|
-
# For an input of
|
228
|
-
# 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]]`.
|
229
233
|
#
|
230
|
-
# For an input of
|
231
|
-
# 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]]`.
|
232
236
|
def parse_data_with_trailing_star(type)
|
233
237
|
Mime::SET.select { |m| m.match?(type) }
|
234
238
|
end
|
@@ -237,7 +241,7 @@ module Mime
|
|
237
241
|
#
|
238
242
|
# To unregister a MIME type:
|
239
243
|
#
|
240
|
-
#
|
244
|
+
# Mime::Type.unregister(:mobile)
|
241
245
|
def unregister(symbol)
|
242
246
|
symbol = symbol.downcase
|
243
247
|
if mime = Mime[symbol]
|
@@ -329,7 +333,7 @@ module Mime
|
|
329
333
|
def to_ary; end
|
330
334
|
def to_a; end
|
331
335
|
|
332
|
-
def method_missing(method,
|
336
|
+
def method_missing(method, ...)
|
333
337
|
if method.end_with?("?")
|
334
338
|
method[0..-2].downcase.to_sym == to_sym
|
335
339
|
else
|
@@ -353,9 +357,9 @@ module Mime
|
|
353
357
|
def html?; true; end
|
354
358
|
end
|
355
359
|
|
356
|
-
# ALL isn't a real MIME type, so we don't register it for lookup with the
|
357
|
-
#
|
358
|
-
#
|
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.
|
359
363
|
ALL = AllType.instance
|
360
364
|
|
361
365
|
class NullType
|
@@ -376,7 +380,7 @@ module Mime
|
|
376
380
|
method.end_with?("?")
|
377
381
|
end
|
378
382
|
|
379
|
-
def method_missing(method,
|
383
|
+
def method_missing(method, ...)
|
380
384
|
false if method.end_with?("?")
|
381
385
|
end
|
382
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 )
|