aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch')
-rw-r--r--actionpack/lib/action_dispatch/http/filter_parameters.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/mime_negotiation.rb3
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb8
-rw-r--r--actionpack/lib/action_dispatch/http/parameter_filter.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb8
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb4
-rw-r--r--actionpack/lib/action_dispatch/http/upload.rb8
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb3
-rw-r--r--actionpack/lib/action_dispatch/journey/gtg/simulator.rb8
-rw-r--r--actionpack/lib/action_dispatch/journey/gtg/transition_table.rb2
-rw-r--r--actionpack/lib/action_dispatch/journey/route.rb10
-rw-r--r--actionpack/lib/action_dispatch/journey/router/utils.rb10
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb54
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/exception_wrapper.rb8
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb14
-rw-r--r--actionpack/lib/action_dispatch/railtie.rb3
-rw-r--r--actionpack/lib/action_dispatch/request/session.rb2
-rw-r--r--actionpack/lib/action_dispatch/request/utils.rb3
-rw-r--r--actionpack/lib/action_dispatch/routing.rb9
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb30
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb8
-rw-r--r--actionpack/lib/action_dispatch/routing/routes_proxy.rb5
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb13
-rw-r--r--actionpack/lib/action_dispatch/system_test_case.rb10
-rw-r--r--actionpack/lib/action_dispatch/system_testing/driver.rb29
-rw-r--r--actionpack/lib/action_dispatch/system_testing/server.rb13
-rw-r--r--actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb7
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb14
29 files changed, 182 insertions, 110 deletions
diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb
index e584b84d92..077ab2561f 100644
--- a/actionpack/lib/action_dispatch/http/filter_parameters.rb
+++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -74,7 +74,7 @@ module ActionDispatch
PAIR_RE = %r{(#{KV_RE})=(#{KV_RE})}
def filtered_query_string # :doc:
query_string.gsub(PAIR_RE) do |_|
- parameter_filter.filter([[$1, $2]]).first.join("=")
+ parameter_filter.filter($1 => $2).first.join("=")
end
end
end
diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
index 19f89edbc1..5994a01c78 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -6,8 +6,7 @@ module ActionDispatch
extend ActiveSupport::Concern
included do
- mattr_accessor :ignore_accept_header
- self.ignore_accept_header = false
+ mattr_accessor :ignore_accept_header, default: false
end
# The MIME type of the HTTP request, such as Mime[:xml].
diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index 0cf010f59e..74a3afab44 100644
--- a/actionpack/lib/action_dispatch/http/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -326,11 +326,11 @@ module Mime
def ref; end
- def respond_to_missing?(method, include_private = false)
- method.to_s.ends_with? "?"
- end
-
private
+ def respond_to_missing?(method, _)
+ method.to_s.ends_with? "?"
+ end
+
def method_missing(method, *args)
false if method.to_s.ends_with? "?"
end
diff --git a/actionpack/lib/action_dispatch/http/parameter_filter.rb b/actionpack/lib/action_dispatch/http/parameter_filter.rb
index 889f55a52a..1d2b4b902b 100644
--- a/actionpack/lib/action_dispatch/http/parameter_filter.rb
+++ b/actionpack/lib/action_dispatch/http/parameter_filter.rb
@@ -54,7 +54,7 @@ module ActionDispatch
end
def call(original_params, parents = [])
- filtered_params = {}
+ filtered_params = original_params.class.new
original_params.each do |key, value|
parents.push(key) if deep_regexps
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index 79a2ef965b..7c585dbe68 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -85,7 +85,7 @@ module ActionDispatch
def set_binary_encoding(params)
action = params[:action]
- if controller_class.binary_params_for?(action)
+ if binary_params_for?(action)
ActionDispatch::Request::Utils.each_param_value(params) do |param|
param.force_encoding ::Encoding::ASCII_8BIT
end
@@ -93,6 +93,12 @@ module ActionDispatch
params
end
+ def binary_params_for?(action)
+ controller_class.binary_params_for?(action)
+ rescue NameError
+ false
+ end
+
def parse_formatted_parameters(parsers)
return yield if content_length.zero? || content_mime_type.nil?
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 2ee52eeb48..3c91677d55 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -81,8 +81,8 @@ module ActionDispatch # :nodoc:
LOCATION = "Location".freeze
NO_CONTENT_CODES = [100, 101, 102, 204, 205, 304]
- cattr_accessor(:default_charset) { "utf-8" }
- cattr_accessor(:default_headers)
+ cattr_accessor :default_charset, default: "utf-8"
+ cattr_accessor :default_headers
include Rack::Response::Helpers
# Aliasing these off because AD::Http::Cache::Response defines them.
diff --git a/actionpack/lib/action_dispatch/http/upload.rb b/actionpack/lib/action_dispatch/http/upload.rb
index 61ba052e45..225272d66e 100644
--- a/actionpack/lib/action_dispatch/http/upload.rb
+++ b/actionpack/lib/action_dispatch/http/upload.rb
@@ -27,14 +27,18 @@ module ActionDispatch
@tempfile = hash[:tempfile]
raise(ArgumentError, ":tempfile is required") unless @tempfile
- @original_filename = hash[:filename]
- if @original_filename
+ if hash[:filename]
+ @original_filename = hash[:filename].dup
+
begin
@original_filename.encode!(Encoding::UTF_8)
rescue EncodingError
@original_filename.force_encoding(Encoding::UTF_8)
end
+ else
+ @original_filename = nil
end
+
@content_type = hash[:type]
@headers = hash[:head]
end
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index b6be48a48b..f902fe36e0 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -7,8 +7,7 @@ module ActionDispatch
HOST_REGEXP = /(^[^:]+:\/\/)?(\[[^\]]+\]|[^:]+)(?::(\d+$))?/
PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
- mattr_accessor :tld_length
- self.tld_length = 1
+ mattr_accessor :tld_length, default: 1
class << self
# Returns the domain part of a host given the domain level.
diff --git a/actionpack/lib/action_dispatch/journey/gtg/simulator.rb b/actionpack/lib/action_dispatch/journey/gtg/simulator.rb
index d692f6415c..62f052ced6 100644
--- a/actionpack/lib/action_dispatch/journey/gtg/simulator.rb
+++ b/actionpack/lib/action_dispatch/journey/gtg/simulator.rb
@@ -18,14 +18,6 @@ module ActionDispatch
@tt = transition_table
end
- def simulate(string)
- ms = memos(string) { return }
- MatchData.new(ms)
- end
-
- alias :=~ :simulate
- alias :match :simulate
-
def memos(string)
input = StringScanner.new(string)
state = [0]
diff --git a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
index e1ac2c873e..45aff287b1 100644
--- a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
+++ b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
@@ -82,7 +82,7 @@ module ActionDispatch
end
def visualizer(paths, title = "FSM")
- viz_dir = File.join File.dirname(__FILE__), "..", "visualizer"
+ viz_dir = File.join __dir__, "..", "visualizer"
fsm_js = File.read File.join(viz_dir, "fsm.js")
fsm_css = File.read File.join(viz_dir, "fsm.css")
erb = File.read File.join(viz_dir, "index.html.erb")
diff --git a/actionpack/lib/action_dispatch/journey/route.rb b/actionpack/lib/action_dispatch/journey/route.rb
index 7bc15aa6b3..0acbac1d9d 100644
--- a/actionpack/lib/action_dispatch/journey/route.rb
+++ b/actionpack/lib/action_dispatch/journey/route.rb
@@ -10,11 +10,11 @@ module ActionDispatch
module VerbMatchers
VERBS = %w{ DELETE GET HEAD OPTIONS LINK PATCH POST PUT TRACE UNLINK }
VERBS.each do |v|
- class_eval <<-eoc
- class #{v}
- def self.verb; name.split("::").last; end
- def self.call(req); req.#{v.downcase}?; end
- end
+ class_eval <<-eoc, __FILE__, __LINE__ + 1
+ class #{v}
+ def self.verb; name.split("::").last; end
+ def self.call(req); req.#{v.downcase}?; end
+ end
eoc
end
diff --git a/actionpack/lib/action_dispatch/journey/router/utils.rb b/actionpack/lib/action_dispatch/journey/router/utils.rb
index ffcd875b4d..6d400f3364 100644
--- a/actionpack/lib/action_dispatch/journey/router/utils.rb
+++ b/actionpack/lib/action_dispatch/journey/router/utils.rb
@@ -13,11 +13,13 @@ module ActionDispatch
# normalize_path("") # => "/"
# normalize_path("/%ab") # => "/%AB"
def self.normalize_path(path)
+ encoding = path.encoding
path = "/#{path}"
path.squeeze!("/".freeze)
path.sub!(%r{/+\Z}, "".freeze)
path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
path = "/" if path == "".freeze
+ path.force_encoding(encoding)
path
end
@@ -59,11 +61,11 @@ module ActionDispatch
end
private
- def escape(component, pattern) # :doc:
+ def escape(component, pattern)
component.gsub(pattern) { |unsafe| percent_encode(unsafe) }.force_encoding(US_ASCII)
end
- def percent_encode(unsafe) # :doc:
+ def percent_encode(unsafe)
safe = EMPTY.dup
unsafe.each_byte { |b| safe << DEC2HEX[b] }
safe
@@ -84,6 +86,10 @@ module ActionDispatch
ENCODER.escape_fragment(fragment.to_s)
end
+ # Replaces any escaped sequences with their unescaped representations.
+ #
+ # uri = "/topics?title=Ruby%20on%20Rails"
+ # unescape_uri(uri) #=> "/topics?title=Ruby on Rails"
def self.unescape_uri(uri)
ENCODER.unescape_uri(uri)
end
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index e565c03a8a..533925ebe1 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -43,6 +43,10 @@ module ActionDispatch
get_header Cookies::ENCRYPTED_SIGNED_COOKIE_SALT
end
+ def authenticated_encrypted_cookie_salt
+ get_header Cookies::AUTHENTICATED_ENCRYPTED_COOKIE_SALT
+ end
+
def secret_token
get_header Cookies::SECRET_TOKEN
end
@@ -149,6 +153,7 @@ module ActionDispatch
SIGNED_COOKIE_SALT = "action_dispatch.signed_cookie_salt".freeze
ENCRYPTED_COOKIE_SALT = "action_dispatch.encrypted_cookie_salt".freeze
ENCRYPTED_SIGNED_COOKIE_SALT = "action_dispatch.encrypted_signed_cookie_salt".freeze
+ AUTHENTICATED_ENCRYPTED_COOKIE_SALT = "action_dispatch.authenticated_encrypted_cookie_salt".freeze
SECRET_TOKEN = "action_dispatch.secret_token".freeze
SECRET_KEY_BASE = "action_dispatch.secret_key_base".freeze
COOKIES_SERIALIZER = "action_dispatch.cookies_serializer".freeze
@@ -207,6 +212,9 @@ module ActionDispatch
# If +secrets.secret_key_base+ and +secrets.secret_token+ (deprecated) are both set,
# legacy cookies signed with the old key generator will be transparently upgraded.
#
+ # If +config.action_dispatch.encrypted_cookie_salt+ and +config.action_dispatch.encrypted_signed_cookie_salt+
+ # are both set, legacy cookies encrypted with HMAC AES-256-CBC will be transparently upgraded.
+ #
# This jar requires that you set a suitable secret for the verification on your app's +secrets.secret_key_base+.
#
# Example:
@@ -219,6 +227,8 @@ module ActionDispatch
@encrypted ||=
if upgrade_legacy_signed_cookies?
UpgradeLegacyEncryptedCookieJar.new(self)
+ elsif upgrade_legacy_hmac_aes_cbc_cookies?
+ UpgradeLegacyHmacAesCbcCookieJar.new(self)
else
EncryptedCookieJar.new(self)
end
@@ -240,6 +250,13 @@ module ActionDispatch
def upgrade_legacy_signed_cookies?
request.secret_token.present? && request.secret_key_base.present?
end
+
+ def upgrade_legacy_hmac_aes_cbc_cookies?
+ request.secret_key_base.present? &&
+ request.authenticated_encrypted_cookie_salt.present? &&
+ request.encrypted_signed_cookie_salt.present? &&
+ request.encrypted_cookie_salt.present?
+ end
end
# Passing the ActiveSupport::MessageEncryptor::NullSerializer downstream
@@ -415,8 +432,7 @@ module ActionDispatch
end
end
- mattr_accessor :always_write_cookie
- self.always_write_cookie = false
+ mattr_accessor :always_write_cookie, default: false
private
@@ -576,9 +592,11 @@ module ActionDispatch
"Read the upgrade documentation to learn more about this new config option."
end
- secret = key_generator.generate_key(request.encrypted_cookie_salt || "")[0, ActiveSupport::MessageEncryptor.key_len]
- sign_secret = key_generator.generate_key(request.encrypted_signed_cookie_salt || "")
- @encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
+ cipher = "aes-256-gcm"
+ key_len = ActiveSupport::MessageEncryptor.key_len(cipher)
+ secret = key_generator.generate_key(request.authenticated_encrypted_cookie_salt || "")[0, key_len]
+
+ @encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: cipher, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
end
private
@@ -603,6 +621,32 @@ module ActionDispatch
include VerifyAndUpgradeLegacySignedMessage
end
+ # UpgradeLegacyHmacAesCbcCookieJar is used by ActionDispatch::Session::CookieStore
+ # to upgrade cookies encrypted with AES-256-CBC with HMAC to AES-256-GCM
+ class UpgradeLegacyHmacAesCbcCookieJar < EncryptedCookieJar
+ def initialize(parent_jar)
+ super
+
+ secret = key_generator.generate_key(request.encrypted_cookie_salt || "")[0, ActiveSupport::MessageEncryptor.key_len]
+ sign_secret = key_generator.generate_key(request.encrypted_signed_cookie_salt || "")
+
+ @legacy_encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, cipher: "aes-256-cbc", digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
+ end
+
+ def decrypt_and_verify_legacy_encrypted_message(name, signed_message)
+ deserialize(name, @legacy_encryptor.decrypt_and_verify(signed_message)).tap do |value|
+ self[name] = { value: value }
+ end
+ rescue ActiveSupport::MessageVerifier::InvalidSignature, ActiveSupport::MessageEncryptor::InvalidMessage
+ nil
+ end
+
+ private
+ def parse(name, signed_message)
+ super || decrypt_and_verify_legacy_encrypted_message(name, signed_message)
+ end
+ end
+
def initialize(app)
@app = app
end
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
index 1c720c5a8e..336a775880 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -10,7 +10,7 @@ module ActionDispatch
# This middleware is responsible for logging exceptions and
# showing a debugging page in case the request is local.
class DebugExceptions
- RESCUES_TEMPLATE_PATH = File.expand_path("../templates", __FILE__)
+ RESCUES_TEMPLATE_PATH = File.expand_path("templates", __dir__)
class DebugView < ActionView::Base
def debug_params(params)
diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
index 397f0a8b92..08b4541d24 100644
--- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
+++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
@@ -3,9 +3,7 @@ require "rack/utils"
module ActionDispatch
class ExceptionWrapper
- cattr_accessor :rescue_responses
- @@rescue_responses = Hash.new(:internal_server_error)
- @@rescue_responses.merge!(
+ cattr_accessor :rescue_responses, default: Hash.new(:internal_server_error).merge!(
"ActionController::RoutingError" => :not_found,
"AbstractController::ActionNotFound" => :not_found,
"ActionController::MethodNotAllowed" => :method_not_allowed,
@@ -21,9 +19,7 @@ module ActionDispatch
"Rack::QueryParser::InvalidParameterError" => :bad_request
)
- cattr_accessor :rescue_templates
- @@rescue_templates = Hash.new("diagnostics")
- @@rescue_templates.merge!(
+ cattr_accessor :rescue_templates, default: Hash.new("diagnostics").merge!(
"ActionView::MissingTemplate" => "missing_template",
"ActionController::RoutingError" => "routing_error",
"AbstractController::ActionNotFound" => "unknown_action",
diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index 5d10129d21..fb99f13a1c 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -6,11 +6,11 @@ module ActionDispatch
# When initialized, it can accept optional HTTP headers, which will be set
# when a response containing a file's contents is delivered.
#
- # This middleware will render the file specified in `env["PATH_INFO"]`
+ # This middleware will render the file specified in <tt>env["PATH_INFO"]</tt>
# where the base path is in the +root+ directory. For example, if the +root+
- # is set to `public/`, then a request with `env["PATH_INFO"]` of
- # `assets/application.js` will return a response with the contents of a file
- # located at `public/assets/application.js` if the file exists. If the file
+ # is set to +public/+, then a request with <tt>env["PATH_INFO"]</tt> of
+ # +assets/application.js+ will return a response with the contents of a file
+ # located at +public/assets/application.js+ if the file exists. If the file
# does not exist, a 404 "File not Found" response will be returned.
class FileHandler
def initialize(root, index: "index", headers: {})
@@ -23,8 +23,8 @@ module ActionDispatch
# correct read permissions, the return value is a URI-escaped string
# representing the filename. Otherwise, false is returned.
#
- # Used by the `Static` class to check the existence of a valid file
- # in the server's `public/` directory (see Static#call).
+ # Used by the +Static+ class to check the existence of a valid file
+ # in the server's +public/+ directory (see Static#call).
def match?(path)
path = ::Rack::Utils.unescape_path path
return false unless ::Rack::Utils.valid_path? path
@@ -99,7 +99,7 @@ module ActionDispatch
# This middleware will attempt to return the contents of a file's body from
# disk in the response. If a file is not found on disk, the request will be
# delegated to the application stack. This middleware is commonly initialized
- # to serve assets from a server's `public/` directory.
+ # to serve assets from a server's +public/+ directory.
#
# This middleware verifies the path to ensure that only files
# living in the root directory can be rendered. A request cannot
diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb
index 16a18a7f25..7662e164b8 100644
--- a/actionpack/lib/action_dispatch/railtie.rb
+++ b/actionpack/lib/action_dispatch/railtie.rb
@@ -16,6 +16,7 @@ module ActionDispatch
config.action_dispatch.signed_cookie_salt = "signed cookie"
config.action_dispatch.encrypted_cookie_salt = "encrypted cookie"
config.action_dispatch.encrypted_signed_cookie_salt = "signed encrypted cookie"
+ config.action_dispatch.use_authenticated_cookie_encryption = false
config.action_dispatch.perform_deep_munge = true
config.action_dispatch.default_headers = {
@@ -36,6 +37,8 @@ module ActionDispatch
ActionDispatch::ExceptionWrapper.rescue_responses.merge!(config.action_dispatch.rescue_responses)
ActionDispatch::ExceptionWrapper.rescue_templates.merge!(config.action_dispatch.rescue_templates)
+ config.action_dispatch.authenticated_encrypted_cookie_salt = "authenticated encrypted cookie" if config.action_dispatch.use_authenticated_cookie_encryption
+
config.action_dispatch.always_write_cookie = Rails.env.development? if config.action_dispatch.always_write_cookie.nil?
ActionDispatch::Cookies::CookieJar.always_write_cookie = config.action_dispatch.always_write_cookie
diff --git a/actionpack/lib/action_dispatch/request/session.rb b/actionpack/lib/action_dispatch/request/session.rb
index 74ba6466cf..3547a8604f 100644
--- a/actionpack/lib/action_dispatch/request/session.rb
+++ b/actionpack/lib/action_dispatch/request/session.rb
@@ -101,11 +101,13 @@ module ActionDispatch
# Returns keys of the session as Array.
def keys
+ load_for_read!
@delegate.keys
end
# Returns values of the session as Array.
def values
+ load_for_read!
@delegate.values
end
diff --git a/actionpack/lib/action_dispatch/request/utils.rb b/actionpack/lib/action_dispatch/request/utils.rb
index 3615e4b1d8..4f79c4c21e 100644
--- a/actionpack/lib/action_dispatch/request/utils.rb
+++ b/actionpack/lib/action_dispatch/request/utils.rb
@@ -1,8 +1,7 @@
module ActionDispatch
class Request
class Utils # :nodoc:
- mattr_accessor :perform_deep_munge
- self.perform_deep_munge = true
+ mattr_accessor :perform_deep_munge, default: true
def self.each_param_value(params, &block)
case params
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index 60d4789a63..87dd1eba38 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -254,14 +254,5 @@ module ActionDispatch
SEPARATORS = %w( / . ? ) #:nodoc:
HTTP_METHODS = [:get, :head, :post, :patch, :put, :delete, :options] #:nodoc:
-
- #:stopdoc:
- INSECURE_URL_PARAMETERS_MESSAGE = <<-MSG.squish
- Attempting to generate a URL from non-sanitized request parameters!
-
- An attacker can inject malicious data into the generated URL, such as
- changing the host. Whitelist and sanitize passed parameters to be secure.
- MSG
- #:startdoc:
end
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 74904e3d45..88deee5f5e 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1837,7 +1837,7 @@ module ActionDispatch
path_types.fetch(String, []).each do |_path|
route_options = options.dup
if _path && option_path
- raise ArgumentError, "Ambigous route definition. Both :path and the route path where specified as strings."
+ raise ArgumentError, "Ambiguous route definition. Both :path and the route path where specified as strings."
end
to = get_to_from_path(_path, to, route_options[:action])
decomposed_match(_path, controller, route_options, _path, to, via, formatted, anchor, options_constraints)
@@ -2038,8 +2038,8 @@ module ActionDispatch
# { controller: "pages", action: "index", subdomain: "www" }
# end
#
- # The return value from the block passed to `direct` must be a valid set of
- # arguments for `url_for` which will actually build the URL string. This can
+ # The return value from the block passed to +direct+ must be a valid set of
+ # arguments for +url_for+ which will actually build the URL string. This can
# be one of the following:
#
# * A string, which is treated as a generated URL
@@ -2058,17 +2058,17 @@ module ActionDispatch
# [ :products, options.merge(params.permit(:page, :size).to_h.symbolize_keys) ]
# end
#
- # In this instance the `params` object comes from the context in which the the
+ # In this instance the +params+ object comes from the context in which the the
# block is executed, e.g. generating a URL inside a controller action or a view.
# If the block is executed where there isn't a params object such as this:
#
# Rails.application.routes.url_helpers.browse_path
#
- # then it will raise a `NameError`. Because of this you need to be aware of the
+ # then it will raise a +NameError+. Because of this you need to be aware of the
# context in which you will use your custom URL helper when defining it.
#
- # NOTE: The `direct` method can't be used inside of a scope block such as
- # `namespace` or `scope` and will raise an error if it detects that it is.
+ # NOTE: The +direct+ method can't be used inside of a scope block such as
+ # +namespace+ or +scope+ and will raise an error if it detects that it is.
def direct(name, options = {}, &block)
unless @scope.root?
raise RuntimeError, "The direct method can't be used inside a routes scope block"
@@ -2078,8 +2078,8 @@ module ActionDispatch
end
# Define custom polymorphic mappings of models to URLs. This alters the
- # behavior of `polymorphic_url` and consequently the behavior of
- # `link_to` and `form_for` when passed a model instance, e.g:
+ # behavior of +polymorphic_url+ and consequently the behavior of
+ # +link_to+ and +form_for+ when passed a model instance, e.g:
#
# resource :basket
#
@@ -2087,8 +2087,8 @@ module ActionDispatch
# [:basket]
# end
#
- # This will now generate "/basket" when a `Basket` instance is passed to
- # `link_to` or `form_for` instead of the standard "/baskets/:id".
+ # This will now generate "/basket" when a +Basket+ instance is passed to
+ # +link_to+ or +form_for+ instead of the standard "/baskets/:id".
#
# NOTE: This custom behavior only applies to simple polymorphic URLs where
# a single model instance is passed and not more complicated forms, e.g:
@@ -2105,7 +2105,7 @@ module ActionDispatch
# link_to "Profile", @current_user
# link_to "Profile", [:admin, @current_user]
#
- # The first `link_to` will generate "/profile" but the second will generate
+ # The first +link_to+ will generate "/profile" but the second will generate
# the standard polymorphic URL of "/admin/users/1".
#
# You can pass options to a polymorphic mapping - the arity for the block
@@ -2116,11 +2116,11 @@ module ActionDispatch
# end
#
# This generates the URL "/basket#items" because when the last item in an
- # array passed to `polymorphic_url` is a hash then it's treated as options
+ # array passed to +polymorphic_url+ is a hash then it's treated as options
# to the URL helper that gets called.
#
- # NOTE: The `resolve` method can't be used inside of a scope block such as
- # `namespace` or `scope` and will raise an error if it detects that it is.
+ # NOTE: The +resolve+ method can't be used inside of a scope block such as
+ # +namespace+ or +scope+ and will raise an error if it detects that it is.
def resolve(*args, &block)
unless @scope.root?
raise RuntimeError, "The resolve method can't be used inside a routes scope block"
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 129e90037e..68bd6d806b 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -279,6 +279,8 @@ module ActionDispatch
if args.size < path_params_size
path_params -= controller_options.keys
path_params -= result.keys
+ else
+ path_params = path_params.dup
end
inner_options.each_key do |key|
path_params.delete(key)
@@ -318,11 +320,7 @@ module ActionDispatch
when Hash
args.pop
when ActionController::Parameters
- if last.permitted?
- args.pop.to_h
- else
- raise ArgumentError, ActionDispatch::Routing::INSECURE_URL_PARAMETERS_MESSAGE
- end
+ args.pop.to_h
end
helper.call self, args, options
end
diff --git a/actionpack/lib/action_dispatch/routing/routes_proxy.rb b/actionpack/lib/action_dispatch/routing/routes_proxy.rb
index ee847eaeed..c1423f770f 100644
--- a/actionpack/lib/action_dispatch/routing/routes_proxy.rb
+++ b/actionpack/lib/action_dispatch/routing/routes_proxy.rb
@@ -19,7 +19,8 @@ module ActionDispatch
end
end
- def respond_to_missing?(method, include_private = false)
+ private
+ def respond_to_missing?(method, _)
super || @helpers.respond_to?(method)
end
@@ -32,7 +33,7 @@ module ActionDispatch
@helpers.#{method}(*args)
end
RUBY
- send(method, *args)
+ public_send(method, *args)
else
super
end
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index 008216cc80..a9bdefa775 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -171,17 +171,10 @@ module ActionDispatch
case options
when nil
_routes.url_for(url_options.symbolize_keys)
- when Hash
+ when Hash, ActionController::Parameters
route_name = options.delete :use_route
- _routes.url_for(options.symbolize_keys.reverse_merge!(url_options),
- route_name)
- when ActionController::Parameters
- unless options.permitted?
- raise ArgumentError.new(ActionDispatch::Routing::INSECURE_URL_PARAMETERS_MESSAGE)
- end
- route_name = options.delete :use_route
- _routes.url_for(options.to_h.symbolize_keys.
- reverse_merge!(url_options), route_name)
+ merged_url_options = options.to_h.symbolize_keys.reverse_merge!(url_options)
+ _routes.url_for(merged_url_options, route_name)
when String
options
when Symbol
diff --git a/actionpack/lib/action_dispatch/system_test_case.rb b/actionpack/lib/action_dispatch/system_test_case.rb
index 98fdb36c91..c39a135ce0 100644
--- a/actionpack/lib/action_dispatch/system_test_case.rb
+++ b/actionpack/lib/action_dispatch/system_test_case.rb
@@ -66,14 +66,18 @@ module ActionDispatch
#
# To use a headless driver, like Poltergeist, update your Gemfile to use
# Poltergeist instead of Selenium and then declare the driver name in the
- # +application_system_test_case.rb+ file. In this case you would leave out the +:using+
- # option because the driver is headless.
+ # +application_system_test_case.rb+ file. In this case, you would leave out
+ # the +:using+ option because the driver is headless, but you can still use
+ # +:screen_size+ to change the size of the browser screen, also you can use
+ # +:options+ to pass options supported by the driver. Please refer to your
+ # driver documentation to learn about supported options.
#
# require "test_helper"
# require "capybara/poltergeist"
#
# class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
- # driven_by :poltergeist
+ # driven_by :poltergeist, screen_size: [1400, 1400], options:
+ # { js_errors: true }
# end
#
# Because <tt>ActionDispatch::SystemTestCase</tt> is a shim between Capybara
diff --git a/actionpack/lib/action_dispatch/system_testing/driver.rb b/actionpack/lib/action_dispatch/system_testing/driver.rb
index 5cf17883f7..1a027f2e23 100644
--- a/actionpack/lib/action_dispatch/system_testing/driver.rb
+++ b/actionpack/lib/action_dispatch/system_testing/driver.rb
@@ -9,23 +9,42 @@ module ActionDispatch
end
def use
- register if selenium?
+ register unless rack_test?
+
setup
end
private
- def selenium?
- @name == :selenium
+ def rack_test?
+ @name == :rack_test
end
def register
Capybara.register_driver @name do |app|
- Capybara::Selenium::Driver.new(app, { browser: @browser }.merge(@options)).tap do |driver|
- driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size)
+ case @name
+ when :selenium then register_selenium(app)
+ when :poltergeist then register_poltergeist(app)
+ when :webkit then register_webkit(app)
end
end
end
+ def register_selenium(app)
+ Capybara::Selenium::Driver.new(app, { browser: @browser }.merge(@options)).tap do |driver|
+ driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size)
+ end
+ end
+
+ def register_poltergeist(app)
+ Capybara::Poltergeist::Driver.new(app, @options.merge(window_size: @screen_size))
+ end
+
+ def register_webkit(app)
+ Capybara::Webkit::Driver.new(app, Capybara::Webkit::Configuration.to_hash.merge(@options)).tap do |driver|
+ driver.resize_window(*@screen_size)
+ end
+ end
+
def setup
Capybara.current_driver = @name
end
diff --git a/actionpack/lib/action_dispatch/system_testing/server.rb b/actionpack/lib/action_dispatch/system_testing/server.rb
index 4a214ef713..89ca6944d9 100644
--- a/actionpack/lib/action_dispatch/system_testing/server.rb
+++ b/actionpack/lib/action_dispatch/system_testing/server.rb
@@ -3,6 +3,12 @@ require "rack/handler/puma"
module ActionDispatch
module SystemTesting
class Server # :nodoc:
+ class << self
+ attr_accessor :silence_puma
+ end
+
+ self.silence_puma = false
+
def run
register
setup
@@ -11,7 +17,12 @@ module ActionDispatch
private
def register
Capybara.register_server :rails_puma do |app, port, host|
- Rack::Handler::Puma.run(app, Port: port, Threads: "0:1")
+ Rack::Handler::Puma.run(
+ app,
+ Port: port,
+ Threads: "0:1",
+ Silent: self.class.silence_puma
+ )
end
end
diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb
index 187ba2cc5f..f03f0d4299 100644
--- a/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb
+++ b/actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb
@@ -2,7 +2,12 @@ module ActionDispatch
module SystemTesting
module TestHelpers
module SetupAndTeardown # :nodoc:
- DEFAULT_HOST = "127.0.0.1"
+ DEFAULT_HOST = "http://127.0.0.1"
+
+ def host!(host)
+ super
+ Capybara.app_host = host
+ end
def before_setup
host! DEFAULT_HOST
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 2e2db98ad6..f16647fac8 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -338,8 +338,7 @@ module ActionDispatch
@integration_session = nil
end
- %w(get post patch put head delete cookies assigns
- xml_http_request xhr get_via_redirect post_via_redirect).each do |method|
+ %w(get post patch put head delete cookies assigns follow_redirect!).each do |method|
define_method(method) do |*args|
# reset the html_document variable, except for cookies/assigns calls
unless method == "cookies" || method == "assigns"
@@ -385,14 +384,15 @@ module ActionDispatch
integration_session.default_url_options = options
end
- def respond_to_missing?(method, include_private = false)
- integration_session.respond_to?(method, include_private) || super
+ private
+ def respond_to_missing?(method, _)
+ integration_session.respond_to?(method) || super
end
# Delegate unhandled messages to the current session instance.
- def method_missing(sym, *args, &block)
- if integration_session.respond_to?(sym)
- integration_session.__send__(sym, *args, &block).tap do
+ def method_missing(method, *args, &block)
+ if integration_session.respond_to?(method)
+ integration_session.public_send(method, *args, &block).tap do
copy_session_variables!
end
else