diff options
Diffstat (limited to 'actionpack/lib/action_dispatch')
11 files changed, 96 insertions, 34 deletions
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 56908b5794..aa5ba3e8a5 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -231,17 +231,24 @@ module ActionDispatch # Override Rack's GET method to support indifferent access def GET - @env["action_dispatch.request.query_parameters"] ||= (normalize_parameters(super) || {}) + begin + @env["action_dispatch.request.query_parameters"] ||= (normalize_parameters(super) || {}) + rescue TypeError => e + raise ActionController::BadRequest, "Invalid query parameters: #{e.message}" + end end alias :query_parameters :GET # Override Rack's POST method to support indifferent access def POST - @env["action_dispatch.request.request_parameters"] ||= (normalize_parameters(super) || {}) + begin + @env["action_dispatch.request.request_parameters"] ||= (normalize_parameters(super) || {}) + rescue TypeError => e + raise ActionController::BadRequest, "Invalid request parameters: #{e.message}" + end end alias :request_parameters :POST - # Returns the authorization header regardless of whether it was specified directly or through one of the # proxy alternatives. def authorization diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb index a8f49bd3bd..7349b578d2 100644 --- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb +++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb @@ -12,7 +12,8 @@ module ActionDispatch 'ActionController::MethodNotAllowed' => :method_not_allowed, 'ActionController::NotImplemented' => :not_implemented, 'ActionController::UnknownFormat' => :not_acceptable, - 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity + 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity, + 'ActionController::BadRequest' => :bad_request ) cattr_accessor :rescue_templates diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb index 12bc438be3..bbf734f103 100644 --- a/actionpack/lib/action_dispatch/middleware/stack.rb +++ b/actionpack/lib/action_dispatch/middleware/stack.rb @@ -75,6 +75,11 @@ module ActionDispatch middlewares[i] end + def unshift(*args, &block) + middleware = self.class::Middleware.new(*args, &block) + middlewares.unshift(middleware) + end + def initialize_copy(other) self.middlewares = other.middlewares.dup end diff --git a/actionpack/lib/action_dispatch/request/session.rb b/actionpack/lib/action_dispatch/request/session.rb index 4ad7071820..d8bcc28613 100644 --- a/actionpack/lib/action_dispatch/request/session.rb +++ b/actionpack/lib/action_dispatch/request/session.rb @@ -87,6 +87,14 @@ module ActionDispatch alias :key? :has_key? alias :include? :has_key? + def keys + @delegate.keys + end + + def values + @delegate.values + end + def []=(key, value) load_for_write! @delegate[key.to_s] = value diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 67a208263b..e43e897783 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1318,7 +1318,7 @@ module ActionDispatch def draw(name) path = @draw_paths.find do |_path| - _path.join("#{name}.rb").file? + File.exists? "#{_path}/#{name}.rb" end unless path @@ -1328,8 +1328,8 @@ module ActionDispatch raise ArgumentError, msg end - route_path = path.join("#{name}.rb") - instance_eval(route_path.read, route_path.to_s) + route_path = "#{path}/#{name}.rb" + instance_eval(File.read(route_path), route_path.to_s) end # match 'path' => 'controller#action' diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb index 95c588c00a..205ff44b1c 100644 --- a/actionpack/lib/action_dispatch/routing/redirection.rb +++ b/actionpack/lib/action_dispatch/routing/redirection.rb @@ -2,6 +2,7 @@ require 'action_dispatch/http/request' require 'active_support/core_ext/uri' require 'active_support/core_ext/array/extract_options' require 'rack/utils' +require 'action_controller/metal/exceptions' module ActionDispatch module Routing @@ -16,6 +17,14 @@ module ActionDispatch def call(env) req = Request.new(env) + # If any of the path parameters has a invalid encoding then + # raise since it's likely to trigger errors further on. + req.symbolized_path_parameters.each do |key, value| + unless value.valid_encoding? + raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}" + end + end + uri = URI.parse(path(req.symbolized_path_parameters, req)) uri.scheme ||= req.scheme uri.host ||= req.host @@ -35,6 +44,25 @@ module ActionDispatch def path(params, request) block.call params, request end + + def inspect + "redirect(#{status})" + end + end + + class PathRedirect < Redirect + def path(params, request) + (params.empty? || !block.match(/%\{\w*\}/)) ? block : (block % escape(params)) + end + + def inspect + "redirect(#{status}, #{block})" + end + + private + def escape(params) + Hash[params.map{ |k,v| [k, Rack::Utils.escape(v)] }] + end end class OptionRedirect < Redirect # :nodoc: @@ -56,6 +84,10 @@ module ActionDispatch ActionDispatch::Http::URL.url_for url_options end + def inspect + "redirect(#{status}, #{options.map{ |k,v| "#{k}: #{v}" }.join(', ')})" + end + private def escape_path(params) Hash[params.map{ |k,v| [k, URI.parser.escape(v)] }] @@ -102,24 +134,15 @@ module ActionDispatch def redirect(*args, &block) options = args.extract_options! status = options.delete(:status) || 301 + path = args.shift return OptionRedirect.new(status, options) if options.any? - - path = args.shift - - block = lambda { |params, request| - (params.empty? || !path.match(/%\{\w*\}/)) ? path : (path % escape(params)) - } if String === path + return PathRedirect.new(status, path) if String === path block = path if path.respond_to? :call raise ArgumentError, "redirection argument not supported" unless block Redirect.new status, block end - - private - def escape(params) - Hash[params.map{ |k,v| [k, Rack::Utils.escape(v)] }] - end end end end diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 0ae668d42a..7872f4007e 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -26,6 +26,15 @@ module ActionDispatch def call(env) params = env[PARAMETERS_KEY] + + # If any of the path parameters has a invalid encoding then + # raise since it's likely to trigger errors further on. + params.each do |key, value| + unless value.valid_encoding? + raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}" + end + end + prepare_params!(params) # Just raise undefined constant errors if a controller was specified as default. @@ -654,9 +663,13 @@ module ActionDispatch dispatcher = dispatcher.app end - if dispatcher.is_a?(Dispatcher) && dispatcher.controller(params, false) - dispatcher.prepare_params!(params) - return params + if dispatcher.is_a?(Dispatcher) + if dispatcher.controller(params, false) + dispatcher.prepare_params!(params) + return params + else + raise ActionController::RoutingError, "A route matches #{path.inspect}, but references missing controller: #{params[:controller].camelize}Controller" + end end end diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index 3d121b6b9c..b4c8f839ac 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -28,7 +28,7 @@ module ActionDispatch assert @response.send("#{type}?"), message else code = Rack::Utils::SYMBOL_TO_STATUS_CODE[type] - assert_equal @response.response_code, code, message + assert_equal code, @response.response_code, message end else assert_equal type, @response.response_code, message diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb index 567ca0c392..41fa3a4b95 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb @@ -69,11 +69,9 @@ module ActionDispatch # assert_generates "changesets/12", { :controller => 'scm', :action => 'show_diff', :revision => "12" } def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil) if expected_path =~ %r{://} - begin + fail_on(URI::InvalidURIError) do uri = URI.parse(expected_path) expected_path = uri.path.to_s.empty? ? "/" : uri.path - rescue URI::InvalidURIError => e - raise ActionController::RoutingError, e.message end else expected_path = "/#{expected_path}" unless expected_path.first == '/' @@ -189,14 +187,12 @@ module ActionDispatch request = ActionController::TestRequest.new if path =~ %r{://} - begin + fail_on(URI::InvalidURIError) do uri = URI.parse(path) request.env["rack.url_scheme"] = uri.scheme || "http" request.host = uri.host if uri.host request.port = uri.port if uri.port request.path = uri.path.to_s.empty? ? "/" : uri.path - rescue URI::InvalidURIError => e - raise ActionController::RoutingError, e.message end else path = "/#{path}" unless path.first == "/" @@ -205,11 +201,21 @@ module ActionDispatch request.request_method = method if method - params = @routes.recognize_path(path, { :method => method, :extras => extras }) + params = fail_on(ActionController::RoutingError) do + @routes.recognize_path(path, { :method => method, :extras => extras }) + end request.path_parameters = params.with_indifferent_access request end + + def fail_on(exception_class) + begin + yield + rescue exception_class => e + raise MiniTest::Assertion, e.message + end + end end end end diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 08fd28d72d..3fdc6688c2 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -17,8 +17,8 @@ module ActionDispatch # a Hash, or a String that is appropriately encoded # (<tt>application/x-www-form-urlencoded</tt> or # <tt>multipart/form-data</tt>). - # - +headers+: Additional HTTP headers to pass, as a Hash. The keys will - # automatically be upcased, with the prefix 'HTTP_' added if needed. + # - +headers+: Additional headers to pass, as a Hash. The headers will be + # merged into the Rack env hash. # # This method returns an Response object, which one can use to # inspect the details of the response. Furthermore, if this method was @@ -73,8 +73,7 @@ module ActionDispatch # # The request_method is +:get+, +:post+, +:patch+, +:put+, +:delete+ or # +:head+; the parameters are +nil+, a hash, or a url-encoded or multipart - # string; the headers are a hash. Keys are automatically upcased and - # prefixed with 'HTTP_' if not already. + # string; the headers are a hash. def xml_http_request(request_method, path, parameters = nil, headers = nil) headers ||= {} headers['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb index d04be2099c..a86b510719 100644 --- a/actionpack/lib/action_dispatch/testing/test_request.rb +++ b/actionpack/lib/action_dispatch/testing/test_request.rb @@ -11,7 +11,7 @@ module ActionDispatch end def initialize(env = {}) - env = Rails.application.env_config.merge(env) if defined?(Rails.application) + env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application super(DEFAULT_ENV.merge(env)) self.host = 'test.host' |