diff options
Diffstat (limited to 'doc/src')
24 files changed, 604 insertions, 629 deletions
diff --git a/doc/src/guide/erlang_beginners.ezdoc b/doc/src/guide/erlang_beginners.ezdoc index f62543f..74d3470 100644 --- a/doc/src/guide/erlang_beginners.ezdoc +++ b/doc/src/guide/erlang_beginners.ezdoc @@ -33,8 +33,3 @@ Instead of going into every single details of the language, Joe focuses on the central concepts behind Erlang, and shows you how they can be used to write a variety of different applications. - -At the time of writing, the 2nd edition of the book is in beta, -and includes a few details about upcoming Erlang features that -cannot be used today. Choose the edition you want, then get -reading! diff --git a/doc/src/guide/getting_started.ezdoc b/doc/src/guide/getting_started.ezdoc index 34f02dc..a959b45 100644 --- a/doc/src/guide/getting_started.ezdoc +++ b/doc/src/guide/getting_started.ezdoc @@ -150,15 +150,15 @@ $ make new t=cowboy_http n=hello_handler ``` You can then open the `src/hello_handler.erl` file and modify -the `handle/2` function like this to send a reply. +the `init/2` function like this to send a reply. ``` erlang -handle(Req, State=#state{}) -> +init(Req, Opts) -> Req2 = cowboy_req:reply(200, [{<<"content-type">>, <<"text/plain">>}], <<"Hello Erlang!">>, Req), - {ok, Req2, State}. + {ok, Req2, Opts}. ``` What the above code does is send a `200 OK` reply, with the diff --git a/doc/src/guide/handlers.ezdoc b/doc/src/guide/handlers.ezdoc new file mode 100644 index 0000000..c0fb97e --- /dev/null +++ b/doc/src/guide/handlers.ezdoc @@ -0,0 +1,99 @@ +::: Handlers + +Handlers are Erlang modules that handle HTTP requests. + +:: Plain HTTP handlers + +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 ^"Req object^req and the options +defined during the ^"router configuration^routing^. + +A handler that does nothing would look like this: + +``` erlang +init(Req, Opts) -> + {ok, Req, Opts}. +``` + +Despite sending no reply, a `204 No Content` reply will be +sent to the client, as Cowboy makes sure that a reply is +sent for every request. + +We need to use the Req object for sending a reply. + +``` erlang +init(Req, Opts) -> + Req2 = cowboy_req:reply(200, [ + {<<"content-type">>, <<"text/plain">>} + ], <<"Hello World!">>, Req), + {ok, Req2, Opts}. +``` + +As you can see we return a 3-tuple. `ok` means that the +handler ran successfully. The Req object is returned as +it may have been modified as is the case here: replying +returns a modified Req object that you need to return +back to Cowboy for proper operations. + +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`. + +:: Other handlers + +The `init/2` callback can also be used to inform Cowboy +that this is a different kind of handler and that Cowboy +should switch to it. To do this you simply need to return +the module name of the handler type you want to switch to. + +Cowboy comes with three handler types you can switch to: +^"cowboy_rest^rest_handlers^, ^"cowboy_websocket^ws_handlers^ +and ^"cowboy_loop^loop_handlers^. In addition to those you +can define your own handler types. + +Switching is simple. Instead of returning `ok`, you simply +return the name of the handler type you want to use. The +following snippet switches to a Websocket handler: + +``` erlang +init(Req, Opts) -> + {cowboy_websocket, Req, Opts}. +``` + +You can also switch to your own custom handler type: + +``` erlang +init(Req, Opts) -> + {my_handler_type, Req, Opts}. +``` + +How to implement a custom handler type is described in the +^"Sub protocols^sub_protocols chapter. + +:: Cleaning up + +All handlers coming with Cowboy allow the use of the optional +`terminate/3` callback. + +``` erlang +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. + +If you used the process dictionary, timers, monitors or may +be receiving messages, then you can use this function to clean +them up, as Cowboy might reuse the process for the next +keep-alive request. + +Note that while this function may be called in a Websocket +handler, it is generally not useful to do any clean up as +the process terminates immediately after calling this callback +when using Websocket. diff --git a/doc/src/guide/http_handlers.ezdoc b/doc/src/guide/http_handlers.ezdoc deleted file mode 100644 index d846ffe..0000000 --- a/doc/src/guide/http_handlers.ezdoc +++ /dev/null @@ -1,132 +0,0 @@ -::: Handling plain HTTP requests - -The simplest way to handle a request is by writing a -plain HTTP handler. It is modeled after Erlang/OTP's -gen_server behaviour, although simplified, as Cowboy -will simply call the three callbacks sequentially. - -:: Initialization - -The first callback, `init/2`, is common to all handlers, -as it is used to identify the type of handler. Plain -HTTP handlers just return `http`. - -``` erlang -init(Req, Opts) -> - {http, Req, Opts}. -``` - -This function receives the options associated with -this route that you configured previously. - -You do not need to validate the options unless they -are user configured. If they are, and there's a -configuration error, you may choose to crash. For -example, this will crash if the required `lang` -option is not found. - -``` erlang -init(Req, Opts) -> - {_, Lang} = lists:keyfind(lang, 1, Opts), - {http, Req, Lang}. -``` - -If your users are unlikely to figure out the issue -without explanations, then you should send a more -meaningful error back to the user. Since we already -replied to the user, there's no need for us to -continue with the handler code, so we use the -`shutdown` return value to stop early. - -``` erlang -init(Req, Opts) -> - case lists:keyfind(lang, 1, Opts) of - false -> - Req2 = cowboy_req:reply(500, [ - {<<"content-type">>, <<"text/plain">>} - ], "Missing option 'lang'.", Req), - {shutdown, Req2, undefined}; - {_, Lang} -> - {http, Req, Lang} - end. -``` - -Once the options have been validated, we can use them -safely. So we need to pass them onward to the rest of -the handler. That's what the third element of the return -tuple, the state, is for. - -You may use a state record for this. The record will make -your handler code clearer and will allow Dialyzer to better -type check your code. - -``` erlang --record(state, { - lang :: en | fr - %% More fields here. -}). - -init(Req, Opts) -> - {_, Lang} = lists:keyfind(lang, 1, Opts), - {http, Req, #state{lang=Lang}}. -``` - -You may also use a map. A map is interesting in that you -do not need to define it beforehand, but is a little less -efficient and not as well supported by Dialyzer. - -``` erlang -init(Req, Opts) -> - {_, Lang} = lists:keyfind(lang, 1, Opts), - {http, Req, #{lang => Lang}. -``` - -:: Handling the request - -The second callback, `handle/2`, is specific to plain HTTP -handlers. It's where you handle the request. - -A handle function that does nothing would look like this: - -``` erlang -handle(Req, State) -> - {ok, Req, State}. -``` - -There's no other return value. To obtain information about -the request, or send a response, you would use the Req object -here. The Req object is documented in its own chapter. - -The following handle function will send a fairly original response. - -``` erlang -handle(Req, State) -> - Req2 = cowboy_req:reply(200, [ - {<<"content-type">>, <<"text/plain">>} - ], <<"Hello World!">>, Req), - {ok, Req2, State}. -``` - -:: Cleaning up - -The third and last callback, `terminate/3`, is optional. - -``` erlang -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. - -If you used the process dictionary, timers, monitors or may -be receiving messages, then you can use this function to clean -them up, as Cowboy might reuse the process for the next -keep-alive request. - -The chances of any of this happening in your handler are pretty -thin however. The use of the process dictionary is discouraged -in Erlang code in general. And if you need to use timers, monitors -or to receive messages, you are better off with a loop handler, -a different kind of handler meant specifically for this use. diff --git a/doc/src/guide/index.ezdoc b/doc/src/guide/index.ezdoc index 300cea8..dbe75ff 100644 --- a/doc/src/guide/index.ezdoc +++ b/doc/src/guide/index.ezdoc @@ -1,35 +1,34 @@ ::: Cowboy User Guide The Cowboy User Guide explores the modern Web and how to make -best use of Cowboy for writing powerful web applications. +best use of Cowboy for writing powerful Web applications. -:: Introducing Cowboy +:: Rationale -* ^"Introduction^introduction * ^"The modern Web^modern_web * ^"Erlang and the Web^erlang_web -* ^"Erlang for beginners^erlang_beginners + +:: Introduction + +* ^"Introduction^introduction * ^"Getting started^getting_started +* ^"Request overview^overview +* ^"Erlang for beginners^erlang_beginners -:: HTTP +:: Configuration -* ^"The life of a request^http_req_life * ^"Routing^routing * ^"Constraints^constraints -* ^"Handling plain HTTP requests^http_handlers +* ^"Static files^static_files + +:: Request and response + +* ^"Handlers^handlers * ^"The Req object^req * ^"Reading the request body^req_body * ^"Sending a response^resp * ^"Using cookies^cookies - -:: Multipart - -* ^"Introduction to multipart^multipart_intro -* ^"Multipart requests^multipart_req - -:: Static files - -* ^"Static handler^static_handlers +* ^"Multipart^multipart :: REST @@ -43,14 +42,14 @@ best use of Cowboy for writing powerful web applications. * ^"The Websocket protocol^ws_protocol * ^"Handling Websocket connections^ws_handlers -:: Server push +:: Push technology * ^"Loop handlers^loop_handlers -:: Pluggable interface +:: Extensions * ^"Middlewares^middlewares -* ^"Protocol upgrades^upgrade_protocol +* ^"Sub protocols^sub_protocols * ^"Hooks^hooks :: Internals diff --git a/doc/src/guide/introduction.ezdoc b/doc/src/guide/introduction.ezdoc index 18345df..e1d2e60 100644 --- a/doc/src/guide/introduction.ezdoc +++ b/doc/src/guide/introduction.ezdoc @@ -16,9 +16,7 @@ features both a Function Reference and a User Guide. :: Prerequisites -No Erlang knowledge is required for reading this guide. The reader will -be introduced to Erlang concepts and redirected to reference material -whenever necessary. +Beginner Erlang knowledge is recommended for reading this guide. Knowledge of the HTTP protocol is recommended but not required, as it will be detailed throughout the guide. @@ -32,12 +30,15 @@ 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 R16B01, R16B02, R16B03-1, 17.0 and -17.1.2. +Cowboy is developed for Erlang/OTP 17.0, 17.1.2 and 17.3. By the time +this branch gets released the target version will probably be 18.0 and +above. Cowboy may be compiled on other Erlang versions with small source code modifications but there is no guarantee that it will work as expected. +Cowboy uses the maps data type which was introduced in Erlang 17.0. + :: Versioning Cowboy uses ^"Semantic Versioning 2.0.0^http://semver.org/^. diff --git a/doc/src/guide/loop_handlers.ezdoc b/doc/src/guide/loop_handlers.ezdoc index 445854c..8da2805 100644 --- a/doc/src/guide/loop_handlers.ezdoc +++ b/doc/src/guide/loop_handlers.ezdoc @@ -8,7 +8,7 @@ a response. 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. +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 @@ -21,12 +21,12 @@ 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/3` and `terminate/3` callbacks which work the same as +the `init/2` and `terminate/3` callbacks which work the same as for plain HTTP handlers. :: Initialization -The `init/3` function must return a `loop` tuple to enable +The `init/2` 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. @@ -35,7 +35,7 @@ This snippet enables the loop handler. ``` erlang init(Req, Opts) -> - {long_polling, Req, Opts}. + {cowboy_loop, Req, Opts}. ``` However it is largely recommended that you set a timeout @@ -44,7 +44,7 @@ also makes the process hibernate. ``` erlang init(Req, Opts) -> - {long_polling, Req, Opts, 30000, hibernate}. + {cowboy_loop, Req, Opts, 30000, hibernate}. ``` :: Receive loop @@ -61,9 +61,9 @@ message otherwise. ``` erlang info({reply, Body}, Req, State) -> Req2 = cowboy_req:reply(200, [], Body, Req), - {ok, Req2, State}; + {shutdown, Req2, State}; info(_Msg, Req, State) -> - {loop, Req, State, hibernate}. + {ok, Req, State, hibernate}. ``` Do note that the `reply` tuple here may be any message @@ -76,17 +76,17 @@ 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 `ok` tuple should be returned. +If a reply is sent, then the `shutdown` tuple should be returned. This will instruct Cowboy to end the request. -Otherwise a `loop` tuple should be returned. +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/3` callback and then using `cowboy_req:chunk/2` +`init/2` callback and then using `cowboy_req:chunk/2` every time a message is received. The following snippet does exactly that. As you can see @@ -96,15 +96,15 @@ and the loop is stopped by sending an `eof` message. ``` erlang init(Req, Opts) -> Req2 = cowboy_req:chunked_reply(200, [], Req), - {long_polling, Req2, Opts}. + {cowboy_loop, Req2, Opts}. info(eof, Req, State) -> - {ok, Req, State}; + {shutdown, Req, State}; info({chunk, Chunk}, Req, State) -> cowboy_req:chunk(Chunk, Req), - {loop, Req, State}; + {ok, Req, State}; info(_Msg, Req, State) -> - {loop, Req, State}. + {ok, Req, State}. ``` :: Cleaning up diff --git a/doc/src/guide/multipart_req.ezdoc b/doc/src/guide/multipart.ezdoc index 21762f6..d0b2e40 100644 --- a/doc/src/guide/multipart_req.ezdoc +++ b/doc/src/guide/multipart.ezdoc @@ -1,11 +1,60 @@ ::: Multipart requests +Multipart originates from MIME, an Internet standard that +extends the format of emails. Multipart messages are a +container for parts of any content-type. + +For example, a multipart message may have a part +containing text and a second part containing an +image. This is what allows you to attach files +to emails. + +In the context of HTTP, multipart is most often used +with the `multipart/form-data` content-type. This is +the content-type you have to use when you want browsers +to be allowed to upload files through HTML forms. + +Multipart is of course not required for uploading +files, it is only required when you want to do so +through HTML forms. + You can read and parse multipart messages using the Req object directly. Cowboy defines two functions that allows you to get information about each part and read their contents. +:: Structure + +A multipart message is a list of parts. Parts may +contain either a multipart message or a non-multipart +content-type. This allows parts to be arranged in a +tree structure, although this is a rare case as far +as the Web is concerned. + +:: Form-data + +In the normal case, when a form is submitted, the +browser will use the `application/x-www-form-urlencoded` +content-type. This type is just a list of keys and +values and is therefore not fit for uploading files. + +That's where the `multipart/form-data` content-type +comes in. When the form is configured to use this +content-type, the browser will use one part of the +message for each form field. This means that a file +input field will be sent in its own part, but the +same applies to all other kinds of fields. + +A form with a text input, a file input and a select +choice box will result in a multipart message with +three parts, one for each field. + +The browser does its best to determine the content-type +of the files it sends this way, but you should not +rely on it for determining the contents of the file. +Proper investigation of the contents is recommended. + :: Checking the content-type While there is a variety of multipart messages, the diff --git a/doc/src/guide/multipart_intro.ezdoc b/doc/src/guide/multipart_intro.ezdoc deleted file mode 100644 index b9a7fa9..0000000 --- a/doc/src/guide/multipart_intro.ezdoc +++ /dev/null @@ -1,50 +0,0 @@ -::: Introduction to multipart - -Multipart originates from MIME, an Internet standard that -extends the format of emails. Multipart messages are a -container for parts of any content-type. - -For example, a multipart message may have a part -containing text and a second part containing an -image. This is what allows you to attach files -to emails. - -In the context of HTTP, multipart is most often used -with the `multipart/form-data` content-type. This is -the content-type you have to use when you want browsers -to be allowed to upload files through HTML forms. - -Multipart is of course not required for uploading -files, it is only required when you want to do so -through HTML forms. - -:: Structure - -A multipart message is a list of parts. Parts may -contain either a multipart message or a non-multipart -content-type. This allows parts to be arranged in a -tree structure, although this is a rare case as far -as the Web is concerned. - -:: Form-data - -In the normal case, when a form is submitted, the -browser will use the `application/x-www-form-urlencoded` -content-type. This type is just a list of keys and -values and is therefore not fit for uploading files. - -That's where the `multipart/form-data` content-type -comes in. When the form is configured to use this -content-type, the browser will use one part of the -message for each form field. This means that a file -input field will be sent in its own part, but the -same applies to all other kinds of fields. - -A form with a text input, a file input and a select -choice box will result in a multipart message with -three parts, one for each field. - -The browser does its best to determine the content-type -of the files it sends this way, but you should not -rely on it for determining the contents of the file. -Proper investigation of the contents is recommended. diff --git a/doc/src/guide/http_req_life.ezdoc b/doc/src/guide/overview.ezdoc index ffe5dfa..725ae4e 100644 --- a/doc/src/guide/http_req_life.ezdoc +++ b/doc/src/guide/overview.ezdoc @@ -1,4 +1,4 @@ -::: The life of a request +::: Request overview This chapter explains the different steps a request goes through until a response is sent, along with diff --git a/doc/src/guide/rest_handlers.ezdoc b/doc/src/guide/rest_handlers.ezdoc index 294392a..8cdd12e 100644 --- a/doc/src/guide/rest_handlers.ezdoc +++ b/doc/src/guide/rest_handlers.ezdoc @@ -1,20 +1,20 @@ ::: REST handlers -REST is implemented in Cowboy as a protocol upgrade. Once upgraded, -the request is handled as a state machine with many optional callbacks +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 requests. +The REST handler is the recommended way to handle HTTP requests. :: Initialization First, the `init/2` callback is called. This callback is common to all handlers. To use REST for the current request, this function -must return a `rest` tuple. +must return a `cowboy_rest` tuple. ``` erlang init(Req, Opts) -> - {rest, Req, Opts}. + {cowboy_rest, Req, Opts}. ``` Cowboy will then switch to the REST protocol and start executing diff --git a/doc/src/guide/static_handlers.ezdoc b/doc/src/guide/static_files.ezdoc index f5eaac3..5a289d0 100644 --- a/doc/src/guide/static_handlers.ezdoc +++ b/doc/src/guide/static_files.ezdoc @@ -1,8 +1,9 @@ -::: Static handler +::: Static files -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. +Cowboy comes with a special handler built as a REST handler +and designed specifically for serving static files. It is +provided as a convenience and provides a quick solution for +serving files during development. For systems in production, consider using one of the many Content Distribution Network (CDN) available on the market, diff --git a/doc/src/guide/sub_protocols.ezdoc b/doc/src/guide/sub_protocols.ezdoc new file mode 100644 index 0000000..d34f21e --- /dev/null +++ b/doc/src/guide/sub_protocols.ezdoc @@ -0,0 +1,64 @@ +::: Sub protocols + +Sub protocols are used for creating new types of handlers that +provide extra functionality in a reusable way. Cowboy uses this +mechanism to provide its loop, REST and Websocket handlers. + +This chapter will explain how to create your own sub protocols +and handler types. + +:: Usage + +To switch to a sub protocol, the `init/2` callback must return +the name of the sub protocol module. Everything past this point +is handled by the sub protocol. + +``` erlang +init(Req, Opts) -> + {cowboy_websocket, Req, Opts}. +``` + +The return value may also have a `Timeout` value and/or the +atom `hibernate`. These options are useful for long living +connections. When they are not provided, the timeout value +defaults to `infinity` and the hibernate value to `run`. + +The following snippet switches to the `my_protocol` sub +protocol, sets the timeout value to 5 seconds and enables +hibernation: + +``` erlang +init(Req, Opts) -> + {my_protocol, Req, Opts, 5000, hibernate}. +``` + +If a sub protocol does not make use of these options, it should +crash if it receives anything other than the default values. + +:: Upgrade + +After the `init/2` function returns, Cowboy will then call the +`upgrade/6` function. This is the only callback defined by the +`cowboy_sub_protocol` behavior. + +The function is named `upgrade` because it mimics the mechanism +of HTTP protocol upgrades. For some sub protocols, like Websocket, +an actual upgrade is performed. For others, like REST, this is +only an upgrade at Cowboy's level and the client has nothing to +do about it. + +The upgrade callback receives the Req object, the middleware +environment, the handler and its options, and the aforementioned +timeout and hibernate values. + +``` erlang +upgrade(Req, Env, Handler, HandlerOpts, Timeout, Hibernate) -> + %% Sub protocol code here. +``` + +This callback is expected to behave like a middleware and to +return an updated environment and Req object. + +Sub protocols are expected to call the `cowboy_handler:terminate/4` +function when they terminate. This function will make sure that +the optional `terminate/3` callback is called, if present. diff --git a/doc/src/guide/upgrade_protocol.ezdoc b/doc/src/guide/upgrade_protocol.ezdoc deleted file mode 100644 index ad2d25a..0000000 --- a/doc/src/guide/upgrade_protocol.ezdoc +++ /dev/null @@ -1,61 +0,0 @@ -::: Protocol upgrades - -Cowboy features many different handlers, each for different purposes. -All handlers have a common entry point: the `init/2` function. -This function returns the name of the protocol that will be -used for processing the request, along with various options. - -Cowboy defines four built-in handler types. Three of them are -implemented as sub protocols. More can be implemented by -writing a custom sub protocol. - -The following table lists the built-in handler types. - -|| Alias Module Description -| -| http - Plain HTTP handler -| long_polling cowboy_long_polling Long-polling handler -| rest cowboy_rest REST handler -| ws cowboy_websocket Websocket handler - -Both the alias or the module name can be used to specify the -kind of handler. In addition, a user-defined module name can -be used. - -``` erlang -init(Req, Opts) -> - {my_protocol, Req, Opts}. -``` - -The `init/2` function can also return some extra options for -handlers that are meant to be long running, for example the -`long_polling` and `ws` handler types. These options can also -be passed on to custom sub protocols. For example the following -`init/2` function defines both a timeout value and enables -process hibernation: - -``` erlang -init(Req, Opts) -> - {my_protocol, Req, Opts, 5000, hibernate}. -``` - -It is up to the sub protocol to implement these (or reject -them if they are not supported). - -The `cowboy_sub_protocol` behavior only requires one callback, -`upgrade/6`. It receives the Req object, the middleware environment, -the handler and options for this request, and the timeout and -hibernate values. The default timeout value is `infinity` and -the default hibernate value is `run`. - -``` erlang -upgrade(Req, Env, Handler, HandlerOpts, Timeout, Hibernate) -> - %% ... -``` - -This callback is expected to behave like a middleware. Please -see the corresponding chapter for more information. - -Sub protocols are expected to call the `cowboy_handler:terminate/5` -function when they terminate. This function will make sure that -the optional `terminate/3` callback will be called, if present. diff --git a/doc/src/guide/ws_handlers.ezdoc b/doc/src/guide/ws_handlers.ezdoc index 893624b..cb30511 100644 --- a/doc/src/guide/ws_handlers.ezdoc +++ b/doc/src/guide/ws_handlers.ezdoc @@ -17,7 +17,7 @@ must return a `ws` tuple. ``` erlang init(Req, Opts) -> - {ws, Req, Opts}. + {cowboy_websocket, Req, Opts}. ``` Upon receiving this tuple, Cowboy will switch to the code @@ -61,7 +61,7 @@ or enabling timers. init(Req, _Opts) -> self() ! post_init, %% Register process here... - {ws, Req, #state{}}. + {cowboy_websocket, Req, #state{}}. websocket_info(post_init, Req, State) -> %% Perform post_init initialization here... @@ -161,7 +161,7 @@ A good timeout value is 60 seconds. ``` erlang init(Req, _Opts) -> - {ws, Req, #state{}, 60000}. + {cowboy_websocket, Req, #state{}, 60000}. ``` This value cannot be changed once it is set. It defaults to diff --git a/doc/src/guide/ws_protocol.ezdoc b/doc/src/guide/ws_protocol.ezdoc index 15aea2c..d283ae3 100644 --- a/doc/src/guide/ws_protocol.ezdoc +++ b/doc/src/guide/ws_protocol.ezdoc @@ -25,7 +25,7 @@ excluding the initial flawed draft sometimes known as :: Implementation Cowboy implements Websocket as a protocol upgrade. Once the -upgrade is performed from the `init/3` callback, Cowboy +upgrade is performed from the `init/2` callback, Cowboy switches to Websocket. Please consult the next chapter for more information on initiating and handling Websocket connections. diff --git a/doc/src/manual/cowboy_handler.ezdoc b/doc/src/manual/cowboy_handler.ezdoc index 0495f28..b440b60 100644 --- a/doc/src/manual/cowboy_handler.ezdoc +++ b/doc/src/manual/cowboy_handler.ezdoc @@ -15,10 +15,96 @@ Environment output: * result = ok +This module also defines the `cowboy_handler` behaviour that +defines the basic interface for handlers. All Cowboy handlers +implement at least the `init/2` callback, and may implement +the `terminate/3` callback optionally. + :: Types None. +:: Terminate reasons + +The following values may be received as the terminate reason +in the optional `terminate/3` callback. Different handler types +may define additional terminate reasons. + +: normal + +The connection was closed normally. + +: {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. + +:: Callbacks + +: init(Req, Opts) + -> {ok, Req, State} + | {Module, Req, State} + | {Module, Req, State, hibernate} + | {Module, Req, State, Timeout} + | {Module, Req, State, Timeout, hibernate} + +Types: + +* Req = cowboy_req:req() +* Opts = any() +* State = any() +* Module = module() +* Timeout = timeout() + +Process the request. + +This function can be used to switch to an alternate handler +type by returning the name of the module to be used, along +with a few options. + +For basic handlers this is the function where the response +should be sent. If no response is sent, Cowboy will ensure +that a `204 No Content` response is sent. + +A crash in this callback will result in `terminate/3` being +called if it is defined, with the `State` argument set to +the value of `Opts` originally given to the `init/2` callback. + +: terminate(Reason, Req, State) -> ok + +Types: + +* Reason = any() +* Req = cowboy_req:req() +* State = any() + +Perform any necessary cleanup of the state. + +This callback should release any resource currently in use, +clear any active timer and reset the process to its original +state, as it might be reused for future requests sent on the +same connection. Typical plain HTTP handlers rarely need to +use it. + +A crash in this callback or an invalid return value will +result in the closing of the connection and the termination +of the process. + :: Exports -None. +: terminate(Reason, Req, State, Handler) -> ok + +Types: + +* Reason = any() +* Req = cowboy_req:req() +* State = any() +* Handler = module() + +Call the optional `terminate/3` callback if it exists. + +This function should always be called at the end of the execution +of a handler, to give it a chance to clean up or perform +miscellaneous operations. diff --git a/doc/src/manual/cowboy_http_handler.ezdoc b/doc/src/manual/cowboy_http_handler.ezdoc deleted file mode 100644 index 6776598..0000000 --- a/doc/src/manual/cowboy_http_handler.ezdoc +++ /dev/null @@ -1,57 +0,0 @@ -::: cowboy_http_handler - -The `cowboy_http_handler` behaviour defines the interface used -by plain HTTP handlers. - -Unless noted otherwise, the callbacks will be executed sequentially. - -:: Types - -None. - -:: Callbacks - -: init({TransportName, ProtocolName}, Req, Opts) - -> {ok, Req, State} | {shutdown, Req, State} - -Types: - -* TransportName = tcp | ssl | atom() -* ProtocolName = http | atom() -* Req = cowboy_req:req() -* Opts = any() -* State = any() - -Initialize the state for this request. - -The `shutdown` return value can be used to skip the `handle/2` -call entirely. - -: handle(Req, State) -> {ok, Req, State} - -Types: - -* Req = cowboy_req:req() -* State = any() - -Handle the request. - -This callback is where the request is handled and a response -should be sent. If a response is not sent, Cowboy will send -a `204 No Content` response automatically. - -: terminate(Reason, Req, State) -> ok - -Types: - -* Reason = {normal, shutdown} | {error, atom()} -* Req = cowboy_req:req() -* State = any() - -Perform any necessary cleanup of the state. - -This callback should release any resource currently in use, -clear any active timer and reset the process to its original -state, as it might be reused for future requests sent on the -same connection. Typical plain HTTP handlers rarely need to -use it. diff --git a/doc/src/manual/cowboy_loop.ezdoc b/doc/src/manual/cowboy_loop.ezdoc new file mode 100644 index 0000000..1f3ab9e --- /dev/null +++ b/doc/src/manual/cowboy_loop.ezdoc @@ -0,0 +1,100 @@ +::: cowboy_loop + +The `cowboy_loop` module implements a handler interface for +long running HTTP connections. It is the recommended interface +for long polling and server-sent events, amongst others. + +This module is a sub protocol that defines three callbacks to +be implemented by handlers. The `init/2` and `terminate/3` +callbacks are common to all handler types and are documented +in the manual for the ^cowboy_handler module. + +The `info/3` callback is specific to loop handlers and will be +called as many times as necessary until a reply is sent. + +It is highly recommended to return a timeout value from the +`init/2` callback to ensure that the process is terminated +when no data has been received during that timespan. The +default timeout is `infinity`, which should only be used if +you have alternate means of ending inactive connections. + +:: Types + +None. + +:: Terminate reasons + +The following values may be received as the terminate reason +in the optional `terminate/3` callback. + +: normal + +The connection was closed normally before switching to the +loop sub protocol. This typically happens if an `ok` tuple is +returned from the `init/2` callback. + +: shutdown + +The handler requested to close the connection by returning +a `shutdown` tuple. + +: timeout + +The connection has been closed due to inactivity. The timeout +value can be configured from `init/2`. The response sent when +this happens is a `204 No Content`. + +: {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, overflow} + +The connection is being closed and the process terminated +because the buffer Cowboy uses to keep data sent by the +client has reached its maximum. The buffer size can be +configured through the environment value `loop_max_buffer` +and defaults to 5000 bytes. + +If the long running request comes with a body it is recommended +to process this body before switching to the loop sub protocol. + +: {error, closed} + +The socket has been closed brutally without a close frame being +received first. + +: {error, Reason} + +A socket error ocurred. + +:: Callbacks + +: info(Info, Req, State) + -> {ok, Req, State} + | {ok, Req, State, hibernate} + | {shutdown, Req, State} + +Types: + +* Info = any() +* Req = cowboy_req:req() +* State = any() + +Handle the Erlang message received. + +This function will be called every time an Erlang message +has been received. The message can be any Erlang term. + +The `shutdown` return value can be used to stop the receive loop, +typically because a response has been sent. + +The `hibernate` option will hibernate the process until +it receives another message. + +:: Exports + +None. diff --git a/doc/src/manual/cowboy_loop_handler.ezdoc b/doc/src/manual/cowboy_loop_handler.ezdoc deleted file mode 100644 index 0811a9a..0000000 --- a/doc/src/manual/cowboy_loop_handler.ezdoc +++ /dev/null @@ -1,91 +0,0 @@ -::: cowboy_loop_handler - -The `cowboy_loop_handler` behaviour defines the interface used -by HTTP handlers that do not send a response directly, instead -requiring a receive loop to process Erlang messages. - -This interface is best fit for long-polling types of requests. - -The `init/3` callback will always be called, followed by zero -or more calls to `info/3`. The `terminate/3` callback will -always be called last. - -:: Types - -None. - -:: Callbacks - -: init({TransportName, ProtocolName}, Req, Opts) - -> {loop, Req, State} - | {loop, Req, State, hibernate} - | {loop, Req, State, Timeout} - | {loop, Req, State, Timeout, hibernate} - | {shutdown, Req, State} - -Types: - -* TransportName = tcp | ssl | atom() -* ProtocolName = http | atom() -* Req = cowboy_req:req() -* Opts = any() -* State = any() -* Timeout = timeout() - -Initialize the state for this request. - -This callback will typically be used to register this process -to an event manager or a message queue in order to receive -the messages the handler wants to process. - -The receive loop will run for a duration of up to `Timeout` -milliseconds after it last received data from the socket, -at which point it will stop and send a `204 No Content` reply. -By default this value is set to `infinity`. It is recommended -to either set this value or ensure by any other mechanism -that the handler will be closed after a certain period of -inactivity. - -The `hibernate` option will hibernate the process until it -starts receiving messages. - -The `shutdown` return value can be used to skip the receive -loop entirely. - -: info(Info, Req, State) -> {ok, Req, State} | {loop, Req, State} - | {loop, Req, State, hibernate} - -Types: - -* Info = any() -* Req = cowboy_req:req() -* State = any() - -Handle the Erlang message received. - -This function will be called every time an Erlang message -has been received. The message can be any Erlang term. - -The `ok` return value can be used to stop the receive loop, -typically because a response has been sent. - -The `hibernate` option will hibernate the process until -it receives another message. - -: terminate(Reason, Req, State) -> ok - -Types: - -* Reason = {normal, shutdown} | {normal, timeout} | {error, closed} | {error, overflow} | {error, atom()} -* Req = cowboy_req:req() -* State = any() - -Perform any necessary cleanup of the state. - -This callback will typically unregister from any event manager -or message queue it registered to in `init/3`. - -This callback should release any resource currently in use, -clear any active timer and reset the process to its original -state, as it might be reused for future requests sent on the -same connection. diff --git a/doc/src/manual/cowboy_rest.ezdoc b/doc/src/manual/cowboy_rest.ezdoc index 9fe5c77..f128a22 100644 --- a/doc/src/manual/cowboy_rest.ezdoc +++ b/doc/src/manual/cowboy_rest.ezdoc @@ -3,12 +3,13 @@ The `cowboy_rest` module implements REST semantics on top of the HTTP protocol. -This module cannot be described as a behaviour due to most of -the callbacks it defines being optional. It has the same -semantics as a behaviour otherwise. +This module is a sub protocol that defines many callbacks +be implemented by handlers. The `init/2` and `terminate/3` +callbacks are common to all handler types and are documented +in the manual for the ^cowboy_handler module. -The only mandatory callback is `init/3`, needed to perform -the protocol upgrade. +All other callbacks are optional, though some may become +required depending on the return value of previous callbacks. :: Types @@ -43,46 +44,23 @@ The media-type is the content-type, excluding the charset. This value is always defined after the call to `content_types_provided/2`. -:: Callbacks - -: init({TransportName, ProtocolName}, Req, Opts) - -> {upgrade, protocol, cowboy_rest} - | {upgrade, protocol, cowboy_rest, Req, Opts} - -Types: - -* TransportName = tcp | ssl | atom() -* ProtocolName = http | atom() -* Req = cowboy_req:req() -* Opts = any() - -Upgrade the protocol to `cowboy_rest`. - -This is the only mandatory callback. - -: rest_init(Req, Opts) -> {ok, Req, State} +:: Terminate reasons -Types: +The following values may be received as the terminate reason +in the optional `terminate/3` callback. -* Req = cowboy_req:req() -* Opts = any() -* State = any() +: normal -Initialize the state for this request. +The connection was closed normally. -: rest_terminate(Req, State) -> ok +: {crash, Class, Reason} -Types: +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. -* Req = cowboy_req:req() -* State = any() - -Perform any necessary cleanup of the state. - -This callback should release any resource currently in use, -clear any active timer and reset the process to its original -state, as it might be reused for future requests sent on the -same connection. +:: Callbacks : Callback(Req, State) -> {Value, Req, State} | {halt, Req, State} diff --git a/doc/src/manual/cowboy_websocket.ezdoc b/doc/src/manual/cowboy_websocket.ezdoc index 59a6248..889ddd7 100644 --- a/doc/src/manual/cowboy_websocket.ezdoc +++ b/doc/src/manual/cowboy_websocket.ezdoc @@ -2,8 +2,25 @@ The `cowboy_websocket` module implements the Websocket protocol. -The callbacks for websocket handlers are defined in the manual -for the `cowboy_websocket_handler` behaviour. +This module is a sub protocol that defines four callbacks to +be implemented by handlers. The `init/2` and `terminate/3` +callbacks are common to all handler types and are documented +in the manual for the ^cowboy_handler module. + +The `websocket_handle/3` and `websocket_info/3` callbacks are +specific to Websocket handlers and will be called as many times +as necessary until the Websocket connection is closed. + +The `init/2` callback can be used to negotiate Websocket protocol +extensions with the client. It is highly recommended to return a +timeout value from this callback to ensure that the process is +terminated when no data has been received during that timespan. +The default timeout is `infinity`, which should only be used if +you have alternate means of ending inactive connections. + +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. :: Types @@ -31,6 +48,118 @@ Type: 7 | 8 | 13 The version of the Websocket protocol being used. +:: Terminate reasons + +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/2` 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. + +: shutdown + +The handler requested to close the connection, either by returning +a `shutdown` tuple or by sending a `close` frame. + +: timeout + +The connection has been closed due to inactivity. The timeout +value can be configured from `init/2`. + +: {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. + +:: Callbacks + +: websocket_handle(InFrame, Req, State) + -> {ok, Req, State} + | {ok, Req, State, hibernate} + | {reply, OutFrame | [OutFrame], Req, State} + | {reply, OutFrame | [OutFrame], Req, State, hibernate} + | {shutdown, Req, State} + +Types: + +* InFrame = {text | binary | ping | pong, binary()} +* Req = cowboy_req:req() +* State = any() +* OutFrame = frame() + +Handle the data received from the Websocket connection. + +This function will be called every time data is received +from the Websocket connection. + +The `shutdown` return value can be used to close the +connection. A close reply will also result in the connection +being closed. + +The `hibernate` option will hibernate the process until +it receives new data from the Websocket connection or an +Erlang message. + +: websocket_info(Info, Req, State) + -> {ok, Req, State} + | {ok, Req, State, hibernate} + | {reply, OutFrame | [OutFrame], Req, State} + | {reply, OutFrame | [OutFrame], Req, State, hibernate} + | {shutdown, Req, State} + +Types: + +* Info = any() +* Req = cowboy_req:req() +* State = any() +* OutFrame = frame() + +Handle the Erlang message received. + +This function will be called every time an Erlang message +has been received. The message can be any Erlang term. + +The `shutdown` return value can be used to close the +connection. A close reply will also result in the connection +being closed. + +The `hibernate` option will hibernate the process until +it receives another message or new data from the Websocket +connection. + :: Exports None. diff --git a/doc/src/manual/cowboy_websocket_handler.ezdoc b/doc/src/manual/cowboy_websocket_handler.ezdoc deleted file mode 100644 index 0d31a54..0000000 --- a/doc/src/manual/cowboy_websocket_handler.ezdoc +++ /dev/null @@ -1,133 +0,0 @@ -::: cowboy_websocket_handler - -The `cowboy_websocket_handler` behaviour defines the interface used -by Websocket handlers. - -The `init/3` and `websocket_init/3` callbacks will always be called, -followed by zero or more calls to `websocket_handle/3` and -`websocket_info/3`. The `websocket_terminate/3` will always -be called last. - -:: Types - -None. - -:: Callbacks - -: init({TransportName, ProtocolName}, Req, Opts) - -> {upgrade, protocol, cowboy_websocket} - | {upgrade, protocol, cowboy_websocket, Req, Opts} - -Types: - -* TransportName = tcp | ssl | atom() -* ProtocolName = http | atom() -* Req = cowboy_req:req() -* Opts = any() - -Upgrade the protocol to `cowboy_websocket`. - -: websocket_init(TransportName, Req, Opts) - -> {ok, Req, State} - | {ok, Req, State, hibernate} - | {ok, Req, State, Timeout} - | {ok, Req, State, Timeout, hibernate} - | {shutdown, Req} - -Types: - -* TransportName = tcp | ssl | atom() -* Req = cowboy_req:req() -* Opts = any() -* State = any() -* Timeout = timeout() - -Initialize the state for this session. - -This function is called before the upgrade to Websocket occurs. -It can be used to negotiate Websocket protocol extensions -with the client. It will typically be used to register this process -to an event manager or a message queue in order to receive -the messages the handler wants to process. - -The connection will stay up for a duration of up to `Timeout` -milliseconds after it last received data from the socket, -at which point it will stop and close the connection. -By default this value is set to `infinity`. It is recommended -to either set this value or ensure by any other mechanism -that the handler will be closed after a certain period of -inactivity. - -The `hibernate` option will hibernate the process until it -starts receiving either data from the Websocket connection -or Erlang messages. - -The `shutdown` return value can be used to close the connection -before upgrading to Websocket. - -: websocket_handle(InFrame, Req, State) - -> {ok, Req, State} - | {ok, Req, State, hibernate} - | {reply, OutFrame | [OutFrame], Req, State} - | {reply, OutFrame | [OutFrame], Req, State, hibernate} - | {shutdown, Req, State} - -Types: - -* InFrame = {text | binary | ping | pong, binary()} -* Req = cowboy_req:req() -* State = any() -* OutFrame = cowboy_websocket:frame() - -Handle the data received from the Websocket connection. - -This function will be called every time data is received -from the Websocket connection. - -The `shutdown` return value can be used to close the -connection. A close reply will also result in the connection -being closed. - -The `hibernate` option will hibernate the process until -it receives new data from the Websocket connection or an -Erlang message. - -: websocket_info(Info, Req, State) - -> {ok, Req, State} - | {ok, Req, State, hibernate} - | {reply, OutFrame | [OutFrame], Req, State} - | {reply, OutFrame | [OutFrame], Req, State, hibernate} - | {shutdown, Req, State} - -Types: - -* Info = any() -* Req = cowboy_req:req() -* State = any() -* OutFrame = cowboy_websocket:frame() - -Handle the Erlang message received. - -This function will be called every time an Erlang message -has been received. The message can be any Erlang term. - -The `shutdown` return value can be used to close the -connection. A close reply will also result in the connection -being closed. - -The `hibernate` option will hibernate the process until -it receives another message or new data from the Websocket -connection. - -: websocket_terminate(Reason, Req, State) -> ok - -Types: - -* Reason = {normal, shutdown | timeout} | {remote, closed} | {remote, cowboy_websocket:close_code(), binary()} | {error, badencoding | badframe | closed | atom()} -* Req = cowboy_req:req() -* State = any() - -Perform any necessary cleanup of the state. - -The connection will be closed and the process stopped right -after this call. diff --git a/doc/src/manual/index.ezdoc b/doc/src/manual/index.ezdoc index e364e90..133a341 100644 --- a/doc/src/manual/index.ezdoc +++ b/doc/src/manual/index.ezdoc @@ -5,8 +5,7 @@ The function reference documents the public interface of Cowboy. * ^"The Cowboy Application^cowboy_app * ^cowboy * ^cowboy_handler -* ^cowboy_http_handler -* ^cowboy_loop_handler +* ^cowboy_loop * ^cowboy_middleware * ^cowboy_protocol * ^cowboy_req @@ -16,5 +15,4 @@ The function reference documents the public interface of Cowboy. * ^cowboy_static * ^cowboy_sub_protocol * ^cowboy_websocket -* ^cowboy_websocket_handler * ^"HTTP status codes^http_status_codes |