actionpack 6.0.5.1 → 6.1.7
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 +382 -253
- data/MIT-LICENSE +1 -2
- data/lib/abstract_controller/base.rb +35 -2
- data/lib/abstract_controller/callbacks.rb +2 -2
- data/lib/abstract_controller/collector.rb +4 -2
- data/lib/abstract_controller/helpers.rb +105 -90
- data/lib/abstract_controller/railties/routes_helpers.rb +17 -1
- data/lib/abstract_controller/rendering.rb +9 -9
- data/lib/abstract_controller/translation.rb +8 -2
- data/lib/abstract_controller.rb +1 -0
- data/lib/action_controller/api.rb +2 -2
- data/lib/action_controller/base.rb +4 -2
- data/lib/action_controller/caching.rb +0 -1
- data/lib/action_controller/log_subscriber.rb +3 -3
- data/lib/action_controller/metal/conditional_get.rb +11 -3
- data/lib/action_controller/metal/content_security_policy.rb +1 -1
- data/lib/action_controller/metal/cookies.rb +3 -1
- data/lib/action_controller/metal/data_streaming.rb +1 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +3 -5
- data/lib/action_controller/metal/exceptions.rb +33 -0
- data/lib/action_controller/metal/head.rb +7 -4
- data/lib/action_controller/metal/helpers.rb +11 -1
- data/lib/action_controller/metal/http_authentication.rb +5 -2
- data/lib/action_controller/metal/implicit_render.rb +1 -1
- data/lib/action_controller/metal/instrumentation.rb +11 -9
- data/lib/action_controller/metal/live.rb +10 -1
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +6 -2
- data/lib/action_controller/metal/parameter_encoding.rb +35 -4
- data/lib/action_controller/metal/params_wrapper.rb +14 -8
- data/lib/action_controller/metal/permissions_policy.rb +46 -0
- data/lib/action_controller/metal/redirecting.rb +1 -1
- data/lib/action_controller/metal/rendering.rb +6 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +1 -1
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/strong_parameters.rb +104 -16
- data/lib/action_controller/metal.rb +2 -2
- data/lib/action_controller/renderer.rb +23 -13
- data/lib/action_controller/test_case.rb +65 -56
- data/lib/action_controller.rb +2 -3
- data/lib/action_dispatch/http/cache.rb +17 -16
- data/lib/action_dispatch/http/content_security_policy.rb +6 -1
- data/lib/action_dispatch/http/filter_parameters.rb +1 -1
- data/lib/action_dispatch/http/filter_redirect.rb +1 -1
- data/lib/action_dispatch/http/headers.rb +3 -2
- data/lib/action_dispatch/http/mime_negotiation.rb +14 -8
- data/lib/action_dispatch/http/mime_type.rb +29 -16
- data/lib/action_dispatch/http/parameters.rb +1 -19
- data/lib/action_dispatch/http/permissions_policy.rb +173 -0
- data/lib/action_dispatch/http/request.rb +24 -8
- data/lib/action_dispatch/http/response.rb +17 -16
- data/lib/action_dispatch/http/url.rb +3 -2
- data/lib/action_dispatch/journey/formatter.rb +55 -30
- data/lib/action_dispatch/journey/gtg/builder.rb +22 -36
- data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -4
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
- data/lib/action_dispatch/journey/nodes/node.rb +4 -3
- 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 +13 -18
- data/lib/action_dispatch/journey/route.rb +7 -18
- data/lib/action_dispatch/journey/router/utils.rb +6 -4
- data/lib/action_dispatch/journey/router.rb +26 -30
- data/lib/action_dispatch/journey/visitors.rb +1 -1
- data/lib/action_dispatch/journey.rb +0 -2
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +1 -1
- data/lib/action_dispatch/middleware/cookies.rb +67 -32
- data/lib/action_dispatch/middleware/debug_exceptions.rb +8 -15
- data/lib/action_dispatch/middleware/debug_view.rb +1 -1
- data/lib/action_dispatch/middleware/exception_wrapper.rb +28 -16
- data/lib/action_dispatch/middleware/host_authorization.rb +63 -14
- data/lib/action_dispatch/middleware/remote_ip.rb +5 -4
- data/lib/action_dispatch/middleware/request_id.rb +4 -5
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -2
- data/lib/action_dispatch/middleware/session/cookie_store.rb +2 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +12 -0
- data/lib/action_dispatch/middleware/ssl.rb +12 -7
- data/lib/action_dispatch/middleware/stack.rb +19 -1
- data/lib/action_dispatch/middleware/static.rb +154 -93
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +2 -5
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +100 -8
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +21 -1
- data/lib/action_dispatch/railtie.rb +3 -2
- data/lib/action_dispatch/request/session.rb +2 -8
- data/lib/action_dispatch/request/utils.rb +26 -2
- data/lib/action_dispatch/routing/inspector.rb +8 -7
- data/lib/action_dispatch/routing/mapper.rb +102 -71
- data/lib/action_dispatch/routing/polymorphic_routes.rb +12 -11
- data/lib/action_dispatch/routing/redirection.rb +4 -4
- data/lib/action_dispatch/routing/route_set.rb +49 -41
- data/lib/action_dispatch/system_test_case.rb +35 -24
- data/lib/action_dispatch/system_testing/browser.rb +33 -27
- data/lib/action_dispatch/system_testing/driver.rb +6 -7
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +47 -6
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +4 -7
- data/lib/action_dispatch/testing/assertions/response.rb +2 -4
- data/lib/action_dispatch/testing/assertions/routing.rb +5 -5
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/integration.rb +40 -29
- data/lib/action_dispatch/testing/test_process.rb +32 -4
- data/lib/action_dispatch/testing/test_request.rb +3 -3
- data/lib/action_dispatch.rb +3 -2
- data/lib/action_pack/gem_version.rb +3 -3
- data/lib/action_pack.rb +1 -1
- metadata +17 -18
- data/lib/action_controller/metal/force_ssl.rb +0 -58
- data/lib/action_dispatch/http/parameter_filter.rb +0 -12
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -119
@@ -68,13 +68,7 @@ module ActionDispatch
|
|
68
68
|
|
69
69
|
def formats
|
70
70
|
fetch_header("action_dispatch.request.formats") do |k|
|
71
|
-
|
72
|
-
parameters[:format]
|
73
|
-
rescue *RESCUABLE_MIME_FORMAT_ERRORS
|
74
|
-
false
|
75
|
-
end
|
76
|
-
|
77
|
-
v = if params_readable
|
71
|
+
v = if params_readable?
|
78
72
|
Array(Mime[parameters[:format]])
|
79
73
|
elsif use_accept_header && valid_accept_header
|
80
74
|
accepts
|
@@ -159,12 +153,24 @@ module ActionDispatch
|
|
159
153
|
order.include?(Mime::ALL) ? format : nil
|
160
154
|
end
|
161
155
|
|
156
|
+
def should_apply_vary_header?
|
157
|
+
!params_readable? && use_accept_header && valid_accept_header
|
158
|
+
end
|
159
|
+
|
162
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
163
|
BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
|
164
164
|
|
165
|
+
def params_readable? # :doc:
|
166
|
+
parameters[:format]
|
167
|
+
rescue *RESCUABLE_MIME_FORMAT_ERRORS
|
168
|
+
false
|
169
|
+
end
|
170
|
+
|
165
171
|
def valid_accept_header # :doc:
|
166
172
|
(xhr? && (accept.present? || content_mime_type)) ||
|
167
|
-
(accept.present? && accept
|
173
|
+
(accept.present? && !accept.match?(BROWSER_LIKE_ACCEPTS))
|
168
174
|
end
|
169
175
|
|
170
176
|
def use_accept_header # :doc:
|
@@ -1,15 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "singleton"
|
4
|
-
require "active_support/core_ext/
|
4
|
+
require "active_support/core_ext/symbol/starts_ends_with"
|
5
5
|
|
6
6
|
module Mime
|
7
7
|
class Mimes
|
8
|
+
attr_reader :symbols
|
9
|
+
|
8
10
|
include Enumerable
|
9
11
|
|
10
12
|
def initialize
|
11
13
|
@mimes = []
|
12
|
-
@symbols =
|
14
|
+
@symbols = []
|
13
15
|
end
|
14
16
|
|
15
17
|
def each
|
@@ -18,15 +20,16 @@ module Mime
|
|
18
20
|
|
19
21
|
def <<(type)
|
20
22
|
@mimes << type
|
21
|
-
@symbols
|
23
|
+
@symbols << type.to_sym
|
22
24
|
end
|
23
25
|
|
24
26
|
def delete_if
|
25
|
-
@mimes.delete_if
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
@mimes.delete_if do |x|
|
28
|
+
if yield x
|
29
|
+
@symbols.delete(x.to_sym)
|
30
|
+
true
|
31
|
+
end
|
32
|
+
end
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
@@ -114,7 +117,7 @@ module Mime
|
|
114
117
|
type = list[idx]
|
115
118
|
break if type.q < app_xml.q
|
116
119
|
|
117
|
-
if type.name.
|
120
|
+
if type.name.end_with? "+xml"
|
118
121
|
list[app_xml_idx], list[idx] = list[idx], app_xml
|
119
122
|
app_xml_idx = idx
|
120
123
|
end
|
@@ -202,7 +205,7 @@ module Mime
|
|
202
205
|
# For an input of <tt>'application'</tt>, returns <tt>[Mime[:html], Mime[:js],
|
203
206
|
# Mime[:xml], Mime[:yaml], Mime[:atom], Mime[:json], Mime[:rss], Mime[:url_encoded_form]</tt>.
|
204
207
|
def parse_data_with_trailing_star(type)
|
205
|
-
Mime::SET.select { |m| m
|
208
|
+
Mime::SET.select { |m| m.match?(type) }
|
206
209
|
end
|
207
210
|
|
208
211
|
# This method is opposite of register method.
|
@@ -283,8 +286,14 @@ module Mime
|
|
283
286
|
@synonyms.any? { |synonym| synonym.to_s =~ regexp } || @string =~ regexp
|
284
287
|
end
|
285
288
|
|
289
|
+
def match?(mime_type)
|
290
|
+
return false unless mime_type
|
291
|
+
regexp = Regexp.new(Regexp.quote(mime_type.to_s))
|
292
|
+
@synonyms.any? { |synonym| synonym.to_s.match?(regexp) } || @string.match?(regexp)
|
293
|
+
end
|
294
|
+
|
286
295
|
def html?
|
287
|
-
symbol == :html || @string
|
296
|
+
(symbol == :html) || /html/.match?(@string)
|
288
297
|
end
|
289
298
|
|
290
299
|
def all?; false; end
|
@@ -297,7 +306,7 @@ module Mime
|
|
297
306
|
def to_a; end
|
298
307
|
|
299
308
|
def method_missing(method, *args)
|
300
|
-
if method.
|
309
|
+
if method.end_with?("?")
|
301
310
|
method[0..-2].downcase.to_sym == to_sym
|
302
311
|
else
|
303
312
|
super
|
@@ -305,7 +314,7 @@ module Mime
|
|
305
314
|
end
|
306
315
|
|
307
316
|
def respond_to_missing?(method, include_private = false)
|
308
|
-
|
317
|
+
method.end_with?("?") || super
|
309
318
|
end
|
310
319
|
end
|
311
320
|
|
@@ -321,7 +330,7 @@ module Mime
|
|
321
330
|
end
|
322
331
|
|
323
332
|
# ALL isn't a real MIME type, so we don't register it for lookup with the
|
324
|
-
# other concrete types. It's a wildcard match that we use for
|
333
|
+
# other concrete types. It's a wildcard match that we use for +respond_to+
|
325
334
|
# negotiation internals.
|
326
335
|
ALL = AllType.instance
|
327
336
|
|
@@ -332,15 +341,19 @@ module Mime
|
|
332
341
|
true
|
333
342
|
end
|
334
343
|
|
344
|
+
def to_s
|
345
|
+
""
|
346
|
+
end
|
347
|
+
|
335
348
|
def ref; end
|
336
349
|
|
337
350
|
private
|
338
351
|
def respond_to_missing?(method, _)
|
339
|
-
method.
|
352
|
+
method.end_with?("?")
|
340
353
|
end
|
341
354
|
|
342
355
|
def method_missing(method, *args)
|
343
|
-
false if method.
|
356
|
+
false if method.end_with?("?")
|
344
357
|
end
|
345
358
|
end
|
346
359
|
end
|
@@ -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,23 +84,6 @@ module ActionDispatch
|
|
85
84
|
end
|
86
85
|
|
87
86
|
private
|
88
|
-
def set_binary_encoding(params, controller, action)
|
89
|
-
return params unless controller && controller.valid_encoding?
|
90
|
-
|
91
|
-
if binary_params_for?(controller, action)
|
92
|
-
ActionDispatch::Request::Utils.each_param_value(params.except(:controller, :action)) do |param|
|
93
|
-
param.force_encoding ::Encoding::ASCII_8BIT
|
94
|
-
end
|
95
|
-
end
|
96
|
-
params
|
97
|
-
end
|
98
|
-
|
99
|
-
def binary_params_for?(controller, action)
|
100
|
-
controller_class_for(controller).binary_params_for?(action)
|
101
|
-
rescue MissingController
|
102
|
-
false
|
103
|
-
end
|
104
|
-
|
105
87
|
def parse_formatted_parameters(parsers)
|
106
88
|
return yield if content_length.zero? || content_mime_type.nil?
|
107
89
|
|
@@ -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,7 +88,7 @@ module ActionDispatch
|
|
84
88
|
def controller_class_for(name)
|
85
89
|
if name
|
86
90
|
controller_param = name.underscore
|
87
|
-
const_name =
|
91
|
+
const_name = controller_param.camelize << "Controller"
|
88
92
|
begin
|
89
93
|
ActiveSupport::Dependencies.constantize(const_name)
|
90
94
|
rescue NameError => error
|
@@ -274,7 +278,7 @@ module ActionDispatch
|
|
274
278
|
# (case-insensitive), which may need to be manually added depending on the
|
275
279
|
# choice of JavaScript libraries and frameworks.
|
276
280
|
def xml_http_request?
|
277
|
-
get_header("HTTP_X_REQUESTED_WITH")
|
281
|
+
/XMLHttpRequest/i.match?(get_header("HTTP_X_REQUESTED_WITH"))
|
278
282
|
end
|
279
283
|
alias :xhr? :xml_http_request?
|
280
284
|
|
@@ -290,6 +294,7 @@ module ActionDispatch
|
|
290
294
|
end
|
291
295
|
|
292
296
|
def remote_ip=(remote_ip)
|
297
|
+
@remote_ip = nil
|
293
298
|
set_header "action_dispatch.remote_ip", remote_ip
|
294
299
|
end
|
295
300
|
|
@@ -331,7 +336,7 @@ module ActionDispatch
|
|
331
336
|
# variable is already set, wrap it in a StringIO.
|
332
337
|
def body
|
333
338
|
if raw_post = get_header("RAW_POST_DATA")
|
334
|
-
raw_post = raw_post.
|
339
|
+
raw_post = (+raw_post).force_encoding(Encoding::BINARY)
|
335
340
|
StringIO.new(raw_post)
|
336
341
|
else
|
337
342
|
body_stream
|
@@ -376,6 +381,9 @@ module ActionDispatch
|
|
376
381
|
def GET
|
377
382
|
fetch_header("action_dispatch.request.query_parameters") do |k|
|
378
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)
|
379
387
|
# Check for non UTF-8 parameter values, which would cause errors later
|
380
388
|
Request::Utils.check_param_encoding(rack_query_params)
|
381
389
|
set_header k, Request::Utils.normalize_encode_params(rack_query_params)
|
@@ -391,6 +399,8 @@ module ActionDispatch
|
|
391
399
|
pr = parse_formatted_parameters(params_parsers) do |params|
|
392
400
|
super || {}
|
393
401
|
end
|
402
|
+
pr = Request::Utils.set_binary_encoding(self, pr, path_parameters[:controller], path_parameters[:action])
|
403
|
+
Request::Utils.check_param_encoding(pr)
|
394
404
|
self.request_parameters = Request::Utils.normalize_encode_params(pr)
|
395
405
|
end
|
396
406
|
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
@@ -409,7 +419,7 @@ module ActionDispatch
|
|
409
419
|
|
410
420
|
# True if the request came from localhost, 127.0.0.1, or ::1.
|
411
421
|
def local?
|
412
|
-
LOCALHOST
|
422
|
+
LOCALHOST.match?(remote_addr) && LOCALHOST.match?(remote_ip)
|
413
423
|
end
|
414
424
|
|
415
425
|
def request_parameters=(params)
|
@@ -428,6 +438,10 @@ module ActionDispatch
|
|
428
438
|
super || scheme == "wss"
|
429
439
|
end
|
430
440
|
|
441
|
+
def inspect # :nodoc:
|
442
|
+
"#<#{self.class.name} #{method} #{original_url.dump} for #{remote_ip}>"
|
443
|
+
end
|
444
|
+
|
431
445
|
private
|
432
446
|
def check_method(name)
|
433
447
|
HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS[0...-1].join(', ')}, and #{HTTP_METHODS[-1]}")
|
@@ -435,3 +449,5 @@ module ActionDispatch
|
|
435
449
|
end
|
436
450
|
end
|
437
451
|
end
|
452
|
+
|
453
|
+
ActiveSupport.run_load_hooks :action_dispatch_request, ActionDispatch::Request
|
@@ -81,11 +81,22 @@ module ActionDispatch # :nodoc:
|
|
81
81
|
CONTENT_TYPE = "Content-Type"
|
82
82
|
SET_COOKIE = "Set-Cookie"
|
83
83
|
LOCATION = "Location"
|
84
|
-
NO_CONTENT_CODES = [100, 101, 102, 204, 205, 304]
|
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 7.0."
|
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 7.0."
|
98
|
+
)
|
99
|
+
end
|
89
100
|
|
90
101
|
include Rack::Response::Helpers
|
91
102
|
# Aliasing these off because AD::Http::Cache::Response defines them.
|
@@ -243,17 +254,7 @@ module ActionDispatch # :nodoc:
|
|
243
254
|
|
244
255
|
# Content type of response.
|
245
256
|
def content_type
|
246
|
-
|
247
|
-
ActiveSupport::Deprecation.warn(
|
248
|
-
"Rails 6.1 will return Content-Type header without modification." \
|
249
|
-
" If you want just the MIME type, please use `#media_type` instead."
|
250
|
-
)
|
251
|
-
|
252
|
-
content_type = super
|
253
|
-
content_type ? content_type.split(/;\s*charset=/)[0].presence : content_type
|
254
|
-
else
|
255
|
-
super.presence
|
256
|
-
end
|
257
|
+
super.presence
|
257
258
|
end
|
258
259
|
|
259
260
|
# Media type of response.
|
@@ -442,8 +443,8 @@ module ActionDispatch # :nodoc:
|
|
442
443
|
end
|
443
444
|
|
444
445
|
def set_content_type(content_type, charset)
|
445
|
-
type =
|
446
|
-
type
|
446
|
+
type = content_type || ""
|
447
|
+
type = "#{type}; charset=#{charset.to_s.downcase}" if charset
|
447
448
|
set_header CONTENT_TYPE, type
|
448
449
|
end
|
449
450
|
|
@@ -503,7 +504,7 @@ module ActionDispatch # :nodoc:
|
|
503
504
|
end
|
504
505
|
|
505
506
|
def respond_to?(method, include_private = false)
|
506
|
-
if method.
|
507
|
+
if method.to_sym == :to_path
|
507
508
|
@response.stream.respond_to?(method)
|
508
509
|
else
|
509
510
|
super
|
@@ -9,6 +9,7 @@ module ActionDispatch
|
|
9
9
|
HOST_REGEXP = /(^[^:]+:\/\/)?(\[[^\]]+\]|[^:]+)(?::(\d+$))?/
|
10
10
|
PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
|
11
11
|
|
12
|
+
mattr_accessor :secure_protocol, default: false
|
12
13
|
mattr_accessor :tld_length, default: 1
|
13
14
|
|
14
15
|
class << self
|
@@ -133,13 +134,13 @@ module ActionDispatch
|
|
133
134
|
end
|
134
135
|
|
135
136
|
def named_host?(host)
|
136
|
-
IP_HOST_REGEXP
|
137
|
+
!IP_HOST_REGEXP.match?(host)
|
137
138
|
end
|
138
139
|
|
139
140
|
def normalize_protocol(protocol)
|
140
141
|
case protocol
|
141
142
|
when nil
|
142
|
-
"http://"
|
143
|
+
secure_protocol ? "https://" : "http://"
|
143
144
|
when false, "//"
|
144
145
|
"//"
|
145
146
|
when PROTOCOL_REGEXP
|