Просмотр исходного кода

Make cowboy_req:read_part return multipart headers as map

Loïc Hoguin 8 лет назад
Родитель
Сommit
ec00e3d60e

+ 1 - 1
doc/src/guide/multipart.asciidoc

@@ -102,7 +102,7 @@ multipart(Req0) ->
                 {data, _FieldName} ->
                     {ok, _Body, Req2} = cowboy_req:read_part_body(Req1),
                     Req2;
-                {file, _FieldName, _Filename, _CType, _CTransferEncoding} ->
+                {file, _FieldName, _Filename, _CType} ->
                     stream_file(Req1)
             end,
             multipart(Req);

+ 2 - 2
doc/src/manual/cowboy_req.read_part.asciidoc

@@ -15,7 +15,7 @@ read_part(Req :: cowboy_req:req(), Opts)
     -> {ok, Headers, Req} | {done, Req}
 
 Opts    :: cowboy_req:read_body_opts()
-Headers :: cow_multipart:headers()
+Headers :: #{binary() => binary()}
 ----
 
 Read the next part of a multipart body.
@@ -70,7 +70,7 @@ to 5 seconds.
 == Return value
 
 An `ok` tuple is returned containing the next part's headers
-as a list of key/values.
+as a map.
 
 A `done` tuple is returned if there are no more parts to read.
 

+ 1 - 1
examples/upload/src/upload_handler.erl

@@ -8,7 +8,7 @@
 init(Req, Opts) ->
 	{ok, Headers, Req2} = cowboy_req:read_part(Req),
 	{ok, Data, Req3} = cowboy_req:read_part_body(Req2),
-	{file, <<"inputfile">>, Filename, ContentType, _TE}
+	{file, <<"inputfile">>, Filename, ContentType}
 		= cow_multipart:form_data(Headers),
 	io:format("Received file ~p of content-type ~p as follow:~n~p~n~n",
 		[Filename, ContentType, Data]),

+ 5 - 4
src/cowboy_req.erl

@@ -463,7 +463,7 @@ read_part(Req) ->
 	read_part(Req, #{length => 64000, period => 5000}).
 
 -spec read_part(Req, read_body_opts())
-	-> {ok, cow_multipart:headers(), Req} | {done, Req}
+	-> {ok, #{binary() => binary()}, Req} | {done, Req}
 	when Req::req().
 read_part(Req, Opts) ->
 	case maps:is_key(multipart, Req) of
@@ -482,9 +482,10 @@ read_part(Buffer, Opts, Req=#{multipart := {Boundary, _}}) ->
 		{more, Buffer2} ->
 			{Data, Req2} = stream_multipart(Req, Opts),
 			read_part(<< Buffer2/binary, Data/binary >>, Opts, Req2);
-		{ok, Headers, Rest} ->
-			%% @todo We may want headers as a map. Need to check the
-			%% rules for multipart header parsing before taking a decision.
+		{ok, Headers0, Rest} ->
+			Headers = maps:from_list(Headers0),
+			%% Reject multipart content containing duplicate headers.
+			true = map_size(Headers) =:= length(Headers0),
 			{ok, Headers, Req#{multipart => {Boundary, Rest}}};
 		%% Ignore epilogue.
 		{done, _} ->

+ 10 - 12
test/req_SUITE.erl

@@ -399,14 +399,13 @@ do_multipart(Path, Config) ->
 		{<<"content-type">>, <<"multipart/mixed; boundary=deadbeef">>}
 	], ReqBody, Config),
 	[
-		{[{<<"content-type">>, <<"text/plain">>}], <<"Cowboy is an HTTP server.">>},
+		{#{<<"content-type">> := <<"text/plain">>}, <<"Cowboy is an HTTP server.">>},
 		{LargeHeaders, LargeBody}
 	] = binary_to_term(RespBody),
-	%% @todo Multipart header order is currently undefined.
-	[
-		{<<"content-type">>, <<"application/octet-stream">>},
-		{<<"x-custom">>, <<"value">>}
-	] = lists:sort(LargeHeaders),
+	#{
+		<<"content-type">> := <<"application/octet-stream">>,
+		<<"x-custom">> := <<"value">>
+	} = LargeHeaders,
 	ok.
 
 read_part_skip_body(Config) ->
@@ -421,14 +420,13 @@ read_part_skip_body(Config) ->
 		{<<"content-type">>, <<"multipart/mixed; boundary=deadbeef">>}
 	], ReqBody, Config),
 	[
-		[{<<"content-type">>, <<"text/plain">>}],
+		#{<<"content-type">> := <<"text/plain">>},
 		LargeHeaders
 	] = binary_to_term(RespBody),
-	%% @todo Multipart header order is currently undefined.
-	[
-		{<<"content-type">>, <<"application/octet-stream">>},
-		{<<"x-custom">>, <<"value">>}
-	] = lists:sort(LargeHeaders),
+	#{
+		<<"content-type">> := <<"application/octet-stream">>,
+		<<"x-custom">> := <<"value">>
+	} = LargeHeaders,
 	ok.
 
 %% @todo When reading a multipart body, length and period