aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/http.hrl3
-rw-r--r--src/cowboy_http_protocol.erl28
-rw-r--r--src/cowboy_http_req.erl23
3 files changed, 47 insertions, 7 deletions
diff --git a/include/http.hrl b/include/http.hrl
index e0fe4f6..e4b9716 100644
--- a/include/http.hrl
+++ b/include/http.hrl
@@ -32,6 +32,9 @@
headers = [] :: http_headers(),
%% cookies = undefined :: undefined | http_cookies() %% @todo
+ %% Request body.
+ body_state = waiting :: waiting | done,
+
%% Response.
resp_state = locked :: locked | waiting | done
}).
diff --git a/src/cowboy_http_protocol.erl b/src/cowboy_http_protocol.erl
index 2b5292c..b02f471 100644
--- a/src/cowboy_http_protocol.erl
+++ b/src/cowboy_http_protocol.erl
@@ -154,16 +154,34 @@ handler_loop(HandlerState, Req, State=#state{handler={Handler, _Opts}}) ->
-spec handler_terminate(HandlerState::term(), Req::#http_req{},
State::#state{}) -> ok.
handler_terminate(HandlerState, Req, State=#state{handler={Handler, _Opts}}) ->
- Res = (catch Handler:terminate(
+ HandlerRes = (catch Handler:terminate(
Req#http_req{resp_state=locked}, HandlerState)),
- %% @todo We must skip any body data from the request
- %% before processing another.
+ BodyRes = ensure_body_processed(Req),
ensure_response(Req, State),
- case {Res, State#state.connection} of
- {ok, keepalive} -> next_request(State);
+ case {HandlerRes, BodyRes, State#state.connection} of
+ {ok, ok, keepalive} -> next_request(State);
_Closed -> terminate(State)
end.
+-spec ensure_body_processed(Req::#http_req{}) -> ok | close.
+ensure_body_processed(#http_req{body_state=done}) ->
+ ok;
+ensure_body_processed(Req=#http_req{body_state=waiting}) ->
+ {Length, Req2} = cowboy_http_req:header('Content-Length', Req),
+ case Length of
+ "" -> ok;
+ _Any ->
+ Length2 = list_to_integer(Length),
+ skip_body(Length2, Req2)
+ end.
+
+-spec skip_body(Length::non_neg_integer(), Req::#http_req{}) -> ok | close.
+skip_body(Length, Req) ->
+ case cowboy_http_req:body(Length, Req) of
+ {error, _Reason} -> close;
+ _Any -> ok
+ end.
+
%% No response has been sent but everything apparently went fine.
%% Reply with 204 No Content to indicate this.
ensure_response(#http_req{resp_state=waiting}, State) ->
diff --git a/src/cowboy_http_req.erl b/src/cowboy_http_req.erl
index 40af601..a1688de 100644
--- a/src/cowboy_http_req.erl
+++ b/src/cowboy_http_req.erl
@@ -25,6 +25,10 @@
]). %% Request API.
-export([
+ body/2
+]). %% Request Body API.
+
+-export([
reply/4
]). %% Response API.
@@ -115,8 +119,10 @@ bindings(Req) ->
-spec header(Name::atom() | string(), Req::#http_req{})
-> {Value::string(), Req::#http_req{}}.
header(Name, Req) ->
- {Name, Value} = lists:keyfind(Name, 1, Req#http_req.headers),
- {Value, Req}.
+ case lists:keyfind(Name, 1, Req#http_req.headers) of
+ {Name, Value} -> {Value, Req};
+ false -> {"", Req}
+ end.
-spec header(Name::atom() | string(), Default::term(), Req::#http_req{})
-> {Value::string() | term(), Req::#http_req{}}.
@@ -129,6 +135,19 @@ header(Name, Default, Req) ->
headers(Req) ->
{Req#http_req.headers, Req}.
+%% Request Body API.
+
+%% @todo We probably want to configure the timeout.
+%% @todo We probably want to allow a max length.
+-spec body(Length::non_neg_integer(), Req::#http_req{})
+ -> {Body::binary(), Req::#http_req{}} | {error, Reason::posix()}.
+body(Length, Req=#http_req{socket=Socket, transport=Transport, body_state=waiting}) ->
+ Transport:setopts(Socket, [{packet, raw}]),
+ case Transport:recv(Socket, Length, 5000) of
+ {ok, Body} -> {ok, Body, Req#http_req{body_state=done}};
+ {error, Reason} -> {error, Reason}
+ end.
+
%% Response API.
-spec reply(Code::http_status(), Headers::http_headers(),