0
Fork 0
mirror of https://github.com/ninenines/cowboy.git synced 2025-07-14 12:20:24 +00:00

Improve the error when trying to send a 204/304 with a body

This commit is contained in:
Loïc Hoguin 2024-01-09 10:59:40 +01:00
parent e4a78aaeb1
commit a40bab8fb3
No known key found for this signature in database
GPG key ID: 8A9DF795F6FED764
2 changed files with 16 additions and 11 deletions

View file

@ -813,20 +813,26 @@ reply(Status, Headers, SendFile = {sendfile, _, Len, _}, Req)
%% Neither status code must include a response body. (RFC7230 3.3) %% Neither status code must include a response body. (RFC7230 3.3)
reply(Status, Headers, Body, Req) reply(Status, Headers, Body, Req)
when Status =:= 204; Status =:= 304 -> when Status =:= 204; Status =:= 304 ->
0 = iolist_size(Body), do_reply_ensure_no_body(Status, Headers, Body, Req);
do_reply(Status, Headers, Body, Req);
reply(Status = <<"204",_/bits>>, Headers, Body, Req) -> reply(Status = <<"204",_/bits>>, Headers, Body, Req) ->
0 = iolist_size(Body), do_reply_ensure_no_body(Status, Headers, Body, Req);
do_reply(Status, Headers, Body, Req);
reply(Status = <<"304",_/bits>>, Headers, Body, Req) -> reply(Status = <<"304",_/bits>>, Headers, Body, Req) ->
0 = iolist_size(Body), do_reply_ensure_no_body(Status, Headers, Body, Req);
do_reply(Status, Headers, Body, Req);
reply(Status, Headers, Body, Req) reply(Status, Headers, Body, Req)
when is_integer(Status); is_binary(Status) -> when is_integer(Status); is_binary(Status) ->
do_reply(Status, Headers#{ do_reply(Status, Headers#{
<<"content-length">> => integer_to_binary(iolist_size(Body)) <<"content-length">> => integer_to_binary(iolist_size(Body))
}, Body, Req). }, Body, Req).
do_reply_ensure_no_body(Status, Headers, Body, Req) ->
case iolist_size(Body) of
0 ->
do_reply(Status, Headers, Body, Req);
_ ->
exit({response_error, payload_too_large,
'204 and 304 responses must not include a response body. (RFC7230 3.3)'})
end.
%% Don't send any body for HEAD responses. While the protocol code is %% Don't send any body for HEAD responses. While the protocol code is
%% supposed to enforce this rule, we prefer to avoid copying too much %% supposed to enforce this rule, we prefer to avoid copying too much
%% data around if we can avoid it. %% data around if we can avoid it.
@ -851,12 +857,11 @@ stream_reply(_, _, #{has_sent_resp := _}) ->
%% 204 and 304 responses must NOT send a body. We therefore %% 204 and 304 responses must NOT send a body. We therefore
%% transform the call to a full response and expect the user %% transform the call to a full response and expect the user
%% to NOT call stream_body/3 afterwards. (RFC7230 3.3) %% to NOT call stream_body/3 afterwards. (RFC7230 3.3)
stream_reply(Status = 204, Headers=#{}, Req) -> stream_reply(Status, Headers=#{}, Req)
when Status =:= 204; Status =:= 304 ->
reply(Status, Headers, <<>>, Req); reply(Status, Headers, <<>>, Req);
stream_reply(Status = <<"204",_/bits>>, Headers=#{}, Req) -> stream_reply(Status = <<"204",_/bits>>, Headers=#{}, Req) ->
reply(Status, Headers, <<>>, Req); reply(Status, Headers, <<>>, Req);
stream_reply(Status = 304, Headers=#{}, Req) ->
reply(Status, Headers, <<>>, Req);
stream_reply(Status = <<"304",_/bits>>, Headers=#{}, Req) -> stream_reply(Status = <<"304",_/bits>>, Headers=#{}, Req) ->
reply(Status, Headers, <<>>, Req); reply(Status, Headers, <<>>, Req);
stream_reply(Status, Headers=#{}, Req) when is_integer(Status); is_binary(Status) -> stream_reply(Status, Headers=#{}, Req) when is_integer(Status); is_binary(Status) ->

View file

@ -182,10 +182,10 @@ do(<<"reply4">>, Req0, Opts) ->
ct_helper:ignore(erlang, iolist_size, 1), ct_helper:ignore(erlang, iolist_size, 1),
cowboy_req:reply(200, #{}, ok, Req0); cowboy_req:reply(200, #{}, ok, Req0);
<<"204body">> -> <<"204body">> ->
ct_helper:ignore(cowboy_req, reply, 4), ct_helper:ignore(cowboy_req, do_reply_ensure_no_body, 4),
cowboy_req:reply(204, #{}, <<"OK">>, Req0); cowboy_req:reply(204, #{}, <<"OK">>, Req0);
<<"304body">> -> <<"304body">> ->
ct_helper:ignore(cowboy_req, reply, 4), ct_helper:ignore(cowboy_req, do_reply_ensure_no_body, 4),
cowboy_req:reply(304, #{}, <<"OK">>, Req0); cowboy_req:reply(304, #{}, <<"OK">>, Req0);
Status -> Status ->
cowboy_req:reply(binary_to_integer(Status), #{}, <<"OK">>, Req0) cowboy_req:reply(binary_to_integer(Status), #{}, <<"OK">>, Req0)