From 7839f1367194813c70d7e223a476f96a62b298ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Wed, 24 Aug 2016 17:25:33 +0200 Subject: More 2.0 documentation updates Still incomplete. --- doc/src/guide/getting_started.asciidoc | 8 +- doc/src/guide/handlers.asciidoc | 47 ++-- doc/src/guide/introduction.asciidoc | 30 ++- doc/src/guide/loop_handlers.asciidoc | 12 +- doc/src/guide/req.asciidoc | 403 ++++++++++++++++++++++----------- doc/src/guide/rest_handlers.asciidoc | 4 +- doc/src/guide/routing.asciidoc | 10 +- doc/src/guide/sub_protocols.asciidoc | 10 +- doc/src/guide/ws_handlers.asciidoc | 22 +- 9 files changed, 351 insertions(+), 195 deletions(-) (limited to 'doc') diff --git a/doc/src/guide/getting_started.asciidoc b/doc/src/guide/getting_started.asciidoc index a4e5637..e9a2756 100644 --- a/doc/src/guide/getting_started.asciidoc +++ b/doc/src/guide/getting_started.asciidoc @@ -106,7 +106,7 @@ chapter. For this tutorial we map the path `/` to the handler module `hello_handler`. This module doesn't exist yet. Build and start the release, then open http://localhost:8080 -in your browser. You will get an error because the module is missing. +in your browser. You will get a 500 error because the module is missing. Any other URL, like http://localhost:8080/test, will result in a 404 error. @@ -126,11 +126,11 @@ the `init/2` function like this to send a reply. [source,erlang] ---- -init(Req, State) -> - cowboy_req:reply(200, +init(Req0, State) -> + Req = cowboy_req:reply(200, #{<<"content-type">> => <<"text/plain">>}, <<"Hello Erlang!">>, - Req), + Req0), {ok, Req, State}. ---- diff --git a/doc/src/guide/handlers.asciidoc b/doc/src/guide/handlers.asciidoc index 83ae2ff..a59b8cf 100644 --- a/doc/src/guide/handlers.asciidoc +++ b/doc/src/guide/handlers.asciidoc @@ -9,40 +9,42 @@ The most basic handler in Cowboy implements the mandatory `init/2` callback, manipulates the request, optionally sends a response and then returns. -This callback receives the xref:req[Req object] and the options -defined during the xref:routing[router configuration]. +This callback receives the xref:req[Req object] and the initial +state defined in the xref:routing[router configuration]. A handler that does nothing would look like this: [source,erlang] ---- -init(Req, _Opts) -> - {ok, Req, #state{}}. +init(Req, State) -> + {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 +Despite sending no reply, a `204 No Content` response will be +sent to the client, as Cowboy makes sure that a response is sent for every request. -We need to use the Req object for sending a reply. +We need to use the Req object to reply. [source,erlang] ---- -init(Req, State) -> - cowboy_req:reply(200, [ +init(Req0, State) -> + Req = cowboy_req:reply(200, [ {<<"content-type">>, <<"text/plain">>} - ], <<"Hello World!">>, Req), + ], <<"Hello World!">>, Req0), {ok, Req, State}. ---- -As you can see we return a 3-tuple. `ok` means that the -handler ran successfully. Note that Cowboy will immediately -send a response when `cowboy:reply/4` is called. +Cowboy will immediately send a response when `cowboy:reply/4` +is called. + +We then return a 3-tuple. `ok` means that the handler ran +successfully. We also give the modified Req back to Cowboy. The last value of the tuple is a state that will be used in every subsequent callbacks to this handler. Plain HTTP handlers only have one additional callback, the optional -`terminate/3`. +and rarely used `terminate/3`. === Other handlers @@ -62,16 +64,16 @@ following snippet switches to a Websocket handler: [source,erlang] ---- -init(Req, _Opts) -> - {cowboy_websocket, Req, #state{}}. +init(Req, State) -> + {cowboy_websocket, Req, State}. ---- You can also switch to your own custom handler type: [source,erlang] ---- -init(Req, _Opts) -> - {my_handler_type, Req, #state{}}. +init(Req, State) -> + {my_handler_type, Req, State}. ---- How to implement a custom handler type is described in the @@ -79,12 +81,12 @@ xref:sub_protocols[Sub protocols] chapter. === Cleaning up -All handlers coming with Cowboy allow the use of the optional -`terminate/3` callback. +With the exception of Websocket handlers, all handler types +provide the optional `terminate/3` callback. [source,erlang] ---- -terminate(_Reason, Req, State) -> +terminate(_Reason, _Req, _State) -> ok. ---- @@ -96,4 +98,5 @@ This callback is optional because it is rarely necessary. Cleanup should be done in separate processes directly (by monitoring the handler process to detect when it exits). -Cowboy does not reuse processes for different requests. +Cowboy does not reuse processes for different requests. The +process will terminate soon after this call returns. diff --git a/doc/src/guide/introduction.asciidoc b/doc/src/guide/introduction.asciidoc index 0179c16..d262b5c 100644 --- a/doc/src/guide/introduction.asciidoc +++ b/doc/src/guide/introduction.asciidoc @@ -35,7 +35,27 @@ guarantee that the experience will be safe and smooth. You are advised to perform the necessary testing and security audits prior to deploying on other platforms. -Cowboy is developed for Erlang/OTP 18.0 and newer. +Cowboy is developed for Erlang/OTP 19.0 and newer. + +=== License + +Cowboy uses the ISC License. + +---- +Copyright (c) 2011-2016, Loïc Hoguin + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +---- === Versioning @@ -46,8 +66,10 @@ Cowboy uses http://semver.org/[Semantic Versioning 2.0.0]. In the HTTP protocol, the method name is case sensitive. All standard method names are uppercase. -Header names are case insensitive. Cowboy converts all the request -header names to lowercase, and expects your application to provide -lowercase header names in the response. +Header names are case insensitive. When using HTTP/1.1, Cowboy converts +all the request header names to lowercase. HTTP/2 requires clients to +send them as lowercase. Any other header name is expected to be provided +lowercased, including when querying information about the request or +when sending responses. The same applies to any other case insensitive value. diff --git a/doc/src/guide/loop_handlers.asciidoc b/doc/src/guide/loop_handlers.asciidoc index d3655e5..c0195ea 100644 --- a/doc/src/guide/loop_handlers.asciidoc +++ b/doc/src/guide/loop_handlers.asciidoc @@ -38,8 +38,8 @@ This snippet enables the loop handler. [source,erlang] ---- -init(Req, _Opts) -> - {cowboy_loop, Req, #state{}}. +init(Req, State) -> + {cowboy_loop, Req, State}. ---- However it is largely recommended that you set a timeout @@ -48,8 +48,8 @@ also makes the process hibernate. [source,erlang] ---- -init(Req, _Opts) -> - {cowboy_loop, Req, #state{}, 30000, hibernate}. +init(Req, State) -> + {cowboy_loop, Req, State, 30000, hibernate}. ---- === Receive loop @@ -101,9 +101,9 @@ and the loop is stopped by sending an `eof` message. [source,erlang] ---- -init(Req, _Opts) -> +init(Req, State) -> Req2 = cowboy_req:chunked_reply(200, [], Req), - {cowboy_loop, Req2, #state{}}. + {cowboy_loop, Req2, State}. info(eof, Req, State) -> {stop, Req, State}; diff --git a/doc/src/guide/req.asciidoc b/doc/src/guide/req.asciidoc index 09d442a..39fcde6 100644 --- a/doc/src/guide/req.asciidoc +++ b/doc/src/guide/req.asciidoc @@ -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. diff --git a/doc/src/guide/rest_handlers.asciidoc b/doc/src/guide/rest_handlers.asciidoc index 6bff18d..f28c066 100644 --- a/doc/src/guide/rest_handlers.asciidoc +++ b/doc/src/guide/rest_handlers.asciidoc @@ -15,8 +15,8 @@ must return a `cowboy_rest` tuple. [source,erlang] ---- -init(Req, _Opts) -> - {cowboy_rest, Req, #state{}}. +init(Req, State) -> + {cowboy_rest, Req, State}. ---- Cowboy will then switch to the REST protocol and start executing diff --git a/doc/src/guide/routing.asciidoc b/doc/src/guide/routing.asciidoc index 150c634..864a19a 100644 --- a/doc/src/guide/routing.asciidoc +++ b/doc/src/guide/routing.asciidoc @@ -37,11 +37,11 @@ PathsList = [Path1, Path2, ... PathN]. Finally, each path contains matching rules for the path along with optional constraints, and gives us the handler module to be used -along with options that will be given to it on initialization. +along with its initial state. [source,erlang] -Path1 = {PathMatch, Handler, Opts}. -Path2 = {PathMatch, Constraints, Handler, Opts}. +Path1 = {PathMatch, Handler, InitialState}. +Path2 = {PathMatch, Constraints, Handler, InitialState}. Continue reading to learn more about the match syntax and the optional constraints. @@ -199,8 +199,8 @@ This can be done with a simple call to `cowboy_router:compile/1`. [source,erlang] ---- Dispatch = cowboy_router:compile([ - %% {HostMatch, list({PathMatch, Handler, Opts})} - {'_', [{'_', my_handler, []}]} + %% {HostMatch, list({PathMatch, Handler, InitialState})} + {'_', [{'_', my_handler, #{}}]} ]), %% Name, NbAcceptors, TransOpts, ProtoOpts cowboy:start_clear(my_http_listener, 100, diff --git a/doc/src/guide/sub_protocols.asciidoc b/doc/src/guide/sub_protocols.asciidoc index 63fd52b..5332eec 100644 --- a/doc/src/guide/sub_protocols.asciidoc +++ b/doc/src/guide/sub_protocols.asciidoc @@ -16,8 +16,8 @@ is handled by the sub protocol. [source,erlang] ---- -init(Req, _Opts) -> - {cowboy_websocket, Req, #state{}}. +init(Req, State) -> + {cowboy_websocket, Req, State}. ---- The return value may also have a `Timeout` value and/or the @@ -29,10 +29,12 @@ The following snippet switches to the `my_protocol` sub protocol, sets the timeout value to 5 seconds and enables hibernation: +// @todo Yeah maybe what we really need is an Opts map. + [source,erlang] ---- -init(Req, _Opts) -> - {my_protocol, Req, #state{}, 5000, hibernate}. +init(Req, State) -> + {my_protocol, Req, State, 5000, hibernate}. ---- If a sub protocol does not make use of these options, it should diff --git a/doc/src/guide/ws_handlers.asciidoc b/doc/src/guide/ws_handlers.asciidoc index 9ddddf4..b280fd8 100644 --- a/doc/src/guide/ws_handlers.asciidoc +++ b/doc/src/guide/ws_handlers.asciidoc @@ -18,8 +18,8 @@ must return a `ws` tuple. [source,erlang] ---- -init(Req, _Opts) -> - {cowboy_websocket, Req, #state{}}. +init(Req, State) -> + {cowboy_websocket, Req, State}. ---- Upon receiving this tuple, Cowboy will switch to the code @@ -34,18 +34,18 @@ the connection, assuming no correct subprotocol was found. [source,erlang] ---- -init(Req, _Opts) -> +init(Req, State) -> case cowboy_req:parse_header(<<"sec-websocket-protocol">>, Req) of undefined -> - {ok, Req, #state{}}; + {ok, Req, State}; Subprotocols -> case lists:keymember(<<"mychat2">>, 1, Subprotocols) of true -> Req2 = cowboy_req:set_resp_header(<<"sec-websocket-protocol">>, <<"mychat2">>, Req), - {ok, Req2, #state{}}; + {ok, Req2, State}; false -> - {stop, Req, undefined} + {stop, Req, State} end end. ---- @@ -60,12 +60,14 @@ It is also very easy to ensure that this message arrives before any message from other processes by sending it before registering or enabling timers. +// @todo This doesn't even work. + [source,erlang] ---- -init(Req, _Opts) -> +init(Req, State) -> self() ! post_init, %% Register process here... - {cowboy_websocket, Req, #state{}}. + {cowboy_websocket, Req, State}. websocket_info(post_init, Req, State) -> %% Perform post_init initialization here... @@ -169,8 +171,8 @@ A good timeout value is 60 seconds. [source,erlang] ---- -init(Req, _Opts) -> - {cowboy_websocket, Req, #state{}, 60000}. +init(Req, State) -> + {cowboy_websocket, Req, State, 60000}. ---- This value cannot be changed once it is set. It defaults to -- cgit v1.2.3