Browse Source

Introduce Handler:terminate to cleanup the handler's state.

Loïc Hoguin 14 years ago
parent
commit
c6ad0273a8
2 changed files with 22 additions and 6 deletions
  1. 4 1
      README.md
  2. 18 5
      src/cowboy_http_protocol.erl

+ 4 - 1
README.md

@@ -63,10 +63,13 @@ use one of the predefined handlers or write your own. An hello world HTTP
 handler could be written like this:
 handler could be written like this:
 
 
     -module(my_handler).
     -module(my_handler).
-    -export([init/2, handle/2]).
+    -export([init/2, handle/2, terminate/2]).
 
 
     init(Req, Opts) ->
     init(Req, Opts) ->
         {ok, Req, undefined}.
         {ok, Req, undefined}.
 
 
     handle(Req, State) ->
     handle(Req, State) ->
         {reply, 200, [], "Hello World!"}.
         {reply, 200, [], "Hello World!"}.
+
+    terminate(Req, State) ->
+        ok.

+ 18 - 5
src/cowboy_http_protocol.erl

@@ -120,10 +120,24 @@ handler_init(Req, State=#state{handler={Handler, Opts}}) ->
 	State::#state{}) -> ok.
 	State::#state{}) -> ok.
 handler_loop(HandlerState, Req, State=#state{handler={Handler, _Opts}}) ->
 handler_loop(HandlerState, Req, State=#state{handler={Handler, _Opts}}) ->
 	case Handler:handle(Req, HandlerState) of
 	case Handler:handle(Req, HandlerState) of
-		%% @todo {ok, HandlerState}; {mode, active}
+		%% @todo {ok, Req2, HandlerState2} -> and use them in handler_terminate
 		%% @todo Move the reply code to the cowboy_http_req module.
 		%% @todo Move the reply code to the cowboy_http_req module.
 		{reply, RCode, RHeaders, RBody} ->
 		{reply, RCode, RHeaders, RBody} ->
-			reply(RCode, RHeaders, RBody, State)
+			reply(RCode, RHeaders, RBody, State),
+			handler_terminate(HandlerState, Req, State)
+		%% @todo {mode, active}
+	end.
+
+-spec handler_terminate(HandlerState::term(), Req::#http_req{},
+	State::#state{}) -> ok.
+handler_terminate(HandlerState, Req, State=#state{handler={Handler, _Opts}}) ->
+	Res = Handler:terminate(Req, HandlerState),
+	%% @todo We need to check if the Req has been replied to.
+	%%       All requests must have a reply, at worst an error.
+	%%       If a request started but wasn't completed, complete it.
+	case Res of
+		ok     -> next_request(State);
+		closed -> terminate(State)
 	end.
 	end.
 
 
 -spec error_terminate(Code::http_status(), State::#state{}) -> ok.
 -spec error_terminate(Code::http_status(), State::#state{}) -> ok.
@@ -138,14 +152,13 @@ terminate(#state{socket=Socket, transport=Transport}) ->
 -spec reply(Code::http_status(), Headers::http_headers(), Body::iolist(),
 -spec reply(Code::http_status(), Headers::http_headers(), Body::iolist(),
 	State::#state{}) -> ok.
 	State::#state{}) -> ok.
 %% @todo Don't be naive about the headers!
 %% @todo Don't be naive about the headers!
-reply(Code, Headers, Body, State=#state{socket=Socket,
+reply(Code, Headers, Body, #state{socket=Socket,
 		transport=TransportMod, connection=Connection}) ->
 		transport=TransportMod, connection=Connection}) ->
 	StatusLine = ["HTTP/1.1 ", status(Code), "\r\n"],
 	StatusLine = ["HTTP/1.1 ", status(Code), "\r\n"],
 	BaseHeaders = ["Connection: ", atom_to_connection(Connection),
 	BaseHeaders = ["Connection: ", atom_to_connection(Connection),
 		"\r\nContent-Length: ", integer_to_list(iolist_size(Body)), "\r\n"],
 		"\r\nContent-Length: ", integer_to_list(iolist_size(Body)), "\r\n"],
 	TransportMod:send(Socket,
 	TransportMod:send(Socket,
-		[StatusLine, BaseHeaders, Headers, "\r\n", Body]),
-	next_request(State).
+		[StatusLine, BaseHeaders, Headers, "\r\n", Body]).
 
 
 -spec next_request(State::#state{}) -> ok.
 -spec next_request(State::#state{}) -> ok.
 next_request(State=#state{connection=keepalive}) ->
 next_request(State=#state{connection=keepalive}) ->