actionpack 5.2.4.1 → 6.0.1
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 +191 -335
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -2
- data/lib/abstract_controller/base.rb +4 -2
- data/lib/abstract_controller/caching/fragments.rb +6 -22
- data/lib/abstract_controller/callbacks.rb +12 -0
- data/lib/abstract_controller/collector.rb +1 -1
- data/lib/abstract_controller/helpers.rb +2 -2
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
- data/lib/abstract_controller/translation.rb +1 -0
- data/lib/action_controller.rb +5 -1
- data/lib/action_controller/api.rb +2 -1
- data/lib/action_controller/base.rb +2 -7
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +8 -5
- data/lib/action_controller/metal.rb +1 -1
- data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
- data/lib/action_controller/metal/conditional_get.rb +9 -3
- data/lib/action_controller/metal/data_streaming.rb +5 -6
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
- data/lib/action_controller/metal/exceptions.rb +23 -2
- data/lib/action_controller/metal/flash.rb +5 -5
- data/lib/action_controller/metal/force_ssl.rb +15 -56
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +3 -4
- data/lib/action_controller/metal/http_authentication.rb +20 -21
- data/lib/action_controller/metal/implicit_render.rb +4 -14
- data/lib/action_controller/metal/instrumentation.rb +3 -5
- data/lib/action_controller/metal/live.rb +29 -27
- data/lib/action_controller/metal/mime_responds.rb +13 -2
- data/lib/action_controller/metal/params_wrapper.rb +17 -13
- data/lib/action_controller/metal/redirecting.rb +5 -5
- data/lib/action_controller/metal/renderers.rb +4 -4
- data/lib/action_controller/metal/rendering.rb +2 -2
- data/lib/action_controller/metal/request_forgery_protection.rb +23 -12
- data/lib/action_controller/metal/strong_parameters.rb +63 -44
- 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 +16 -3
- data/lib/action_controller/template_assertions.rb +1 -1
- data/lib/action_controller/test_case.rb +2 -5
- data/lib/action_dispatch.rb +8 -7
- data/lib/action_dispatch/http/cache.rb +14 -10
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +28 -16
- data/lib/action_dispatch/http/filter_parameters.rb +8 -6
- data/lib/action_dispatch/http/filter_redirect.rb +1 -1
- data/lib/action_dispatch/http/headers.rb +1 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +7 -5
- data/lib/action_dispatch/http/mime_type.rb +14 -6
- data/lib/action_dispatch/http/parameter_filter.rb +5 -79
- data/lib/action_dispatch/http/parameters.rb +13 -3
- data/lib/action_dispatch/http/request.rb +10 -13
- data/lib/action_dispatch/http/response.rb +40 -20
- data/lib/action_dispatch/http/upload.rb +9 -1
- data/lib/action_dispatch/http/url.rb +81 -81
- data/lib/action_dispatch/journey/formatter.rb +2 -2
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -2
- data/lib/action_dispatch/journey/nodes/node.rb +9 -8
- data/lib/action_dispatch/journey/path/pattern.rb +6 -2
- data/lib/action_dispatch/journey/route.rb +5 -4
- data/lib/action_dispatch/journey/router.rb +0 -3
- data/lib/action_dispatch/journey/router/utils.rb +10 -10
- data/lib/action_dispatch/journey/routes.rb +0 -1
- data/lib/action_dispatch/journey/scanner.rb +11 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -1
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +39 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +52 -74
- data/lib/action_dispatch/middleware/debug_exceptions.rb +39 -59
- data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
- data/lib/action_dispatch/middleware/debug_view.rb +68 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +49 -15
- data/lib/action_dispatch/middleware/flash.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +103 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +6 -2
- data/lib/action_dispatch/middleware/remote_ip.rb +9 -11
- data/lib/action_dispatch/middleware/request_id.rb +2 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +0 -14
- data/lib/action_dispatch/middleware/session/cache_store.rb +6 -11
- data/lib/action_dispatch/middleware/session/cookie_store.rb +8 -23
- data/lib/action_dispatch/middleware/show_exceptions.rb +1 -1
- data/lib/action_dispatch/middleware/ssl.rb +8 -8
- data/lib/action_dispatch/middleware/stack.rb +33 -1
- data/lib/action_dispatch/middleware/static.rb +5 -6
- 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/_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 +26 -4
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +7 -4
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -0
- 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/routes/_table.html.erb +3 -0
- data/lib/action_dispatch/railtie.rb +7 -2
- data/lib/action_dispatch/request/session.rb +8 -6
- data/lib/action_dispatch/routing.rb +21 -20
- data/lib/action_dispatch/routing/inspector.rb +99 -50
- data/lib/action_dispatch/routing/mapper.rb +61 -39
- data/lib/action_dispatch/routing/polymorphic_routes.rb +3 -4
- data/lib/action_dispatch/routing/route_set.rb +24 -27
- data/lib/action_dispatch/routing/url_for.rb +1 -0
- data/lib/action_dispatch/system_test_case.rb +43 -5
- data/lib/action_dispatch/system_testing/browser.rb +38 -7
- data/lib/action_dispatch/system_testing/driver.rb +10 -1
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +6 -5
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +7 -6
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +2 -3
- data/lib/action_dispatch/testing/assertions/routing.rb +15 -3
- data/lib/action_dispatch/testing/integration.rb +12 -5
- data/lib/action_dispatch/testing/request_encoder.rb +2 -2
- data/lib/action_dispatch/testing/test_process.rb +2 -2
- 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 +28 -21
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -26,7 +26,7 @@ module ActionController
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
# ActionController::TestCase will be deprecated and moved to a gem in
|
29
|
+
# ActionController::TestCase will be deprecated and moved to a gem in the future.
|
30
30
|
# Please use ActionDispatch::IntegrationTest going forward.
|
31
31
|
class TestRequest < ActionDispatch::TestRequest #:nodoc:
|
32
32
|
DEFAULT_ENV = ActionDispatch::TestRequest::DEFAULT_ENV.dup
|
@@ -276,9 +276,6 @@ module ActionController
|
|
276
276
|
# after calling +post+. If the various assert methods are not sufficient, then you
|
277
277
|
# may use this object to inspect the HTTP response in detail.
|
278
278
|
#
|
279
|
-
# (Earlier versions of \Rails required each functional test to subclass
|
280
|
-
# Test::Unit::TestCase and define @controller, @request, @response in +setup+.)
|
281
|
-
#
|
282
279
|
# == Controller is automatically inferred
|
283
280
|
#
|
284
281
|
# ActionController::TestCase will automatically infer the controller under test
|
@@ -460,7 +457,7 @@ module ActionController
|
|
460
457
|
def process(action, method: "GET", params: nil, session: nil, body: nil, flash: {}, format: nil, xhr: false, as: nil)
|
461
458
|
check_required_ivars
|
462
459
|
|
463
|
-
action = action.to_s
|
460
|
+
action = +action.to_s
|
464
461
|
http_method = method.to_s.upcase
|
465
462
|
|
466
463
|
@html_document = nil
|
data/lib/action_dispatch.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright (c) 2004-
|
4
|
+
# Copyright (c) 2004-2019 David Heinemeier Hansson
|
5
5
|
#
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining
|
7
7
|
# a copy of this software and associated documentation files (the
|
@@ -49,11 +49,14 @@ module ActionDispatch
|
|
49
49
|
end
|
50
50
|
|
51
51
|
autoload_under "middleware" do
|
52
|
+
autoload :HostAuthorization
|
52
53
|
autoload :RequestId
|
53
54
|
autoload :Callbacks
|
54
55
|
autoload :Cookies
|
56
|
+
autoload :ActionableExceptions
|
55
57
|
autoload :DebugExceptions
|
56
58
|
autoload :DebugLocks
|
59
|
+
autoload :DebugView
|
57
60
|
autoload :ExceptionWrapper
|
58
61
|
autoload :Executor
|
59
62
|
autoload :Flash
|
@@ -77,17 +80,15 @@ module ActionDispatch
|
|
77
80
|
autoload :MimeNegotiation
|
78
81
|
autoload :Parameters
|
79
82
|
autoload :ParameterFilter
|
80
|
-
autoload :Upload
|
81
83
|
autoload :UploadedFile, "action_dispatch/http/upload"
|
82
84
|
autoload :URL
|
83
85
|
end
|
84
86
|
|
85
87
|
module Session
|
86
|
-
autoload :AbstractStore,
|
87
|
-
autoload :
|
88
|
-
autoload :
|
89
|
-
autoload :
|
90
|
-
autoload :CacheStore, "action_dispatch/middleware/session/cache_store"
|
88
|
+
autoload :AbstractStore, "action_dispatch/middleware/session/abstract_store"
|
89
|
+
autoload :CookieStore, "action_dispatch/middleware/session/cookie_store"
|
90
|
+
autoload :MemCacheStore, "action_dispatch/middleware/session/mem_cache_store"
|
91
|
+
autoload :CacheStore, "action_dispatch/middleware/session/cache_store"
|
91
92
|
end
|
92
93
|
|
93
94
|
mattr_accessor :test_app
|
@@ -4,8 +4,8 @@ module ActionDispatch
|
|
4
4
|
module Http
|
5
5
|
module Cache
|
6
6
|
module Request
|
7
|
-
HTTP_IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE"
|
8
|
-
HTTP_IF_NONE_MATCH = "HTTP_IF_NONE_MATCH"
|
7
|
+
HTTP_IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE"
|
8
|
+
HTTP_IF_NONE_MATCH = "HTTP_IF_NONE_MATCH"
|
9
9
|
|
10
10
|
def if_modified_since
|
11
11
|
if since = get_header(HTTP_IF_MODIFIED_SINCE)
|
@@ -124,8 +124,8 @@ module ActionDispatch
|
|
124
124
|
|
125
125
|
private
|
126
126
|
|
127
|
-
DATE = "Date"
|
128
|
-
LAST_MODIFIED = "Last-Modified"
|
127
|
+
DATE = "Date"
|
128
|
+
LAST_MODIFIED = "Last-Modified"
|
129
129
|
SPECIAL_KEYS = Set.new(%w[extras no-cache max-age public private must-revalidate])
|
130
130
|
|
131
131
|
def generate_weak_etag(validators)
|
@@ -166,11 +166,11 @@ module ActionDispatch
|
|
166
166
|
@cache_control = cache_control_headers
|
167
167
|
end
|
168
168
|
|
169
|
-
DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
|
170
|
-
NO_CACHE = "no-cache"
|
171
|
-
PUBLIC = "public"
|
172
|
-
PRIVATE = "private"
|
173
|
-
MUST_REVALIDATE = "must-revalidate"
|
169
|
+
DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
|
170
|
+
NO_CACHE = "no-cache"
|
171
|
+
PUBLIC = "public"
|
172
|
+
PRIVATE = "private"
|
173
|
+
MUST_REVALIDATE = "must-revalidate"
|
174
174
|
|
175
175
|
def handle_conditional_get!
|
176
176
|
# Normally default cache control setting is handled by ETag
|
@@ -204,13 +204,17 @@ module ActionDispatch
|
|
204
204
|
|
205
205
|
self._cache_control = options.join(", ")
|
206
206
|
else
|
207
|
-
extras
|
207
|
+
extras = control[:extras]
|
208
208
|
max_age = control[:max_age]
|
209
|
+
stale_while_revalidate = control[:stale_while_revalidate]
|
210
|
+
stale_if_error = control[:stale_if_error]
|
209
211
|
|
210
212
|
options = []
|
211
213
|
options << "max-age=#{max_age.to_i}" if max_age
|
212
214
|
options << (control[:public] ? PUBLIC : PRIVATE)
|
213
215
|
options << MUST_REVALIDATE if control[:must_revalidate]
|
216
|
+
options << "stale-while-revalidate=#{stale_while_revalidate.to_i}" if stale_while_revalidate
|
217
|
+
options << "stale-if-error=#{stale_if_error.to_i}" if stale_if_error
|
214
218
|
options.concat(extras) if extras
|
215
219
|
|
216
220
|
self._cache_control = options.join(", ")
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
module Http
|
5
|
+
class ContentDisposition # :nodoc:
|
6
|
+
def self.format(disposition:, filename:)
|
7
|
+
new(disposition: disposition, filename: filename).to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :disposition, :filename
|
11
|
+
|
12
|
+
def initialize(disposition:, filename:)
|
13
|
+
@disposition = disposition
|
14
|
+
@filename = filename
|
15
|
+
end
|
16
|
+
|
17
|
+
TRADITIONAL_ESCAPED_CHAR = /[^ A-Za-z0-9!#$+.^_`|~-]/
|
18
|
+
|
19
|
+
def ascii_filename
|
20
|
+
'filename="' + percent_escape(I18n.transliterate(filename), TRADITIONAL_ESCAPED_CHAR) + '"'
|
21
|
+
end
|
22
|
+
|
23
|
+
RFC_5987_ESCAPED_CHAR = /[^A-Za-z0-9!#$&+.^_`|~-]/
|
24
|
+
|
25
|
+
def utf8_filename
|
26
|
+
"filename*=UTF-8''" + percent_escape(filename, RFC_5987_ESCAPED_CHAR)
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
if filename
|
31
|
+
"#{disposition}; #{ascii_filename}; #{utf8_filename}"
|
32
|
+
else
|
33
|
+
"#{disposition}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def percent_escape(string, pattern)
|
39
|
+
string.gsub(pattern) do |char|
|
40
|
+
char.bytes.map { |byte| "%%%02X" % byte }.join
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -5,9 +5,9 @@ require "active_support/core_ext/object/deep_dup"
|
|
5
5
|
module ActionDispatch #:nodoc:
|
6
6
|
class ContentSecurityPolicy
|
7
7
|
class Middleware
|
8
|
-
CONTENT_TYPE = "Content-Type"
|
9
|
-
POLICY = "Content-Security-Policy"
|
10
|
-
POLICY_REPORT_ONLY = "Content-Security-Policy-Report-Only"
|
8
|
+
CONTENT_TYPE = "Content-Type"
|
9
|
+
POLICY = "Content-Security-Policy"
|
10
|
+
POLICY_REPORT_ONLY = "Content-Security-Policy-Report-Only"
|
11
11
|
|
12
12
|
def initialize(app)
|
13
13
|
@app = app
|
@@ -22,8 +22,9 @@ module ActionDispatch #:nodoc:
|
|
22
22
|
|
23
23
|
if policy = request.content_security_policy
|
24
24
|
nonce = request.content_security_policy_nonce
|
25
|
+
nonce_directives = request.content_security_policy_nonce_directives
|
25
26
|
context = request.controller_instance || request
|
26
|
-
headers[header_name(request)] = policy.build(context, nonce)
|
27
|
+
headers[header_name(request)] = policy.build(context, nonce, nonce_directives)
|
27
28
|
end
|
28
29
|
|
29
30
|
response
|
@@ -51,10 +52,11 @@ module ActionDispatch #:nodoc:
|
|
51
52
|
end
|
52
53
|
|
53
54
|
module Request
|
54
|
-
POLICY = "action_dispatch.content_security_policy"
|
55
|
-
POLICY_REPORT_ONLY = "action_dispatch.content_security_policy_report_only"
|
56
|
-
NONCE_GENERATOR = "action_dispatch.content_security_policy_nonce_generator"
|
57
|
-
NONCE = "action_dispatch.content_security_policy_nonce"
|
55
|
+
POLICY = "action_dispatch.content_security_policy"
|
56
|
+
POLICY_REPORT_ONLY = "action_dispatch.content_security_policy_report_only"
|
57
|
+
NONCE_GENERATOR = "action_dispatch.content_security_policy_nonce_generator"
|
58
|
+
NONCE = "action_dispatch.content_security_policy_nonce"
|
59
|
+
NONCE_DIRECTIVES = "action_dispatch.content_security_policy_nonce_directives"
|
58
60
|
|
59
61
|
def content_security_policy
|
60
62
|
get_header(POLICY)
|
@@ -80,6 +82,14 @@ module ActionDispatch #:nodoc:
|
|
80
82
|
set_header(NONCE_GENERATOR, generator)
|
81
83
|
end
|
82
84
|
|
85
|
+
def content_security_policy_nonce_directives
|
86
|
+
get_header(NONCE_DIRECTIVES)
|
87
|
+
end
|
88
|
+
|
89
|
+
def content_security_policy_nonce_directives=(generator)
|
90
|
+
set_header(NONCE_DIRECTIVES, generator)
|
91
|
+
end
|
92
|
+
|
83
93
|
def content_security_policy_nonce
|
84
94
|
if content_security_policy_nonce_generator
|
85
95
|
if nonce = get_header(NONCE)
|
@@ -127,14 +137,15 @@ module ActionDispatch #:nodoc:
|
|
127
137
|
manifest_src: "manifest-src",
|
128
138
|
media_src: "media-src",
|
129
139
|
object_src: "object-src",
|
140
|
+
prefetch_src: "prefetch-src",
|
130
141
|
script_src: "script-src",
|
131
142
|
style_src: "style-src",
|
132
143
|
worker_src: "worker-src"
|
133
144
|
}.freeze
|
134
145
|
|
135
|
-
|
146
|
+
DEFAULT_NONCE_DIRECTIVES = %w[script-src style-src].freeze
|
136
147
|
|
137
|
-
private_constant :MAPPINGS, :DIRECTIVES, :
|
148
|
+
private_constant :MAPPINGS, :DIRECTIVES, :DEFAULT_NONCE_DIRECTIVES
|
138
149
|
|
139
150
|
attr_reader :directives
|
140
151
|
|
@@ -203,8 +214,9 @@ module ActionDispatch #:nodoc:
|
|
203
214
|
end
|
204
215
|
end
|
205
216
|
|
206
|
-
def build(context = nil, nonce = nil)
|
207
|
-
|
217
|
+
def build(context = nil, nonce = nil, nonce_directives = nil)
|
218
|
+
nonce_directives = DEFAULT_NONCE_DIRECTIVES if nonce_directives.nil?
|
219
|
+
build_directives(context, nonce, nonce_directives).compact.join("; ")
|
208
220
|
end
|
209
221
|
|
210
222
|
private
|
@@ -227,10 +239,10 @@ module ActionDispatch #:nodoc:
|
|
227
239
|
end
|
228
240
|
end
|
229
241
|
|
230
|
-
def build_directives(context, nonce)
|
242
|
+
def build_directives(context, nonce, nonce_directives)
|
231
243
|
@directives.map do |directive, sources|
|
232
244
|
if sources.is_a?(Array)
|
233
|
-
if nonce && nonce_directive?(directive)
|
245
|
+
if nonce && nonce_directive?(directive, nonce_directives)
|
234
246
|
"#{directive} #{build_directive(sources, context).join(' ')} 'nonce-#{nonce}'"
|
235
247
|
else
|
236
248
|
"#{directive} #{build_directive(sources, context).join(' ')}"
|
@@ -265,8 +277,8 @@ module ActionDispatch #:nodoc:
|
|
265
277
|
end
|
266
278
|
end
|
267
279
|
|
268
|
-
def nonce_directive?(directive)
|
269
|
-
|
280
|
+
def nonce_directive?(directive, nonce_directives)
|
281
|
+
nonce_directives.include?(directive)
|
270
282
|
end
|
271
283
|
end
|
272
284
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "active_support/parameter_filter"
|
4
4
|
|
5
5
|
module ActionDispatch
|
6
6
|
module Http
|
@@ -9,8 +9,8 @@ module ActionDispatch
|
|
9
9
|
# sub-hashes of the params hash to filter. Filtering only certain sub-keys
|
10
10
|
# from a hash is possible by using the dot notation: 'credit_card.number'.
|
11
11
|
# If a block is given, each key and value of the params hash and all
|
12
|
-
# sub-hashes
|
13
|
-
# String#replace or similar
|
12
|
+
# sub-hashes are passed to it, where the value or the key can be replaced using
|
13
|
+
# String#replace or similar methods.
|
14
14
|
#
|
15
15
|
# env["action_dispatch.parameter_filter"] = [:password]
|
16
16
|
# => replaces the value to all keys matching /password/i with "[FILTERED]"
|
@@ -28,8 +28,8 @@ module ActionDispatch
|
|
28
28
|
# => reverses the value to all keys matching /secret/i
|
29
29
|
module FilterParameters
|
30
30
|
ENV_MATCH = [/RAW_POST_DATA/, "rack.request.form_vars"] # :nodoc:
|
31
|
-
NULL_PARAM_FILTER = ParameterFilter.new # :nodoc:
|
32
|
-
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:
|
33
33
|
|
34
34
|
def initialize
|
35
35
|
super
|
@@ -41,6 +41,8 @@ module ActionDispatch
|
|
41
41
|
# Returns a hash of parameters with all sensitive data replaced.
|
42
42
|
def filtered_parameters
|
43
43
|
@filtered_parameters ||= parameter_filter.filter(parameters)
|
44
|
+
rescue ActionDispatch::Http::Parameters::ParseError
|
45
|
+
@filtered_parameters = {}
|
44
46
|
end
|
45
47
|
|
46
48
|
# Returns a hash of request.env with all sensitive data replaced.
|
@@ -69,7 +71,7 @@ module ActionDispatch
|
|
69
71
|
end
|
70
72
|
|
71
73
|
def parameter_filter_for(filters) # :doc:
|
72
|
-
ParameterFilter.new(filters)
|
74
|
+
ActiveSupport::ParameterFilter.new(filters)
|
73
75
|
end
|
74
76
|
|
75
77
|
KV_RE = "[^&;=]+"
|
@@ -121,7 +121,7 @@ module ActionDispatch
|
|
121
121
|
# not contained within the headers hash.
|
122
122
|
def env_name(key)
|
123
123
|
key = key.to_s
|
124
|
-
if key
|
124
|
+
if HTTP_HEADER.match?(key)
|
125
125
|
key = key.upcase.tr("-", "_")
|
126
126
|
key = "HTTP_" + key unless CGI_VARIABLES.include?(key)
|
127
127
|
end
|
@@ -7,6 +7,11 @@ module ActionDispatch
|
|
7
7
|
module MimeNegotiation
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
|
10
|
+
RESCUABLE_MIME_FORMAT_ERRORS = [
|
11
|
+
ActionController::BadRequest,
|
12
|
+
ActionDispatch::Http::Parameters::ParseError,
|
13
|
+
]
|
14
|
+
|
10
15
|
included do
|
11
16
|
mattr_accessor :ignore_accept_header, default: false
|
12
17
|
end
|
@@ -59,7 +64,7 @@ module ActionDispatch
|
|
59
64
|
fetch_header("action_dispatch.request.formats") do |k|
|
60
65
|
params_readable = begin
|
61
66
|
parameters[:format]
|
62
|
-
rescue
|
67
|
+
rescue *RESCUABLE_MIME_FORMAT_ERRORS
|
63
68
|
false
|
64
69
|
end
|
65
70
|
|
@@ -90,10 +95,7 @@ module ActionDispatch
|
|
90
95
|
if variant.all? { |v| v.is_a?(Symbol) }
|
91
96
|
@variant = ActiveSupport::ArrayInquirer.new(variant)
|
92
97
|
else
|
93
|
-
raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols.
|
94
|
-
"For security reasons, never directly set the variant to a user-provided value, " \
|
95
|
-
"like params[:variant].to_sym. Check user-provided value against a whitelist first, " \
|
96
|
-
"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."
|
97
99
|
end
|
98
100
|
end
|
99
101
|
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# -*- frozen-string-literal: true -*-
|
4
|
-
|
5
3
|
require "singleton"
|
6
4
|
require "active_support/core_ext/string/starts_ends_with"
|
7
5
|
|
@@ -74,7 +72,7 @@ module Mime
|
|
74
72
|
def initialize(index, name, q = nil)
|
75
73
|
@index = index
|
76
74
|
@name = name
|
77
|
-
q ||= 0.0 if @name == "*/*"
|
75
|
+
q ||= 0.0 if @name == "*/*" # Default wildcard match to end of list.
|
78
76
|
@q = ((q || 1.0).to_f * 100).to_i
|
79
77
|
end
|
80
78
|
|
@@ -172,6 +170,7 @@ module Mime
|
|
172
170
|
def parse(accept_header)
|
173
171
|
if !accept_header.include?(",")
|
174
172
|
accept_header = accept_header.split(PARAMETER_SEPARATOR_REGEXP).first
|
173
|
+
return [] unless accept_header
|
175
174
|
parse_trailing_star(accept_header) || [Mime::Type.lookup(accept_header)].compact
|
176
175
|
else
|
177
176
|
list, index = [], 0
|
@@ -223,7 +222,18 @@ module Mime
|
|
223
222
|
|
224
223
|
attr_reader :hash
|
225
224
|
|
225
|
+
MIME_NAME = "[a-zA-Z0-9][a-zA-Z0-9#{Regexp.escape('!#$&-^_.+')}]{0,126}"
|
226
|
+
MIME_PARAMETER_KEY = "[a-zA-Z0-9][a-zA-Z0-9#{Regexp.escape('!#$&-^_.+')}]{0,126}"
|
227
|
+
MIME_PARAMETER_VALUE = "#{Regexp.escape('"')}?[a-zA-Z0-9][a-zA-Z0-9#{Regexp.escape('!#$&-^_.+')}]{0,126}#{Regexp.escape('"')}?"
|
228
|
+
MIME_PARAMETER = "\s*\;\s+#{MIME_PARAMETER_KEY}(?:\=#{MIME_PARAMETER_VALUE})?"
|
229
|
+
MIME_REGEXP = /\A(?:\*\/\*|#{MIME_NAME}\/(?:\*|#{MIME_NAME})(?:\s*#{MIME_PARAMETER}\s*)*)\z/
|
230
|
+
|
231
|
+
class InvalidMimeType < StandardError; end
|
232
|
+
|
226
233
|
def initialize(string, symbol = nil, synonyms = [])
|
234
|
+
unless MIME_REGEXP.match?(string)
|
235
|
+
raise InvalidMimeType, "#{string.inspect} is not a valid MIME type"
|
236
|
+
end
|
227
237
|
@symbol, @synonyms = symbol, synonyms
|
228
238
|
@string = string
|
229
239
|
@hash = [@string, @synonyms, @symbol].hash
|
@@ -279,8 +289,6 @@ module Mime
|
|
279
289
|
|
280
290
|
def all?; false; end
|
281
291
|
|
282
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
283
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
284
292
|
protected
|
285
293
|
|
286
294
|
attr_reader :string, :synonyms
|
@@ -307,7 +315,7 @@ module Mime
|
|
307
315
|
include Singleton
|
308
316
|
|
309
317
|
def initialize
|
310
|
-
super "*/*",
|
318
|
+
super "*/*", nil
|
311
319
|
end
|
312
320
|
|
313
321
|
def all?; true; end
|
@@ -1,86 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/
|
3
|
+
require "active_support/deprecation/constant_accessor"
|
4
|
+
require "active_support/parameter_filter"
|
4
5
|
|
5
6
|
module ActionDispatch
|
6
7
|
module Http
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def initialize(filters = [])
|
11
|
-
@filters = filters
|
12
|
-
end
|
13
|
-
|
14
|
-
def filter(params)
|
15
|
-
compiled_filter.call(params)
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def compiled_filter
|
21
|
-
@compiled_filter ||= CompiledFilter.compile(@filters)
|
22
|
-
end
|
23
|
-
|
24
|
-
class CompiledFilter # :nodoc:
|
25
|
-
def self.compile(filters)
|
26
|
-
return lambda { |params| params.dup } if filters.empty?
|
27
|
-
|
28
|
-
strings, regexps, blocks = [], [], []
|
29
|
-
|
30
|
-
filters.each do |item|
|
31
|
-
case item
|
32
|
-
when Proc
|
33
|
-
blocks << item
|
34
|
-
when Regexp
|
35
|
-
regexps << item
|
36
|
-
else
|
37
|
-
strings << Regexp.escape(item.to_s)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
deep_regexps, regexps = regexps.partition { |r| r.to_s.include?("\\.".freeze) }
|
42
|
-
deep_strings, strings = strings.partition { |s| s.include?("\\.".freeze) }
|
43
|
-
|
44
|
-
regexps << Regexp.new(strings.join("|".freeze), true) unless strings.empty?
|
45
|
-
deep_regexps << Regexp.new(deep_strings.join("|".freeze), true) unless deep_strings.empty?
|
46
|
-
|
47
|
-
new regexps, deep_regexps, blocks
|
48
|
-
end
|
49
|
-
|
50
|
-
attr_reader :regexps, :deep_regexps, :blocks
|
51
|
-
|
52
|
-
def initialize(regexps, deep_regexps, blocks)
|
53
|
-
@regexps = regexps
|
54
|
-
@deep_regexps = deep_regexps.any? ? deep_regexps : nil
|
55
|
-
@blocks = blocks
|
56
|
-
end
|
57
|
-
|
58
|
-
def call(original_params, parents = [])
|
59
|
-
filtered_params = original_params.class.new
|
60
|
-
|
61
|
-
original_params.each do |key, value|
|
62
|
-
parents.push(key) if deep_regexps
|
63
|
-
if regexps.any? { |r| key =~ r }
|
64
|
-
value = FILTERED
|
65
|
-
elsif deep_regexps && (joined = parents.join(".")) && deep_regexps.any? { |r| joined =~ r }
|
66
|
-
value = FILTERED
|
67
|
-
elsif value.is_a?(Hash)
|
68
|
-
value = call(value, parents)
|
69
|
-
elsif value.is_a?(Array)
|
70
|
-
value = value.map { |v| v.is_a?(Hash) ? call(v, parents) : v }
|
71
|
-
elsif blocks.any?
|
72
|
-
key = key.dup if key.duplicable?
|
73
|
-
value = value.dup if value.duplicable?
|
74
|
-
blocks.each { |b| b.call(key, value) }
|
75
|
-
end
|
76
|
-
parents.pop if deep_regexps
|
77
|
-
|
78
|
-
filtered_params[key] = value
|
79
|
-
end
|
80
|
-
|
81
|
-
filtered_params
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
8
|
+
include ActiveSupport::Deprecation::DeprecatedConstantAccessor
|
9
|
+
deprecate_constant "ParameterFilter", "ActiveSupport::ParameterFilter",
|
10
|
+
message: "ActionDispatch::Http::ParameterFilter is deprecated and will be removed from Rails 6.1. Use ActiveSupport::ParameterFilter instead."
|
85
11
|
end
|
86
12
|
end
|