Permalink
Browse files

Switch to Ranch for the listeners handling

  • Loading branch information...
Loïc Hoguin
Loïc Hoguin committed May 31, 2012
1 parent 557cce0 commit e80e37bfc587206a0b5ff7a9cd2c179a6660bfa0
Showing with 221 additions and 1,078 deletions.
  1. +2 −2 Makefile
  2. +20 −81 README.md
  3. +4 −0 rebar.config
  4. +2 −0 rebar.tests.config
  5. +2 −1 src/cowboy.app.src
  6. +21 −96 src/cowboy.erl
  7. +0 −57 src/cowboy_acceptor.erl
  8. +0 −48 src/cowboy_acceptors_sup.erl
  9. +5 −5 src/cowboy_client.erl
  10. +0 −224 src/cowboy_listener.erl
  11. +0 −46 src/cowboy_listener_sup.erl
  12. +10 −11 src/{cowboy_http_protocol.erl → cowboy_protocol.erl}
  13. +3 −3 src/{cowboy_http_req.erl → cowboy_req.erl}
  14. +0 −44 src/cowboy_requests_sup.erl
  15. +28 −28 src/{cowboy_http_rest.erl → cowboy_rest.erl}
  16. +0 −177 src/cowboy_ssl_transport.erl
  17. +20 −20 src/{cowboy_http_static.erl → cowboy_static.erl}
  18. +0 −119 src/cowboy_tcp_transport.erl
  19. +18 −18 src/{cowboy_http_websocket.erl → cowboy_websocket.erl}
  20. +3 −4 test/autobahn_SUITE.erl
  21. +3 −3 test/chunked_handler.erl
  22. +39 −49 test/http_SUITE.erl
  23. +1 −1 test/http_handler.erl
  24. +4 −4 test/http_handler_echo_body.erl
  25. +4 −4 test/http_handler_errors.erl
  26. +2 −2 test/http_handler_init_shutdown.erl
  27. +1 −1 test/http_handler_long_polling.erl
  28. +1 −1 test/http_handler_loop_timeout.erl
  29. +2 −2 test/http_handler_multipart.erl
  30. +7 −7 test/http_handler_set_resp.erl
  31. +3 −3 test/http_handler_stream_body.erl
  32. +2 −2 test/rest_forbidden_resource.erl
  33. +1 −1 test/rest_nodelete_resource.erl
  34. +2 −2 test/rest_resource_etags.erl
  35. +1 −1 test/rest_simple_resource.erl
  36. +2 −2 test/websocket_echo_handler.erl
  37. +2 −2 test/websocket_handler.erl
  38. +2 −2 test/websocket_handler_init_shutdown.erl
  39. +3 −4 test/ws_SUITE.erl
  40. +1 −1 test/ws_timeout_hibernate_handler.erl
