aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/abstract_controller/base.rb8
-rw-r--r--actionpack/lib/abstract_controller/caching/fragments.rb35
-rw-r--r--actionpack/lib/abstract_controller/callbacks.rb20
-rw-r--r--actionpack/lib/action_controller/api.rb1
-rw-r--r--actionpack/lib/action_controller/base.rb7
-rw-r--r--actionpack/lib/action_controller/log_subscriber.rb4
-rw-r--r--actionpack/lib/action_controller/metal.rb2
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb2
-rw-r--r--actionpack/lib/action_controller/metal/params_wrapper.rb6
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb6
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb121
-rw-r--r--actionpack/lib/action_controller/test_case.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/mime_negotiation.rb4
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb26
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb19
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb14
-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.rb2
-rw-r--r--actionpack/lib/action_dispatch/journey/formatter.rb2
-rw-r--r--actionpack/lib/action_dispatch/journey/gtg/simulator.rb8
-rw-r--r--actionpack/lib/action_dispatch/journey/gtg/transition_table.rb3
-rw-r--r--actionpack/lib/action_dispatch/journey/route.rb9
-rw-r--r--actionpack/lib/action_dispatch/journey/router/utils.rb12
-rw-r--r--actionpack/lib/action_dispatch/journey/visitors.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb61
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/remote_ip.rb6
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/show_exceptions.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb4
-rw-r--r--actionpack/lib/action_dispatch/railtie.rb3
-rw-r--r--actionpack/lib/action_dispatch/request/session.rb10
-rw-r--r--actionpack/lib/action_dispatch/request/utils.rb3
-rw-r--r--actionpack/lib/action_dispatch/routing.rb11
-rw-r--r--actionpack/lib/action_dispatch/routing/inspector.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb53
-rw-r--r--actionpack/lib/action_dispatch/routing/polymorphic_routes.rb8
-rw-r--r--actionpack/lib/action_dispatch/routing/redirection.rb4
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb44
-rw-r--r--actionpack/lib/action_dispatch/routing/routes_proxy.rb5
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb25
-rw-r--r--actionpack/lib/action_dispatch/system_test_case.rb17
-rw-r--r--actionpack/lib/action_dispatch/system_testing/driver.rb3
-rw-r--r--actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb2
-rw-r--r--actionpack/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb7
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/response.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb8
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb28
-rw-r--r--actionpack/lib/action_dispatch/testing/test_request.rb2
-rw-r--r--actionpack/lib/action_pack/gem_version.rb4
52 files changed, 409 insertions, 237 deletions
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index e7cb6347a2..dc79820a82 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -14,8 +14,16 @@ module AbstractController
# expected to provide their own +render+ method, since rendering means
# different things depending on the context.
class Base
+ ##
+ # Returns the body of the HTTP response sent by the controller.
attr_internal :response_body
+
+ ##
+ # Returns the name of the action this controller is processing.
attr_internal :action_name
+
+ ##
+ # Returns the formats that can be processed by the controller.
attr_internal :formats
include ActiveSupport::Configurable
diff --git a/actionpack/lib/abstract_controller/caching/fragments.rb b/actionpack/lib/abstract_controller/caching/fragments.rb
index c85b4adba1..14e4a82523 100644
--- a/actionpack/lib/abstract_controller/caching/fragments.rb
+++ b/actionpack/lib/abstract_controller/caching/fragments.rb
@@ -25,7 +25,10 @@ module AbstractController
self.fragment_cache_keys = []
- helper_method :fragment_cache_key if respond_to?(:helper_method)
+ if respond_to?(:helper_method)
+ helper_method :fragment_cache_key
+ helper_method :combined_fragment_cache_key
+ end
end
module ClassMethods
@@ -62,17 +65,36 @@ module AbstractController
# with the specified +key+ value. The key is expanded using
# ActiveSupport::Cache.expand_cache_key.
def fragment_cache_key(key)
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Calling fragment_cache_key directly is deprecated and will be removed in Rails 6.0.
+ All fragment accessors now use the combined_fragment_cache_key method that retains the key as an array,
+ such that the caching stores can interrogate the parts for cache versions used in
+ recyclable cache keys.
+ MSG
+
head = self.class.fragment_cache_keys.map { |k| instance_exec(&k) }
tail = key.is_a?(Hash) ? url_for(key).split("://").last : key
ActiveSupport::Cache.expand_cache_key([*head, *tail], :views)
end
+ # Given a key (as described in +expire_fragment+), returns
+ # a key array suitable for use in reading, writing, or expiring a
+ # cached fragment. All keys begin with <tt>:views</tt>,
+ # followed by ENV["RAILS_CACHE_ID"] or ENV["RAILS_APP_VERSION"] if set,
+ # followed by any controller-wide key prefix values, ending
+ # with the specified +key+ value.
+ def combined_fragment_cache_key(key)
+ head = self.class.fragment_cache_keys.map { |k| instance_exec(&k) }
+ tail = key.is_a?(Hash) ? url_for(key).split("://").last : key
+ [ :views, (ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]), *head, *tail ].compact
+ end
+
# Writes +content+ to the location signified by
# +key+ (see +expire_fragment+ for acceptable formats).
def write_fragment(key, content, options = nil)
return content unless cache_configured?
- key = fragment_cache_key(key)
+ key = combined_fragment_cache_key(key)
instrument_fragment_cache :write_fragment, key do
content = content.to_str
cache_store.write(key, content, options)
@@ -85,7 +107,7 @@ module AbstractController
def read_fragment(key, options = nil)
return unless cache_configured?
- key = fragment_cache_key(key)
+ key = combined_fragment_cache_key(key)
instrument_fragment_cache :read_fragment, key do
result = cache_store.read(key, options)
result.respond_to?(:html_safe) ? result.html_safe : result
@@ -96,7 +118,7 @@ module AbstractController
# +key+ exists (see +expire_fragment+ for acceptable formats).
def fragment_exist?(key, options = nil)
return unless cache_configured?
- key = fragment_cache_key(key)
+ key = combined_fragment_cache_key(key)
instrument_fragment_cache :exist_fragment?, key do
cache_store.exist?(key, options)
@@ -123,7 +145,7 @@ module AbstractController
# method (or <tt>delete_matched</tt>, for Regexp keys).
def expire_fragment(key, options = nil)
return unless cache_configured?
- key = fragment_cache_key(key) unless key.is_a?(Regexp)
+ key = combined_fragment_cache_key(key) unless key.is_a?(Regexp)
instrument_fragment_cache :expire_fragment, key do
if key.is_a?(Regexp)
@@ -135,8 +157,7 @@ module AbstractController
end
def instrument_fragment_cache(name, key) # :nodoc:
- payload = instrument_payload(key)
- ActiveSupport::Notifications.instrument("#{name}.#{instrument_name}", payload) { yield }
+ ActiveSupport::Notifications.instrument("#{name}.#{instrument_name}", instrument_payload(key)) { yield }
end
end
end
diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb
index ce4ecf17cc..ba7dec6083 100644
--- a/actionpack/lib/abstract_controller/callbacks.rb
+++ b/actionpack/lib/abstract_controller/callbacks.rb
@@ -1,4 +1,24 @@
module AbstractController
+ # = Abstract Controller Callbacks
+ #
+ # Abstract Controller provides hooks during the life cycle of a controller action.
+ # Callbacks allow you to trigger logic during this cycle. Available callbacks are:
+ #
+ # * <tt>after_action</tt>
+ # * <tt>append_after_action</tt>
+ # * <tt>append_around_action</tt>
+ # * <tt>append_before_action</tt>
+ # * <tt>around_action</tt>
+ # * <tt>before_action</tt>
+ # * <tt>prepend_after_action</tt>
+ # * <tt>prepend_around_action</tt>
+ # * <tt>prepend_before_action</tt>
+ # * <tt>skip_after_action</tt>
+ # * <tt>skip_around_action</tt>
+ # * <tt>skip_before_action</tt>
+ #
+ # NOTE: Calling the same callback multiple times will overwrite previous callback definitions.
+ #
module Callbacks
extend ActiveSupport::Concern
diff --git a/actionpack/lib/action_controller/api.rb b/actionpack/lib/action_controller/api.rb
index 0d1af0d0bd..94698df730 100644
--- a/actionpack/lib/action_controller/api.rb
+++ b/actionpack/lib/action_controller/api.rb
@@ -141,6 +141,7 @@ module ActionController
include mod
end
+ ActiveSupport.run_load_hooks(:action_controller_api, self)
ActiveSupport.run_load_hooks(:action_controller, self)
end
end
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 0fe0853da3..8c2b111f89 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -261,6 +261,13 @@ module ActionController
PROTECTED_IVARS
end
+ def self.make_response!(request)
+ ActionDispatch::Response.create.tap do |res|
+ res.request = request
+ end
+ end
+
+ ActiveSupport.run_load_hooks(:action_controller_base, self)
ActiveSupport.run_load_hooks(:action_controller, self)
end
end
diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb
index d29a5fe68f..d00fcbcd13 100644
--- a/actionpack/lib/action_controller/log_subscriber.rb
+++ b/actionpack/lib/action_controller/log_subscriber.rb
@@ -60,9 +60,9 @@ module ActionController
class_eval <<-METHOD, __FILE__, __LINE__ + 1
def #{method}(event)
return unless logger.info? && ActionController::Base.enable_fragment_cache_logging
- key_or_path = event.payload[:key] || event.payload[:path]
+ key = ActiveSupport::Cache.expand_cache_key(event.payload[:key] || event.payload[:path])
human_name = #{method.to_s.humanize.inspect}
- info("\#{human_name} \#{key_or_path} (\#{event.duration.round(1)}ms)")
+ info("\#{human_name} \#{key} (\#{event.duration.round(1)}ms)")
end
METHOD
end
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index 74c4153cd2..246644dcbd 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -129,7 +129,7 @@ module ActionController
end
def self.make_response!(request)
- ActionDispatch::Response.create.tap do |res|
+ ActionDispatch::Response.new.tap do |res|
res.request = request
end
end
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index 7b4c7b923e..96bd548268 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -182,7 +182,7 @@ module ActionController #:nodoc:
# request.variant = [:tablet, :phone]
#
# This will work similarly to formats and MIME types negotiation. If there
- # is no +:tablet+ variant declared, +:phone+ variant will be picked:
+ # is no +:tablet+ variant declared, the +:phone+ variant will be used:
#
# respond_to do |format|
# format.html.none
diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb
index 3cca5e8906..a89fc1678b 100644
--- a/actionpack/lib/action_controller/metal/params_wrapper.rb
+++ b/actionpack/lib/action_controller/metal/params_wrapper.rb
@@ -105,7 +105,11 @@ module ActionController
unless super || exclude
if m.respond_to?(:attribute_names) && m.attribute_names.any?
- self.include = m.attribute_names
+ if m.respond_to?(:stored_attributes) && !m.stored_attributes.empty?
+ self.include = m.attribute_names + m.stored_attributes.values.flatten.map(&:to_s)
+ else
+ self.include = m.attribute_names
+ end
end
end
end
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index d9a8b9c12d..5051c02a62 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -213,7 +213,11 @@ module ActionController #:nodoc:
if !verified_request?
if logger && log_warning_on_csrf_failure
- logger.warn "Can't verify CSRF token authenticity."
+ if valid_request_origin?
+ logger.warn "Can't verify CSRF token authenticity."
+ else
+ logger.warn "HTTP Origin header (#{request.origin}) didn't match request.base_url (#{request.base_url})"
+ end
end
handle_unverified_request
end
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 1190e0ed69..20330b5091 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -43,6 +43,18 @@ module ActionController
end
end
+ # Raised when a Parameters instance is not marked as permitted and
+ # an operation to transform it to hash is called.
+ #
+ # params = ActionController::Parameters.new(a: "123", b: "456")
+ # params.to_h
+ # # => ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
+ class UnfilteredParameters < ArgumentError
+ def initialize # :nodoc:
+ super("unable to convert unpermitted parameters to hash")
+ end
+ end
+
# == Action Controller \Parameters
#
# Allows you to choose which attributes should be whitelisted for mass updating
@@ -53,9 +65,9 @@ module ActionController
#
# params = ActionController::Parameters.new({
# person: {
- # name: 'Francesco',
+ # name: "Francesco",
# age: 22,
- # role: 'admin'
+ # role: "admin"
# }
# })
#
@@ -103,7 +115,7 @@ module ActionController
# You can fetch values of <tt>ActionController::Parameters</tt> using either
# <tt>:key</tt> or <tt>"key"</tt>.
#
- # params = ActionController::Parameters.new(key: 'value')
+ # params = ActionController::Parameters.new(key: "value")
# params[:key] # => "value"
# params["key"] # => "value"
class Parameters
@@ -203,13 +215,13 @@ module ActionController
# class Person < ActiveRecord::Base
# end
#
- # params = ActionController::Parameters.new(name: 'Francesco')
+ # params = ActionController::Parameters.new(name: "Francesco")
# params.permitted? # => false
# Person.new(params) # => ActiveModel::ForbiddenAttributesError
#
# ActionController::Parameters.permit_all_parameters = true
#
- # params = ActionController::Parameters.new(name: 'Francesco')
+ # params = ActionController::Parameters.new(name: "Francesco")
# params.permitted? # => true
# Person.new(params) # => #<Person id: nil, name: "Francesco">
def initialize(parameters = {})
@@ -228,13 +240,14 @@ module ActionController
end
# Returns a safe <tt>ActiveSupport::HashWithIndifferentAccess</tt>
- # representation of this parameter with all unpermitted keys removed.
+ # representation of the parameters with all unpermitted keys removed.
#
# params = ActionController::Parameters.new({
- # name: 'Senjougahara Hitagi',
- # oddity: 'Heavy stone crab'
+ # name: "Senjougahara Hitagi",
+ # oddity: "Heavy stone crab"
# })
- # params.to_h # => {}
+ # params.to_h
+ # # => ActionController::UnfilteredParameters: unable to convert unfiltered parameters to hash
#
# safe_params = params.permit(:name)
# safe_params.to_h # => {"name"=>"Senjougahara Hitagi"}
@@ -242,17 +255,61 @@ module ActionController
if permitted?
convert_parameters_to_hashes(@parameters, :to_h)
else
- slice(*self.class.always_permitted_parameters).permit!.to_h
+ raise UnfilteredParameters
end
end
+ # Returns a safe <tt>Hash</tt> representation of the parameters
+ # with all unpermitted keys removed.
+ #
+ # params = ActionController::Parameters.new({
+ # name: "Senjougahara Hitagi",
+ # oddity: "Heavy stone crab"
+ # })
+ # params.to_hash
+ # # => ActionController::UnfilteredParameters: unable to convert unfiltered parameters to hash
+ #
+ # safe_params = params.permit(:name)
+ # safe_params.to_hash # => {"name"=>"Senjougahara Hitagi"}
+ def to_hash
+ to_h.to_hash
+ end
+
+ # Returns a string representation of the receiver suitable for use as a URL
+ # query string:
+ #
+ # params = ActionController::Parameters.new({
+ # name: "David",
+ # nationality: "Danish"
+ # })
+ # params.to_query
+ # # => "name=David&nationality=Danish"
+ #
+ # An optional namespace can be passed to enclose key names:
+ #
+ # params = ActionController::Parameters.new({
+ # name: "David",
+ # nationality: "Danish"
+ # })
+ # params.to_query("user")
+ # # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
+ #
+ # The string pairs "key=value" that conform the query string
+ # are sorted lexicographically in ascending order.
+ #
+ # This method is also aliased as +to_param+.
+ def to_query(*args)
+ to_h.to_query(*args)
+ end
+ alias_method :to_param, :to_query
+
# Returns an unsafe, unfiltered
- # <tt>ActiveSupport::HashWithIndifferentAccess</tt> representation of this
- # parameter.
+ # <tt>ActiveSupport::HashWithIndifferentAccess</tt> representation of the
+ # parameters.
#
# params = ActionController::Parameters.new({
- # name: 'Senjougahara Hitagi',
- # oddity: 'Heavy stone crab'
+ # name: "Senjougahara Hitagi",
+ # oddity: "Heavy stone crab"
# })
# params.to_unsafe_h
# # => {"name"=>"Senjougahara Hitagi", "oddity" => "Heavy stone crab"}
@@ -297,7 +354,7 @@ module ActionController
# class Person < ActiveRecord::Base
# end
#
- # params = ActionController::Parameters.new(name: 'Francesco')
+ # params = ActionController::Parameters.new(name: "Francesco")
# params.permitted? # => false
# Person.new(params) # => ActiveModel::ForbiddenAttributesError
# params.permit!
@@ -319,7 +376,7 @@ module ActionController
# When passed a single key, if it exists and its associated value is
# either present or the singleton +false+, returns said value:
#
- # ActionController::Parameters.new(person: { name: 'Francesco' }).require(:person)
+ # ActionController::Parameters.new(person: { name: "Francesco" }).require(:person)
# # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
#
# Otherwise raises <tt>ActionController::ParameterMissing</tt>:
@@ -352,7 +409,7 @@ module ActionController
# Technically this method can be used to fetch terminal values:
#
# # CAREFUL
- # params = ActionController::Parameters.new(person: { name: 'Finn' })
+ # params = ActionController::Parameters.new(person: { name: "Finn" })
# name = params.require(:person).require(:name) # CAREFUL
#
# but take into account that at some point those ones have to be permitted:
@@ -382,7 +439,7 @@ module ActionController
# for the object to +true+. This is useful for limiting which attributes
# should be allowed for mass updating.
#
- # params = ActionController::Parameters.new(user: { name: 'Francesco', age: 22, role: 'admin' })
+ # params = ActionController::Parameters.new(user: { name: "Francesco", age: 22, role: "admin" })
# permitted = params.require(:user).permit(:name, :age)
# permitted.permitted? # => true
# permitted.has_key?(:name) # => true
@@ -402,7 +459,7 @@ module ActionController
# You may declare that the parameter should be an array of permitted scalars
# by mapping it to an empty array:
#
- # params = ActionController::Parameters.new(tags: ['rails', 'parameters'])
+ # params = ActionController::Parameters.new(tags: ["rails", "parameters"])
# params.permit(tags: [])
#
# Sometimes it is not possible or convenient to declare the valid keys of
@@ -418,11 +475,11 @@ module ActionController
#
# params = ActionController::Parameters.new({
# person: {
- # name: 'Francesco',
+ # name: "Francesco",
# age: 22,
# pets: [{
- # name: 'Purplish',
- # category: 'dogs'
+ # name: "Purplish",
+ # category: "dogs"
# }]
# }
# })
@@ -441,8 +498,8 @@ module ActionController
# params = ActionController::Parameters.new({
# person: {
# contact: {
- # email: 'none@test.com',
- # phone: '555-1234'
+ # email: "none@test.com",
+ # phone: "555-1234"
# }
# }
# })
@@ -475,7 +532,7 @@ module ActionController
# Returns a parameter for the given +key+. If not found,
# returns +nil+.
#
- # params = ActionController::Parameters.new(person: { name: 'Francesco' })
+ # params = ActionController::Parameters.new(person: { name: "Francesco" })
# params[:person] # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
# params[:none] # => nil
def [](key)
@@ -494,11 +551,11 @@ module ActionController
# if more arguments are given, then that will be returned; if a block
# is given, then that will be run and its result returned.
#
- # params = ActionController::Parameters.new(person: { name: 'Francesco' })
+ # params = ActionController::Parameters.new(person: { name: "Francesco" })
# params.fetch(:person) # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
# params.fetch(:none) # => ActionController::ParameterMissing: param is missing or the value is empty: none
- # params.fetch(:none, 'Francesco') # => "Francesco"
- # params.fetch(:none) { 'Francesco' } # => "Francesco"
+ # params.fetch(:none, "Francesco") # => "Francesco"
+ # params.fetch(:none) { "Francesco" } # => "Francesco"
def fetch(key, *args)
convert_value_to_parameters(
@parameters.fetch(key) {
@@ -609,8 +666,8 @@ module ActionController
# to key. If the key is not found, returns the default value. If the
# optional code block is given and the key is not found, pass in the key
# and return the result of block.
- def delete(key)
- convert_value_to_parameters(@parameters.delete(key))
+ def delete(key, &block)
+ convert_value_to_parameters(@parameters.delete(key, &block))
end
# Returns a new instance of <tt>ActionController::Parameters</tt> with only
@@ -667,6 +724,7 @@ module ActionController
other_hash.to_h.merge(@parameters)
)
end
+ alias_method :with_defaults, :reverse_merge
# Returns current <tt>ActionController::Parameters</tt> instance with
# current hash merged into +other_hash+.
@@ -674,6 +732,7 @@ module ActionController
@parameters.merge!(other_hash.to_h) { |key, left, right| left }
self
end
+ alias_method :with_defaults!, :reverse_merge!
# This is required by ActiveModel attribute assignment, so that user can
# pass +Parameters+ to a mass assignment methods in a model. It should not
@@ -713,8 +772,6 @@ module ActionController
end
end
- undef_method :to_param
-
# Returns duplicate of object including all parameters.
def deep_dup
self.class.new(@parameters.deep_dup).tap do |duplicate|
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 72e29c2c9d..bc42d50205 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -534,7 +534,6 @@ module ActionController
@request.delete_header "HTTP_ACCEPT"
end
@request.query_string = ""
- @request.env.delete "PATH_INFO"
@response.sent!
end
diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
index c4fe3a5c09..19f89edbc1 100644
--- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb
+++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb
@@ -135,9 +135,7 @@ module ActionDispatch
}
end
- # Receives an array of mimes and return the first user sent mime that
- # matches the order array.
- #
+ # Returns the first MIME type that matches the provided array of MIME types.
def negotiate_mime(order)
formats.each do |priority|
if priority == Mime::ALL
diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index 1583a8f87f..74a3afab44 100644
--- a/actionpack/lib/action_dispatch/http/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -46,7 +46,7 @@ module Mime
end
end
- # Encapsulates the notion of a mime type. Can be used at render time, for example, with:
+ # Encapsulates the notion of a MIME type. Can be used at render time, for example, with:
#
# class PostsController < ActionController::Base
# def show
@@ -64,7 +64,7 @@ module Mime
@register_callbacks = []
- # A simple helper class used in parsing the accept header
+ # A simple helper class used in parsing the accept header.
class AcceptItem #:nodoc:
attr_accessor :index, :name, :q
alias :to_s :name
@@ -72,7 +72,7 @@ module Mime
def initialize(index, name, q = nil)
@index = index
@name = name
- q ||= 0.0 if @name == "*/*".freeze # default wildcard match to end of list
+ q ||= 0.0 if @name == "*/*".freeze # Default wildcard match to end of list.
@q = ((q || 1.0).to_f * 100).to_i
end
@@ -90,22 +90,22 @@ module Mime
text_xml_idx = find_item_by_name list, "text/xml"
app_xml_idx = find_item_by_name list, Mime[:xml].to_s
- # Take care of the broken text/xml entry by renaming or deleting it
+ # Take care of the broken text/xml entry by renaming or deleting it.
if text_xml_idx && app_xml_idx
app_xml = list[app_xml_idx]
text_xml = list[text_xml_idx]
- app_xml.q = [text_xml.q, app_xml.q].max # set the q value to the max of the two
- if app_xml_idx > text_xml_idx # make sure app_xml is ahead of text_xml in the list
+ app_xml.q = [text_xml.q, app_xml.q].max # Set the q value to the max of the two.
+ if app_xml_idx > text_xml_idx # Make sure app_xml is ahead of text_xml in the list.
list[app_xml_idx], list[text_xml_idx] = text_xml, app_xml
app_xml_idx, text_xml_idx = text_xml_idx, app_xml_idx
end
- list.delete_at(text_xml_idx) # delete text_xml from the list
+ list.delete_at(text_xml_idx) # Delete text_xml from the list.
elsif text_xml_idx
list[text_xml_idx].name = Mime[:xml].to_s
end
- # Look for more specific XML-based types and sort them ahead of app/xml
+ # Look for more specific XML-based types and sort them ahead of app/xml.
if app_xml_idx
app_xml = list[app_xml_idx]
idx = app_xml_idx
@@ -147,7 +147,7 @@ module Mime
EXTENSION_LOOKUP[extension.to_s]
end
- # Registers an alias that's not used on mime type lookup, but can be referenced directly. Especially useful for
+ # Registers an alias that's not used on MIME type lookup, but can be referenced directly. Especially useful for
# rendering different HTML versions depending on the user agent, like an iPhone.
def register_alias(string, symbol, extension_synonyms = [])
register(string, symbol, [], extension_synonyms, true)
@@ -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/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index 8f21eca440..7c585dbe68 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -13,7 +13,7 @@ module ActionDispatch
}
# Raised when raw data from the request cannot be parsed by the parser
- # defined for request's content mime type.
+ # defined for request's content MIME type.
class ParseError < StandardError
def initialize
super($!.message)
@@ -30,9 +30,9 @@ module ActionDispatch
end
module ClassMethods
- # Configure the parameter parser for a given mime type.
+ # Configure the parameter parser for a given MIME type.
#
- # It accepts a hash where the key is the symbol of the mime type
+ # It accepts a hash where the key is the symbol of the MIME type
# and the value is a proc.
#
# original_parsers = ActionDispatch::Request.parameter_parsers
@@ -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?
@@ -100,7 +106,7 @@ module ActionDispatch
begin
strategy.call(raw_post)
- rescue # JSON or Ruby code block errors
+ rescue # JSON or Ruby code block errors.
my_logger = logger || ActiveSupport::Logger.new($stderr)
my_logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{raw_post}"
@@ -115,6 +121,7 @@ module ActionDispatch
end
module ParamsParser
- ParseError = ActiveSupport::Deprecation::DeprecatedConstantProxy.new("ActionDispatch::ParamsParser::ParseError", "ActionDispatch::Http::Parameters::ParseError")
+ include ActiveSupport::Deprecation::DeprecatedConstantAccessor
+ deprecate_constant "ParseError", "ActionDispatch::Http::Parameters::ParseError"
end
end
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 19fa42ce12..6d42404a98 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -114,7 +114,7 @@ module ActionDispatch
HTTP_METHOD_LOOKUP = {}
- # Populate the HTTP method lookup cache
+ # Populate the HTTP method lookup cache.
HTTP_METHODS.each { |method|
HTTP_METHOD_LOOKUP[method] = method.underscore.to_sym
}
@@ -165,12 +165,12 @@ module ActionDispatch
def show_exceptions? # :nodoc:
# We're treating `nil` as "unset", and we want the default setting to be
- # `true`. This logic should be extracted to `env_config` and calculated
+ # `true`. This logic should be extracted to `env_config` and calculated
# once.
!(get_header("action_dispatch.show_exceptions".freeze) == false)
end
- # Returns a symbol form of the #request_method
+ # Returns a symbol form of the #request_method.
def request_method_symbol
HTTP_METHOD_LOOKUP[request_method]
end
@@ -182,7 +182,7 @@ module ActionDispatch
@method ||= check_method(get_header("rack.methodoverride.original_method") || get_header("REQUEST_METHOD"))
end
- # Returns a symbol form of the #method
+ # Returns a symbol form of the #method.
def method_symbol
HTTP_METHOD_LOOKUP[method]
end
@@ -267,7 +267,7 @@ module ActionDispatch
# (which sets the action_dispatch.request_id environment variable).
#
# This unique ID is useful for tracing a request from end-to-end as part of logging or debugging.
- # This relies on the rack variable set by the ActionDispatch::RequestId middleware.
+ # This relies on the Rack variable set by the ActionDispatch::RequestId middleware.
def request_id
get_header ACTION_DISPATCH_REQUEST_ID
end
@@ -339,7 +339,7 @@ module ActionDispatch
Session::Options.set self, options
end
- # Override Rack's GET method to support indifferent access
+ # Override Rack's GET method to support indifferent access.
def GET
fetch_header("action_dispatch.request.query_parameters") do |k|
rack_query_params = super || {}
@@ -352,7 +352,7 @@ module ActionDispatch
end
alias :query_parameters :GET
- # Override Rack's POST method to support indifferent access
+ # Override Rack's POST method to support indifferent access.
def POST
fetch_header("action_dispatch.request.request_parameters") do
pr = parse_formatted_parameters(params_parsers) do |params|
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index dc159596c4..2ee52eeb48 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -85,7 +85,7 @@ module ActionDispatch # :nodoc:
cattr_accessor(:default_headers)
include Rack::Response::Helpers
- # Aliasing these off because AD::Http::Cache::Response defines them
+ # Aliasing these off because AD::Http::Cache::Response defines them.
alias :_cache_control :cache_control
alias :_cache_control= :cache_control=
@@ -142,7 +142,7 @@ module ActionDispatch # :nodoc:
private
def each_chunk(&block)
- @buf.each(&block) # extract into own method
+ @buf.each(&block)
end
end
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 a6937d54ff..b6be48a48b 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -101,10 +101,8 @@ module ActionDispatch
end
def add_trailing_slash(path)
- # includes querysting
if path.include?("?")
path.sub!(/\?/, '/\&')
- # does not have a .format
elsif !path.include?(".")
path.sub!(/[^\/]\z|\A\z/, '\&/')
end
diff --git a/actionpack/lib/action_dispatch/journey/formatter.rb b/actionpack/lib/action_dispatch/journey/formatter.rb
index f3b8e82d32..326f4e52f9 100644
--- a/actionpack/lib/action_dispatch/journey/formatter.rb
+++ b/actionpack/lib/action_dispatch/journey/formatter.rb
@@ -15,7 +15,7 @@ module ActionDispatch
def generate(name, options, path_parameters, parameterize = nil)
constraints = path_parameters.merge(options)
- missing_keys = nil # need for variable scope
+ missing_keys = nil
match_route(name, constraints) do |route|
parameterized_parts = extract_parameterized_parts(route, options, path_parameters, parameterize)
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 beb9f1ef3b..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")
@@ -109,7 +109,6 @@ module ActionDispatch
svg = to_svg
javascripts = [states, fsm_js]
- # Annoying hack warnings
fun_routes = fun_routes
stylesheets = stylesheets
svg = svg
diff --git a/actionpack/lib/action_dispatch/journey/route.rb b/actionpack/lib/action_dispatch/journey/route.rb
index 927fd369c4..7bc15aa6b3 100644
--- a/actionpack/lib/action_dispatch/journey/route.rb
+++ b/actionpack/lib/action_dispatch/journey/route.rb
@@ -89,8 +89,15 @@ module ActionDispatch
end
end
+ # Needed for `rails routes`. Picks up succinctly defined requirements
+ # for a route, for example route
+ #
+ # get 'photo/:id', :controller => 'photos', :action => 'show',
+ # :id => /[A-Z]\d{5}/
+ #
+ # will have {:controller=>"photos", :action=>"show", :id=>/[A-Z]\d{5}/}
+ # as requirements.
def requirements
- # needed for rails `rails routes`
@defaults.merge(path.requirements).delete_if { |_, v|
/.+?/ == v
}
diff --git a/actionpack/lib/action_dispatch/journey/router/utils.rb b/actionpack/lib/action_dispatch/journey/router/utils.rb
index d641642338..6d400f3364 100644
--- a/actionpack/lib/action_dispatch/journey/router/utils.rb
+++ b/actionpack/lib/action_dispatch/journey/router/utils.rb
@@ -5,7 +5,7 @@ module ActionDispatch
# Normalizes URI path.
#
# Strips off trailing slash and ensures there is a leading slash.
- # Also converts downcase url encoded string to uppercase.
+ # Also converts downcase URL encoded string to uppercase.
#
# normalize_path("/foo") # => "/foo"
# normalize_path("/foo/") # => "/foo"
@@ -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/journey/visitors.rb b/actionpack/lib/action_dispatch/journey/visitors.rb
index 1c50192867..335797f4b9 100644
--- a/actionpack/lib/action_dispatch/journey/visitors.rb
+++ b/actionpack/lib/action_dispatch/journey/visitors.rb
@@ -154,7 +154,7 @@ module ActionDispatch
end
end
- # Loop through the requirements AST
+ # Loop through the requirements AST.
class Each < FunctionalVisitor # :nodoc:
def visit(node, block)
block.call(node)
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index c61cb3fd68..c0dda1bba5 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
@@ -160,7 +165,7 @@ module ActionDispatch
# Raised when storing more than 4K of session data.
CookieOverflow = Class.new StandardError
- # Include in a cookie jar to allow chaining, e.g. cookies.permanent.signed
+ # Include in a cookie jar to allow chaining, e.g. cookies.permanent.signed.
module ChainedCookieJars
# Returns a jar that'll automatically set the assigned cookies to have an expiration date 20 years from now. Example:
#
@@ -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
@@ -345,16 +362,16 @@ module ActionDispatch
options[:path] ||= "/"
if options[:domain] == :all || options[:domain] == "all"
- # if there is a provided tld length then we use it otherwise default domain regexp
+ # If there is a provided tld length then we use it otherwise default domain regexp.
domain_regexp = options[:tld_length] ? /([^.]+\.?){#{options[:tld_length]}}$/ : DOMAIN_REGEXP
- # if host is not ip and matches domain regexp
+ # If host is not ip and matches domain regexp.
# (ip confirms to domain regexp so we explicitly check for ip)
options[:domain] = if (request.host !~ /^[\d.]+$/) && (request.host =~ domain_regexp)
".#{$&}"
end
elsif options[:domain].is_a? Array
- # if host matches one of the supplied domains without a dot in front of it
+ # If host matches one of the supplied domains without a dot in front of it.
options[:domain] = options[:domain].find { |domain| request.host.include? domain.sub(/^\./, "") }
end
end
@@ -404,7 +421,7 @@ module ActionDispatch
@delete_cookies[name.to_s] == options
end
- # Removes all cookies on the client machine by calling <tt>delete</tt> for each cookie
+ # Removes all cookies on the client machine by calling <tt>delete</tt> for each cookie.
def clear(options = {})
@cookies.each_key { |k| delete(k, options) }
end
@@ -576,9 +593,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 +622,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, 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/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index cbe2f4be4d..6b29ce63ba 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -65,7 +65,7 @@ module ActionDispatch
self.flash = flash_hash.dup
end
- if (!session.respond_to?(:loaded?) || session.loaded?) && # (reset_session uses {}, which doesn't implement #loaded?)
+ if (!session.respond_to?(:loaded?) || session.loaded?) && # reset_session uses {}, which doesn't implement #loaded?
session.key?("flash") && session["flash"].nil?
session.delete("flash")
end
diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
index 8bae5bfeff..53d5a4918c 100644
--- a/actionpack/lib/action_dispatch/middleware/remote_ip.rb
+++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
@@ -157,13 +157,13 @@ module ActionDispatch
def ips_from(header) # :doc:
return [] unless header
- # Split the comma-separated list into an array of strings
+ # Split the comma-separated list into an array of strings.
ips = header.strip.split(/[,\s]+/)
ips.select do |ip|
begin
- # Only return IPs that are valid according to the IPAddr#new method
+ # Only return IPs that are valid according to the IPAddr#new method.
range = IPAddr.new(ip).to_range
- # we want to make sure nobody is sneaking a netmask in
+ # We want to make sure nobody is sneaking a netmask in.
range.begin == range.end
rescue ArgumentError
nil
diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index d9f018c8ac..21ccf5a097 100644
--- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -53,7 +53,7 @@ module ActionDispatch
rescue ArgumentError => argument_error
if argument_error.message =~ %r{undefined class/module ([\w:]*\w)}
begin
- # Note that the regexp does not allow $1 to end with a ':'
+ # Note that the regexp does not allow $1 to end with a ':'.
$1.constantize
rescue LoadError, NameError
raise ActionDispatch::Session::SessionRestoreError
diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
index 90f26a1c33..5a99714ec2 100644
--- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
@@ -8,7 +8,7 @@ module ActionDispatch
# The exceptions app should be passed as parameter on initialization
# of ShowExceptions. Every time there is an exception, ShowExceptions will
# store the exception in env["action_dispatch.exception"], rewrite the
- # PATH_INFO to the exception status code and call the rack app.
+ # PATH_INFO to the exception status code and call the Rack app.
#
# If the application returns a "X-Cascade" pass response, this middleware
# will send an empty response as result with the correct status code.
diff --git a/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb b/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb
index 429ea7057c..2d21ae63f5 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/routes/_table.html.erb
@@ -60,7 +60,7 @@
<%= link_to "Path", "#", 'data-route-helper' => '_path',
title: "Returns a relative path (without the http or domain)" %> /
<%= link_to "Url", "#", 'data-route-helper' => '_url',
- title: "Returns an absolute url (with the http and domain)" %>
+ title: "Returns an absolute URL (with the http and domain)" %>
</th>
<th><%# HTTP Verb %>
</th>
@@ -93,7 +93,7 @@
}
}
- // get JSON from url and invoke callback with result
+ // get JSON from URL and invoke callback with result
function getJSON(url, success) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
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 a2a80f39fc..3547a8604f 100644
--- a/actionpack/lib/action_dispatch/request/session.rb
+++ b/actionpack/lib/action_dispatch/request/session.rb
@@ -7,10 +7,10 @@ module ActionDispatch
ENV_SESSION_KEY = Rack::RACK_SESSION # :nodoc:
ENV_SESSION_OPTIONS_KEY = Rack::RACK_SESSION_OPTIONS # :nodoc:
- # Singleton object used to determine if an optional param wasn't specified
+ # Singleton object used to determine if an optional param wasn't specified.
Unspecified = Object.new
- # Creates a session hash, merging the properties of the previous session if any
+ # Creates a session hash, merging the properties of the previous session if any.
def self.create(store, req, default_options)
session_was = find req
session = Request::Session.new(store, req)
@@ -63,7 +63,7 @@ module ActionDispatch
@req = req
@delegate = {}
@loaded = false
- @exists = nil # we haven't checked yet
+ @exists = nil # We haven't checked yet.
end
def id
@@ -79,7 +79,7 @@ module ActionDispatch
options = self.options || {}
@by.send(:delete_session, @req, options.id(@req), options)
- # Load the new sid to be written with the response
+ # Load the new sid to be written with the response.
@loaded = false
load_for_write!
end
@@ -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 01bc871e5f..3615e4b1d8 100644
--- a/actionpack/lib/action_dispatch/request/utils.rb
+++ b/actionpack/lib/action_dispatch/request/utils.rb
@@ -40,7 +40,6 @@ module ActionDispatch
class ParamEncoder # :nodoc:
# Convert nested Hash to HashWithIndifferentAccess.
- #
def self.normalize_encode_params(params)
case params
when Array
@@ -63,7 +62,7 @@ module ActionDispatch
end
end
- # Remove nils from the params hash
+ # Remove nils from the params hash.
class NoNilParamEncoder < ParamEncoder # :nodoc:
def self.handle_array(params)
list = super
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index c554ce98bc..87dd1eba38 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -120,7 +120,7 @@ module ActionDispatch
# controller :blog do
# get 'blog/show' => :list
# get 'blog/delete' => :delete
- # get 'blog/edit' => :edit
+ # get 'blog/edit' => :edit
# end
#
# # provides named routes for show, delete, and edit
@@ -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/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb
index b91ffb8419..9aa4b92df2 100644
--- a/actionpack/lib/action_dispatch/routing/inspector.rb
+++ b/actionpack/lib/action_dispatch/routing/inspector.rb
@@ -196,7 +196,7 @@ module ActionDispatch
@buffer << @view.render(partial: "routes/route", collection: routes)
end
- # the header is part of the HTML page, so we don't construct it here.
+ # The header is part of the HTML page, so we don't construct it here.
def header(routes)
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index dea6c4482e..74904e3d45 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -17,9 +17,9 @@ module ActionDispatch
CALL = ->(app, req) { app.call req.env }
def initialize(app, constraints, strategy)
- # Unwrap Constraints objects. I don't actually think it's possible
+ # Unwrap Constraints objects. I don't actually think it's possible
# to pass a Constraints object to this constructor, but there were
- # multiple places that kept testing children of this object. I
+ # multiple places that kept testing children of this object. I
# *think* they were just being defensive, but I have no idea.
if app.is_a?(self.class)
constraints += app.constraints
@@ -54,6 +54,7 @@ module ActionDispatch
class Mapping #:nodoc:
ANCHOR_CHARACTERS_REGEX = %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
+ OPTIONAL_FORMAT_REGEX = %r{(?:\(\.:format\)+|\.:format|/)\Z}
attr_reader :requirements, :defaults
attr_reader :to, :default_controller, :default_action
@@ -93,7 +94,7 @@ module ActionDispatch
end
def self.optional_format?(path, format)
- format != false && !path.include?(":format") && !path.end_with?("/")
+ format != false && path !~ OPTIONAL_FORMAT_REGEX
end
def initialize(set, ast, defaults, controller, default_action, modyoule, to, formatted, scope_constraints, blocks, via, options_constraints, anchor, options)
@@ -218,7 +219,7 @@ module ActionDispatch
private
def add_wildcard_options(options, formatted, path_ast)
# Add a constraint for wildcard route to make it non-greedy and match the
- # optional format part of the route by default
+ # optional format part of the route by default.
if formatted != false
path_ast.grep(Journey::Nodes::Star).each_with_object({}) { |node, hash|
hash[node.name.to_sym] ||= /.+?/
@@ -396,7 +397,7 @@ module ActionDispatch
end
module Base
- # Matches a url pattern to one or more routes.
+ # Matches a URL pattern to one or more routes.
#
# You should not use the +match+ method in your router
# without specifying an HTTP method.
@@ -406,7 +407,7 @@ module ActionDispatch
# # sets :controller, :action and :id in params
# match ':controller/:action/:id', via: [:get, :post]
#
- # Note that +:controller+, +:action+ and +:id+ are interpreted as url
+ # Note that +:controller+, +:action+ and +:id+ are interpreted as URL
# query parameters and thus available through +params+ in an action.
#
# If you want to expose your action to GET, use +get+ in the router:
@@ -455,7 +456,7 @@ module ActionDispatch
#
# === Options
#
- # Any options not seen here are passed on as params with the url.
+ # Any options not seen here are passed on as params with the URL.
#
# [:controller]
# The route's controller.
@@ -660,7 +661,7 @@ module ActionDispatch
else
prefix_options = options.slice(*_route.segment_keys)
prefix_options[:relative_url_root] = "".freeze
- # we must actually delete prefix segment keys to avoid passing them to next url_for
+ # We must actually delete prefix segment keys to avoid passing them to next url_for.
_route.segment_keys.each { |k| options.delete(k) }
_routes.url_helpers.send("#{name}_path", prefix_options)
end
@@ -1238,7 +1239,7 @@ module ActionDispatch
#
# resource :profile
#
- # creates six different routes in your application, all mapping to
+ # This creates six different routes in your application, all mapping to
# the +Profiles+ controller (note that the controller is named after
# the plural):
#
@@ -1323,14 +1324,14 @@ module ActionDispatch
#
# resources :posts, path_names: { new: "brand_new" }
#
- # The above example will now change /posts/new to /posts/brand_new
+ # The above example will now change /posts/new to /posts/brand_new.
#
# [:path]
# Allows you to change the path prefix for the resource.
#
# resources :posts, path: 'postings'
#
- # The resource and all segments will now route to /postings instead of /posts
+ # The resource and all segments will now route to /postings instead of /posts.
#
# [:only]
# Only generate routes for the given actions.
@@ -1525,7 +1526,7 @@ module ActionDispatch
end
end
- # See ActionDispatch::Routing::Mapper::Scoping#namespace
+ # See ActionDispatch::Routing::Mapper::Scoping#namespace.
def namespace(path, options = {})
if resource_scope?
nested { super }
@@ -1545,7 +1546,7 @@ module ActionDispatch
!parent_resource.singleton? && @scope[:shallow]
end
- # Matches a url pattern to one or more routes.
+ # Matches a URL pattern to one or more routes.
# For more information, see match[rdoc-ref:Base#match].
#
# match 'path' => 'controller#action', via: patch
@@ -2003,7 +2004,7 @@ module ActionDispatch
# concerns :commentable
# end
#
- # concerns also work in any routes helper that you want to use:
+ # Concerns also work in any routes helper that you want to use:
#
# namespace :posts do
# concerns :commentable
@@ -2038,33 +2039,33 @@ module ActionDispatch
# 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
+ # 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
+ # * A string, which is treated as a generated URL
# * A hash, e.g. { controller: "pages", action: "index" }
# * An array, which is passed to `polymorphic_url`
# * An Active Model instance
# * An Active Model class
#
- # NOTE: Other url helpers can be called in the block but be careful not to invoke
- # your custom url helper again otherwise it will result in a stack overflow error
+ # NOTE: Other URL helpers can be called in the block but be careful not to invoke
+ # your custom URL helper again otherwise it will result in a stack overflow error.
#
# You can also specify default options that will be passed through to
- # your url helper definition, e.g:
+ # your URL helper definition, e.g:
#
# direct :browse, page: 1, size: 10 do |options|
# [ :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
- # block is executed, e.g. generating a url inside a controller action or a view.
+ # 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
- # context in which you will use your custom url helper when defining it.
+ # 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.
@@ -2076,7 +2077,7 @@ module ActionDispatch
@set.add_url_helper(name, options, &block)
end
- # Define custom polymorphic mappings of models to urls. This alters the
+ # 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:
#
@@ -2089,7 +2090,7 @@ module ActionDispatch
# 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
+ # NOTE: This custom behavior only applies to simple polymorphic URLs where
# a single model instance is passed and not more complicated forms, e.g:
#
# # config/routes.rb
@@ -2105,7 +2106,7 @@ module ActionDispatch
# link_to "Profile", [:admin, @current_user]
#
# The first `link_to` will generate "/profile" but the second will generate
- # the standard polymorphic url of "/admin/users/1".
+ # the standard polymorphic URL of "/admin/users/1".
#
# You can pass options to a polymorphic mapping - the arity for the block
# needs to be two as the instance is passed as the first argument, e.g:
@@ -2114,9 +2115,9 @@ module ActionDispatch
# [:basket, options]
# end
#
- # This generates the url "/basket#items" because when the last item in an
+ # 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
- # to the url helper that gets called.
+ # 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.
diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
index 984ded1ff5..e89ea8b21d 100644
--- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
+++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
@@ -40,7 +40,7 @@ module ActionDispatch
#
# Example usage:
#
- # edit_polymorphic_path(@post) # => "/posts/1/edit"
+ # edit_polymorphic_path(@post) # => "/posts/1/edit"
# polymorphic_path(@post, format: :pdf) # => "/posts/1.pdf"
#
# == Usage with mounted engines
@@ -104,7 +104,7 @@ module ActionDispatch
end
if mapping = polymorphic_mapping(record_or_hash_or_array)
- return mapping.call(self, [record_or_hash_or_array, options])
+ return mapping.call(self, [record_or_hash_or_array, options], false)
end
opts = options.dup
@@ -128,7 +128,7 @@ module ActionDispatch
end
if mapping = polymorphic_mapping(record_or_hash_or_array)
- return mapping.call(self, [record_or_hash_or_array, options], only_path: true)
+ return mapping.call(self, [record_or_hash_or_array, options], true)
end
opts = options.dup
@@ -273,7 +273,7 @@ module ActionDispatch
def handle_model_call(target, record)
if mapping = polymorphic_mapping(target, record)
- mapping.call(target, [record], only_path: suffix == "path")
+ mapping.call(target, [record], suffix == "path")
else
method, args = handle_model(record)
target.send(method, *args)
diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb
index e8f47b8640..3bcb341758 100644
--- a/actionpack/lib/action_dispatch/routing/redirection.rb
+++ b/actionpack/lib/action_dispatch/routing/redirection.rb
@@ -146,7 +146,7 @@ module ActionDispatch
#
# get 'docs/:article', to: redirect('/wiki/%{article}')
#
- # Note that if you return a path without a leading slash then the url is prefixed with the
+ # Note that if you return a path without a leading slash then the URL is prefixed with the
# current SCRIPT_NAME environment variable. This is typically '/' but may be different in
# a mounted engine or where the application is deployed to a subdirectory of a website.
#
@@ -165,7 +165,7 @@ module ActionDispatch
# Note that the +do end+ syntax for the redirect block wouldn't work, as Ruby would pass
# the block to +get+ instead of +redirect+. Use <tt>{ ... }</tt> instead.
#
- # The options version of redirect allows you to supply only the parts of the url which need
+ # The options version of redirect allows you to supply only the parts of the URL which need
# to change, it also supports interpolation of the path similar to the first example.
#
# get 'stores/:name', to: redirect(subdomain: 'stores', path: '/%{name}')
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 118dec2ad4..e1f9fc9ecc 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -164,13 +164,13 @@ module ActionDispatch
@path_helpers_module.module_eval do
define_method(:"#{name}_path") do |*args|
- helper.call(self, args, only_path: true)
+ helper.call(self, args, true)
end
end
@url_helpers_module.module_eval do
define_method(:"#{name}_url") do |*args|
- helper.call(self, args)
+ helper.call(self, args, false)
end
end
end
@@ -295,7 +295,7 @@ module ActionDispatch
end
private
- # Create a url helper allowing ordered parameters to be associated
+ # Create a URL helper allowing ordered parameters to be associated
# with corresponding dynamic segments, so you can do:
#
# foo_url(bar, baz, bang)
@@ -318,11 +318,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
@@ -509,6 +505,14 @@ module ActionDispatch
@_proxy.url_for(options)
end
+ def full_url_for(options)
+ @_proxy.full_url_for(options)
+ end
+
+ def route_for(name, *args)
+ @_proxy.route_for(name, *args)
+ end
+
def optimize_routes_generation?
@_proxy.optimize_routes_generation?
end
@@ -613,26 +617,14 @@ module ActionDispatch
@block = block
end
- def call(t, args, outer_options = {})
+ def call(t, args, only_path = false)
options = args.extract_options!
- url_options = eval_block(t, args, options)
-
- case url_options
- when String
- t.url_for(url_options)
- when Hash
- t.url_for(url_options.merge(outer_options))
- when ActionController::Parameters
- if url_options.permitted?
- t.url_for(url_options.to_h.merge(outer_options))
- else
- raise ArgumentError, "Generating a URL from non sanitized request parameters is insecure!"
- end
- when Array
- opts = url_options.extract_options!
- t.url_for(url_options.push(opts.merge(outer_options)))
+ url = t.full_url_for(eval_block(t, args, options))
+
+ if only_path
+ "/" + url.partition(%r{(?<!/)/(?!/)}).last
else
- t.url_for([url_options, outer_options])
+ url
end
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 3e564f13d8..a9bdefa775 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -113,10 +113,10 @@ module ActionDispatch
default_url_options
end
- # Generate a url based on the options provided, default_url_options and the
+ # Generate a URL based on the options provided, default_url_options and the
# routes defined in routes.rb. The following options are supported:
#
- # * <tt>:only_path</tt> - If true, the relative url is returned. Defaults to +false+.
+ # * <tt>:only_path</tt> - If true, the relative URL is returned. Defaults to +false+.
# * <tt>:protocol</tt> - The protocol to connect to. Defaults to 'http'.
# * <tt>:host</tt> - Specifies the host the link should be targeted at.
# If <tt>:only_path</tt> is false, this option must be
@@ -164,20 +164,17 @@ module ActionDispatch
# implicitly used by +url_for+ can always be overwritten like shown on the
# last +url_for+ calls.
def url_for(options = nil)
+ full_url_for(options)
+ end
+
+ def full_url_for(options = nil) # :nodoc:
case options
when nil
_routes.url_for(url_options.symbolize_keys)
- when Hash
- 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
+ when Hash, ActionController::Parameters
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
@@ -192,6 +189,10 @@ module ActionDispatch
end
end
+ def route_for(name, *args) # :nodoc:
+ public_send(:"#{name}_url", *args)
+ end
+
protected
def optimize_routes_generation?
diff --git a/actionpack/lib/action_dispatch/system_test_case.rb b/actionpack/lib/action_dispatch/system_test_case.rb
index 1bf47d2556..98fdb36c91 100644
--- a/actionpack/lib/action_dispatch/system_test_case.rb
+++ b/actionpack/lib/action_dispatch/system_test_case.rb
@@ -1,4 +1,5 @@
require "capybara/dsl"
+require "capybara/minitest"
require "action_controller"
require "action_dispatch/system_testing/driver"
require "action_dispatch/system_testing/server"
@@ -48,7 +49,7 @@ module ActionDispatch
# By default, <tt>ActionDispatch::SystemTestCase</tt> is driven by the
# Selenium driver, with the Chrome browser, and a browser size of 1400x1400.
#
- # Changing the driver configuration options are easy. Let's say you want to use
+ # Changing the driver configuration options is easy. Let's say you want to use
# the Firefox browser instead of Chrome. In your +application_system_test_case.rb+
# file add the following:
#
@@ -80,12 +81,13 @@ module ActionDispatch
# tests as long as you include the required gems and files.
class SystemTestCase < IntegrationTest
include Capybara::DSL
+ include Capybara::Minitest::Assertions
include SystemTesting::TestHelpers::SetupAndTeardown
include SystemTesting::TestHelpers::ScreenshotHelper
def initialize(*) # :nodoc:
super
- self.class.superclass.driver.use
+ self.class.driver.use
end
def self.start_application # :nodoc:
@@ -98,6 +100,8 @@ module ActionDispatch
SystemTesting::Server.new.run
end
+ class_attribute :driver, instance_accessor: false
+
# System Test configuration options
#
# The default settings are Selenium, using Chrome, with a screen size
@@ -110,14 +114,11 @@ module ActionDispatch
# driven_by :selenium, using: :firefox
#
# driven_by :selenium, screen_size: [800, 800]
- def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400])
- @driver = SystemTesting::Driver.new(driver, using: using, screen_size: screen_size)
+ def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {})
+ self.driver = SystemTesting::Driver.new(driver, using: using, screen_size: screen_size, options: options)
end
- # Returns the driver object for the initialized system test
- def self.driver
- @driver ||= SystemTestCase.driven_by(:selenium)
- end
+ driven_by :selenium
end
SystemTestCase.start_application
diff --git a/actionpack/lib/action_dispatch/system_testing/driver.rb b/actionpack/lib/action_dispatch/system_testing/driver.rb
index 72d132d64f..5cf17883f7 100644
--- a/actionpack/lib/action_dispatch/system_testing/driver.rb
+++ b/actionpack/lib/action_dispatch/system_testing/driver.rb
@@ -5,6 +5,7 @@ module ActionDispatch
@name = name
@browser = options[:using]
@screen_size = options[:screen_size]
+ @options = options[:options]
end
def use
@@ -19,7 +20,7 @@ module ActionDispatch
def register
Capybara.register_driver @name do |app|
- Capybara::Selenium::Driver.new(app, browser: @browser).tap do |driver|
+ 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
diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb
index 3078e035a3..859d68e475 100644
--- a/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb
+++ b/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb
@@ -1,7 +1,7 @@
module ActionDispatch
module SystemTesting
module TestHelpers
- # Screenshot helper for system testing
+ # Screenshot helper for system testing.
module ScreenshotHelper
# Takes a screenshot of the current page in the browser.
#
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/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb
index 817737341c..1baf979ac9 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/response.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb
@@ -45,7 +45,7 @@ module ActionDispatch
# # Asserts that the redirection was to the named route login_url
# assert_redirected_to login_url
#
- # # Asserts that the redirection was to the url for @customer
+ # # Asserts that the redirection was to the URL for @customer
# assert_redirected_to @customer
#
# # Asserts that the redirection matches the regular expression
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index 37c1ca02b6..8645df4370 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -18,8 +18,8 @@ module ActionDispatch
# assert_recognizes({controller: 'items', action: 'create'}, {path: 'items', method: :post})
#
# You can also pass in +extras+ with a hash containing URL parameters that would normally be in the query string. This can be used
- # to assert that values in the query string will end up in the params hash correctly. To test query strings you must use the
- # extras argument, appending the query string on the path directly will not work. For example:
+ # to assert that values in the query string will end up in the params hash correctly. To test query strings you must use the extras
+ # argument because appending the query string on the path directly will not work. For example:
#
# # Asserts that a path of '/items/list/1?view=print' returns the correct options
# assert_recognizes({controller: 'items', action: 'list', id: '1', view: 'print'}, 'items/list/1', { view: "print" })
@@ -132,8 +132,7 @@ module ActionDispatch
end
# A helper to make it easier to test different route configurations.
- # This method temporarily replaces @routes
- # with a new RouteSet instance.
+ # This method temporarily replaces @routes with a new RouteSet instance.
#
# The new instance is yielded to the passed block. Typically the block
# will create some routes using <tt>set.draw { match ... }</tt>:
@@ -186,7 +185,6 @@ module ActionDispatch
method = :get
end
- # Assume given controller
request = ActionController::TestRequest.create @controller.class
if path =~ %r{://}
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index a3430e210e..2416c58817 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -192,11 +192,10 @@ module ActionDispatch
# HTTP methods in integration tests. +#process+ is only required when using a
# request method that doesn't have a method defined in the integration tests.
#
- # This method returns a Response object, which one can use to
- # inspect the details of the response. Furthermore, if this method was
- # called from an ActionDispatch::IntegrationTest object, then that
- # object's <tt>@response</tt> instance variable will point to the same
- # response object.
+ # This method returns the response status, after performing the request.
+ # Furthermore, if this method was called from an ActionDispatch::IntegrationTest object,
+ # then that object's <tt>@response</tt> instance variable will point to a Response object
+ # which one can use to inspect the details of the response.
#
# Example:
# process :get, '/author', params: { since: 201501011400 }
@@ -247,7 +246,7 @@ module ActionDispatch
wrapped_headers["HTTP_ACCEPT"] ||= [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ")
end
- # this modifies the passed request_env directly
+ # This modifies the passed request_env directly.
if wrapped_headers.present?
Http::Headers.from_hash(request_env).merge!(wrapped_headers)
end
@@ -258,7 +257,7 @@ module ActionDispatch
session = Rack::Test::Session.new(_mock_session)
# NOTE: rack-test v0.5 doesn't build a default uri correctly
- # Make sure requested path is always a full uri
+ # Make sure requested path is always a full URI.
session.request(build_full_uri(path, request_env), request_env)
@request_count += 1
@@ -325,8 +324,8 @@ module ActionDispatch
def create_session(app)
klass = APP_SESSIONS[app] ||= Class.new(Integration::Session) {
- # If the app is a Rails app, make url_helpers available on the session
- # This makes app.url_for and app.foo_path available in the console
+ # If the app is a Rails app, make url_helpers available on the session.
+ # This makes app.url_for and app.foo_path available in the console.
if app.respond_to?(:routes)
include app.routes.url_helpers
include app.routes.mounted_helpers
@@ -386,14 +385,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
diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb
index 91b25ec155..ec949c869b 100644
--- a/actionpack/lib/action_dispatch/testing/test_request.rb
+++ b/actionpack/lib/action_dispatch/testing/test_request.rb
@@ -9,7 +9,7 @@ module ActionDispatch
"HTTP_USER_AGENT" => "Rails Testing",
)
- # Create a new test request with default `env` values
+ # Create a new test request with default `env` values.
def self.create(env = {})
env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
env["rack.request.cookie_hash"] ||= {}.with_indifferent_access
diff --git a/actionpack/lib/action_pack/gem_version.rb b/actionpack/lib/action_pack/gem_version.rb
index d6a91a0569..fddc3033d5 100644
--- a/actionpack/lib/action_pack/gem_version.rb
+++ b/actionpack/lib/action_pack/gem_version.rb
@@ -6,9 +6,9 @@ module ActionPack
module VERSION
MAJOR = 5
- MINOR = 1
+ MINOR = 2
TINY = 0
- PRE = "beta1"
+ PRE = "alpha"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end