mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-15 04:30:25 +00:00
More 2.0 documentation updates
Still incomplete.
This commit is contained in:
parent
b9ad02d305
commit
7839f13671
9 changed files with 363 additions and 207 deletions
|
@ -106,7 +106,7 @@ chapter. For this tutorial we map the path `/` to the handler
|
||||||
module `hello_handler`. This module doesn't exist yet.
|
module `hello_handler`. This module doesn't exist yet.
|
||||||
|
|
||||||
Build and start the release, then open http://localhost:8080
|
Build and start the release, then open http://localhost:8080
|
||||||
in your browser. You will get an error because the module is missing.
|
in your browser. You will get a 500 error because the module is missing.
|
||||||
Any other URL, like http://localhost:8080/test, will result in a
|
Any other URL, like http://localhost:8080/test, will result in a
|
||||||
404 error.
|
404 error.
|
||||||
|
|
||||||
|
@ -126,11 +126,11 @@ the `init/2` function like this to send a reply.
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
init(Req, State) ->
|
init(Req0, State) ->
|
||||||
cowboy_req:reply(200,
|
Req = cowboy_req:reply(200,
|
||||||
#{<<"content-type">> => <<"text/plain">>},
|
#{<<"content-type">> => <<"text/plain">>},
|
||||||
<<"Hello Erlang!">>,
|
<<"Hello Erlang!">>,
|
||||||
Req),
|
Req0),
|
||||||
{ok, Req, State}.
|
{ok, Req, State}.
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
|
@ -9,40 +9,42 @@ The most basic handler in Cowboy implements the mandatory
|
||||||
`init/2` callback, manipulates the request, optionally
|
`init/2` callback, manipulates the request, optionally
|
||||||
sends a response and then returns.
|
sends a response and then returns.
|
||||||
|
|
||||||
This callback receives the xref:req[Req object] and the options
|
This callback receives the xref:req[Req object] and the initial
|
||||||
defined during the xref:routing[router configuration].
|
state defined in the xref:routing[router configuration].
|
||||||
|
|
||||||
A handler that does nothing would look like this:
|
A handler that does nothing would look like this:
|
||||||
|
|
||||||
[source,erlang]
|
|
||||||
----
|
|
||||||
init(Req, _Opts) ->
|
|
||||||
{ok, Req, #state{}}.
|
|
||||||
----
|
|
||||||
|
|
||||||
Despite sending no reply, a `204 No Content` reply will be
|
|
||||||
sent to the client, as Cowboy makes sure that a reply is
|
|
||||||
sent for every request.
|
|
||||||
|
|
||||||
We need to use the Req object for sending a reply.
|
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
init(Req, State) ->
|
init(Req, State) ->
|
||||||
cowboy_req:reply(200, [
|
|
||||||
{<<"content-type">>, <<"text/plain">>}
|
|
||||||
], <<"Hello World!">>, Req),
|
|
||||||
{ok, Req, State}.
|
{ok, Req, State}.
|
||||||
----
|
----
|
||||||
|
|
||||||
As you can see we return a 3-tuple. `ok` means that the
|
Despite sending no reply, a `204 No Content` response will be
|
||||||
handler ran successfully. Note that Cowboy will immediately
|
sent to the client, as Cowboy makes sure that a response is
|
||||||
send a response when `cowboy:reply/4` is called.
|
sent for every request.
|
||||||
|
|
||||||
|
We need to use the Req object to reply.
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
----
|
||||||
|
init(Req0, State) ->
|
||||||
|
Req = cowboy_req:reply(200, [
|
||||||
|
{<<"content-type">>, <<"text/plain">>}
|
||||||
|
], <<"Hello World!">>, Req0),
|
||||||
|
{ok, Req, State}.
|
||||||
|
----
|
||||||
|
|
||||||
|
Cowboy will immediately send a response when `cowboy:reply/4`
|
||||||
|
is called.
|
||||||
|
|
||||||
|
We then return a 3-tuple. `ok` means that the handler ran
|
||||||
|
successfully. We also give the modified Req back to Cowboy.
|
||||||
|
|
||||||
The last value of the tuple is a state that will be used
|
The last value of the tuple is a state that will be used
|
||||||
in every subsequent callbacks to this handler. Plain HTTP
|
in every subsequent callbacks to this handler. Plain HTTP
|
||||||
handlers only have one additional callback, the optional
|
handlers only have one additional callback, the optional
|
||||||
`terminate/3`.
|
and rarely used `terminate/3`.
|
||||||
|
|
||||||
=== Other handlers
|
=== Other handlers
|
||||||
|
|
||||||
|
@ -62,16 +64,16 @@ following snippet switches to a Websocket handler:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, State) ->
|
||||||
{cowboy_websocket, Req, #state{}}.
|
{cowboy_websocket, Req, State}.
|
||||||
----
|
----
|
||||||
|
|
||||||
You can also switch to your own custom handler type:
|
You can also switch to your own custom handler type:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, State) ->
|
||||||
{my_handler_type, Req, #state{}}.
|
{my_handler_type, Req, State}.
|
||||||
----
|
----
|
||||||
|
|
||||||
How to implement a custom handler type is described in the
|
How to implement a custom handler type is described in the
|
||||||
|
@ -79,12 +81,12 @@ xref:sub_protocols[Sub protocols] chapter.
|
||||||
|
|
||||||
=== Cleaning up
|
=== Cleaning up
|
||||||
|
|
||||||
All handlers coming with Cowboy allow the use of the optional
|
With the exception of Websocket handlers, all handler types
|
||||||
`terminate/3` callback.
|
provide the optional `terminate/3` callback.
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
terminate(_Reason, Req, State) ->
|
terminate(_Reason, _Req, _State) ->
|
||||||
ok.
|
ok.
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -96,4 +98,5 @@ This callback is optional because it is rarely necessary.
|
||||||
Cleanup should be done in separate processes directly (by
|
Cleanup should be done in separate processes directly (by
|
||||||
monitoring the handler process to detect when it exits).
|
monitoring the handler process to detect when it exits).
|
||||||
|
|
||||||
Cowboy does not reuse processes for different requests.
|
Cowboy does not reuse processes for different requests. The
|
||||||
|
process will terminate soon after this call returns.
|
||||||
|
|
|
@ -35,7 +35,27 @@ guarantee that the experience will be safe and smooth. You are advised
|
||||||
to perform the necessary testing and security audits prior to deploying
|
to perform the necessary testing and security audits prior to deploying
|
||||||
on other platforms.
|
on other platforms.
|
||||||
|
|
||||||
Cowboy is developed for Erlang/OTP 18.0 and newer.
|
Cowboy is developed for Erlang/OTP 19.0 and newer.
|
||||||
|
|
||||||
|
=== License
|
||||||
|
|
||||||
|
Cowboy uses the ISC License.
|
||||||
|
|
||||||
|
----
|
||||||
|
Copyright (c) 2011-2016, Loïc Hoguin <essen@ninenines.eu>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
----
|
||||||
|
|
||||||
=== Versioning
|
=== Versioning
|
||||||
|
|
||||||
|
@ -46,8 +66,10 @@ Cowboy uses http://semver.org/[Semantic Versioning 2.0.0].
|
||||||
In the HTTP protocol, the method name is case sensitive. All standard
|
In the HTTP protocol, the method name is case sensitive. All standard
|
||||||
method names are uppercase.
|
method names are uppercase.
|
||||||
|
|
||||||
Header names are case insensitive. Cowboy converts all the request
|
Header names are case insensitive. When using HTTP/1.1, Cowboy converts
|
||||||
header names to lowercase, and expects your application to provide
|
all the request header names to lowercase. HTTP/2 requires clients to
|
||||||
lowercase header names in the response.
|
send them as lowercase. Any other header name is expected to be provided
|
||||||
|
lowercased, including when querying information about the request or
|
||||||
|
when sending responses.
|
||||||
|
|
||||||
The same applies to any other case insensitive value.
|
The same applies to any other case insensitive value.
|
||||||
|
|
|
@ -38,8 +38,8 @@ This snippet enables the loop handler.
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, State) ->
|
||||||
{cowboy_loop, Req, #state{}}.
|
{cowboy_loop, Req, State}.
|
||||||
----
|
----
|
||||||
|
|
||||||
However it is largely recommended that you set a timeout
|
However it is largely recommended that you set a timeout
|
||||||
|
@ -48,8 +48,8 @@ also makes the process hibernate.
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, State) ->
|
||||||
{cowboy_loop, Req, #state{}, 30000, hibernate}.
|
{cowboy_loop, Req, State, 30000, hibernate}.
|
||||||
----
|
----
|
||||||
|
|
||||||
=== Receive loop
|
=== Receive loop
|
||||||
|
@ -101,9 +101,9 @@ and the loop is stopped by sending an `eof` message.
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, State) ->
|
||||||
Req2 = cowboy_req:chunked_reply(200, [], Req),
|
Req2 = cowboy_req:chunked_reply(200, [], Req),
|
||||||
{cowboy_loop, Req2, #state{}}.
|
{cowboy_loop, Req2, State}.
|
||||||
|
|
||||||
info(eof, Req, State) ->
|
info(eof, Req, State) ->
|
||||||
{stop, Req, State};
|
{stop, Req, State};
|
||||||
|
|
|
@ -1,155 +1,293 @@
|
||||||
|
+++
|
||||||
|
title = "The Req object"
|
||||||
|
+++
|
||||||
|
|
||||||
[[req]]
|
[[req]]
|
||||||
== The Req object
|
== The Req object
|
||||||
|
|
||||||
The Req object is this variable that you will use to obtain
|
The Req object is a variable used for obtaining information
|
||||||
information about a request, read the body of the request
|
about a request, read its body or send a response.
|
||||||
and send a response.
|
|
||||||
|
|
||||||
=== A special variable
|
It is not really an object in the object-oriented sense.
|
||||||
|
It is a simple map that can be directly accessed or
|
||||||
|
used when calling functions from the `cowboy_req` module.
|
||||||
|
|
||||||
While we call it an "object", it is not an object in the
|
The Req object is the subject of a few different chapters.
|
||||||
OOP sense of the term. In fact it is completely opaque
|
In this chapter we will learn about the Req object and
|
||||||
to you and the only way you can perform operations using
|
look at how to retrieve information about the request.
|
||||||
it is by calling the functions from the `cowboy_req`
|
|
||||||
module.
|
|
||||||
|
|
||||||
Almost all the calls to the `cowboy_req` module will
|
=== Direct access
|
||||||
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
|
The Req map contains a number of fields which are documented
|
||||||
mutable state. This means that calling some of the
|
and can be accessed directly. They are the fields that have
|
||||||
functions twice will not produce the same result.
|
a direct mapping to HTTP: the request `method`; the HTTP
|
||||||
For example, when streaming the request body, the
|
`version` used; the effective URI components `scheme`,
|
||||||
function will return the body by chunks, one at a
|
`host`, `port`, `path` and `qs`; the request `headers`;
|
||||||
time, until there is none left.
|
and the connection `peer` address and port.
|
||||||
|
|
||||||
=== Overview of the cowboy_req interface
|
Note that the `version` field can be used to determine
|
||||||
|
whether a connection is using HTTP/2.
|
||||||
|
|
||||||
With the exception of functions manipulating the request
|
To access a field, you can simply match in the function
|
||||||
body, all functions return a single value. Depending on
|
head. The following example sends a simple "Hello world!"
|
||||||
the function this can be the requested value (method,
|
response when the `method` is GET, and a 405 error
|
||||||
host, path, ...), a boolean (has_body, has_resp_header...)
|
otherwise.
|
||||||
a new Req object (set_resp_body, set_resp_header...), or
|
|
||||||
simply the atom `ok` (chunk, continue, ...).
|
|
||||||
|
|
||||||
The request body reading functions may return `{Result, Req}`
|
[source,erlang]
|
||||||
or `{Result, Value, Req}`. The functions in this category
|
----
|
||||||
are `body/{1,2}`, `body_qs/{1,2}`, `part/{1,2}`, `part_body/{1,2}`.
|
init(Req0=#{method := <<"GET">>}, State) ->
|
||||||
|
Req = cowboy_req:reply(200, #{
|
||||||
|
<<"content-type">> => <<"text/plain">>
|
||||||
|
}, <<"Hello world!">>, Req0),
|
||||||
|
{ok, Req, State};
|
||||||
|
init(Req0, State) ->
|
||||||
|
Req = cowboy_req:reply(405, #{
|
||||||
|
<<"allow">> => <<"GET">>
|
||||||
|
}, Req0),
|
||||||
|
{ok, Req, State}.
|
||||||
|
----
|
||||||
|
|
||||||
This chapter covers the access functions mainly. Cookies,
|
Any other field is internal and should not be accessed.
|
||||||
request body and response functions are covered in their
|
They may change in future releases, including maintenance
|
||||||
own chapters.
|
releases, without notice.
|
||||||
|
|
||||||
=== Request
|
Modifying the Req object, while allowed, is not recommended
|
||||||
|
unless strictly necessary. If adding new fields, make sure
|
||||||
|
to namespace the field names so that no conflict can occur
|
||||||
|
with future Cowboy updates or third party projects.
|
||||||
|
|
||||||
When a client performs a request, it first sends a few required
|
// @todo There are currently no tests for direct access.
|
||||||
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.
|
|
||||||
|
|
||||||
The method identifies the action. Standard methods include
|
=== Introduction to the cowboy_req interface
|
||||||
GET, HEAD, OPTIONS, PATCH, POST, PUT, DELETE. Method names
|
|
||||||
are case sensitive.
|
// @todo Link to cowboy_req manual
|
||||||
|
|
||||||
|
Functions in the `cowboy_req` module provide access to
|
||||||
|
the request information but also various operations that
|
||||||
|
are common when dealing with HTTP requests.
|
||||||
|
|
||||||
|
All the functions that begin with a verb indicate an action.
|
||||||
|
Other functions simply return the corresponding value
|
||||||
|
(sometimes that value does need to be built, but the
|
||||||
|
cost of the operation is equivalent to retrieving a value).
|
||||||
|
|
||||||
|
Some of the `cowboy_req` functions return an updated Req
|
||||||
|
object. They are the read, reply, set and delete functions.
|
||||||
|
While ignoring the returned Req will not cause incorrect
|
||||||
|
behavior for some of them, it is highly recommended to
|
||||||
|
always keep and use the last returned Req object. The
|
||||||
|
manual for `cowboy_req` details these functions and what
|
||||||
|
modifications are done to the Req object.
|
||||||
|
|
||||||
|
Some of the calls to `cowboy_req` have side effects. This
|
||||||
|
is the case of the read and reply functions. Cowboy reads
|
||||||
|
the request body or replies immediately when the function
|
||||||
|
is called.
|
||||||
|
|
||||||
|
All functions will crash if something goes wrong. There
|
||||||
|
is usually no need to catch these errors, Cowboy will
|
||||||
|
send the appropriate 4xx or 5xx response depending on
|
||||||
|
where the crash occurred.
|
||||||
|
|
||||||
|
=== Request method
|
||||||
|
|
||||||
|
The request method can be retrieved directly:
|
||||||
|
|
||||||
|
[source, erlang]
|
||||||
|
#{method := Method} = Req.
|
||||||
|
|
||||||
|
Or using a function:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
Method = cowboy_req:method(Req).
|
Method = cowboy_req:method(Req).
|
||||||
|
|
||||||
The host, port and path parts of the URL identify the resource
|
The method is a case sensitive binary string. Standard
|
||||||
being accessed. The host and port information may not be
|
methods include GET, HEAD, OPTIONS, PATCH, POST, PUT
|
||||||
available if the client uses HTTP/1.0.
|
or DELETE.
|
||||||
|
|
||||||
|
=== HTTP version
|
||||||
|
|
||||||
|
The HTTP version is informational. It does not indicate that
|
||||||
|
the client implements the protocol well or fully.
|
||||||
|
|
||||||
|
There is typically no need to change behavior based on the
|
||||||
|
HTTP version: Cowboy already does it for you.
|
||||||
|
|
||||||
|
It can be useful in some cases, though. For example, one may
|
||||||
|
want to redirect HTTP/1.1 clients to use Websocket, while HTTP/2
|
||||||
|
clients keep using HTTP/2.
|
||||||
|
|
||||||
|
The HTTP version can be retrieved directly:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
Host = cowboy_req:host(Req),
|
#{version := Version} = Req.
|
||||||
Port = cowboy_req:port(Req),
|
|
||||||
Path = cowboy_req:path(Req).
|
|
||||||
|
|
||||||
The version used by the client can of course also be obtained.
|
Or using a function:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
Version = cowboy_req:version(Req).
|
Version = cowboy_req:version(Req).
|
||||||
|
|
||||||
Do note however that clients claiming to implement one version
|
Cowboy defines the `'HTTP/1.0'`, `'HTTP/1.1'` and `'HTTP/2'`
|
||||||
of the protocol does not mean they implement it fully, or even
|
versions. Custom protocols can define their own values as
|
||||||
properly.
|
atoms.
|
||||||
|
|
||||||
|
=== Effective request URI
|
||||||
|
|
||||||
|
The scheme, host, port, path and query string components
|
||||||
|
of the effective request URI can all be retrieved directly:
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
----
|
||||||
|
#{
|
||||||
|
scheme := Scheme,
|
||||||
|
host := Host,
|
||||||
|
port := Port,
|
||||||
|
path := Path,
|
||||||
|
qs := Qs
|
||||||
|
} = Req.
|
||||||
|
----
|
||||||
|
|
||||||
|
Or using the related functions:
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
Scheme = cowboy_req:scheme(Req),
|
||||||
|
Host = cowboy_req:host(Req),
|
||||||
|
Port = cowboy_req:port(Req),
|
||||||
|
Path = cowboy_req:path(Req).
|
||||||
|
Qs = cowboy_req:qs(Req).
|
||||||
|
|
||||||
|
The scheme and host are lowercased case insensitive binary
|
||||||
|
strings. The port is an integer representing the port number.
|
||||||
|
The path and query string are case sensitive binary strings.
|
||||||
|
|
||||||
|
Cowboy defines only the <<"http">> and <<"https">> schemes.
|
||||||
|
They are chosen so that the scheme will only be <<"https">>
|
||||||
|
for requests on secure HTTP/1.1 or HTTP/2 connections.
|
||||||
|
// @todo Is that tested well?
|
||||||
|
|
||||||
|
The effective request URI itself can be reconstructed with
|
||||||
|
the `cowboy_req:uri/1,2` function. By default, an absolute
|
||||||
|
URI is returned:
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
%% scheme://host[:port]/path[?qs]
|
||||||
|
URI = cowboy_req:uri(Req).
|
||||||
|
|
||||||
|
Options are available to either disable or replace some
|
||||||
|
or all of the components. Various URIs or URI formats can
|
||||||
|
be generated this way, including the origin form:
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
%% /path[?qs]
|
||||||
|
URI = cowboy_req:uri(Req, #{host => undefined}).
|
||||||
|
|
||||||
|
The protocol relative form:
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
%% //host[:port]/path[?qs]
|
||||||
|
URI = cowboy_req:uri(Req, #{scheme => undefined}).
|
||||||
|
|
||||||
|
The absolute URI without a query string:
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
URI = cowboy_req:uri(Req, #{qs => undefined}).
|
||||||
|
|
||||||
|
A different host:
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
URI = cowboy_req:uri(Req, #{host => <<"example.org">>}).
|
||||||
|
|
||||||
|
And any other combination.
|
||||||
|
|
||||||
=== Bindings
|
=== Bindings
|
||||||
|
|
||||||
After routing the request, bindings are available. Bindings
|
// @todo Bindings should probably be a map themselves.
|
||||||
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`
|
Bindings are the host and path components that you chose
|
||||||
if the binding doesn't exist.
|
to extract when defining the routes of your application.
|
||||||
|
They are only available after the routing.
|
||||||
|
|
||||||
|
Cowboy provides functions to retrieve one or all bindings.
|
||||||
|
|
||||||
|
To retrieve a single value:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
Binding = cowboy_req:binding(my_binding, Req).
|
Value = cowboy_req:binding(userid, Req).
|
||||||
|
|
||||||
If you need a different value when the binding doesn't exist,
|
When attempting to retrieve a value that was not bound,
|
||||||
you can change the default.
|
`undefined` will be returned. A different default value
|
||||||
|
can be provided:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
Binding = cowboy_req:binding(my_binding, Req, 42).
|
Value = cowboy_req:binding(userid, Req, 42).
|
||||||
|
|
||||||
You can also obtain all bindings in one call. They will be
|
To retrieve everything that was bound:
|
||||||
returned as a list of key/value tuples.
|
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
AllBindings = cowboy_req:bindings(Req).
|
Bindings = cowboy_req:bindings(Req).
|
||||||
|
|
||||||
If you used `...` at the beginning of the route's pattern
|
They are returned as a list of key/value pairs, with
|
||||||
for the host, you can retrieve the matched part of the host.
|
keys being atoms.
|
||||||
The value will be `undefined` otherwise.
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
The Cowboy router also allows you to capture many host
|
||||||
|
or path segments at once using the `...` qualifier.
|
||||||
|
|
||||||
|
To retrieve the segments captured from the host name:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
HostInfo = cowboy_req:host_info(Req).
|
HostInfo = cowboy_req:host_info(Req).
|
||||||
|
|
||||||
Similarly, if you used `...` at the end of the route's
|
And the path segments:
|
||||||
pattern for the path, you can retrieve the matched part,
|
|
||||||
or get `undefined` otherwise.
|
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
PathInfo = cowboy_req:path_info(Req).
|
PathInfo = cowboy_req:path_info(Req).
|
||||||
|
|
||||||
=== Query string
|
Cowboy will return `undefined` if `...` was not used
|
||||||
|
in the route.
|
||||||
|
|
||||||
The raw query string can be obtained directly.
|
=== Query parameters
|
||||||
|
|
||||||
[source,erlang]
|
Cowboy provides two functions to access query parameters.
|
||||||
Qs = cowboy_req:qs(Req).
|
You can use the first to get the entire list of parameters.
|
||||||
|
|
||||||
You can parse the query string and then use standard library
|
|
||||||
functions to access individual values.
|
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
QsVals = cowboy_req:parse_qs(Req),
|
QsVals = cowboy_req:parse_qs(Req),
|
||||||
{_, Lang} = lists:keyfind(<<"lang">>, 1, QsVals).
|
{_, Lang} = lists:keyfind(<<"lang">>, 1, QsVals).
|
||||||
|
|
||||||
You can match the query string into a map.
|
Cowboy will only parse the query string, and not do any
|
||||||
|
transformation. This function may therefore return duplicates,
|
||||||
|
or parameter names without an associated value.
|
||||||
|
|
||||||
|
When a query string is `key=1&key=2`, the list returned will
|
||||||
|
contain two parameters of name `key`.
|
||||||
|
|
||||||
|
The same is true when trying to use the PHP-style suffix `[]`.
|
||||||
|
When a query string is `key[]=1&key[]=2`, the list returned will
|
||||||
|
contain two parameters of name `key[]`.
|
||||||
|
|
||||||
|
When a query string is simply `key`, Cowboy will return the
|
||||||
|
list `[{<<"key">>, true}]`, using `true` to indicate that the
|
||||||
|
parameter `key` was defined, but with no value.
|
||||||
|
|
||||||
|
The second function Cowboy provides allows you to match out
|
||||||
|
only the parameters you are interested in, and at the same
|
||||||
|
time do any post processing you require using ^constraints^.
|
||||||
|
This function returns a map.
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
#{id := ID, lang := Lang} = cowboy_req:match_qs([id, lang], Req).
|
#{id := ID, lang := Lang} = cowboy_req:match_qs([id, lang], Req).
|
||||||
|
|
||||||
You can use constraints to validate the values while matching
|
Constraints can be applied automatically. The following
|
||||||
them. The following snippet will crash if the `id` value is
|
snippet will crash when the `id` parameter is not an integer,
|
||||||
not an integer number or if the `lang` value is empty. Additionally
|
or when the `lang` parameter is empty. At the same time, the
|
||||||
the `id` value will be converted to an integer term, saving
|
value for `id` will be converted to an integer term:
|
||||||
you a conversion step.
|
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
QsMap = cowboy_req:match_qs([{id, int}, {lang, nonempty}], Req).
|
QsMap = cowboy_req:match_qs([{id, int}, {lang, nonempty}], Req).
|
||||||
|
|
||||||
Note that in the case of duplicate query string keys, the map
|
A default value may also be provided. The default will be used
|
||||||
value will become a list of the different values.
|
|
||||||
|
|
||||||
Read more about ^constraints^.
|
|
||||||
|
|
||||||
A default value can be provided. The default will be used
|
|
||||||
if the `lang` key is not found. It will not be used if
|
if the `lang` key is not found. It will not be used if
|
||||||
the key is found but has an empty value.
|
the key is found but has an empty value.
|
||||||
|
|
||||||
|
@ -159,51 +297,56 @@ the key is found but has an empty value.
|
||||||
If no default is provided and the value is missing, the
|
If no default is provided and the value is missing, the
|
||||||
query string is deemed invalid and the process will crash.
|
query string is deemed invalid and the process will crash.
|
||||||
|
|
||||||
=== Request URL
|
When the query string is `key=1&key=2`, the value for `key`
|
||||||
|
will be the list `[1, 2]`. Parameter names do not need to
|
||||||
You can reconstruct the full URL of the resource.
|
include the PHP-style suffix. Constraints may be used to
|
||||||
|
ensure that only one value was passed through.
|
||||||
[source,erlang]
|
|
||||||
URL = cowboy_req:url(Req).
|
|
||||||
|
|
||||||
You can also obtain only the base of the URL, excluding the
|
|
||||||
path and query string.
|
|
||||||
|
|
||||||
[source,erlang]
|
|
||||||
BaseURL = cowboy_req:host_url(Req).
|
|
||||||
|
|
||||||
=== Headers
|
=== Headers
|
||||||
|
|
||||||
Cowboy allows you to obtain the header values as string,
|
Header values can be retrieved either as a binary string
|
||||||
or parsed into a more meaningful representation.
|
or parsed into a more meaningful representation.
|
||||||
|
|
||||||
This will get the string value of a header.
|
The get the raw value:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
HeaderVal = cowboy_req:header(<<"content-type">>, Req).
|
HeaderVal = cowboy_req:header(<<"content-type">>, Req).
|
||||||
|
|
||||||
You can of course set a default in case the header is missing.
|
Cowboy expects all header names to be provided as lowercase
|
||||||
|
binary strings. This is true for both requests and responses,
|
||||||
|
regardless of the underlying protocol.
|
||||||
|
|
||||||
|
When the header is missing from the request, `undefined`
|
||||||
|
will be returned. A different default can be provided:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
HeaderVal = cowboy_req:header(<<"content-type">>, Req, <<"text/plain">>).
|
HeaderVal = cowboy_req:header(<<"content-type">>, Req, <<"text/plain">>).
|
||||||
|
|
||||||
And also obtain all headers.
|
All headers can be retrieved at once, either directly:
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
#{headers := AllHeaders} = Req.
|
||||||
|
|
||||||
|
Or using a function:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
AllHeaders = cowboy_req:headers(Req).
|
AllHeaders = cowboy_req:headers(Req).
|
||||||
|
|
||||||
To parse the previous header, simply call `parse_header/{2,3}`
|
Cowboy provides equivalent functions to parse individual
|
||||||
where you would call `header/{2,3}` otherwise.
|
headers. There is no function to parse all headers at once.
|
||||||
|
|
||||||
|
To parse a specific header:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req).
|
ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req).
|
||||||
|
|
||||||
Cowboy will crash if it doesn't know how to parse the given
|
An exception will be thrown if it doesn't know how to parse the
|
||||||
header, or if the value is invalid.
|
given header, or if the value is invalid. The list of known headers
|
||||||
|
and default values can be found in the manual.
|
||||||
|
|
||||||
You can of course define a default value. Note that the default
|
When the header is missing, `undefined` is returned. You can
|
||||||
value you specify here is the parsed value you'd like to get
|
change the default value. Note that it should be the parsed value
|
||||||
by default.
|
directly:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
|
@ -211,37 +354,21 @@ ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req,
|
||||||
{<<"text">>, <<"plain">>, []}).
|
{<<"text">>, <<"plain">>, []}).
|
||||||
----
|
----
|
||||||
|
|
||||||
The list of known headers and default values is defined in the
|
|
||||||
manual.
|
|
||||||
|
|
||||||
=== Meta
|
|
||||||
|
|
||||||
Cowboy will sometimes associate some meta information with
|
|
||||||
the request. Built-in meta values are listed in the manual
|
|
||||||
for their respective modules.
|
|
||||||
|
|
||||||
This will get a meta value. The returned value will be `undefined`
|
|
||||||
if it isn't defined.
|
|
||||||
|
|
||||||
[source,erlang]
|
|
||||||
MetaVal = cowboy_req:meta(websocket_version, Req).
|
|
||||||
|
|
||||||
You can change the default value if needed.
|
|
||||||
|
|
||||||
[source,erlang]
|
|
||||||
MetaVal = cowboy_req:meta(websocket_version, Req, 13).
|
|
||||||
|
|
||||||
You can also define your own meta values. The name must be
|
|
||||||
an `atom()`.
|
|
||||||
|
|
||||||
[source,erlang]
|
|
||||||
Req2 = cowboy_req:set_meta(the_answer, 42, Req).
|
|
||||||
|
|
||||||
=== Peer
|
=== Peer
|
||||||
|
|
||||||
You can obtain the peer address and port number. This is
|
The peer address and port number for the connection can be
|
||||||
not necessarily the actual IP and port of the client, but
|
retrieved either directly or using a function.
|
||||||
rather the one of the machine that connected to the server.
|
|
||||||
|
To retrieve the peer directly:
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
#{peer := {IP, Port}} = Req.
|
||||||
|
|
||||||
|
And using a function:
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
{IP, Port} = cowboy_req:peer(Req).
|
{IP, Port} = cowboy_req:peer(Req).
|
||||||
|
|
||||||
|
Note that the peer corresponds to the remote end of the
|
||||||
|
connection to the server, which may or may not be the
|
||||||
|
client itself. It may also be a proxy or a gateway.
|
||||||
|
|
|
@ -15,8 +15,8 @@ must return a `cowboy_rest` tuple.
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, State) ->
|
||||||
{cowboy_rest, Req, #state{}}.
|
{cowboy_rest, Req, State}.
|
||||||
----
|
----
|
||||||
|
|
||||||
Cowboy will then switch to the REST protocol and start executing
|
Cowboy will then switch to the REST protocol and start executing
|
||||||
|
|
|
@ -37,11 +37,11 @@ PathsList = [Path1, Path2, ... PathN].
|
||||||
|
|
||||||
Finally, each path contains matching rules for the path along with
|
Finally, each path contains matching rules for the path along with
|
||||||
optional constraints, and gives us the handler module to be used
|
optional constraints, and gives us the handler module to be used
|
||||||
along with options that will be given to it on initialization.
|
along with its initial state.
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
Path1 = {PathMatch, Handler, Opts}.
|
Path1 = {PathMatch, Handler, InitialState}.
|
||||||
Path2 = {PathMatch, Constraints, Handler, Opts}.
|
Path2 = {PathMatch, Constraints, Handler, InitialState}.
|
||||||
|
|
||||||
Continue reading to learn more about the match syntax and the optional
|
Continue reading to learn more about the match syntax and the optional
|
||||||
constraints.
|
constraints.
|
||||||
|
@ -199,8 +199,8 @@ This can be done with a simple call to `cowboy_router:compile/1`.
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
Dispatch = cowboy_router:compile([
|
Dispatch = cowboy_router:compile([
|
||||||
%% {HostMatch, list({PathMatch, Handler, Opts})}
|
%% {HostMatch, list({PathMatch, Handler, InitialState})}
|
||||||
{'_', [{'_', my_handler, []}]}
|
{'_', [{'_', my_handler, #{}}]}
|
||||||
]),
|
]),
|
||||||
%% Name, NbAcceptors, TransOpts, ProtoOpts
|
%% Name, NbAcceptors, TransOpts, ProtoOpts
|
||||||
cowboy:start_clear(my_http_listener, 100,
|
cowboy:start_clear(my_http_listener, 100,
|
||||||
|
|
|
@ -16,8 +16,8 @@ is handled by the sub protocol.
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, State) ->
|
||||||
{cowboy_websocket, Req, #state{}}.
|
{cowboy_websocket, Req, State}.
|
||||||
----
|
----
|
||||||
|
|
||||||
The return value may also have a `Timeout` value and/or the
|
The return value may also have a `Timeout` value and/or the
|
||||||
|
@ -29,10 +29,12 @@ The following snippet switches to the `my_protocol` sub
|
||||||
protocol, sets the timeout value to 5 seconds and enables
|
protocol, sets the timeout value to 5 seconds and enables
|
||||||
hibernation:
|
hibernation:
|
||||||
|
|
||||||
|
// @todo Yeah maybe what we really need is an Opts map.
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, State) ->
|
||||||
{my_protocol, Req, #state{}, 5000, hibernate}.
|
{my_protocol, Req, State, 5000, hibernate}.
|
||||||
----
|
----
|
||||||
|
|
||||||
If a sub protocol does not make use of these options, it should
|
If a sub protocol does not make use of these options, it should
|
||||||
|
|
|
@ -18,8 +18,8 @@ must return a `ws` tuple.
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, State) ->
|
||||||
{cowboy_websocket, Req, #state{}}.
|
{cowboy_websocket, Req, State}.
|
||||||
----
|
----
|
||||||
|
|
||||||
Upon receiving this tuple, Cowboy will switch to the code
|
Upon receiving this tuple, Cowboy will switch to the code
|
||||||
|
@ -34,18 +34,18 @@ the connection, assuming no correct subprotocol was found.
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, State) ->
|
||||||
case cowboy_req:parse_header(<<"sec-websocket-protocol">>, Req) of
|
case cowboy_req:parse_header(<<"sec-websocket-protocol">>, Req) of
|
||||||
undefined ->
|
undefined ->
|
||||||
{ok, Req, #state{}};
|
{ok, Req, State};
|
||||||
Subprotocols ->
|
Subprotocols ->
|
||||||
case lists:keymember(<<"mychat2">>, 1, Subprotocols) of
|
case lists:keymember(<<"mychat2">>, 1, Subprotocols) of
|
||||||
true ->
|
true ->
|
||||||
Req2 = cowboy_req:set_resp_header(<<"sec-websocket-protocol">>,
|
Req2 = cowboy_req:set_resp_header(<<"sec-websocket-protocol">>,
|
||||||
<<"mychat2">>, Req),
|
<<"mychat2">>, Req),
|
||||||
{ok, Req2, #state{}};
|
{ok, Req2, State};
|
||||||
false ->
|
false ->
|
||||||
{stop, Req, undefined}
|
{stop, Req, State}
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
----
|
----
|
||||||
|
@ -60,12 +60,14 @@ It is also very easy to ensure that this message arrives before
|
||||||
any message from other processes by sending it before registering
|
any message from other processes by sending it before registering
|
||||||
or enabling timers.
|
or enabling timers.
|
||||||
|
|
||||||
|
// @todo This doesn't even work.
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, State) ->
|
||||||
self() ! post_init,
|
self() ! post_init,
|
||||||
%% Register process here...
|
%% Register process here...
|
||||||
{cowboy_websocket, Req, #state{}}.
|
{cowboy_websocket, Req, State}.
|
||||||
|
|
||||||
websocket_info(post_init, Req, State) ->
|
websocket_info(post_init, Req, State) ->
|
||||||
%% Perform post_init initialization here...
|
%% Perform post_init initialization here...
|
||||||
|
@ -169,8 +171,8 @@ A good timeout value is 60 seconds.
|
||||||
|
|
||||||
[source,erlang]
|
[source,erlang]
|
||||||
----
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, State) ->
|
||||||
{cowboy_websocket, Req, #state{}, 60000}.
|
{cowboy_websocket, Req, State, 60000}.
|
||||||
----
|
----
|
||||||
|
|
||||||
This value cannot be changed once it is set. It defaults to
|
This value cannot be changed once it is set. It defaults to
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue