From ec00e3d60e985e00c6b425434af5017c634801db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Fri, 9 Jun 2017 16:57:11 +0200 Subject: Make cowboy_req:read_part return multipart headers as map --- doc/src/guide/multipart.asciidoc | 2 +- doc/src/manual/cowboy_req.read_part.asciidoc | 4 ++-- examples/upload/src/upload_handler.erl | 2 +- src/cowboy_req.erl | 9 +++++---- test/req_SUITE.erl | 22 ++++++++++------------ 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/doc/src/guide/multipart.asciidoc b/doc/src/guide/multipart.asciidoc index 77d263a..756d3b4 100644 --- a/doc/src/guide/multipart.asciidoc +++ b/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); diff --git a/doc/src/manual/cowboy_req.read_part.asciidoc b/doc/src/manual/cowboy_req.read_part.asciidoc index 0d689d8..fd21d4a 100644 --- a/doc/src/manual/cowboy_req.read_part.asciidoc +++ b/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. diff --git a/examples/upload/src/upload_handler.erl b/examples/upload/src/upload_handler.erl index 08bca6f..5dbf08f 100644 --- a/examples/upload/src/upload_handler.erl +++ b/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]), diff --git a/src/cowboy_req.erl b/src/cowboy_req.erl index ffc6e12..ab77a68 100644 --- a/src/cowboy_req.erl +++ b/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, _} -> diff --git a/test/req_SUITE.erl b/test/req_SUITE.erl index a2c040e..d155aa8 100644 --- a/test/req_SUITE.erl +++ b/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 -- cgit v1.2.3