mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 20:30:23 +00:00
Don't send the content-length header in empty 304 responses
It's OK to send it when set explicitly, as it can be set to what the representation's size would have been.
This commit is contained in:
parent
4fedb33631
commit
292039362a
4 changed files with 74 additions and 5 deletions
|
@ -963,6 +963,8 @@ commands(State0=#state{socket=Socket, transport=Transport, streams=Streams0, out
|
||||||
{State1, Headers1} = case {Status, ContentLength, Version} of
|
{State1, Headers1} = case {Status, ContentLength, Version} of
|
||||||
{204, _, 'HTTP/1.1'} ->
|
{204, _, 'HTTP/1.1'} ->
|
||||||
{State0#state{out_state=done}, Headers0};
|
{State0#state{out_state=done}, Headers0};
|
||||||
|
{304, _, 'HTTP/1.1'} ->
|
||||||
|
{State0#state{out_state=done}, Headers0};
|
||||||
{_, undefined, 'HTTP/1.1'} ->
|
{_, undefined, 'HTTP/1.1'} ->
|
||||||
{State0#state{out_state=chunked}, Headers0#{<<"transfer-encoding">> => <<"chunked">>}};
|
{State0#state{out_state=chunked}, Headers0#{<<"transfer-encoding">> => <<"chunked">>}};
|
||||||
%% Close the connection after streaming without content-length to HTTP/1.0 client.
|
%% Close the connection after streaming without content-length to HTTP/1.0 client.
|
||||||
|
|
|
@ -771,11 +771,15 @@ reply(Status, Headers, SendFile = {sendfile, _, Len, _}, Req)
|
||||||
do_reply(Status, Headers#{
|
do_reply(Status, Headers#{
|
||||||
<<"content-length">> => integer_to_binary(Len)
|
<<"content-length">> => integer_to_binary(Len)
|
||||||
}, SendFile, Req);
|
}, SendFile, Req);
|
||||||
%% 204 responses must not include content-length. (RFC7230 3.3.1, RFC7230 3.3.2)
|
%% 204 responses must not include content-length. 304 responses may
|
||||||
reply(Status=204, Headers, Body, Req) ->
|
%% but only when set explicitly. (RFC7230 3.3.1, RFC7230 3.3.2)
|
||||||
|
reply(Status, Headers, Body, Req)
|
||||||
|
when Status =:= 204; Status =:= 304 ->
|
||||||
do_reply(Status, Headers, Body, Req);
|
do_reply(Status, Headers, Body, Req);
|
||||||
reply(Status= <<"204",_/bits>>, Headers, Body, Req) ->
|
reply(Status= <<"204",_/bits>>, Headers, Body, Req) ->
|
||||||
do_reply(Status, Headers, Body, Req);
|
do_reply(Status, Headers, Body, Req);
|
||||||
|
reply(Status= <<"304",_/bits>>, 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#{
|
||||||
|
|
|
@ -186,6 +186,9 @@ do(<<"stream_reply2">>, Req0, Opts) ->
|
||||||
<<"204">> ->
|
<<"204">> ->
|
||||||
Req = cowboy_req:stream_reply(204, Req0),
|
Req = cowboy_req:stream_reply(204, Req0),
|
||||||
{ok, Req, Opts};
|
{ok, Req, Opts};
|
||||||
|
<<"304">> ->
|
||||||
|
Req = cowboy_req:stream_reply(304, Req0),
|
||||||
|
{ok, Req, Opts};
|
||||||
Status ->
|
Status ->
|
||||||
Req = cowboy_req:stream_reply(binary_to_integer(Status), Req0),
|
Req = cowboy_req:stream_reply(binary_to_integer(Status), Req0),
|
||||||
stream_body(Req),
|
stream_body(Req),
|
||||||
|
|
|
@ -1745,9 +1745,55 @@ no_body_in_head_response(Config) ->
|
||||||
%no_body_in_100_response(Config) ->
|
%no_body_in_100_response(Config) ->
|
||||||
%no_body_in_101_response(Config) ->
|
%no_body_in_101_response(Config) ->
|
||||||
%no_body_in_102_response(Config) ->
|
%no_body_in_102_response(Config) ->
|
||||||
%no_body_in_204_response(Config) ->
|
%1xx responses never include a message body. (RFC7230 3.3)
|
||||||
%no_body_in_304_response(Config) ->
|
|
||||||
%1xx, 204 and 304 responses never include a message body. (RFC7230 3.3)
|
no_body_in_204_response(Config) ->
|
||||||
|
doc("204 responses never include a message body. (RFC7230 3.3)"),
|
||||||
|
Client = raw_open(Config),
|
||||||
|
ok = raw_send(Client, [
|
||||||
|
"GET /resp/reply2/204 HTTP/1.1\r\n"
|
||||||
|
"Host: localhost\r\n"
|
||||||
|
"\r\n"]),
|
||||||
|
{_, 204, _, Rest} = cow_http:parse_status_line(raw_recv_head(Client)),
|
||||||
|
{_, <<>>} = cow_http:parse_headers(Rest),
|
||||||
|
{error, timeout} = raw_recv(Client, 1, 1000),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
no_body_in_204_response_stream(Config) ->
|
||||||
|
doc("204 responses never include a message body. (RFC7230 3.3)"),
|
||||||
|
Client = raw_open(Config),
|
||||||
|
ok = raw_send(Client, [
|
||||||
|
"GET /resp/stream_reply2/204 HTTP/1.1\r\n"
|
||||||
|
"Host: localhost\r\n"
|
||||||
|
"\r\n"]),
|
||||||
|
{_, 204, _, Rest} = cow_http:parse_status_line(raw_recv_head(Client)),
|
||||||
|
{_, <<>>} = cow_http:parse_headers(Rest),
|
||||||
|
{error, timeout} = raw_recv(Client, 1, 1000),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
no_body_in_304_response(Config) ->
|
||||||
|
doc("304 responses never include a message body. (RFC7230 3.3)"),
|
||||||
|
Client = raw_open(Config),
|
||||||
|
ok = raw_send(Client, [
|
||||||
|
"GET /resp/reply2/304 HTTP/1.1\r\n"
|
||||||
|
"Host: localhost\r\n"
|
||||||
|
"\r\n"]),
|
||||||
|
{_, 304, _, Rest} = cow_http:parse_status_line(raw_recv_head(Client)),
|
||||||
|
{_, <<>>} = cow_http:parse_headers(Rest),
|
||||||
|
{error, timeout} = raw_recv(Client, 1, 1000),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
no_body_in_304_response_stream(Config) ->
|
||||||
|
doc("304 responses never include a message body. (RFC7230 3.3)"),
|
||||||
|
Client = raw_open(Config),
|
||||||
|
ok = raw_send(Client, [
|
||||||
|
"GET /resp/stream_reply2/304 HTTP/1.1\r\n"
|
||||||
|
"Host: localhost\r\n"
|
||||||
|
"\r\n"]),
|
||||||
|
{_, 304, _, Rest} = cow_http:parse_status_line(raw_recv_head(Client)),
|
||||||
|
{_, <<>>} = cow_http:parse_headers(Rest),
|
||||||
|
{error, timeout} = raw_recv(Client, 1, 1000),
|
||||||
|
ok.
|
||||||
|
|
||||||
same_content_length_as_get_in_head_response(Config) ->
|
same_content_length_as_get_in_head_response(Config) ->
|
||||||
doc("Responses to HEAD requests can include a content-length header. "
|
doc("Responses to HEAD requests can include a content-length header. "
|
||||||
|
@ -1802,6 +1848,20 @@ no_content_length_in_204_response(Config) ->
|
||||||
false = lists:keyfind(<<"content-length">>, 1, Headers),
|
false = lists:keyfind(<<"content-length">>, 1, Headers),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
no_content_length_in_empty_304_response(Config) ->
|
||||||
|
doc("304 responses should not include a content-length header, "
|
||||||
|
"unless it matches the resource's and was therefore set "
|
||||||
|
"explicitly by the user. (RFC7230 3.3.1, RFC7230 3.3.2)"),
|
||||||
|
Client = raw_open(Config),
|
||||||
|
ok = raw_send(Client, [
|
||||||
|
"GET /resp/reply3/304 HTTP/1.1\r\n"
|
||||||
|
"Host: localhost\r\n"
|
||||||
|
"\r\n"]),
|
||||||
|
{_, 304, _, Rest} = cow_http:parse_status_line(raw_recv_head(Client)),
|
||||||
|
{Headers, <<>>} = cow_http:parse_headers(Rest),
|
||||||
|
false = lists:keyfind(<<"content-length">>, 1, Headers),
|
||||||
|
ok.
|
||||||
|
|
||||||
%%% @todo CONNECT no_content_length_in_2xx_response_to_connect_request(Config) ->
|
%%% @todo CONNECT no_content_length_in_2xx_response_to_connect_request(Config) ->
|
||||||
%no_transfer_encoding_in_100_response(Config) ->
|
%no_transfer_encoding_in_100_response(Config) ->
|
||||||
%no_transfer_encoding_in_101_response(Config) ->
|
%no_transfer_encoding_in_101_response(Config) ->
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue