From aa4d86b81f6095316813c599659014c15bf9b935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Wed, 24 Sep 2014 14:39:17 +0300 Subject: [PATCH] Remove the onrequest hook It was redundant with middlewares. Allows us to save a few operations for every incoming requests. --- ROADMAP.md | 3 - doc/src/guide/hooks.ezdoc | 48 +------- doc/src/guide/http_req_resp.png | Bin 33228 -> 28370 bytes doc/src/guide/http_req_resp.svg | 178 +++++++++++---------------- doc/src/manual/cowboy.ezdoc | 9 -- doc/src/manual/cowboy_protocol.ezdoc | 5 - doc/src/manual/cowboy_req.ezdoc | 6 +- doc/src/manual/cowboy_spdy.ezdoc | 5 - src/cowboy.erl | 3 - src/cowboy_protocol.erl | 22 +--- src/cowboy_spdy.erl | 27 ++-- test/http_SUITE.erl | 40 ------ 12 files changed, 86 insertions(+), 260 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 5a2f95c1..ad684ecb 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -45,9 +45,6 @@ the halt tuple. The error tuple will therefore be removed. ### Hooks -The `onrequest` hook will be removed. It can easily be replaced -by a middleware. - The interface of the `onresponse` hook will change. There has been a number of issues and added complexity with the current interface that warrant fixing. The main problem is that the diff --git a/doc/src/guide/hooks.ezdoc b/doc/src/guide/hooks.ezdoc index e835a6f9..1c196488 100644 --- a/doc/src/guide/hooks.ezdoc +++ b/doc/src/guide/hooks.ezdoc @@ -1,45 +1,7 @@ ::: Hooks -Cowboy provides two hooks. `onrequest` is called once the request -line and headers have been received. `onresponse` is called just -before sending the response. - -:: Onrequest - -The `onrequest` hook is called as soon as Cowboy finishes fetching -the request headers. It occurs before any other processing, including -routing. It can be used to perform any modification needed on the -request object before continuing with the processing. If a reply is -sent inside this hook, then Cowboy will move on to the next request, -skipping any subsequent handling. - -This hook is a function that takes a request object as argument, -and returns a request object. This function MUST NOT crash. Cowboy -will not send any reply if a crash occurs in this function. - -You can specify the `onrequest` hook when creating the listener, -inside the request options. - -``` erlang -cowboy:start_http(my_http_listener, 100, - [{port, 8080}], - [ - {env, [{dispatch, Dispatch}]}, - {onrequest, fun ?MODULE:debug_hook/1} - ] -). -``` - -The following hook function prints the request object everytime a -request is received. This can be useful for debugging, for example. - -``` erlang -debug_hook(Req) -> - erlang:display(Req), - Req. -``` - -Make sure to always return the last request object obtained. +Hooks allow the user to customize Cowboy's behavior during specific +operations. :: Onresponse @@ -48,9 +10,9 @@ to the socket. It can be used for the purposes of logging responses, or for modifying the response headers or body. The best example is providing custom error pages. -Note that like the `onrequest` hook, this function MUST NOT crash. -Cowboy may or may not send a reply if this function crashes. If a reply -is sent, the hook MUST explicitly provide all headers that are needed. +Note that this function MUST NOT crash. Cowboy may or may not send a +reply if this function crashes. If a reply is sent, the hook MUST +explicitly provide all headers that are needed. You can specify the `onresponse` hook when creating the listener. diff --git a/doc/src/guide/http_req_resp.png b/doc/src/guide/http_req_resp.png index e38935f3efe19602ff29f8d3170fad145c7f8a4d..8c9cae9948161951df06513229b0763609fdd403 100644 GIT binary patch literal 28370 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 E2Y8$R1poj5 diff --git a/doc/src/guide/http_req_resp.svg b/doc/src/guide/http_req_resp.svg index 0cfa0ae9..d1e7f784 100644 --- a/doc/src/guide/http_req_resp.svg +++ b/doc/src/guide/http_req_resp.svg @@ -65,15 +65,15 @@ inkscape:pageopacity="1" inkscape:pageshadow="2" inkscape:zoom="1.4142136" - inkscape:cx="229.71447" + inkscape:cx="82.28271" inkscape:cy="764.83183" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" - inkscape:window-width="1920" - inkscape:window-height="1014" + inkscape:window-width="2560" + inkscape:window-height="1402" inkscape:window-x="0" - inkscape:window-y="33" + inkscape:window-y="38" inkscape:window-maximized="1" inkscape:snap-global="true" showguides="true"> @@ -93,7 +93,7 @@ image/svg+xml - + @@ -101,42 +101,28 @@ inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1"> - - + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:connector-curvature="0" + id="use5779" + d="M 194.29441,340.67017 369.64493,238.3853" + style="fill:none;stroke:#6d8e41;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 4;stroke-dashoffset:0" /> + - - + transform="translate(205.03261,-207.5)"> + + + - - + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" /> router + y="323.0921">router some text - onrequest handler + y="410.38519">handler middlewares reply + y="236.73991">reply onresponse + y="323.09195">onresponse diff --git a/doc/src/manual/cowboy.ezdoc b/doc/src/manual/cowboy.ezdoc index 209d4734..c26ed374 100644 --- a/doc/src/manual/cowboy.ezdoc +++ b/doc/src/manual/cowboy.ezdoc @@ -25,15 +25,6 @@ A binary status can be used to set a custom message. HTTP version. -: onrequest_fun() = fun((cowboy_req:req()) -> cowboy_req:req()) - -Fun called immediately after receiving a request. - -It can perform any operation on the Req object, including -reading the request body or replying. If a reply is sent, -the processing of the request ends here, before any middleware -is executed. - : onresponse_fun() = fun((http_status(), http_headers(), iodata(), cowboy_req:req()) -> cowboy_req:req()) diff --git a/doc/src/manual/cowboy_protocol.ezdoc b/doc/src/manual/cowboy_protocol.ezdoc index 68132957..335f2ff9 100644 --- a/doc/src/manual/cowboy_protocol.ezdoc +++ b/doc/src/manual/cowboy_protocol.ezdoc @@ -14,7 +14,6 @@ as a Ranch protocol. | {max_keepalive, non_neg_integer()} | {max_request_line_length, non_neg_integer()} | {middlewares, [module()]} - | {onrequest, cowboy:onrequest_fun()} | {onresponse, cowboy:onresponse_fun()} | {timeout, timeout()}] @@ -67,10 +66,6 @@ Maximum length of the request line. List of middlewares to execute for every requests. -: onrequest (undefined) - -Fun called every time a request is received. - : onresponse (undefined) Fun called every time a response is sent. diff --git a/doc/src/manual/cowboy_req.ezdoc b/doc/src/manual/cowboy_req.ezdoc index 94556b28..bcec9b9b 100644 --- a/doc/src/manual/cowboy_req.ezdoc +++ b/doc/src/manual/cowboy_req.ezdoc @@ -126,8 +126,7 @@ Types: Return the requested URL excluding the path component. This function will always return `undefined` until the -`cowboy_router` middleware has been executed. This includes -the `onrequest` hook. +`cowboy_router` middleware has been executed. : match_cookies(Req, Fields) -> Map @@ -371,8 +370,7 @@ Types: Return the requested URL. This function will always return `undefined` until the -`cowboy_router` middleware has been executed. This includes -the `onrequest` hook. +`cowboy_router` middleware has been executed. : version(Req) -> Version diff --git a/doc/src/manual/cowboy_spdy.ezdoc b/doc/src/manual/cowboy_spdy.ezdoc index 51a21103..534434cb 100644 --- a/doc/src/manual/cowboy_spdy.ezdoc +++ b/doc/src/manual/cowboy_spdy.ezdoc @@ -6,7 +6,6 @@ The `cowboy_spdy` module implements SPDY/3 as a Ranch protocol. : opts() = [{env, cowboy_middleware:env()} | {middlewares, [module()]} - | {onrequest, cowboy:onrequest_fun()} | {onresponse, cowboy:onresponse_fun()}] Configuration for the SPDY protocol handler. @@ -30,10 +29,6 @@ Initial middleware environment. List of middlewares to execute for every requests. -: onrequest (undefined) - -Fun called every time a request is received. - : onresponse (undefined) Fun called every time a response is sent. diff --git a/src/cowboy.erl b/src/cowboy.erl index 8e9232f5..af9f1b36 100644 --- a/src/cowboy.erl +++ b/src/cowboy.erl @@ -34,9 +34,6 @@ -type http_version() :: 'HTTP/1.1' | 'HTTP/1.0'. -export_type([http_version/0]). --type onrequest_fun() :: fun((Req) -> Req). --export_type([onrequest_fun/0]). - -type onresponse_fun() :: fun((http_status(), http_headers(), iodata(), Req) -> Req). -export_type([onresponse_fun/0]). diff --git a/src/cowboy_protocol.erl b/src/cowboy_protocol.erl index 1026d285..a5873ea8 100644 --- a/src/cowboy_protocol.erl +++ b/src/cowboy_protocol.erl @@ -32,7 +32,6 @@ | {max_keepalive, non_neg_integer()} | {max_request_line_length, non_neg_integer()} | {middlewares, [module()]} - | {onrequest, cowboy:onrequest_fun()} | {onresponse, cowboy:onresponse_fun()} | {timeout, timeout()}]. -export_type([opts/0]). @@ -43,7 +42,6 @@ middlewares :: [module()], compress :: boolean(), env :: cowboy_middleware:env(), - onrequest :: undefined | cowboy:onrequest_fun(), onresponse = undefined :: undefined | cowboy:onresponse_fun(), max_empty_lines :: non_neg_integer(), req_keepalive = 1 :: non_neg_integer(), @@ -85,7 +83,6 @@ init(Ref, Socket, Transport, Opts) -> MaxRequestLineLength = get_value(max_request_line_length, Opts, 4096), Middlewares = get_value(middlewares, Opts, [cowboy_router, cowboy_handler]), Env = [{listener, Ref}|get_value(env, Opts, [])], - OnRequest = get_value(onrequest, Opts, undefined), OnResponse = get_value(onresponse, Opts, undefined), Timeout = get_value(timeout, Opts, 5000), ok = ranch:accept_ack(Ref), @@ -95,8 +92,7 @@ init(Ref, Socket, Transport, Opts) -> max_request_line_length=MaxRequestLineLength, max_header_name_length=MaxHeaderNameLength, max_header_value_length=MaxHeaderValueLength, max_headers=MaxHeaders, - onrequest=OnRequest, onresponse=OnResponse, - timeout=Timeout, until=until(Timeout)}, 0). + onresponse=OnResponse, timeout=Timeout, until=until(Timeout)}, 0). -spec until(timeout()) -> non_neg_integer() | infinity. until(infinity) -> @@ -410,26 +406,12 @@ request(Buffer, State=#state{socket=Socket, transport=Transport, Req = cowboy_req:new(Socket, Transport, Peer, Method, Path, Query, Version, Headers, Host, Port, Buffer, ReqKeepalive < MaxKeepalive, Compress, OnResponse), - onrequest(Req, State); + execute(Req, State); {error, _} -> %% Couldn't read the peer address; connection is gone. terminate(State) end. -%% 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(cowboy_req:req(), #state{}) -> ok. -onrequest(Req, State=#state{onrequest=undefined}) -> - execute(Req, State); -onrequest(Req, State=#state{onrequest=OnRequest}) -> - Req2 = OnRequest(Req), - case cowboy_req:get(resp_state, Req2) of - waiting -> execute(Req2, State); - _ -> next_request(Req2, State, ok) - end. - -spec execute(cowboy_req:req(), #state{}) -> ok. execute(Req, State=#state{middlewares=Middlewares, env=Env}) -> execute(Req, State, Env, Middlewares). diff --git a/src/cowboy_spdy.erl b/src/cowboy_spdy.erl index 8da9613f..5b89c48d 100644 --- a/src/cowboy_spdy.erl +++ b/src/cowboy_spdy.erl @@ -24,7 +24,7 @@ -export([system_code_change/4]). %% Internal request process. --export([request_init/11]). +-export([request_init/10]). -export([resume/5]). -export([reply/4]). -export([stream_reply/3]). @@ -59,7 +59,6 @@ buffer = <<>> :: binary(), middlewares, env, - onrequest, onresponse, peer, zdef, @@ -70,7 +69,6 @@ -type opts() :: [{env, cowboy_middleware:env()} | {middlewares, [module()]} - | {onrequest, cowboy:onrequest_fun()} | {onresponse, cowboy:onresponse_fun()}]. -export_type([opts/0]). @@ -97,13 +95,12 @@ init(Parent, Ref, Socket, Transport, Opts) -> {ok, Peer} = Transport:peername(Socket), Middlewares = get_value(middlewares, Opts, [cowboy_router, cowboy_handler]), Env = [{listener, Ref}|get_value(env, Opts, [])], - OnRequest = get_value(onrequest, Opts, undefined), OnResponse = get_value(onresponse, Opts, undefined), Zdef = cow_spdy:deflate_init(), Zinf = cow_spdy:inflate_init(), ok = ranch:accept_ack(Ref), loop(#state{parent=Parent, socket=Socket, transport=Transport, - middlewares=Middlewares, env=Env, onrequest=OnRequest, + middlewares=Middlewares, env=Env, onresponse=OnResponse, peer=Peer, zdef=Zdef, zinf=Zinf}). loop(State=#state{parent=Parent, socket=Socket, transport=Transport, @@ -257,11 +254,11 @@ handle_frame(State, {syn_stream, StreamID, AssocToStreamID, %% Erlang does not allow us to control the priority of processes %% so we ignore that value entirely. handle_frame(State=#state{middlewares=Middlewares, env=Env, - onrequest=OnRequest, onresponse=OnResponse, peer=Peer}, + onresponse=OnResponse, peer=Peer}, {syn_stream, StreamID, _, IsFin, _, _, Method, _, Host, Path, Version, Headers}) -> Pid = spawn_link(?MODULE, request_init, [ - {self(), StreamID}, Peer, OnRequest, OnResponse, + {self(), StreamID}, Peer, OnResponse, Env, Middlewares, Method, Host, Path, Version, Headers ]), new_child(State, StreamID, Pid, IsFin); @@ -385,11 +382,10 @@ delete_child(Pid, State=#state{children=Children}) -> %% Request process. -spec request_init(socket(), {inet:ip_address(), inet:port_number()}, - cowboy:onrequest_fun(), cowboy:onresponse_fun(), - cowboy_middleware:env(), [module()], + cowboy:onresponse_fun(), cowboy_middleware:env(), [module()], binary(), binary(), binary(), binary(), [{binary(), binary()}]) -> ok. -request_init(FakeSocket, Peer, OnRequest, OnResponse, +request_init(FakeSocket, Peer, OnResponse, Env, Middlewares, Method, Host, Path, Version, Headers) -> {Host2, Port} = cow_http:parse_fullhost(Host), {Path2, Qs} = cow_http:parse_fullpath(Path), @@ -397,16 +393,7 @@ request_init(FakeSocket, Peer, OnRequest, OnResponse, Req = cowboy_req:new(FakeSocket, ?MODULE, Peer, Method, Path2, Qs, Version2, Headers, Host2, Port, <<>>, true, false, OnResponse), - case OnRequest of - undefined -> - execute(Req, Env, Middlewares); - _ -> - Req2 = OnRequest(Req), - case cowboy_req:get(resp_state, Req2) of - waiting -> execute(Req2, Env, Middlewares); - _ -> ok - end - end. + execute(Req, Env, Middlewares). -spec execute(cowboy_req:req(), cowboy_middleware:env(), [module()]) -> ok. diff --git a/test/http_SUITE.erl b/test/http_SUITE.erl index 1bc13c17..e98ce1b9 100644 --- a/test/http_SUITE.erl +++ b/test/http_SUITE.erl @@ -34,7 +34,6 @@ all() -> {group, https}, {group, http_compress}, {group, https_compress}, - {group, onrequest}, {group, onresponse}, {group, onresponse_capitalize}, {group, parse_host}, @@ -43,7 +42,6 @@ all() -> groups() -> Tests = cowboy_test:all(?MODULE) -- [ - onrequest, onrequest_reply, onrequest_hook, onresponse_crash, onresponse_reply, onresponse_capitalize, parse_host, set_env_dispatch ], @@ -52,10 +50,6 @@ groups() -> {https, [parallel], Tests}, {http_compress, [parallel], Tests}, {https_compress, [parallel], Tests}, - {onrequest, [parallel], [ - onrequest, - onrequest_reply - ]}, {onresponse, [parallel], [ onresponse_crash, onresponse_reply @@ -98,15 +92,6 @@ init_per_group(Name = https_compress, Config) -> {compress, true} ], Config); %% Most, if not all of these, should be in separate test suites. -init_per_group(onrequest, Config) -> - {ok, _} = cowboy:start_http(onrequest, 100, [{port, 0}], [ - {env, [{dispatch, init_dispatch(Config)}]}, - {max_keepalive, 50}, - {onrequest, fun do_onrequest_hook/1}, - {timeout, 500} - ]), - Port = ranch:get_port(onrequest), - [{type, tcp}, {port, Port}, {opts, []}|Config]; init_per_group(onresponse, Config) -> {ok, _} = cowboy:start_http(onresponse, 100, [{port, 0}], [ {env, [{dispatch, init_dispatch(Config)}]}, @@ -574,31 +559,6 @@ nc_rand(Config) -> nc_zero(Config) -> do_nc(Config, "/dev/zero"). -onrequest(Config) -> - ConnPid = gun_open(Config), - Ref = gun:get(ConnPid, "/"), - {response, nofin, 200, Headers} = gun:await(ConnPid, Ref), - {<<"server">>, <<"Serenity">>} = lists:keyfind(<<"server">>, 1, Headers), - {ok, <<"http_handler">>} = gun:await_body(ConnPid, Ref), - ok. - -onrequest_reply(Config) -> - ConnPid = gun_open(Config), - Ref = gun:get(ConnPid, "/?reply=1"), - {response, nofin, 200, Headers} = gun:await(ConnPid, Ref), - {<<"server">>, <<"Cowboy">>} = lists:keyfind(<<"server">>, 1, Headers), - {ok, <<"replied!">>} = gun:await_body(ConnPid, Ref), - ok. - -%% Hook for the above onrequest tests. -do_onrequest_hook(Req) -> - case cowboy_req:match_qs(Req, [{reply, [], noreply}]) of - #{reply := noreply} -> - cowboy_req:set_resp_header(<<"server">>, <<"Serenity">>, Req); - _ -> - cowboy_req:reply(200, [], <<"replied!">>, Req) - end. - onresponse_capitalize(Config) -> Client = raw_open(Config), ok = raw_send(Client, "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"),