aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
authorJeremy Kemper <jeremy@bitsweat.net>2007-05-26 20:07:34 +0000
committerJeremy Kemper <jeremy@bitsweat.net>2007-05-26 20:07:34 +0000
commitdcaa074abf5691a933b9c55159cc7d98a02b3b2f (patch)
tree4d58fee286eaa957e141939dcbd898055cab2325 /actionpack/lib
parent42ebf559cc6ed80fa3bf55ecc1dea7c9e593f45e (diff)
downloadrails-dcaa074abf5691a933b9c55159cc7d98a02b3b2f.tar.gz
rails-dcaa074abf5691a933b9c55159cc7d98a02b3b2f.tar.bz2
rails-dcaa074abf5691a933b9c55159cc7d98a02b3b2f.zip
Routing: respond with 405 Method Not Allowed status when the route path matches but the HTTP method does not. Closes #6953.
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@6862 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'actionpack/lib')
-rwxr-xr-xactionpack/lib/action_controller/base.rb18
-rw-r--r--actionpack/lib/action_controller/rescue.rb20
-rw-r--r--actionpack/lib/action_controller/routing.rb13
3 files changed, 44 insertions, 7 deletions
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index dc5a1d18cd..8bff41d38d 100755
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -22,6 +22,24 @@ module ActionController #:nodoc:
@failures = failures
end
end
+ class MethodNotAllowed < ActionControllerError #:nodoc:
+ attr_reader :allowed_methods
+
+ def initialize(*allowed_methods)
+ super("Only #{allowed_methods.to_sentence} requests are allowed.")
+ @allowed_methods = allowed_methods
+ end
+
+ def allowed_methods_header
+ allowed_methods.map { |method_symbol| method_symbol.to_s.upcase } * ', '
+ end
+
+ def handle_response!(response)
+ response.headers['Allow'] ||= allowed_methods_header
+ end
+ end
+ class NotImplemented < MethodNotAllowed #:nodoc:
+ end
class UnknownController < ActionControllerError #:nodoc:
end
class UnknownAction < ActionControllerError #:nodoc:
diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/rescue.rb
index 225acd28f3..3ab10107bf 100644
--- a/actionpack/lib/action_controller/rescue.rb
+++ b/actionpack/lib/action_controller/rescue.rb
@@ -13,12 +13,14 @@ module ActionController #:nodoc:
DEFAULT_RESCUE_RESPONSE = :internal_server_error
DEFAULT_RESCUE_RESPONSES = {
- 'ActionController::RoutingError' => :not_found,
- 'ActionController::UnknownAction' => :not_found,
- 'ActiveRecord::RecordNotFound' => :not_found,
- 'ActiveRecord::StaleObjectError' => :conflict,
- 'ActiveRecord::RecordInvalid' => :unprocessable_entity,
- 'ActiveRecord::RecordNotSaved' => :unprocessable_entity
+ 'ActionController::RoutingError' => :not_found,
+ 'ActionController::UnknownAction' => :not_found,
+ 'ActiveRecord::RecordNotFound' => :not_found,
+ 'ActiveRecord::StaleObjectError' => :conflict,
+ 'ActiveRecord::RecordInvalid' => :unprocessable_entity,
+ 'ActiveRecord::RecordNotSaved' => :unprocessable_entity,
+ 'ActionController::MethodNotAllowed' => :method_not_allowed,
+ 'ActionController::NotImplemented' => :not_implemented
}
DEFAULT_RESCUE_TEMPLATE = 'diagnostics'
@@ -56,6 +58,12 @@ module ActionController #:nodoc:
log_error(exception) if logger
erase_results if performed?
+ # Let the exception alter the response if it wants.
+ # For example, MethodNotAllowed sets the Allow header.
+ if exception.respond_to?(:handle_response!)
+ exception.handle_response!(response)
+ end
+
if consider_all_requests_local || local_request?
rescue_action_locally(exception)
else
diff --git a/actionpack/lib/action_controller/routing.rb b/actionpack/lib/action_controller/routing.rb
index 00d5050b7e..4a1eda82bf 100644
--- a/actionpack/lib/action_controller/routing.rb
+++ b/actionpack/lib/action_controller/routing.rb
@@ -251,6 +251,8 @@ module ActionController
# TODO: , (comma) should be an allowed path character.
SEPARATORS = %w( / ; . , ? )
+ HTTP_METHODS = [:get, :head, :post, :put, :delete]
+
# The root paths which may contain controller files
mattr_accessor :controller_paths
self.controller_paths = []
@@ -1345,7 +1347,16 @@ module ActionController
routes.each do |route|
result = route.recognize(path, environment) and return result
end
- raise RoutingError, "no route found to match #{path.inspect} with #{environment.inspect}"
+
+ allows = HTTP_METHODS.select { |verb| routes.find { |r| r.recognize(path, :method => verb) } }
+
+ if environment[:method] && !HTTP_METHODS.include?(environment[:method])
+ raise NotImplemented.new(*allows)
+ elsif !allows.empty?
+ raise MethodNotAllowed.new(*allows)
+ else
+ raise RoutingError, "No route matches #{path.inspect} with #{environment.inspect}"
+ end
end
def routes_by_controller