mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 20:30:23 +00:00
Skip the request body if it hasn't been read by the handler.
This commit is contained in:
parent
e40001a884
commit
8b02992e6a
3 changed files with 47 additions and 7 deletions
|
@ -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
|
||||
}).
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
%% cookie/2, cookie/3, cookies/1 @todo
|
||||
]). %% 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(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue