From 02b1b281785a815ff5b4c7bfc45053f0c786a18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Sun, 21 Dec 2014 16:23:46 +0200 Subject: Discard whitespace at the end of header values early This is more in line with what RC7230 says, and will allow simplifying the parsing code of a few headers in cowlib. --- src/cowboy_protocol.erl | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/cowboy_protocol.erl b/src/cowboy_protocol.erl index e469bc7..558dcc3 100644 --- a/src/cowboy_protocol.erl +++ b/src/cowboy_protocol.erl @@ -348,7 +348,7 @@ parse_hd_value(<< $\r, Rest/bits >>, S, M, P, Q, V, Headers, Name, SoFar) -> parse_hd_value(Rest2, S, M, P, Q, V, Headers, Name, << SoFar/binary, C >>); << $\n, Rest2/bits >> -> - parse_header(Rest2, S, M, P, Q, V, [{Name, SoFar}|Headers]) + parse_header(Rest2, S, M, P, Q, V, [{Name, clean_value_ws_end(SoFar, byte_size(SoFar) - 1)}|Headers]) end; parse_hd_value(<< C, Rest/bits >>, S, M, P, Q, V, H, N, SoFar) -> parse_hd_value(Rest, S, M, P, Q, V, H, N, << SoFar/binary, C >>); @@ -358,6 +358,42 @@ parse_hd_value(<<>>, State=#state{max_header_value_length=MaxLength}, parse_hd_value(<<>>, S, M, P, Q, V, H, N, SoFar) -> wait_hd_value(<<>>, S, M, P, Q, V, H, N, SoFar). +clean_value_ws_end(_, -1) -> + <<>>; +clean_value_ws_end(Value, N) -> + case binary:at(Value, N) of + $\s -> clean_value_ws_end(Value, N - 1); + $\t -> clean_value_ws_end(Value, N - 1); + _ -> + S = N + 1, + << Value2:S/binary, _/bits >> = Value, + Value2 + end. + +-ifdef(TEST). +clean_value_ws_end_test_() -> + Tests = [ + {<<>>, <<>>}, + {<<" ">>, <<>>}, + {<<"text/*;q=0.3, text/html;q=0.7, text/html;level=1, " + "text/html;level=2;q=0.4, */*;q=0.5 \t \t ">>, + <<"text/*;q=0.3, text/html;q=0.7, text/html;level=1, " + "text/html;level=2;q=0.4, */*;q=0.5">>} + ], + [{V, fun() -> R = clean_value_ws_end(V, byte_size(V) - 1) end} || {V, R} <- Tests]. +-endif. + +-ifdef(PERF). +horse_clean_value_ws_end() -> + horse:repeat(200000, + clean_value_ws_end( + <<"text/*;q=0.3, text/html;q=0.7, text/html;level=1, " + "text/html;level=2;q=0.4, */*;q=0.5 ">>, + byte_size(<<"text/*;q=0.3, text/html;q=0.7, text/html;level=1, " + "text/html;level=2;q=0.4, */*;q=0.5 ">>) - 1) + ). +-endif. + request(B, State=#state{transport=Transport}, M, P, Q, Version, Headers) -> case lists:keyfind(<<"host">>, 1, Headers) of false when Version =:= 'HTTP/1.1' -> -- cgit v1.2.3