aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2025-02-10 18:41:11 +0100
committerLoïc Hoguin <[email protected]>2025-02-10 18:41:11 +0100
commitf316a65906d97609c7a3f317c0b1dea95fc37e6c (patch)
tree5c2d52ba719ac8b1edf751cc8efbf1d0d4646b22
parent58402b416295c2bbedeb0f7855803dca4b9c1da3 (diff)
downloadcowboy-f316a65906d97609c7a3f317c0b1dea95fc37e6c.tar.gz
cowboy-f316a65906d97609c7a3f317c0b1dea95fc37e6c.tar.bz2
cowboy-f316a65906d97609c7a3f317c0b1dea95fc37e6c.zip
cowboy_rest: Always set the Allow header
Not just on 405 responses or OPTIONS requests.
-rw-r--r--src/cowboy_rest.erl40
-rw-r--r--test/rest_handler_SUITE.erl1
2 files changed, 11 insertions, 30 deletions
diff --git a/src/cowboy_rest.erl b/src/cowboy_rest.erl
index f0a9ff4..be33d03 100644
--- a/src/cowboy_rest.erl
+++ b/src/cowboy_rest.erl
@@ -246,9 +246,6 @@
handler :: atom(),
handler_state :: any(),
- %% Allowed methods. Only used for OPTIONS requests.
- allowed_methods :: [binary()] | undefined,
-
%% Media type.
content_types_p = [] ::
[{binary() | {binary(), binary(), [{binary(), binary()}] | '*'},
@@ -327,37 +324,26 @@ uri_too_long(Req, State) ->
%% allowed_methods/2 should return a list of binary methods.
allowed_methods(Req, State=#state{method=Method}) ->
case call(Req, State, allowed_methods) of
- no_call when Method =:= <<"HEAD">>; Method =:= <<"GET">> ->
- malformed_request(Req, State);
- no_call when Method =:= <<"OPTIONS">> ->
- malformed_request(Req, State#state{allowed_methods=
- [<<"HEAD">>, <<"GET">>, <<"OPTIONS">>]});
+ no_call when Method =:= <<"HEAD">>; Method =:= <<"GET">>; Method =:= <<"OPTIONS">> ->
+ Req2 = cowboy_req:set_resp_header(<<"allow">>, <<"HEAD, GET, OPTIONS">>, Req),
+ malformed_request(Req2, State);
no_call ->
- method_not_allowed(Req, State,
- [<<"HEAD">>, <<"GET">>, <<"OPTIONS">>]);
+ Req2 = cowboy_req:set_resp_header(<<"allow">>, <<"HEAD, GET, OPTIONS">>, Req),
+ respond(Req2, State, 405);
{stop, Req2, State2} ->
terminate(Req2, State2);
{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
switch_handler(Switch, Req2, State2);
{List, Req2, State2} ->
+ Req3 = cowboy_req:set_resp_header(<<"allow">>, cow_http_hd:allow(List), Req2),
case lists:member(Method, List) of
- true when Method =:= <<"OPTIONS">> ->
- malformed_request(Req2, State2#state{allowed_methods=List});
true ->
- malformed_request(Req2, State2);
+ malformed_request(Req3, State2);
false ->
- method_not_allowed(Req2, State2, List)
+ respond(Req3, State2, 405)
end
end.
-method_not_allowed(Req, State, []) ->
- Req2 = cowboy_req:set_resp_header(<<"allow">>, <<>>, Req),
- respond(Req2, State, 405);
-method_not_allowed(Req, State, Methods) ->
- << ", ", Allow/binary >> = << << ", ", M/binary >> || M <- Methods >>,
- Req2 = cowboy_req:set_resp_header(<<"allow">>, Allow, Req),
- respond(Req2, State, 405).
-
malformed_request(Req, State) ->
expect(Req, State, malformed_request, false, fun is_authorized/2, 400).
@@ -411,16 +397,10 @@ valid_entity_length(Req, State) ->
%% If you need to add additional headers to the response at this point,
%% you should do it directly in the options/2 call using set_resp_headers.
-options(Req, State=#state{allowed_methods=Methods, method= <<"OPTIONS">>}) ->
+options(Req, State=#state{method= <<"OPTIONS">>}) ->
case call(Req, State, options) of
- no_call when Methods =:= [] ->
- Req2 = cowboy_req:set_resp_header(<<"allow">>, <<>>, Req),
- respond(Req2, State, 200);
no_call ->
- << ", ", Allow/binary >>
- = << << ", ", M/binary >> || M <- Methods >>,
- Req2 = cowboy_req:set_resp_header(<<"allow">>, Allow, Req),
- respond(Req2, State, 200);
+ respond(Req, State, 200);
{stop, Req2, State2} ->
terminate(Req2, State2);
{Switch, Req2, State2} when element(1, Switch) =:= switch_handler ->
diff --git a/test/rest_handler_SUITE.erl b/test/rest_handler_SUITE.erl
index 324a50c..b739e4d 100644
--- a/test/rest_handler_SUITE.erl
+++ b/test/rest_handler_SUITE.erl
@@ -817,6 +817,7 @@ provide_callback(Config) ->
]),
{response, nofin, 200, Headers} = gun:await(ConnPid, Ref),
{_, <<"text/plain">>} = lists:keyfind(<<"content-type">>, 1, Headers),
+ {_, <<"HEAD, GET, OPTIONS">>} = lists:keyfind(<<"allow">>, 1, Headers),
{ok, <<"This is REST!">>} = gun:await_body(ConnPid, Ref),
ok.