diff options
author | Loïc Hoguin <[email protected]> | 2017-11-22 23:10:50 +0100 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2017-11-22 23:10:50 +0100 |
commit | e48f1cb34f5cc16844577ae55a9ebf0b7d08818a (patch) | |
tree | a7319d2475bb533e3565982b3cd733467f4929c4 | |
parent | 757898658df849192ba4d21e11dd470daabeb44c (diff) | |
download | cowlib-e48f1cb34f5cc16844577ae55a9ebf0b7d08818a.tar.gz cowlib-e48f1cb34f5cc16844577ae55a9ebf0b7d08818a.tar.bz2 cowlib-e48f1cb34f5cc16844577ae55a9ebf0b7d08818a.zip |
Crash on more error cases when parsing chnuked data
-rw-r--r-- | src/cow_http_te.erl | 22 |
1 files changed, 15 insertions, 7 deletions
diff --git a/src/cow_http_te.erl b/src/cow_http_te.erl index b6290b7..9ef7a76 100644 --- a/src/cow_http_te.erl +++ b/src/cow_http_te.erl @@ -34,6 +34,8 @@ | {done, Data::binary(), TotalLen::non_neg_integer(), Rest::binary()}. -export_type([decode_ret/0]). +-include("cow_parse.hrl"). + -ifdef(TEST). dripfeed(<< C, Rest/bits >>, Acc, State, F) -> case F(<< Acc/binary, C >>, State) of @@ -164,8 +166,9 @@ stream_chunked(Data, {Rem, Streamed}, Acc) when Rem > 2 -> stream_chunked(Rest, {0, Streamed + RemSize}, << Acc/binary, Chunk/binary >>); << Chunk:RemSize/binary, "\r" >> -> {more, << Acc/binary, Chunk/binary >>, {1, Streamed + RemSize}}; - %% Everything in Data is part of the chunk. - _ -> + %% Everything in Data is part of the chunk. If we have more + %% data than the chunk accepts, then this is an error and we crash. + _ when DataSize =< RemSize -> Rem2 = Rem - DataSize, {more, << Acc/binary, Data/binary >>, Rem2, {Rem2, Streamed + DataSize}} end. @@ -197,7 +200,7 @@ chunked_len(<< $f, R/bits >>, S, A, Len) -> chunked_len(R, S, A, Len * 16 + 15); %% Note that we currently skip the first character we encounter here, %% and not in the skip_chunk_ext function. If we latter implement %% chunk extensions (unlikely) we will need to change this clause too. -chunked_len(<< C, R/bits >>, S, A, Len) when C =/= $\r -> skip_chunk_ext(R, S, A, Len); +chunked_len(<< C, R/bits >>, S, A, Len) when ?IS_WS(C); C =:= $; -> skip_chunk_ext(R, S, A, Len, 0); %% Final chunk. %% %% When trailers are following we simply return them as the Rest. @@ -216,10 +219,15 @@ chunked_len(<<"\r">>, S, A, _) -> {more, {0, S}, A}; chunked_len(<<>>, _, <<>>, _) -> more; chunked_len(<<>>, S, A, _) -> {more, {0, S}, A}. -%% @todo We should probably limit how much we skip. -skip_chunk_ext(R = << "\r", _/bits >>, S, A, Len) -> chunked_len(R, S, A, Len); -skip_chunk_ext(R = <<>>, S, A, Len) -> chunked_len(R, S, A, Len); -skip_chunk_ext(<< _, R/bits >>, S, A, Len) -> skip_chunk_ext(R, S, A, Len). +skip_chunk_ext(R = << "\r", _/bits >>, S, A, Len, _) -> chunked_len(R, S, A, Len); +skip_chunk_ext(R = <<>>, S, A, Len, _) -> chunked_len(R, S, A, Len); +%% We skip up to 128 characters of chunk extensions. The value +%% is hardcoded: chunk extensions are very rarely seen in the +%% wild and Cowboy doesn't do anything with them anyway. +%% +%% Line breaks are not allowed in the middle of chunk extensions. +skip_chunk_ext(<< C, R/bits >>, S, A, Len, Skipped) when C =/= $\n, Skipped < 128 -> + skip_chunk_ext(R, S, A, Len, Skipped + 1). %% @doc Encode a chunk. |