aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/src/manual/cowboy_http.asciidoc12
-rw-r--r--src/cowboy_http.erl11
-rw-r--r--test/http_SUITE.erl67
3 files changed, 89 insertions, 1 deletions
diff --git a/doc/src/manual/cowboy_http.asciidoc b/doc/src/manual/cowboy_http.asciidoc
index 96a5585..daa48a5 100644
--- a/doc/src/manual/cowboy_http.asciidoc
+++ b/doc/src/manual/cowboy_http.asciidoc
@@ -29,6 +29,8 @@ opts() :: #{
initial_stream_flow_size => non_neg_integer(),
linger_timeout => timeout(),
logger => module(),
+ max_authorization_header_value_length => non_neg_integer(),
+ max_cookie_header_value_length => non_neg_integer(),
max_empty_lines => non_neg_integer(),
max_header_name_length => non_neg_integer(),
max_header_value_length => non_neg_integer(),
@@ -131,6 +133,16 @@ logger (error_logger)::
The module that will be used to write log messages.
+max_authorization_header_value_length::
+
+Maximum length of the `authorization` header value.
+Defaults to the value of the option `max_header_value_length`.
+
+max_cookie_header_value_length::
+
+Maximum length of the `cookie` header value.
+Defaults to the value of the option `max_header_value_length`.
+
max_empty_lines (5)::
Maximum number of empty lines before a request.
diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl
index a2cf6c9..f1eabf1 100644
--- a/src/cowboy_http.erl
+++ b/src/cowboy_http.erl
@@ -703,7 +703,7 @@ parse_hd_before_value(<< $\s, Rest/bits >>, S, H, N) ->
parse_hd_before_value(<< $\t, Rest/bits >>, S, H, N) ->
parse_hd_before_value(Rest, S, H, N);
parse_hd_before_value(Buffer, State=#state{opts=Opts, in_state=PS}, H, N) ->
- MaxLength = maps:get(max_header_value_length, Opts, 4096),
+ MaxLength = max_header_value_length(N, Opts),
case match_eol(Buffer, 0) of
nomatch when byte_size(Buffer) > MaxLength ->
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) ->
parse_hd_value(Buffer, State, H, N, <<>>)
end.
+max_header_value_length(<<"authorization">>, #{max_authorization_header_value_length := Max}) ->
+ Max;
+max_header_value_length(<<"cookie">>, #{max_cookie_header_value_length := Max}) ->
+ Max;
+max_header_value_length(_, #{max_header_value_length := Max}) ->
+ Max;
+max_header_value_length(_, _) ->
+ 4096.
+
parse_hd_value(<< $\r, $\n, Rest/bits >>, S, Headers0, Name, SoFar) ->
Value = clean_value_ws_end(SoFar, byte_size(SoFar) - 1),
Headers = case maps:get(Name, Headers0, undefined) of
diff --git a/test/http_SUITE.erl b/test/http_SUITE.erl
index 9928136..51b4ac5 100644
--- a/test/http_SUITE.erl
+++ b/test/http_SUITE.erl
@@ -489,6 +489,73 @@ do_idle_timeout_recv_loop(Ref, Pid, ConnPid, StreamRef, ExpectCompletion) ->
error(timeout)
end.
+max_authorization_header_value_length(Config) ->
+ doc("Confirm the max_authorization_header_value_length option "
+ "correctly limits the length of authorization header values."),
+ {ok, _} = cowboy:start_clear(?FUNCTION_NAME, [{port, 0}], #{
+ env => #{dispatch => init_dispatch(Config)},
+ max_authorization_header_value_length => 2048
+ }),
+ Port = ranch:get_port(?FUNCTION_NAME),
+ try
+ do_max_header_value_length(Config, Port,
+ <<"authorization">>, 2048),
+ %% Confirm that other headers still use the default limit.
+ do_max_header_value_length(Config, Port,
+ <<"my-header">>, 4096)
+ after
+ cowboy:stop_listener(?FUNCTION_NAME)
+ end.
+
+max_cookie_header_value_length(Config) ->
+ doc("Confirm the max_cookie_header_value_length option "
+ "correctly limits the length of cookie header values."),
+ {ok, _} = cowboy:start_clear(?FUNCTION_NAME, [{port, 0}], #{
+ env => #{dispatch => init_dispatch(Config)},
+ max_cookie_header_value_length => 2048
+ }),
+ Port = ranch:get_port(?FUNCTION_NAME),
+ try
+ do_max_header_value_length(Config, Port,
+ <<"cookie">>, 2048),
+ %% Confirm that other headers still use the default limit.
+ do_max_header_value_length(Config, Port,
+ <<"my-header">>, 4096)
+ after
+ cowboy:stop_listener(?FUNCTION_NAME)
+ end.
+
+max_header_value_length(Config) ->
+ doc("Confirm the max_header_value_length option "
+ "correctly limits the length of header values."),
+ {ok, _} = cowboy:start_clear(?FUNCTION_NAME, [{port, 0}], #{
+ env => #{dispatch => init_dispatch(Config)},
+ max_header_value_length => 2048
+ }),
+ Port = ranch:get_port(?FUNCTION_NAME),
+ try
+ do_max_header_value_length(Config, Port,
+ <<"my-header">>, 2048)
+ after
+ cowboy:stop_listener(?FUNCTION_NAME)
+ end.
+
+max_header_value_length_default(Config) ->
+ doc("Confirm the max_header_value_length option "
+ "correctly limits the length of header values."),
+ do_max_header_value_length(Config, config(port, Config),
+ <<"my-header">>, 4096).
+
+do_max_header_value_length(Config, Port, Name, MaxLen) ->
+ ConnPid = gun_open([{type, tcp}, {protocol, http}, {port, Port}|Config]),
+ {ok, http} = gun:await_up(ConnPid),
+ StreamRef1 = gun:get(ConnPid, "/", #{Name => lists:duplicate(MaxLen, $a)}),
+ {response, nofin, 200, _} = gun:await(ConnPid, StreamRef1),
+ %% We * 2 because this is a soft limit.
+ StreamRef2 = gun:get(ConnPid, "/", #{Name => lists:duplicate(MaxLen * 2, $a)}),
+ {response, fin, 431, _} = gun:await(ConnPid, StreamRef2),
+ gun:close(ConnPid).
+
persistent_term_router(Config) ->
doc("The router can retrieve the routes from persistent_term storage."),
case erlang:function_exported(persistent_term, get, 1) of