aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/action_controller/metal/etag_with_template_digest.rb2
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb6
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb47
-rw-r--r--actionpack/lib/action_controller/test_case.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/parameter_filter.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb9
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb12
-rw-r--r--actionpack/lib/action_dispatch/middleware/exception_wrapper.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb6
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb9
-rw-r--r--actionpack/lib/action_dispatch/routing/redirection.rb1
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb64
-rw-r--r--actionpack/lib/action_dispatch/testing/request_encoder.rb54
-rw-r--r--actionpack/lib/action_dispatch/testing/test_response.rb9
14 files changed, 130 insertions, 96 deletions
diff --git a/actionpack/lib/action_controller/metal/etag_with_template_digest.rb b/actionpack/lib/action_controller/metal/etag_with_template_digest.rb
index 75ac996793..e3a7c3b166 100644
--- a/actionpack/lib/action_controller/metal/etag_with_template_digest.rb
+++ b/actionpack/lib/action_controller/metal/etag_with_template_digest.rb
@@ -45,7 +45,7 @@ module ActionController
# template digest from the ETag.
def pick_template_for_etag(options)
unless options[:template] == false
- options[:template] || "#{controller_name}/#{action_name}"
+ options[:template] || "#{controller_path}/#{action_name}"
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 0559fbc6ce..fd7ffcfcd7 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -109,10 +109,10 @@ module ActionController #:nodoc:
# * <tt>:only/:except</tt> - Only apply forgery protection to a subset of actions. For example <tt>only: [ :create, :create_all ]</tt>.
# * <tt>:if/:unless</tt> - Turn off the forgery protection entirely depending on the passed Proc or method reference.
# * <tt>:prepend</tt> - By default, the verification of the authentication token will be added at the position of the
- # protect_from_forgery call in your application. This means any callbacks added before are run first. This is useful
- # when you want your forgery protection to depend on other callbacks, like authentication methods (Oauth vs Cookie auth).
+ # protect_from_forgery call in your application. This means any callbacks added before are run first. This is useful
+ # when you want your forgery protection to depend on other callbacks, like authentication methods (Oauth vs Cookie auth).
#
- # If you need to add verification to the beginning of the callback chain, use <tt>prepend: true</tt>.
+ # If you need to add verification to the beginning of the callback chain, use <tt>prepend: true</tt>.
# * <tt>:with</tt> - Set the method to handle unverified request.
#
# Valid unverified request handling methods are:
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index b326695ce2..f101c7b836 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -7,6 +7,7 @@ require 'action_dispatch/http/upload'
require 'rack/test'
require 'stringio'
require 'set'
+require 'yaml'
module ActionController
# Raised when a required parameter is missing.
@@ -572,20 +573,6 @@ module ActionController
convert_value_to_parameters(@parameters.values_at(*keys))
end
- # Returns an exact copy of the <tt>ActionController::Parameters</tt>
- # instance. +permitted+ state is kept on the duped object.
- #
- # params = ActionController::Parameters.new(a: 1)
- # params.permit!
- # params.permitted? # => true
- # copy_params = params.dup # => <ActionController::Parameters {"a"=>1} permitted: true>
- # copy_params.permitted? # => true
- def dup
- super.tap do |duplicate|
- duplicate.permitted = @permitted
- end
- end
-
# Returns a new <tt>ActionController::Parameters</tt> with all keys from
# +other_hash+ merges into current hash.
def merge(other_hash)
@@ -605,6 +592,33 @@ module ActionController
"<#{self.class} #{@parameters} permitted: #{@permitted}>"
end
+ def self.hook_into_yaml_loading # :nodoc:
+ # Wire up YAML format compatibility with Rails 4.2 and Psych 2.0.8 and 2.0.9+.
+ # Makes the YAML parser call `init_with` when it encounters the keys below
+ # instead of trying its own parsing routines.
+ YAML.load_tags['!ruby/hash-with-ivars:ActionController::Parameters'] = name
+ YAML.load_tags['!ruby/hash:ActionController::Parameters'] = name
+ end
+ hook_into_yaml_loading
+
+ def init_with(coder) # :nodoc:
+ case coder.tag
+ when '!ruby/hash:ActionController::Parameters'
+ # YAML 2.0.8's format where hash instance variables weren't stored.
+ @parameters = coder.map.with_indifferent_access
+ @permitted = false
+ when '!ruby/hash-with-ivars:ActionController::Parameters'
+ # YAML 2.0.9's Hash subclass format where keys and values
+ # were stored under an elements hash and `permitted` within an ivars hash.
+ @parameters = coder.map['elements'].with_indifferent_access
+ @permitted = coder.map['ivars'][:@permitted]
+ when '!ruby/object:ActionController::Parameters'
+ # YAML's Object format. Only needed because of the format
+ # backwardscompability above, otherwise equivalent to YAML's initialization.
+ @parameters, @permitted = coder.map['parameters'], coder.map['permitted']
+ end
+ end
+
def method_missing(method_sym, *args, &block)
if @parameters.respond_to?(method_sym)
message = <<-DEPRECATE.squish
@@ -783,6 +797,11 @@ module ActionController
end
end
end
+
+ def initialize_copy(source)
+ super
+ @parameters = @parameters.dup
+ end
end
# == Strong \Parameters
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index b1b3e87934..6c5d7b5e37 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -620,6 +620,7 @@ module ActionController
env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
env.delete 'action_dispatch.request.query_parameters'
env.delete 'action_dispatch.request.request_parameters'
+ env['rack.input'] = StringIO.new
env
end
diff --git a/actionpack/lib/action_dispatch/http/parameter_filter.rb b/actionpack/lib/action_dispatch/http/parameter_filter.rb
index e826551f4b..01f1666b9b 100644
--- a/actionpack/lib/action_dispatch/http/parameter_filter.rb
+++ b/actionpack/lib/action_dispatch/http/parameter_filter.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/duplicable'
+
module ActionDispatch
module Http
class ParameterFilter
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index ff5031d7d5..ea0e2ee41f 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -44,7 +44,14 @@ module ActionDispatch
def path_parameters=(parameters) #:nodoc:
delete_header('action_dispatch.request.parameters')
+
+ # If any of the path parameters has an invalid encoding then
+ # raise since it's likely to trigger errors further on.
+ Request::Utils.check_param_encoding(parameters)
+
set_header PARAMETERS_KEY, parameters
+ rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
+ raise ActionController::BadRequest.new("Invalid path parameters: #{e.message}")
end
# Returns a hash with the \parameters used to form the \path of the request.
@@ -58,7 +65,7 @@ module ActionDispatch
private
def parse_formatted_parameters(parsers)
- return yield if content_length.zero?
+ return yield if content_length.zero? || content_mime_type.nil?
strategy = parsers.fetch(content_mime_type.symbol) { return yield }
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index b0ed681623..954dd4f354 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -66,24 +66,12 @@ module ActionDispatch
def commit_cookie_jar! # :nodoc:
end
- def check_path_parameters!
- # If any of the path parameters has an invalid encoding then
- # raise since it's likely to trigger errors further on.
- path_parameters.each do |key, value|
- next unless value.respond_to?(:valid_encoding?)
- unless value.valid_encoding?
- raise ActionController::BadRequest, "Invalid parameter encoding: #{key} => #{value.inspect}"
- end
- end
- end
-
PASS_NOT_FOUND = Class.new { # :nodoc:
def self.action(_); self; end
def self.call(_); [404, {'X-Cascade' => 'pass'}, []]; end
}
def controller_class
- check_path_parameters!
params = path_parameters
if params.key?(:controller)
diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
index 59edc66086..b02f10c9ec 100644
--- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
+++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
@@ -17,8 +17,8 @@ module ActionDispatch
'ActionDispatch::ParamsParser::ParseError' => :bad_request,
'ActionController::BadRequest' => :bad_request,
'ActionController::ParameterMissing' => :bad_request,
- 'Rack::Utils::ParameterTypeError' => :bad_request,
- 'Rack::Utils::InvalidParameterError' => :bad_request
+ 'Rack::QueryParser::ParameterTypeError' => :bad_request,
+ 'Rack::QueryParser::InvalidParameterError' => :bad_request
)
cattr_accessor :rescue_templates
diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index 2c5721dc22..4161c1d110 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -46,7 +46,7 @@ module ActionDispatch
end
def call(env)
- serve ActionDispatch::Request.new env
+ serve(Rack::Request.new(env))
end
def serve(request)
@@ -82,7 +82,7 @@ module ActionDispatch
end
def gzip_encoding_accepted?(request)
- request.accept_encoding =~ /\bgzip\b/i
+ request.accept_encoding.any? { |enc, quality| enc =~ /\bgzip\b/i }
end
def gzip_file_path(path)
@@ -119,7 +119,7 @@ module ActionDispatch
end
def call(env)
- req = ActionDispatch::Request.new env
+ req = Rack::Request.new env
if req.get? || req.head?
path = req.path_info.chomp('/'.freeze)
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 73b4864e45..12ddd0f148 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1923,7 +1923,14 @@ to this:
def match_root_route(options)
name = has_named_route?(:root) ? nil : :root
- match '/', { :as => name, :via => :get }.merge!(options)
+ defaults_option = options.delete(:defaults)
+ args = ['/', { as: name, via: :get }.merge!(options)]
+
+ if defaults_option
+ defaults(defaults_option) { match(*args) }
+ else
+ match(*args)
+ end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb
index d6987f4d09..3265caa00b 100644
--- a/actionpack/lib/action_dispatch/routing/redirection.rb
+++ b/actionpack/lib/action_dispatch/routing/redirection.rb
@@ -22,7 +22,6 @@ module ActionDispatch
end
def serve(req)
- req.check_path_parameters!
uri = URI.parse(path(req.path_parameters, req))
unless uri.host
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 10cd1e5787..9a76b68ae1 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -6,6 +6,8 @@ require 'active_support/core_ext/string/strip'
require 'rack/test'
require 'minitest'
+require 'action_dispatch/testing/request_encoder'
+
module ActionDispatch
module Integration #:nodoc:
module RequestHelpers
@@ -383,7 +385,6 @@ module ActionDispatch
response = _mock_session.last_response
@response = ActionDispatch::TestResponse.from_response(response)
@response.request = @request
- @response.response_parser = RequestEncoder.parser(@response.content_type)
@html_document = nil
@url_options = nil
@@ -402,59 +403,6 @@ module ActionDispatch
path = request_encoder.append_format_to location.path
location.query ? "#{path}?#{location.query}" : path
end
-
- class RequestEncoder # :nodoc:
- @encoders = {}
-
- attr_reader :response_parser
-
- def initialize(mime_name, param_encoder, response_parser, url_encoded_form = false)
- @mime = Mime[mime_name]
-
- unless @mime
- raise ArgumentError, "Can't register a request encoder for " \
- "unregistered MIME Type: #{mime_name}. See `Mime::Type.register`."
- end
-
- @url_encoded_form = url_encoded_form
- @path_format = ".#{@mime.symbol}" unless @url_encoded_form
- @response_parser = response_parser || -> body { body }
- @param_encoder = param_encoder || :"to_#{@mime.symbol}".to_proc
- end
-
- def append_format_to(path)
- if @url_encoded_form
- path
- else
- path + @path_format
- end
- end
-
- def content_type
- @mime.to_s
- end
-
- def encode_params(params)
- @param_encoder.call(params)
- end
-
- def self.parser(content_type)
- mime = Mime::Type.lookup(content_type)
- encoder(mime ? mime.ref : nil).response_parser
- end
-
- def self.encoder(name)
- @encoders[name] || WWWFormEncoder
- end
-
- def self.register_encoder(mime_name, param_encoder: nil, response_parser: nil)
- @encoders[mime_name] = new(mime_name, param_encoder, response_parser)
- end
-
- register_encoder :json, response_parser: -> body { JSON.parse(body) }
-
- WWWFormEncoder = new(:url_encoded_form, -> params { params }, nil, true)
- end
end
module Runner
@@ -769,7 +717,11 @@ module ActionDispatch
module ClassMethods
def app
- defined?(@@app) ? @@app : ActionDispatch.test_app
+ if defined?(@@app) && @@app
+ @@app
+ else
+ ActionDispatch.test_app
+ end
end
def app=(app)
@@ -777,7 +729,7 @@ module ActionDispatch
end
def register_encoder(*args)
- Integration::Session::RequestEncoder.register_encoder(*args)
+ RequestEncoder.register_encoder(*args)
end
end
diff --git a/actionpack/lib/action_dispatch/testing/request_encoder.rb b/actionpack/lib/action_dispatch/testing/request_encoder.rb
new file mode 100644
index 0000000000..b0b994b2d0
--- /dev/null
+++ b/actionpack/lib/action_dispatch/testing/request_encoder.rb
@@ -0,0 +1,54 @@
+module ActionDispatch
+ class RequestEncoder # :nodoc:
+ @encoders = {}
+
+ attr_reader :response_parser
+
+ def initialize(mime_name, param_encoder, response_parser, url_encoded_form = false)
+ @mime = Mime[mime_name]
+
+ unless @mime
+ raise ArgumentError, "Can't register a request encoder for " \
+ "unregistered MIME Type: #{mime_name}. See `Mime::Type.register`."
+ end
+
+ @url_encoded_form = url_encoded_form
+ @path_format = ".#{@mime.symbol}" unless @url_encoded_form
+ @response_parser = response_parser || -> body { body }
+ @param_encoder = param_encoder || :"to_#{@mime.symbol}".to_proc
+ end
+
+ def append_format_to(path)
+ if @url_encoded_form
+ path
+ else
+ path + @path_format
+ end
+ end
+
+ def content_type
+ @mime.to_s
+ end
+
+ def encode_params(params)
+ @param_encoder.call(params)
+ end
+
+ def self.parser(content_type)
+ mime = Mime::Type.lookup(content_type)
+ encoder(mime ? mime.ref : nil).response_parser
+ end
+
+ def self.encoder(name)
+ @encoders[name] || WWWFormEncoder
+ end
+
+ def self.register_encoder(mime_name, param_encoder: nil, response_parser: nil)
+ @encoders[mime_name] = new(mime_name, param_encoder, response_parser)
+ end
+
+ register_encoder :json, response_parser: -> body { JSON.parse(body) }
+
+ WWWFormEncoder = new(:url_encoded_form, -> params { params }, nil, true)
+ end
+end
diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb
index 9d4b73a43d..bedb7a5558 100644
--- a/actionpack/lib/action_dispatch/testing/test_response.rb
+++ b/actionpack/lib/action_dispatch/testing/test_response.rb
@@ -1,3 +1,5 @@
+require 'action_dispatch/testing/request_encoder'
+
module ActionDispatch
# Integration test methods such as ActionDispatch::Integration::Session#get
# and ActionDispatch::Integration::Session#post return objects of class
@@ -10,6 +12,11 @@ module ActionDispatch
new response.status, response.headers, response.body
end
+ def initialize(*) # :nodoc:
+ super
+ @response_parser = RequestEncoder.parser(content_type)
+ end
+
# Was the response successful?
alias_method :success?, :successful?
@@ -19,8 +26,6 @@ module ActionDispatch
# Was there a server-side error?
alias_method :error?, :server_error?
- attr_writer :response_parser # :nodoc:
-
def parsed_body
@parsed_body ||= @response_parser.call(body)
end