Skip to content

Commit 802858b

Browse files
MarkoMinessen
authored andcommitted
HTTP/1: Allow independent max authorization/cookie length
Adds two options: * max_authorization_header_value_length to configure the maximum length of the authorization header specifically; * max_cookie_header_value_length to configure the maximum length of the cookie header specifically. LH: I added the relevant tests.
1 parent 495e74a commit 802858b

File tree

3 files changed

+89
-1
lines changed

3 files changed

+89
-1
lines changed

doc/src/manual/cowboy_http.asciidoc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ opts() :: #{
2929
initial_stream_flow_size => non_neg_integer(),
3030
linger_timeout => timeout(),
3131
logger => module(),
32+
max_authorization_header_value_length => non_neg_integer(),
33+
max_cookie_header_value_length => non_neg_integer(),
3234
max_empty_lines => non_neg_integer(),
3335
max_header_name_length => non_neg_integer(),
3436
max_header_value_length => non_neg_integer(),
@@ -131,6 +133,16 @@ logger (error_logger)::
131133

132134
The module that will be used to write log messages.
133135

136+
max_authorization_header_value_length::
137+
138+
Maximum length of the `authorization` header value.
139+
Defaults to the value of the option `max_header_value_length`.
140+
141+
max_cookie_header_value_length::
142+
143+
Maximum length of the `cookie` header value.
144+
Defaults to the value of the option `max_header_value_length`.
145+
134146
max_empty_lines (5)::
135147

136148
Maximum number of empty lines before a request.

src/cowboy_http.erl

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ parse_hd_before_value(<< $\s, Rest/bits >>, S, H, N) ->
703703
parse_hd_before_value(<< $\t, Rest/bits >>, S, H, N) ->
704704
parse_hd_before_value(Rest, S, H, N);
705705
parse_hd_before_value(Buffer, State=#state{opts=Opts, in_state=PS}, H, N) ->
706-
MaxLength = maps:get(max_header_value_length, Opts, 4096),
706+
MaxLength = max_header_value_length(N, Opts),
707707
case match_eol(Buffer, 0) of
708708
nomatch when byte_size(Buffer) > MaxLength ->
709709
error_terminate(431, State#state{in_state=PS#ps_header{headers=H}},
@@ -715,6 +715,15 @@ parse_hd_before_value(Buffer, State=#state{opts=Opts, in_state=PS}, H, N) ->
715715
parse_hd_value(Buffer, State, H, N, <<>>)
716716
end.
717717

718+
max_header_value_length(<<"authorization">>, #{max_authorization_header_value_length := Max}) ->
719+
Max;
720+
max_header_value_length(<<"cookie">>, #{max_cookie_header_value_length := Max}) ->
721+
Max;
722+
max_header_value_length(_, #{max_header_value_length := Max}) ->
723+
Max;
724+
max_header_value_length(_, _) ->
725+
4096.
726+
718727
parse_hd_value(<< $\r, $\n, Rest/bits >>, S, Headers0, Name, SoFar) ->
719728
Value = clean_value_ws_end(SoFar, byte_size(SoFar) - 1),
720729
Headers = case maps:get(Name, Headers0, undefined) of

test/http_SUITE.erl

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,73 @@ do_idle_timeout_recv_loop(Ref, Pid, ConnPid, StreamRef, ExpectCompletion) ->
489489
error(timeout)
490490
end.
491491

492+
max_authorization_header_value_length(Config) ->
493+
doc("Confirm the max_authorization_header_value_length option "
494+
"correctly limits the length of authorization header values."),
495+
{ok, _} = cowboy:start_clear(?FUNCTION_NAME, [{port, 0}], #{
496+
env => #{dispatch => init_dispatch(Config)},
497+
max_authorization_header_value_length => 2048
498+
}),
499+
Port = ranch:get_port(?FUNCTION_NAME),
500+
try
501+
do_max_header_value_length(Config, Port,
502+
<<"authorization">>, 2048),
503+
%% Confirm that other headers still use the default limit.
504+
do_max_header_value_length(Config, Port,
505+
<<"my-header">>, 4096)
506+
after
507+
cowboy:stop_listener(?FUNCTION_NAME)
508+
end.
509+
510+
max_cookie_header_value_length(Config) ->
511+
doc("Confirm the max_cookie_header_value_length option "
512+
"correctly limits the length of cookie header values."),
513+
{ok, _} = cowboy:start_clear(?FUNCTION_NAME, [{port, 0}], #{
514+
env => #{dispatch => init_dispatch(Config)},
515+
max_cookie_header_value_length => 2048
516+
}),
517+
Port = ranch:get_port(?FUNCTION_NAME),
518+
try
519+
do_max_header_value_length(Config, Port,
520+
<<"cookie">>, 2048),
521+
%% Confirm that other headers still use the default limit.
522+
do_max_header_value_length(Config, Port,
523+
<<"my-header">>, 4096)
524+
after
525+
cowboy:stop_listener(?FUNCTION_NAME)
526+
end.
527+
528+
max_header_value_length(Config) ->
529+
doc("Confirm the max_header_value_length option "
530+
"correctly limits the length of header values."),
531+
{ok, _} = cowboy:start_clear(?FUNCTION_NAME, [{port, 0}], #{
532+
env => #{dispatch => init_dispatch(Config)},
533+
max_header_value_length => 2048
534+
}),
535+
Port = ranch:get_port(?FUNCTION_NAME),
536+
try
537+
do_max_header_value_length(Config, Port,
538+
<<"my-header">>, 2048)
539+
after
540+
cowboy:stop_listener(?FUNCTION_NAME)
541+
end.
542+
543+
max_header_value_length_default(Config) ->
544+
doc("Confirm the max_header_value_length option "
545+
"correctly limits the length of header values."),
546+
do_max_header_value_length(Config, config(port, Config),
547+
<<"my-header">>, 4096).
548+
549+
do_max_header_value_length(Config, Port, Name, MaxLen) ->
550+
ConnPid = gun_open([{type, tcp}, {protocol, http}, {port, Port}|Config]),
551+
{ok, http} = gun:await_up(ConnPid),
552+
StreamRef1 = gun:get(ConnPid, "/", #{Name => lists:duplicate(MaxLen, $a)}),
553+
{response, nofin, 200, _} = gun:await(ConnPid, StreamRef1),
554+
%% We * 2 because this is a soft limit.
555+
StreamRef2 = gun:get(ConnPid, "/", #{Name => lists:duplicate(MaxLen * 2, $a)}),
556+
{response, fin, 431, _} = gun:await(ConnPid, StreamRef2),
557+
gun:close(ConnPid).
558+
492559
persistent_term_router(Config) ->
493560
doc("The router can retrieve the routes from persistent_term storage."),
494561
case erlang:function_exported(persistent_term, get, 1) of

0 commit comments

Comments
 (0)