From faca7866ed1c59cd41e11fcfc5a9f95378380497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Sat, 5 Nov 2016 14:17:30 +0200 Subject: Partially update manual for the cowboy_req Only the access functions have been modified so far. --- doc/src/manual/cowboy_req.asciidoc | 793 ++++++----------------------- doc/src/manual/cowboy_req.header.asciidoc | 74 +++ doc/src/manual/cowboy_req.headers.asciidoc | 51 ++ doc/src/manual/cowboy_req.host.asciidoc | 52 ++ doc/src/manual/cowboy_req.method.asciidoc | 60 +++ doc/src/manual/cowboy_req.path.asciidoc | 51 ++ doc/src/manual/cowboy_req.peer.asciidoc | 61 +++ doc/src/manual/cowboy_req.port.asciidoc | 52 ++ doc/src/manual/cowboy_req.qs.asciidoc | 50 ++ doc/src/manual/cowboy_req.scheme.asciidoc | 55 ++ doc/src/manual/cowboy_req.uri.asciidoc | 116 +++++ doc/src/manual/cowboy_req.version.asciidoc | 49 ++ 12 files changed, 819 insertions(+), 645 deletions(-) create mode 100644 doc/src/manual/cowboy_req.header.asciidoc create mode 100644 doc/src/manual/cowboy_req.headers.asciidoc create mode 100644 doc/src/manual/cowboy_req.host.asciidoc create mode 100644 doc/src/manual/cowboy_req.method.asciidoc create mode 100644 doc/src/manual/cowboy_req.path.asciidoc create mode 100644 doc/src/manual/cowboy_req.peer.asciidoc create mode 100644 doc/src/manual/cowboy_req.port.asciidoc create mode 100644 doc/src/manual/cowboy_req.qs.asciidoc create mode 100644 doc/src/manual/cowboy_req.scheme.asciidoc create mode 100644 doc/src/manual/cowboy_req.uri.asciidoc create mode 100644 doc/src/manual/cowboy_req.version.asciidoc (limited to 'doc') diff --git a/doc/src/manual/cowboy_req.asciidoc b/doc/src/manual/cowboy_req.asciidoc index e1a2c4d..b1d97ff 100644 --- a/doc/src/manual/cowboy_req.asciidoc +++ b/doc/src/manual/cowboy_req.asciidoc @@ -6,685 +6,188 @@ cowboy_req - HTTP request and response == Description -The `cowboy_req` module provides functions to access, manipulate +The module `cowboy_req` provides functions to access, manipulate and respond to requests. -The functions in this module follow patterns for their return types, -based on the kind of function. +There are four types of functions in this module. They can be +differentiated by their name and their return type: -* access: `Value` -* action: `ok | {Result, Req} | {Result, Value, Req}` -* modification: `Req` -* question: `boolean()` - -Whenever `Req` is returned, you must use this returned value and -ignore any previous you may have had. This value contains various -values which are necessary for Cowboy to keep track of the request -and response states. - -All functions which perform an action should only be called once. -This includes reading the request body or replying. Cowboy will -throw an error on the second call when it detects suspicious behavior. +[options="header"] +|=== +| Type | Name pattern | Return type +| access | no verb, parse_*, match_* | `Value` +| question | has_* | `boolean()` +| modification | set_* | `Req` +| action | any other verb | `ok \| {Result, Value, Req}` +|=== -It is highly discouraged to pass the Req object to another process. -Doing so and calling `cowboy_req` functions from it leads to -undefined behavior. +Any `Req` returned must be used in place of the one passed as +argument. Functions that perform an action in particular write +state in the Req object to make sure you are using the function +correctly. For example, it's only possible to send one response, +and to read the body once. + +== Exports + +Raw request: + +* link:man:cowboy_req:method(3)[cowboy_req:method(3)] - HTTP method +* link:man:cowboy_req:version(3)[cowboy_req:version(3)] - HTTP version +* link:man:cowboy_req:scheme(3)[cowboy_req:scheme(3)] - URI scheme +* link:man:cowboy_req:host(3)[cowboy_req:host(3)] - URI host name +* link:man:cowboy_req:port(3)[cowboy_req:port(3)] - URI port number +* link:man:cowboy_req:path(3)[cowboy_req:path(3)] - URI path +* link:man:cowboy_req:qs(3)[cowboy_req:qs(3)] - URI query string +* link:man:cowboy_req:uri(3)[cowboy_req:uri(3)] - Reconstructed URI +* link:man:cowboy_req:header(3)[cowboy_req:header(3)] - HTTP header +* link:man:cowboy_req:headers(3)[cowboy_req:headers(3)] - HTTP headers +* link:man:cowboy_req:peer(3)[cowboy_req:peer(3)] - Peer address and port + +Processed request: + +* link:man:cowboy_req:parse_qs(3)[cowboy_req:parse_qs(3)] - Parse the query string +* link:man:cowboy_req:match_qs(3)[cowboy_req:match_qs(3)] - Match the query string against constraints +* link:man:cowboy_req:parse_header(3)[cowboy_req:parse_header(3)] - Parse the given HTTP header +* link:man:cowboy_req:parse_cookies(3)[cowboy_req:parse_cookies(3)] - Parse cookie headers +* link:man:cowboy_req:match_cookies(3)[cowboy_req:match_cookies(3)] - Match cookies against constraints +* link:man:cowboy_req:binding(3)[cowboy_req:binding(3)] - Access a value bound from the route +* link:man:cowboy_req:bindings(3)[cowboy_req:bindings(3)] - Access all values bound from the route +* link:man:cowboy_req:host_info(3)[cowboy_req:host_info(3)] - Access the route's heading host segments +* link:man:cowboy_req:path_info(3)[cowboy_req:path_info(3)] - Access the route's trailing path segments + +Request body: + +* link:man:cowboy_req:has_body(3)[cowboy_req:has_body(3)] - Is there a request body? +* link:man:cowboy_req:body_length(3)[cowboy_req:body_length(3)] - Body length +* link:man:cowboy_req:read_body(3)[cowboy_req:read_body(3)] - Read the request body +* link:man:cowboy_req:read_urlencoded_body(3)[cowboy_req:read_urlencoded_body(3)] - Read and parse a urlencoded request body +* link:man:cowboy_req:read_part(3)[cowboy_req:read_part(3)] - Read the next part of a multipart body +* link:man:cowboy_req:read_part_body(3)[cowboy_req:read_part_body(3)] - Read the current part's body in a multipart body + +Response: + +* link:man:cowboy_req:set_resp_cookie(3)[cowboy_req:set_resp_cookie(3)] - Set a cookie +* link:man:cowboy_req:set_resp_header(3)[cowboy_req:set_resp_header(3)] - Set a response header +* link:man:cowboy_req:has_resp_header(3)[cowboy_req:has_resp_header(3)] - Is the given response header set? +* link:man:cowboy_req:delete_resp_header(3)[cowboy_req:delete_resp_header(3)] - Delete a response header +* link:man:cowboy_req:set_resp_body(3)[cowboy_req:set_resp_body(3)] - Set the response body +* link:man:cowboy_req:has_resp_body(3)[cowboy_req:has_resp_body(3)] - Is there a response body? +* link:man:cowboy_req:reply(3)[cowboy_req:reply(3)] - Send the response +* link:man:cowboy_req:stream_reply(3)[cowboy_req:stream_reply(3)] - Send the response and stream its body +* link:man:cowboy_req:stream_body(3)[cowboy_req:stream_body(3)] - Send a chunk of the response body +* link:man:cowboy_req:push(3)[cowboy_req:push(3)] - Push a resource to the client == Types -=== body_opts() = [Option] +=== push_opts() [source,erlang] ---- -Option = {continue, boolean()} - | {length, non_neg_integer()} - | {read_length, non_neg_integer()} - | {read_timeout, timeout()} - | {transfer_decode, transfer_decode_fun(), any()} - | {content_decode, content_decode_fun()} +push_opts() :: #{ + method => binary(), %% case sensitive + scheme => binary(), %% lowercase; case insensitive + host => binary(), %% lowercase; case insensitive + port => inet:port_number(), + qs => binary() %% case sensitive +} ---- -Request body reading options. +Push options. -=== cookie_opts() = [Option] +By default, Cowboy will use the GET method, an empty query string, +and take the scheme, host and port directly from the current +request's URI. + +=== read_body_opts() [source,erlang] ---- -Option = {max_age, non_neg_integer()} - | {domain, binary()} - | {path, binary()} - | {secure, boolean()} - | {http_only, boolean()} +read_body_opts() :: #{ + length => non_neg_integer(), + period => non_neg_integer(), + timeout => timeout() +} ---- -Cookie options. - -=== req() - opaque to the user - -The Req object. - -All functions in this module receive a `Req` as argument, -and some of them return a new object labelled `Req2` in -the function descriptions below. - -== Request related exports - -=== binding(Name, Req) -> binding(Name, Req, undefined) - -Alias of `cowboy_req:binding/3`. - -=== binding(Name, Req, Default) -> Value - -Name = atom():: Binding name. -Default = any():: Default value. -Value = any() | Default:: Binding value. - -Return the value for the given binding. - -By default the value is a binary, however constraints may change -the type of this value (for example automatically converting -numbers to integer). - -=== bindings(Req) -> [{Name, Value}] - -Name = atom():: Binding name. -Value = any():: Binding value. - -Return all bindings. - -By default the value is a binary, however constraints may change -the type of this value (for example automatically converting -numbers to integer). - -=== header(Name, Req) -> header(Name, Req, undefined) - -Alias of `cowboy_req:header/3`. - -=== header(Name, Req, Default) -> Value - -Name = binary():: Request header name. -Default = any():: Default value. -Value = binary() | Default:: Request header value. - -Return the value for the given header. - -While header names are case insensitive, this function expects -the name to be a lowercase binary. - -=== headers(Req) -> Headers - -Headers = cowboy:http_headers():: Request headers. - -Return all headers. - -=== host(Req) -> Host - -Host = binary():: Requested host. - -Return the requested host. - -=== host_info(Req) -> HostInfo - -HostInfo = cowboy_router:tokens() | undefined:: Extra tokens for the host. - -Return the extra tokens from matching against `...` during routing. - -=== host_url(Req) -> HostURL - -HostURL = binary() | undefined:: Requested URL, without the path component. - -Return the requested URL excluding the path component. - -This function will always return `undefined` until the -`cowboy_router` middleware has been executed. - -=== match_cookies(Fields, Req) -> Map - -Fields = cowboy:fields():: Cookie fields match rules. -Map = map():: Cookie fields matched. - -Match cookies against the given fields. - -Cowboy will only return the cookie values specified in the -fields list, and ignore all others. Fields can be either -the name of the cookie requested; the name along with a -list of constraints; or the name, a list of constraints -and a default value in case the cookie is missing. - -This function will crash if the cookie is missing and no -default value is provided. This function will also crash -if a constraint fails. - -The name of the cookie must be provided as an atom. The -key of the returned map will be that atom. The value may -be converted through the use of constraints, making this -function able to extract, validate and convert values all -in one step. - -=== match_qs(Fields, Req) -> Map - -Fields = cowboy:fields():: Query string fields match rules. -Map = map():: Query string fields matched. - -Match the query string against the given fields. - -Cowboy will only return the query string values specified -in the fields list, and ignore all others. Fields can be -either the key requested; the key along with a list of -constraints; or the key, a list of constraints and a -default value in case the key is missing. - -This function will crash if the key is missing and no -default value is provided. This function will also crash -if a constraint fails. - -The key must be provided as an atom. The key of the -returned map will be that atom. The value may be converted -through the use of constraints, making this function able -to extract, validate and convert values all in one step. - -=== meta(Name, Req) -> meta(Name, Req, undefined) - -Alias for `cowboy_req:meta/3`. - -=== meta(Name, Req, Default) -> Value - -Name = atom():: Metadata name. -Default = any():: Default value. -Value = any():: Metadata value. - -Return metadata about the request. - -=== method(Req) -> Method - -Method = binary():: Request method. - -Return the method. - -Methods are case sensitive. Standard methods are always uppercase. - -=== parse_cookies(Req) -> [{Name, Value}] - -Name = binary():: Cookie name. -Value = binary():: Cookie value. - -Parse and return all cookies. - -Cookie names are case sensitive. - -=== parse_header(Name, Req) -> see below - -Alias of `cowboy_req:parse_header/3`. - -The `parse_header/2` function will call `parser_header/3` with a -different default value depending on the header being parsed. The -following table summarizes the default values used. - -[cols="<,^",options="header"] -|=== -| Header name | Header value -| content-length | `0` -| cookie | `[]` -| transfer-encoding | `[<<"identity">>]` -| Any other header | `undefined` -|=== - -=== parse_header(Name, Req, Default) -> ParsedValue | Default - -Name = binary():: Request header name. -Default = any():: Default value. -ParsedValue - see below:: Parsed request header value. - -Parse the given header. - -While header names are case insensitive, this function expects -the name to be a lowercase binary. - -The parsed value differs depending on the header being parsed. The -following table summarizes the different types returned. - -[cols="<,^",options="header"] -|=== -| Header name | Type of parsed header value -| accept | `[{{Type, SubType, Params}, Quality, AcceptExt}]` -| accept-charset | `[{Charset, Quality}]` -| accept-encoding | `[{Encoding, Quality}]` -| accept-language | `[{LanguageTag, Quality}]` -| authorization | `{AuthType, Credentials}` -| content-length | `non_neg_integer()` -| content-type | `{Type, SubType, ContentTypeParams}` -| cookie | `[{binary(), binary()}]` -| expect | `[Expect \| {Expect, ExpectValue, Params}]` -| if-match | `'*' \| [{weak \| strong, OpaqueTag}]` -| if-modified-since | `calendar:datetime()` -| if-none-match | `'*' \| [{weak \| strong, OpaqueTag}]` -| if-unmodified-since | `calendar:datetime()` -| range | `{Unit, [Range]}` -| sec-websocket-protocol | `[binary()]` -| transfer-encoding | `[binary()]` -| upgrade | `[binary()]` -| x-forwarded-for | `[binary()]` -|=== - -Types for the above table: - -* Type = SubType = Charset = Encoding = LanguageTag = binary() -* AuthType = Expect = OpaqueTag = Unit = binary() -* Params = ContentTypeParams = [{binary(), binary()}] -* Quality = 0..1000 -* AcceptExt = [{binary(), binary()} | binary()] -* Credentials - see below -* Range = {non_neg_integer(), non_neg_integer() | infinity} | neg_integer() - -The cookie names and values, the values of the sec-websocket-protocol -and x-forwarded-for headers, the values in `AcceptExt` and `Params`, -the authorization `Credentials`, the `ExpectValue` and `OpaqueTag` -are case sensitive. All values in `ContentTypeParams` are case sensitive -except the value of the charset parameter, which is case insensitive. -All other values are case insensitive and will be returned as lowercase. - -The headers accept, accept-encoding and cookie headers can return -an empty list. Some other headers are expected to have a value if provided -and may crash if the value is missing. - -The authorization header parsing code currently only supports basic -HTTP authentication. The `Credentials` type is thus `{Username, Password}` -with `Username` and `Password` being `binary()`. - -The range header value `Range` can take three forms: - -* `{From, To}`: from `From` to `To` units -* `{From, infinity}`: everything after `From` units -* `-Final`: the final `Final` units - -An `undefined` tuple will be returned if Cowboy doesn't know how -to parse the requested header. - -=== parse_qs(Req) -> [{Name, Value}] - -Name = binary():: Query string field name. -Value = binary() | true:: Query string field value. - -Return the request's query string as a list of tuples. - -The atom `true` is returned for keys which have no value. -Keys with no value are different from keys with an empty -value in that they do not have a `=` indicating the presence -of a value. - -=== path(Req) -> Path - -Path = binary():: Requested path. - -Return the requested path. - -=== path_info(Req) -> PathInfo - -PathInfo = cowboy_router:tokens() | undefined:: Extra tokens for the path. - -Return the extra tokens from matching against `...` during routing. - -=== peer(Req) -> Peer - -Peer = `{inet:ip_address(), inet:port_number()}`:: Peer IP address and port number. - -Return the client's IP address and port number. - -=== port(Req) -> Port - -Port = inet:port_number():: Requested port number. - -Return the request's port. - -The port returned by this function is obtained by parsing -the host header. It may be different than the actual port -the client used to connect to the Cowboy server. - -=== qs(Req) -> QueryString - -QueryString = binary():: Unprocessed query string. - -Return the request's query string. - -=== set_meta(Name, Value, Req) -> Req2 - -Name = atom():: Metadata name. -Value = any():: Metadata value. - -Set metadata about the request. - -An existing value will be overwritten. - -=== url(Req) -> URL - -URL = binary() | undefined:: Requested URL. +Body reading options. -Return the requested URL. +The defaults are function-specific. -This function will always return `undefined` until the -`cowboy_router` middleware has been executed. +=== req() -=== version(Req) -> Version - -Version = cowboy:http_version():: Client's advertised HTTP version. - -Return the HTTP version used for this request. - -== Request body related exports - -=== body(Req) -> body(Req, []) - -Alias of `cowboy_req:body/2`. - -=== body(Req, Opts) -> {ok, Data, Req2} | {more, Data, Req2} - -Opts = [body_opt()]:: Request body reading options. -Data = binary():: Data read from the body. - -Read the request body. - -This function will read a chunk of the request body. If there is -more data to be read after this function call, then a `more` tuple -is returned. Otherwise an `ok` tuple is returned. - -Cowboy will automatically send a `100 Continue` reply if -required. If this behavior is not desirable, it can be disabled -by setting the `continue` option to `false`. - -Cowboy will by default attempt to read up to 8MB of the body, -but in chunks of 1MB. It will use a timeout of 15s per chunk. -All these values can be changed using the `length`, `read_length` -and `read_timeout` options respectively. Note that the size -of the data may not be the same as requested as the decoding -functions may grow or shrink it, and Cowboy makes not attempt -at returning an exact amount. - -Cowboy will properly handle chunked transfer-encoding by -default. If any other transfer-encoding or content-encoding -has been used for the request, custom decoding functions -can be used. The `content_decode` and `transfer_decode` -options allow setting the decode functions manually. - -After the body has been streamed fully, Cowboy will remove -the transfer-encoding header from the Req object, and add -the content-length header if it wasn't already there. - -This function can only be called once. Cowboy will not cache -the result of this call. - -=== body_length(Req) -> Length - -Length = non_neg_integer() | undefined:: Length of the request body. - -Return the length of the request body. - -The length will only be returned if the request does not -use any transfer-encoding and if the content-length header -is present. - -=== body_qs(Req) -> body_qs(Req, [{length, 64000}, {read_length, 64000}, {read_timeout, 5000}]) - -Alias of `cowboy_req:body_qs/2`. - -=== body_qs(Req, Opts) -> {ok, [{Name, Value}], Req2} | {badlength, Req2} - -Opts = [body_opt()]:: Request body reading options. -Name = binary():: Field name. -Value = binary() | true:: Field value. - -Return the request body as a list of tuples. - -This function will parse the body assuming the content-type -application/x-www-form-urlencoded, commonly used for the -query string. - -This function calls `body/2` for reading the body, with the -same options it received. By default it will attempt to read -a body of 64KB in one chunk, with a timeout of 5s. If the -body is larger then a `badlength` tuple is returned. - -This function can only be called once. Cowboy will not cache -the result of this call. - -=== has_body(Req) -> boolean() - -Return whether the request has a body. - -=== part(Req) -> part(Req, [{length, 64000}, {read_length, 64000}, {read_timeout, 5000}]) - -Alias of `cowboy_req:part/2`. - -=== part(Req, Opts) -> {ok, Headers, Req2} | {done, Req2} - -Opts = [body_opt()]:: Request body reading options. -Headers = cow_multipart:headers():: Part's headers. - -Read the headers for the next part of the multipart message. - -Cowboy will skip any data remaining until the beginning of -the next part. This includes the preamble to the multipart -message but also the body of a previous part if it hasn't -been read. Both are skipped automatically when calling this -function. - -The headers returned are MIME headers, NOT HTTP headers. -They can be parsed using the functions from the `cow_multipart` -module. In addition, the `cow_multipart:form_data/1` function -can be used to quickly figure out `multipart/form-data` messages. -It takes the list of headers and returns whether this part is -a simple form field or a file being uploaded. - -Note that once a part has been read, or skipped, it cannot -be read again. - -This function calls `body/2` for reading the body, with the -same options it received. By default it will only read chunks -of 64KB with a timeout of 5s. This is tailored for reading -part headers, not for skipping the previous part's body. -You might want to consider skipping large parts manually. - -=== part_body(Req) -> part_body(Req, []) - -Alias of `cowboy_req:part_body/2`. - -=== part_body(Req, Opts) -> {ok, Data, Req2} | {more, Data, Req2} - -Opts = [body_opt()]:: Request body reading options. -Data = binary():: Part's body. - -Read the body of the current part of the multipart message. - -This function calls `body/2` for reading the body, with the -same options it received. It uses the same defaults. - -If there are more data to be read from the socket for this -part, the function will return what it could read inside a -`more` tuple. Otherwise, it will return an `ok` tuple. - -Calling this function again after receiving a `more` tuple -will return another chunk of body. The last chunk will be -returned inside an `ok` tuple. - -Note that once the body has been read, fully or partially, -it cannot be read again. - -== Response related exports - -=== chunk(Data, Req) -> ok - -Data = iodata():: Chunk data to be sent. - -Send a chunk of data. - -This function should be called as many times as needed -to send data chunks after calling `chunked_reply/{2,3}`. - -When the method is HEAD, no data will actually be sent. - -If the request uses HTTP/1.0, the data is sent directly -without wrapping it in an HTTP/1.1 chunk, providing -compatibility with older clients. - -=== chunked_reply(StatusCode, Req) -> chunked_reply(StatusCode, [], Req) - -Alias of `cowboy_req:chunked_reply/3`. - -=== chunked_reply(StatusCode, Headers, Req) -> Req2 - -StatusCode = cowboy:http_status():: Response status code. -Headers = cowboy:http_headers():: Response headers. - -Send a response using chunked transfer-encoding. - -This function effectively sends the response status line -and headers to the client. - -This function will not send any body set previously. After -this call the handler must use the `chunk/2` function -repeatedly to send the body in as many chunks as needed. - -If the request uses HTTP/1.0, the data is sent directly -without wrapping it in an HTTP/1.1 chunk, providing -compatibility with older clients. - -This function can only be called once, with the exception -of overriding the response in the `onresponse` hook. - -=== continue(Req) -> ok - -Send a 100 Continue intermediate reply. - -This reply is required before the client starts sending the -body when the request contains the `expect` header with the -`100-continue` value. - -Cowboy will send this automatically when required. However -you may want to do it manually by disabling this behavior -with the `continue` body option and then calling this -function. - -=== delete_resp_header(Name, Req) -> Req2 - -Name = binary():: Response header name. - -Delete the given response header. - -While header names are case insensitive, this function expects -the name to be a lowercase binary. - -=== has_resp_body(Req) -> boolean() - -Return whether a response body has been set. - -This function will return false if a response body has -been set with a length of 0. - -=== has_resp_header(Name, Req) -> boolean() - -Name = binary():: Response header name. - -Return whether the given response header has been set. - -While header names are case insensitive, this function expects -the name to be a lowercase binary. - -=== reply(StatusCode, Req) -> reply(StatusCode, [], Req) - -Alias of `cowboy_req:reply/3`. - -=== reply(StatusCode, Headers, Req) - see below - -Alias of `cowboy_req:reply/4`, with caveats. - -=== reply(StatusCode, Headers, Body, Req) -> Req2 - -StatusCode = cowboy:http_status():: Response status code. -Headers = cowboy:http_headers():: Response headers. -Body = iodata():: Response body. - -Send a response. - -This function effectively sends the response status line, -headers and body to the client, in a single send function -call. - -The `reply/2` and `reply/3` functions will send the body -set previously, if any. The `reply/4` function overrides -any body set previously and sends `Body` instead. - -If a body function was set, and `reply/2` or `reply/3` was -used, it will be called before returning. - -No more data can be sent to the client after this function -returns. - -This function can only be called once, with the exception -of overriding the response in the `onresponse` hook. - -=== set_resp_body(Body, Req) -> Req2 - -Body = iodata():: Response body. - -Set a response body. - -This body will not be sent if `chunked_reply/{2,3}` or -`reply/4` is used, as they override it. - -=== set_resp_body_fun(Fun, Req) -> Req2 - -Alias of `cowboy_req:set_resp_body_fun/3`. - -=== set_resp_body_fun(Length, Fun, Req) -> Req2 - -Fun = fun((Socket, Transport) -> ok):: Fun that will send the response body. -Socket = inet:socket():: Socket for this connection. -Transport = module():: Transport module for this socket. -Length = non_neg_integer():: Length of the response body. - -Set a fun for sending the response body. +[source,erlang] +---- +req() :: #{ + method := binary(), %% case sensitive + version := cowboy:http_version() | atom(), + scheme := binary(), %% lowercase; case insensitive + host := binary(), %% lowercase; case insensitive + port := inet:port_number(), + path := binary(), %% case sensitive + qs := binary(), %% case sensitive + headers := cowboy:http_headers(), + peer := {inet:ip_address(), inet:port_number()} +} +---- -If a `Length` is provided, it will be sent in the -content-length header in the response. It is recommended -to set the length if it can be known in advance. Otherwise, -the transfer-encoding header will be set to identity. +The Req object. -This function will only be called if the response is sent -using the `reply/2` or `reply/3` function. +Contains information about the request and response. While +some fields are publicly documented, others aren't and shouldn't +be used. -The fun will receive the Ranch `Socket` and `Transport` as -arguments. Only send and sendfile operations are supported. +You may add custom fields if required. Make sure to namespace +them by prepending an underscore and the name of your application: -=== set_resp_body_fun(chunked, Fun, Req) -> Req2 +.Setting a custom field +[source,erlang] +---- +Req#{_myapp_auth_method => pubkey}. +---- -Fun = fun((ChunkFun) -> ok):: Fun that will send the response body. -ChunkFun = fun((iodata()) -> ok):: Fun to call for every chunk to be sent. +=== resp_body() -Set a fun for sending the response body using chunked transfer-encoding. +[source,erlang] +---- +resp_body() :: iodata() + | {sendfile, Offset, Length, Filename} -This function will only be called if the response is sent -using the `reply/2` or `reply/3` function. +Offset :: non_neg_integer() +Length :: pos_integer() +Filename :: file:name_all() +---- -The fun will receive another fun as argument. This fun is to -be used to send chunks in a similar way to the `chunk/2` function, -except the fun only takes one argument, the data to be sent in -the chunk. +Response body. -=== set_resp_cookie(Name, Value, Opts, Req) -> Req2 +It can take two forms: the actual data to be sent or a +tuple indicating which file to send. -Name = iodata():: Cookie name. -Value = iodata():: Cookie value. -Opts = cookie_opts():: Cookie options. +When sending data directly, the type is either a binary or +an iolist. Iolists are an efficient way to build output. +Instead of concatenating strings or binaries, you can simply +build a list containing the fragments you want to send in the +order they should be sent: -Set a cookie in the response. +.Example iolists usage +[source,erlang] +---- +1> RespBody = ["Hello ", [<<"world">>, $!]]. +["Hello ",[<<"world">>,33]] +2> io:format("~s~n", [RespBody]). +Hello world! +---- -Cookie names are case sensitive. +When using the sendfile tuple, the `Length` value is mandatory +and must be higher than 0. It is sent with the response in the +content-length header. -=== set_resp_header(Name, Value, Req) -> Req2 +// @todo Make sure we have a test with an empty file... +// @todo cowboy_static should probably NOT return a sendfile tuple if size is 0. -Name = binary():: Response header name. -Value = iodata():: Response header value. +//%% While sendfile allows a Len of 0 that means "everything past Offset", +//%% Cowboy expects the real length as it is used as metadata. +//%% @todo We should probably explicitly reject it. -Set a response header. +== See also -You should use `set_resp_cookie/4` instead of this function -to set cookies. +link:man:cowboy(7)[cowboy(7)] diff --git a/doc/src/manual/cowboy_req.header.asciidoc b/doc/src/manual/cowboy_req.header.asciidoc new file mode 100644 index 0000000..e16b902 --- /dev/null +++ b/doc/src/manual/cowboy_req.header.asciidoc @@ -0,0 +1,74 @@ += cowboy_req:header(3) + +== Name + +cowboy_req:header - HTTP header + +== Description + +[source,erlang] +---- +header(Name :: binary(), Req) -> header(Name, Req, undefined) +header(Name :: binary(), Req, Default) -> binary() | Default + +Req :: cowboy_req:req() +---- + +Return the value for the given HTTP header. + +The header name must be given as a lowercase binary string. +While header names are case insensitive, Cowboy requires them +to be given as lowercase to function properly. + +Headers can also be obtained using pattern matching: + +[source,erlang] +---- +#{headers := #{Name := Value}} = Req. +---- + +Note that this snippet will crash if the header is missing. + +== Arguments + +Name:: + +Desired HTTP header name as a binary string. + +Req:: + +The Req object. + +Default:: + +Default value returned when the header is missing. + +== Return value + +The header value is returned as a binary string. When the +header is missing, the default argument is returned. + +== Changelog + +* *2.0*: Only the header value is returned, it is no longer wrapped in a tuple. +* *1.0*: Function introduced. + +== Examples + +.Get the accept header +[source,erlang] +---- +Accept = cowboy_req:header(<<"accept">>, Req). +---- + +.Get the content-length header with a default value +[source,erlang] +---- +Length = cowboy_req:header(<<"content-length">>, Req, <<"0">>). +---- + +== See also + +link:man:cowboy_req(3)[cowboy_req(3)], +link:man:cowboy_req:headers(3)[cowboy_req:headers(3)], +link:man:cowboy_req:parse_header(3)[cowboy_req:parse_header(3)] diff --git a/doc/src/manual/cowboy_req.headers.asciidoc b/doc/src/manual/cowboy_req.headers.asciidoc new file mode 100644 index 0000000..c370f6d --- /dev/null +++ b/doc/src/manual/cowboy_req.headers.asciidoc @@ -0,0 +1,51 @@ += cowboy_req:headers(3) + +== Name + +cowboy_req:headers - HTTP headers + +== Description + +[source,erlang] +---- +headers(Req :: cowboy_req:req()) -> cowboy:http_headers() +---- + +Return all request headers. + +Request headers can also be obtained using pattern matching: + +[source,erlang] +---- +#{headers := Headers} = Req. +---- + +== Arguments + +Req:: + +The Req object. + +== Return value + +Headers are returned as a map with keys being lowercase +binary strings, and values as binary strings. + +== Changelog + +* *2.0*: Only the headers are returned, they are no longer wrapped in a tuple. +* *1.0*: Function introduced. + +== Examples + +.Get all headers +[source,erlang] +---- +Headers = cowboy_req:headers(Req). +---- + +== See also + +link:man:cowboy_req(3)[cowboy_req(3)], +link:man:cowboy_req:header(3)[cowboy_req:header(3)], +link:man:cowboy_req:parse_header(3)[cowboy_req:parse_header(3)] diff --git a/doc/src/manual/cowboy_req.host.asciidoc b/doc/src/manual/cowboy_req.host.asciidoc new file mode 100644 index 0000000..2c512e2 --- /dev/null +++ b/doc/src/manual/cowboy_req.host.asciidoc @@ -0,0 +1,52 @@ += cowboy_req:host(3) + +== Name + +cowboy_req:host - URI host name + +== Description + +[source,erlang] +---- +host(Req :: cowboy_req:req()) -> Host :: binary() +---- + +Return the host name of the effective request URI. + +The host name can also be obtained using pattern matching: + +[source,erlang] +---- +#{host := Host} = Req. +---- + +== Arguments + +Req:: + +The Req object. + +== Return value + +The host name is returned as a lowercase binary string. +It is case insensitive. + +== Changelog + +* *2.0*: Only the host name is returned, it is no longer wrapped in a tuple. +* *1.0*: Function introduced. + +== Examples + +.Get the effective request URI's host name +[source,erlang] +---- +Host = cowboy_req:host(Req). +---- + +== See also + +link:man:cowboy_req(3)[cowboy_req(3)], +link:man:cowboy_req:binding(3)[cowboy_req:binding(3)], +link:man:cowboy_req:bindings(3)[cowboy_req:bindings(3)], +link:man:cowboy_req:host_info(3)[cowboy_req:host_info(3)] diff --git a/doc/src/manual/cowboy_req.method.asciidoc b/doc/src/manual/cowboy_req.method.asciidoc new file mode 100644 index 0000000..bb3ad6e --- /dev/null +++ b/doc/src/manual/cowboy_req.method.asciidoc @@ -0,0 +1,60 @@ += cowboy_req:method(3) + +== Name + +cowboy_req:method - HTTP method + +== Description + +[source,erlang] +---- +method(Req :: cowboy_req:req()) -> Method :: binary() +---- + +Return the request's HTTP method. + +The method can also be obtained using pattern matching: + +[source,erlang] +---- +#{method := Method} = Req. +---- + +== Arguments + +Req:: + +The Req object. + +== Return value + +The request's HTTP method is returned as a binary string. +While methods are case sensitive, standard methods are +always uppercase. + +== Changelog + +* *2.0*: Only the method is returned, it is no longer wrapped in a tuple. +* *1.0*: Function introduced. + +== Examples + +.Ensure the request's method is GET +[source,erlang] +---- +<<"GET">> = cowboy_req:method(Req). +---- + +.Allow methods from list +[source,erlang] +---- +init(Req, State) -> + case lists:member(cowboy_req:method(Req), [<<"GET">>, <<"POST">>]) of + true -> handle(Req, State); + false -> method_not_allowed(Req, State) + end. +---- + +== See also + +link:man:cowboy_req(3)[cowboy_req(3)] diff --git a/doc/src/manual/cowboy_req.path.asciidoc b/doc/src/manual/cowboy_req.path.asciidoc new file mode 100644 index 0000000..5f26548 --- /dev/null +++ b/doc/src/manual/cowboy_req.path.asciidoc @@ -0,0 +1,51 @@ += cowboy_req:path(3) + +== Name + +cowboy_req:path - URI path + +== Description + +[source,erlang] +---- +path(Req :: cowboy_req:req()) -> Path :: binary() +---- + +Return the path of the effective request URI. + +The path can also be obtained using pattern matching: + +[source,erlang] +---- +#{path := Path} = Req. +---- + +== Arguments + +Req:: + +The Req object. + +== Return value + +The path is returned as a binary string. It is case sensitive. + +== Changelog + +* *2.0*: Only the path is returned, it is no longer wrapped in a tuple. +* *1.0*: Function introduced. + +== Examples + +.Get the effective request URI's path +[source,erlang] +---- +Path = cowboy_req:path(Req). +---- + +== See also + +link:man:cowboy_req(3)[cowboy_req(3)], +link:man:cowboy_req:binding(3)[cowboy_req:binding(3)], +link:man:cowboy_req:bindings(3)[cowboy_req:bindings(3)], +link:man:cowboy_req:path_info(3)[cowboy_req:path_info(3)] diff --git a/doc/src/manual/cowboy_req.peer.asciidoc b/doc/src/manual/cowboy_req.peer.asciidoc new file mode 100644 index 0000000..e2df691 --- /dev/null +++ b/doc/src/manual/cowboy_req.peer.asciidoc @@ -0,0 +1,61 @@ += cowboy_req:peer(3) + +== Name + +cowboy_req:peer - Peer address and port + +== Description + +[source,erlang] +---- +peer(Req :: cowboy_req:req()) -> Peer + +Peer :: {inet:ip_address(), inet:port_number()} +---- + +Return the peer's IP address and port number. + +The peer can also be obtained using pattern matching: + +[source,erlang] +---- +#{peer := {IP, Port}} = Req. +---- + +// @todo So we need tests for accessing the Req directly. + +== Arguments + +Req:: + +The Req object. + +== Return value + +The peer's IP address and port number. + +The peer is not necessarily the client's IP address and port. +It is the IP address of the endpoint connecting directly to +the server, which may be a gateway or a proxy. + +The forwarded header can be used to get better information +about the different endpoints from the client to the server. +Note however that it is only informative; there is no reliable +way of determining the source of an HTTP request. + +== Changelog + +* *2.0*: Only the peer is returned, it is no longer wrapped in a tuple. +* *1.0*: Function introduced. + +== Examples + +.Get the peer IP address and port number. +[source,erlang] +---- +{IP, Port} = cowboy_req:peer(Req). +---- + +== See also + +link:man:cowboy_req(3)[cowboy_req(3)] diff --git a/doc/src/manual/cowboy_req.port.asciidoc b/doc/src/manual/cowboy_req.port.asciidoc new file mode 100644 index 0000000..57f0875 --- /dev/null +++ b/doc/src/manual/cowboy_req.port.asciidoc @@ -0,0 +1,52 @@ += cowboy_req:port(3) + +== Name + +cowboy_req:port - URI port number + +== Description + +[source,erlang] +---- +port(Req :: cowboy_req:req()) -> Port :: inet:port_number() +---- + +Return the port number of the effective request URI. + +Note that the port number returned by this function is obtained +by parsing the host header. It may be different from the port +the peer used to connect to Cowboy. + +The port number can also be obtained using pattern matching: + +[source,erlang] +---- +#{port := Port} = Req. +---- + +== Arguments + +Req:: + +The Req object. + +== Return value + +The port number is returned as an integer. + +== Changelog + +* *2.0*: Only the port number is returned, it is no longer wrapped in a tuple. +* *1.0*: Function introduced. + +== Examples + +.Get the effective request URI's port number +[source,erlang] +---- +Port = cowboy_req:port(Req). +---- + +== See also + +link:man:cowboy_req(3)[cowboy_req(3)] diff --git a/doc/src/manual/cowboy_req.qs.asciidoc b/doc/src/manual/cowboy_req.qs.asciidoc new file mode 100644 index 0000000..6e92357 --- /dev/null +++ b/doc/src/manual/cowboy_req.qs.asciidoc @@ -0,0 +1,50 @@ += cowboy_req:qs(3) + +== Name + +cowboy_req:qs - URI query string + +== Description + +[source,erlang] +---- +qs(Req :: cowboy_req:req()) -> Qs :: binary() +---- + +Return the query string of the effective request URI. + +The query string can also be obtained using pattern matching: + +[source,erlang] +---- +#{qs := Qs} = Req. +---- + +== Arguments + +Req:: + +The Req object. + +== Return value + +The query string is returned as a binary string. It is case sensitive. + +== Changelog + +* *2.0*: Only the query string is returned, it is no longer wrapped in a tuple. +* *1.0*: Function introduced. + +== Examples + +.Get the effective request URI's query string +[source,erlang] +---- +Qs = cowboy_req:qs(Req). +---- + +== See also + +link:man:cowboy_req(3)[cowboy_req(3)], +link:man:cowboy_req:parse_qs(3)[cowboy_req:parse_qs(3)], +link:man:cowboy_req:match_qs(3)[cowboy_req:match_qs(3)] diff --git a/doc/src/manual/cowboy_req.scheme.asciidoc b/doc/src/manual/cowboy_req.scheme.asciidoc new file mode 100644 index 0000000..bbe147d --- /dev/null +++ b/doc/src/manual/cowboy_req.scheme.asciidoc @@ -0,0 +1,55 @@ += cowboy_req:scheme(3) + +== Name + +cowboy_req:scheme - URI scheme + +== Description + +[source,erlang] +---- +scheme(Req :: cowboy_req:req()) -> Scheme :: binary() +---- + +Return the scheme of the effective request URI. + +The scheme can also be obtained using pattern matching: + +[source,erlang] +---- +#{scheme := Scheme} = Req. +---- + +== Arguments + +Req:: + +The Req object. + +== Return value + +The scheme is returned as a binary. It is case insensitive. + +Cowboy will only set the scheme to `<<"http">>` or `<<"https">>`. + +== Changelog + +* *2.0*: Function introduced. + +== Examples + +.Redirect HTTP to HTTPS +[source,erlang] +---- +init(Req0=#{scheme := <<"http">>}, State) -> + Req = cowboy_req:reply(302, #{ + <<"location">> => cowboy_req:uri(Req, #{scheme => <<"https">>}) + }, Req0), + {ok, Req, State}; +init(Req, State) -> + {cowboy_rest, Req, State}. +---- + +== See also + +link:man:cowboy_req(3)[cowboy_req(3)] diff --git a/doc/src/manual/cowboy_req.uri.asciidoc b/doc/src/manual/cowboy_req.uri.asciidoc new file mode 100644 index 0000000..790f863 --- /dev/null +++ b/doc/src/manual/cowboy_req.uri.asciidoc @@ -0,0 +1,116 @@ += cowboy_req:uri(3) + +== Name + +cowboy_req:uri - Reconstructed URI + +== Description + +[source,erlang] +---- +uri(Req :: cowboy_req:req()) -> uri(Req, #{}) +uri(Req :: cowboy_req:req(), Opts) -> URI :: iodata() + +Opts :: #{ + scheme => iodata() | undefined, + host => iodata() | undefined, + port => inet:port_number() | undefined, + path => iodata() | undefined, + qs => iodata() | undefined, + fragment => iodata() | undefined +} +---- + +Reconstruct the effective request URI, optionally modifying components. + +By default Cowboy will build a URI using the components found +in the request. Options allow disabling or replacing individual +components. + +== Arguments + +Req:: + +The Req object. + +Opts:: + +Map for overriding individual components. ++ +To replace a component, provide its new value as a binary +string or an iolist. To disable a component, set its value +to `undefined`. ++ +As this function always returns a valid URI, there are some +things to note: ++ + * Disabling the host also disables the scheme and port. + * There is no fragment component by default as these are + not sent with the request. + * The port number may not appear in the resulting URI if + it is the default port for the given scheme (http: 80; https: 443). + +== Return value + +The reconstructed URI is returned as an iolist or a binary string. + +== Changelog + +* *2.0*: Individual components can be replaced or disabled. +* *2.0*: Only the URI is returned, it is no longer wrapped in a tuple. +* *2.0*: Function introduced. Replaces `host_url/1` and `url/1`. + +== Examples + +With an effective request URI http://example.org/path/to/res?edit=1 +we can have: + +.Protocol relative form +[source,erlang] +---- +%% //example.org/path/to/res?edit=1 +cowboy_req:uri(Req, #{scheme => undefined}). +---- + +.Serialized origin for use in the origin header +[source,erlang] +---- +%% http://example.org +cowboy_req:uri(Req, #{path => undefined, qs => undefined}). +---- + +.HTTP/1.1 origin form (path and query string only) +[source,erlang] +---- +%% /path/to/res?edit=1 +cowboy_req:uri(Req, #{host => undefined}). +---- + +.Add a fragment to the URI +[source,erlang] +---- +%% http://example.org/path/to/res?edit=1#errors +cowboy_req:uri(Req, #{fragment => <<"errors">>}). +---- + +.Ensure the scheme is HTTPS +[source,erlang] +---- +%% https://example.org/path/to/res?edit=1 +cowboy_req:uri(Req, #{scheme => <<"https">>}). +---- + +.Convert the URI to a binary string +[source,erlang] +---- +iolist_to_binary(cowboy_req:uri(Req)). +---- + +== See also + +link:man:cowboy_req(3)[cowboy_req(3)], +link:man:cowboy_req:scheme(3)[cowboy_req:scheme(3)], +link:man:cowboy_req:host(3)[cowboy_req:host(3)], +link:man:cowboy_req:port(3)[cowboy_req:port(3)], +link:man:cowboy_req:path(3)[cowboy_req:path(3)], +link:man:cowboy_req:qs(3)[cowboy_req:qs(3)] diff --git a/doc/src/manual/cowboy_req.version.asciidoc b/doc/src/manual/cowboy_req.version.asciidoc new file mode 100644 index 0000000..15920c4 --- /dev/null +++ b/doc/src/manual/cowboy_req.version.asciidoc @@ -0,0 +1,49 @@ += cowboy_req:version(3) + +== Name + +cowboy_req:version - HTTP version + +== Description + +[source,erlang] +---- +version(Req :: cowboy_req:req()) -> Version :: cowboy:http_version() +---- + +Return the HTTP version used for the request. + +The version can also be obtained using pattern matching: + +[source,erlang] +---- +#{version := Version} = Req. +---- + +== Arguments + +Req:: + +The Req object. + +== Return value + +The HTTP version used for the request is returned as an +atom. It is provided for informative purposes only. + +== Changelog + +* *2.0*: Only the version is returned, it is no longer wrapped in a tuple. +* *1.0*: Function introduced. + +== Examples + +.Get the HTTP version +[source,erlang] +---- +Version = cowboy_req:version(Req). +---- + +== See also + +link:man:cowboy_req(3)[cowboy_req(3)] -- cgit v1.2.3