Browse files

Documented all events sent to user callbacks.

  • Loading branch information...
knutin committed Mar 27, 2013
1 parent 8b57695 commit a6d1a5b734712404e8120be52ab7111cf2e39c7e
Showing with 70 additions and 12 deletions.
  1. +4 −6
  2. +64 −4 src/elli_example_callback.erl
  3. +2 −2 src/elli_http.erl
@@ -37,7 +37,7 @@ Here's the features Elli *does* have:
* Binaries everywhere for strings.
- * Instrumentation inside the core of the webserver, calling user
+ * Instrumentation inside the core of the webserver, triggering user
callbacks. For example when a request completes, the user callback
gets the `request_complete` event which contains timings of all the
different parts of handling a request. There's also events for
@@ -161,8 +161,9 @@ $: erl -pa deps/*/ebin ebin
## Callback module
-There is an [example callback module](
-distributed with elli that can be used and adopted right away.
+The best source of documentation for how to write a callback module is
+[src/elli_example_callback.erl]( It
+has a bunch of examples used in the tests.
A minimal callback module could look like this:
@@ -220,6 +221,3 @@ init([]) ->
{ok, { {one_for_one, 5, 10}, [ElliSpec]} }.
@@ -192,7 +192,67 @@ chunk_loop(Ref, N) ->
-%% @doc: Handle request events, like request completed, exception
-%% thrown, client timeout, etc. Must return 'ok'.
-handle_event(_Event, _Data, _Args) ->
- ok.
+%% elli_startup is sent when Elli is starting up. If you are
+%% implementing a middleware, you can use it to spawn processes,
+%% create ETS tables or start supervised processes in a supervisor
+%% tree.
+handle_event(elli_startup, [], _) -> ok;
+%% request_complete fires *after* Elli has sent the response to the
+%% client. Timings contains timestamps of events like when the
+%% connection was accepted, when request parsing finished, when the
+%% user callback returns, etc. This allows you to collect performance
+%% statistics for monitoring your app.
+handle_event(request_complete, [_Request,
+ _ResponseCode, _ResponseHeaders, _ResponseBody,
+ _Timings], _) -> ok;
+%% request_throw, request_error and request_exit events are sent if
+%% the user callback code throws an exception, has an error or
+%% exits. After triggering this event, a generated response is sent to
+%% the user.
+handle_event(request_throw, [_Request, _Exception, _Stacktrace], _) -> ok;
+handle_event(request_error, [_Request, _Exception, _Stacktrace], _) -> ok;
+handle_event(request_exit, [_Request, _Exception, _Stacktrace], _) -> ok;
+%% chunk_complete fires when a chunked response is completely
+%% sent. It's identical to the request_complete event, except instead
+%% of the response body you get the atom "client" or "server"
+%% depending on who closed the connection.
+handle_event(chunk_complete, [_Request,
+ _ResponseCode, _ResponseHeaders, _ClosingEnd,
+ _Timings], _) -> ok;
+%% request_closed is sent if the client closes the connection when
+%% Elli is waiting for the next request on a keep alive connection.
+handle_event(request_closed, [], _) -> ok;
+%% request_parse_error fires if the request is invalid and cannot be
+%% parsed by erlang:decode_packet/3 or it contains a path Elli cannot
+%% parse or does not support.
+handle_event(request_parse_error, [_], _) -> ok;
+%% client_closed can be sent from multiple parts of the request
+%% handling. It's sent when the client closes the connection or if for
+%% any reason the socket is closed unexpectedly. The "Where" atom
+%% tells you in which part of the request processing the closed socket
+%% was detected: receiving_headers, receiving_body, before_response
+handle_event(client_closed, [_Where], _) -> ok;
+%% client_timeout can as with client_closed be sent from multiple
+%% parts of the request handling. If Elli tries to receive data from
+%% the client socket and does not receive anything within a timeout,
+%% this event fires and the socket is closed.
+handle_event(client_timeout, [_Where], _) -> ok;
+%% bad_request is sent when Elli detects a request is not well
+%% formatted or does not conform to the configured limits. Currently
+%% the Reason variable can be any of the following: {too_many_headers,
+%% Headers}, {body_size, ContentLength}
+handle_event(bad_request, [_Reason], _) -> ok;
+%% file_error is sent when the user wants to return a file as a
+%% response, but for some reason it cannot be opened.
+handle_event(file_error, [_ErrorReason], _) -> ok.
@@ -166,8 +166,8 @@ send_response(Socket, Method, Code, Headers, UserBody, {Mod, Args}) ->
Filename::file:filename(), Range::range(),
Callback::callback()) -> ok.
%% @doc: Sends a HTTP response to the client where the body is the
-%% contents of the given file. Assumes correctly set response code &
-%% headers.
+%% contents of the given file. Assumes correctly set response code
+%% and headers.
send_file(Socket, Code, Headers, Filename, {Offset, Length}, {Mod, Args}) ->
ResponseHeaders = [<<"HTTP/1.1 ">>, status(Code), <<"\r\n">>,
encode_headers(Headers), <<"\r\n">>],

0 comments on commit a6d1a5b

Please sign in to comment.