From 3eaf525213ccef5c63c9e296fa643ad416a3f84c Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Fri, 15 Jan 2010 12:35:18 -0600 Subject: Make HEAD method masquerade as GET so requests are routed correctly --- actionpack/lib/action_dispatch.rb | 1 + actionpack/lib/action_dispatch/http/request.rb | 12 +++++++----- actionpack/lib/action_dispatch/middleware/head.rb | 18 ++++++++++++++++++ actionpack/test/abstract_unit.rb | 2 +- actionpack/test/controller/integration_test.rb | 13 +++++++++++++ actionpack/test/dispatch/request_test.rb | 4 ++-- railties/lib/rails/configuration.rb | 2 +- railties/test/application/middleware_test.rb | 2 +- 8 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 actionpack/lib/action_dispatch/middleware/head.rb diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index ad6d54b6a2..f6d693d6f0 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -43,6 +43,7 @@ module ActionDispatch autoload_under 'middleware' do autoload :Callbacks autoload :Cascade + autoload :Head autoload :ParamsParser autoload :Rescue autoload :ShowExceptions diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 6e8a5dcb8a..3d0aab8a06 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -35,7 +35,8 @@ module ActionDispatch # :get. If the request \method is not listed in the HTTP_METHODS # constant above, an UnknownHttpMethod exception is raised. def request_method - HTTP_METHOD_LOOKUP[super] || raise(ActionController::UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}") + method = env["rack.methodoverride.original_method"] || env["REQUEST_METHOD"] + HTTP_METHOD_LOOKUP[method] || raise(ActionController::UnknownHttpMethod, "#{method}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}") end # Returns the HTTP request \method used for action processing as a @@ -43,7 +44,8 @@ module ActionDispatch # method returns :get for a HEAD request because the two are # functionally equivalent from the application's perspective.) def method - request_method == :head ? :get : request_method + method = env["REQUEST_METHOD"] + HTTP_METHOD_LOOKUP[method] || raise(ActionController::UnknownHttpMethod, "#{method}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}") end # Is this a GET (or HEAD) request? Equivalent to request.method == :get. @@ -53,17 +55,17 @@ module ActionDispatch # Is this a POST request? Equivalent to request.method == :post. def post? - request_method == :post + method == :post end # Is this a PUT request? Equivalent to request.method == :put. def put? - request_method == :put + method == :put end # Is this a DELETE request? Equivalent to request.method == :delete. def delete? - request_method == :delete + method == :delete end # Is this a HEAD request? Since request.method sees HEAD as :get, diff --git a/actionpack/lib/action_dispatch/middleware/head.rb b/actionpack/lib/action_dispatch/middleware/head.rb new file mode 100644 index 0000000000..56e2d2f2a8 --- /dev/null +++ b/actionpack/lib/action_dispatch/middleware/head.rb @@ -0,0 +1,18 @@ +module ActionDispatch + class Head + def initialize(app) + @app = app + end + + def call(env) + if env["REQUEST_METHOD"] == "HEAD" + env["REQUEST_METHOD"] = "GET" + env["rack.methodoverride.original_method"] = "HEAD" + status, headers, body = @app.call(env) + [status, headers, []] + else + @app.call(env) + end + end + end +end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 3e631d45df..f26542b31e 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -91,7 +91,7 @@ class ActionController::IntegrationTest < ActiveSupport::TestCase middleware.use "ActionDispatch::ShowExceptions" middleware.use "ActionDispatch::Callbacks" middleware.use "ActionDispatch::ParamsParser" - middleware.use "Rack::Head" + middleware.use "ActionDispatch::Head" }.build(routes || ActionController::Routing::Routes) end diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 624b14e69b..683ab5236c 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -254,6 +254,10 @@ class IntegrationProcessTest < ActionController::IntegrationTest render :text => "Created", :status => 201 end + def method + render :text => "method: #{request.method}" + end + def cookie_monster cookies["cookie_1"] = nil cookies["cookie_3"] = "chocolate" @@ -379,6 +383,14 @@ class IntegrationProcessTest < ActionController::IntegrationTest head '/post' assert_equal 201, status assert_equal "", body + + get '/get/method' + assert_equal 200, status + assert_equal "method: get", body + + head '/get/method' + assert_equal 200, status + assert_equal "", body end end @@ -391,6 +403,7 @@ class IntegrationProcessTest < ActionController::IntegrationTest with_routing do |set| set.draw do |map| match ':action', :to => ::IntegrationProcessTest::IntegrationController + get 'get/:action', :to => ::IntegrationProcessTest::IntegrationController end yield end diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index b62df9a6b2..cb95ecea50 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -319,7 +319,7 @@ class RequestTest < ActiveSupport::TestCase end test "allow method hacking on post" do - [:get, :head, :options, :put, :post, :delete].each do |method| + [:get, :options, :put, :post, :delete].each do |method| request = stub_request "REQUEST_METHOD" => method.to_s.upcase assert_equal(method == :head ? :get : method, request.method) end @@ -341,7 +341,7 @@ class RequestTest < ActiveSupport::TestCase end test "head masquerading as get" do - request = stub_request 'REQUEST_METHOD' => 'HEAD' + request = stub_request 'REQUEST_METHOD' => 'GET', "rack.methodoverride.original_method" => "HEAD" assert_equal :get, request.method assert request.get? assert request.head? diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index 9991288cc5..cf452ac611 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -18,7 +18,7 @@ module Rails middleware.use(lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options }) middleware.use('ActionDispatch::ParamsParser') middleware.use('::Rack::MethodOverride') - middleware.use('::Rack::Head') + middleware.use('::ActionDispatch::Head') end end diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 8ba3a7bdfc..c2b8db495f 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -23,7 +23,7 @@ module ApplicationTests "ActionDispatch::Cascade", "ActionDispatch::ParamsParser", "Rack::MethodOverride", - "Rack::Head", + "ActionDispatch::Head", "ActiveRecord::ConnectionAdapters::ConnectionManagement", "ActiveRecord::QueryCache" ], middleware -- cgit v1.2.3