aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2014-02-19 18:56:50 +0100
committerLoïc Hoguin <[email protected]>2014-02-19 18:56:50 +0100
commit943d80e7ec4eaf57a8a47b60d357ec35cb336d8a (patch)
treeced5fcabcd2e2316366b3261e546c311f443652f
parent5bc352df0cb2010b697179d8a25d2282db03c1e3 (diff)
downloadcowlib-943d80e7ec4eaf57a8a47b60d357ec35cb336d8a.tar.gz
cowlib-943d80e7ec4eaf57a8a47b60d357ec35cb336d8a.tar.bz2
cowlib-943d80e7ec4eaf57a8a47b60d357ec35cb336d8a.zip
Fix bugs in cow_multipart:parse_body/2 when a partial was found at the end
There was three bugs: lack of a scope argument in binary:match (I swear I had it in a previous version, whoops!); a misinterpretation of the returned position when the scope is used (so yeah it wouldn't have worked either way); \r\n being incorrectly removed when we got a partial, despite not knowing whether it was a boundary. Added a series of different tests to ensure that it all works as intended.
-rw-r--r--src/cow_multipart.erl41
1 files changed, 34 insertions, 7 deletions
diff --git a/src/cow_multipart.erl b/src/cow_multipart.erl
index e1acf63..c412497 100644
--- a/src/cow_multipart.erl
+++ b/src/cow_multipart.erl
@@ -216,18 +216,22 @@ parse_body(Stream, Boundary) ->
%% No boundary, check for a possible partial at the end.
%% Return more or less of the body depending on the result.
nomatch ->
- From = byte_size(Stream) - BoundarySize - 3,
- case binary:match(Stream, <<"\r">>) of
+ StreamSize = byte_size(Stream),
+ From = StreamSize - BoundarySize - 3,
+ MatchOpts = if
+ %% Binary too small to contain boundary, check it fully.
+ From < 0 -> [];
+ %% Optimize, only check the end of the binary.
+ true -> [{scope, {From, StreamSize - From}}]
+ end,
+ case binary:match(Stream, <<"\r">>, MatchOpts) of
nomatch ->
{ok, Stream};
{Pos, _} ->
- Pos2 = From + Pos,
case Stream of
- << Body:Pos2/binary, "\r\n" >> ->
+ << Body:Pos/binary >> ->
{ok, Body};
- << Body:Pos2/binary, "\r\n", Rest/bits >> ->
- {ok, Body, Rest};
- << Body:Pos2/binary, Rest/bits >> ->
+ << Body:Pos/binary, Rest/bits >> ->
{ok, Body, Rest}
end
end;
@@ -293,6 +297,29 @@ parse_interleaved_test() ->
{done, Rest4} = parse_headers(InRest4, InBoundary),
{done, <<>>} = parse_headers(Rest4, ?TEST2_BOUNDARY),
ok.
+
+parse_partial_test() ->
+ {ok, <<0:8000, "abcdef">>, <<"\rghij">>}
+ = parse_body(<<0:8000, "abcdef\rghij">>, <<"boundary">>),
+ {ok, <<"abcdef">>, <<"\rghij">>}
+ = parse_body(<<"abcdef\rghij">>, <<"boundary">>),
+ {ok, <<"abc">>, <<"\rdef">>}
+ = parse_body(<<"abc\rdef">>, <<"boundaryboundary">>),
+ {ok, <<0:8000, "abcdef">>, <<"\r\nghij">>}
+ = parse_body(<<0:8000, "abcdef\r\nghij">>, <<"boundary">>),
+ {ok, <<"abcdef">>, <<"\r\nghij">>}
+ = parse_body(<<"abcdef\r\nghij">>, <<"boundary">>),
+ {ok, <<"abc">>, <<"\r\ndef">>}
+ = parse_body(<<"abc\r\ndef">>, <<"boundaryboundary">>),
+ {ok, <<"boundary">>, <<"\r">>}
+ = parse_body(<<"boundary\r">>, <<"boundary">>),
+ {ok, <<"boundary">>, <<"\r\n">>}
+ = parse_body(<<"boundary\r\n">>, <<"boundary">>),
+ {ok, <<"boundary">>, <<"\r\n-">>}
+ = parse_body(<<"boundary\r\n-">>, <<"boundary">>),
+ {ok, <<"boundary">>, <<"\r\n--">>}
+ = parse_body(<<"boundary\r\n--">>, <<"boundary">>),
+ ok.
-endif.
-ifdef(PERF).