Skip to content

Commit

Permalink
Make it possible to configure how to handle unsupported HTTP methods …
Browse files Browse the repository at this point in the history
…in handlers
  • Loading branch information
ellmetha committed Sep 25, 2024
1 parent f9296fb commit 4318d74
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 2 deletions.
8 changes: 8 additions & 0 deletions docs/docs/development/reference/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ This setting allows you to configure whether an HTTP permanent redirect (301) sh
* `:add` - If the incoming URL does not end with a slash and does not match any routes, a redirect is issued to the same URL with a trailing slash appended.
* `:remove` - If the incoming URL ends with a slash and does not match any routes, a redirect is issued to the same URL with the trailing slash removed.

### `unsupported_http_method_strategy`

Default: `:deny`

The strategy to use when an unsupported HTTP method is encountered.

This setting allows you to configure the strategy to use when a handler processes an unsupported HTTP method. The default strategy is `:deny`, which means that the application will return a 405 Method Not Allowed response when an unsupported HTTP method is encountered. The other available strategy is `:hide`, which will results in 404 Not Found responses to be returned instead.

### `use_x_forwarded_host`

Default: `false`
Expand Down
23 changes: 23 additions & 0 deletions spec/marten/conf/global_settings_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,29 @@ describe Marten::Conf::GlobalSettings do
end
end

describe "#unsupported_http_method_strategy" do
it "returns :deny by default" do
global_settings = Marten::Conf::GlobalSettings.new
global_settings.unsupported_http_method_strategy.deny?.should be_true
end

it "returns the configured unsupported HTTP method strategy if explicitly set" do
global_settings = Marten::Conf::GlobalSettings.new
global_settings.unsupported_http_method_strategy = :hide

global_settings.unsupported_http_method_strategy.hide?.should be_true
end
end

describe "#unsupported_http_method_strategy=" do
it "allows to configure the unsupported HTTP method strategy" do
global_settings = Marten::Conf::GlobalSettings.new
global_settings.unsupported_http_method_strategy = :hide

global_settings.unsupported_http_method_strategy.hide?.should be_true
end
end

describe "#use_x_forwarded_host" do
it "returns false by default" do
global_settings = Marten::Conf::GlobalSettings.new
Expand Down
22 changes: 21 additions & 1 deletion spec/marten/handlers/base_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ describe Marten::Handlers::Base do
response.content.should eq "TRACE processed"
end

it "returns an HTTP Not Allowed responses for if the method is not handled by the handler" do
it "returns an HTTP Not Allowed response if the method is not handled by the handler" do
request = Marten::HTTP::Request.new(
::HTTP::Request.new(
method: "PATCH",
Expand All @@ -416,6 +416,26 @@ describe Marten::Handlers::Base do
response = handler.dispatch
response.status.should eq 405
end

it "returns an HTTP Not Found response if the method is not handled and the corresponding setting is set to hide" do
with_overridden_setting(
"unsupported_http_method_strategy",
Marten::Conf::GlobalSettings::UnsupportedHttpMethodStrategy::HIDE
) do
request = Marten::HTTP::Request.new(
::HTTP::Request.new(
method: "PATCH",
resource: "",
headers: HTTP::Headers{"Host" => "example.com"}
)
)
handler = Marten::Handlers::BaseSpec::Test1Handler.new(request)

expect_raises(Marten::HTTP::Errors::NotFound) do
handler.dispatch
end
end
end
end

describe "#head" do
Expand Down
12 changes: 12 additions & 0 deletions src/marten/conf/global_settings.cr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module Marten
@root_path : String?
@target_env : String?
@trailing_slash : TrailingSlash
@unsupported_http_method_strategy : UnsupportedHttpMethodStrategy

# Returns the explicit list of allowed hosts for the application.
getter allowed_hosts
Expand Down Expand Up @@ -84,6 +85,9 @@ module Marten
# Returns the trailing slash strategy.
getter trailing_slash

# Returns the strategy to use when an unsupported HTTP method is encountered.
getter unsupported_http_method_strategy

# Returns a boolean indicating whether the X-Forwarded-Host header is used to look for the host.
getter use_x_forwarded_host

Expand Down Expand Up @@ -172,6 +176,13 @@ module Marten
# from URLs if they can't be found.
setter trailing_slash

# Allows to set the strategy to use when an unsupported HTTP method is encountered.
#
# The default strategy is `:deny`, which means that the application will return a 405 Method Not Allowed response
# when an unsupported HTTP method is encountered. The other available strategy is `:hide`, which will results in
# 404 Not Found responses being returned instead.
setter unsupported_http_method_strategy

# Allows to set whether the X-Forwarded-Host header is used to look for the host.
setter use_x_forwarded_host

Expand Down Expand Up @@ -215,6 +226,7 @@ module Marten
@secret_key = ""
@time_zone = Time::Location.load("UTC")
@trailing_slash = :do_nothing
@unsupported_http_method_strategy = :deny
@use_x_forwarded_host = false
@use_x_forwarded_port = false
@use_x_forwarded_proto = false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module Marten
module Conf
class GlobalSettings
enum UnsupportedHttpMethodStrategy
DENY # Method Not Allowed (405)
HIDE # Not Found (404)
end
end
end
end
6 changes: 5 additions & 1 deletion src/marten/handlers/base.cr
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,11 @@ module Marten
end

private def handle_http_method_not_allowed
HTTP::Response::MethodNotAllowed.new(self.class.http_method_names)
if Marten.settings.unsupported_http_method_strategy.deny?
HTTP::Response::MethodNotAllowed.new(self.class.http_method_names)
else
raise Marten::HTTP::Errors::NotFound.new("Method not allowed")
end
end
end
end
Expand Down

0 comments on commit 4318d74

Please sign in to comment.