aboutsummaryrefslogtreecommitdiffstats
path: root/guide
diff options
context:
space:
mode:
Diffstat (limited to 'guide')
-rw-r--r--guide/handlers.md22
-rw-r--r--guide/hooks.md69
-rw-r--r--guide/http_handlers.md22
-rw-r--r--guide/internals.md76
-rw-r--r--guide/introduction.md2
-rw-r--r--guide/loop_handlers.md30
-rw-r--r--guide/req.md180
-rw-r--r--guide/routing.md89
-rw-r--r--guide/static_handlers.md18
-rw-r--r--guide/toc.md14
-rw-r--r--guide/ws_handlers.md25
11 files changed, 496 insertions, 51 deletions
diff --git a/guide/handlers.md b/guide/handlers.md
index dac5460..e2c1264 100644
--- a/guide/handlers.md
+++ b/guide/handlers.md
@@ -33,7 +33,23 @@ init(_Any, _Req, _Opts) ->
{upgrade, protocol, my_protocol}.
```
-The `my_protocol` module will be used for further processing of the
-request. It requires only one callback, `upgrade/4`.
+Cowboy comes with two protocol upgrades: `cowboy_rest` and
+`cowboy_websocket`. Use these values in place of `my_protocol`
+to use them.
-@todo Describe `upgrade/4` when the middleware code gets pushed.
+Custom protocol upgrades
+------------------------
+
+The `my_protocol` module above will be used for further processing
+of the request. It requires only one callback, `upgrade/4`.
+
+It receives the request object, the middleware environment, and
+the handler this request has been routed to along with its options.
+
+``` erlang
+upgrade(Req, Env, Handler, HandlerOpts) ->
+ %% ...
+```
+
+This callback is expected to behave like any middleware. Please
+see the corresponding chapter for more information.
diff --git a/guide/hooks.md b/guide/hooks.md
index ba48c4a..d4b520a 100644
--- a/guide/hooks.md
+++ b/guide/hooks.md
@@ -4,9 +4,74 @@ Hooks
On request
----------
-@todo Describe.
+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.
On response
-----------
-@todo Describe.
+The `onresponse` hook is called right before sending the response
+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.
+
+You can specify the `onresponse` hook when creating the listener also.
+
+``` erlang
+cowboy:start_http(my_http_listener, 100,
+ [{port, 8080}],
+ [
+ {env, [{dispatch, Dispatch}]},
+ {onresponse, fun ?MODULE:custom_404_hook/4}
+ ]
+).
+```
+
+The following hook function will provide a custom body for 404 errors
+when it has not been provided before, and will let Cowboy proceed with
+the default response otherwise.
+
+``` erlang
+custom_404_hook(404, Headers, <<>>, Req) ->
+ {ok, Req2} = cowboy_req:reply(404, Headers, <<"404 Not Found.">>, Req),
+ Req2;
+custom_404_hook(_, _, _, Req) ->
+ Req.
+```
+
+Again, make sure to always return the last request object obtained.
diff --git a/guide/http_handlers.md b/guide/http_handlers.md
index 0d8886d..ea88c79 100644
--- a/guide/http_handlers.md
+++ b/guide/http_handlers.md
@@ -6,12 +6,22 @@ Purpose
HTTP handlers are the simplest Cowboy module to handle a request.
-Callbacks
----------
-
-@todo Describe the callbacks.
-
Usage
-----
-@todo Explain how to use them.
+You need to implement three callbacks for HTTP handlers. The first,
+`init/3`, is common to all handlers. In the context of HTTP handlers
+this should be used for any initialization needs.
+
+The second callback, `handle/2`, is where most of your code should
+be. As the name explains, this is where you handle the request.
+
+The last callback, `terminate/2`, will be empty most of the time.
+It's used for any needed cleanup. If you used the process dictionary,
+timers, monitors then you most likely want to stop them in this
+callback, as Cowboy might end up reusing this process for subsequent
+requests. Please see the Internals chapter for more information.
+
+Of course the general advice is to not use the process dictionary,
+and that any operation requiring reception of messages should be
+done in a loop handler, documented in its own chapter.
diff --git a/guide/internals.md b/guide/internals.md
index 431ca01..0f8adc2 100644
--- a/guide/internals.md
+++ b/guide/internals.md
@@ -4,10 +4,76 @@ Internals
Architecture
------------
-@todo Describe.
+Cowboy is a lightweight HTTP server.
-Efficiency considerations
--------------------------
+It is built on top of Ranch. Please see the Ranch guide for more
+informations.
-@todo Mention that you need to cleanup in terminate especially if you
-used the process dictionary, started timers, started monitoring...
+It uses only one process per connection. The process where your
+code runs is the process controlling the socket. Using one process
+instead of two allows for lower memory usage.
+
+It uses binaries. Binaries are more efficient than lists for
+representing strings because they take less memory space. Processing
+performance can vary depending on the operation. Binaries are known
+for generally getting a great boost if the code is compiled natively.
+Please see the HiPE documentation for more details.
+
+Because querying for the current date and time can be expensive,
+Cowboy generates one `Date` header value every second, shares it
+to all other processes, which then simply copy it in the response.
+This allows compliance with HTTP/1.1 with no actual performance loss.
+
+One process for many requests
+-----------------------------
+
+As previously mentioned, Cowboy only use one process per connection.
+Because there can be more than one request per connection with the
+keepalive feature of HTTP/1.1, that means the same process will be
+used to handle many requests.
+
+Because of this, you are expected to make sure your process cleans
+up before terminating the handling of the current request. This may
+include cleaning up the process dictionary, timers, monitoring and
+more.
+
+Lowercase header names
+----------------------
+
+For consistency reasons it has been chosen to convert all header names
+to lowercase binary strings. This prevents the programmer from making
+case mistakes, and is possible because header names are case insensitive.
+
+This works fine for the large majority of clients. However, some badly
+implemented clients, especially ones found in corporate code or closed
+source products, may not handle header names in a case insensitive manner.
+This means that when Cowboy returns lowercase header names, these clients
+will not find the headers they are looking for.
+
+A simple way to solve this is to create an `onresponse` hook that will
+format the header names with the expected case.
+
+``` erlang
+capitalize_hook(Status, Headers, Body, Req) ->
+ Headers2 = [{cowboy_bstr:capitalize_token(N), V}
+ || {N, V} <- Headers],
+ {ok, Req2} = cowboy_req:reply(Status, Headers2, Body, Req),
+ Req2.
+```
+
+Improving performance
+---------------------
+
+By default the maximum number of active connections is set to a
+generally accepted big enough number. This is meant to prevent having
+too many processes performing potentially heavy work and slowing
+everything else down, or taking up all the memory.
+
+Disabling this feature, by setting the `{max_connections, infinity}`
+protocol option, would give you greater performance when you are
+only processing short-lived requests.
+
+Another option is to define platform-specific socket options that
+are known to improve their efficiency.
+
+Please see the Ranch guide for more information.
diff --git a/guide/introduction.md b/guide/introduction.md
index 4d1dacc..f1fd18e 100644
--- a/guide/introduction.md
+++ b/guide/introduction.md
@@ -77,7 +77,7 @@ Dispatch = [
],
%% Name, NbAcceptors, TransOpts, ProtoOpts
cowboy:start_http(my_http_listener, 100,
- [{port, 8080}],
+ [{port, 8080}],
[{env, [{dispatch, Dispatch}]}]
).
```
diff --git a/guide/loop_handlers.md b/guide/loop_handlers.md
index 6d67c62..64cf80a 100644
--- a/guide/loop_handlers.md
+++ b/guide/loop_handlers.md
@@ -16,15 +16,23 @@ While the same can be accomplished using plain HTTP handlers,
it is recommended to use loop handlers because they are well-tested
and allow using built-in features like hibernation and timeouts.
-Callbacks
----------
-
-@todo Describe the callbacks.
-
Usage
-----
-@todo Explain how to use them.
+Loop handlers are used for requests where a response might not
+be immediately available, but where you would like to keep the
+connection open for a while in case the response arrives. The
+most known example of such practice is known as long-polling.
+
+Loop handlers can also be used for requests where a response is
+partially available and you need to stream the response body
+while the connection is open. The most known example of such
+practice is known as server-sent events.
+
+Loop handlers essentially wait for one or more Erlang messages
+and feed these messages to the `info/3` callback. It also features
+the `init/3` and `terminate/2` callbacks which work the same as
+for plain HTTP handlers.
The following handler waits for a message `{reply, Body}` before
sending a response. If this message doesn't arrive within 60
@@ -41,14 +49,14 @@ this message.
-export([terminate/2]).
init({tcp, http}, Req, Opts) ->
- {loop, Req, undefined_state, 60000, hibernate}.
+ {loop, Req, undefined_state, 60000, hibernate}.
info({reply, Body}, Req, State) ->
- {ok, Req2} = cowboy_req:reply(200, [], Body, Req),
- {ok, Req2, State};
+ {ok, Req2} = cowboy_req:reply(200, [], Body, Req),
+ {ok, Req2, State};
info(Message, Req, State) ->
- {loop, Req, State, hibernate}.
+ {loop, Req, State, hibernate}.
terminate(Req, State) ->
- ok.
+ ok.
```
diff --git a/guide/req.md b/guide/req.md
index 79c59a9..c039658 100644
--- a/guide/req.md
+++ b/guide/req.md
@@ -4,19 +4,187 @@ Request object
Purpose
-------
-@todo Describe.
+The request object is a special variable that can be used
+to interact with a request, extracting information from it
+or modifying it, and sending a response.
+
+It's a special variable because it contains both immutable
+and mutable state. This means that some operations performed
+on the request object will always return the same result,
+while others will not. For example, obtaining request headers
+can be repeated safely. Obtaining the request body can only
+be done once, as it is read directly from the socket.
+
+With few exceptions, all calls to the `cowboy_req` module
+will return an updated request object. You MUST use the new
+request object instead of the old one for all subsequent
+operations.
Request
-------
-@todo Describe.
+Cowboy allows you to retrieve a lot of information about
+the request. All these calls return a `{Value, Req}` tuple,
+with `Value` the requested value and `Req` the updated
+request object.
+
+The following access functions are defined in `cowboy_req`:
+
+ * `method/1`: the request method (`<<"GET">>`, `<<"POST">>`...)
+ * `version/1`: the HTTP version (`{1,0}` or `{1,1}`)
+ * `peer/1`: the peer address and port number
+ * `peer_addr/1`: the peer address guessed using the request headers
+ * `host/1`: the hostname requested
+ * `host_info/1`: the result of the `[...]` match on the host
+ * `port/1`: the port number used for the connection
+ * `path/1`: the path requested
+ * `path_info/1`: the result of the `[...]` match on the path
+ * `qs/1`: the entire query string unmodified
+ * `qs_val/{2,3}`: the value for the requested query string key
+ * `qs_vals/1`: all key/values found in the query string
+ * `fragment/1`: the fragment part of the URL (e.g. `#nav-links`)
+ * `host_url/1`: the requested URL without the path, qs and fragment
+ * `url/1`: the requested URL
+ * `binding/{2,3}`: the value for the requested binding found during routing
+ * `bindings/1`: all key/values found during routing
+ * `header/{2,3}`: the value for the requested header name
+ * `headers/1`: all headers name/value
+ * `cookie/{2,3}`: the value for the requested cookie name
+ * `cookies/1`: all cookies name/value
+ * `meta/{2,3}`: the meta information for the requested key
+
+All the functions above that can take two or three arguments
+take an optional third argument for the default value if
+none is found. Otherwise it will return `undefined`.
+
+In addition, Cowboy allows you to parse headers using the
+`parse_header/{2,3}` function, which takes a header name
+as lowercase binary, the request object, and an optional
+default value. It returns `{ok, ParsedValue, Req}` if it
+could be parsed, `{undefined, RawValue, Req}` if Cowboy
+doesn't know this header, and `{error, badarg}` if Cowboy
+encountered an error while trying to parse it.
+
+Finally, Cowboy allows you to set request meta information
+using the `set_meta/3` function, which takes a name, a value
+and the request object and returns the latter modified.
Request body
------------
-@todo Describe.
+Cowboy will not read the request body until you ask it to.
+If you don't, then Cowboy will simply discard it. It will
+not take extra memory space until you start reading it.
+
+Cowboy has a few utility functions for dealing with the
+request body.
+
+The function `has_body/1` will return whether the request
+contains a body. Note that some clients may not send the
+right headers while still sending a body, but as Cowboy has
+no way of detecting it this function will return `false`.
+
+The function `body_length/1` retrieves the size of the
+request body. If the body is compressed, the value returned
+here is the compressed size. If a `Transfer-Encoding` header
+was passed in the request, then Cowboy will return a size
+of `undefined`, as it has no way of knowing it.
+
+If you know the request contains a body, and that it is
+of appropriate size, then you can read it directly with
+either `body/1` or `body_qs/1`. Otherwise, you will want
+to stream it with `stream_body/1` and `skip_body/1`, with
+the streaming process optionally initialized using `init_stream/4`.
+
+Multipart request body
+----------------------
+
+Cowboy provides facilities for dealing with multipart bodies.
+They are typically used for uploading files. You can use two
+functions to process these bodies, `multipart_data/1` and
+`multipart_skip/1`.
+
+Response
+--------
+
+You can send a response by calling the `reply/{2,3,4}` function.
+It takes the status code for the response (usually `200`),
+an optional list of headers, an optional body and the request
+object.
+
+The following snippet sends a simple response with no headers
+specified but with a body.
+
+``` erlang
+{ok, Req2} = cowboy_req:reply(200, [], "Hello world!", Req).
+```
+
+If this is the only line in your handler then make sure to return
+the `Req2` variable to Cowboy so it can know you replied.
+
+If you want to send HTML you'll need to specify the `Content-Type`
+header so the client can properly interpret it.
+
+``` erlang
+{ok, Req2} = cowboy_req:reply(200,
+ [{<<"content-type">>, <<"text/html">>}],
+ "<html><head>Hello world!</head><body><p>Hats off!</p></body></html>",
+ Req).
+```
+
+You only need to make sure to follow conventions and to use a
+lowercase header name.
+
+Chunked response
+----------------
+
+You can also send chunked responses using `chunked_reply/{2,3}`.
+Chunked responses allow you to send the body in chunks of various
+sizes. It is the recommended way of performing streaming if the
+client supports it.
+
+You must first initiate the response by calling the aforementioned
+function, then you can call `chunk/2` as many times as needed.
+The following snippet sends a body in three chunks.
+
+``` erlang
+{ok, Req2} = cowboy_req:chunked_reply(200, Req),
+ok = cowboy_req:chunk("Hello...", Req2),
+ok = cowboy_req:chunk("chunked...", Req2),
+ok = cowboy_req:chunk("world!!", Req2).
+```
+
+As you can see the call to `chunk/2` does not return a modified
+request object. It may return an error, however, so you should
+make sure that you match the return value on `ok`.
+
+Response preconfiguration
+-------------------------
+
+Cowboy allows you to set response cookies, headers or body
+in advance without having to send the response at the same time.
+Then, when you decide to send it, all these informations will be
+built into the resulting response.
+
+Some of the functions available for this purpose also give you
+additional functionality, like `set_resp_cookie/4` which will build
+the appropriate `Set-Cookie` header, or `set_resp_body_fun/{2,3}`
+which allows you to stream the response body.
+
+Note that any value given directly to `reply/{2,3,4}` will
+override all preset values. This means for example that you
+can set a default body and then override it when you decide
+to send a reply.
+
+Reducing the memory footprint
+-----------------------------
-Reply
------
+When you are done reading information from the request object
+and know you are not going to access it anymore, for example
+when using long-polling or Websocket, you can use the `compact/1`
+function to remove most of the data from the request object and
+free memory.
-@todo Describe.
+``` erlang
+Req2 = cowboy_req:compact(Req).
+```
diff --git a/guide/routing.md b/guide/routing.md
index 7d6fa41..2970b39 100644
--- a/guide/routing.md
+++ b/guide/routing.md
@@ -90,10 +90,12 @@ PathMatch3 = "/path/to/resource/".
```
Hosts with and without a trailing dot are equivalent for routing.
+Similarly, hosts with and without a leading dot are also equivalent.
``` erlang
HostMatch1 = "cowboy.example.org".
HostMatch2 = "cowboy.example.org.".
+HostMatch3 = ".cowboy.example.org".
```
It is possible to extract segments of the host and path and to store
@@ -115,16 +117,93 @@ segment value where they were defined. For example, the URL
`http://test.example.org/hats/wild_cowboy_legendary/prices` will
result in having the value `test` bound to the name `subdomain`
and the value `wild_cowboy_legendary` bound to the name `hat_name`.
-They can later be retrieved using `cowboy_req:binding/{2,3}`.
+They can later be retrieved using `cowboy_req:binding/{2,3}`. The
+binding name must be given as an atom.
-@todo special binding `'_'`
-@todo optional path or segments
-@todo same binding twice (+ optional + host/path)
+There is a special binding name you can use to mimic the underscore
+variable in Erlang. Any match against the `_` binding will succeed
+but the data will be discarded. This is especially useful for
+matching against many domain names in one go.
+
+``` erlang
+HostMatch = "ninenines.:_".
+```
+
+Similarly, it is possible to have optional segments. Anything
+between brackets is optional.
+
+``` erlang
+PathMatch = "/hats/[page/:number]".
+HostMatch = "[www.]ninenines.eu".
+```
+
+You can also have imbricated optional segments.
+
+``` erlang
+PathMatch = "/hats/[page/[:number]]".
+```
+
+You can retrieve the rest of the host or path using `[...]`.
+In the case of hosts it will match anything before, in the case
+of paths anything after the previously matched segments. It is
+a special case of optional segments, in that it can have
+zero, one or many segments. You can then find the segments using
+`cowboy_req:host_info/1` and `cowboy_req:path_info/1` respectively.
+They will be represented as a list of segments.
+
+``` erlang
+PathMatch = "/hats/[...]".
+HostMatch = "[...]ninenines.eu".
+```
+
+Finally, if a binding appears twice in the routing rules, then the
+match will succeed only if they share the same value. This copies
+the Erlang pattern matching behavior.
+
+``` erlang
+PathMatch = "/hats/:name/:name".
+```
+
+This is also true when an optional segment is present. In this
+case the two values must be identical only if the segment is
+available.
+
+``` erlang
+PathMatch = "/hats/:name/[:name]".
+```
+
+If a binding is defined in both the host and path, then they must
+also share the same value.
+
+``` erlang
+PathMatch = "/:user/[...]".
+HostMatch = ":user.github.com".
+```
Constraints
-----------
-@todo Describe constraints.
+After the matching has completed, the resulting bindings can be tested
+against a set of constraints. The match will succeed only if they all
+succeed.
+
+They are always given as a two or three elements tuple, where the first
+element is the name of the binding, the second element is the constraint's
+name, and the optional third element is the constraint's arguments.
+
+The following constraints are currently defined:
+
+ * {Name, int}
+ * {Name, function, (fun(Value) -> true | {true, NewValue} | false)}
+
+The `int` constraint will check if the binding is a binary string
+representing an integer, and if it is, will convert the value to integer.
+
+The `function` constraint will pass the binding value to a user specified
+function that receives the binary value as its only argument and must
+return whether it fulfills the constraint, optionally modifying the value.
+
+Note that constraint functions SHOULD be pure and MUST NOT crash.
Compilation
-----------
diff --git a/guide/static_handlers.md b/guide/static_handlers.md
index 5c897dd..f87515a 100644
--- a/guide/static_handlers.md
+++ b/guide/static_handlers.md
@@ -11,4 +11,20 @@ proper cache handling.
Usage
-----
-@todo Describe.
+Static handlers are pre-written REST handlers. They only need
+to be specified in the routing information with the proper options.
+
+The following example routing serves all files found in the
+`priv_dir/static/` directory of the application. It uses a
+mimetypes library to figure out the files' content types.
+
+``` erlang
+Dispatch = [
+ {'_', [
+ {['...'], cowboy_static, [
+ {directory, {priv_dir, static, []}},
+ {mimetypes, {fun mimetypes:path_to_mimes/2, default}}
+ ]}
+ ]}
+].
+```
diff --git a/guide/toc.md b/guide/toc.md
index 2498b4d..2890172 100644
--- a/guide/toc.md
+++ b/guide/toc.md
@@ -15,17 +15,15 @@ Cowboy User Guide
* [Handlers](handlers.md)
* Purpose
* Protocol upgrades
+ * Custom protocol upgrades
* [HTTP handlers](http_handlers.md)
* Purpose
- * Callbacks
* Usage
* [Loop handlers](loop_handlers.md)
* Purpose
- * Callbacks
* Usage
* [Websocket handlers](ws_handlers.md)
* Purpose
- * Callbacks
* Usage
* [REST handlers](rest_handlers.md)
* Purpose
@@ -39,7 +37,11 @@ Cowboy User Guide
* Purpose
* Request
* Request body
- * Reply
+ * Multipart request body
+ * Response
+ * Chunked response
+ * Response preconfiguration
+ * Reducing the memory footprint
* [Hooks](hooks.md)
* On request
* On response
@@ -51,4 +53,6 @@ Cowboy User Guide
* Handler middleware
* [Internals](internals.md)
* Architecture
- * Efficiency considerations
+ * One process for many requests
+ * Lowercase header names
+ * Improving performance
diff --git a/guide/ws_handlers.md b/guide/ws_handlers.md
index 226ada0..c1e551e 100644
--- a/guide/ws_handlers.md
+++ b/guide/ws_handlers.md
@@ -16,15 +16,28 @@ is implemented by most browsers today, although for backward
compatibility reasons a solution like [Bullet](https://github.com/extend/bullet)
might be preferred.
-Callbacks
----------
-
-@todo Describe the callbacks.
-
Usage
-----
-@todo Explain how to use them.
+Websocket handlers are a bridge between the client and your system.
+They can receive data from the client, through `websocket_handle/3`,
+or from the system, through `websocket_info/3`. It is up to the
+handler to decide to process this data, and optionally send a reply
+to the client.
+
+The first thing to do to be able to handle websockets is to tell
+Cowboy that it should upgrade the connection to use the Websocket
+protocol, as follow.
+
+``` erlang
+init({tcp, http}, Req, Opts) ->
+ {upgrade, protocol, cowboy_websocket}.
+```
+
+Cowboy will then switch the protocol and call `websocket_init`,
+followed by zero or more calls to `websocket_data` and
+`websocket_info`. Then, when the connection is shutting down,
+`websocket_terminate` will be called.
The following handler sends a message every second. It also echoes
back what it receives.