Browse Source

No line break required after close-delimiter
RFC 1341 does not specify this and indeed some upload clients (for example Flash) do not terminate the request with line breaks

Mikkel Jensen 10 years ago
parent
commit
f87a4712a1
1 changed files with 47 additions and 5 deletions
  1. 47 5
      src/cow_multipart.erl

+ 47 - 5
src/cow_multipart.erl

@@ -47,7 +47,7 @@
 	"\r\n"
 	"\r\n"
 	"PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg\r\n"
 	"PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg\r\n"
 	"Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg==\r\n"
 	"Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg==\r\n"
-	"--frontier--\r\n"
+	"--frontier--"
 >>).
 >>).
 -define(TEST1_BOUNDARY, <<"frontier">>).
 -define(TEST1_BOUNDARY, <<"frontier">>).
 
 
@@ -72,10 +72,32 @@
 	"\r\n"
 	"\r\n"
 	"...contents of file2.gif...\r\n"
 	"...contents of file2.gif...\r\n"
 	"--BbC04y--\r\n"
 	"--BbC04y--\r\n"
-	"--AaB03x--\r\n"
+	"--AaB03x--"
 >>).
 >>).
 -define(TEST2_BOUNDARY, <<"AaB03x">>).
 -define(TEST2_BOUNDARY, <<"AaB03x">>).
 
 
+-define(TEST3_MIME, <<
+	"This is the preamble.\r\n"
+	"--boundary\r\n"
+	"Content-Type: text/plain\r\n"
+	"\r\n"
+	"This is the body of the message.\r\n"
+	"--boundary--"
+	"\r\nThis is the epilogue. Here it includes leading CRLF"
+>>).
+-define(TEST3_BOUNDARY, <<"boundary">>).
+
+-define(TEST4_MIME, <<
+	"This is the preamble.\r\n"
+	"--boundary\r\n"
+	"Content-Type: text/plain\r\n"
+	"\r\n"
+	"This is the body of the message.\r\n"
+	"--boundary--"
+	"\r\n"
+>>).
+-define(TEST4_BOUNDARY, <<"boundary">>).
+
 %% Parsing.
 %% Parsing.
 %%
 %%
 %% The multipart format is defined in RFC 2045.
 %% The multipart format is defined in RFC 2045.
@@ -98,7 +120,7 @@ parse_headers(<< "--", Stream/bits >>, Boundary) ->
 	BoundarySize = byte_size(Boundary),
 	BoundarySize = byte_size(Boundary),
 	case Stream of
 	case Stream of
 		%% Last boundary. Return the epilogue.
 		%% Last boundary. Return the epilogue.
-		<< Boundary:BoundarySize/binary, "--\r\n", Stream2/bits >> ->
+		<< Boundary:BoundarySize/binary, "--", Stream2/bits >> ->
 			{done, Stream2};
 			{done, Stream2};
 		<< Boundary:BoundarySize/binary, Stream2/bits >> ->
 		<< Boundary:BoundarySize/binary, Stream2/bits >> ->
 			%% We have all the headers only if there is a \r\n\r\n
 			%% We have all the headers only if there is a \r\n\r\n
@@ -144,7 +166,7 @@ skip_preamble(Stream, Boundary) ->
 			<< _:Start2/binary, Stream2/bits >> = Stream,
 			<< _:Start2/binary, Stream2/bits >> = Stream,
 			case Stream2 of
 			case Stream2 of
 				%% Last boundary. Return the epilogue.
 				%% Last boundary. Return the epilogue.
-				<< "--\r\n", Stream3/bits >> ->
+				<< "--", Stream3/bits >> ->
 					{done, Stream3};
 					{done, Stream3};
 				_ ->
 				_ ->
 					case binary:match(Stream, <<"\r\n\r\n">>) of
 					case binary:match(Stream, <<"\r\n\r\n">>) of
@@ -298,6 +320,26 @@ parse_interleaved_test() ->
 	{done, <<>>} = parse_headers(Rest4, ?TEST2_BOUNDARY),
 	{done, <<>>} = parse_headers(Rest4, ?TEST2_BOUNDARY),
 	ok.
 	ok.
 
 
+parse_epilogue_test() ->
+	H1 = [{<<"content-type">>, <<"text/plain">>}],
+	Body1 = <<"This is the body of the message.">>,
+	Epilogue = <<"\r\nThis is the epilogue. Here it includes leading CRLF">>,
+	{ok, H1, Rest} = parse_headers(?TEST3_MIME, ?TEST3_BOUNDARY),
+	{done, Body1, Rest2} = parse_body(Rest, ?TEST3_BOUNDARY),
+	done = parse_body(Rest2, ?TEST3_BOUNDARY),
+	{done, Epilogue} = parse_headers(Rest2, ?TEST3_BOUNDARY),
+	ok.
+
+parse_epilogue_crlf_test() ->
+	H1 = [{<<"content-type">>, <<"text/plain">>}],
+	Body1 = <<"This is the body of the message.">>,
+	Epilogue = <<"\r\n">>,
+	{ok, H1, Rest} = parse_headers(?TEST4_MIME, ?TEST4_BOUNDARY),
+	{done, Body1, Rest2} = parse_body(Rest, ?TEST4_BOUNDARY),
+	done = parse_body(Rest2, ?TEST4_BOUNDARY),
+	{done, Epilogue} = parse_headers(Rest2, ?TEST4_BOUNDARY),
+	ok.
+
 parse_partial_test() ->
 parse_partial_test() ->
 	{ok, <<0:8000, "abcdef">>, <<"\rghij">>}
 	{ok, <<0:8000, "abcdef">>, <<"\rghij">>}
 		= parse_body(<<0:8000, "abcdef\rghij">>, <<"boundary">>),
 		= parse_body(<<0:8000, "abcdef\rghij">>, <<"boundary">>),
@@ -376,7 +418,7 @@ headers_to_iolist([{N, V}|Tail], Acc) ->
 
 
 -spec close(binary()) -> iodata().
 -spec close(binary()) -> iodata().
 close(Boundary) ->
 close(Boundary) ->
-	[<<"\r\n--">>, Boundary, <<"--\r\n">>].
+	[<<"\r\n--">>, Boundary, <<"--">>].
 
 
 -ifdef(TEST).
 -ifdef(TEST).
 build_test() ->
 build_test() ->