actionpack 4.2.11.1 → 6.1.3.2
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 +291 -489
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -9
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +81 -51
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +64 -17
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/abstract_controller/callbacks.rb +61 -33
- data/lib/abstract_controller/collector.rb +9 -13
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +115 -99
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +21 -3
- data/lib/abstract_controller/rendering.rb +48 -47
- data/lib/abstract_controller/translation.rb +17 -8
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/abstract_controller.rb +13 -5
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/api.rb +150 -0
- data/lib/action_controller/base.rb +29 -24
- data/lib/action_controller/caching.rb +12 -57
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +17 -19
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +134 -46
- data/lib/action_controller/metal/content_security_policy.rb +51 -0
- data/lib/action_controller/metal/cookies.rb +6 -4
- data/lib/action_controller/metal/data_streaming.rb +30 -50
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +21 -16
- data/lib/action_controller/metal/exceptions.rb +63 -15
- data/lib/action_controller/metal/flash.rb +9 -8
- data/lib/action_controller/metal/head.rb +26 -21
- data/lib/action_controller/metal/helpers.rb +37 -18
- data/lib/action_controller/metal/http_authentication.rb +81 -73
- data/lib/action_controller/metal/implicit_render.rb +53 -9
- data/lib/action_controller/metal/instrumentation.rb +32 -35
- data/lib/action_controller/metal/live.rb +102 -120
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +49 -47
- data/lib/action_controller/metal/parameter_encoding.rb +82 -0
- data/lib/action_controller/metal/params_wrapper.rb +83 -66
- data/lib/action_controller/metal/permissions_policy.rb +46 -0
- data/lib/action_controller/metal/redirecting.rb +53 -32
- data/lib/action_controller/metal/renderers.rb +87 -44
- data/lib/action_controller/metal/rendering.rb +77 -50
- data/lib/action_controller/metal/request_forgery_protection.rb +267 -103
- data/lib/action_controller/metal/rescue.rb +10 -17
- data/lib/action_controller/metal/streaming.rb +12 -11
- data/lib/action_controller/metal/strong_parameters.rb +714 -186
- data/lib/action_controller/metal/testing.rb +2 -17
- data/lib/action_controller/metal/url_for.rb +19 -10
- data/lib/action_controller/metal.rb +104 -87
- data/lib/action_controller/railtie.rb +28 -10
- data/lib/action_controller/railties/helpers.rb +3 -1
- data/lib/action_controller/renderer.rb +141 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +296 -422
- data/lib/action_controller.rb +34 -23
- data/lib/action_dispatch/http/cache.rb +107 -56
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +286 -0
- data/lib/action_dispatch/http/filter_parameters.rb +32 -25
- data/lib/action_dispatch/http/filter_redirect.rb +10 -12
- data/lib/action_dispatch/http/headers.rb +55 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +79 -51
- data/lib/action_dispatch/http/mime_type.rb +153 -121
- data/lib/action_dispatch/http/mime_types.rb +20 -6
- data/lib/action_dispatch/http/parameters.rb +90 -40
- data/lib/action_dispatch/http/permissions_policy.rb +173 -0
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +226 -121
- data/lib/action_dispatch/http/response.rb +248 -113
- data/lib/action_dispatch/http/upload.rb +21 -7
- data/lib/action_dispatch/http/url.rb +182 -100
- data/lib/action_dispatch/journey/formatter.rb +90 -43
- data/lib/action_dispatch/journey/gtg/builder.rb +28 -41
- data/lib/action_dispatch/journey/gtg/simulator.rb +11 -16
- data/lib/action_dispatch/journey/gtg/transition_table.rb +23 -21
- data/lib/action_dispatch/journey/nfa/dot.rb +3 -14
- data/lib/action_dispatch/journey/nodes/node.rb +29 -15
- data/lib/action_dispatch/journey/parser.rb +17 -16
- data/lib/action_dispatch/journey/parser.y +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +12 -4
- data/lib/action_dispatch/journey/path/pattern.rb +58 -54
- data/lib/action_dispatch/journey/route.rb +100 -32
- data/lib/action_dispatch/journey/router/utils.rb +29 -18
- data/lib/action_dispatch/journey/router.rb +55 -51
- data/lib/action_dispatch/journey/routes.rb +17 -17
- data/lib/action_dispatch/journey/scanner.rb +26 -17
- data/lib/action_dispatch/journey/visitors.rb +98 -54
- data/lib/action_dispatch/journey.rb +5 -5
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/callbacks.rb +3 -6
- data/lib/action_dispatch/middleware/cookies.rb +347 -217
- data/lib/action_dispatch/middleware/debug_exceptions.rb +135 -63
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/debug_view.rb +66 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +115 -71
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +78 -54
- data/lib/action_dispatch/middleware/host_authorization.rb +130 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +32 -27
- data/lib/action_dispatch/middleware/reloader.rb +5 -91
- data/lib/action_dispatch/middleware/remote_ip.rb +53 -45
- data/lib/action_dispatch/middleware/request_id.rb +17 -10
- data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -26
- data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
- data/lib/action_dispatch/middleware/session/cookie_store.rb +74 -75
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +28 -23
- data/lib/action_dispatch/middleware/ssl.rb +118 -35
- data/lib/action_dispatch/middleware/stack.rb +82 -41
- data/lib/action_dispatch/middleware/static.rb +156 -89
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -14
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +15 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +105 -8
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +87 -64
- data/lib/action_dispatch/railtie.rb +27 -13
- data/lib/action_dispatch/request/session.rb +109 -61
- data/lib/action_dispatch/request/utils.rb +90 -23
- data/lib/action_dispatch/routing/endpoint.rb +9 -2
- data/lib/action_dispatch/routing/inspector.rb +141 -102
- data/lib/action_dispatch/routing/mapper.rb +811 -473
- data/lib/action_dispatch/routing/polymorphic_routes.rb +167 -143
- data/lib/action_dispatch/routing/redirection.rb +37 -27
- data/lib/action_dispatch/routing/route_set.rb +363 -331
- data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
- data/lib/action_dispatch/routing/url_for.rb +66 -26
- data/lib/action_dispatch/routing.rb +36 -36
- data/lib/action_dispatch/system_test_case.rb +190 -0
- data/lib/action_dispatch/system_testing/browser.rb +86 -0
- data/lib/action_dispatch/system_testing/driver.rb +67 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +138 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +29 -0
- data/lib/action_dispatch/testing/assertion_response.rb +46 -0
- data/lib/action_dispatch/testing/assertions/response.rb +44 -22
- data/lib/action_dispatch/testing/assertions/routing.rb +47 -31
- data/lib/action_dispatch/testing/assertions.rb +6 -4
- data/lib/action_dispatch/testing/integration.rb +391 -220
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +53 -22
- data/lib/action_dispatch/testing/test_request.rb +27 -34
- data/lib/action_dispatch/testing/test_response.rb +11 -11
- data/lib/action_dispatch.rb +35 -21
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +4 -2
- metadata +78 -48
- data/lib/action_controller/metal/force_ssl.rb +0 -97
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/http/parameter_filter.rb +0 -72
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,14 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/parameter_filter"
|
4
4
|
|
5
5
|
module ActionDispatch
|
6
6
|
module Http
|
7
7
|
# Allows you to specify sensitive parameters which will be replaced from
|
8
8
|
# the request log by looking in the query string of the request and all
|
9
|
-
# sub-hashes of the params hash to filter.
|
10
|
-
#
|
11
|
-
#
|
9
|
+
# sub-hashes of the params hash to filter. Filtering only certain sub-keys
|
10
|
+
# from a hash is possible by using the dot notation: 'credit_card.number'.
|
11
|
+
# If a block is given, each key and value of the params hash and all
|
12
|
+
# sub-hashes are passed to it, where the value or the key can be replaced using
|
13
|
+
# String#replace or similar methods.
|
12
14
|
#
|
13
15
|
# env["action_dispatch.parameter_filter"] = [:password]
|
14
16
|
# => replaces the value to all keys matching /password/i with "[FILTERED]"
|
@@ -16,61 +18,66 @@ module ActionDispatch
|
|
16
18
|
# env["action_dispatch.parameter_filter"] = [:foo, "bar"]
|
17
19
|
# => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
|
18
20
|
#
|
19
|
-
# env["action_dispatch.parameter_filter"] =
|
20
|
-
#
|
21
|
+
# env["action_dispatch.parameter_filter"] = [ "credit_card.code" ]
|
22
|
+
# => replaces { credit_card: {code: "xxxx"} } with "[FILTERED]", does not
|
23
|
+
# change { file: { code: "xxxx"} }
|
24
|
+
#
|
25
|
+
# env["action_dispatch.parameter_filter"] = -> (k, v) do
|
26
|
+
# v.reverse! if k.match?(/secret/i)
|
21
27
|
# end
|
22
28
|
# => reverses the value to all keys matching /secret/i
|
23
29
|
module FilterParameters
|
24
30
|
ENV_MATCH = [/RAW_POST_DATA/, "rack.request.form_vars"] # :nodoc:
|
25
|
-
NULL_PARAM_FILTER = ParameterFilter.new # :nodoc:
|
26
|
-
NULL_ENV_FILTER = ParameterFilter.new ENV_MATCH # :nodoc:
|
31
|
+
NULL_PARAM_FILTER = ActiveSupport::ParameterFilter.new # :nodoc:
|
32
|
+
NULL_ENV_FILTER = ActiveSupport::ParameterFilter.new ENV_MATCH # :nodoc:
|
27
33
|
|
28
|
-
def initialize
|
34
|
+
def initialize
|
29
35
|
super
|
30
36
|
@filtered_parameters = nil
|
31
37
|
@filtered_env = nil
|
32
38
|
@filtered_path = nil
|
33
39
|
end
|
34
40
|
|
35
|
-
#
|
41
|
+
# Returns a hash of parameters with all sensitive data replaced.
|
36
42
|
def filtered_parameters
|
37
43
|
@filtered_parameters ||= parameter_filter.filter(parameters)
|
44
|
+
rescue ActionDispatch::Http::Parameters::ParseError
|
45
|
+
@filtered_parameters = {}
|
38
46
|
end
|
39
47
|
|
40
|
-
#
|
48
|
+
# Returns a hash of request.env with all sensitive data replaced.
|
41
49
|
def filtered_env
|
42
50
|
@filtered_env ||= env_filter.filter(@env)
|
43
51
|
end
|
44
52
|
|
45
|
-
#
|
53
|
+
# Reconstructs a path with all sensitive GET parameters replaced.
|
46
54
|
def filtered_path
|
47
55
|
@filtered_path ||= query_string.empty? ? path : "#{path}?#{filtered_query_string}"
|
48
56
|
end
|
49
57
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
parameter_filter_for @env.fetch("action_dispatch.parameter_filter") {
|
58
|
+
private
|
59
|
+
def parameter_filter # :doc:
|
60
|
+
parameter_filter_for fetch_header("action_dispatch.parameter_filter") {
|
54
61
|
return NULL_PARAM_FILTER
|
55
62
|
}
|
56
63
|
end
|
57
64
|
|
58
|
-
def env_filter
|
59
|
-
user_key =
|
65
|
+
def env_filter # :doc:
|
66
|
+
user_key = fetch_header("action_dispatch.parameter_filter") {
|
60
67
|
return NULL_ENV_FILTER
|
61
68
|
}
|
62
69
|
parameter_filter_for(Array(user_key) + ENV_MATCH)
|
63
70
|
end
|
64
71
|
|
65
|
-
def parameter_filter_for(filters)
|
66
|
-
ParameterFilter.new(filters)
|
72
|
+
def parameter_filter_for(filters) # :doc:
|
73
|
+
ActiveSupport::ParameterFilter.new(filters)
|
67
74
|
end
|
68
75
|
|
69
|
-
KV_RE =
|
76
|
+
KV_RE = "[^&;=]+"
|
70
77
|
PAIR_RE = %r{(#{KV_RE})=(#{KV_RE})}
|
71
|
-
def filtered_query_string
|
78
|
+
def filtered_query_string # :doc:
|
72
79
|
query_string.gsub(PAIR_RE) do |_|
|
73
|
-
parameter_filter.filter(
|
80
|
+
parameter_filter.filter($1 => $2).first.join("=")
|
74
81
|
end
|
75
82
|
end
|
76
83
|
end
|
@@ -1,12 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionDispatch
|
2
4
|
module Http
|
3
5
|
module FilterRedirect
|
6
|
+
FILTERED = "[FILTERED]" # :nodoc:
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
def filtered_location
|
8
|
-
filters = location_filter
|
9
|
-
if !filters.empty? && location_filter_match?(filters)
|
8
|
+
def filtered_location # :nodoc:
|
9
|
+
if location_filter_match?
|
10
10
|
FILTERED
|
11
11
|
else
|
12
12
|
location
|
@@ -14,25 +14,23 @@ module ActionDispatch
|
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
17
|
-
|
18
|
-
def location_filter
|
17
|
+
def location_filters
|
19
18
|
if request
|
20
|
-
request.
|
19
|
+
request.get_header("action_dispatch.redirect_filter") || []
|
21
20
|
else
|
22
21
|
[]
|
23
22
|
end
|
24
23
|
end
|
25
24
|
|
26
|
-
def location_filter_match?
|
27
|
-
|
25
|
+
def location_filter_match?
|
26
|
+
location_filters.any? do |filter|
|
28
27
|
if String === filter
|
29
28
|
location.include?(filter)
|
30
29
|
elsif Regexp === filter
|
31
|
-
location.match(filter)
|
30
|
+
location.match?(filter)
|
32
31
|
end
|
33
32
|
end
|
34
33
|
end
|
35
|
-
|
36
34
|
end
|
37
35
|
end
|
38
36
|
end
|
@@ -1,10 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionDispatch
|
2
4
|
module Http
|
3
5
|
# Provides access to the request's HTTP headers from the environment.
|
4
6
|
#
|
5
|
-
# env = { "CONTENT_TYPE" => "text/plain" }
|
6
|
-
# headers = ActionDispatch::Http::Headers.
|
7
|
+
# env = { "CONTENT_TYPE" => "text/plain", "HTTP_USER_AGENT" => "curl/7.43.0" }
|
8
|
+
# headers = ActionDispatch::Http::Headers.from_hash(env)
|
7
9
|
# headers["Content-Type"] # => "text/plain"
|
10
|
+
# headers["User-Agent"] # => "curl/7.43.0"
|
11
|
+
#
|
12
|
+
# Also note that when headers are mapped to CGI-like variables by the Rack
|
13
|
+
# server, both dashes and underscores are converted to underscores. This
|
14
|
+
# ambiguity cannot be resolved at this stage anymore. Both underscores and
|
15
|
+
# dashes have to be interpreted as if they were originally sent as dashes.
|
16
|
+
#
|
17
|
+
# # GET / HTTP/1.1
|
18
|
+
# # ...
|
19
|
+
# # User-Agent: curl/7.43.0
|
20
|
+
# # X_Custom_Header: token
|
21
|
+
#
|
22
|
+
# headers["X_Custom_Header"] # => nil
|
23
|
+
# headers["X-Custom-Header"] # => "token"
|
8
24
|
class Headers
|
9
25
|
CGI_VARIABLES = Set.new(%W[
|
10
26
|
AUTH_TYPE
|
@@ -30,27 +46,37 @@ module ActionDispatch
|
|
30
46
|
HTTP_HEADER = /\A[A-Za-z0-9-]+\z/
|
31
47
|
|
32
48
|
include Enumerable
|
33
|
-
attr_reader :env
|
34
49
|
|
35
|
-
def
|
36
|
-
|
50
|
+
def self.from_hash(hash)
|
51
|
+
new ActionDispatch::Request.new hash
|
52
|
+
end
|
53
|
+
|
54
|
+
def initialize(request) # :nodoc:
|
55
|
+
@req = request
|
37
56
|
end
|
38
57
|
|
39
58
|
# Returns the value for the given key mapped to @env.
|
40
59
|
def [](key)
|
41
|
-
@
|
60
|
+
@req.get_header env_name(key)
|
42
61
|
end
|
43
62
|
|
44
63
|
# Sets the given value for the key mapped to @env.
|
45
64
|
def []=(key, value)
|
46
|
-
@
|
65
|
+
@req.set_header env_name(key), value
|
66
|
+
end
|
67
|
+
|
68
|
+
# Add a value to a multivalued header like Vary or Accept-Encoding.
|
69
|
+
def add(key, value)
|
70
|
+
@req.add_header env_name(key), value
|
47
71
|
end
|
48
72
|
|
49
73
|
def key?(key)
|
50
|
-
@
|
74
|
+
@req.has_header? env_name(key)
|
51
75
|
end
|
52
76
|
alias :include? :key?
|
53
77
|
|
78
|
+
DEFAULT = Object.new # :nodoc:
|
79
|
+
|
54
80
|
# Returns the value for the given key mapped to @env.
|
55
81
|
#
|
56
82
|
# If the key is not found and an optional code block is not provided,
|
@@ -58,18 +84,22 @@ module ActionDispatch
|
|
58
84
|
#
|
59
85
|
# If the code block is provided, then it will be run and
|
60
86
|
# its result returned.
|
61
|
-
def fetch(key,
|
62
|
-
@
|
87
|
+
def fetch(key, default = DEFAULT)
|
88
|
+
@req.fetch_header(env_name(key)) do
|
89
|
+
return default unless default == DEFAULT
|
90
|
+
return yield if block_given?
|
91
|
+
raise KeyError, key
|
92
|
+
end
|
63
93
|
end
|
64
94
|
|
65
95
|
def each(&block)
|
66
|
-
@
|
96
|
+
@req.each_header(&block)
|
67
97
|
end
|
68
98
|
|
69
99
|
# Returns a new Http::Headers instance containing the contents of
|
70
100
|
# <tt>headers_or_env</tt> and the original instance.
|
71
101
|
def merge(headers_or_env)
|
72
|
-
headers =
|
102
|
+
headers = @req.dup.headers
|
73
103
|
headers.merge!(headers_or_env)
|
74
104
|
headers
|
75
105
|
end
|
@@ -79,21 +109,24 @@ module ActionDispatch
|
|
79
109
|
# <tt>headers_or_env</tt>.
|
80
110
|
def merge!(headers_or_env)
|
81
111
|
headers_or_env.each do |key, value|
|
82
|
-
|
112
|
+
@req.set_header env_name(key), value
|
83
113
|
end
|
84
114
|
end
|
85
115
|
|
116
|
+
def env; @req.env.dup; end
|
117
|
+
|
86
118
|
private
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
119
|
+
# Converts an HTTP header name to an environment variable name if it is
|
120
|
+
# not contained within the headers hash.
|
121
|
+
def env_name(key)
|
122
|
+
key = key.to_s
|
123
|
+
if HTTP_HEADER.match?(key)
|
124
|
+
key = key.upcase
|
125
|
+
key.tr!("-", "_")
|
126
|
+
key.prepend("HTTP_") unless CGI_VARIABLES.include?(key)
|
127
|
+
end
|
128
|
+
key
|
94
129
|
end
|
95
|
-
key
|
96
|
-
end
|
97
130
|
end
|
98
131
|
end
|
99
132
|
end
|
@@ -1,28 +1,34 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/module/attribute_accessors"
|
2
4
|
|
3
5
|
module ActionDispatch
|
4
6
|
module Http
|
5
7
|
module MimeNegotiation
|
6
8
|
extend ActiveSupport::Concern
|
7
9
|
|
10
|
+
class InvalidType < ::Mime::Type::InvalidMimeType; end
|
11
|
+
|
12
|
+
RESCUABLE_MIME_FORMAT_ERRORS = [
|
13
|
+
ActionController::BadRequest,
|
14
|
+
ActionDispatch::Http::Parameters::ParseError,
|
15
|
+
]
|
16
|
+
|
8
17
|
included do
|
9
|
-
mattr_accessor :ignore_accept_header
|
10
|
-
self.ignore_accept_header = false
|
18
|
+
mattr_accessor :ignore_accept_header, default: false
|
11
19
|
end
|
12
20
|
|
13
|
-
|
14
|
-
|
15
|
-
# The MIME type of the HTTP request, such as Mime::XML.
|
16
|
-
#
|
17
|
-
# For backward compatibility, the post \format is extracted from the
|
18
|
-
# X-Post-Data-Format HTTP header if present.
|
21
|
+
# The MIME type of the HTTP request, such as Mime[:xml].
|
19
22
|
def content_mime_type
|
20
|
-
|
21
|
-
if
|
23
|
+
fetch_header("action_dispatch.request.content_type") do |k|
|
24
|
+
v = if get_header("CONTENT_TYPE") =~ /^([^,\;]*)/
|
22
25
|
Mime::Type.lookup($1.strip.downcase)
|
23
26
|
else
|
24
27
|
nil
|
25
28
|
end
|
29
|
+
set_header k, v
|
30
|
+
rescue ::Mime::Type::InvalidMimeType => e
|
31
|
+
raise InvalidType, e.message
|
26
32
|
end
|
27
33
|
end
|
28
34
|
|
@@ -30,67 +36,73 @@ module ActionDispatch
|
|
30
36
|
content_mime_type && content_mime_type.to_s
|
31
37
|
end
|
32
38
|
|
39
|
+
def has_content_type? # :nodoc:
|
40
|
+
get_header "CONTENT_TYPE"
|
41
|
+
end
|
42
|
+
|
33
43
|
# Returns the accepted MIME type for the request.
|
34
44
|
def accepts
|
35
|
-
|
36
|
-
header =
|
45
|
+
fetch_header("action_dispatch.request.accepts") do |k|
|
46
|
+
header = get_header("HTTP_ACCEPT").to_s.strip
|
37
47
|
|
38
|
-
if header.empty?
|
48
|
+
v = if header.empty?
|
39
49
|
[content_mime_type]
|
40
50
|
else
|
41
51
|
Mime::Type.parse(header)
|
42
52
|
end
|
53
|
+
set_header k, v
|
54
|
+
rescue ::Mime::Type::InvalidMimeType => e
|
55
|
+
raise InvalidType, e.message
|
43
56
|
end
|
44
57
|
end
|
45
58
|
|
46
59
|
# Returns the MIME type for the \format used in the request.
|
47
60
|
#
|
48
|
-
# GET /posts/5.xml | request.format => Mime
|
49
|
-
# GET /posts/5.xhtml | request.format => Mime
|
50
|
-
# GET /posts/5 | request.format => Mime
|
61
|
+
# GET /posts/5.xml | request.format => Mime[:xml]
|
62
|
+
# GET /posts/5.xhtml | request.format => Mime[:html]
|
63
|
+
# GET /posts/5 | request.format => Mime[:html] or Mime[:js], or request.accepts.first
|
51
64
|
#
|
52
65
|
def format(view_path = [])
|
53
66
|
formats.first || Mime::NullType.instance
|
54
67
|
end
|
55
68
|
|
56
69
|
def formats
|
57
|
-
|
58
|
-
|
59
|
-
parameters[:format]
|
60
|
-
rescue ActionController::BadRequest
|
61
|
-
false
|
62
|
-
end
|
63
|
-
|
64
|
-
v = if params_readable
|
70
|
+
fetch_header("action_dispatch.request.formats") do |k|
|
71
|
+
v = if params_readable?
|
65
72
|
Array(Mime[parameters[:format]])
|
66
73
|
elsif use_accept_header && valid_accept_header
|
67
74
|
accepts
|
75
|
+
elsif extension_format = format_from_path_extension
|
76
|
+
[extension_format]
|
68
77
|
elsif xhr?
|
69
|
-
[Mime
|
78
|
+
[Mime[:js]]
|
70
79
|
else
|
71
|
-
[Mime
|
80
|
+
[Mime[:html]]
|
72
81
|
end
|
73
82
|
|
74
|
-
v.select do |format|
|
83
|
+
v = v.select do |format|
|
75
84
|
format.symbol || format.ref == "*/*"
|
76
85
|
end
|
86
|
+
|
87
|
+
set_header k, v
|
77
88
|
end
|
78
89
|
end
|
79
90
|
|
80
91
|
# Sets the \variant for template.
|
81
92
|
def variant=(variant)
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
@variant = variant
|
93
|
+
variant = Array(variant)
|
94
|
+
|
95
|
+
if variant.all? { |v| v.is_a?(Symbol) }
|
96
|
+
@variant = ActiveSupport::ArrayInquirer.new(variant)
|
86
97
|
else
|
87
|
-
raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols
|
88
|
-
"For security reasons, never directly set the variant to a user-provided value, " \
|
89
|
-
"like params[:variant].to_sym. Check user-provided value against a whitelist first, " \
|
90
|
-
"then set the variant: request.variant = :tablet if params[:variant] == 'tablet'"
|
98
|
+
raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols."
|
91
99
|
end
|
92
100
|
end
|
93
101
|
|
102
|
+
def variant
|
103
|
+
@variant ||= ActiveSupport::ArrayInquirer.new
|
104
|
+
end
|
105
|
+
|
94
106
|
# Sets the \format by string extension, which can be used to force custom formats
|
95
107
|
# that are not controlled by the extension.
|
96
108
|
#
|
@@ -104,7 +116,7 @@ module ActionDispatch
|
|
104
116
|
# end
|
105
117
|
def format=(extension)
|
106
118
|
parameters[:format] = extension.to_s
|
107
|
-
|
119
|
+
set_header "action_dispatch.request.formats", [Mime::Type.lookup_by_extension(parameters[:format])]
|
108
120
|
end
|
109
121
|
|
110
122
|
# Sets the \formats by string extensions. This differs from #format= by allowing you
|
@@ -123,14 +135,12 @@ module ActionDispatch
|
|
123
135
|
# end
|
124
136
|
def formats=(extensions)
|
125
137
|
parameters[:format] = extensions.first.to_s
|
126
|
-
|
138
|
+
set_header "action_dispatch.request.formats", extensions.collect { |extension|
|
127
139
|
Mime::Type.lookup_by_extension(extension)
|
128
|
-
|
140
|
+
}
|
129
141
|
end
|
130
142
|
|
131
|
-
#
|
132
|
-
# matches the order array.
|
133
|
-
#
|
143
|
+
# Returns the first MIME type that matches the provided array of MIME types.
|
134
144
|
def negotiate_mime(order)
|
135
145
|
formats.each do |priority|
|
136
146
|
if priority == Mime::ALL
|
@@ -143,18 +153,36 @@ module ActionDispatch
|
|
143
153
|
order.include?(Mime::ALL) ? format : nil
|
144
154
|
end
|
145
155
|
|
146
|
-
|
156
|
+
def should_apply_vary_header?
|
157
|
+
!params_readable? && use_accept_header && valid_accept_header
|
158
|
+
end
|
147
159
|
|
148
|
-
|
160
|
+
private
|
161
|
+
# We use normal content negotiation unless you include */* in your list,
|
162
|
+
# in which case we assume you're a browser and send HTML.
|
163
|
+
BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
|
149
164
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
165
|
+
def params_readable? # :doc:
|
166
|
+
parameters[:format]
|
167
|
+
rescue *RESCUABLE_MIME_FORMAT_ERRORS
|
168
|
+
false
|
169
|
+
end
|
154
170
|
|
155
|
-
|
156
|
-
|
157
|
-
|
171
|
+
def valid_accept_header # :doc:
|
172
|
+
(xhr? && (accept.present? || content_mime_type)) ||
|
173
|
+
(accept.present? && !accept.match?(BROWSER_LIKE_ACCEPTS))
|
174
|
+
end
|
175
|
+
|
176
|
+
def use_accept_header # :doc:
|
177
|
+
!self.class.ignore_accept_header
|
178
|
+
end
|
179
|
+
|
180
|
+
def format_from_path_extension # :doc:
|
181
|
+
path = get_header("action_dispatch.original_path") || get_header("PATH_INFO")
|
182
|
+
if match = path && path.match(/\.(\w+)\z/)
|
183
|
+
Mime[match.captures.first]
|
184
|
+
end
|
185
|
+
end
|
158
186
|
end
|
159
187
|
end
|
160
188
|
end
|