View
@@ -9,10 +9,10 @@ all: app
# Application.
-deps:
+deps/ranch:
@$(REBAR) get-deps
-app: deps
+app: deps/ranch
@$(REBAR) compile
clean:
View
101 README.md
@@ -3,17 +3,13 @@ Cowboy
Cowboy is a small, fast and modular HTTP server written in Erlang.
-Cowboy is also a socket acceptor pool, able to accept connections
-for any kind of TCP protocol.
-
Goals
-----
Cowboy aims to provide the following advantages:
* **Small** code base.
* Damn **fast**.
-* **Modular**: transport and protocol handlers are replaceable.
* **Binary HTTP** for greater speed and lower memory usage.
* Easy to **embed** inside another application.
* Selectively **dispatch** requests to handlers, allowing you to send some
@@ -31,44 +27,23 @@ Quick start
-----------
* Add Cowboy as a rebar or agner dependency to your application.
-* Start Cowboy and add one or more listeners.
+* Start Ranch, Cowboy and add one or more listeners.
* Write handlers for your application.
* Check out [examples](https://github.com/extend/cowboy_examples)!
Getting Started
---------------
-At heart, Cowboy is nothing more than an TCP acceptor pool. All it does is
-accept connections received on a given port and using a given transport,
-like TCP or SSL, and forward them to a request handler for the given
-protocol. Acceptors and request handlers are of course supervised
-automatically.
-
-It just so happens that Cowboy also includes an HTTP protocol handler.
-But Cowboy does nothing by default. You need to explicitly ask Cowboy
-to listen on a port with your chosen transport and protocol handlers.
-To do so, you must start a listener.
-
-A listener is a special kind of supervisor that manages both the
-acceptor pool and the request processes. It is named and can thus be
-started and stopped at will.
+Cowboy does nothing by default. You need to explicitly ask Cowboy
+to listen on a port. To do so, you must start a listener. See the
+Ranch project for more information about listeners and acceptor
+pools.
-An acceptor pool is a pool of processes whose only role is to accept
-new connections. It's good practice to have many of these processes
-as they are very cheap and allow much quicker response when you get
-many connections. Of course, as with everything else, you should
-**benchmark** before you decide what's best for you.
+Cowboy provides two convenience functions to start HTTP and HTTPS
+listeners.
-Cowboy includes a TCP transport handler for HTTP and an SSL transport
-handler for HTTPS. The transport handlers can of course be reused for
-other protocols like FTP or IRC.
-
-The HTTP protocol requires one last thing to continue: dispatching rules.
-Don't worry about it right now though and continue reading, it'll all
-be explained.
-
-You can start and stop listeners by calling `cowboy:start_listener/6` and
-`cowboy:stop_listener/1` respectively.
+You can start listeners by calling `cowboy:start_http/4` or
+`cowboy:start_https/4` and stop them by calling `cowboy:stop_listener/1`.
The following example demonstrates the startup of a very simple listener.
@@ -78,10 +53,9 @@ Dispatch = [
%% {Host, list({Path, Handler, Opts})}
{'_', [{'_', my_handler, []}]}
],
-%% Name, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts
-cowboy:start_listener(my_http_listener, 100,
- cowboy_tcp_transport, [{port, 8080}],
- cowboy_http_protocol, [{dispatch, Dispatch}]
+%% Name, NbAcceptors, TransportOpts, ProtocolOpts
+cowboy:start_http(my_http_listener, 100,
+ [{port, 8080}], [{dispatch, Dispatch}]
).
```
@@ -100,7 +74,7 @@ init({tcp, http}, Req, Opts) ->
{ok, Req, undefined_state}.
handle(Req, State) ->
- {ok, Req2} = cowboy_http_req:reply(200, [], <<"Hello World!">>, Req),
+ {ok, Req2} = cowboy_req:reply(200, [], <<"Hello World!">>, Req),
{ok, Req2, State}.
terminate(Req, State) ->
@@ -125,7 +99,7 @@ init({tcp, http}, Req, Opts) ->
{loop, Req, undefined_state, ?TIMEOUT, hibernate}.
info({reply, Body}, Req, State) ->
- {ok, Req2} = cowboy_http_req:reply(200, [], Body, Req),
+ {ok, Req2} = cowboy_req:reply(200, [], Body, Req),
{ok, Req2, State};
info(Message, Req, State) ->
{loop, Req, State, hibernate}.
@@ -174,13 +148,13 @@ example, host rule `['...', <<"ninenines">>, <<"eu">>]` can match both
"cowboy.bugs.ninenines.eu" and "ninenines.eu" and path rule
`[<<"projects">>, '...']` can match both "/projects" and
"/projects/cowboy/issues/42". The host leading segments and the path trailing
-segments can later be retrieved through `cowboy_http_req:host_info/1` and
-`cowboy_http_req:path_info/1`.
+segments can later be retrieved through `cowboy_req:host_info/1` and
+`cowboy_req:path_info/1`.
Any other atom used as a token will bind the value to this atom when
matching. To follow on our hostnames example, `[<<"ninenines">>, ext]`
would bind the values `<<"eu">>` and `<<"fr">>` to the ext atom, that you
-can later retrieve in your handler by calling `cowboy_http_req:binding/{2,3}`.
+can later retrieve in your handler by calling `cowboy_req:binding/{2,3}`.
You can also accept any match spec by using the atom `'_'` directly instead of
a list of tokens. Our hello world example above uses this to forward all
@@ -193,7 +167,7 @@ Requests handling
Requests are passed around in the Request variable. Although they are
defined as a record, it is recommended to access them only through the
-cowboy_http_req module API.
+cowboy_req module API.
You can retrieve the HTTP method, HTTP version, peer address and port,
host tokens, raw host, used port, path tokens, raw path, query string
@@ -202,7 +176,7 @@ request. You can also read the request body, if any, optionally parsing
it as a query string. Finally, the request allows you to send a response
to the client.
-See the cowboy_http_req module for more information.
+See the cowboy_req module for more information.
Websockets
----------
@@ -223,7 +197,7 @@ Websocket would look like this:
websocket_info/3, websocket_terminate/3]).
init({tcp, http}, Req, Opts) ->
- {upgrade, protocol, cowboy_http_websocket}.
+ {upgrade, protocol, cowboy_websocket}.
websocket_init(TransportName, Req, _Opts) ->
erlang:start_timer(1000, self(), <<"Hello!">>),
@@ -253,38 +227,3 @@ regularly when support to the most recent drafts gets added. Features may
be added, changed or removed before the protocol gets finalized. Cowboy
tries to implement all drafts transparently and give a single interface to
handle them all, however.
-
-Using Cowboy with other protocols
----------------------------------
-
-One of the strengths of Cowboy is of course that you can use it with any
-protocol you want. The only downside is that if it's not HTTP, you'll
-probably have to write the protocol handler yourself.
-
-The only exported function a protocol handler needs is the start_link/4
-function, with arguments ListenerPid, Socket, Transport and Opts. ListenerPid
-is the pid to the listener's gen_server, managing the connections. Socket is of
-course the client socket; Transport is the module name of the chosen transport
-handler and Opts is protocol options defined when starting the listener.
-
-After initializing your protocol, it is recommended to call the
-function cowboy:accept_ack/1 with the ListenerPid as argument,
-as it will ensure Cowboy has been able to fully initialize the socket.
-Anything you do past this point is up to you!
-
-If you need to change some socket options, like enabling raw mode for example,
-you can call the <em>Transport:setopts/2</em> function. It is the protocol's
-responsability to manage the socket usage, there should be no need for an user
-to specify that kind of options while starting a listener.
-
-You should definitely look at the cowboy_http_protocol module for a great
-example of fast request handling if you need to. Otherwise it's probably
-safe to use `{active, once}` mode and handle everything as it comes.
-
-Note that while you technically can run a protocol handler directly as a
-gen_server or a gen_fsm, it's probably not a good idea, as the only call
-you'll ever receive from Cowboy is the start_link/4 call. On the other
-hand, feel free to write a very basic protocol handler which then forwards
-requests to a gen_server or gen_fsm. By doing so however you must take
-care to supervise their processes as Cowboy only knows about the protocol
-handler itself.
View
@@ -1,3 +1,7 @@
+{deps, [
+ {ranch, "0.2.0",
+ {git, "git://github.com/extend/ranch.git", {tag, "0.2.0"}}}
+]}.
{erl_opts, [
%% bin_opt_info,
%% warn_missing_spec,
View
@@ -1,5 +1,7 @@
{cover_enabled, true}.
{deps, [
+ {ranch, "0.2.0",
+ {git, "git://github.com/extend/ranch.git", {tag, "0.2.0"}}},
{proper, "1.0",
{git, "git://github.com/manopapad/proper.git", {tag, "v1.0"}}}
]}.
View
@@ -19,7 +19,8 @@
{registered, [cowboy_clock, cowboy_sup]},
{applications, [
kernel,
- stdlib
+ stdlib,
+ ranch
]},
{mod, {cowboy_app, []}},
{env, []}
View
@@ -12,103 +12,28 @@
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-%% @doc Cowboy API to start and stop listeners.
+%% @doc Cowboy convenience API to start HTTP/HTTPS listeners.
-module(cowboy).
--export([start_listener/6, stop_listener/1, child_spec/6, accept_ack/1,
- get_protocol_options/1, set_protocol_options/2]).
-
-%% @doc Start a listener for the given transport and protocol.
-%%
-%% A listener is effectively a pool of <em>NbAcceptors</em> acceptors.
-%% Acceptors accept connections on the given <em>Transport</em> and forward
-%% requests to the given <em>Protocol</em> handler. Both transport and protocol
-%% modules can be given options through the <em>TransOpts</em> and the
-%% <em>ProtoOpts</em> arguments. Available options are documented in the
-%% <em>listen</em> transport function and in the protocol module of your choice.
-%%
-%% All acceptor and request processes are supervised by the listener.
-%%
-%% It is recommended to set a large enough number of acceptors to improve
-%% performance. The exact number depends of course on your hardware, on the
-%% protocol used and on the number of expected simultaneous connections.
-%%
-%% The <em>Transport</em> option <em>max_connections</em> allows you to define
-%% the maximum number of simultaneous connections for this listener. It defaults
-%% to 1024. See <em>cowboy_listener</em> for more details on limiting the number
-%% of connections.
-%%
-%% Although Cowboy includes a <em>cowboy_http_protocol</em> handler, other
-%% handlers can be created for different protocols like IRC, FTP and more.
-%%
-%% <em>Ref</em> can be used to stop the listener later on.
--spec start_listener(any(), non_neg_integer(), module(), any(), module(), any())
- -> {ok, pid()}.
-start_listener(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts)
- when is_integer(NbAcceptors) andalso is_atom(Transport)
- andalso is_atom(Protocol) ->
- supervisor:start_child(cowboy_sup, child_spec(Ref, NbAcceptors,
- Transport, TransOpts, Protocol, ProtoOpts)).
-
-%% @doc Stop a listener identified by <em>Ref</em>.
+-export([start_http/4]).
+-export([start_https/4]).
+-export([stop_listener/1]).
+
+%% @doc Start an HTTP listener.
+-spec start_http(any(), non_neg_integer(), any(), any()) -> {ok, pid()}.
+start_http(Ref, NbAcceptors, TransOpts, ProtoOpts)
+ when is_integer(NbAcceptors) ->
+ ranch:start_listener(Ref, NbAcceptors,
+ ranch_tcp, TransOpts, cowboy_protocol, ProtoOpts).
+
+%% @doc Start an HTTPS listener.
+-spec start_https(any(), non_neg_integer(), any(), any()) -> {ok, pid()}.
+start_https(Ref, NbAcceptors, TransOpts, ProtoOpts)
+ when is_integer(NbAcceptors) ->
+ ranch:start_listener(Ref, NbAcceptors,
+ ranch_ssl, TransOpts, cowboy_protocol, ProtoOpts).
+
+%% @doc Stop a listener.
-spec stop_listener(any()) -> ok | {error, not_found}.
stop_listener(Ref) ->
- case supervisor:terminate_child(cowboy_sup, {cowboy_listener_sup, Ref}) of
- ok ->
- supervisor:delete_child(cowboy_sup, {cowboy_listener_sup, Ref});
- {error, Reason} ->
- {error, Reason}
- end.
-
-%% @doc Return a child spec suitable for embedding.
-%%
-%% When you want to embed cowboy in another application, you can use this
-%% function to create a <em>ChildSpec</em> suitable for use in a supervisor.
-%% The parameters are the same as in <em>start_listener/6</em> but rather
-%% than hooking the listener to the cowboy internal supervisor, it just returns
-%% the spec.
--spec child_spec(any(), non_neg_integer(), module(), any(), module(), any())
- -> supervisor:child_spec().
-child_spec(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts)
- when is_integer(NbAcceptors) andalso is_atom(Transport)
- andalso is_atom(Protocol) ->
- {{cowboy_listener_sup, Ref}, {cowboy_listener_sup, start_link, [
- NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts
- ]}, permanent, 5000, supervisor, [cowboy_listener_sup]}.
-
-%% @doc Acknowledge the accepted connection.
-%%
-%% Effectively used to make sure the socket control has been given to
-%% the protocol process before starting to use it.
--spec accept_ack(pid()) -> ok.
-accept_ack(ListenerPid) ->
- receive {shoot, ListenerPid} -> ok end.
-
-%% @doc Return the current protocol options for the given listener.
--spec get_protocol_options(any()) -> any().
-get_protocol_options(Ref) ->
- ListenerPid = ref_to_listener_pid(Ref),
- {ok, ProtoOpts} = cowboy_listener:get_protocol_options(ListenerPid),
- ProtoOpts.
-
-%% @doc Upgrade the protocol options for the given listener.
-%%
-%% The upgrade takes place at the acceptor level, meaning that only the
-%% newly accepted connections receive the new protocol options. This has
-%% no effect on the currently opened connections.
--spec set_protocol_options(any(), any()) -> ok.
-set_protocol_options(Ref, ProtoOpts) ->
- ListenerPid = ref_to_listener_pid(Ref),
- ok = cowboy_listener:set_protocol_options(ListenerPid, ProtoOpts).
-
-%% Internal.
-
--spec ref_to_listener_pid(any()) -> pid().
-ref_to_listener_pid(Ref) ->
- Children = supervisor:which_children(cowboy_sup),
- {_, ListenerSupPid, _, _} = lists:keyfind(
- {cowboy_listener_sup, Ref}, 1, Children),
- ListenerSupChildren = supervisor:which_children(ListenerSupPid),
- {_, ListenerPid, _, _} = lists:keyfind(
- cowboy_listener, 1, ListenerSupChildren),
- ListenerPid.
+ ranch:stop_listener(Ref).
Oops, something went wrong.

0 comments on commit e80e37b

Please sign in to comment.