aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG.md25
-rw-r--r--actionpack/lib/action_controller/metal/etag_with_template_digest.rb2
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb19
-rw-r--r--actionpack/lib/action_dispatch/http/parameter_filter.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb7
-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/session/cookie_store.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/ssl.rb9
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb6
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb6
-rw-r--r--actionpack/lib/action_dispatch/routing/redirection.rb1
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb58
-rw-r--r--actionpack/lib/action_dispatch/testing/request_encoder.rb54
-rw-r--r--actionpack/lib/action_dispatch/testing/test_response.rb9
-rw-r--r--actionpack/test/abstract_unit.rb1
-rw-r--r--actionpack/test/controller/parameters/dup_test.rb43
-rw-r--r--actionpack/test/controller/parameters/parameters_permit_test.rb5
-rw-r--r--actionpack/test/controller/render_test.rb54
-rw-r--r--actionpack/test/dispatch/exception_wrapper_test.rb6
-rw-r--r--actionpack/test/dispatch/request_test.rb10
-rw-r--r--actionpack/test/dispatch/response_test.rb20
-rw-r--r--actionpack/test/dispatch/routing_test.rb31
-rw-r--r--actionpack/test/dispatch/static_test.rb9
-rw-r--r--actionpack/test/dispatch/test_response_test.rb8
-rw-r--r--actionpack/test/fixtures/namespaced/implicit_render_test/hello_world.erb1
26 files changed, 277 insertions, 127 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index be911b147c..d50cbaee38 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,2 +1,27 @@
+* Check `request.path_parameters` encoding at the point they're set.
+
+ Check for any non-UTF8 characters in path parameters at the point they're
+ set in `env`. Previously they were checked for when used to get a controller
+ class, but this meant routes that went directly to a Rack app, or skipped
+ controller instantiation for some other reason, had to defend against
+ non-UTF8 characters themselves.
+
+ *Grey Baker*
+
+* Don't raise ActionController::UnknownHttpMethod from ActionDispatch::Static
+
+ Pass `Rack::Request` objects to `ActionDispatch::FileHandler` to avoid it
+ raising `ActionController::UnknownHttpMethod`. If an unknown method is
+ passed, it should exception higher in the stack instead, once we've had a
+ chance to define exception handling behaviour.
+
+ *Grey Baker*
+
+* Handle `Rack::QueryParser` errors in `ActionDispatch::ExceptionWrapper`
+
+ Updated `ActionDispatch::ExceptionWrapper` to handle the Rack 2.0 namespace
+ for `ParameterTypeError` and `InvalidParameterError` errors.
+
+ *Grey Baker*
Please check [5-0-stable](https://github.com/rails/rails/blob/5-0-stable/actionpack/CHANGELOG.md) for previous changes.
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/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index b326695ce2..26794c67b7 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -572,20 +572,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)
@@ -783,6 +769,11 @@ module ActionController
end
end
end
+
+ def initialize_copy(source)
+ super
+ @parameters = @parameters.dup
+ end
end
# == Strong \Parameters
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..3f0e51790c 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.
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/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index dec9c60ef2..380a24a367 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -64,7 +64,7 @@ module ActionDispatch
# <tt>:httponly</tt>.
class CookieStore < AbstractStore
def initialize(app, options={})
- super(app, options.merge!(:cookie_only => true))
+ super(app, options.merge!(cookie_only: true))
end
def delete_session(req, session_id, options)
diff --git a/actionpack/lib/action_dispatch/middleware/ssl.rb b/actionpack/lib/action_dispatch/middleware/ssl.rb
index ab3077b308..0e04d3a524 100644
--- a/actionpack/lib/action_dispatch/middleware/ssl.rb
+++ b/actionpack/lib/action_dispatch/middleware/ssl.rb
@@ -18,17 +18,18 @@ module ActionDispatch
# Enabled by default. Configure `config.ssl_options` with `hsts: false` to disable.
#
# Set `config.ssl_options` with `hsts: { … }` to configure HSTS:
- # * `expires`: How long, in seconds, these settings will stick. Defaults to
- # `180.days` (recommended). The minimum required to qualify for browser
- # preload lists is `18.weeks`.
+ # * `expires`: How long, in seconds, these settings will stick. The minimum
+ # required to qualify for browser preload lists is `18.weeks`. Defaults to
+ # `180.days` (recommended).
# * `subdomains`: Set to `true` to tell the browser to apply these settings
# to all subdomains. This protects your cookies from interception by a
- # vulnerable site on a subdomain. Defaults to `true`.
+ # vulnerable site on a subdomain. Defaults to `false`.
# * `preload`: Advertise that this site may be included in browsers'
# preloaded HSTS lists. HSTS protects your site on every visit *except the
# first visit* since it hasn't seen your HSTS header yet. To close this
# gap, browser vendors include a baked-in list of HSTS-enabled sites.
# Go to https://hstspreload.appspot.com to submit your site for inclusion.
+ # Defaults to `false`.
#
# To turn off HSTS, omitting the header is not enough. Browsers will remember the
# original HSTS directive until it expires. Instead, use the header to tell browsers to
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 e2cf75da3a..73b4864e45 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1562,6 +1562,12 @@ module ActionDispatch
options = path
path, to = options.find { |name, _value| name.is_a?(String) }
+ if path.nil?
+ ActiveSupport::Deprecation.warn 'Omitting the route path is deprecated. '\
+ 'Specify the path with a String or a Symbol instead.'
+ path = ''
+ end
+
case to
when Symbol
options[:action] = to
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..4897f44268 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
@@ -777,7 +725,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
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 1e1d6f5429..c8a45a0851 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -33,7 +33,6 @@ require 'action_view/testing/resolvers'
require 'action_dispatch'
require 'active_support/dependencies'
require 'active_model'
-require 'active_record'
require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late
diff --git a/actionpack/test/controller/parameters/dup_test.rb b/actionpack/test/controller/parameters/dup_test.rb
new file mode 100644
index 0000000000..66bc8155c8
--- /dev/null
+++ b/actionpack/test/controller/parameters/dup_test.rb
@@ -0,0 +1,43 @@
+require 'abstract_unit'
+require 'action_controller/metal/strong_parameters'
+
+class ParametersDupTest < ActiveSupport::TestCase
+ setup do
+ ActionController::Parameters.permit_all_parameters = false
+
+ @params = ActionController::Parameters.new(
+ person: {
+ age: '32',
+ name: {
+ first: 'David',
+ last: 'Heinemeier Hansson'
+ },
+ addresses: [{city: 'Chicago', state: 'Illinois'}]
+ }
+ )
+ end
+
+ test "a duplicate maintains the original's permitted status" do
+ @params.permit!
+ dupped_params = @params.dup
+ assert dupped_params.permitted?
+ end
+
+ test "a duplicate maintains the original's parameters" do
+ @params.permit!
+ dupped_params = @params.dup
+ assert_equal @params.to_h, dupped_params.to_h
+ end
+
+ test "changes to a duplicate's parameters do not affect the original" do
+ dupped_params = @params.dup
+ dupped_params.delete(:person)
+ assert_not_equal @params, dupped_params
+ end
+
+ test "changes to a duplicate's permitted status do not affect the original" do
+ dupped_params = @params.dup
+ dupped_params.permit!
+ assert_not_equal @params, dupped_params
+ end
+end
diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb
index 2eed2996f6..2dd94c7230 100644
--- a/actionpack/test/controller/parameters/parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/parameters_permit_test.rb
@@ -245,11 +245,6 @@ class ParametersPermitTest < ActiveSupport::TestCase
assert_equal "Jonas", @params[:person][:family][:brother]
end
- test "permit state is kept on a dup" do
- @params.permit!
- assert_equal @params.permitted?, @params.dup.permitted?
- end
-
test "permit is recursive" do
@params.permit!
assert @params.permitted?
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 652c06af19..e56f6e840a 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -42,6 +42,14 @@ class ImplicitRenderTestController < ActionController::Base
end
end
+module Namespaced
+ class ImplicitRenderTestController < ActionController::Base
+ def hello_world
+ fresh_when(etag: 'abc')
+ end
+ end
+end
+
class TestController < ActionController::Base
protect_from_forgery
@@ -258,6 +266,19 @@ class TestController < ActionController::Base
end
end
+module TemplateModificationHelper
+ private
+ def modify_template(name)
+ path = File.expand_path("../../fixtures/#{name}.erb", __FILE__)
+ original = File.read(path)
+ File.write(path, "#{original} Modified!")
+ ActionView::LookupContext::DetailsKey.clear
+ yield
+ ensure
+ File.write(path, original)
+ end
+end
+
class MetalTestController < ActionController::Metal
include AbstractController::Rendering
include ActionView::Rendering
@@ -487,6 +508,7 @@ end
class EtagRenderTest < ActionController::TestCase
tests TestControllerWithExtraEtags
+ include TemplateModificationHelper
def test_strong_etag
@request.if_none_match = strong_etag(['strong', 'ab', :cde, [:f]])
@@ -535,7 +557,7 @@ class EtagRenderTest < ActionController::TestCase
get :with_template
assert_response :not_modified
- modify_template(:hello_world) do
+ modify_template("test/hello_world") do
request.if_none_match = etag
get :with_template
assert_response :ok
@@ -552,7 +574,7 @@ class EtagRenderTest < ActionController::TestCase
get :with_implicit_template
assert_response :not_modified
- modify_template(:with_implicit_template) do
+ modify_template("test/with_implicit_template") do
request.if_none_match = etag
get :with_implicit_template
assert_response :ok
@@ -568,16 +590,28 @@ class EtagRenderTest < ActionController::TestCase
def strong_etag(record)
%("#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(record))}")
end
+end
- def modify_template(name)
- path = File.expand_path("../../fixtures/test/#{name}.erb", __FILE__)
- original = File.read(path)
- File.write(path, "#{original} Modified!")
- ActionView::LookupContext::DetailsKey.clear
- yield
- ensure
- File.write(path, original)
+class NamespacedEtagRenderTest < ActionController::TestCase
+ tests Namespaced::ImplicitRenderTestController
+ include TemplateModificationHelper
+
+ def test_etag_reflects_template_digest
+ get :hello_world
+ assert_response :ok
+ assert_not_nil etag = @response.etag
+
+ request.if_none_match = etag
+ get :hello_world
+ assert_response :not_modified
+
+ modify_template("namespaced/implicit_render_test/hello_world") do
+ request.if_none_match = etag
+ get :hello_world
+ assert_response :ok
+ assert_not_equal etag, @response.etag
end
+ end
end
class MetalRenderTest < ActionController::TestCase
diff --git a/actionpack/test/dispatch/exception_wrapper_test.rb b/actionpack/test/dispatch/exception_wrapper_test.rb
index dfbb91c0ca..0959cf2805 100644
--- a/actionpack/test/dispatch/exception_wrapper_test.rb
+++ b/actionpack/test/dispatch/exception_wrapper_test.rb
@@ -57,6 +57,12 @@ module ActionDispatch
assert_equal [ "lib/file.rb:42:in `index'" ], wrapper.application_trace
end
+ test '#status_code returns 400 for Rack::Utils::ParameterTypeError' do
+ exception = Rack::Utils::ParameterTypeError.new
+ wrapper = ExceptionWrapper.new(@cleaner, exception)
+ assert_equal 400, wrapper.status_code
+ end
+
test '#application_trace cannot be nil' do
nil_backtrace_wrapper = ExceptionWrapper.new(@cleaner, BadlyDefinedError.new)
nil_cleaner_wrapper = ExceptionWrapper.new(nil, BadlyDefinedError.new)
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index 8a5d85ab84..634f6d80c4 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -1018,17 +1018,13 @@ class RequestParameters < BaseRequestTest
end
test "path parameters with invalid UTF8 encoding" do
- request = stub_request(
- "action_dispatch.request.path_parameters" => { foo: "\xBE" }
- )
+ request = stub_request
err = assert_raises(ActionController::BadRequest) do
- request.check_path_parameters!
+ request.path_parameters = { foo: "\xBE" }
end
- assert_match "Invalid parameter encoding", err.message
- assert_match "foo", err.message
- assert_match "\\xBE", err.message
+ assert_equal "Invalid path parameters: Non UTF-8 value: \xBE", err.message
end
test "parameters not accessible after rack parse error of invalid UTF8 character" do
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index aa90433505..9eed796d3c 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -145,6 +145,26 @@ class ResponseTest < ActiveSupport::TestCase
}, headers)
end
+ test "content length" do
+ [100, 101, 102, 204].each do |c|
+ @response = ActionDispatch::Response.new
+ @response.status = c.to_s
+ @response.set_header "Content-Length", "0"
+ _, headers, _ = @response.to_a
+ assert !headers.has_key?("Content-Length"), "#{c} must not have a Content-Length header field"
+ end
+ end
+
+ test "does not contain a message-body" do
+ [100, 101, 102, 204, 304].each do |c|
+ @response = ActionDispatch::Response.new
+ @response.status = c.to_s
+ @response.body = "Body must not be included"
+ _, _, body = @response.to_a
+ assert_empty body, "#{c} must not have a message-body but actually contains #{body}"
+ end
+ end
+
test "content type" do
[204, 304].each do |c|
@response = ActionDispatch::Response.new
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 75fdc9469f..5298e63fef 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -373,6 +373,9 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
post "create", :as => ""
put "update"
get "remove", :action => :destroy, :as => :remove
+ tc.assert_deprecated do
+ get action: :show, as: :show
+ end
end
end
@@ -391,6 +394,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get '/pagemark/remove'
assert_equal 'pagemarks#destroy', @response.body
assert_equal '/pagemark/remove', pagemark_remove_path
+
+ get '/pagemark'
+ assert_equal 'pagemarks#show', @response.body
+ assert_equal '/pagemark', pagemark_show_path
end
def test_admin
@@ -4324,15 +4331,16 @@ class TestInvalidUrls < ActionDispatch::IntegrationTest
test "invalid UTF-8 encoding returns a 400 Bad Request" do
with_routing do |set|
- ActiveSupport::Deprecation.silence do
- set.draw do
- get "/bar/:id", :to => redirect("/foo/show/%{id}")
- get "/foo/show(/:id)", :to => "test_invalid_urls/foo#show"
+ set.draw do
+ get "/bar/:id", :to => redirect("/foo/show/%{id}")
+ get "/foo/show(/:id)", :to => "test_invalid_urls/foo#show"
- ActiveSupport::Deprecation.silence do
- get "/foo(/:action(/:id))", :controller => "test_invalid_urls/foo"
- get "/:controller(/:action(/:id))"
- end
+ ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }
+ get '/foobar/:id', to: ok
+
+ ActiveSupport::Deprecation.silence do
+ get "/foo(/:action(/:id))", :controller => "test_invalid_urls/foo"
+ get "/:controller(/:action(/:id))"
end
end
@@ -4347,6 +4355,9 @@ class TestInvalidUrls < ActionDispatch::IntegrationTest
get "/bar/%E2%EF%BF%BD%A6"
assert_response :bad_request
+
+ get "/foobar/%E2%EF%BF%BD%A6"
+ assert_response :bad_request
end
end
end
@@ -4767,7 +4778,9 @@ class TestPathParameters < ActionDispatch::IntegrationTest
end
end
- get ':controller(/:action/(:id))'
+ ActiveSupport::Deprecation.silence do
+ get ':controller(/:action/(:id))'
+ end
end
end
diff --git a/actionpack/test/dispatch/static_test.rb b/actionpack/test/dispatch/static_test.rb
index ea8b5e904e..1036758f35 100644
--- a/actionpack/test/dispatch/static_test.rb
+++ b/actionpack/test/dispatch/static_test.rb
@@ -160,6 +160,9 @@ module StaticTests
response = get(file_name, 'HTTP_ACCEPT_ENCODING' => 'GZIP')
assert_gzip file_name, response
+ response = get(file_name, 'HTTP_ACCEPT_ENCODING' => 'compress;q=0.5, gzip;q=1.0')
+ assert_gzip file_name, response
+
response = get(file_name, 'HTTP_ACCEPT_ENCODING' => '')
assert_not_equal 'gzip', response.headers["Content-Encoding"]
end
@@ -205,6 +208,12 @@ module StaticTests
assert_equal "I'm a teapot", response.headers["X-Custom-Header"]
end
+ def test_ignores_unknown_http_methods
+ app = ActionDispatch::Static.new(DummyApp, @root)
+
+ assert_nothing_raised { Rack::MockRequest.new(app).request("BAD_METHOD", "/foo/bar.html") }
+ end
+
# Windows doesn't allow \ / : * ? " < > | in filenames
unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
def test_serves_static_file_with_colon
diff --git a/actionpack/test/dispatch/test_response_test.rb b/actionpack/test/dispatch/test_response_test.rb
index a4f9d56a6a..72e06b4590 100644
--- a/actionpack/test/dispatch/test_response_test.rb
+++ b/actionpack/test/dispatch/test_response_test.rb
@@ -17,4 +17,12 @@ class TestResponseTest < ActiveSupport::TestCase
assert_response_code_range 500..599, :server_error?
assert_response_code_range 400..499, :client_error?
end
+
+ test "response parsing" do
+ response = ActionDispatch::TestResponse.create(200, {}, '')
+ assert_equal response.body, response.parsed_body
+
+ response = ActionDispatch::TestResponse.create(200, { 'Content-Type' => 'application/json' }, '{ "foo": "fighters" }')
+ assert_equal({ 'foo' => 'fighters' }, response.parsed_body)
+ end
end
diff --git a/actionpack/test/fixtures/namespaced/implicit_render_test/hello_world.erb b/actionpack/test/fixtures/namespaced/implicit_render_test/hello_world.erb
new file mode 100644
index 0000000000..cd0875583a
--- /dev/null
+++ b/actionpack/test/fixtures/namespaced/implicit_render_test/hello_world.erb
@@ -0,0 +1 @@
+Hello world!