cowboy (2.0.0)

  • routing
  • handlers
  • static handler
  • Req object
  • response
  • cookies
  • hooks
  • websockets
  • rest
  • loop

  • how it works

    when cowboy receives a request, it tries to match the requested host and path to the resources given in the dispatch rules

    if it matches, then the associated Erlang code will be executed

    you can only send one response - any other attempt will trigger a crash

    the response may be sent in one go or with its body streamed by chunks of arbitrary size

    you can set headers or the response body in advance and cowboy will use them when you finally do reply

    cowboy provides the hook onresponse which can be called just before sending the response


    routing

    you need to map URLs to Erlang modules that will handle the requests. this is called routing

    routing rules are given per host

    cowboy will first match on the host, and then try to find a matching path

    routes need to be compiled before they can be used by cowboy_router:compile/1

    structure

    Routes = [Host] 
    
    Host = {HostMatch, [Path]} | {HostMatch, Constraints, [Path]} 
    
    Path = {PathMatch, Handler, [Opt]} | {PathMatch, Constraints, Handler, [Opt]}
    

    each path contains matching rules for the path along with optional constraints, and gives the handler module to be used along with options that will be given to it on initialization

    [Opt] is a proplist(). this list is sent as second parameter to handler (in case matching is successfull). this list may be empty

     Opt = {Name , Value}

    match syntax

    the match syntax is the same for host and path - indeed, the segments separator is different, and the host is matched starting from the last segment going to the first

    the simplest match value is a host or a path. it can be given as either a string() or a binary()

    
    PathMatch1 = "/"
    PathMatch2 = "/path/to/resource"
    
    HostMatch1 = "cowboy.example.org"
    

    all paths must start with a slash character

    hosts with and without a trailing dot are equivalent for routing. similarly, hosts with and without a leading dot are also equivalent:

    
    HostMatch1 = "cowboy.example.org"
    HostMatch2 = "cowboy.example.org."
    HostMatch3 = ".cowboy.example.org"
    

    it is possible to extract segments of the host and path and to store the values in the Req object for later use. these kind of values are called bindings

    a segment that begins with the : character means that what follows until the end of the segment is the name of the binding in which the segment value will be stored:

    PathMatch = "/hats/:name/prices".
    HostMatch = ":subdomain.example.org".
    

    if these two end up matching when routing, you will end up with two bindings defined, subdomain and name, each containing the segment value where they were defined

    for previous example, the URL http://test.example.org/hats/wild_cowboy_legendary/prices will result in having

    they can later be retrieved using cowboy_req:binding/2/3

    the binding name must be given as an atom()

    any match against the _ binding will succeed but the data will be discarded. this is especially useful for matching against many domain names in one go

    HostMatch = "ninenines.:_".
    

    it is possible to have optional segments. anything between brackets is optional:

    PathMatch = "/hats/[page/:number]".
    HostMatch = "[www.]ninenines.eu".
    

    you can also have imbricated optional segments:

    PathMatch = "/hats/[page/[:number]]".
    

    you can retrieve the rest of the host or path using [...] . in the case of hosts it will match anything before, in the case of paths anything after the previously matched segments. it is a special case of optional segments, in that it can have zero, one or many segments

    PathMatch = "/hats/[...]".
    HostMatch = "[...]ninenines.eu".
    

    you can then find the segments using cowboy_req:host_info/1 and cowboy_req:path_info/1 respectively. they will be represented as a list of segments:

    if a binding appears twice in the routing rules, then the match will succeed only if they share the same value - this copies the Erlang pattern matching behavior

    PathMatch = "/hats/:name/:name".
    

    this is also true when an optional segment is present. in this case the two values must be identical only if the segment is available:

    PathMatch = "/hats/:name/[:name]".
    

    if a binding is defined in both the host and path, then they must also share the same value:

    PathMatch = "/:user/[...]".
    HostMatch = ":user.github.com".
    

    there are two special match values that can be used. The first is the atom '_' which will match any host or path:

    PathMatch = '_'.
    HostMatch = '_'.
    

    the second is the special host match "*" which will match the wildcard path, generally used alongside the OPTIONS HTTP method

    HostMatch = "*".
    

    constraints

    after the matching has completed, the resulting bindings can be tested against a set of constraints

    constraints are only tested when the binding is defined. they run in the order you defined them. the match will succeed only if all constrains succeed. if the match fails, then cowboy tries the next route in the list

    the format used for constraints is the next: they are provided as a list of fields which may have one or more constraints. while the router accepts the same format, it will skip fields with no constraints and will also ignore default values, if any

    compilation

    the structure needs to be compiled before it is passed to cowboy. this can be done with a simple call to cowboy_router:compile/1:

    D = cowboy_router:compile ([ % HostMatch, PathMatch, Handler, Opts % -------------------------------------------- {'_', [{'_', my_handler, []}]} ]), cowboy:start_http ( % Name, NbAcceptors, TransOpts, ProtoOpts % -------------------------------------------------------------- my_http_listener, 100, [{port, 8080}], [{env, [{dispatch, D}]}]).

    this function will return {error, badarg} if the structure given is incorrect

    live update

    you can use the cowboy:set_env/3 function for updating the dispatch list used by routing. this will apply to all new connections accepted by the listener

    cowboy:set_env (my_http_listener, dispatch, cowboy_router:compile (Dispatch)).
    

    you need to compile the routes before updating


    handlers

    basic handlers

    the most basic handler module implements the mandatory init/3 callback which manipulates the request, (optionally) sends a response and then returns

    init/3 receives as args the Req object and the Options defined during the router configuration

    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

    init (Req, _Opts) -> cowboy_req:reply ( 200, [ {<<"content-type">>, <<"text/plain">>} ], <<"Hello World!">>, Req ).

    the function return a 2-tuple. ok means that the handler ran successfully

    plain HTTP handlers only have one additional callback, the optional terminate/3

    other handlers

    the init/2 callback can be used to inform cowboy that this is a different kind of handler and that cowboy should switch to it. you simply need to return the module name of the handler type you want to switch to {Mod, Req}

    cowboy comes with three handler types you can switch to:

    in addition to those you can define your own handler types

    init (Req, _Opts) -> {cowboy_rest, Req}.
    
    init (Req, Opts) -> {cowboy_websocket, Req, Opts}.
    
    init (Req, _Opts) -> {my_handler_type, Req}.
    

    cleaning up

    terminate (_Reason, Req, State) -> ok.
    

    this callback is strictly reserved for any required cleanup. you cannot send a response from this function. there is no other return value


    static handler

    the static handler is a built-in REST handler for serving files. it is available as a convenience and provides a quick solution for serving files during development.

    the static handler can serve either one file or all files from a given directory. it can also send etag headers for client-side caching

    to use the static file handler, simply add routes for it with the appropriate options

    one file

    you can use the static handler to serve one specific file from an application's private directory. this is particularly useful to serve an index.html file when the client requests the / path, for example. the path configured is relative to the given application's private directory

    the following rule will serve the file static/index.html from the application my_app's priv directory whenever the path / is accessed

    {"/", cowboy_static, {priv_file, my_app, "static/index.html"}}
    

    you can also specify the absolute path to a file, or the path to the file relative to the current directory:

    {"/", cowboy_static, {file, "/var/www/index.html"}}
    

    all files from a directory

    you can also use the static handler to serve all files that can be found in the configured directory. the handler will use the path_info information to resolve the file location, which means that your route must end with a [...] pattern for it to work. all files are served, including the ones that may be found in subfolders

    you can specify the directory relative to an application's private directory

    it will work only in release-based cowboy application, not standalone. and if you testing it in your local directory - dont foget opriton [local] in the command:
    > systools:make_script ("my_app-ver", [local]). ok

    now, if you have used command systools:make_script with option local then you can start your application in current working directory:

    $> erl -boot my_app-ver

    to shut down the system, use the normal q() command in the shell and all processes will be graefully stopped

    the following rule will serve any file found in the application my_app's priv directory inside the static/assets folder whenever the requested path begins with /assets/

    {"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets"}}
    

    you can also specify the absolute path to the directory or set it relative to the current directory:

    {"/assets/[...]", cowboy_static, {dir, "/var/www/assets"}}
    

    customize the mimetype detection

    by default, cowboy will attempt to recognize the mimetype of your static files by looking at the extension

    you can override the function that figures out the mimetype of the static files. it can be useful when cowboy is missing a mimetype you need to handle, or when you want to reduce the list to make lookups faster. you can also give a hard-coded mimetype that will be used unconditionally

    cowboy comes with two functions built-in. The default function only handles common file types used when building Web applications. The other function is an extensive list of hundreds of mimetypes that should cover almost any need you may have. You can of course create your own function.

    to use the default function, you should not have to configure anything. if you insist, though, the following will do the job:

    {"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
                                      [{mimetypes, cow_mimetypes, web}]}}
    

    there is an optional field that may contain a list of less used options, like mimetypes or etag. all option types have this optional field

    to use the function that will detect almost any mimetype, the following configuration will do:

    {"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
                                      [{mimetypes, cow_mimetypes, all}]}}
    

    you probably noticed the pattern by now. the configuration expects a module and a function name, so you can use any of your own functions instead:

    {"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
                                      [{mimetypes, Module, Function}]}}
    

    the function that performs the mimetype detection receives a single argument that is the path to the file on disk. it is recommended to return the mimetype in tuple form, although a binary string is also allowed (but will require extra processing). if the function can't figure out the mimetype, then it should return {<<"application">>, <<"octet-stream">>, []}

    when the static handler fails to find the extension in the list, it will send the file as application/octet-stream. a browser receiving such file will attempt to download it directly to disk

    finally, the mimetype can be hard-coded for all files. this is especially useful in combination with the file and priv_file options as it avoids needless computation:

    {"/", cowboy_static, {priv_file, my_app, "static/index.html",
                          [{mimetypes, {<<"text">>, <<"html">>, []}}]}}
    

    ETAG

    by default, the static handler will generate an etag header value based on the size and modified time. this solution can not be applied to all systems though. it would perform rather poorly over a cluster of nodes, for example, as the file metadata will vary from server to server, giving a different etag on each server

    you can however change the way the etag is calculated:

    {"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
                                      [{etag, Module, Function}]}}
    

    this function will receive three arguments: the path to the file on disk, the size of the file and the last modification time. in a distributed setup, you would typically use the file path to retrieve an etag value that is identical across all your servers

    you can also completely disable etag handling:

    {"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets", [{etag, false}]}}
    

    the Req object

    Req is the variable that you will use to obtain information about a request and read the body of the request. in fact it is completely opaque to you and the only way you can perform operations using it is by calling the functions from the cowboy_req module

    almost all the calls to the cowboy_req module will return an Req. this object is immutable but Req allows accessing both immutable and mutable state. this means that calling some of the functions with that object as param 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. so in stream-oriented applications you should pass this object as param (just as State in gen_server apps)

    interface

    when a client performs a request, it first sends a few required values. they indicate to the server the type of action it wants to do and how to locate the resource to perform it on

    cowboy_req:method   (Req) -> Method
    cowboy_req:host     (Req) -> Host
    cowboy_req:port     (Req) -> Port
    cowboy_req:path     (Req) -> Path
    cowboy_req:version  (Req) -> Version
    
         Method, Host, Port, Path, Version, Value :: binary()
    
    

    the method identifies the action. standard methods: GET, HEAD, OPTIONS, PATCH, POST, PUT, DELETE. method names are case sensitive

    the host and port information may not be available if the client uses HTTP/1.0

    cowboy_req:url      (Req) -> URL 
    cowboy_req:host_url (Req) -> Value
    
         URL :: binary() | undefined
    
    

    these two functions will always return undefined until the cowboy_router middleware has been executed

    bindings

    you can fetch a single binding. the value will be undefined if the binding doesn't exist

    cowboy_req:binding (my_binding, Req) -> Value
    

    if you need a different value when the binding doesn't exist, you can change the default:

    cowboy_req:binding (my_binding, Req, DefaultValue) -> Value
    

    you can also obtain all bindings in one call:

    cowboy_req:bindings (Req) -> [{atom(), any()}].
    

    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

    query

    the raw query string can be obtained directly;

    cowboy_req:qs (Req) -> binary() 
    cowboy_req:parse_qs (Req) -> [{Name, Value}]
    
    Name  ::  binary ()
    Value ::  binary () | true
    
    cowboy_req:match_qs ([Param], Req) -> proplist() 
    
    Param :: atom() | {atom(), atom()}
    
    

    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:

    cowboy_req:match_qs ([{id, int}, {lang, nonempty}], Req)
    

    in the case of duplicate query string keys, the map value will become a list of the different values

    a default value can be provided. it will not be used if the key is found but has an empty value.

    cowboy_req:match_qs ([{atom(), [], binary()}], Req)
    

    if no default is provided and the value is missing, the query string is deemed invalid and the process will crash

    headers

    this will get the string value of a header:

    cowboy_req:header (<<"content-type">>, Req)
    

    you can set a default in case the header is missing:

    cowboy_req:header (<<"content-type">>, Req, <<"text/plain">>)
    

    to obtain all headers:

    cowboy_req:headers (Req) -> [binary()]
    

    to parse header, simply call parse_header/2/3:

    cowboy_req:parse_header (<<"content-type">>, Req) -> Value | undefined
    

    cowboy will crash if it doesn't know how to parse the given header, or if the value is invalid

    you can define a default value:

    cowboy_req:parse_header (<<"content-type">>, Req, {<<"text">>, <<"plain">>, []})
    

    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:

    cowboy_req:peer (Req) -> {{A, B, C, D}, integer()}
    
     A, B, C, D :: nat()
    

    response

    general

    you can send a reply with no particular headers or body:

    cowboy_req:reply (200, Req)
    

    you can define headers to be sent with the response. note that header names must be lowercase:

    cowboy_req:reply (303, [{<<"location">>, <<"http://ninenines.eu">>}], Req).
    

    you can override headers - any header set by the user will be used over the ones set by cowboy. for example, you can advertise yourself as a different server:

    cowboy_req:reply(200, [{<<"server">>, <<"yaws">>}], Req).
    

    you can also send a body with the response. cowboy will automatically set the content-length header if you do

    cowboy_req:reply (200, [{<<"content-type">>, <<"text/plain">>}],
                             "Hello world!", Req).
    

    here is the same example but sending HTML this time:

    cowboy_req:reply (200, [{<<"content-type">>, <<"text/html">>}],
        "<html><body>Hello world!</body></html>", Req)
    

    note that the reply is sent immediately

    chunked reply

    you can also stream the response body

    first, you need to initiate the reply by sending the response status code

    then you can send the body in chunks of arbitrary size.

    cowboy_req:chunked_reply (200, Req), cowboy_req:chunk ("Hello...", Req), cowboy_req:chunk ("chunked...", Req), cowboy_req:chunk ("world!", Req).

    while it is possible to send a chunked response without a content-type header, it is still recommended. you can set this header or any other just like for normal replies:

    cowboy_req:chunked_reply(200, [{<<"content-type">>, <<"text/html">>}], Req), cowboy_req:chunk ("<html><head>Hello world!</head>", Req), cowboy_req:chunk ("<body><p>Hats off!</p></body></html>", Req).

    note that the reply and each chunk following it are sent immediately

    preset response headers

    you can define response headers in advance. they will be merged into the headers given in the reply call. headers in the reply call override preset response headers which override the default cowboy headers:

    cowboy_req:set_resp_header (<<"allow">>, "GET", Req).
    

    you can check if a response header has already been set. this will only check the response headers that you set, and not the ones cowboy will add when actually sending the reply:

    cowboy_req:has_resp_header (<<"allow">>, Req)
    

    it will return true if the header is defined, and false otherwise

    you can also delete a preset response header if needed. if you do, it will not be sent:

    cowboy_req:delete_resp_header (<<"allow">>, Req)
    

    preset response body

    you can set the response body in advance. note that this body will be ignored if you then choose to send a chunked reply, or if you send a reply with an explicit body:

    cowboy_req:set_resp_body (binary(), Req) -> Req
    

    you can also set a fun that will be called when it is time to send the body. there are three different ways of doing that

    if you know the length of the body that needs to be sent, you should specify it, as it will help clients determine the remaining download time and allow them to inform the user:

    F = fun (Socket, Transport) -> Transport:send (Socket, "Hello world!") end,
    cowboy_req:set_resp_body_fun (12, F, Req),
    

    if you do not know the length of the body, you should use a chunked response body fun instead:

    F = fun (SendChunk) -> 
      Body = lists:duplicate (random:uniform(1024, $a)), 
      SendChunk (Body)
    end,
    cowboy_req:set_resp_body_fun (chunked, F, Req),
    

    you can also send data on the socket directly, without knowing the length in advance. cowboy may be forced to close the connection at the end of the response though depending on the protocol capabilities:

    F = fun (Socket, Transport) ->
      Body = lists:duplicate (random:uniform(1024, $a)),
      Transport:send (Socket, Body)
    end,
    cowboy_req:set_resp_body_fun (F, Req),
    

    sending files

    you can send files directly from disk without having to read them. cowboy will use the sendfile syscall when possible, which means that the file is sent to the socket directly from the kernel, which is a lot more performant than doing it from userland

    again, it is recommended to set the size of the file if it can be known in advance:

    F = fun (Socket, Transport) -> Transport:sendfile (Socket, "priv/styles.css") end,
    cowboy_req:set_resp_body_fun (FileSize, F, Req),
    

    cookies

    setting cookies

    cowboy_req:set_resp_cookie (Name, Value, [], Req) -> Req
    
      Name, Value :: binary()  
    

    you can make them expire at a specific point in the future:

    cowboy_req:set_resp_cookie (Name, Value, [{max_age, nat()}], Req) -> Req
    
      Name, Value :: binary()  
    

    you can delete cookies that have already been set:

    cowboy_req:set_resp_cookie (<<"sessionid">>, <<>>, [{max_age, 0}], Req).

    you can restrict them to a specific domain and path:

    cowboy_req:set_resp_cookie (<<"inaccount">>, <<"1">>, [ {domain, "my.example.org"}, {path, "/account"} ], Req).

    you can restrict the cookie to secure channels, typically HTTPS:

    cowboy_req:set_resp_cookie (<<"sessionid">>, SessionID, [{secure, true}], Req).

    you can restrict the cookie to client-server communication only. such a cookie will not be available to client-side scripts:

    cowboy_req:set_resp_cookie (<<"sessionid">>, SessionID, [{http_only, true}], Req).

    reading cookies

    the client sends cookies with every request but, unlike the server, the client only sends the cookie name and value

    cookie (Name, Req)          -> Value
     cookie (Name, Req, Default) -> Value
    

    you can match the cookies into a map:

    cowboy_req:match_cookies ([Name1, Name2], Req) -> proplist()
    

    you can use constraints to validate the values while matching them. additionally the id cookie value will be converted to an integer term, saving you a conversion step:

    Mcookies = cowboy_req:match_cookies ([{id, int}, {lang, nonempty}], Req)

    if no default is provided and the value is missing, the query string is deemed invalid and the process will crash


    hooks

    the onresponse hook is called right before sending the response to the socket. it can be used for the purposes of logging responses, or for modifying the response headers or body. the best example is providing custom error pages

    note that this function MUST NOT crash. cowboy may or may not send a reply if this function crashes

    if a reply is sent, the hook MUST explicitly provide all headers that are needed

    you can specify the onresponse hook when creating the listener. the following hook function will provide a custom body for 404 errors when it has not been provided before, and will let cowboy proceed with the default response otherwise:

    cowboy:start_http (my_http_listener, 100, [{port, 8080}], [ {env, [{dispatch, Dispatch}]}, {onresponse, fun ?MODULE:custom_404_hook/4} ] ) custom_404_hook (404, Headers, <<>>, Req) -> Body = <<"404 Not Found.">>, Headers2 = lists:keyreplace (<<"content-length">>, 1, Headers, {<<"content-length">>, integer_to_list(byte_size(Body))}), {ok, Req} = cowboy_req:reply (404, Headers2, Body, Req), Req; custom_404_hook (_, _, _, Req) -> Req.

    make sure to ALWAYS return the last request object obtained


    websockets

    websocket_version 7 | 8 | 13

    module cowboy_websocket defines four callbacks which can be implemented by handlers. the init/3 and terminate/3 callbacks are common to all handler types. the websocket_handle/3 and websocket_info/3 callbacks are specific to Websocket handlers

    -module (websocket_handler). -compile (export_all). init (_, Req, Opts) -> {upgrade, protocol, cowboy_websocket, Req, Opts}. websocket_init (_Type, Req, _Opts) -> {ok, Req, [], 60000}. websocket_handle ({text, <<"stop">>}, Req, State) -> {reply, close, Req, State}; websocket_handle ({text, Msg}, Req, State) -> NewMsg = list_to_binary (lists:reverse (binary_to_list (Msg))), {reply, {text, NewMsg}, Req, State}; websocket_handle(_Data, Req, State) -> {ok, Req, State}. websocket_info (_Info, Req, State) -> {ok, Req, State}. websocket_terminate (_Reason, _Req, _State) -> ok.

    initialization

    first, the init/3 callback is called:

    init(_Type, Req, Opts) ->
      {upgrade, protocol, cowboy_websocket, Req, Opts, Timeout}
    

    upon receiving this tuple, Cowboy will switch to the code that handles Websocket connections and perform the handshake immediately

    the init/3 callback can be used to negotiate Websocket protocol extensions with the client. it is highly recommended to return a timeout value from this callback

    don't stay in init so long:

    init (_Type, Req, Opts) -> self() ! your_post_init, {upgrade, protocol, cowboy_websocket, Req, Opts, 30000}. websocket_info (your_post_init, Req, State) -> %% perform durable initialization here... {ok, Req, State}.

    callbacks

    websocket_handle (InFrame, Req, State) -> 
       {ok, Req, State}
     | {ok, Req, State, hibernate} 
     | {reply, OutFrame | [OutFrame], Req, State} 
     | {reply, OutFrame | [OutFrame], Req, State, hibernate} 
     | {stop, Req, State}
    

    Cowboy will call websocket_handle/3 whenever a text, binary, ping or pong frame arrives from the client. the handler can decide to send frames to the socket, stop or just continue without sending anything

    this function will be called every time data is received from the Websocket connection. the stop return value can be used to close the connection. the hibernate option will hibernate the process until it receives new data from the Websocket connection or an Erlang message

    the following snippet echoes back any text frame received and ignores all others:

    websocket_handle (Frame = {text, _}, Req, State) -> {reply, Frame, Req, State}; websocket_handle(_Frame, Req, State) -> {ok, Req, State}.

     

    websocket_info (Info, Req, State) ->
       {ok, Req, State}
     | {ok, Req, State, hibernate} 
     | {reply, OutFrame | [OutFrame], Req, State}
     | {reply, OutFrame | [OutFrame], Req, State, hibernate} 
     | {stop, Req, State}
    

    this function will be called every time an Erlang message has been received. the message can be any Erlang term. the stop return value can be used to close the connection. the hibernate option will hibernate the process until it receives another message or new data from the Websocket connection

    websocket handlers allow you to initialize the connection, handle incoming frames from the socket, handle incoming Erlang messages and then clean up on termination.

    Cowboy allows sending either a single frame or a list of frames to the socket, in which case the frames are sent sequentially. any frame can be sent: text, binary, ping, pong or close frames

    websocket_info(hello_world, Req, State) -> {reply, [ {text, "Hello"}, {text, <<"world!">>}, {binary, <<0:8000>>} ], Req, State}; %% More websocket_info/3 clauses here...

    note that the payload for text and binary frames is of type iodata(), meaning it can be either a binary() or an iolist()

    sending a close frame will immediately initiate the closing of the Websocket connection

    termination

    Cowboy will terminate the process right after closing the Websocket connection. this means that there is no real need to perform any cleanup in the optional terminate/3 callback

    the following values may be received as the terminate reason in the optional terminate/3 callback

    normal: the connection was closed normally before establishing a Websocket connection. this typically happens if an ok tuple is returned from the init/3 callback

    remote the remote endpoint closed the connection without giving any further details

    {remote, Code, Payload} the remote endpoint closed the connection with the given Code and Payload as the reason

    stop the handler requested to close the connection, either by returning a stop tuple or by sending a close frame

    timeout the connection has been closed due to inactivity. the timeout value can be configured from init/3

    {crash, Class, Reason} a crash occurred in the handler. Class and Reason can be used to obtain more information about the crash. the function erlang:get_stacktrace/0 can also be called to obtain the stacktrace of the process when the crash occurred.

    {error, badencoding} a text frame was sent by the client with invalid encoding. all text frames must be valid UTF-8

    {error, badframe} a protocol error has been detected

    {error, closed} the socket has been closed brutally without a close frame being received first

    {error, Reason} a socket error ocurred

    ping, timeout and hibernate

    Cowboy will automatically respond to ping frames sent by the client. it will still forward the frame to the handler for informative purpose, but no further action is required

    Cowboy can be configured to automatically close the Websocket connection when no data arrives on the socket. it is highly recommended to configure a timeout for it, as otherwise you may end up with zombie "half-connected" sockets that may leave the process alive forever. this value cannot be changed once it is set. it defaults to infinity

    most tuples returned from handler callbacks can include an extra value hibernate. after doing any necessary operations following the return of the callback, Cowboy will hibernate the process. it is highly recommended to hibernate processes that do not handle much traffic


    rest

    REST is implemented in Cowboy as a sub protocol. the request is handled as a state machine with many optional callbacks describing the resource and modifying the machine's behavior

    the REST handler is the recommended way to handle HTTP requests

    initialization

    first, the init/2 callback is called. to use REST for the current request, this function must return a cowboy_rest tuple:

    init (Req, _Opts) -> {cowboy_rest, Req, #state{}}
    

    Cowboy will then switch to the REST protocol and start executing the state machine

    after reaching the end of the flowchart, the terminate/3 callback will be called if it is defined

    methods

    the REST component has code for handling the following HTTP methods: HEAD, GET, POST, PATCH, PUT, DELETE and OPTIONS

    callbacks

    all callbacks are optional. all callbacks take two arguments, the Req object and the State, and return a three-element tuple of the form {Value, Req, State}

    all callbacks can also return {stop, Req, State} to stop execution of the request

    if the callback isn't defined, then the default value will be used

    in the following table, "skip" means the callback is entirely skipped if it is undefined, moving directly to the next step. Similarly, "none" means there is no default value for this callback

    Callback nameDefault value
    allowed_methods[<<"GET">>, <<"HEAD">>, <<"OPTIONS">>]
    allow_missing_posttrue
    charsets_providedskip
    content_types_acceptednone
    content_types_provided[{{<<"text">>, <<"html">>, '*'}, to_html}]
    delete_completedtrue
    delete_resourcefalse
    expiresundefined
    forbiddenfalse
    generate_etagundefined
    is_authorizedtrue
    is_conflictfalse
    known_methods[<<"GET">>, <<"HEAD">>, <<"POST">>, <<"PUT">>,
    <<"PATCH">>, <<"DELETE">>, <<"OPTIONS">>]
    languages_providedskip
    last_modifiedundefined
    malformed_requestfalse
    moved_permanentlyfalse
    moved_temporarilyfalse
    multiple_choicesfalse
    optionsok
    previously_existedfalse
    resource_existstrue
    service_availabletrue
    uri_too_longfalse
    valid_content_headerstrue
    valid_entity_lengthtrue
    variances[]

    Cowboy tries to move on with the request whenever possible by using well thought out default values

    in addition to these, there can be any number of user-defined callbacks that are specified through content_types_accepted/2 and content_types_provided/2. they can take any name, however it is recommended to use a separate prefix for the callbacks of each function

    Meta data

    Cowboy will set informative meta values at various points of the execution. you can retrieve them using cowboy_req:meta/2/3

    meta keydetails
    media_typethe content-type negotiated for the response entity.
    languagethe language negotiated for the response entity.
    charsetthe charset negotiated for the response entity.

    they can be used to send a proper body with the response to a request that used a method other than HEAD or GET

    Response headers

    Cowboy will set response headers automatically over the execution of the REST code

    header namedetails
    content-languagelanguage used in the response body
    content-typemedia type and charset of the response body
    etagEtag of the resource
    expiresexpiration date of the resource
    last-modifiedlast modification date for the resource
    locationrelative or absolute URI to the requested resource
    varylist of headers that may change the representation of the resource

    loop

    loop handlers are used for requests where a response might not be immediately available, but where you would like to keep the connection open for a while in case the response arrives. the most known example of such practice is known as long polling

    loop handlers can also be used for requests where a response is partially available and you need to stream the response body while the connection is open. the most known example of such practice is known as server-sent events

    while the same can be accomplished using plain HTTP handlers, it is recommended to use loop handlers because they are well-tested and allow using built-in features like hibernation and timeouts

    loop handlers essentially wait for one or more Erlang messages and feed these messages to the info/3 callback. it also features the init/2 and terminate/3 callbacks which work the same as for plain HTTP handlers

    -module (stream_handler). -compile (export_all). init (_Type, Req, _Opts) -> {ok, Req2} = cowboy_req:chunked_reply (200, [ {<<"content-type">>, <<"text/event-stream">>} , {<<"data">>, <<"start streaming">>} ], Req), timer:sleep(2000), self() ! {chunk, "data: abc\n\n"}, timer:sleep(2000), self() ! {chunk, "data: def\n\n"}, timer:sleep(2000), self() ! {chunk, "data: xyz\n\n"}, timer:sleep(2000), self() ! eof, {loop, Req2, [], 60000}. info ({chunk, D}, Req, State) -> ok = cowboy_req:chunk (D, Req), {loop, Req, State}; info (eof, Req, State) -> {ok, Req, State}; info (_Msg, Req, State) -> {loop, Req, State}. terminate (_Reason, _Req, _State) -> ok.

    initialization

    the init/3 function must return a cowboy_loop tuple to enable loop handler behavior. this tuple may optionally contain a timeout value and/or the atom hibernate to make the process enter hibernation until a message is received

    init(_Type, Req, _Opts) -> {loop, Req, State, Timeout}
    

    receive loop

    once initialized, Cowboy will wait for messages to arrive in the process' mailbox. when a message arrives, Cowboy calls the info/3 function with the message, the Req object and the handler's state

    the following snippet sends a reply when it receives a reply message from another process, or waits for another message otherwise:

    info ({reply, Body}, Req, State) -> Req2 = cowboy_req:reply (200, [], Body, Req), {stop, Req2, State}; info (_Msg, Req, State) -> {ok, Req, State, hibernate}.

    note that the `reply` tuple here may be any message and is simply an example

    this callback may perform any necessary operation including sending all or parts of a reply, and will subsequently return a tuple indicating if more messages are to be expected. the callback may also choose to do nothing at all and just skip the message received

    if a reply is sent, then the `stop` tuple should be returned. this will instruct Cowboy to end the request. otherwise an `ok` tuple should be returned

    streaming loop

    another common case well suited for loop handlers is streaming data received in the form of Erlang messages. this can be done by initiating a chunked reply in the init/2 callback and then using cowboy_req:chunk/2 every time a message is received

    the following snippet does exactly that. a chunk is sent every time a `chunk` message is received, and the loop is stopped by sending an `eof` message

    init (Req, _Opts) -> Req2 = cowboy_req:chunked_reply (200, [], Req), {cowboy_loop, Req2, #state{}}. info (eof, Req, State) -> {stop, Req, State}; info ({chunk, Chunk}, Req, State) -> cowboy_req:chunk (Chunk, Req), {ok, Req, State}; info (_Msg, Req, State) -> {ok, Req, State}.

    it is recommended that you set the connection header to `close` when replying, as this process may be reused for a subsequent request

    timeout and hibernate

    by default Cowboy will not attempt to close the connection if there is no activity from the client. this is not always desirable, which is why you can set a timeout. Cowboy will close the connection if no data was received from the client after the configured time. the timeout only needs to be set once and can't be modified afterwards

    because the request may have had a body, or may be followed by another request, Cowboy is forced to buffer all data it receives. this data may grow to become too large though, so there is a configurable limit for it. the default buffer size is of 5000 bytes, but it may be changed by setting the `loop_max_buffer` middleware environment value

    to save memory, you may hibernate the process in between messages received. this is done by returning the atom `hibernate` as part of the `loop` tuple callbacks normally return. just add the atom at the end and Cowboy will hibernate accordingly