aboutsummaryrefslogtreecommitdiffstats
path: root/guide
diff options
context:
space:
mode:
Diffstat (limited to 'guide')
-rw-r--r--guide/cookies.md140
-rw-r--r--guide/req.md426
-rw-r--r--guide/req_body.md169
-rw-r--r--guide/resp.md203
-rw-r--r--guide/toc.md5
5 files changed, 776 insertions, 167 deletions
diff --git a/guide/cookies.md b/guide/cookies.md
new file mode 100644
index 0000000..bfc8651
--- /dev/null
+++ b/guide/cookies.md
@@ -0,0 +1,140 @@
+Using cookies
+=============
+
+Cookies are a mechanism allowing applications to maintain
+state on top of the stateless HTTP protocol.
+
+Cowboy provides facilities for handling cookies. It is highly
+recommended to use them instead of writing your own, as the
+implementation of cookies can vary greatly between clients.
+
+Cookies are stored client-side and sent with every subsequent
+request that matches the domain and path for which they were
+stored, including requests for static files. For this reason
+they can incur a cost which must be taken in consideration.
+
+Also consider that, regardless of the options used, cookies
+are not to be trusted. They may be read and modified by any
+program on the user's computer, but also by proxies. You
+should always validate cookie values before using them. Do
+not store any sensitive information in cookies either.
+
+When explicitly setting the domain, the cookie will be sent
+for the domain and all subdomains from that domain. Otherwise
+the current domain will be used. The same is true for the
+path.
+
+When the server sets cookies, they will only be available
+for requests that are sent after the client receives the
+response.
+
+Cookies are sent in HTTP headers, therefore they must have
+text values. It is your responsibility to encode any other
+data type. Also note that cookie names are de facto case
+sensitive.
+
+Cookies can be set for the client session (which generally
+means until the browser is closed), or it can be set for
+a number of seconds. Once it expires, or when the server
+says the cookie must exist for up to 0 seconds, the cookie
+is deleted by the client. To avoid this while the user
+is browsing your site, you should set the cookie for
+every request, essentially resetting the expiration time.
+
+Cookies can be restricted to secure channels. This typically
+means that such a cookie will only be sent over HTTPS,
+and that it will only be available by client-side scripts
+that run from HTTPS webpages.
+
+Finally, cookies can be restricted to HTTP and HTTPS requests,
+essentially disabling their access from client-side scripts.
+
+Setting cookies
+---------------
+
+By default, cookies you set are defined for the session.
+
+``` erlang
+SessionID = generate_session_id(),
+Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [], Req).
+```
+
+You can also make them expire at a specific point in the
+future.
+
+``` erlang
+SessionID = generate_session_id(),
+Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [
+ {max_age, 3600}
+], Req).
+```
+
+You can delete cookies that have already been set. The value
+is ignored.
+
+``` erlang
+Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, <<>>, [
+ {max_age, 0}
+], Req).
+```
+
+You can restrict them to a specific domain and path.
+For example, the following cookie will be set for the domain
+`my.example.org` and all its subdomains, but only on the path
+`/account` and all its subdirectories.
+
+``` erlang
+Req2 = cowboy_req:set_resp_cookie(<<"inaccount">>, <<"1">>, [
+ {domain, "my.example.org"},
+ {path, "/account"}
+], Req).
+```
+
+You can restrict the cookie to secure channels, typically HTTPS.
+
+``` erlang
+SessionID = generate_session_id(),
+Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [
+ {secure, true}
+], Req).
+```
+
+You can restrict the cookie to client-server communication
+only. Such a cookie will not be available to client-side scripts.
+
+``` erlang
+SessionID = generate_session_id(),
+Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [
+ {http_only, true}
+], Req).
+```
+
+Cookies may also be set client-side, for example using
+Javascript.
+
+Reading cookies
+---------------
+
+As we said, the client sends cookies with every request.
+But unlike the server, the client only sends the cookie
+name and value.
+
+You can read the value of a cookie.
+
+``` erlang
+{CookieVal, Req2} = cowboy_req:cookie(<<"lang">>, Req).
+```
+
+You can also get a default value returned when the cookie
+isn't set.
+
+``` erlang
+{CookieVal, Req2} = cowboy_req:cookie(<<"lang">>, Req, <<"fr">>).
+```
+
+And you can obtain all cookies at once as a list of
+key/value tuples.
+
+``` erlang
+{AllCookies, Req2} = cowboy_req:cookies(Req).
+```
diff --git a/guide/req.md b/guide/req.md
index 96f72b9..2b59152 100644
--- a/guide/req.md
+++ b/guide/req.md
@@ -1,204 +1,298 @@
-Request object
+The Req object
==============
-Purpose
+The Req object is this variable that you will use to obtain
+information about a request, read the body of the request
+and send a response.
+
+A special variable
+------------------
+
+While we call it an "object", it is not an object in the
+OOP sense of the term. In fact it is completely opaque
+to you and the only way you can perform operations using
+it is by calling the functions from the `cowboy_req`
+module.
+
+Almost all the calls to the `cowboy_req` module will
+return an updated request object. Just like you would
+keep the updated `State` variable in a gen_server,
+you MUST keep the updated `Req` variable in a Cowboy
+handler. Cowboy will use this object to know whether
+a response has been sent when the handler has finished
+executing.
+
+The Req object allows accessing both immutable and
+mutable state. This means that calling some of the
+functions twice will not produce the same result.
+For example, when streaming the request body, the
+function will return the body by chunks, one at a
+time, until there is none left.
+
+It also caches the result of operations performed
+on the immutable state. That means that some calls
+will give a result much faster when called many times.
+
+Overview of the cowboy_req interface
+------------------------------------
+
+The `cowboy_req` interface is divided in four groups
+of functions, each having a well defined return type
+signature common to the entire group.
+
+The first group, access functions, will always return
+`{Value, Req}`. The group includes all the following
+functions: `binding/{2,3}`, `bindings/1`, `body_length/1`,
+`cookie/{2,3}`, `cookies/1`, `header/{2,3}`, `headers/1`,
+`host/1`, `host_info/1`, `host_url/1`, `meta/{2,3}`,
+`method/1`, `path/1`, `path_info/1`, `peer/1`, `port/1`,
+`qs/1`, `qs_val/{2,3}`, `qs_vals/1`, `url/1`, `version/1`.
+
+The second group, question functions, will always return
+a `boolean()`. The group includes the following three
+functions: `has_body/1`, `has_resp_body/1`, `has_resp_header/2`.
+
+The third group contains the functions that manipulate
+the socket or perform operations that may legitimately fail.
+They may return `{Result, Req}`, `{Result, Value, Req}`
+or `{error, atom()}`. This includes the following functions:
+`body/{1,2}`, `body_qs/{1,2}`, `chunked_reply/{2,3}`,
+`init_stream/4`, `parse_header/{2,3}`, `reply/{2,3,4}`,
+`skip_body/1`, `stream_body/{1,2}`. Finally, the group
+also includes the `chunk/2` function which always returns
+`ok`.
+
+The final group modifies the Req object, so it always return
+a new `Req`. It includes the following functions: `compact/1`,
+`delete_resp_header/2`, `set_meta/3`, `set_resp_body/2`,
+`set_resp_body_fun/{2,3}`, `set_resp_cookie/4`, `set_resp_header/3`.
+
+This chapter covers most of the first group, plus a few other
+functions. The next few chapters cover cookies handling, reading
+the request body and sending a response.
+
+Request
-------
-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.
+When a client performs a request, it first sends a few required
+values. They are sent differently depending on the protocol
+being used, but the intent is the same. They indicate to the
+server the type of action it wants to do and how to locate
+the resource to perform it on.
-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.
+The method identifies the action. Standard methods include
+GET, HEAD, OPTIONS, PATCH, POST, PUT, DELETE. Method names
+are case sensitive.
-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.
+``` erlang
+{Method, Req2} = cowboy_req:method(Req).
+```
-Request
--------
+The host, port and path parts of the URL identify the resource
+being accessed. The host and port information may not be
+available if the client uses HTTP/1.0.
-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 (`'HTTP/1.0'` or `'HTTP/1.1'`)
- * `peer/1`: the peer address and port number
- * `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
- * `host_url/1`: the requested URL without the path and query string
- * `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
-------------
+``` erlang
+{Host, Req2} = cowboy_req:host(Req),
+{Port, Req3} = cowboy_req:port(Req2),
+{Path, Req4} = cowboy_req:path(Req3).
+```
-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
-within 8MB (for `body/1`) or 16KB (for `body_qs/1`) bytes,
-then you can read it directly with either `body/1` or `body_qs/1`.
-If you want to override the default size limits of `body/1`
-or `body_qs/1`, you can pass the maximum body length byte
-size as first parameter to `body/2` and `body_qs/2` or pass
-atom `infinity` to ignore size limits.
-
-If the request contains bigger body than allowed default sizes
-or supplied maximum body length, `body/1`, `body/2`, `body_qs/1`
-and `body_qs/2` will return `{error, badlength}`. If the request
-contains chunked body, `body/1`, `body/2`, `body_qs/1`
-and `body_qs/2` will return `{error, chunked}`.
-If you get either of the above two errors, you will want to
-handle the body of the request using `stream_body/1`,
-`stream_body/2` 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
+The version used by the client can of course also be obtained.
+
+``` erlang
+{Version, Req2} = cowboy_req:version(Req).
+```
+
+Do note however that clients claiming to implement one version
+of the protocol does not mean they implement it fully, or even
+properly.
+
+Bindings
--------
-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.
+After routing the request, bindings are available. Bindings
+are these parts of the host or path that you chose to extract
+when defining the routes of your application.
+
+You can fetch a single binding. The value will be `undefined`
+if the binding doesn't exist.
+
+``` erlang
+{Binding, Req2} = cowboy_req:binding(my_binding, Req).
+```
+
+If you need a different value when the binding doesn't exist,
+you can change the default.
+
+``` erlang
+{Binding, Req2} = cowboy_req:binding(my_binding, Req, 42).
+```
+
+You can also obtain all bindings in one call. They will be
+returned as a list of key/value tuples.
+
+``` erlang
+{AllBindings, Req2} = cowboy_req:bindings(Req).
+```
+
+If you used `...` at the beginning of the route's pattern
+for the host, you can retrieve the matched part of the host.
+The value will be `undefined` otherwise.
+
+``` erlang
+{HostInfo, Req2} = cowboy_req:host_info(Req).
+```
+
+Similarly, if you used `...` at the end of the route's
+pattern for the path, you can retrieve the matched part,
+or get `undefined` otherwise.
+
+``` erlang
+{PathInfo, Req2} = cowboy_req:path_info(Req).
+```
+
+Query string
+------------
+
+The query string can be obtained directly.
+
+``` erlang
+{Qs, Req2} = cowboy_req:qs(Req).
+```
+
+You can also requests only one value.
+
+``` erlang
+{QsVal, Req2} = cowboy_req:qs_val(<<"lang">>, Req).
+```
+
+If that value is optional, you can define a default to simplify
+your task.
+
+``` erlang
+{QsVal, Req2} = cowboy_req:qs_val(<<"lang">>, Req, <<"en">>).
+```
+
+Finally, you can obtain all query string values.
+
+``` erlang
+{AllValues, Req2} = cowboy_req:qs_vals(Req).
+```
+
+Request URL
+-----------
+
+You can reconstruct the full URL of the resource.
+
+``` erlang
+{URL, Req2} = cowboy_req:url(Req).
+```
+
+You can also obtain only the base of the URL, excluding the
+path and query string.
+
+``` erlang
+{BaseURL, Req2} = cowboy_req:host_url(Req).
+```
+
+Headers
+-------
-The following snippet sends a simple response with no headers
-specified but with a body.
+Cowboy allows you to obtain the header values as string,
+or parsed into a more meaningful representation.
+
+This will get the string value of a header.
``` erlang
-{ok, Req2} = cowboy_req:reply(200, [], "Hello world!", Req).
+{HeaderVal, Req2} = cowboy_req:header(<<"content-type">>, 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.
+You can of course set a default in case the header is missing.
+
+``` erlang
+{HeaderVal, Req2}
+ = cowboy_req:header(<<"content-type">>, Req, <<"text/plain">>).
+```
-If you want to send HTML you'll need to specify the `Content-Type`
-header so the client can properly interpret it.
+And also obtain all headers.
``` erlang
-{ok, Req2} = cowboy_req:reply(200,
- [{<<"content-type">>, <<"text/html">>}],
- "<html><head>Hello world!</head><body><p>Hats off!</p></body></html>",
- Req).
+{AllHeaders, Req2} = cowboy_req:headers(Req).
```
-You only need to make sure to follow conventions and to use a
-lowercase header name.
+To parse the previous header, simply call `parse_header/{2,3}`
+where you would call `header/{2,3}` otherwise. Note that the
+return value changes and includes the result of the operation
+as the first element of the returned tuple. A successful parse
+returns `ok`.
-Chunked response
-----------------
+``` erlang
+{ok, ParsedVal, Req2} = cowboy_req:parse_header(<<"content-type">>, Req).
+```
-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.
+When Cowboy doesn't know how to parse the given header, the
+result of the operation will be `undefined` and the string value
+will be returned instead.
-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
+{undefined, HeaderVal, Req2}
+ = cowboy_req:parse_header(<<"unicorn-header">>, Req).
+```
+
+When parsing fails, `{error, Reason}` is returned instead.
+
+You can of course define a default value. Note that the default
+value you specify here is the parsed value you'd like to get
+by default.
``` 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).
+{ok, ParsedVal, Req2}
+ = cowboy_req:parse_header(<<"content-type">>, Req,
+ {<<"text">>, <<"plain">>, []}).
```
-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`.
+The list of known headers and default values is defined in the
+manual. Also note that the result of parsing is cached, so
+calling this function multiple times for the same values will
+not have a significant performance impact.
-Response preconfiguration
--------------------------
+Meta
+----
-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.
+Cowboy will sometimes associate some meta information with
+the request. Built-in meta values are listed in the manual
+for their respective modules.
-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.
+This will get a meta value. The returned value will be `undefined`
+if it isn't defined.
-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.
+``` erlang
+{MetaVal, Req2} = cowboy_req:meta(websocket_version, Req).
+```
+
+You can change the default value if needed.
+
+``` erlang
+{MetaVal, Req2} = cowboy_req:meta(websocket_version, Req, 13).
+```
-Closing the connection
-----------------------
+You can also define your own meta values. The name must be
+an `atom()`.
-HTTP/1.1 keep-alive allows clients to send more than one request
-on the same connection. This can be useful for speeding up the
-loading of webpages, but is not required. You can tell Cowboy
-explicitly that you want to close the connection by setting the
-`Connection` header to `close`.
+``` erlang
+Req2 = cowboy_req:set_meta(the_answer, 42, Req).
+```
+
+Peer
+----
+
+You can obtain the peer address and port number. This is
+not necessarily the actual IP and port of the client, but
+rather the one of the machine that connected to the server.
``` erlang
-{ok, Req2} = cowboy_req:reply(200,
- [{<<"connection">>, <<"close">>}],
- Req).
+{{IP, Port}, Req2} = cowboy_req:peer(Req).
```
Reducing the memory footprint
@@ -213,3 +307,5 @@ free memory.
``` erlang
Req2 = cowboy_req:compact(Req).
```
+
+You will still be able to send a reply if needed.
diff --git a/guide/req_body.md b/guide/req_body.md
new file mode 100644
index 0000000..d573505
--- /dev/null
+++ b/guide/req_body.md
@@ -0,0 +1,169 @@
+Reading the request body
+========================
+
+The Req object also allows you to read the request body.
+
+Because the request body can be of any size, all body
+reading operations will only work once, as Cowboy will
+not cache the result of these operations.
+
+Cowboy will not attempt to read the body until you do.
+If handler execution ends without reading it, Cowboy
+will simply skip it.
+
+Check for request body
+----------------------
+
+You can check whether a body was sent with the request.
+
+``` erlang
+cowboy_req:has_body(Req).
+```
+
+It will return `true` if there is a request body, and
+`false` otherwise.
+
+Note that it is generally safe to assume that a body is
+sent for `POST`, `PUT` and `PATCH` requests, without
+having to explicitly check for it.
+
+Request body length
+-------------------
+
+You can obtain the body length if it was sent with the
+request.
+
+``` erlang
+{Length, Req2} = cowboy_req:body_length(Req).
+```
+
+The value returned will be `undefined` if the length
+couldn't be figured out from the request headers. If
+there's a body but no length is given, this means that
+the chunked transfer-encoding was used. You can read
+chunked bodies by using the stream functions.
+
+Reading the body
+----------------
+
+If a content-length header was sent with the request,
+you can read the whole body directly.
+
+``` erlang
+{ok, Body, Req2} = cowboy_req:body(Req).
+```
+
+If no content-length header is available, Cowboy will
+return the `{error, chunked}` tuple. You will need to
+stream the request body instead.
+
+By default, Cowboy will reject all body sizes above 8MB,
+to prevent an attacker from needlessly filling up memory.
+You can override this limit however.
+
+``` erlang
+{ok, Body, Req2} = cowboy_req:body(100000000, Req).
+```
+
+You can also disable it.
+
+``` erlang
+{ok, Body, Req2} = cowboy_req:body(infinity, Req).
+```
+
+It is recommended that you do not disable it for public
+facing websites.
+
+Reading a body sent from an HTML form
+-------------------------------------
+
+You can directly obtain a list of key/value pairs if the
+body was sent using the application/x-www-form-urlencoded
+content-type.
+
+``` erlang
+{ok, KeyValues, Req2} = cowboy_req:body_qs(Req).
+```
+
+You can then retrieve an individual value from that list.
+
+``` erlang
+{_, Lang} = lists:keyfind(lang, 1, KeyValues).
+```
+
+You should not attempt to match on the list as the order
+of the values is undefined.
+
+By default Cowboy will reject bodies with a size above
+16KB when using this function. You can override this limit.
+
+``` erlang
+{ok, KeyValues, Req2} = cowboy_req:body_qs(500000, Req).
+```
+
+You can also disable it by passing the atom `infinity`,
+although it is not recommended.
+
+Streaming the body
+------------------
+
+You can stream the request body by chunks.
+
+``` erlang
+{ok, Chunk, Req2} = cowboy_req:stream_body(Req).
+```
+
+By default, Cowboy will attempt to read chunks of up to
+1MB in size. The chunks returned by this function will
+often be smaller, however. You can also change this limit.
+
+``` erlang
+{ok, Chunk, Req2} = cowboy_req:stream_body(500000, Req).
+```
+
+When Cowboy finishes reading the body, any subsequent call
+will return `{done, Req2}`. You can thus write a recursive
+function to read the whole body and perform an action on
+all chunks, for example printing them to the console.
+
+``` erlang
+body_to_console(Req) ->
+ case cowboy_req:stream_body(Req) of
+ {ok, Chunk, Req2} ->
+ io:format("~s", [Chunk]),
+ body_to_console(Req2);
+ {done, Req2} ->
+ Req2
+ end.
+```
+
+Advanced streaming
+------------------
+
+Cowboy will by default decode the chunked transfer-encoding
+if any. It will not decode any content-encoding by default.
+
+Before starting to stream, you can configure the functions
+that will be used for decoding both transfer-encoding and
+content-encoding.
+
+``` erlang
+{ok, Req2} = cowboy_req:init_stream(fun transfer_decode/2,
+ TransferStartState, fun content_decode/1, Req).
+```
+
+Note that you do not need to call this function generally,
+as Cowboy will happily initialize the stream on its own.
+
+Skipping the body
+-----------------
+
+If you do not need the body, or if you started streaming
+the body but do not need the rest of it, you can skip it.
+
+``` erlang
+{ok, Req2} = cowboy_req:skip_body(Req).
+```
+
+You do not have to call this function though, as Cowboy will
+do it automatically when handler execution ends.
diff --git a/guide/resp.md b/guide/resp.md
new file mode 100644
index 0000000..088b10d
--- /dev/null
+++ b/guide/resp.md
@@ -0,0 +1,203 @@
+Sending a response
+==================
+
+The Req object also allows you to send a response.
+
+You can only send one response. Any other attempt will
+trigger a crash. The response may be sent in one go or
+with its body streamed by chunks of arbitrary size.
+
+You can also set headers or the response body in advance
+and Cowboy will use them when you finally do reply.
+
+Reply
+-----
+
+You can send a reply with no particular headers or body.
+Cowboy will make sure to send the mandatory headers with
+the response.
+
+``` erlang
+{ok, Req2} = cowboy_req:reply(200, Req).
+```
+
+You can define headers to be sent with the response. Note
+that header names must be lowercase. Again, Cowboy will
+make sure to send the mandatory headers with the response.
+
+``` erlang
+{ok, Req2} = cowboy_req:reply(303, [
+ {<<"location">>, <<"http://ninenines.eu">>}
+], Req).
+```
+
+You can override headers that Cowboy would send otherwise.
+Any header set by the user will be used over the ones set
+by Cowboy. For example, you can advertise yourself as a
+different server.
+
+``` erlang
+{ok, Req2} = cowboy_req:reply(200, [
+ {<<"server">>, <<"yaws">>}
+], Req).
+```
+
+We also saw earlier how to force close the connection by
+overriding the connection header.
+
+Finally, you can also send a body with the response. Cowboy
+will automatically set the content-length header if you do.
+We recommend that you set the content-type header so the
+client may know how to read the body.
+
+``` erlang
+{ok, Req2} = cowboy_req:reply(200, [
+ {<<"content-type">>, <<"text/plain">>
+], "Hello world!", Req).
+```
+
+Here is the same example but sending HTML this time.
+
+``` erlang
+{ok, Req2} = cowboy_req:reply(200, [
+ {<<"content-type">>, <<"text/html">>}
+], "<html><head>Hello world!</head><body><p>Hats off!</p></body></html>", Req).
+```
+
+Note that the reply is sent immediately.
+
+Chunked reply
+-------------
+
+You can also stream the response body. First, you need to
+initiate the reply by sending the response status code.
+Then you can send the body in chunks of arbitrary size.
+
+``` 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).
+```
+
+You should make sure to match on `ok` as an error may be
+returned.
+
+While it is possible to send a chunked response without
+a content-type header, it is still recommended. You can
+set this header or any other just like for normal replies.
+
+``` erlang
+{ok, Req2} = cowboy_req:chunked_reply(200, [
+ {<<"content-type">>, <<"text/html">>}
+], Req),
+ok = cowboy_req:chunk("<html><head>Hello world!</head>", Req2),
+ok = cowboy_req:chunk("<body><p>Hats off!</p></body></html>", Req2).
+```
+
+Note that the reply and each chunk following it are sent
+immediately.
+
+Preset response headers
+-----------------------
+
+You can define response headers in advance. They will be
+merged into the headers given in the reply call. Headers
+in the reply call override preset response headers which
+override the default Cowboy headers.
+
+``` erlang
+Req2 = cowboy_req:set_resp_header(<<"allow">>, "GET", Req).
+```
+
+You can check if a response header has already been set.
+This will only check the response headers that you set,
+and not the ones Cowboy will add when actually sending
+the reply.
+
+``` erlang
+cowboy_req:has_resp_header(<<"allow">>, Req).
+```
+
+It will return `true` if the header is defined, and `false`
+otherwise.
+
+Finally, you can also delete a preset response header if
+needed. If you do, it will not be sent.
+
+``` erlang
+Req2 = cowboy_req:delete_resp_header(<<"allow">>, Req).
+```
+
+Preset response body
+--------------------
+
+You can set the response body in advance. Note that this
+body will be ignored if you then choose to send a chunked
+reply, or if you send a reply with an explicit body.
+
+``` erlang
+Req2 = cowboy_req:set_resp_body("Hello world!", Req).
+```
+
+You can also set a fun that will be called when it is time
+to send the body. There are three different ways of doing
+that.
+
+If you know the length of the body that needs to be sent,
+you should specify it, as it will help clients determine
+the remaining download time and allow them to inform the
+user.
+
+``` erlang
+F = fun (Socket, Transport) ->
+ Transport:send(Socket, "Hello world!")
+end,
+Req2 = cowboy_req:set_resp_body_fun(12, F, Req).
+```
+
+If you do not know the length of the body, you should use
+a chunked response body fun instead.
+
+``` erlang
+F = fun (SendChunk) ->
+ Body = lists:duplicate(random:uniform(1024, $a)),
+ SendChunk(Body)
+end,
+Req2 = cowboy_req:set_resp_body_fun(chunked, F, Req).
+```
+
+Finally, you can also send data on the socket directly,
+without knowing the length in advance. Cowboy may be
+forced to close the connection at the end of the response
+though depending on the protocol capabilities.
+
+``` erlang
+F = fun (Socket, Transport) ->
+ Body = lists:duplicate(random:uniform(1024, $a)),
+ Transport:send(Socket, Body)
+end,
+Req2 = cowboy_req:set_resp_body_fun(F, Req).
+```
+
+Sending files
+-------------
+
+You can send files directly from disk without having to
+read them. Cowboy will use the `sendfile` syscall when
+possible, which means that the file is sent to the socket
+directly from the kernel, which is a lot more performant
+than doing it from userland.
+
+Again, it is recommended to set the size of the file if it
+can be known in advance.
+
+``` erlang
+F = fun (Socket, Transport) ->
+ Transport:sendfile(Socket, "priv/styles.css")
+end,
+Req2 = cowboy_req:set_resp_body_fun(FileSize, F, Req).
+```
+
+Please see the Ranch guide for more information about
+sending files.
diff --git a/guide/toc.md b/guide/toc.md
index 3397f46..315dfac 100644
--- a/guide/toc.md
+++ b/guide/toc.md
@@ -20,8 +20,9 @@ HTTP
* [Routing](routing.md)
* [Handling plain HTTP requests](http_handlers.md)
* [The Req object](req.md)
- * Reading the request body
- * Sending a response
+ * [Reading the request body](req_body.md)
+ * [Sending a response](resp.md)
+ * [Using cookies](cookies.md)
Static files
------------