aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2014-12-21 16:23:46 +0200
committerLoïc Hoguin <[email protected]>2014-12-21 16:23:46 +0200
commit02b1b281785a815ff5b4c7bfc45053f0c786a18c (patch)
tree2b7bd70b1cf5c4988b6772ae67aafd4f153b8ba4
parent0b1ab1eca80c10316a7d3bec464109a92e312ac5 (diff)
downloadcowboy-02b1b281785a815ff5b4c7bfc45053f0c786a18c.tar.gz
cowboy-02b1b281785a815ff5b4c7bfc45053f0c786a18c.tar.bz2
cowboy-02b1b281785a815ff5b4c7bfc45053f0c786a18c.zip
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.
-rw-r--r--src/cowboy_protocol.erl38
1 files changed, 37 insertions, 1 deletions
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' ->