aboutsummaryrefslogtreecommitdiffstats
path: root/src/cowboy_http_req.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/cowboy_http_req.erl')
-rw-r--r--src/cowboy_http_req.erl67
1 files changed, 67 insertions, 0 deletions
diff --git a/src/cowboy_http_req.erl b/src/cowboy_http_req.erl
index fa4e620..f850e52 100644
--- a/src/cowboy_http_req.erl
+++ b/src/cowboy_http_req.erl
@@ -37,6 +37,10 @@
]). %% 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,
upgrade_reply/3
@@ -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)