diff options
4 files changed, 56 insertions, 2 deletions
diff --git a/actionwebservice/CHANGELOG b/actionwebservice/CHANGELOG index c243b6a343..7913609587 100644 --- a/actionwebservice/CHANGELOG +++ b/actionwebservice/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Allow action_web_service to handle various HTTP methods including GET. Closes #7011. [zackchandler] + * Ensure that DispatcherError is being thrown when a malformed request is received. [Kent Sibilev] * Added support for decimal types. Closes #6676. [Kent Sibilev] diff --git a/actionwebservice/lib/action_web_service/api.rb b/actionwebservice/lib/action_web_service/api.rb index 73fb886e6d..d97eb5e6a1 100644 --- a/actionwebservice/lib/action_web_service/api.rb +++ b/actionwebservice/lib/action_web_service/api.rb @@ -21,6 +21,9 @@ module ActionWebService # :nodoc: # Whether to transform the public API method names into camel-cased names class_inheritable_option :inflect_names, true + # By default only HTTP POST requests are processed + class_inheritable_option :allowed_http_methods, [ :post ] + # Whether to allow ActiveRecord::Base models in <tt>:expects</tt>. # The default is +false+; you should be aware of the security implications # of allowing this, and ensure that you don't allow remote callers to diff --git a/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb b/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb index 85773a617d..9c16c50248 100644 --- a/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +++ b/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb @@ -37,8 +37,11 @@ module ActionWebService # :nodoc: module InstanceMethods # :nodoc: private def dispatch_web_service_request - if request.get? - render_text('GET not supported', '500 GET not supported') + method = request.method.to_s.upcase + allowed_methods = self.class.web_service_api ? (self.class.web_service_api.allowed_http_methods.dup || []) : [ :post ] + allowed_methods.map!{|m| m.to_s.upcase } + if !allowed_methods.include?(method) + render_text("#{method} not supported", "500 #{method} not supported") return end exception = nil diff --git a/actionwebservice/test/abstract_dispatcher.rb b/actionwebservice/test/abstract_dispatcher.rb index 8d7c98a916..c15af41797 100644 --- a/actionwebservice/test/abstract_dispatcher.rb +++ b/actionwebservice/test/abstract_dispatcher.rb @@ -426,6 +426,43 @@ module DispatcherCommonTests assert_match /Web Service Request/, buf end + def test_allowed_http_methods + webservice_api = @direct_controller.class.web_service_api + original_allowed_http_methods = webservice_api.allowed_http_methods + + # check defaults + assert_equal false, http_method_allowed?(:get) + assert_equal false, http_method_allowed?(:head) + assert_equal false, http_method_allowed?(:put) + assert_equal false, http_method_allowed?(:delete) + assert_equal false, http_method_allowed?(:trace) + assert_equal false, http_method_allowed?(:connect) + assert_equal true, http_method_allowed?(:post) + + # allow get and post + webservice_api.allowed_http_methods = [ :get, :post ] + assert_equal true, http_method_allowed?(:get) + assert_equal true, http_method_allowed?(:post) + + # allow get only + webservice_api.allowed_http_methods = [ :get ] + assert_equal true, http_method_allowed?(:get) + assert_equal false, http_method_allowed?(:post) + + # allow delete only + webservice_api.allowed_http_methods = [ 'DELETE' ] + assert_equal false, http_method_allowed?(:get) + assert_equal false, http_method_allowed?(:head) + assert_equal false, http_method_allowed?(:post) + assert_equal false, http_method_allowed?(:put) + assert_equal false, http_method_allowed?(:trace) + assert_equal false, http_method_allowed?(:connect) + assert_equal true, http_method_allowed?(:delete) + + ensure + webservice_api.allowed_http_methods = original_allowed_http_methods + end + protected def service_name(container) raise NotImplementedError @@ -502,4 +539,13 @@ module DispatcherCommonTests end return_value end + + def http_method_allowed?(method) + method = method.to_s.upcase + test_request = ActionController::TestRequest.new({ 'action' => 'api' }) + test_response = ActionController::TestResponse.new + test_request.env['REQUEST_METHOD'] = method + result = @direct_controller.process(test_request, test_response) + result.body =~ /(GET|POST|PUT|DELETE|TRACE|CONNECT) not supported/ ? false : true + end end |