mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-15 12:40:25 +00:00
205 lines
7.3 KiB
Markdown
205 lines
7.3 KiB
Markdown
Request object
|
|
==============
|
|
|
|
Purpose
|
|
-------
|
|
|
|
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
|
|
-------
|
|
|
|
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
|
|
------------
|
|
|
|
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.
|
|
|
|
Closing the connection
|
|
----------------------
|
|
|
|
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
|
|
{ok, Req2} = cowboy_req:reply(200,
|
|
[{<<"connection">>, <<"close">>}],
|
|
Req).
|
|
```
|
|
|
|
Reducing the memory footprint
|
|
-----------------------------
|
|
|
|
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.
|
|
|
|
``` erlang
|
|
Req2 = cowboy_req:compact(Req).
|
|
```
|