mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-16 13:10:24 +00:00
Add multipart support
This commit is contained in:
parent
a5b47fda8d
commit
528507c7de
7 changed files with 382 additions and 6 deletions
|
@ -36,6 +36,10 @@
|
|||
body/1, body/2, body_qs/1
|
||||
]). %% Request Body API.
|
||||
|
||||
-export([
|
||||
multipart_data/1, multipart_skip/1
|
||||
]). %% Request Multipart API.
|
||||
|
||||
-export([
|
||||
reply/2, reply/3, reply/4,
|
||||
chunked_reply/2, chunked_reply/3, chunk/2,
|
||||
|
@ -358,6 +362,69 @@ body_qs(Req) ->
|
|||
{ok, Body, Req2} = body(Req),
|
||||
{parse_qs(Body), Req2}.
|
||||
|
||||
%% Multipart Request API.
|
||||
|
||||
%% @doc Return data from the multipart parser.
|
||||
%%
|
||||
%% Use this function for multipart streaming. For each part in the request,
|
||||
%% this function returns <em>{headers, Headers}</em> followed by a sequence of
|
||||
%% <em>{data, Data}</em> tuples and finally <em>end_of_part</em>. When there
|
||||
%% is no part to parse anymore, <em>eof</em> is returned.
|
||||
%%
|
||||
%% If the request Content-Type is not a multipart one, <em>{error, badarg}</em>
|
||||
%% is returned.
|
||||
-spec multipart_data(#http_req{}) -> {multipart_data(), #http_req{}}.
|
||||
multipart_data(Req=#http_req{body_state=waiting}) ->
|
||||
{{<<"multipart">>, _SubType, Params}, Req2} =
|
||||
parse_header('Content-Type', Req),
|
||||
{_, Boundary} = lists:keyfind(<<"boundary">>, 1, Params),
|
||||
{Length, Req3=#http_req{buffer=Buffer}} =
|
||||
parse_header('Content-Length', Req2),
|
||||
multipart_data(Req3, Length, cowboy_multipart:parser(Boundary), Buffer);
|
||||
multipart_data(Req=#http_req{body_state={multipart, Length, Cont}}) ->
|
||||
multipart_data(Req, Length, Cont());
|
||||
multipart_data(Req=#http_req{body_state=done}) ->
|
||||
{eof, Req}.
|
||||
|
||||
multipart_data(Req, Length, Parser, Buffer) when byte_size(Buffer) >= Length ->
|
||||
<< Data:Length/binary, Rest/binary >> = Buffer,
|
||||
multipart_data(Req#http_req{buffer=Rest}, 0, Parser(Data));
|
||||
multipart_data(Req, Length, Parser, Buffer) ->
|
||||
NewLength = Length - byte_size(Buffer),
|
||||
multipart_data(Req#http_req{buffer= <<>>}, NewLength, Parser(Buffer)).
|
||||
|
||||
multipart_data(Req, Length, {headers, Headers, Cont}) ->
|
||||
{{headers, Headers}, Req#http_req{body_state={multipart, Length, Cont}}};
|
||||
multipart_data(Req, Length, {body, Data, Cont}) ->
|
||||
{{body, Data}, Req#http_req{body_state={multipart, Length, Cont}}};
|
||||
multipart_data(Req, Length, {end_of_part, Cont}) ->
|
||||
{end_of_part, Req#http_req{body_state={multipart, Length, Cont}}};
|
||||
multipart_data(Req, 0, eof) ->
|
||||
{eof, Req#http_req{body_state=done}};
|
||||
multipart_data(Req=#http_req{socket=Socket, transport=Transport},
|
||||
Length, eof) ->
|
||||
{ok, _Data} = Transport:recv(Socket, Length, 5000),
|
||||
{eof, Req#http_req{body_state=done}};
|
||||
multipart_data(Req=#http_req{socket=Socket, transport=Transport},
|
||||
Length, {more, Parser}) when Length > 0 ->
|
||||
case Transport:recv(Socket, 0, 5000) of
|
||||
{ok, << Data:Length/binary, Buffer/binary >>} ->
|
||||
multipart_data(Req#http_req{buffer=Buffer}, 0, Parser(Data));
|
||||
{ok, Data} ->
|
||||
multipart_data(Req, Length - byte_size(Data), Parser(Data))
|
||||
end.
|
||||
|
||||
%% @doc Skip a part returned by the multipart parser.
|
||||
%%
|
||||
%% This function repeatedly calls <em>multipart_data/1</em> until
|
||||
%% <em>end_of_part</em> or <em>eof</em> is parsed.
|
||||
multipart_skip(Req) ->
|
||||
case multipart_data(Req) of
|
||||
{end_of_part, Req2} -> {ok, Req2};
|
||||
{eof, Req2} -> {ok, Req2};
|
||||
{_Other, Req2} -> multipart_skip(Req2)
|
||||
end.
|
||||
|
||||
%% Response API.
|
||||
|
||||
%% @equiv reply(Status, [], [], Req)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue