actionpack 6.0.6.1 → 6.1.7.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +416 -255
- 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 +21 -2
- 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 +18 -17
- 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 +89 -46
- 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 +18 -19
- 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
|