diff options
author | Loïc Hoguin <[email protected]> | 2012-03-15 21:53:47 +0100 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2012-03-15 22:29:38 +0100 |
commit | 8e2cc3d7f1c30212450e36f9ae725244e79451fb (patch) | |
tree | 4d9dc1d8b1588885df53157a249a74888aa86a6a /src/cowboy_http_protocol.erl | |
parent | 36a6823e50e36c201df6c7a88a4c77cdaac7f2e6 (diff) | |
download | cowboy-8e2cc3d7f1c30212450e36f9ae725244e79451fb.tar.gz cowboy-8e2cc3d7f1c30212450e36f9ae725244e79451fb.tar.bz2 cowboy-8e2cc3d7f1c30212450e36f9ae725244e79451fb.zip |
Add an 'onrequest' hook for HTTP
This new protocol option is a fun.
It expects a single arg, the Req, and should only return a possibly
modified Req. This can be used for many things like URL rewriting,
access logging or listener-wide authentication.
If a reply is sent inside the hook, then Cowboy will consider the
request handled and will move on to the next one.
Diffstat (limited to 'src/cowboy_http_protocol.erl')
-rw-r--r-- | src/cowboy_http_protocol.erl | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/src/cowboy_http_protocol.erl b/src/cowboy_http_protocol.erl index 2d58315..c5a6f7f 100644 --- a/src/cowboy_http_protocol.erl +++ b/src/cowboy_http_protocol.erl @@ -47,6 +47,7 @@ transport :: module(), dispatch :: cowboy_dispatcher:dispatch_rules(), handler :: {module(), any()}, + onrequest :: undefined | fun((#http_req{}) -> #http_req{}), urldecode :: {fun((binary(), T) -> binary()), T}, req_empty_lines = 0 :: integer(), max_empty_lines :: integer(), @@ -77,6 +78,7 @@ init(ListenerPid, Socket, Transport, Opts) -> MaxEmptyLines = proplists:get_value(max_empty_lines, Opts, 5), MaxKeepalive = proplists:get_value(max_keepalive, Opts, infinity), MaxLineLength = proplists:get_value(max_line_length, Opts, 4096), + OnRequest = proplists:get_value(onrequest, Opts), Timeout = proplists:get_value(timeout, Opts, 5000), URLDecDefault = {fun cowboy_http:urldecode/2, crash}, URLDec = proplists:get_value(urldecode, Opts, URLDecDefault), @@ -84,7 +86,7 @@ init(ListenerPid, Socket, Transport, Opts) -> wait_request(#state{listener=ListenerPid, socket=Socket, transport=Transport, dispatch=Dispatch, max_empty_lines=MaxEmptyLines, max_keepalive=MaxKeepalive, max_line_length=MaxLineLength, - timeout=Timeout, urldecode=URLDec}). + timeout=Timeout, onrequest=OnRequest, urldecode=URLDec}). %% @private -spec parse_request(#state{}) -> ok. @@ -170,11 +172,11 @@ header({http_header, _I, 'Host', _R, RawHost}, Req=#http_req{ case catch cowboy_dispatcher:split_host(RawHost2) of {Host, RawHost3, undefined} -> Port = default_port(Transport:name()), - dispatch(fun parse_header/2, Req#http_req{ + parse_header(Req#http_req{ host=Host, raw_host=RawHost3, port=Port, headers=[{'Host', RawHost3}|Req#http_req.headers]}, State); {Host, RawHost3, Port} -> - dispatch(fun parse_header/2, Req#http_req{ + parse_header(Req#http_req{ host=Host, raw_host=RawHost3, port=Port, headers=[{'Host', RawHost3}|Req#http_req.headers]}, State); {'EXIT', _Reason} -> @@ -201,24 +203,33 @@ header(http_eoh, #http_req{version={1, 1}, host=undefined}, State) -> header(http_eoh, Req=#http_req{version={1, 0}, transport=Transport, host=undefined}, State=#state{buffer=Buffer}) -> Port = default_port(Transport:name()), - dispatch(fun handler_init/2, Req#http_req{host=[], raw_host= <<>>, + onrequest(Req#http_req{host=[], raw_host= <<>>, port=Port, buffer=Buffer}, State#state{buffer= <<>>}); header(http_eoh, Req, State=#state{buffer=Buffer}) -> - handler_init(Req#http_req{buffer=Buffer}, State#state{buffer= <<>>}); + onrequest(Req#http_req{buffer=Buffer}, State#state{buffer= <<>>}); header(_Any, _Req, State) -> error_terminate(400, State). --spec dispatch(fun((#http_req{}, #state{}) -> ok), - #http_req{}, #state{}) -> ok. -dispatch(Next, Req=#http_req{host=Host, path=Path}, +%% Call the global onrequest callback. The callback can send a reply, +%% in which case we consider the request handled and move on to the next +%% one. Note that since we haven't dispatched yet, we don't know the +%% handler, host_info, path_info or bindings yet. +-spec onrequest(#http_req{}, #state{}) -> ok. +onrequest(Req, State=#state{onrequest=undefined}) -> + dispatch(Req, State); +onrequest(Req, State=#state{onrequest=OnRequest}) -> + Req2 = OnRequest(Req), + case Req2#http_req.resp_state of + waiting -> dispatch(Req2, State); + _ -> next_request(Req2, State, ok) + end. + +-spec dispatch(#http_req{}, #state{}) -> ok. +dispatch(Req=#http_req{host=Host, path=Path}, State=#state{dispatch=Dispatch}) -> - %% @todo We should allow a configurable chain of handlers here to - %% allow things like url rewriting, site-wide authentication, - %% optional dispatching, and more. It would default to what - %% we are doing so far. case cowboy_dispatcher:match(Host, Path, Dispatch) of {ok, Handler, Opts, Binds, HostInfo, PathInfo} -> - Next(Req#http_req{host_info=HostInfo, path_info=PathInfo, + handler_init(Req#http_req{host_info=HostInfo, path_info=PathInfo, bindings=Binds}, State#state{handler={Handler, Opts}}); {error, notfound, host} -> error_terminate(400, State); |