actionpack 5.2.4.4 → 6.1.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 +264 -322
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -3
- data/lib/abstract_controller.rb +1 -0
- data/lib/abstract_controller/base.rb +38 -4
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/caching/fragments.rb +6 -22
- data/lib/abstract_controller/callbacks.rb +14 -2
- data/lib/abstract_controller/collector.rb +1 -2
- data/lib/abstract_controller/helpers.rb +106 -90
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
- data/lib/abstract_controller/rendering.rb +9 -9
- data/lib/abstract_controller/translation.rb +11 -5
- data/lib/action_controller.rb +7 -4
- data/lib/action_controller/api.rb +4 -3
- data/lib/action_controller/base.rb +6 -9
- data/lib/action_controller/caching.rb +1 -3
- data/lib/action_controller/log_subscriber.rb +10 -7
- data/lib/action_controller/metal.rb +10 -8
- data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
- data/lib/action_controller/metal/conditional_get.rb +19 -5
- data/lib/action_controller/metal/content_security_policy.rb +1 -2
- data/lib/action_controller/metal/cookies.rb +3 -1
- data/lib/action_controller/metal/data_streaming.rb +6 -7
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +3 -5
- data/lib/action_controller/metal/exceptions.rb +56 -2
- data/lib/action_controller/metal/flash.rb +5 -5
- data/lib/action_controller/metal/head.rb +7 -4
- data/lib/action_controller/metal/helpers.rb +14 -5
- data/lib/action_controller/metal/http_authentication.rb +24 -23
- data/lib/action_controller/metal/implicit_render.rb +5 -15
- data/lib/action_controller/metal/instrumentation.rb +13 -14
- data/lib/action_controller/metal/live.rb +30 -32
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +19 -4
- data/lib/action_controller/metal/parameter_encoding.rb +35 -4
- data/lib/action_controller/metal/params_wrapper.rb +31 -22
- data/lib/action_controller/metal/permissions_policy.rb +46 -0
- data/lib/action_controller/metal/redirecting.rb +6 -6
- data/lib/action_controller/metal/renderers.rb +4 -4
- data/lib/action_controller/metal/rendering.rb +8 -3
- data/lib/action_controller/metal/request_forgery_protection.rb +62 -34
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/streaming.rb +0 -1
- data/lib/action_controller/metal/strong_parameters.rb +167 -58
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +37 -13
- data/lib/action_controller/template_assertions.rb +1 -1
- data/lib/action_controller/test_case.rb +70 -65
- data/lib/action_dispatch.rb +9 -3
- data/lib/action_dispatch/http/cache.rb +26 -21
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +33 -19
- data/lib/action_dispatch/http/filter_parameters.rb +9 -8
- data/lib/action_dispatch/http/filter_redirect.rb +2 -3
- data/lib/action_dispatch/http/headers.rb +4 -4
- data/lib/action_dispatch/http/mime_negotiation.rb +26 -13
- data/lib/action_dispatch/http/mime_type.rb +42 -23
- data/lib/action_dispatch/http/parameters.rb +14 -23
- data/lib/action_dispatch/http/permissions_policy.rb +173 -0
- data/lib/action_dispatch/http/request.rb +45 -22
- data/lib/action_dispatch/http/response.rb +45 -25
- data/lib/action_dispatch/http/upload.rb +9 -1
- data/lib/action_dispatch/http/url.rb +82 -82
- data/lib/action_dispatch/journey.rb +0 -2
- data/lib/action_dispatch/journey/formatter.rb +54 -30
- data/lib/action_dispatch/journey/gtg/builder.rb +22 -37
- data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -5
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
- data/lib/action_dispatch/journey/nodes/node.rb +13 -11
- data/lib/action_dispatch/journey/parser.rb +13 -13
- data/lib/action_dispatch/journey/parser.y +1 -1
- data/lib/action_dispatch/journey/path/pattern.rb +19 -21
- data/lib/action_dispatch/journey/route.rb +10 -20
- data/lib/action_dispatch/journey/router.rb +26 -34
- data/lib/action_dispatch/journey/router/utils.rb +14 -12
- data/lib/action_dispatch/journey/routes.rb +0 -2
- data/lib/action_dispatch/journey/scanner.rb +10 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -4
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +128 -109
- data/lib/action_dispatch/middleware/debug_exceptions.rb +43 -66
- data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
- data/lib/action_dispatch/middleware/debug_view.rb +66 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -30
- data/lib/action_dispatch/middleware/flash.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +121 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +14 -16
- data/lib/action_dispatch/middleware/request_id.rb +5 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -3
- data/lib/action_dispatch/middleware/session/cookie_store.rb +3 -9
- data/lib/action_dispatch/middleware/show_exceptions.rb +3 -2
- data/lib/action_dispatch/middleware/ssl.rb +20 -15
- data/lib/action_dispatch/middleware/stack.rb +56 -2
- data/lib/action_dispatch/middleware/static.rb +153 -93
- 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 +3 -1
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
- 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 +6 -3
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -1
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +104 -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 +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +24 -1
- data/lib/action_dispatch/railtie.rb +8 -2
- data/lib/action_dispatch/request/session.rb +10 -9
- data/lib/action_dispatch/request/utils.rb +26 -2
- data/lib/action_dispatch/routing.rb +21 -20
- data/lib/action_dispatch/routing/inspector.rb +100 -52
- data/lib/action_dispatch/routing/mapper.rb +155 -103
- data/lib/action_dispatch/routing/polymorphic_routes.rb +13 -15
- data/lib/action_dispatch/routing/redirection.rb +3 -3
- data/lib/action_dispatch/routing/route_set.rb +71 -69
- data/lib/action_dispatch/routing/url_for.rb +2 -2
- data/lib/action_dispatch/system_test_case.rb +54 -11
- data/lib/action_dispatch/system_testing/browser.rb +53 -16
- data/lib/action_dispatch/system_testing/driver.rb +11 -3
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +49 -7
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +8 -10
- data/lib/action_dispatch/testing/assertion_response.rb +0 -1
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +4 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
- data/lib/action_dispatch/testing/integration.rb +61 -28
- data/lib/action_dispatch/testing/request_encoder.rb +2 -2
- data/lib/action_dispatch/testing/test_process.rb +29 -4
- data/lib/action_dispatch/testing/test_request.rb +3 -3
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/gem_version.rb +4 -4
- metadata +38 -26
- data/lib/action_controller/metal/force_ssl.rb +0 -99
- data/lib/action_dispatch/http/parameter_filter.rb +0 -86
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -57,7 +57,6 @@ module ActionDispatch
|
|
57
57
|
query_parameters.dup
|
58
58
|
end
|
59
59
|
params.merge!(path_parameters)
|
60
|
-
params = set_binary_encoding(params, params[:controller], params[:action])
|
61
60
|
set_header("action_dispatch.request.parameters", params)
|
62
61
|
params
|
63
62
|
end
|
@@ -66,7 +65,7 @@ module ActionDispatch
|
|
66
65
|
def path_parameters=(parameters) #:nodoc:
|
67
66
|
delete_header("action_dispatch.request.parameters")
|
68
67
|
|
69
|
-
parameters = set_binary_encoding(parameters, parameters[:controller], parameters[:action])
|
68
|
+
parameters = Request::Utils.set_binary_encoding(self, parameters, parameters[:controller], parameters[:action])
|
70
69
|
# If any of the path parameters has an invalid encoding then
|
71
70
|
# raise since it's likely to trigger errors further on.
|
72
71
|
Request::Utils.check_param_encoding(parameters)
|
@@ -85,24 +84,6 @@ module ActionDispatch
|
|
85
84
|
end
|
86
85
|
|
87
86
|
private
|
88
|
-
|
89
|
-
def set_binary_encoding(params, controller, action)
|
90
|
-
return params unless controller && controller.valid_encoding?
|
91
|
-
|
92
|
-
if binary_params_for?(controller, action)
|
93
|
-
ActionDispatch::Request::Utils.each_param_value(params) do |param|
|
94
|
-
param.force_encoding ::Encoding::ASCII_8BIT
|
95
|
-
end
|
96
|
-
end
|
97
|
-
params
|
98
|
-
end
|
99
|
-
|
100
|
-
def binary_params_for?(controller, action)
|
101
|
-
controller_class_for(controller).binary_params_for?(action)
|
102
|
-
rescue NameError
|
103
|
-
false
|
104
|
-
end
|
105
|
-
|
106
87
|
def parse_formatted_parameters(parsers)
|
107
88
|
return yield if content_length.zero? || content_mime_type.nil?
|
108
89
|
|
@@ -111,13 +92,23 @@ module ActionDispatch
|
|
111
92
|
begin
|
112
93
|
strategy.call(raw_post)
|
113
94
|
rescue # JSON or Ruby code block errors.
|
114
|
-
|
115
|
-
my_logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{raw_post}"
|
116
|
-
|
95
|
+
log_parse_error_once
|
117
96
|
raise ParseError
|
118
97
|
end
|
119
98
|
end
|
120
99
|
|
100
|
+
def log_parse_error_once
|
101
|
+
@parse_error_logged ||= begin
|
102
|
+
parse_logger = logger || ActiveSupport::Logger.new($stderr)
|
103
|
+
parse_logger.debug <<~MSG.chomp
|
104
|
+
Error occurred while parsing request parameters.
|
105
|
+
Contents:
|
106
|
+
|
107
|
+
#{raw_post}
|
108
|
+
MSG
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
121
112
|
def params_parsers
|
122
113
|
ActionDispatch::Request.parameter_parsers
|
123
114
|
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/object/deep_dup"
|
4
|
+
|
5
|
+
module ActionDispatch #:nodoc:
|
6
|
+
class PermissionsPolicy
|
7
|
+
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
|
+
def initialize(app)
|
17
|
+
@app = app
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(env)
|
21
|
+
request = ActionDispatch::Request.new(env)
|
22
|
+
_, headers, _ = response = @app.call(env)
|
23
|
+
|
24
|
+
return response unless html_response?(headers)
|
25
|
+
return response if policy_present?(headers)
|
26
|
+
|
27
|
+
if policy = request.permissions_policy
|
28
|
+
headers[POLICY] = policy.build(request.controller_instance)
|
29
|
+
end
|
30
|
+
|
31
|
+
if policy_empty?(policy)
|
32
|
+
headers.delete(POLICY)
|
33
|
+
end
|
34
|
+
|
35
|
+
response
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def html_response?(headers)
|
40
|
+
if content_type = headers[CONTENT_TYPE]
|
41
|
+
/html/.match?(content_type)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def policy_present?(headers)
|
46
|
+
headers[POLICY]
|
47
|
+
end
|
48
|
+
|
49
|
+
def policy_empty?(policy)
|
50
|
+
policy&.directives&.empty?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
module Request
|
55
|
+
POLICY = "action_dispatch.permissions_policy"
|
56
|
+
|
57
|
+
def permissions_policy
|
58
|
+
get_header(POLICY)
|
59
|
+
end
|
60
|
+
|
61
|
+
def permissions_policy=(policy)
|
62
|
+
set_header(POLICY, policy)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
MAPPINGS = {
|
67
|
+
self: "'self'",
|
68
|
+
none: "'none'",
|
69
|
+
}.freeze
|
70
|
+
|
71
|
+
# List of available permissions can be found at
|
72
|
+
# https://github.com/w3c/webappsec-permissions-policy/blob/master/features.md#policy-controlled-features
|
73
|
+
DIRECTIVES = {
|
74
|
+
accelerometer: "accelerometer",
|
75
|
+
ambient_light_sensor: "ambient-light-sensor",
|
76
|
+
autoplay: "autoplay",
|
77
|
+
camera: "camera",
|
78
|
+
encrypted_media: "encrypted-media",
|
79
|
+
fullscreen: "fullscreen",
|
80
|
+
geolocation: "geolocation",
|
81
|
+
gyroscope: "gyroscope",
|
82
|
+
magnetometer: "magnetometer",
|
83
|
+
microphone: "microphone",
|
84
|
+
midi: "midi",
|
85
|
+
payment: "payment",
|
86
|
+
picture_in_picture: "picture-in-picture",
|
87
|
+
speaker: "speaker",
|
88
|
+
usb: "usb",
|
89
|
+
vibrate: "vibrate",
|
90
|
+
vr: "vr",
|
91
|
+
}.freeze
|
92
|
+
|
93
|
+
private_constant :MAPPINGS, :DIRECTIVES
|
94
|
+
|
95
|
+
attr_reader :directives
|
96
|
+
|
97
|
+
def initialize
|
98
|
+
@directives = {}
|
99
|
+
yield self if block_given?
|
100
|
+
end
|
101
|
+
|
102
|
+
def initialize_copy(other)
|
103
|
+
@directives = other.directives.deep_dup
|
104
|
+
end
|
105
|
+
|
106
|
+
DIRECTIVES.each do |name, directive|
|
107
|
+
define_method(name) do |*sources|
|
108
|
+
if sources.first
|
109
|
+
@directives[directive] = apply_mappings(sources)
|
110
|
+
else
|
111
|
+
@directives.delete(directive)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def build(context = nil)
|
117
|
+
build_directives(context).compact.join("; ")
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
def apply_mappings(sources)
|
122
|
+
sources.map do |source|
|
123
|
+
case source
|
124
|
+
when Symbol
|
125
|
+
apply_mapping(source)
|
126
|
+
when String, Proc
|
127
|
+
source
|
128
|
+
else
|
129
|
+
raise ArgumentError, "Invalid HTTP permissions policy source: #{source.inspect}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def apply_mapping(source)
|
135
|
+
MAPPINGS.fetch(source) do
|
136
|
+
raise ArgumentError, "Unknown HTTP permissions policy source mapping: #{source.inspect}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def build_directives(context)
|
141
|
+
@directives.map do |directive, sources|
|
142
|
+
if sources.is_a?(Array)
|
143
|
+
"#{directive} #{build_directive(sources, context).join(' ')}"
|
144
|
+
elsif sources
|
145
|
+
directive
|
146
|
+
else
|
147
|
+
nil
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def build_directive(sources, context)
|
153
|
+
sources.map { |source| resolve_source(source, context) }
|
154
|
+
end
|
155
|
+
|
156
|
+
def resolve_source(source, context)
|
157
|
+
case source
|
158
|
+
when String
|
159
|
+
source
|
160
|
+
when Symbol
|
161
|
+
source.to_s
|
162
|
+
when Proc
|
163
|
+
if context.nil?
|
164
|
+
raise RuntimeError, "Missing context for the dynamic permissions policy source: #{source.inspect}"
|
165
|
+
else
|
166
|
+
context.instance_exec(&source)
|
167
|
+
end
|
168
|
+
else
|
169
|
+
raise RuntimeError, "Unexpected permissions policy source: #{source.inspect}"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -23,6 +23,7 @@ module ActionDispatch
|
|
23
23
|
include ActionDispatch::Http::FilterParameters
|
24
24
|
include ActionDispatch::Http::URL
|
25
25
|
include ActionDispatch::ContentSecurityPolicy::Request
|
26
|
+
include ActionDispatch::PermissionsPolicy::Request
|
26
27
|
include Rack::Request::Env
|
27
28
|
|
28
29
|
autoload :Session, "action_dispatch/request/session"
|
@@ -44,11 +45,14 @@ module ActionDispatch
|
|
44
45
|
SERVER_ADDR
|
45
46
|
].freeze
|
46
47
|
|
48
|
+
# TODO: Remove SERVER_ADDR when we remove support to Rack 2.1.
|
49
|
+
# See https://github.com/rack/rack/commit/c173b188d81ee437b588c1e046a1c9f031dea550
|
47
50
|
ENV_METHODS.each do |env|
|
48
51
|
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
+
# frozen_string_literal: true
|
53
|
+
def #{env.delete_prefix("HTTP_").downcase} # def accept_charset
|
54
|
+
get_header "#{env}" # get_header "HTTP_ACCEPT_CHARSET"
|
55
|
+
end # end
|
52
56
|
METHOD
|
53
57
|
end
|
54
58
|
|
@@ -72,7 +76,7 @@ module ActionDispatch
|
|
72
76
|
PASS_NOT_FOUND = Class.new { # :nodoc:
|
73
77
|
def self.action(_); self; end
|
74
78
|
def self.call(_); [404, { "X-Cascade" => "pass" }, []]; end
|
75
|
-
def self.
|
79
|
+
def self.action_encoding_template(action); false; end
|
76
80
|
}
|
77
81
|
|
78
82
|
def controller_class
|
@@ -84,8 +88,16 @@ module ActionDispatch
|
|
84
88
|
def controller_class_for(name)
|
85
89
|
if name
|
86
90
|
controller_param = name.underscore
|
87
|
-
const_name =
|
88
|
-
|
91
|
+
const_name = controller_param.camelize << "Controller"
|
92
|
+
begin
|
93
|
+
ActiveSupport::Dependencies.constantize(const_name)
|
94
|
+
rescue NameError => error
|
95
|
+
if error.missing_name == const_name || const_name.start_with?("#{error.missing_name}::")
|
96
|
+
raise MissingController.new(error.message, error.name)
|
97
|
+
else
|
98
|
+
raise
|
99
|
+
end
|
100
|
+
end
|
89
101
|
else
|
90
102
|
PASS_NOT_FOUND
|
91
103
|
end
|
@@ -125,6 +137,8 @@ module ActionDispatch
|
|
125
137
|
HTTP_METHOD_LOOKUP[method] = method.underscore.to_sym
|
126
138
|
}
|
127
139
|
|
140
|
+
alias raw_request_method request_method # :nodoc:
|
141
|
+
|
128
142
|
# Returns the HTTP \method that the application should see.
|
129
143
|
# In the case where the \method was overridden by a middleware
|
130
144
|
# (for instance, if a HEAD request was converted to a GET,
|
@@ -136,11 +150,11 @@ module ActionDispatch
|
|
136
150
|
end
|
137
151
|
|
138
152
|
def routes # :nodoc:
|
139
|
-
get_header("action_dispatch.routes"
|
153
|
+
get_header("action_dispatch.routes")
|
140
154
|
end
|
141
155
|
|
142
156
|
def routes=(routes) # :nodoc:
|
143
|
-
set_header("action_dispatch.routes"
|
157
|
+
set_header("action_dispatch.routes", routes)
|
144
158
|
end
|
145
159
|
|
146
160
|
def engine_script_name(_routes) # :nodoc:
|
@@ -158,11 +172,11 @@ module ActionDispatch
|
|
158
172
|
end
|
159
173
|
|
160
174
|
def controller_instance # :nodoc:
|
161
|
-
get_header("action_controller.instance"
|
175
|
+
get_header("action_controller.instance")
|
162
176
|
end
|
163
177
|
|
164
178
|
def controller_instance=(controller) # :nodoc:
|
165
|
-
set_header("action_controller.instance"
|
179
|
+
set_header("action_controller.instance", controller)
|
166
180
|
end
|
167
181
|
|
168
182
|
def http_auth_salt
|
@@ -173,7 +187,7 @@ module ActionDispatch
|
|
173
187
|
# We're treating `nil` as "unset", and we want the default setting to be
|
174
188
|
# `true`. This logic should be extracted to `env_config` and calculated
|
175
189
|
# once.
|
176
|
-
!(get_header("action_dispatch.show_exceptions"
|
190
|
+
!(get_header("action_dispatch.show_exceptions") == false)
|
177
191
|
end
|
178
192
|
|
179
193
|
# Returns a symbol form of the #request_method.
|
@@ -264,7 +278,7 @@ module ActionDispatch
|
|
264
278
|
# (case-insensitive), which may need to be manually added depending on the
|
265
279
|
# choice of JavaScript libraries and frameworks.
|
266
280
|
def xml_http_request?
|
267
|
-
get_header("HTTP_X_REQUESTED_WITH")
|
281
|
+
/XMLHttpRequest/i.match?(get_header("HTTP_X_REQUESTED_WITH"))
|
268
282
|
end
|
269
283
|
alias :xhr? :xml_http_request?
|
270
284
|
|
@@ -280,10 +294,11 @@ module ActionDispatch
|
|
280
294
|
end
|
281
295
|
|
282
296
|
def remote_ip=(remote_ip)
|
283
|
-
|
297
|
+
@remote_ip = nil
|
298
|
+
set_header "action_dispatch.remote_ip", remote_ip
|
284
299
|
end
|
285
300
|
|
286
|
-
ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id"
|
301
|
+
ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
|
287
302
|
|
288
303
|
# Returns the unique request id, which is based on either the X-Request-Id header that can
|
289
304
|
# be generated by a firewall, load balancer, or web server or by the RequestId middleware
|
@@ -321,7 +336,7 @@ module ActionDispatch
|
|
321
336
|
# variable is already set, wrap it in a StringIO.
|
322
337
|
def body
|
323
338
|
if raw_post = get_header("RAW_POST_DATA")
|
324
|
-
raw_post = raw_post.
|
339
|
+
raw_post = (+raw_post).force_encoding(Encoding::BINARY)
|
325
340
|
StringIO.new(raw_post)
|
326
341
|
else
|
327
342
|
body_stream
|
@@ -366,6 +381,9 @@ module ActionDispatch
|
|
366
381
|
def GET
|
367
382
|
fetch_header("action_dispatch.request.query_parameters") do |k|
|
368
383
|
rack_query_params = super || {}
|
384
|
+
controller = path_parameters[:controller]
|
385
|
+
action = path_parameters[:action]
|
386
|
+
rack_query_params = Request::Utils.set_binary_encoding(self, rack_query_params, controller, action)
|
369
387
|
# Check for non UTF-8 parameter values, which would cause errors later
|
370
388
|
Request::Utils.check_param_encoding(rack_query_params)
|
371
389
|
set_header k, Request::Utils.normalize_encode_params(rack_query_params)
|
@@ -381,11 +399,10 @@ module ActionDispatch
|
|
381
399
|
pr = parse_formatted_parameters(params_parsers) do |params|
|
382
400
|
super || {}
|
383
401
|
end
|
402
|
+
pr = Request::Utils.set_binary_encoding(self, pr, path_parameters[:controller], path_parameters[:action])
|
403
|
+
Request::Utils.check_param_encoding(pr)
|
384
404
|
self.request_parameters = Request::Utils.normalize_encode_params(pr)
|
385
405
|
end
|
386
|
-
rescue Http::Parameters::ParseError # one of the parse strategies blew up
|
387
|
-
self.request_parameters = Request::Utils.normalize_encode_params(super || {})
|
388
|
-
raise
|
389
406
|
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
390
407
|
raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}")
|
391
408
|
end
|
@@ -402,23 +419,27 @@ module ActionDispatch
|
|
402
419
|
|
403
420
|
# True if the request came from localhost, 127.0.0.1, or ::1.
|
404
421
|
def local?
|
405
|
-
LOCALHOST
|
422
|
+
LOCALHOST.match?(remote_addr) && LOCALHOST.match?(remote_ip)
|
406
423
|
end
|
407
424
|
|
408
425
|
def request_parameters=(params)
|
409
426
|
raise if params.nil?
|
410
|
-
set_header("action_dispatch.request.request_parameters"
|
427
|
+
set_header("action_dispatch.request.request_parameters", params)
|
411
428
|
end
|
412
429
|
|
413
430
|
def logger
|
414
|
-
get_header("action_dispatch.logger"
|
431
|
+
get_header("action_dispatch.logger")
|
415
432
|
end
|
416
433
|
|
417
434
|
def commit_flash
|
418
435
|
end
|
419
436
|
|
420
437
|
def ssl?
|
421
|
-
super || scheme == "wss"
|
438
|
+
super || scheme == "wss"
|
439
|
+
end
|
440
|
+
|
441
|
+
def inspect # :nodoc:
|
442
|
+
"#<#{self.class.name} #{method} #{original_url.dump} for #{remote_ip}>"
|
422
443
|
end
|
423
444
|
|
424
445
|
private
|
@@ -428,3 +449,5 @@ module ActionDispatch
|
|
428
449
|
end
|
429
450
|
end
|
430
451
|
end
|
452
|
+
|
453
|
+
ActiveSupport.run_load_hooks :action_dispatch_request, ActionDispatch::Request
|
@@ -78,14 +78,26 @@ module ActionDispatch # :nodoc:
|
|
78
78
|
x
|
79
79
|
end
|
80
80
|
|
81
|
-
CONTENT_TYPE = "Content-Type"
|
82
|
-
SET_COOKIE = "Set-Cookie"
|
83
|
-
LOCATION = "Location"
|
84
|
-
NO_CONTENT_CODES = [100, 101, 102, 204, 205, 304]
|
81
|
+
CONTENT_TYPE = "Content-Type"
|
82
|
+
SET_COOKIE = "Set-Cookie"
|
83
|
+
LOCATION = "Location"
|
84
|
+
NO_CONTENT_CODES = [100, 101, 102, 103, 204, 205, 304]
|
85
85
|
|
86
86
|
cattr_accessor :default_charset, default: "utf-8"
|
87
87
|
cattr_accessor :default_headers
|
88
88
|
|
89
|
+
def self.return_only_media_type_on_content_type=(*)
|
90
|
+
ActiveSupport::Deprecation.warn(
|
91
|
+
".return_only_media_type_on_content_type= is dreprecated with no replacement and will be removed in 6.2."
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.return_only_media_type_on_content_type
|
96
|
+
ActiveSupport::Deprecation.warn(
|
97
|
+
".return_only_media_type_on_content_type is dreprecated with no replacement and will be removed in 6.2."
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
89
101
|
include Rack::Response::Helpers
|
90
102
|
# Aliasing these off because AD::Http::Cache::Response defines them.
|
91
103
|
alias :_cache_control :cache_control
|
@@ -105,7 +117,7 @@ module ActionDispatch # :nodoc:
|
|
105
117
|
|
106
118
|
def body
|
107
119
|
@str_body ||= begin
|
108
|
-
buf = ""
|
120
|
+
buf = +""
|
109
121
|
each { |chunk| buf << chunk }
|
110
122
|
buf
|
111
123
|
end
|
@@ -142,7 +154,6 @@ module ActionDispatch # :nodoc:
|
|
142
154
|
end
|
143
155
|
|
144
156
|
private
|
145
|
-
|
146
157
|
def each_chunk(&block)
|
147
158
|
@buf.each(&block)
|
148
159
|
end
|
@@ -224,16 +235,6 @@ module ActionDispatch # :nodoc:
|
|
224
235
|
@status = Rack::Utils.status_code(status)
|
225
236
|
end
|
226
237
|
|
227
|
-
# Sets the HTTP content type.
|
228
|
-
def content_type=(content_type)
|
229
|
-
return unless content_type
|
230
|
-
new_header_info = parse_content_type(content_type.to_s)
|
231
|
-
prev_header_info = parsed_content_type_header
|
232
|
-
charset = new_header_info.charset || prev_header_info.charset
|
233
|
-
charset ||= self.class.default_charset unless prev_header_info.mime_type
|
234
|
-
set_content_type new_header_info.mime_type, charset
|
235
|
-
end
|
236
|
-
|
237
238
|
# Sets the HTTP response's content MIME type. For example, in the controller
|
238
239
|
# you could write this:
|
239
240
|
#
|
@@ -242,8 +243,22 @@ module ActionDispatch # :nodoc:
|
|
242
243
|
# If a character set has been defined for this response (see charset=) then
|
243
244
|
# the character set information will also be included in the content type
|
244
245
|
# information.
|
246
|
+
def content_type=(content_type)
|
247
|
+
return unless content_type
|
248
|
+
new_header_info = parse_content_type(content_type.to_s)
|
249
|
+
prev_header_info = parsed_content_type_header
|
250
|
+
charset = new_header_info.charset || prev_header_info.charset
|
251
|
+
charset ||= self.class.default_charset unless prev_header_info.mime_type
|
252
|
+
set_content_type new_header_info.mime_type, charset
|
253
|
+
end
|
245
254
|
|
255
|
+
# Content type of response.
|
246
256
|
def content_type
|
257
|
+
super.presence
|
258
|
+
end
|
259
|
+
|
260
|
+
# Media type of response.
|
261
|
+
def media_type
|
247
262
|
parsed_content_type_header.mime_type
|
248
263
|
end
|
249
264
|
|
@@ -404,15 +419,18 @@ module ActionDispatch # :nodoc:
|
|
404
419
|
end
|
405
420
|
|
406
421
|
private
|
407
|
-
|
408
422
|
ContentTypeHeader = Struct.new :mime_type, :charset
|
409
423
|
NullContentTypeHeader = ContentTypeHeader.new nil, nil
|
410
424
|
|
425
|
+
CONTENT_TYPE_PARSER = /
|
426
|
+
\A
|
427
|
+
(?<mime_type>[^;\s]+\s*(?:;\s*(?:(?!charset)[^;\s])+)*)?
|
428
|
+
(?:;\s*charset=(?<quote>"?)(?<charset>[^;\s]+)\k<quote>)?
|
429
|
+
/x # :nodoc:
|
430
|
+
|
411
431
|
def parse_content_type(content_type)
|
412
|
-
if content_type
|
413
|
-
|
414
|
-
type = nil if type && type.empty?
|
415
|
-
ContentTypeHeader.new(type, charset)
|
432
|
+
if content_type && match = CONTENT_TYPE_PARSER.match(content_type)
|
433
|
+
ContentTypeHeader.new(match[:mime_type], match[:charset])
|
416
434
|
else
|
417
435
|
NullContentTypeHeader
|
418
436
|
end
|
@@ -425,8 +443,8 @@ module ActionDispatch # :nodoc:
|
|
425
443
|
end
|
426
444
|
|
427
445
|
def set_content_type(content_type, charset)
|
428
|
-
type =
|
429
|
-
type
|
446
|
+
type = content_type || ""
|
447
|
+
type = "#{type}; charset=#{charset.to_s.downcase}" if charset
|
430
448
|
set_header CONTENT_TYPE, type
|
431
449
|
end
|
432
450
|
|
@@ -459,7 +477,7 @@ module ActionDispatch # :nodoc:
|
|
459
477
|
end
|
460
478
|
|
461
479
|
def assign_default_content_type_and_charset!
|
462
|
-
return if
|
480
|
+
return if media_type
|
463
481
|
|
464
482
|
ct = parsed_content_type_header
|
465
483
|
set_content_type(ct.mime_type || Mime[:html].to_s,
|
@@ -486,7 +504,7 @@ module ActionDispatch # :nodoc:
|
|
486
504
|
end
|
487
505
|
|
488
506
|
def respond_to?(method, include_private = false)
|
489
|
-
if method.
|
507
|
+
if method.to_sym == :to_path
|
490
508
|
@response.stream.respond_to?(method)
|
491
509
|
else
|
492
510
|
super
|
@@ -517,4 +535,6 @@ module ActionDispatch # :nodoc:
|
|
517
535
|
end
|
518
536
|
end
|
519
537
|
end
|
538
|
+
|
539
|
+
ActiveSupport.run_load_hooks(:action_dispatch_response, Response)
|
520
540
|
end
|