From 3f7c8b45772cbc5c5459d8a4f5ee501e917f2457 Mon Sep 17 00:00:00 2001 From: Serdar Dogruyol Date: Fri, 26 Oct 2018 15:00:24 +0300 Subject: [PATCH 1/2] Add Kemal::OverrideMethodHandler --- spec/override_method_handler_spec.cr | 29 ++++++++++++++++++++++++++++ src/kemal/override_method_handler.cr | 24 +++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 spec/override_method_handler_spec.cr create mode 100644 src/kemal/override_method_handler.cr diff --git a/spec/override_method_handler_spec.cr b/spec/override_method_handler_spec.cr new file mode 100644 index 0000000..2b34e29 --- /dev/null +++ b/spec/override_method_handler_spec.cr @@ -0,0 +1,29 @@ +require "./spec_helper" + +describe "Kemal::OverrideMethodHandler" do + it "does not override method without _method for POST requests" do + request = HTTP::Request.new( + "POST", + "/", + body: "_not_method=PATCH", + headers: HTTP::Headers{"Content-Type" => "application/x-www-form-urlencoded; charset=UTF-8"} + ) + + context = create_request_and_return_io_and_context(Kemal::OverrideMethodHandler::INSTANCE, request)[1] + + context.request.method.should eq "POST" + end + + it "overrides method with _method for POST requests" do + request = HTTP::Request.new( + "POST", + "/", + body: "_method=PATCH", + headers: HTTP::Headers{"Content-Type" => "application/x-www-form-urlencoded; charset=UTF-8"} + ) + + context = create_request_and_return_io_and_context(Kemal::OverrideMethodHandler::INSTANCE, request)[1] + + context.request.method.should eq "PATCH" + end +end diff --git a/src/kemal/override_method_handler.cr b/src/kemal/override_method_handler.cr new file mode 100644 index 0000000..097dee9 --- /dev/null +++ b/src/kemal/override_method_handler.cr @@ -0,0 +1,24 @@ +module Kemal + class OverrideMethodHandler + include HTTP::Handler + INSTANCE = new + + ALLOWED_METHODS = ["PUT", "PATCH", "DELETE"] + OVERRIDE_METHOD = "POST" + OVERRIDE_METHOD_PARAM_KEY = "_method" + + def call(context) + request = context.request + if request.method == OVERRIDE_METHOD + if context.params.body.has_key?(OVERRIDE_METHOD_PARAM_KEY) && override_method_valid?(context.params.body["_method"]) + request.method = context.params.body["_method"].upcase + end + end + call_next(context) + end + + def override_method_valid?(override_method : String) + ALLOWED_METHODS.includes?(override_method.upcase) + end + end +end From a60168d0396b4907dfcfab9f78685c43e45b2efb Mon Sep 17 00:00:00 2001 From: Serdar Dogruyol Date: Fri, 26 Oct 2018 18:45:04 +0300 Subject: [PATCH 2/2] Add docs to Kemal::OverrideMethodHandler --- src/kemal/override_method_handler.cr | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/kemal/override_method_handler.cr b/src/kemal/override_method_handler.cr index 097dee9..523e9e6 100644 --- a/src/kemal/override_method_handler.cr +++ b/src/kemal/override_method_handler.cr @@ -1,4 +1,13 @@ module Kemal + # Adds support for `_method` magic parameter to simulate PUT, PATCH, DELETE requests in an html form. + # + # This middleware is **not** in the default Kemal handlers. You need to explicitly add this to your handlers: + # + # ```ruby + # add_handler Kemal::OverrideMethodHandler + # ``` + # + # **Important:** This middleware consumes `params.body` to read the `_method` magic parameter. class OverrideMethodHandler include HTTP::Handler INSTANCE = new @@ -10,14 +19,14 @@ module Kemal def call(context) request = context.request if request.method == OVERRIDE_METHOD - if context.params.body.has_key?(OVERRIDE_METHOD_PARAM_KEY) && override_method_valid?(context.params.body["_method"]) + if context.params.body.has_key?(OVERRIDE_METHOD_PARAM_KEY) && override_method_valid?(context.params.body[OVERRIDE_METHOD_PARAM_KEY]) request.method = context.params.body["_method"].upcase end end call_next(context) end - def override_method_valid?(override_method : String) + private def override_method_valid?(override_method : String) ALLOWED_METHODS.includes?(override_method.upcase) end end