|
@@ -1,155 +1,293 @@
|
|
|
++++
|
|
|
+title = "The Req object"
|
|
|
++++
|
|
|
+
|
|
|
[[req]]
|
|
|
== The Req object
|
|
|
|
|
|
-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.
|
|
|
+The Req object is a variable used for obtaining information
|
|
|
+about a request, read its body or send a response.
|
|
|
+
|
|
|
+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.
|
|
|
+
|
|
|
+The Req object is the subject of a few different chapters.
|
|
|
+In this chapter we will learn about the Req object and
|
|
|
+look at how to retrieve information about the request.
|
|
|
+
|
|
|
+=== Direct access
|
|
|
+
|
|
|
+The Req map contains a number of fields which are documented
|
|
|
+and can be accessed directly. They are the fields that have
|
|
|
+a direct mapping to HTTP: the request `method`; the HTTP
|
|
|
+`version` used; the effective URI components `scheme`,
|
|
|
+`host`, `port`, `path` and `qs`; the request `headers`;
|
|
|
+and the connection `peer` address and port.
|
|
|
+
|
|
|
+Note that the `version` field can be used to determine
|
|
|
+whether a connection is using HTTP/2.
|
|
|
+
|
|
|
+To access a field, you can simply match in the function
|
|
|
+head. The following example sends a simple "Hello world!"
|
|
|
+response when the `method` is GET, and a 405 error
|
|
|
+otherwise.
|
|
|
+
|
|
|
+[source,erlang]
|
|
|
+----
|
|
|
+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}.
|
|
|
+----
|
|
|
+
|
|
|
+Any other field is internal and should not be accessed.
|
|
|
+They may change in future releases, including maintenance
|
|
|
+releases, without notice.
|
|
|
+
|
|
|
+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.
|
|
|
+
|
|
|
+// @todo There are currently no tests for direct access.
|
|
|
|
|
|
-=== A special variable
|
|
|
+=== Introduction to the cowboy_req interface
|
|
|
|
|
|
-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.
|
|
|
+// @todo Link to cowboy_req manual
|
|
|
|
|
|
-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.
|
|
|
+Functions in the `cowboy_req` module provide access to
|
|
|
+the request information but also various operations that
|
|
|
+are common when dealing with HTTP requests.
|
|
|
|
|
|
-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.
|
|
|
+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).
|
|
|
|
|
|
-=== Overview of the cowboy_req interface
|
|
|
+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.
|
|
|
|
|
|
-With the exception of functions manipulating the request
|
|
|
-body, all functions return a single value. Depending on
|
|
|
-the function this can be the requested value (method,
|
|
|
-host, path, ...), a boolean (has_body, has_resp_header...)
|
|
|
-a new Req object (set_resp_body, set_resp_header...), or
|
|
|
-simply the atom `ok` (chunk, continue, ...).
|
|
|
+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.
|
|
|
|
|
|
-The request body reading functions may return `{Result, Req}`
|
|
|
-or `{Result, Value, Req}`. The functions in this category
|
|
|
-are `body/{1,2}`, `body_qs/{1,2}`, `part/{1,2}`, `part_body/{1,2}`.
|
|
|
+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.
|
|
|
|
|
|
-This chapter covers the access functions mainly. Cookies,
|
|
|
-request body and response functions are covered in their
|
|
|
-own chapters.
|
|
|
+=== Request method
|
|
|
|
|
|
-=== Request
|
|
|
+The request method can be retrieved directly:
|
|
|
|
|
|
-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.
|
|
|
+[source, erlang]
|
|
|
+#{method := Method} = Req.
|
|
|
|
|
|
-The method identifies the action. Standard methods include
|
|
|
-GET, HEAD, OPTIONS, PATCH, POST, PUT, DELETE. Method names
|
|
|
-are case sensitive.
|
|
|
+Or using a function:
|
|
|
|
|
|
[source,erlang]
|
|
|
Method = cowboy_req:method(Req).
|
|
|
|
|
|
-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.
|
|
|
+The method is a case sensitive binary string. Standard
|
|
|
+methods include GET, HEAD, OPTIONS, PATCH, POST, PUT
|
|
|
+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]
|
|
|
+#{version := Version} = Req.
|
|
|
+
|
|
|
+Or using a function:
|
|
|
|
|
|
[source,erlang]
|
|
|
+Version = cowboy_req:version(Req).
|
|
|
+
|
|
|
+Cowboy defines the `'HTTP/1.0'`, `'HTTP/1.1'` and `'HTTP/2'`
|
|
|
+versions. Custom protocols can define their own values as
|
|
|
+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 version used by the client can of course also be obtained.
|
|
|
+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]
|
|
|
-Version = cowboy_req:version(Req).
|
|
|
+%% 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}).
|
|
|
|
|
|
-Do note however that clients claiming to implement one version
|
|
|
-of the protocol does not mean they implement it fully, or even
|
|
|
-properly.
|
|
|
+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
|
|
|
|
|
|
-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.
|
|
|
+// @todo Bindings should probably be a map themselves.
|
|
|
|
|
|
-You can fetch a single binding. The value will be `undefined`
|
|
|
-if the binding doesn't exist.
|
|
|
+Bindings are the host and path components that you chose
|
|
|
+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]
|
|
|
-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,
|
|
|
-you can change the default.
|
|
|
+When attempting to retrieve a value that was not bound,
|
|
|
+`undefined` will be returned. A different default value
|
|
|
+can be provided:
|
|
|
|
|
|
[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
|
|
|
-returned as a list of key/value tuples.
|
|
|
+To retrieve everything that was bound:
|
|
|
|
|
|
[source,erlang]
|
|
|
-AllBindings = cowboy_req:bindings(Req).
|
|
|
+Bindings = cowboy_req:bindings(Req).
|
|
|
+
|
|
|
+They are returned as a list of key/value pairs, with
|
|
|
+keys being atoms.
|
|
|
+
|
|
|
+// ...
|
|
|
+
|
|
|
+The Cowboy router also allows you to capture many host
|
|
|
+or path segments at once using the `...` qualifier.
|
|
|
|
|
|
-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.
|
|
|
+To retrieve the segments captured from the host name:
|
|
|
|
|
|
[source,erlang]
|
|
|
HostInfo = 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.
|
|
|
+And the path segments:
|
|
|
|
|
|
[source,erlang]
|
|
|
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]
|
|
|
-Qs = cowboy_req:qs(Req).
|
|
|
-
|
|
|
-You can parse the query string and then use standard library
|
|
|
-functions to access individual values.
|
|
|
+Cowboy provides two functions to access query parameters.
|
|
|
+You can use the first to get the entire list of parameters.
|
|
|
|
|
|
[source,erlang]
|
|
|
QsVals = cowboy_req:parse_qs(Req),
|
|
|
{_, 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]
|
|
|
#{id := ID, lang := Lang} = cowboy_req:match_qs([id, lang], Req).
|
|
|
|
|
|
-You can use constraints to validate the values while matching
|
|
|
-them. The following snippet will crash if the `id` value is
|
|
|
-not an integer number or if the `lang` value is empty. Additionally
|
|
|
-the `id` value will be converted to an integer term, saving
|
|
|
-you a conversion step.
|
|
|
+Constraints can be applied automatically. The following
|
|
|
+snippet will crash when the `id` parameter is not an integer,
|
|
|
+or when the `lang` parameter is empty. At the same time, the
|
|
|
+value for `id` will be converted to an integer term:
|
|
|
|
|
|
[source,erlang]
|
|
|
QsMap = cowboy_req:match_qs([{id, int}, {lang, nonempty}], Req).
|
|
|
|
|
|
-Note that in the case of duplicate query string keys, the map
|
|
|
-value will become a list of the different values.
|
|
|
-
|
|
|
-Read more about ^constraints^.
|
|
|
-
|
|
|
-A default value can be provided. The default will be used
|
|
|
+A default value may also be provided. The default will be used
|
|
|
if the `lang` key is not found. It will not be used if
|
|
|
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
|
|
|
query string is deemed invalid and the process will crash.
|
|
|
|
|
|
-=== Request URL
|
|
|
-
|
|
|
-You can reconstruct the full URL of the resource.
|
|
|
-
|
|
|
-[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).
|
|
|
+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
|
|
|
+include the PHP-style suffix. Constraints may be used to
|
|
|
+ensure that only one value was passed through.
|
|
|
|
|
|
=== 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.
|
|
|
|
|
|
-This will get the string value of a header.
|
|
|
+The get the raw value:
|
|
|
|
|
|
[source,erlang]
|
|
|
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]
|
|
|
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]
|
|
|
AllHeaders = cowboy_req:headers(Req).
|
|
|
|
|
|
-To parse the previous header, simply call `parse_header/{2,3}`
|
|
|
-where you would call `header/{2,3}` otherwise.
|
|
|
+Cowboy provides equivalent functions to parse individual
|
|
|
+headers. There is no function to parse all headers at once.
|
|
|
+
|
|
|
+To parse a specific header:
|
|
|
|
|
|
[source,erlang]
|
|
|
ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req).
|
|
|
|
|
|
-Cowboy will crash if it doesn't know how to parse the given
|
|
|
-header, or if the value is invalid.
|
|
|
+An exception will be thrown if it doesn't know how to parse the
|
|
|
+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
|
|
|
-value you specify here is the parsed value you'd like to get
|
|
|
-by default.
|
|
|
+When the header is missing, `undefined` is returned. You can
|
|
|
+change the default value. Note that it should be the parsed value
|
|
|
+directly:
|
|
|
|
|
|
[source,erlang]
|
|
|
----
|
|
@@ -211,37 +354,21 @@ ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req,
|
|
|
{<<"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.
|
|
|
+=== Peer
|
|
|
|
|
|
-[source,erlang]
|
|
|
-MetaVal = cowboy_req:meta(websocket_version, Req, 13).
|
|
|
+The peer address and port number for the connection can be
|
|
|
+retrieved either directly or using a function.
|
|
|
|
|
|
-You can also define your own meta values. The name must be
|
|
|
-an `atom()`.
|
|
|
+To retrieve the peer directly:
|
|
|
|
|
|
[source,erlang]
|
|
|
-Req2 = cowboy_req:set_meta(the_answer, 42, Req).
|
|
|
+#{peer := {IP, Port}} = 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.
|
|
|
+And using a function:
|
|
|
|
|
|
[source,erlang]
|
|
|
{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.
|