mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 12:20:24 +00:00
Convert the documentation to Asciidoc
A few small revisions were made, and Erlang.mk has been updated.
This commit is contained in:
parent
b7d666cfc7
commit
4023e7f4e4
55 changed files with 5701 additions and 1889 deletions
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
erlang.mk -diff
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -3,9 +3,10 @@
|
||||||
_rel
|
_rel
|
||||||
cowboy.d
|
cowboy.d
|
||||||
deps
|
deps
|
||||||
|
doc/guide.pdf
|
||||||
|
doc/html
|
||||||
doc/man3
|
doc/man3
|
||||||
doc/man7
|
doc/man7
|
||||||
doc/markdown
|
|
||||||
ebin/*.beam
|
ebin/*.beam
|
||||||
ebin/test
|
ebin/test
|
||||||
examples/*/ebin
|
examples/*/ebin
|
||||||
|
|
52
Makefile
52
Makefile
|
@ -45,55 +45,3 @@ app:: rebar.config
|
||||||
|
|
||||||
ci-setup:: clean deps test-deps
|
ci-setup:: clean deps test-deps
|
||||||
$(gen_verbose) cp ~/.kerl/builds/$(CI_OTP_RELEASE)/otp_src_git/lib/ssl/test/erl_make_certs.erl deps/ct_helper/src/
|
$(gen_verbose) cp ~/.kerl/builds/$(CI_OTP_RELEASE)/otp_src_git/lib/ssl/test/erl_make_certs.erl deps/ct_helper/src/
|
||||||
|
|
||||||
# Documentation.
|
|
||||||
|
|
||||||
dep_ezdoc = git https://github.com/ninenines/ezdoc master
|
|
||||||
$(eval $(call dep_target,ezdoc))
|
|
||||||
|
|
||||||
build-doc-deps: $(DEPS_DIR)/ezdoc
|
|
||||||
$(MAKE) -C $(DEPS_DIR)/ezdoc
|
|
||||||
|
|
||||||
define ezdoc_script
|
|
||||||
io:format("Building manual~n"),
|
|
||||||
[begin
|
|
||||||
AST = ezdoc:parse_file(F),
|
|
||||||
BF = filename:rootname(filename:basename(F)),
|
|
||||||
io:format(" ~s~n", [BF]),
|
|
||||||
file:write_file("doc/markdown/manual/" ++ BF ++ ".md", ezdoc_markdown:export(AST)),
|
|
||||||
case BF of
|
|
||||||
"cowboy" ++ _ when BF =/= "cowboy_app" ->
|
|
||||||
file:write_file("doc/man3/" ++ BF ++ ".3", ezdoc_man:export(3, AST));
|
|
||||||
_ when BF =/= "index" ->
|
|
||||||
file:write_file("doc/man7/" ++ BF ++ ".7", ezdoc_man:export(7, AST));
|
|
||||||
_ ->
|
|
||||||
ok
|
|
||||||
end
|
|
||||||
end || F <- filelib:wildcard("doc/src/manual/*.ezdoc")],
|
|
||||||
io:format("Building guide~n"),
|
|
||||||
[begin
|
|
||||||
AST = ezdoc:parse_file(F),
|
|
||||||
BF = filename:rootname(filename:basename(F)),
|
|
||||||
io:format(" ~s~n", [BF]),
|
|
||||||
file:write_file("doc/markdown/guide/" ++ BF ++ ".md", ezdoc_markdown:export(AST))
|
|
||||||
end || F <- filelib:wildcard("doc/src/guide/*.ezdoc")],
|
|
||||||
io:format("Done.~n"),
|
|
||||||
init:stop().
|
|
||||||
endef
|
|
||||||
export ezdoc_script
|
|
||||||
|
|
||||||
docs:: clean-docs build-doc-deps
|
|
||||||
@mkdir -p doc/man3 doc/man7 doc/markdown/guide doc/markdown/manual
|
|
||||||
$(gen_verbose) erl -noinput -pa ebin deps/ezdoc/ebin -eval "$$ezdoc_script"
|
|
||||||
@gzip doc/man3/*.3 doc/man7/*.7
|
|
||||||
@cp doc/src/guide/*.png doc/markdown/guide
|
|
||||||
|
|
||||||
clean-docs:
|
|
||||||
$(gen_verbose) rm -rf doc/man3 doc/man7 doc/markdown
|
|
||||||
|
|
||||||
MAN_INSTALL_PATH ?= /usr/local/share/man
|
|
||||||
|
|
||||||
install-docs:
|
|
||||||
mkdir -p $(MAN_INSTALL_PATH)/man3/ $(MAN_INSTALL_PATH)/man7/
|
|
||||||
install -g 0 -o 0 -m 0644 doc/man3/*.gz $(MAN_INSTALL_PATH)/man3/
|
|
||||||
install -g 0 -o 0 -m 0644 doc/man7/*.gz $(MAN_INSTALL_PATH)/man7/
|
|
||||||
|
|
36
build.config
36
build.config
|
@ -1,36 +0,0 @@
|
||||||
# Do *not* comment or remove core modules
|
|
||||||
# unless you know what you are doing.
|
|
||||||
#
|
|
||||||
# Feel free to comment plugins out however.
|
|
||||||
|
|
||||||
# Core modules.
|
|
||||||
core/core
|
|
||||||
core/deps
|
|
||||||
|
|
||||||
# Plugins that must run before Erlang code gets compiled.
|
|
||||||
plugins/protobuffs
|
|
||||||
|
|
||||||
# Core modules, continued.
|
|
||||||
core/erlc
|
|
||||||
core/docs
|
|
||||||
core/test
|
|
||||||
|
|
||||||
# Plugins.
|
|
||||||
plugins/asciidoc
|
|
||||||
plugins/bootstrap
|
|
||||||
plugins/c_src
|
|
||||||
plugins/ci
|
|
||||||
plugins/ct
|
|
||||||
plugins/dialyzer
|
|
||||||
#plugins/edoc
|
|
||||||
plugins/elvis
|
|
||||||
plugins/erlydtl
|
|
||||||
plugins/escript
|
|
||||||
plugins/eunit
|
|
||||||
plugins/relx
|
|
||||||
plugins/shell
|
|
||||||
plugins/triq
|
|
||||||
plugins/xref
|
|
||||||
|
|
||||||
# Plugins enhancing the functionality of other plugins.
|
|
||||||
plugins/cover
|
|
|
@ -1,11 +1,12 @@
|
||||||
::: Architecture
|
[[architecture]]
|
||||||
|
== Architecture
|
||||||
|
|
||||||
Cowboy is a lightweight HTTP server.
|
Cowboy is a lightweight HTTP server.
|
||||||
|
|
||||||
It is built on top of Ranch. Please see the Ranch guide for more
|
It is built on top of Ranch. Please see the Ranch guide for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
:: One process per connection
|
=== One process per connection
|
||||||
|
|
||||||
It uses only one process per connection. The process where your
|
It uses only one process per connection. The process where your
|
||||||
code runs is the process controlling the socket. Using one process
|
code runs is the process controlling the socket. Using one process
|
||||||
|
@ -20,7 +21,7 @@ up before terminating the handling of the current request. This may
|
||||||
include cleaning up the process dictionary, timers, monitoring and
|
include cleaning up the process dictionary, timers, monitoring and
|
||||||
more.
|
more.
|
||||||
|
|
||||||
:: Binaries
|
=== Binaries
|
||||||
|
|
||||||
It uses binaries. Binaries are more efficient than lists for
|
It uses binaries. Binaries are more efficient than lists for
|
||||||
representing strings because they take less memory space. Processing
|
representing strings because they take less memory space. Processing
|
||||||
|
@ -28,14 +29,14 @@ performance can vary depending on the operation. Binaries are known
|
||||||
for generally getting a great boost if the code is compiled natively.
|
for generally getting a great boost if the code is compiled natively.
|
||||||
Please see the HiPE documentation for more details.
|
Please see the HiPE documentation for more details.
|
||||||
|
|
||||||
:: Date header
|
=== Date header
|
||||||
|
|
||||||
Because querying for the current date and time can be expensive,
|
Because querying for the current date and time can be expensive,
|
||||||
Cowboy generates one `Date` header value every second, shares it
|
Cowboy generates one `Date` header value every second, shares it
|
||||||
to all other processes, which then simply copy it in the response.
|
to all other processes, which then simply copy it in the response.
|
||||||
This allows compliance with HTTP/1.1 with no actual performance loss.
|
This allows compliance with HTTP/1.1 with no actual performance loss.
|
||||||
|
|
||||||
:: Max connections
|
=== Max connections
|
||||||
|
|
||||||
By default the maximum number of active connections is set to a
|
By default the maximum number of active connections is set to a
|
||||||
generally accepted big enough number. This is meant to prevent having
|
generally accepted big enough number. This is meant to prevent having
|
72
doc/src/guide/book.asciidoc
Normal file
72
doc/src/guide/book.asciidoc
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// a2x: --dblatex-opts "-P latex.output.revhistory=0 -P doc.publisher.show=0 -P index.numbered=0"
|
||||||
|
// a2x: -d book --attribute tabsize=4
|
||||||
|
|
||||||
|
= Cowboy User Guide
|
||||||
|
|
||||||
|
= Rationale
|
||||||
|
|
||||||
|
include::modern_web.asciidoc[The modern Web]
|
||||||
|
|
||||||
|
include::erlang_web.asciidoc[Erlang and the Web]
|
||||||
|
|
||||||
|
= Introduction
|
||||||
|
|
||||||
|
include::introduction.asciidoc[Introduction]
|
||||||
|
|
||||||
|
include::getting_started.asciidoc[Getting started]
|
||||||
|
|
||||||
|
include::overview.asciidoc[Request overview]
|
||||||
|
|
||||||
|
include::erlang_beginners.asciidoc[Erlang for beginners]
|
||||||
|
|
||||||
|
= Configuration
|
||||||
|
|
||||||
|
include::routing.asciidoc[routing]
|
||||||
|
|
||||||
|
include::constraints.asciidoc[Constraints]
|
||||||
|
|
||||||
|
include::static_files.asciidoc[Static files]
|
||||||
|
|
||||||
|
= Request and response
|
||||||
|
|
||||||
|
include::handlers.asciidoc[Handlers]
|
||||||
|
|
||||||
|
include::loop_handlers.asciidoc[Loop handlers]
|
||||||
|
|
||||||
|
include::req.asciidoc[The Req object]
|
||||||
|
|
||||||
|
include::req_body.asciidoc[Reading the request body]
|
||||||
|
|
||||||
|
include::resp.asciidoc[Sending a response]
|
||||||
|
|
||||||
|
include::cookies.asciidoc[Using cookies]
|
||||||
|
|
||||||
|
include::multipart.asciidoc[Multipart]
|
||||||
|
|
||||||
|
= REST
|
||||||
|
|
||||||
|
include::rest_principles.asciidoc[REST principles]
|
||||||
|
|
||||||
|
include::rest_handlers.asciidoc[Handling REST requests]
|
||||||
|
|
||||||
|
include::rest_flowcharts.asciidoc[REST flowcharts]
|
||||||
|
|
||||||
|
include::resource_design.asciidoc[Designing a resource handler]
|
||||||
|
|
||||||
|
= Websocket
|
||||||
|
|
||||||
|
include::ws_protocol.asciidoc[The Websocket protocol]
|
||||||
|
|
||||||
|
include::ws_handlers.asciidoc[Handling Websocket connections]
|
||||||
|
|
||||||
|
= Internals
|
||||||
|
|
||||||
|
include::architecture.asciidoc[Architecture]
|
||||||
|
|
||||||
|
include::broken_clients.asciidoc[Dealing with broken clients]
|
||||||
|
|
||||||
|
include::middlewares.asciidoc[Middlewares]
|
||||||
|
|
||||||
|
include::sub_protocols.asciidoc[Sub protocols]
|
||||||
|
|
||||||
|
include::hooks.asciidoc[Hooks]
|
|
@ -1,4 +1,5 @@
|
||||||
::: Dealing with broken clients
|
[[broken_clients]]
|
||||||
|
== Dealing with broken clients
|
||||||
|
|
||||||
There exists a very large number of implementations for the
|
There exists a very large number of implementations for the
|
||||||
HTTP protocol. Most widely used clients, like browsers,
|
HTTP protocol. Most widely used clients, like browsers,
|
||||||
|
@ -15,7 +16,7 @@ That means clients that ignore the HTTP standard completely
|
||||||
may fail to understand Cowboy's responses. There are of
|
may fail to understand Cowboy's responses. There are of
|
||||||
course workarounds. This chapter aims to cover them.
|
course workarounds. This chapter aims to cover them.
|
||||||
|
|
||||||
:: Lowercase headers
|
=== Lowercase headers
|
||||||
|
|
||||||
Cowboy converts all headers it receives to lowercase, and
|
Cowboy converts all headers it receives to lowercase, and
|
||||||
similarly sends back headers all in lowercase. Some broken
|
similarly sends back headers all in lowercase. Some broken
|
||||||
|
@ -24,19 +25,20 @@ HTTP clients have issues with that.
|
||||||
A simple way to solve this is to create an `onresponse` hook
|
A simple way to solve this is to create an `onresponse` hook
|
||||||
that will format the header names with the expected case.
|
that will format the header names with the expected case.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
capitalize_hook(Status, Headers, Body, Req) ->
|
capitalize_hook(Status, Headers, Body, Req) ->
|
||||||
Headers2 = [{cowboy_bstr:capitalize_token(N), V}
|
Headers2 = [{cowboy_bstr:capitalize_token(N), V}
|
||||||
|| {N, V} <- Headers],
|
|| {N, V} <- Headers],
|
||||||
cowboy_req:reply(Status, Headers2, Body, Req).
|
cowboy_req:reply(Status, Headers2, Body, Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
Note that SPDY clients do not have that particular issue
|
Note that SPDY clients do not have that particular issue
|
||||||
because the specification explicitly says all headers are
|
because the specification explicitly says all headers are
|
||||||
lowercase, unlike HTTP which allows any case but treats
|
lowercase, unlike HTTP which allows any case but treats
|
||||||
them as case insensitive.
|
them as case insensitive.
|
||||||
|
|
||||||
:: Camel-case headers
|
=== Camel-case headers
|
||||||
|
|
||||||
Sometimes it is desirable to keep the actual case used by
|
Sometimes it is desirable to keep the actual case used by
|
||||||
clients, for example when acting as a proxy between two broken
|
clients, for example when acting as a proxy between two broken
|
||||||
|
@ -44,7 +46,7 @@ implementations. There is no easy solution for this other than
|
||||||
forking the project and editing the `cowboy_protocol` file
|
forking the project and editing the `cowboy_protocol` file
|
||||||
directly.
|
directly.
|
||||||
|
|
||||||
:: Chunked transfer-encoding
|
=== Chunked transfer-encoding
|
||||||
|
|
||||||
Sometimes an HTTP client advertises itself as HTTP/1.1 but
|
Sometimes an HTTP client advertises itself as HTTP/1.1 but
|
||||||
does not support chunked transfer-encoding. This is invalid
|
does not support chunked transfer-encoding. This is invalid
|
||||||
|
@ -55,6 +57,5 @@ Req object response state to `waiting_stream`, Cowboy will
|
||||||
understand that it must use the identity transfer-encoding
|
understand that it must use the identity transfer-encoding
|
||||||
when replying, just like if it was an HTTP/1.0 client.
|
when replying, just like if it was an HTTP/1.0 client.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Req2 = cowboy_req:set(resp_state, waiting_stream).
|
Req2 = cowboy_req:set(resp_state, waiting_stream).
|
||||||
```
|
|
|
@ -1,4 +1,5 @@
|
||||||
::: Constraints
|
[[constraints]]
|
||||||
|
== Constraints
|
||||||
|
|
||||||
Cowboy provides an optional constraints based validation feature
|
Cowboy provides an optional constraints based validation feature
|
||||||
when interacting with user input.
|
when interacting with user input.
|
||||||
|
@ -16,7 +17,7 @@ Finally, constraints can be used to not only validate input,
|
||||||
but also convert said input into proper Erlang terms, all in
|
but also convert said input into proper Erlang terms, all in
|
||||||
one step.
|
one step.
|
||||||
|
|
||||||
:: Structure
|
=== Structure
|
||||||
|
|
||||||
Constraints are provided as a list of fields and for each
|
Constraints are provided as a list of fields and for each
|
||||||
field a list of constraints for that field can be provided.
|
field a list of constraints for that field can be provided.
|
||||||
|
@ -32,14 +33,16 @@ All constraints for a field will be used to match its value
|
||||||
in the order they are given. If the value is modified by a
|
in the order they are given. If the value is modified by a
|
||||||
constraint, the next constraint receives the updated value.
|
constraint, the next constraint receives the updated value.
|
||||||
|
|
||||||
:: Built-in constraints
|
=== Built-in constraints
|
||||||
|
|
||||||
|| Constraint Description
|
[cols="<,<",options="header"]
|
||||||
|
|
|===
|
||||||
| int Convert binary value to integer
|
| Constraint | Description
|
||||||
| nonempty Ensures the binary value is non-empty
|
| int | Convert binary value to integer.
|
||||||
|
| nonempty | Ensures the binary value is non-empty.
|
||||||
|
|===
|
||||||
|
|
||||||
:: Custom constraint
|
=== Custom constraint
|
||||||
|
|
||||||
In addition to the predefined constraints, Cowboy will accept
|
In addition to the predefined constraints, Cowboy will accept
|
||||||
a fun. This fun must accept one argument and return one of
|
a fun. This fun must accept one argument and return one of
|
|
@ -1,4 +1,5 @@
|
||||||
::: Using cookies
|
[[cookies]]
|
||||||
|
== Using cookies
|
||||||
|
|
||||||
Cookies are a mechanism allowing applications to maintain
|
Cookies are a mechanism allowing applications to maintain
|
||||||
state on top of the stateless HTTP protocol.
|
state on top of the stateless HTTP protocol.
|
||||||
|
@ -48,69 +49,73 @@ that run from HTTPS webpages.
|
||||||
Finally, cookies can be restricted to HTTP and HTTPS requests,
|
Finally, cookies can be restricted to HTTP and HTTPS requests,
|
||||||
essentially disabling their access from client-side scripts.
|
essentially disabling their access from client-side scripts.
|
||||||
|
|
||||||
:: Setting cookies
|
=== Setting cookies
|
||||||
|
|
||||||
By default, cookies you set are defined for the session.
|
By default, cookies you set are defined for the session.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
SessionID = generate_session_id(),
|
SessionID = generate_session_id(),
|
||||||
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [], Req).
|
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [], Req).
|
||||||
```
|
|
||||||
|
|
||||||
You can also make them expire at a specific point in the
|
You can also make them expire at a specific point in the
|
||||||
future.
|
future.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
SessionID = generate_session_id(),
|
SessionID = generate_session_id(),
|
||||||
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [
|
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [
|
||||||
{max_age, 3600}
|
{max_age, 3600}
|
||||||
], Req).
|
], Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
You can delete cookies that have already been set. The value
|
You can delete cookies that have already been set. The value
|
||||||
is ignored.
|
is ignored.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, <<>>, [
|
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, <<>>, [
|
||||||
{max_age, 0}
|
{max_age, 0}
|
||||||
], Req).
|
], Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
You can restrict them to a specific domain and path.
|
You can restrict them to a specific domain and path.
|
||||||
For example, the following cookie will be set for the domain
|
For example, the following cookie will be set for the domain
|
||||||
`my.example.org` and all its subdomains, but only on the path
|
`my.example.org` and all its subdomains, but only on the path
|
||||||
`/account` and all its subdirectories.
|
`/account` and all its subdirectories.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
Req2 = cowboy_req:set_resp_cookie(<<"inaccount">>, <<"1">>, [
|
Req2 = cowboy_req:set_resp_cookie(<<"inaccount">>, <<"1">>, [
|
||||||
{domain, "my.example.org"},
|
{domain, "my.example.org"},
|
||||||
{path, "/account"}
|
{path, "/account"}
|
||||||
], Req).
|
], Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
You can restrict the cookie to secure channels, typically HTTPS.
|
You can restrict the cookie to secure channels, typically HTTPS.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
SessionID = generate_session_id(),
|
SessionID = generate_session_id(),
|
||||||
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [
|
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [
|
||||||
{secure, true}
|
{secure, true}
|
||||||
], Req).
|
], Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
You can restrict the cookie to client-server communication
|
You can restrict the cookie to client-server communication
|
||||||
only. Such a cookie will not be available to client-side scripts.
|
only. Such a cookie will not be available to client-side scripts.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
SessionID = generate_session_id(),
|
SessionID = generate_session_id(),
|
||||||
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [
|
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [
|
||||||
{http_only, true}
|
{http_only, true}
|
||||||
], Req).
|
], Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
Cookies may also be set client-side, for example using
|
Cookies may also be set client-side, for example using
|
||||||
Javascript.
|
Javascript.
|
||||||
|
|
||||||
:: Reading cookies
|
=== Reading cookies
|
||||||
|
|
||||||
As we said, the client sends cookies with every request.
|
As we said, the client sends cookies with every request.
|
||||||
But unlike the server, the client only sends the cookie
|
But unlike the server, the client only sends the cookie
|
||||||
|
@ -124,16 +129,14 @@ to the values or providing a default if they are missing.
|
||||||
You can parse the cookies and then use standard library
|
You can parse the cookies and then use standard library
|
||||||
functions to access individual values.
|
functions to access individual values.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Cookies = cowboy_req:parse_cookies(Req),
|
Cookies = cowboy_req:parse_cookies(Req),
|
||||||
{_, Lang} = lists:keyfind(<<"lang">>, 1, Cookies).
|
{_, Lang} = lists:keyfind(<<"lang">>, 1, Cookies).
|
||||||
```
|
|
||||||
|
|
||||||
You can match the cookies into a map.
|
You can match the cookies into a map.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
#{id := ID, lang := Lang} = cowboy_req:match_cookies([id, lang], Req).
|
#{id := ID, lang := Lang} = cowboy_req:match_cookies([id, lang], Req).
|
||||||
```
|
|
||||||
|
|
||||||
You can use constraints to validate the values while matching
|
You can use constraints to validate the values while matching
|
||||||
them. The following snippet will crash if the `id` cookie is
|
them. The following snippet will crash if the `id` cookie is
|
||||||
|
@ -141,22 +144,20 @@ not an integer number or if the `lang` cookie is empty. Additionally
|
||||||
the `id` cookie value will be converted to an integer term, saving
|
the `id` cookie value will be converted to an integer term, saving
|
||||||
you a conversion step.
|
you a conversion step.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
CookiesMap = cowboy_req:match_cookies([{id, int}, {lang, nonempty}], Req).
|
CookiesMap = cowboy_req:match_cookies([{id, int}, {lang, nonempty}], Req).
|
||||||
```
|
|
||||||
|
|
||||||
Note that if two cookies share the same name, then the map value
|
Note that if two cookies share the same name, then the map value
|
||||||
will be a list of the two cookie values.
|
will be a list of the two cookie values.
|
||||||
|
|
||||||
Read more about ^constraints^.
|
Read more about xref:constraints[constraints].
|
||||||
|
|
||||||
A default value can be provided. The default will be used
|
A default value can be provided. The default will be used
|
||||||
if the `lang` cookie is not found. It will not be used if
|
if the `lang` cookie is not found. It will not be used if
|
||||||
the cookie is found but has an empty value.
|
the cookie is found but has an empty value.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
#{lang := Lang} = cowboy_req:match_cookies([{lang, [], <<"en-US">>}], Req).
|
#{lang := Lang} = cowboy_req:match_cookies([{lang, [], <<"en-US">>}], Req).
|
||||||
```
|
|
||||||
|
|
||||||
If no default is provided and the value is missing, the
|
If no default is provided and the value is missing, the
|
||||||
query string is deemed invalid and the process will crash.
|
query string is deemed invalid and the process will crash.
|
|
@ -1,4 +1,5 @@
|
||||||
::: Erlang for beginners
|
[[erlang_beginners]]
|
||||||
|
== Erlang for beginners
|
||||||
|
|
||||||
Chances are you are interested in using Cowboy, but have
|
Chances are you are interested in using Cowboy, but have
|
||||||
no idea how to write an Erlang program. Fear not! This
|
no idea how to write an Erlang program. Fear not! This
|
||||||
|
@ -8,10 +9,10 @@ We recommend two books for beginners. You should read them
|
||||||
both at some point, as they cover Erlang from two entirely
|
both at some point, as they cover Erlang from two entirely
|
||||||
different perspectives.
|
different perspectives.
|
||||||
|
|
||||||
:: Learn You Some Erlang for Great Good!
|
=== Learn You Some Erlang for Great Good!
|
||||||
|
|
||||||
The quickest way to get started with Erlang is by reading
|
The quickest way to get started with Erlang is by reading
|
||||||
a book with the funny name of ^"LYSE^http://learnyousomeerlang.com^,
|
a book with the funny name of http://learnyousomeerlang.com[LYSE],
|
||||||
as we affectionately call it.
|
as we affectionately call it.
|
||||||
|
|
||||||
It will get right into the syntax and quickly answer the questions
|
It will get right into the syntax and quickly answer the questions
|
||||||
|
@ -22,12 +23,12 @@ You can read an early version of the book online for free,
|
||||||
but you really should buy the much more refined paper and
|
but you really should buy the much more refined paper and
|
||||||
ebook versions.
|
ebook versions.
|
||||||
|
|
||||||
:: Programming Erlang
|
=== Programming Erlang
|
||||||
|
|
||||||
After writing some code, you will probably want to understand
|
After writing some code, you will probably want to understand
|
||||||
the very concepts that make Erlang what it is today. These
|
the very concepts that make Erlang what it is today. These
|
||||||
are best explained by Joe Armstrong, the godfather of Erlang,
|
are best explained by Joe Armstrong, the godfather of Erlang,
|
||||||
in his book ^"Programming Erlang^http://pragprog.com/book/jaerlang2/programming-erlang^.
|
in his book http://pragprog.com/book/jaerlang2/programming-erlang[Programming Erlang].
|
||||||
|
|
||||||
Instead of going into every single details of the language,
|
Instead of going into every single details of the language,
|
||||||
Joe focuses on the central concepts behind Erlang, and shows
|
Joe focuses on the central concepts behind Erlang, and shows
|
|
@ -1,6 +1,7 @@
|
||||||
::: Erlang and the Web
|
[[erlang_web]]
|
||||||
|
== Erlang and the Web
|
||||||
|
|
||||||
:: The Web is concurrent
|
=== The Web is concurrent
|
||||||
|
|
||||||
When you access a website there is little concurrency
|
When you access a website there is little concurrency
|
||||||
involved. A few connections are opened and requests
|
involved. A few connections are opened and requests
|
||||||
|
@ -53,7 +54,7 @@ will also connect to various applications on the Internet.
|
||||||
|
|
||||||
Only Erlang is prepared to deal with what's coming.
|
Only Erlang is prepared to deal with what's coming.
|
||||||
|
|
||||||
:: The Web is soft real time
|
=== The Web is soft real time
|
||||||
|
|
||||||
What does soft real time mean, you ask? It means we want the
|
What does soft real time mean, you ask? It means we want the
|
||||||
operations done as quickly as possible, and in the case of
|
operations done as quickly as possible, and in the case of
|
||||||
|
@ -82,7 +83,7 @@ can guarantee stable low latency of operations.
|
||||||
Erlang provides the guarantees that the soft real time Web
|
Erlang provides the guarantees that the soft real time Web
|
||||||
requires.
|
requires.
|
||||||
|
|
||||||
:: The Web is asynchronous
|
=== The Web is asynchronous
|
||||||
|
|
||||||
Long ago, the Web was synchronous because HTTP was synchronous.
|
Long ago, the Web was synchronous because HTTP was synchronous.
|
||||||
You fired a request, and then waited for a response. Not anymore.
|
You fired a request, and then waited for a response. Not anymore.
|
||||||
|
@ -114,7 +115,7 @@ Erlang is by nature asynchronous and really good at it thanks to the
|
||||||
great engineering that has been done in the VM over the years. It's
|
great engineering that has been done in the VM over the years. It's
|
||||||
only natural that it's so good at dealing with the asynchronous Web.
|
only natural that it's so good at dealing with the asynchronous Web.
|
||||||
|
|
||||||
:: The Web is omnipresent
|
=== The Web is omnipresent
|
||||||
|
|
||||||
The Web has taken a very important part of our lives. We're
|
The Web has taken a very important part of our lives. We're
|
||||||
connected at all times, when we're on our phone, using our computer,
|
connected at all times, when we're on our phone, using our computer,
|
||||||
|
@ -167,7 +168,7 @@ down, or even a data center entirely.
|
||||||
Fault tolerance and distribution are important today, and will be
|
Fault tolerance and distribution are important today, and will be
|
||||||
vital in the future of the Web. Erlang is ready.
|
vital in the future of the Web. Erlang is ready.
|
||||||
|
|
||||||
:: Erlang is the ideal platform for the Web
|
=== Erlang is the ideal platform for the Web
|
||||||
|
|
||||||
Erlang provides all the important features that the Web requires
|
Erlang provides all the important features that the Web requires
|
||||||
or will require in the near future. Erlang is a perfect match
|
or will require in the near future. Erlang is a perfect match
|
|
@ -1,4 +1,5 @@
|
||||||
::: Getting started
|
[[getting_started]]
|
||||||
|
== Getting started
|
||||||
|
|
||||||
Erlang is more than a language, it is also an operating system
|
Erlang is more than a language, it is also an operating system
|
||||||
for your applications. Erlang developers rarely write standalone
|
for your applications. Erlang developers rarely write standalone
|
||||||
|
@ -12,44 +13,40 @@ Cowboy, writing your first application and generating your first
|
||||||
release. At the end of this chapter you should know everything
|
release. At the end of this chapter you should know everything
|
||||||
you need to push your first Cowboy application to production.
|
you need to push your first Cowboy application to production.
|
||||||
|
|
||||||
:: Bootstrap
|
=== Bootstrap
|
||||||
|
|
||||||
We are going to use the ^"erlang.mk^https://github.com/ninenines/erlang.mk
|
We are going to use the https://github.com/ninenines/erlang.mk[Erlang.mk]
|
||||||
build system. It also offers bootstrap features allowing us to
|
build system. It also offers bootstrap features allowing us to
|
||||||
quickly get started without having to deal with minute details.
|
quickly get started without having to deal with minute details.
|
||||||
|
|
||||||
First, let's create the directory for our application.
|
First, let's create the directory for our application.
|
||||||
|
|
||||||
``` bash
|
[source,bash]
|
||||||
$ mkdir hello_erlang
|
$ mkdir hello_erlang
|
||||||
$ cd hello_erlang
|
$ cd hello_erlang
|
||||||
```
|
|
||||||
|
|
||||||
Then we need to download `erlang.mk`. Either use the following
|
Then we need to download Erlang.mk. Either use the following
|
||||||
command or download it manually.
|
command or download it manually.
|
||||||
|
|
||||||
``` bash
|
[source,bash]
|
||||||
$ wget https://raw.githubusercontent.com/ninenines/erlang.mk/master/erlang.mk
|
$ wget https://raw.githubusercontent.com/ninenines/erlang.mk/master/erlang.mk
|
||||||
```
|
|
||||||
|
|
||||||
We can now bootstrap our application. Since we are going to generate
|
We can now bootstrap our application. Since we are going to generate
|
||||||
a release, we will also bootstrap it at the same time.
|
a release, we will also bootstrap it at the same time.
|
||||||
|
|
||||||
``` bash
|
[source,bash]
|
||||||
$ make -f erlang.mk bootstrap bootstrap-rel
|
$ make -f erlang.mk bootstrap bootstrap-rel
|
||||||
```
|
|
||||||
|
|
||||||
This creates a Makefile, a base application, and the release files
|
This creates a Makefile, a base application, and the release files
|
||||||
necessary for creating the release. We can already build and start
|
necessary for creating the release. We can already build and start
|
||||||
this release.
|
this release.
|
||||||
|
|
||||||
``` bash
|
[source,bash]
|
||||||
$ make
|
----
|
||||||
...
|
$ make run
|
||||||
$ ./_rel/hello_erlang_release/bin/hello_erlang_release console
|
|
||||||
...
|
...
|
||||||
(hello_erlang@127.0.0.1)1>
|
(hello_erlang@127.0.0.1)1>
|
||||||
```
|
----
|
||||||
|
|
||||||
Entering the command `i().` will show the running processes, including
|
Entering the command `i().` will show the running processes, including
|
||||||
one called `hello_erlang_sup`. This is the supervisor for our
|
one called `hello_erlang_sup`. This is the supervisor for our
|
||||||
|
@ -59,64 +56,34 @@ The release currently does nothing. In the rest of this chapter we
|
||||||
will add Cowboy as a dependency and write a simple "Hello world!"
|
will add Cowboy as a dependency and write a simple "Hello world!"
|
||||||
handler.
|
handler.
|
||||||
|
|
||||||
:: Cowboy setup
|
=== Cowboy setup
|
||||||
|
|
||||||
To add Cowboy as a dependency to your application, you need to modify
|
Modifying the 'Makefile' allows the build system to know it needs to
|
||||||
two files: the Makefile and the application resource file.
|
|
||||||
|
|
||||||
Modifying the Makefile allows the build system to know it needs to
|
|
||||||
fetch and compile Cowboy. To do that we simply need to add one line
|
fetch and compile Cowboy. To do that we simply need to add one line
|
||||||
to our Makefile to make it look like this:
|
to our Makefile to make it look like this:
|
||||||
|
|
||||||
``` Makefile
|
[source,make]
|
||||||
PROJECT = hello_erlang
|
PROJECT = hello_erlang
|
||||||
DEPS = cowboy
|
DEPS = cowboy
|
||||||
include erlang.mk
|
include erlang.mk
|
||||||
```
|
|
||||||
|
|
||||||
Modifying the application resource file, `src/hello_erlang.app.src`,
|
If you run `make run` now, Cowboy will be included in the release
|
||||||
allows the build system to know it needs to include Cowboy in the
|
|
||||||
release and start it automatically. This is a different step because
|
|
||||||
some dependencies are only needed during development.
|
|
||||||
|
|
||||||
We are simply going to add `cowboy` to the list of `applications`,
|
|
||||||
right after `stdlib`. Don't forget the comma separator.
|
|
||||||
|
|
||||||
``` erlang
|
|
||||||
{application, hello_erlang, [
|
|
||||||
{description, "Hello Erlang!"},
|
|
||||||
{vsn, "0.1.0"},
|
|
||||||
{modules, []},
|
|
||||||
{registered, []},
|
|
||||||
{applications, [
|
|
||||||
kernel,
|
|
||||||
stdlib,
|
|
||||||
cowboy
|
|
||||||
]},
|
|
||||||
{mod, {hello_erlang_app, []}},
|
|
||||||
{env, []}
|
|
||||||
]}.
|
|
||||||
```
|
|
||||||
|
|
||||||
You may want to set a description for the application while you
|
|
||||||
are editing the file.
|
|
||||||
|
|
||||||
If you run `make` now and start the release, Cowboy will be included
|
|
||||||
and started automatically. This is not enough however, as Cowboy
|
and started automatically. This is not enough however, as Cowboy
|
||||||
doesn't do anything by default. We still need to tell Cowboy to
|
doesn't do anything by default. We still need to tell Cowboy to
|
||||||
listen for connections.
|
listen for connections.
|
||||||
|
|
||||||
:: Listening for connections
|
=== Listening for connections
|
||||||
|
|
||||||
We will do this when our application starts. It's a two step process.
|
We will do this when our application starts. It's a two step process.
|
||||||
First we need to define and compile the dispatch list, a list of
|
First we need to define and compile the dispatch list, a list of
|
||||||
routes that Cowboy will use to map requests to handler modules.
|
routes that Cowboy will use to map requests to handler modules.
|
||||||
Then we tell Cowboy to listen for connections.
|
Then we tell Cowboy to listen for connections.
|
||||||
|
|
||||||
Open the `src/hello_erlang_app.erl` file and add the necessary
|
Open the 'src/hello_erlang_app.erl' file and add the necessary
|
||||||
code to the `start/2` function to make it look like this:
|
code to the `start/2` function to make it look like this:
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
start(_Type, _Args) ->
|
start(_Type, _Args) ->
|
||||||
Dispatch = cowboy_router:compile([
|
Dispatch = cowboy_router:compile([
|
||||||
{'_', [{"/", hello_handler, []}]}
|
{'_', [{"/", hello_handler, []}]}
|
||||||
|
@ -125,19 +92,19 @@ start(_Type, _Args) ->
|
||||||
[{env, [{dispatch, Dispatch}]}]
|
[{env, [{dispatch, Dispatch}]}]
|
||||||
),
|
),
|
||||||
hello_erlang_sup:start_link().
|
hello_erlang_sup:start_link().
|
||||||
```
|
----
|
||||||
|
|
||||||
The dispatch list is explained in great details in the
|
The dispatch list is explained in great details in the
|
||||||
^"Routing^routing^ chapter. For this tutorial we map the
|
xref:routing[Routing] chapter. For this tutorial we map the
|
||||||
path `/` to the handler module `hello_handler`. This module
|
path `/` to the handler module `hello_handler`. This module
|
||||||
doesn't exist yet, we still have to write it.
|
doesn't exist yet, we still have to write it.
|
||||||
|
|
||||||
If you build the release, start it and open ^http://localhost:8080
|
If you build and start the release, then open http://localhost:8080
|
||||||
now, you will get an error because the module is missing. Any
|
in your browser, you will get an error because the module is missing.
|
||||||
other URL, like ^http://localhost:8080/test^, will result in a
|
Any other URL, like http://localhost:8080/test, will result in a
|
||||||
404 error.
|
404 error.
|
||||||
|
|
||||||
:: Handling requests
|
=== Handling requests
|
||||||
|
|
||||||
Cowboy features different kinds of handlers, including REST
|
Cowboy features different kinds of handlers, including REST
|
||||||
and Websocket handlers. For this tutorial we will use a plain
|
and Websocket handlers. For this tutorial we will use a plain
|
||||||
|
@ -145,25 +112,25 @@ HTTP handler.
|
||||||
|
|
||||||
First, let's generate a handler from a template.
|
First, let's generate a handler from a template.
|
||||||
|
|
||||||
``` bash
|
[source,bash]
|
||||||
$ make new t=cowboy_http n=hello_handler
|
$ make new t=cowboy_http n=hello_handler
|
||||||
```
|
|
||||||
|
|
||||||
You can then open the `src/hello_handler.erl` file and modify
|
You can then open the 'src/hello_handler.erl' file and modify
|
||||||
the `init/2` function like this to send a reply.
|
the `init/2` function like this to send a reply.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, Opts) ->
|
init(Req, Opts) ->
|
||||||
Req2 = cowboy_req:reply(200,
|
Req2 = cowboy_req:reply(200,
|
||||||
[{<<"content-type">>, <<"text/plain">>}],
|
[{<<"content-type">>, <<"text/plain">>}],
|
||||||
<<"Hello Erlang!">>,
|
<<"Hello Erlang!">>,
|
||||||
Req),
|
Req),
|
||||||
{ok, Req2, Opts}.
|
{ok, Req2, Opts}.
|
||||||
```
|
----
|
||||||
|
|
||||||
What the above code does is send a `200 OK` reply, with the
|
What the above code does is send a `200 OK` reply, with the
|
||||||
`content-type` header set to `text/plain` and the response
|
`content-type` header set to `text/plain` and the response
|
||||||
body set to `Hello Erlang!`.
|
body set to `Hello Erlang!`.
|
||||||
|
|
||||||
If you build the release, start it and open ^http://localhost:8080
|
If you run the release and open http://localhost:8080
|
||||||
in your browser, you should get a nice `Hello Erlang!` displayed!
|
in your browser, you should get a nice `Hello Erlang!` displayed!
|
|
@ -1,22 +1,24 @@
|
||||||
::: Handlers
|
[[handlers]]
|
||||||
|
== Handlers
|
||||||
|
|
||||||
Handlers are Erlang modules that handle HTTP requests.
|
Handlers are Erlang modules that handle HTTP requests.
|
||||||
|
|
||||||
:: Plain HTTP handlers
|
=== Plain HTTP handlers
|
||||||
|
|
||||||
The most basic handler in Cowboy implements the mandatory
|
The most basic handler in Cowboy implements the mandatory
|
||||||
`init/2` callback, manipulates the request, optionally
|
`init/2` callback, manipulates the request, optionally
|
||||||
sends a response and then returns.
|
sends a response and then returns.
|
||||||
|
|
||||||
This callback receives the ^"Req object^req and the options
|
This callback receives the xref:req[Req object] and the options
|
||||||
defined during the ^"router configuration^routing^.
|
defined during the xref:routing[router configuration].
|
||||||
|
|
||||||
A handler that does nothing would look like this:
|
A handler that does nothing would look like this:
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, _Opts) ->
|
||||||
{ok, Req, #state{}}.
|
{ok, Req, #state{}}.
|
||||||
```
|
----
|
||||||
|
|
||||||
Despite sending no reply, a `204 No Content` reply will be
|
Despite sending no reply, a `204 No Content` reply will be
|
||||||
sent to the client, as Cowboy makes sure that a reply is
|
sent to the client, as Cowboy makes sure that a reply is
|
||||||
|
@ -24,13 +26,14 @@ sent for every request.
|
||||||
|
|
||||||
We need to use the Req object for sending a reply.
|
We need to use the Req object for sending a reply.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, _Opts) ->
|
||||||
Req2 = cowboy_req:reply(200, [
|
Req2 = cowboy_req:reply(200, [
|
||||||
{<<"content-type">>, <<"text/plain">>}
|
{<<"content-type">>, <<"text/plain">>}
|
||||||
], <<"Hello World!">>, Req),
|
], <<"Hello World!">>, Req),
|
||||||
{ok, Req2, #state{}}.
|
{ok, Req2, #state{}}.
|
||||||
```
|
----
|
||||||
|
|
||||||
As you can see we return a 3-tuple. `ok` means that the
|
As you can see we return a 3-tuple. `ok` means that the
|
||||||
handler ran successfully. The Req object is returned as
|
handler ran successfully. The Req object is returned as
|
||||||
|
@ -43,7 +46,7 @@ in every subsequent callbacks to this handler. Plain HTTP
|
||||||
handlers only have one additional callback, the optional
|
handlers only have one additional callback, the optional
|
||||||
`terminate/3`.
|
`terminate/3`.
|
||||||
|
|
||||||
:: Other handlers
|
=== Other handlers
|
||||||
|
|
||||||
The `init/2` callback can also be used to inform Cowboy
|
The `init/2` callback can also be used to inform Cowboy
|
||||||
that this is a different kind of handler and that Cowboy
|
that this is a different kind of handler and that Cowboy
|
||||||
|
@ -51,38 +54,41 @@ should switch to it. To do this you simply need to return
|
||||||
the module name of the handler type you want to switch to.
|
the module name of the handler type you want to switch to.
|
||||||
|
|
||||||
Cowboy comes with three handler types you can switch to:
|
Cowboy comes with three handler types you can switch to:
|
||||||
^"cowboy_rest^rest_handlers^, ^"cowboy_websocket^ws_handlers^
|
xref:rest_handlers[cowboy_rest], xref:ws_handlers[cowboy_websocket]
|
||||||
and ^"cowboy_loop^loop_handlers^. In addition to those you
|
and xref:loop_handlers[cowboy_loop]. In addition to those you
|
||||||
can define your own handler types.
|
can define your own handler types.
|
||||||
|
|
||||||
Switching is simple. Instead of returning `ok`, you simply
|
Switching is simple. Instead of returning `ok`, you simply
|
||||||
return the name of the handler type you want to use. The
|
return the name of the handler type you want to use. The
|
||||||
following snippet switches to a Websocket handler:
|
following snippet switches to a Websocket handler:
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, _Opts) ->
|
||||||
{cowboy_websocket, Req, #state{}}.
|
{cowboy_websocket, Req, #state{}}.
|
||||||
```
|
----
|
||||||
|
|
||||||
You can also switch to your own custom handler type:
|
You can also switch to your own custom handler type:
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, _Opts) ->
|
||||||
{my_handler_type, Req, #state{}}.
|
{my_handler_type, Req, #state{}}.
|
||||||
```
|
----
|
||||||
|
|
||||||
How to implement a custom handler type is described in the
|
How to implement a custom handler type is described in the
|
||||||
^"Sub protocols^sub_protocols chapter.
|
xref:sub_protocols[Sub protocols] chapter.
|
||||||
|
|
||||||
:: Cleaning up
|
=== Cleaning up
|
||||||
|
|
||||||
All handlers coming with Cowboy allow the use of the optional
|
All handlers coming with Cowboy allow the use of the optional
|
||||||
`terminate/3` callback.
|
`terminate/3` callback.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
terminate(_Reason, Req, State) ->
|
terminate(_Reason, Req, State) ->
|
||||||
ok.
|
ok.
|
||||||
```
|
----
|
||||||
|
|
||||||
This callback is strictly reserved for any required cleanup.
|
This callback is strictly reserved for any required cleanup.
|
||||||
You cannot send a response from this function. There is no
|
You cannot send a response from this function. There is no
|
|
@ -1,9 +1,10 @@
|
||||||
::: Hooks
|
[[hooks]]
|
||||||
|
== Hooks
|
||||||
|
|
||||||
Hooks allow the user to customize Cowboy's behavior during specific
|
Hooks allow the user to customize Cowboy's behavior during specific
|
||||||
operations.
|
operations.
|
||||||
|
|
||||||
:: Onresponse
|
=== Onresponse
|
||||||
|
|
||||||
The `onresponse` hook is called right before sending the response
|
The `onresponse` hook is called right before sending the response
|
||||||
to the socket. It can be used for the purposes of logging responses,
|
to the socket. It can be used for the purposes of logging responses,
|
||||||
|
@ -16,7 +17,8 @@ explicitly provide all headers that are needed.
|
||||||
|
|
||||||
You can specify the `onresponse` hook when creating the listener.
|
You can specify the `onresponse` hook when creating the listener.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
cowboy:start_http(my_http_listener, 100,
|
cowboy:start_http(my_http_listener, 100,
|
||||||
[{port, 8080}],
|
[{port, 8080}],
|
||||||
[
|
[
|
||||||
|
@ -24,13 +26,14 @@ cowboy:start_http(my_http_listener, 100,
|
||||||
{onresponse, fun ?MODULE:custom_404_hook/4}
|
{onresponse, fun ?MODULE:custom_404_hook/4}
|
||||||
]
|
]
|
||||||
).
|
).
|
||||||
```
|
----
|
||||||
|
|
||||||
The following hook function will provide a custom body for 404 errors
|
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
|
when it has not been provided before, and will let Cowboy proceed with
|
||||||
the default response otherwise.
|
the default response otherwise.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
custom_404_hook(404, Headers, <<>>, Req) ->
|
custom_404_hook(404, Headers, <<>>, Req) ->
|
||||||
Body = <<"404 Not Found.">>,
|
Body = <<"404 Not Found.">>,
|
||||||
Headers2 = lists:keyreplace(<<"content-length">>, 1, Headers,
|
Headers2 = lists:keyreplace(<<"content-length">>, 1, Headers,
|
||||||
|
@ -38,6 +41,6 @@ custom_404_hook(404, Headers, <<>>, Req) ->
|
||||||
cowboy_req:reply(404, Headers2, Body, Req);
|
cowboy_req:reply(404, Headers2, Body, Req);
|
||||||
custom_404_hook(_, _, _, Req) ->
|
custom_404_hook(_, _, _, Req) ->
|
||||||
Req.
|
Req.
|
||||||
```
|
----
|
||||||
|
|
||||||
Again, make sure to always return the last request object obtained.
|
Again, make sure to always return the last request object obtained.
|
|
@ -1,58 +0,0 @@
|
||||||
::: Cowboy User Guide
|
|
||||||
|
|
||||||
The Cowboy User Guide explores the modern Web and how to make
|
|
||||||
best use of Cowboy for writing powerful Web applications.
|
|
||||||
|
|
||||||
:: Rationale
|
|
||||||
|
|
||||||
* ^"The modern Web^modern_web
|
|
||||||
* ^"Erlang and the Web^erlang_web
|
|
||||||
|
|
||||||
:: Introduction
|
|
||||||
|
|
||||||
* ^"Introduction^introduction
|
|
||||||
* ^"Getting started^getting_started
|
|
||||||
* ^"Request overview^overview
|
|
||||||
* ^"Erlang for beginners^erlang_beginners
|
|
||||||
|
|
||||||
:: Configuration
|
|
||||||
|
|
||||||
* ^"Routing^routing
|
|
||||||
* ^"Constraints^constraints
|
|
||||||
* ^"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^multipart
|
|
||||||
|
|
||||||
:: REST
|
|
||||||
|
|
||||||
* ^"REST principles^rest_principles
|
|
||||||
* ^"Handling REST requests^rest_handlers
|
|
||||||
* ^"REST flowcharts^rest_flowcharts
|
|
||||||
* ^"Designing a resource handler^resource_design
|
|
||||||
|
|
||||||
:: Websocket
|
|
||||||
|
|
||||||
* ^"The Websocket protocol^ws_protocol
|
|
||||||
* ^"Handling Websocket connections^ws_handlers
|
|
||||||
|
|
||||||
:: Push technology
|
|
||||||
|
|
||||||
* ^"Loop handlers^loop_handlers
|
|
||||||
|
|
||||||
:: Extensions
|
|
||||||
|
|
||||||
* ^"Middlewares^middlewares
|
|
||||||
* ^"Sub protocols^sub_protocols
|
|
||||||
* ^"Hooks^hooks
|
|
||||||
|
|
||||||
:: Internals
|
|
||||||
|
|
||||||
* ^"Architecture^architecture
|
|
||||||
* ^"Dealing with broken clients^broken_clients
|
|
|
@ -1,4 +1,5 @@
|
||||||
::: Introduction
|
[[introduction]]
|
||||||
|
== Introduction
|
||||||
|
|
||||||
Cowboy is a small, fast and modular HTTP server written in Erlang.
|
Cowboy is a small, fast and modular HTTP server written in Erlang.
|
||||||
|
|
||||||
|
@ -14,14 +15,14 @@ Cowboy is clean Erlang code. It includes hundreds of tests and its code
|
||||||
is fully compliant with the Dialyzer. It is also well documented and
|
is fully compliant with the Dialyzer. It is also well documented and
|
||||||
features both a Function Reference and a User Guide.
|
features both a Function Reference and a User Guide.
|
||||||
|
|
||||||
:: Prerequisites
|
=== Prerequisites
|
||||||
|
|
||||||
Beginner Erlang knowledge is recommended for reading this guide.
|
Beginner Erlang knowledge is recommended for reading this guide.
|
||||||
|
|
||||||
Knowledge of the HTTP protocol is recommended but not required, as it
|
Knowledge of the HTTP protocol is recommended but not required, as it
|
||||||
will be detailed throughout the guide.
|
will be detailed throughout the guide.
|
||||||
|
|
||||||
:: Supported platforms
|
=== Supported platforms
|
||||||
|
|
||||||
Cowboy is tested and supported on Linux.
|
Cowboy is tested and supported on Linux.
|
||||||
|
|
||||||
|
@ -39,11 +40,11 @@ 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.
|
Cowboy uses the maps data type which was introduced in Erlang 17.0.
|
||||||
|
|
||||||
:: Versioning
|
=== Versioning
|
||||||
|
|
||||||
Cowboy uses ^"Semantic Versioning 2.0.0^http://semver.org/^.
|
Cowboy uses http://semver.org/[Semantic Versioning 2.0.0].
|
||||||
|
|
||||||
:: Conventions
|
=== Conventions
|
||||||
|
|
||||||
In the HTTP protocol, the method name is case sensitive. All standard
|
In the HTTP protocol, the method name is case sensitive. All standard
|
||||||
method names are uppercase.
|
method names are uppercase.
|
|
@ -1,4 +1,5 @@
|
||||||
::: Loop handlers
|
[[loop_handlers]]
|
||||||
|
== Loop handlers
|
||||||
|
|
||||||
Loop handlers are a special kind of HTTP handlers used when the
|
Loop handlers are a special kind of HTTP handlers used when the
|
||||||
response can not be sent right away. The handler enters instead
|
response can not be sent right away. The handler enters instead
|
||||||
|
@ -24,7 +25,7 @@ and feed these messages to the `info/3` callback. It also features
|
||||||
the `init/2` 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.
|
for plain HTTP handlers.
|
||||||
|
|
||||||
:: Initialization
|
=== Initialization
|
||||||
|
|
||||||
The `init/2` function must return a `cowboy_loop` tuple to enable
|
The `init/2` function must return a `cowboy_loop` tuple to enable
|
||||||
loop handler behavior. This tuple may optionally contain
|
loop handler behavior. This tuple may optionally contain
|
||||||
|
@ -33,21 +34,23 @@ process enter hibernation until a message is received.
|
||||||
|
|
||||||
This snippet enables the loop handler.
|
This snippet enables the loop handler.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, _Opts) ->
|
||||||
{cowboy_loop, Req, #state{}}.
|
{cowboy_loop, Req, #state{}}.
|
||||||
```
|
----
|
||||||
|
|
||||||
However it is largely recommended that you set a timeout
|
However it is largely recommended that you set a timeout
|
||||||
value. The next example sets a timeout value of 30s and
|
value. The next example sets a timeout value of 30s and
|
||||||
also makes the process hibernate.
|
also makes the process hibernate.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, _Opts) ->
|
||||||
{cowboy_loop, Req, #state{}, 30000, hibernate}.
|
{cowboy_loop, Req, #state{}, 30000, hibernate}.
|
||||||
```
|
----
|
||||||
|
|
||||||
:: Receive loop
|
=== Receive loop
|
||||||
|
|
||||||
Once initialized, Cowboy will wait for messages to arrive
|
Once initialized, Cowboy will wait for messages to arrive
|
||||||
in the process' mailbox. When a message arrives, Cowboy
|
in the process' mailbox. When a message arrives, Cowboy
|
||||||
|
@ -58,13 +61,14 @@ The following snippet sends a reply when it receives a
|
||||||
`reply` message from another process, or waits for another
|
`reply` message from another process, or waits for another
|
||||||
message otherwise.
|
message otherwise.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
info({reply, Body}, Req, State) ->
|
info({reply, Body}, Req, State) ->
|
||||||
Req2 = cowboy_req:reply(200, [], Body, Req),
|
Req2 = cowboy_req:reply(200, [], Body, Req),
|
||||||
{stop, Req2, State};
|
{stop, Req2, State};
|
||||||
info(_Msg, Req, State) ->
|
info(_Msg, Req, State) ->
|
||||||
{ok, Req, State, hibernate}.
|
{ok, Req, State, hibernate}.
|
||||||
```
|
----
|
||||||
|
|
||||||
Do note that the `reply` tuple here may be any message
|
Do note that the `reply` tuple here may be any message
|
||||||
and is simply an example.
|
and is simply an example.
|
||||||
|
@ -81,7 +85,7 @@ This will instruct Cowboy to end the request.
|
||||||
|
|
||||||
Otherwise an `ok` tuple should be returned.
|
Otherwise an `ok` tuple should be returned.
|
||||||
|
|
||||||
:: Streaming loop
|
=== Streaming loop
|
||||||
|
|
||||||
Another common case well suited for loop handlers is
|
Another common case well suited for loop handlers is
|
||||||
streaming data received in the form of Erlang messages.
|
streaming data received in the form of Erlang messages.
|
||||||
|
@ -93,7 +97,8 @@ The following snippet does exactly that. As you can see
|
||||||
a chunk is sent every time a `chunk` message is received,
|
a chunk is sent every time a `chunk` message is received,
|
||||||
and the loop is stopped by sending an `eof` message.
|
and the loop is stopped by sending an `eof` message.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, _Opts) ->
|
||||||
Req2 = cowboy_req:chunked_reply(200, [], Req),
|
Req2 = cowboy_req:chunked_reply(200, [], Req),
|
||||||
{cowboy_loop, Req2, #state{}}.
|
{cowboy_loop, Req2, #state{}}.
|
||||||
|
@ -105,18 +110,18 @@ info({chunk, Chunk}, Req, State) ->
|
||||||
{ok, Req, State};
|
{ok, Req, State};
|
||||||
info(_Msg, Req, State) ->
|
info(_Msg, Req, State) ->
|
||||||
{ok, Req, State}.
|
{ok, Req, State}.
|
||||||
```
|
----
|
||||||
|
|
||||||
:: Cleaning up
|
==== Cleaning up
|
||||||
|
|
||||||
It is recommended that you set the connection header to
|
It is recommended that you set the connection header to
|
||||||
`close` when replying, as this process may be reused for
|
`close` when replying, as this process may be reused for
|
||||||
a subsequent request.
|
a subsequent request.
|
||||||
|
|
||||||
Please refer to the ^"Handlers chapter^handlers
|
Please refer to the xref:handlers[Handlers chapter]
|
||||||
for general instructions about cleaning up.
|
for general instructions about cleaning up.
|
||||||
|
|
||||||
:: Timeout
|
=== Timeout
|
||||||
|
|
||||||
By default Cowboy will not attempt to close the connection
|
By default Cowboy will not attempt to close the connection
|
||||||
if there is no activity from the client. This is not always
|
if there is no activity from the client. This is not always
|
||||||
|
@ -132,7 +137,7 @@ so there is a configurable limit for it. The default buffer
|
||||||
size is of 5000 bytes, but it may be changed by setting the
|
size is of 5000 bytes, but it may be changed by setting the
|
||||||
`loop_max_buffer` middleware environment value.
|
`loop_max_buffer` middleware environment value.
|
||||||
|
|
||||||
:: Hibernate
|
=== Hibernate
|
||||||
|
|
||||||
To save memory, you may hibernate the process in between
|
To save memory, you may hibernate the process in between
|
||||||
messages received. This is done by returning the atom
|
messages received. This is done by returning the atom
|
|
@ -1,4 +1,5 @@
|
||||||
::: Middlewares
|
[[middlewares]]
|
||||||
|
== Middlewares
|
||||||
|
|
||||||
Cowboy delegates the request processing to middleware components.
|
Cowboy delegates the request processing to middleware components.
|
||||||
By default, two middlewares are defined, for the routing and handling
|
By default, two middlewares are defined, for the routing and handling
|
||||||
|
@ -11,7 +12,7 @@ change the chain of middlewares as needed.
|
||||||
Cowboy will execute all middlewares in the given order, unless one
|
Cowboy will execute all middlewares in the given order, unless one
|
||||||
of them decides to stop processing.
|
of them decides to stop processing.
|
||||||
|
|
||||||
:: Usage
|
=== Usage
|
||||||
|
|
||||||
Middlewares only need to implement a single callback: `execute/2`.
|
Middlewares only need to implement a single callback: `execute/2`.
|
||||||
It is defined in the `cowboy_middleware` behavior.
|
It is defined in the `cowboy_middleware` behavior.
|
||||||
|
@ -34,7 +35,7 @@ to send an error back to the socket, the process will just crash. It
|
||||||
is up to the middleware to make sure that a reply is sent if something
|
is up to the middleware to make sure that a reply is sent if something
|
||||||
goes wrong.
|
goes wrong.
|
||||||
|
|
||||||
:: Configuration
|
=== Configuration
|
||||||
|
|
||||||
The middleware environment is defined as the `env` protocol option.
|
The middleware environment is defined as the `env` protocol option.
|
||||||
In the previous chapters we saw it briefly when we needed to pass
|
In the previous chapters we saw it briefly when we needed to pass
|
||||||
|
@ -56,13 +57,13 @@ environment values to perform.
|
||||||
You can update the environment by calling the `cowboy:set_env/3`
|
You can update the environment by calling the `cowboy:set_env/3`
|
||||||
convenience function, adding or replacing a value in the environment.
|
convenience function, adding or replacing a value in the environment.
|
||||||
|
|
||||||
:: Routing middleware
|
=== Routing middleware
|
||||||
|
|
||||||
The routing middleware requires the `dispatch` value. If routing
|
The routing middleware requires the `dispatch` value. If routing
|
||||||
succeeds, it will put the handler name and options in the `handler`
|
succeeds, it will put the handler name and options in the `handler`
|
||||||
and `handler_opts` values of the environment, respectively.
|
and `handler_opts` values of the environment, respectively.
|
||||||
|
|
||||||
:: Handler middleware
|
=== Handler middleware
|
||||||
|
|
||||||
The handler middleware requires the `handler` and `handler_opts`
|
The handler middleware requires the `handler` and `handler_opts`
|
||||||
values. It puts the result of the request handling into `result`.
|
values. It puts the result of the request handling into `result`.
|
|
@ -1,4 +1,5 @@
|
||||||
::: The modern Web
|
[[modern_web]]
|
||||||
|
== The modern Web
|
||||||
|
|
||||||
Let's take a look at various technologies from the beginnings
|
Let's take a look at various technologies from the beginnings
|
||||||
of the Web up to this day, and get a preview of what's
|
of the Web up to this day, and get a preview of what's
|
||||||
|
@ -8,7 +9,7 @@ Cowboy is compatible with all the technology cited in this
|
||||||
chapter except of course HTTP/2.0 which has no implementation
|
chapter except of course HTTP/2.0 which has no implementation
|
||||||
in the wild at the time of writing.
|
in the wild at the time of writing.
|
||||||
|
|
||||||
:: The prehistoric Web
|
=== The prehistoric Web
|
||||||
|
|
||||||
HTTP was initially created to serve HTML pages and only
|
HTTP was initially created to serve HTML pages and only
|
||||||
had the GET method for retrieving them. This initial
|
had the GET method for retrieving them. This initial
|
||||||
|
@ -29,7 +30,7 @@ this.
|
||||||
Most improvements done in recent years focused on reducing
|
Most improvements done in recent years focused on reducing
|
||||||
this load time and reducing the latency of the requests.
|
this load time and reducing the latency of the requests.
|
||||||
|
|
||||||
:: HTTP/1.1
|
=== HTTP/1.1
|
||||||
|
|
||||||
HTTP/1.1 quickly followed and added a keep-alive mechanism
|
HTTP/1.1 quickly followed and added a keep-alive mechanism
|
||||||
to allow using the same connection for many requests, as
|
to allow using the same connection for many requests, as
|
||||||
|
@ -47,7 +48,7 @@ clients to perform what is called as pipelining: sending many
|
||||||
requests in a row, and then processing the responses which will
|
requests in a row, and then processing the responses which will
|
||||||
be received in the same order as the requests.
|
be received in the same order as the requests.
|
||||||
|
|
||||||
:: REST
|
=== REST
|
||||||
|
|
||||||
The design of HTTP/1.1 was influenced by the REST architectural
|
The design of HTTP/1.1 was influenced by the REST architectural
|
||||||
style. REST, or REpresentational State Transfer, is a style of
|
style. REST, or REpresentational State Transfer, is a style of
|
||||||
|
@ -72,7 +73,7 @@ to implement RESTful systems.
|
||||||
REST is most often used when designing web application APIs
|
REST is most often used when designing web application APIs
|
||||||
which are generally meant to be used by executable code directly.
|
which are generally meant to be used by executable code directly.
|
||||||
|
|
||||||
:: XmlHttpRequest
|
=== XmlHttpRequest
|
||||||
|
|
||||||
Also know as AJAX, this technology allows Javascript code running
|
Also know as AJAX, this technology allows Javascript code running
|
||||||
on a web page to perform asynchronous requests to the server.
|
on a web page to perform asynchronous requests to the server.
|
||||||
|
@ -88,7 +89,7 @@ This is of course still requests initiated by the client,
|
||||||
the server still had no way of pushing data to the client
|
the server still had no way of pushing data to the client
|
||||||
on its own, so new technology appeared to allow that.
|
on its own, so new technology appeared to allow that.
|
||||||
|
|
||||||
:: Long-polling
|
=== Long-polling
|
||||||
|
|
||||||
Polling was a technique used to overcome the fact that the server
|
Polling was a technique used to overcome the fact that the server
|
||||||
cannot push data directly to the client. Therefore the client had
|
cannot push data directly to the client. Therefore the client had
|
||||||
|
@ -116,7 +117,7 @@ You probably guessed by now that long-polling is a hack, and
|
||||||
like most hacks it can suffer from unforeseen issues, in this
|
like most hacks it can suffer from unforeseen issues, in this
|
||||||
case it doesn't always play well with proxies.
|
case it doesn't always play well with proxies.
|
||||||
|
|
||||||
:: HTML5
|
=== HTML5
|
||||||
|
|
||||||
HTML5 is, of course, the HTML version after HTML4. But HTML5
|
HTML5 is, of course, the HTML version after HTML4. But HTML5
|
||||||
emerged to solve a specific problem: dynamic web applications.
|
emerged to solve a specific problem: dynamic web applications.
|
||||||
|
@ -140,7 +141,7 @@ events from the server.
|
||||||
The solution went on to become HTML5. At the time of writing
|
The solution went on to become HTML5. At the time of writing
|
||||||
it is being standardized.
|
it is being standardized.
|
||||||
|
|
||||||
:: EventSource
|
=== EventSource
|
||||||
|
|
||||||
EventSource, sometimes also called Server-Sent Events, is a
|
EventSource, sometimes also called Server-Sent Events, is a
|
||||||
technology allowing servers to push data to HTML5 applications.
|
technology allowing servers to push data to HTML5 applications.
|
||||||
|
@ -159,7 +160,7 @@ UTF-8 encoded text data. Binary data and text data encoded
|
||||||
differently are not allowed by the protocol. A heavier but
|
differently are not allowed by the protocol. A heavier but
|
||||||
more generic approach can be found in Websocket.
|
more generic approach can be found in Websocket.
|
||||||
|
|
||||||
:: Websocket
|
=== Websocket
|
||||||
|
|
||||||
Websocket is a protocol built on top of HTTP/1.1 that provides
|
Websocket is a protocol built on top of HTTP/1.1 that provides
|
||||||
a two-ways communication channel between the client and the
|
a two-ways communication channel between the client and the
|
||||||
|
@ -179,7 +180,7 @@ A Websocket connection can be used to transfer any kind of data,
|
||||||
small or big, text or binary. Because of this Websocket is
|
small or big, text or binary. Because of this Websocket is
|
||||||
sometimes used for communication between systems.
|
sometimes used for communication between systems.
|
||||||
|
|
||||||
:: SPDY
|
=== SPDY
|
||||||
|
|
||||||
SPDY is an attempt to reduce page loading time by opening a
|
SPDY is an attempt to reduce page loading time by opening a
|
||||||
single connection per server, keeping it open for subsequent
|
single connection per server, keeping it open for subsequent
|
||||||
|
@ -203,7 +204,7 @@ to a SPDY connection seamlessly if the protocol supports it.
|
||||||
The protocol itself has a few shortcomings which are being
|
The protocol itself has a few shortcomings which are being
|
||||||
fixed in HTTP/2.0.
|
fixed in HTTP/2.0.
|
||||||
|
|
||||||
:: HTTP/2.0
|
=== HTTP/2.0
|
||||||
|
|
||||||
HTTP/2.0 is the long-awaited update to the HTTP/1.1 protocol.
|
HTTP/2.0 is the long-awaited update to the HTTP/1.1 protocol.
|
||||||
It is based on SPDY although a lot has been improved at the
|
It is based on SPDY although a lot has been improved at the
|
||||||
|
@ -211,5 +212,3 @@ time of writing.
|
||||||
|
|
||||||
HTTP/2.0 is an asynchronous two-ways communication channel
|
HTTP/2.0 is an asynchronous two-ways communication channel
|
||||||
between two endpoints.
|
between two endpoints.
|
||||||
|
|
||||||
It is planned to be ready late 2014.
|
|
|
@ -1,4 +1,5 @@
|
||||||
::: Multipart requests
|
[[multipart]]
|
||||||
|
== Multipart requests
|
||||||
|
|
||||||
Multipart originates from MIME, an Internet standard that
|
Multipart originates from MIME, an Internet standard that
|
||||||
extends the format of emails. Multipart messages are a
|
extends the format of emails. Multipart messages are a
|
||||||
|
@ -24,7 +25,7 @@ Req object directly.
|
||||||
Cowboy defines two functions that allows you to get
|
Cowboy defines two functions that allows you to get
|
||||||
information about each part and read their contents.
|
information about each part and read their contents.
|
||||||
|
|
||||||
:: Structure
|
=== Structure
|
||||||
|
|
||||||
A multipart message is a list of parts. Parts may
|
A multipart message is a list of parts. Parts may
|
||||||
contain either a multipart message or a non-multipart
|
contain either a multipart message or a non-multipart
|
||||||
|
@ -32,7 +33,7 @@ content-type. This allows parts to be arranged in a
|
||||||
tree structure, although this is a rare case as far
|
tree structure, although this is a rare case as far
|
||||||
as the Web is concerned.
|
as the Web is concerned.
|
||||||
|
|
||||||
:: Form-data
|
=== Form-data
|
||||||
|
|
||||||
In the normal case, when a form is submitted, the
|
In the normal case, when a form is submitted, the
|
||||||
browser will use the `application/x-www-form-urlencoded`
|
browser will use the `application/x-www-form-urlencoded`
|
||||||
|
@ -55,7 +56,7 @@ of the files it sends this way, but you should not
|
||||||
rely on it for determining the contents of the file.
|
rely on it for determining the contents of the file.
|
||||||
Proper investigation of the contents is recommended.
|
Proper investigation of the contents is recommended.
|
||||||
|
|
||||||
:: Checking the content-type
|
=== Checking the content-type
|
||||||
|
|
||||||
While there is a variety of multipart messages, the
|
While there is a variety of multipart messages, the
|
||||||
most common on the Web is `multipart/form-data`. It's
|
most common on the Web is `multipart/form-data`. It's
|
||||||
|
@ -65,18 +66,20 @@ allows uploading files.
|
||||||
You can quickly figure out if a multipart message
|
You can quickly figure out if a multipart message
|
||||||
has been sent by parsing the `content-type` header.
|
has been sent by parsing the `content-type` header.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
{<<"multipart">>, <<"form-data">>, _}
|
{<<"multipart">>, <<"form-data">>, _}
|
||||||
= cowboy_req:parse_header(<<"content-type">>, Req).
|
= cowboy_req:parse_header(<<"content-type">>, Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
:: Reading a multipart message
|
=== Reading a multipart message
|
||||||
|
|
||||||
To read a message you have to iterate over all its
|
To read a message you have to iterate over all its
|
||||||
parts. Then, for each part, you can inspect its headers
|
parts. Then, for each part, you can inspect its headers
|
||||||
and read its body.
|
and read its body.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
multipart(Req) ->
|
multipart(Req) ->
|
||||||
case cowboy_req:part(Req) of
|
case cowboy_req:part(Req) of
|
||||||
{ok, _Headers, Req2} ->
|
{ok, _Headers, Req2} ->
|
||||||
|
@ -85,7 +88,7 @@ multipart(Req) ->
|
||||||
{done, Req2} ->
|
{done, Req2} ->
|
||||||
Req2
|
Req2
|
||||||
end.
|
end.
|
||||||
```
|
----
|
||||||
|
|
||||||
Parts do not have a size limit. When a part body is
|
Parts do not have a size limit. When a part body is
|
||||||
too big, Cowboy will return what it read so far and
|
too big, Cowboy will return what it read so far and
|
||||||
|
@ -100,7 +103,8 @@ is a file being uploaded.
|
||||||
This can be used for example to allow large part bodies
|
This can be used for example to allow large part bodies
|
||||||
for files but crash when a normal field is too large.
|
for files but crash when a normal field is too large.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
multipart(Req) ->
|
multipart(Req) ->
|
||||||
case cowboy_req:part(Req) of
|
case cowboy_req:part(Req) of
|
||||||
{ok, Headers, Req2} ->
|
{ok, Headers, Req2} ->
|
||||||
|
@ -123,14 +127,14 @@ stream_file(Req) ->
|
||||||
{more, _Body, Req2} ->
|
{more, _Body, Req2} ->
|
||||||
stream_file(Req2)
|
stream_file(Req2)
|
||||||
end.
|
end.
|
||||||
```
|
----
|
||||||
|
|
||||||
By default the body chunk Cowboy will return is limited
|
By default the body chunk Cowboy will return is limited
|
||||||
to 8MB. This can of course be overriden. Both functions
|
to 8MB. This can of course be overriden. Both functions
|
||||||
can take a second argument, the same list of options that
|
can take a second argument, the same list of options that
|
||||||
will be passed to `cowboy_req:body/2` function.
|
will be passed to `cowboy_req:body/2` function.
|
||||||
|
|
||||||
:: Skipping unwanted parts
|
=== Skipping unwanted parts
|
||||||
|
|
||||||
If you do not want to read a part's body, you can skip it.
|
If you do not want to read a part's body, you can skip it.
|
||||||
Skipping is easy. If you do not call the function to read
|
Skipping is easy. If you do not call the function to read
|
||||||
|
@ -140,7 +144,8 @@ you request the next part.
|
||||||
The following snippet reads all part headers and skips
|
The following snippet reads all part headers and skips
|
||||||
all bodies:
|
all bodies:
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
multipart(Req) ->
|
multipart(Req) ->
|
||||||
case cowboy_req:part(Req) of
|
case cowboy_req:part(Req) of
|
||||||
{ok, _Headers, Req2} ->
|
{ok, _Headers, Req2} ->
|
||||||
|
@ -148,7 +153,7 @@ multipart(Req) ->
|
||||||
{done, Req2} ->
|
{done, Req2} ->
|
||||||
Req2
|
Req2
|
||||||
end.
|
end.
|
||||||
```
|
----
|
||||||
|
|
||||||
Similarly, if you start reading the body and it ends up
|
Similarly, if you start reading the body and it ends up
|
||||||
being too big, you can simply continue with the next part,
|
being too big, you can simply continue with the next part,
|
|
@ -1,10 +1,11 @@
|
||||||
::: Request overview
|
[[overview]]
|
||||||
|
== Request overview
|
||||||
|
|
||||||
This chapter explains the different steps a request
|
This chapter explains the different steps a request
|
||||||
goes through until a response is sent, along with
|
goes through until a response is sent, along with
|
||||||
details of the Cowboy implementation.
|
details of the Cowboy implementation.
|
||||||
|
|
||||||
:: Request/response
|
=== Request/response
|
||||||
|
|
||||||
As you already know, HTTP clients connect to the server and
|
As you already know, HTTP clients connect to the server and
|
||||||
send a request for a resource; the server then sends a
|
send a request for a resource; the server then sends a
|
||||||
|
@ -18,7 +19,7 @@ add like writing logs.
|
||||||
|
|
||||||
Requests take the following route in Cowboy:
|
Requests take the following route in Cowboy:
|
||||||
|
|
||||||
^"HTTP request/response flowchart^!http_req_resp.png
|
image::http_req_resp.png[HTTP request/response flowchart]
|
||||||
|
|
||||||
This shows the default middlewares, but they may be
|
This shows the default middlewares, but they may be
|
||||||
configured differently in your setup. The dark green
|
configured differently in your setup. The dark green
|
||||||
|
@ -42,7 +43,7 @@ When a response is sent, you can optionally modify it
|
||||||
or act upon it by enabling the `onresponse` hook. By
|
or act upon it by enabling the `onresponse` hook. By
|
||||||
default the response is sent directly to the client.
|
default the response is sent directly to the client.
|
||||||
|
|
||||||
:: And then?
|
=== And then?
|
||||||
|
|
||||||
Behavior depends on what protocol is in use.
|
Behavior depends on what protocol is in use.
|
||||||
|
|
||||||
|
@ -59,7 +60,7 @@ asynchronously on the same connection. Details on what
|
||||||
this means for your application is described in this
|
this means for your application is described in this
|
||||||
chapter.
|
chapter.
|
||||||
|
|
||||||
:: Keep-alive (HTTP/1.1)
|
=== Keep-alive (HTTP/1.1)
|
||||||
|
|
||||||
With HTTP/1.1, the connection may be left open for
|
With HTTP/1.1, the connection may be left open for
|
||||||
subsequent requests to come. This mechanism is called
|
subsequent requests to come. This mechanism is called
|
||||||
|
@ -79,11 +80,12 @@ as the reply is sent.
|
||||||
|
|
||||||
This snippet will force Cowboy to close the connection.
|
This snippet will force Cowboy to close the connection.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
Req2 = cowboy_req:reply(200, [
|
Req2 = cowboy_req:reply(200, [
|
||||||
{<<"connection">>, <<"close">>},
|
{<<"connection">>, <<"close">>},
|
||||||
], <<"Closing the socket in 3.. 2.. 1..">>, Req).
|
], <<"Closing the socket in 3.. 2.. 1..">>, Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
Cowboy will only accept a certain number of new requests
|
Cowboy will only accept a certain number of new requests
|
||||||
on the same connection. By default it will run up to 100
|
on the same connection. By default it will run up to 100
|
||||||
|
@ -91,12 +93,13 @@ requests. This number can be changed by setting the
|
||||||
`max_keepalive` configuration value when starting an
|
`max_keepalive` configuration value when starting an
|
||||||
HTTP listener.
|
HTTP listener.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
cowboy:start_http(my_http_listener, 100, [{port, 8080}], [
|
cowboy:start_http(my_http_listener, 100, [{port, 8080}], [
|
||||||
{env, [{dispatch, Dispatch}]},
|
{env, [{dispatch, Dispatch}]},
|
||||||
{max_keepalive, 5}
|
{max_keepalive, 5}
|
||||||
]).
|
]).
|
||||||
```
|
----
|
||||||
|
|
||||||
Cowboy implements the keep-alive mechanism by reusing
|
Cowboy implements the keep-alive mechanism by reusing
|
||||||
the same process for all requests. This allows Cowboy
|
the same process for all requests. This allows Cowboy
|
||||||
|
@ -106,7 +109,7 @@ But it also means you need to clean up if you do have
|
||||||
code with side effects. The `terminate/3` function can
|
code with side effects. The `terminate/3` function can
|
||||||
be used for this purpose.
|
be used for this purpose.
|
||||||
|
|
||||||
:: Pipelining (HTTP/1.1)
|
=== Pipelining (HTTP/1.1)
|
||||||
|
|
||||||
While HTTP is designed as a sequential protocol, with
|
While HTTP is designed as a sequential protocol, with
|
||||||
the client sending a request and then waiting for the
|
the client sending a request and then waiting for the
|
||||||
|
@ -123,7 +126,7 @@ static files for example.
|
||||||
|
|
||||||
This is handled automatically by the server.
|
This is handled automatically by the server.
|
||||||
|
|
||||||
:: Asynchronous requests (SPDY)
|
=== Asynchronous requests (SPDY)
|
||||||
|
|
||||||
In SPDY, the client can send a request at any time.
|
In SPDY, the client can send a request at any time.
|
||||||
And the server can send a response at any time too.
|
And the server can send a response at any time too.
|
|
@ -1,10 +1,11 @@
|
||||||
::: The Req object
|
[[req]]
|
||||||
|
== The Req object
|
||||||
|
|
||||||
The Req object is this variable that you will use to obtain
|
The Req object is this variable that you will use to obtain
|
||||||
information about a request, read the body of the request
|
information about a request, read the body of the request
|
||||||
and send a response.
|
and send a response.
|
||||||
|
|
||||||
:: A special variable
|
=== A special variable
|
||||||
|
|
||||||
While we call it an "object", it is not an object in the
|
While we call it an "object", it is not an object in the
|
||||||
OOP sense of the term. In fact it is completely opaque
|
OOP sense of the term. In fact it is completely opaque
|
||||||
|
@ -27,7 +28,7 @@ For example, when streaming the request body, the
|
||||||
function will return the body by chunks, one at a
|
function will return the body by chunks, one at a
|
||||||
time, until there is none left.
|
time, until there is none left.
|
||||||
|
|
||||||
:: Overview of the cowboy_req interface
|
=== Overview of the cowboy_req interface
|
||||||
|
|
||||||
With the exception of functions manipulating the request
|
With the exception of functions manipulating the request
|
||||||
body, all functions return a single value. Depending on
|
body, all functions return a single value. Depending on
|
||||||
|
@ -44,7 +45,7 @@ This chapter covers the access functions mainly. Cookies,
|
||||||
request body and response functions are covered in their
|
request body and response functions are covered in their
|
||||||
own chapters.
|
own chapters.
|
||||||
|
|
||||||
:: Request
|
=== Request
|
||||||
|
|
||||||
When a client performs a request, it first sends a few required
|
When a client performs a request, it first sends a few required
|
||||||
values. They are sent differently depending on the protocol
|
values. They are sent differently depending on the protocol
|
||||||
|
@ -56,31 +57,28 @@ The method identifies the action. Standard methods include
|
||||||
GET, HEAD, OPTIONS, PATCH, POST, PUT, DELETE. Method names
|
GET, HEAD, OPTIONS, PATCH, POST, PUT, DELETE. Method names
|
||||||
are case sensitive.
|
are case sensitive.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Method = cowboy_req:method(Req).
|
Method = cowboy_req:method(Req).
|
||||||
```
|
|
||||||
|
|
||||||
The host, port and path parts of the URL identify the resource
|
The host, port and path parts of the URL identify the resource
|
||||||
being accessed. The host and port information may not be
|
being accessed. The host and port information may not be
|
||||||
available if the client uses HTTP/1.0.
|
available if the client uses HTTP/1.0.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Host = cowboy_req:host(Req),
|
Host = cowboy_req:host(Req),
|
||||||
Port = cowboy_req:port(Req),
|
Port = cowboy_req:port(Req),
|
||||||
Path = cowboy_req:path(Req).
|
Path = cowboy_req:path(Req).
|
||||||
```
|
|
||||||
|
|
||||||
The version used by the client can of course also be obtained.
|
The version used by the client can of course also be obtained.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Version = cowboy_req:version(Req).
|
Version = cowboy_req:version(Req).
|
||||||
```
|
|
||||||
|
|
||||||
Do note however that clients claiming to implement one version
|
Do note however that clients claiming to implement one version
|
||||||
of the protocol does not mean they implement it fully, or even
|
of the protocol does not mean they implement it fully, or even
|
||||||
properly.
|
properly.
|
||||||
|
|
||||||
:: Bindings
|
=== Bindings
|
||||||
|
|
||||||
After routing the request, bindings are available. Bindings
|
After routing the request, bindings are available. Bindings
|
||||||
are these parts of the host or path that you chose to extract
|
are these parts of the host or path that you chose to extract
|
||||||
|
@ -89,61 +87,53 @@ when defining the routes of your application.
|
||||||
You can fetch a single binding. The value will be `undefined`
|
You can fetch a single binding. The value will be `undefined`
|
||||||
if the binding doesn't exist.
|
if the binding doesn't exist.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Binding = cowboy_req:binding(my_binding, Req).
|
Binding = cowboy_req:binding(my_binding, Req).
|
||||||
```
|
|
||||||
|
|
||||||
If you need a different value when the binding doesn't exist,
|
If you need a different value when the binding doesn't exist,
|
||||||
you can change the default.
|
you can change the default.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Binding = cowboy_req:binding(my_binding, Req, 42).
|
Binding = cowboy_req:binding(my_binding, Req, 42).
|
||||||
```
|
|
||||||
|
|
||||||
You can also obtain all bindings in one call. They will be
|
You can also obtain all bindings in one call. They will be
|
||||||
returned as a list of key/value tuples.
|
returned as a list of key/value tuples.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
AllBindings = cowboy_req:bindings(Req).
|
AllBindings = cowboy_req:bindings(Req).
|
||||||
```
|
|
||||||
|
|
||||||
If you used `...` at the beginning of the route's pattern
|
If you used `...` at the beginning of the route's pattern
|
||||||
for the host, you can retrieve the matched part of the host.
|
for the host, you can retrieve the matched part of the host.
|
||||||
The value will be `undefined` otherwise.
|
The value will be `undefined` otherwise.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
HostInfo = cowboy_req:host_info(Req).
|
HostInfo = cowboy_req:host_info(Req).
|
||||||
```
|
|
||||||
|
|
||||||
Similarly, if you used `...` at the end of the route's
|
Similarly, if you used `...` at the end of the route's
|
||||||
pattern for the path, you can retrieve the matched part,
|
pattern for the path, you can retrieve the matched part,
|
||||||
or get `undefined` otherwise.
|
or get `undefined` otherwise.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
PathInfo = cowboy_req:path_info(Req).
|
PathInfo = cowboy_req:path_info(Req).
|
||||||
```
|
|
||||||
|
|
||||||
:: Query string
|
=== Query string
|
||||||
|
|
||||||
The raw query string can be obtained directly.
|
The raw query string can be obtained directly.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Qs = cowboy_req:qs(Req).
|
Qs = cowboy_req:qs(Req).
|
||||||
```
|
|
||||||
|
|
||||||
You can parse the query string and then use standard library
|
You can parse the query string and then use standard library
|
||||||
functions to access individual values.
|
functions to access individual values.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
QsVals = cowboy_req:parse_qs(Req),
|
QsVals = cowboy_req:parse_qs(Req),
|
||||||
{_, Lang} = lists:keyfind(<<"lang">>, 1, QsVals).
|
{_, Lang} = lists:keyfind(<<"lang">>, 1, QsVals).
|
||||||
```
|
|
||||||
|
|
||||||
You can match the query string into a map.
|
You can match the query string into a map.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
#{id := ID, lang := Lang} = cowboy_req:match_qs([id, lang], Req).
|
#{id := ID, lang := Lang} = cowboy_req:match_qs([id, lang], Req).
|
||||||
```
|
|
||||||
|
|
||||||
You can use constraints to validate the values while matching
|
You can use constraints to validate the values while matching
|
||||||
them. The following snippet will crash if the `id` value is
|
them. The following snippet will crash if the `id` value is
|
||||||
|
@ -151,9 +141,8 @@ not an integer number or if the `lang` value is empty. Additionally
|
||||||
the `id` value will be converted to an integer term, saving
|
the `id` value will be converted to an integer term, saving
|
||||||
you a conversion step.
|
you a conversion step.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
QsMap = cowboy_req:match_qs([{id, int}, {lang, nonempty}], Req).
|
QsMap = cowboy_req:match_qs([{id, int}, {lang, nonempty}], Req).
|
||||||
```
|
|
||||||
|
|
||||||
Note that in the case of duplicate query string keys, the map
|
Note that in the case of duplicate query string keys, the map
|
||||||
value will become a list of the different values.
|
value will become a list of the different values.
|
||||||
|
@ -164,58 +153,50 @@ A default value can be provided. The default will be used
|
||||||
if the `lang` key is not found. It will not be used if
|
if the `lang` key is not found. It will not be used if
|
||||||
the key is found but has an empty value.
|
the key is found but has an empty value.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
#{lang := Lang} = cowboy_req:match_qs([{lang, [], <<"en-US">>}], Req).
|
#{lang := Lang} = cowboy_req:match_qs([{lang, [], <<"en-US">>}], Req).
|
||||||
```
|
|
||||||
|
|
||||||
If no default is provided and the value is missing, the
|
If no default is provided and the value is missing, the
|
||||||
query string is deemed invalid and the process will crash.
|
query string is deemed invalid and the process will crash.
|
||||||
|
|
||||||
:: Request URL
|
=== Request URL
|
||||||
|
|
||||||
You can reconstruct the full URL of the resource.
|
You can reconstruct the full URL of the resource.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
URL = cowboy_req:url(Req).
|
URL = cowboy_req:url(Req).
|
||||||
```
|
|
||||||
|
|
||||||
You can also obtain only the base of the URL, excluding the
|
You can also obtain only the base of the URL, excluding the
|
||||||
path and query string.
|
path and query string.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
BaseURL = cowboy_req:host_url(Req).
|
BaseURL = cowboy_req:host_url(Req).
|
||||||
```
|
|
||||||
|
|
||||||
:: Headers
|
=== Headers
|
||||||
|
|
||||||
Cowboy allows you to obtain the header values as string,
|
Cowboy allows you to obtain the header values as string,
|
||||||
or parsed into a more meaningful representation.
|
or parsed into a more meaningful representation.
|
||||||
|
|
||||||
This will get the string value of a header.
|
This will get the string value of a header.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
HeaderVal = cowboy_req:header(<<"content-type">>, Req).
|
HeaderVal = cowboy_req:header(<<"content-type">>, Req).
|
||||||
```
|
|
||||||
|
|
||||||
You can of course set a default in case the header is missing.
|
You can of course set a default in case the header is missing.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
HeaderVal
|
HeaderVal = cowboy_req:header(<<"content-type">>, Req, <<"text/plain">>).
|
||||||
= cowboy_req:header(<<"content-type">>, Req, <<"text/plain">>).
|
|
||||||
```
|
|
||||||
|
|
||||||
And also obtain all headers.
|
And also obtain all headers.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
AllHeaders = cowboy_req:headers(Req).
|
AllHeaders = cowboy_req:headers(Req).
|
||||||
```
|
|
||||||
|
|
||||||
To parse the previous header, simply call `parse_header/{2,3}`
|
To parse the previous header, simply call `parse_header/{2,3}`
|
||||||
where you would call `header/{2,3}` otherwise.
|
where you would call `header/{2,3}` otherwise.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req).
|
ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req).
|
||||||
```
|
|
||||||
|
|
||||||
Cowboy will crash if it doesn't know how to parse the given
|
Cowboy will crash if it doesn't know how to parse the given
|
||||||
header, or if the value is invalid.
|
header, or if the value is invalid.
|
||||||
|
@ -224,15 +205,16 @@ 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
|
value you specify here is the parsed value you'd like to get
|
||||||
by default.
|
by default.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req,
|
ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req,
|
||||||
{<<"text">>, <<"plain">>, []}).
|
{<<"text">>, <<"plain">>, []}).
|
||||||
```
|
----
|
||||||
|
|
||||||
The list of known headers and default values is defined in the
|
The list of known headers and default values is defined in the
|
||||||
manual.
|
manual.
|
||||||
|
|
||||||
:: Meta
|
=== Meta
|
||||||
|
|
||||||
Cowboy will sometimes associate some meta information with
|
Cowboy will sometimes associate some meta information with
|
||||||
the request. Built-in meta values are listed in the manual
|
the request. Built-in meta values are listed in the manual
|
||||||
|
@ -241,29 +223,25 @@ for their respective modules.
|
||||||
This will get a meta value. The returned value will be `undefined`
|
This will get a meta value. The returned value will be `undefined`
|
||||||
if it isn't defined.
|
if it isn't defined.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
MetaVal = cowboy_req:meta(websocket_version, Req).
|
MetaVal = cowboy_req:meta(websocket_version, Req).
|
||||||
```
|
|
||||||
|
|
||||||
You can change the default value if needed.
|
You can change the default value if needed.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
MetaVal = cowboy_req:meta(websocket_version, Req, 13).
|
MetaVal = cowboy_req:meta(websocket_version, Req, 13).
|
||||||
```
|
|
||||||
|
|
||||||
You can also define your own meta values. The name must be
|
You can also define your own meta values. The name must be
|
||||||
an `atom()`.
|
an `atom()`.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Req2 = cowboy_req:set_meta(the_answer, 42, Req).
|
Req2 = cowboy_req:set_meta(the_answer, 42, Req).
|
||||||
```
|
|
||||||
|
|
||||||
:: Peer
|
=== Peer
|
||||||
|
|
||||||
You can obtain the peer address and port number. This is
|
You can obtain the peer address and port number. This is
|
||||||
not necessarily the actual IP and port of the client, but
|
not necessarily the actual IP and port of the client, but
|
||||||
rather the one of the machine that connected to the server.
|
rather the one of the machine that connected to the server.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
{IP, Port} = cowboy_req:peer(Req).
|
{IP, Port} = cowboy_req:peer(Req).
|
||||||
```
|
|
|
@ -1,4 +1,5 @@
|
||||||
::: Reading the request body
|
[[req_body]]
|
||||||
|
== Reading the request body
|
||||||
|
|
||||||
The Req object also allows you to read the request body.
|
The Req object also allows you to read the request body.
|
||||||
|
|
||||||
|
@ -16,13 +17,12 @@ parse in a single call for form urlencoded formats or
|
||||||
multipart. All of these except multipart are covered in
|
multipart. All of these except multipart are covered in
|
||||||
this chapter. Multipart is covered later on in the guide.
|
this chapter. Multipart is covered later on in the guide.
|
||||||
|
|
||||||
:: Check for request body
|
=== Check for request body
|
||||||
|
|
||||||
You can check whether a body was sent with the request.
|
You can check whether a body was sent with the request.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
cowboy_req:has_body(Req).
|
cowboy_req:has_body(Req).
|
||||||
```
|
|
||||||
|
|
||||||
It will return `true` if there is a request body, and
|
It will return `true` if there is a request body, and
|
||||||
`false` otherwise.
|
`false` otherwise.
|
||||||
|
@ -31,14 +31,13 @@ Note that it is generally safe to assume that a body is
|
||||||
sent for `POST`, `PUT` and `PATCH` requests, without
|
sent for `POST`, `PUT` and `PATCH` requests, without
|
||||||
having to explicitly check for it.
|
having to explicitly check for it.
|
||||||
|
|
||||||
:: Request body length
|
=== Request body length
|
||||||
|
|
||||||
You can obtain the body length if it was sent with the
|
You can obtain the body length if it was sent with the
|
||||||
request.
|
request.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Length = cowboy_req:body_length(Req).
|
Length = cowboy_req:body_length(Req).
|
||||||
```
|
|
||||||
|
|
||||||
The value returned will be `undefined` if the length
|
The value returned will be `undefined` if the length
|
||||||
couldn't be figured out from the request headers. If
|
couldn't be figured out from the request headers. If
|
||||||
|
@ -46,26 +45,23 @@ there's a body but no length is given, this means that
|
||||||
the chunked transfer-encoding was used. You can read
|
the chunked transfer-encoding was used. You can read
|
||||||
chunked bodies by using the stream functions.
|
chunked bodies by using the stream functions.
|
||||||
|
|
||||||
:: Reading the body
|
=== Reading the body
|
||||||
|
|
||||||
You can read the whole body directly in one call.
|
You can read the whole body directly in one call.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
{ok, Body, Req2} = cowboy_req:body(Req).
|
{ok, Body, Req2} = cowboy_req:body(Req).
|
||||||
```
|
|
||||||
|
|
||||||
By default, Cowboy will attempt to read up to a
|
By default, Cowboy will attempt to read up to a
|
||||||
size of 8MB. You can override this limit as needed.
|
size of 8MB. You can override this limit as needed.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
{ok, Body, Req2} = cowboy_req:body(Req, [{length, 100000000}]).
|
{ok, Body, Req2} = cowboy_req:body(Req, [{length, 100000000}]).
|
||||||
```
|
|
||||||
|
|
||||||
You can also disable it.
|
You can also disable it.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
{ok, Body, Req2} = cowboy_req:body(Req, [{length, infinity}]).
|
{ok, Body, Req2} = cowboy_req:body(Req, [{length, infinity}]).
|
||||||
```
|
|
||||||
|
|
||||||
It is recommended that you do not disable it for public
|
It is recommended that you do not disable it for public
|
||||||
facing websites.
|
facing websites.
|
||||||
|
@ -74,7 +70,7 @@ If the body is larger than the limit, then Cowboy will return
|
||||||
a `more` tuple instead, allowing you to stream it if you
|
a `more` tuple instead, allowing you to stream it if you
|
||||||
would like to.
|
would like to.
|
||||||
|
|
||||||
:: Streaming the body
|
=== Streaming the body
|
||||||
|
|
||||||
You can stream the request body by chunks.
|
You can stream the request body by chunks.
|
||||||
|
|
||||||
|
@ -82,7 +78,8 @@ Cowboy returns a `more` tuple when there is more body to
|
||||||
be read, and an `ok` tuple for the last chunk. This allows
|
be read, and an `ok` tuple for the last chunk. This allows
|
||||||
you to loop over all chunks.
|
you to loop over all chunks.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
body_to_console(Req) ->
|
body_to_console(Req) ->
|
||||||
case cowboy_req:body(Req) of
|
case cowboy_req:body(Req) of
|
||||||
{ok, Data, Req2} ->
|
{ok, Data, Req2} ->
|
||||||
|
@ -92,12 +89,12 @@ body_to_console(Req) ->
|
||||||
io:format("~s", [Data]),
|
io:format("~s", [Data]),
|
||||||
body_to_console(Req2)
|
body_to_console(Req2)
|
||||||
end.
|
end.
|
||||||
```
|
----
|
||||||
|
|
||||||
You can of course set the `length` option to configure the
|
You can of course set the `length` option to configure the
|
||||||
size of chunks.
|
size of chunks.
|
||||||
|
|
||||||
:: Rate of data transmission
|
=== Rate of data transmission
|
||||||
|
|
||||||
You can control the rate of data transmission by setting
|
You can control the rate of data transmission by setting
|
||||||
options when calling body functions. This applies not only
|
options when calling body functions. This applies not only
|
||||||
|
@ -110,7 +107,7 @@ to be received from the socket at once, in bytes.
|
||||||
The `read_timeout` option defines the time Cowboy waits
|
The `read_timeout` option defines the time Cowboy waits
|
||||||
before that amount is received, in milliseconds.
|
before that amount is received, in milliseconds.
|
||||||
|
|
||||||
:: Transfer and content decoding
|
=== Transfer and content decoding
|
||||||
|
|
||||||
Cowboy will by default decode the chunked transfer-encoding
|
Cowboy will by default decode the chunked transfer-encoding
|
||||||
if any. It will not decode any content-encoding by default.
|
if any. It will not decode any content-encoding by default.
|
||||||
|
@ -122,28 +119,27 @@ ignored.
|
||||||
|
|
||||||
The following example shows how to set both options.
|
The following example shows how to set both options.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
{ok, Data, Req2} = cowboy_req:body(Req, [
|
{ok, Data, Req2} = cowboy_req:body(Req, [
|
||||||
{transfer_decode, fun transfer_decode/2, TransferState},
|
{transfer_decode, fun transfer_decode/2, TransferState},
|
||||||
{content_decode, fun content_decode/1}
|
{content_decode, fun content_decode/1}
|
||||||
]).
|
]).
|
||||||
```
|
----
|
||||||
|
|
||||||
:: Reading a form urlencoded body
|
=== Reading a form urlencoded body
|
||||||
|
|
||||||
You can directly obtain a list of key/value pairs if the
|
You can directly obtain a list of key/value pairs if the
|
||||||
body was sent using the application/x-www-form-urlencoded
|
body was sent using the application/x-www-form-urlencoded
|
||||||
content-type.
|
content-type.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
{ok, KeyValues, Req2} = cowboy_req:body_qs(Req).
|
{ok, KeyValues, Req2} = cowboy_req:body_qs(Req).
|
||||||
```
|
|
||||||
|
|
||||||
You can then retrieve an individual value from that list.
|
You can then retrieve an individual value from that list.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
{_, Lang} = lists:keyfind(lang, 1, KeyValues).
|
{_, Lang} = lists:keyfind(lang, 1, KeyValues).
|
||||||
```
|
|
||||||
|
|
||||||
You should not attempt to match on the list as the order
|
You should not attempt to match on the list as the order
|
||||||
of the values is undefined.
|
of the values is undefined.
|
||||||
|
@ -152,7 +148,5 @@ By default Cowboy will reject bodies with a size above
|
||||||
64KB when using this function. You can override this limit
|
64KB when using this function. You can override this limit
|
||||||
by setting the `length` option.
|
by setting the `length` option.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
{ok, KeyValues, Req2} = cowboy_req:body_qs(Req,
|
{ok, KeyValues, Req2} = cowboy_req:body_qs(Req, [{length, 2000000}]).
|
||||||
[{length, 2000000}]).
|
|
||||||
```
|
|
|
@ -1,10 +1,11 @@
|
||||||
::: Designing a resource handler
|
[[resource_design]]
|
||||||
|
== Designing a resource handler
|
||||||
|
|
||||||
This chapter aims to provide you with a list of questions
|
This chapter aims to provide you with a list of questions
|
||||||
you must answer in order to write a good resource handler.
|
you must answer in order to write a good resource handler.
|
||||||
It is meant to be usable as a step by step guide.
|
It is meant to be usable as a step by step guide.
|
||||||
|
|
||||||
:: The service
|
=== The service
|
||||||
|
|
||||||
Can the service become unavailable, and when it does, can
|
Can the service become unavailable, and when it does, can
|
||||||
we detect it? For example database connectivity problems
|
we detect it? For example database connectivity problems
|
||||||
|
@ -17,7 +18,7 @@ more than the standard OPTIONS, HEAD, GET, PUT, POST,
|
||||||
PATCH and DELETE? Are we not using one of those at all?
|
PATCH and DELETE? Are we not using one of those at all?
|
||||||
Implement the `known_methods` callback.
|
Implement the `known_methods` callback.
|
||||||
|
|
||||||
:: Type of resource handler
|
=== Type of resource handler
|
||||||
|
|
||||||
Am I writing a handler for a collection of resources,
|
Am I writing a handler for a collection of resources,
|
||||||
or for a single resource?
|
or for a single resource?
|
||||||
|
@ -26,7 +27,7 @@ The semantics for each of these are quite different.
|
||||||
You should not mix collection and single resource in
|
You should not mix collection and single resource in
|
||||||
the same handler.
|
the same handler.
|
||||||
|
|
||||||
:: Collection handler
|
=== Collection handler
|
||||||
|
|
||||||
Skip this section if you are not doing a collection.
|
Skip this section if you are not doing a collection.
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ operation is atomic. The PATCH operation may
|
||||||
be used for such things as reordering; adding,
|
be used for such things as reordering; adding,
|
||||||
modifying or deleting parts of the collection.
|
modifying or deleting parts of the collection.
|
||||||
|
|
||||||
:: Single resource handler
|
=== Single resource handler
|
||||||
|
|
||||||
Skip this section if you are doing a collection.
|
Skip this section if you are doing a collection.
|
||||||
|
|
||||||
|
@ -98,7 +99,7 @@ operation is atomic. The PATCH operation may
|
||||||
be used for adding, removing or modifying specific
|
be used for adding, removing or modifying specific
|
||||||
values in the resource.
|
values in the resource.
|
||||||
|
|
||||||
:: The resource
|
=== The resource
|
||||||
|
|
||||||
Following the above discussion, implement the
|
Following the above discussion, implement the
|
||||||
`allowed_methods` callback.
|
`allowed_methods` callback.
|
||||||
|
@ -125,7 +126,7 @@ Is there any constraints on the length of the resource URI?
|
||||||
For example the URI may be used as a key in storage and may
|
For example the URI may be used as a key in storage and may
|
||||||
have a limit in length. Implement `uri_too_long`.
|
have a limit in length. Implement `uri_too_long`.
|
||||||
|
|
||||||
:: Representations
|
=== Representations
|
||||||
|
|
||||||
What media types do I provide? If text based, what charsets
|
What media types do I provide? If text based, what charsets
|
||||||
are provided? What languages do I provide?
|
are provided? What languages do I provide?
|
||||||
|
@ -149,7 +150,7 @@ representation available? Send a list of available
|
||||||
representations in the response body and implement
|
representations in the response body and implement
|
||||||
the `multiple_choices` callback.
|
the `multiple_choices` callback.
|
||||||
|
|
||||||
:: Redirections
|
=== Redirections
|
||||||
|
|
||||||
Do I need to keep track of what resources were deleted?
|
Do I need to keep track of what resources were deleted?
|
||||||
For example you may have a mechanism where moving a
|
For example you may have a mechanism where moving a
|
||||||
|
@ -161,7 +162,7 @@ it is explicitly temporary, for example due to maintenance,
|
||||||
implement the `moved_temporarily` callback. Otherwise,
|
implement the `moved_temporarily` callback. Otherwise,
|
||||||
implement the `moved_permanently` callback.
|
implement the `moved_permanently` callback.
|
||||||
|
|
||||||
:: The request
|
=== The request
|
||||||
|
|
||||||
Do we need to perform extra checks to make sure the request
|
Do we need to perform extra checks to make sure the request
|
||||||
is valid? Cowboy will do many checks when receiving the
|
is valid? Cowboy will do many checks when receiving the
|
||||||
|
@ -176,20 +177,20 @@ to accept? Implement `valid_entity_length`.
|
||||||
Finally, take a look at the sections corresponding to the
|
Finally, take a look at the sections corresponding to the
|
||||||
methods you are implementing.
|
methods you are implementing.
|
||||||
|
|
||||||
:: OPTIONS method
|
=== OPTIONS method
|
||||||
|
|
||||||
Cowboy by default will send back a list of allowed methods.
|
Cowboy by default will send back a list of allowed methods.
|
||||||
Do I need to add more information to the response? Implement
|
Do I need to add more information to the response? Implement
|
||||||
the `options` method.
|
the `options` method.
|
||||||
|
|
||||||
:: GET and HEAD methods
|
=== GET and HEAD methods
|
||||||
|
|
||||||
If you implement the methods GET and/or HEAD, you must
|
If you implement the methods GET and/or HEAD, you must
|
||||||
implement one `ProvideResource` callback for each
|
implement one `ProvideResource` callback for each
|
||||||
content-type returned by the `content_types_provided`
|
content-type returned by the `content_types_provided`
|
||||||
callback.
|
callback.
|
||||||
|
|
||||||
:: PUT, POST and PATCH methods
|
=== PUT, POST and PATCH methods
|
||||||
|
|
||||||
If you implement the methods PUT, POST and/or PATCH,
|
If you implement the methods PUT, POST and/or PATCH,
|
||||||
you must implement the `content_types_accepted` callback,
|
you must implement the `content_types_accepted` callback,
|
||||||
|
@ -208,7 +209,7 @@ a resource? Do we want to make sure that two updates around
|
||||||
the same time are not cancelling one another? Implement the
|
the same time are not cancelling one another? Implement the
|
||||||
`is_conflict` callback.
|
`is_conflict` callback.
|
||||||
|
|
||||||
:: DELETE methods
|
=== DELETE methods
|
||||||
|
|
||||||
If you implement the method DELETE, you must implement
|
If you implement the method DELETE, you must implement
|
||||||
the `delete_resource` callback.
|
the `delete_resource` callback.
|
|
@ -1,4 +1,5 @@
|
||||||
::: Sending a response
|
[[resp]]
|
||||||
|
== Sending a response
|
||||||
|
|
||||||
The Req object also allows you to send a response.
|
The Req object also allows you to send a response.
|
||||||
|
|
||||||
|
@ -9,36 +10,37 @@ with its body streamed by chunks of arbitrary size.
|
||||||
You can also set headers or the response body in advance
|
You can also set headers or the response body in advance
|
||||||
and Cowboy will use them when you finally do reply.
|
and Cowboy will use them when you finally do reply.
|
||||||
|
|
||||||
:: Reply
|
=== Reply
|
||||||
|
|
||||||
You can send a reply with no particular headers or body.
|
You can send a reply with no particular headers or body.
|
||||||
Cowboy will make sure to send the mandatory headers with
|
Cowboy will make sure to send the mandatory headers with
|
||||||
the response.
|
the response.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Req2 = cowboy_req:reply(200, Req).
|
Req2 = cowboy_req:reply(200, Req).
|
||||||
```
|
|
||||||
|
|
||||||
You can define headers to be sent with the response. Note
|
You can define headers to be sent with the response. Note
|
||||||
that header names must be lowercase. Again, Cowboy will
|
that header names must be lowercase. Again, Cowboy will
|
||||||
make sure to send the mandatory headers with the response.
|
make sure to send the mandatory headers with the response.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
Req2 = cowboy_req:reply(303, [
|
Req2 = cowboy_req:reply(303, [
|
||||||
{<<"location">>, <<"http://ninenines.eu">>}
|
{<<"location">>, <<"http://ninenines.eu">>}
|
||||||
], Req).
|
], Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
You can override headers that Cowboy would send otherwise.
|
You can override headers that Cowboy would send otherwise.
|
||||||
Any header set by the user will be used over the ones set
|
Any header set by the user will be used over the ones set
|
||||||
by Cowboy. For example, you can advertise yourself as a
|
by Cowboy. For example, you can advertise yourself as a
|
||||||
different server.
|
different server.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
Req2 = cowboy_req:reply(200, [
|
Req2 = cowboy_req:reply(200, [
|
||||||
{<<"server">>, <<"yaws">>}
|
{<<"server">>, <<"yaws">>}
|
||||||
], Req).
|
], Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
We also saw earlier how to force close the connection by
|
We also saw earlier how to force close the connection by
|
||||||
overriding the connection header.
|
overriding the connection header.
|
||||||
|
@ -48,34 +50,35 @@ will automatically set the content-length header if you do.
|
||||||
We recommend that you set the content-type header so the
|
We recommend that you set the content-type header so the
|
||||||
client may know how to read the body.
|
client may know how to read the body.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
Req2 = cowboy_req:reply(200, [
|
Req2 = cowboy_req:reply(200, [
|
||||||
{<<"content-type">>, <<"text/plain">>}
|
{<<"content-type">>, <<"text/plain">>}
|
||||||
], "Hello world!", Req).
|
], "Hello world!", Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
Here is the same example but sending HTML this time.
|
Here is the same example but sending HTML this time.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
Req2 = cowboy_req:reply(200, [
|
Req2 = cowboy_req:reply(200, [
|
||||||
{<<"content-type">>, <<"text/html">>}
|
{<<"content-type">>, <<"text/html">>}
|
||||||
], "<html><head>Hello world!</head><body><p>Hats off!</p></body></html>", Req).
|
], "<html><head>Hello world!</head><body><p>Hats off!</p></body></html>", Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
Note that the reply is sent immediately.
|
Note that the reply is sent immediately.
|
||||||
|
|
||||||
:: Chunked reply
|
=== Chunked reply
|
||||||
|
|
||||||
You can also stream the response body. First, you need to
|
You can also stream the response body. First, you need to
|
||||||
initiate the reply by sending the response status code.
|
initiate the reply by sending the response status code.
|
||||||
Then you can send the body in chunks of arbitrary size.
|
Then you can send the body in chunks of arbitrary size.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Req2 = cowboy_req:chunked_reply(200, Req),
|
Req2 = cowboy_req:chunked_reply(200, Req),
|
||||||
cowboy_req:chunk("Hello...", Req2),
|
cowboy_req:chunk("Hello...", Req2),
|
||||||
cowboy_req:chunk("chunked...", Req2),
|
cowboy_req:chunk("chunked...", Req2),
|
||||||
cowboy_req:chunk("world!!", Req2).
|
cowboy_req:chunk("world!!", Req2).
|
||||||
```
|
|
||||||
|
|
||||||
You should make sure to match on `ok` as an error may be
|
You should make sure to match on `ok` as an error may be
|
||||||
returned.
|
returned.
|
||||||
|
@ -84,36 +87,35 @@ While it is possible to send a chunked response without
|
||||||
a content-type header, it is still recommended. You can
|
a content-type header, it is still recommended. You can
|
||||||
set this header or any other just like for normal replies.
|
set this header or any other just like for normal replies.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
Req2 = cowboy_req:chunked_reply(200, [
|
Req2 = cowboy_req:chunked_reply(200, [
|
||||||
{<<"content-type">>, <<"text/html">>}
|
{<<"content-type">>, <<"text/html">>}
|
||||||
], Req),
|
], Req),
|
||||||
cowboy_req:chunk("<html><head>Hello world!</head>", Req2),
|
cowboy_req:chunk("<html><head>Hello world!</head>", Req2),
|
||||||
cowboy_req:chunk("<body><p>Hats off!</p></body></html>", Req2).
|
cowboy_req:chunk("<body><p>Hats off!</p></body></html>", Req2).
|
||||||
```
|
----
|
||||||
|
|
||||||
Note that the reply and each chunk following it are sent
|
Note that the reply and each chunk following it are sent
|
||||||
immediately.
|
immediately.
|
||||||
|
|
||||||
:: Preset response headers
|
=== Preset response headers
|
||||||
|
|
||||||
You can define response headers in advance. They will be
|
You can define response headers in advance. They will be
|
||||||
merged into the headers given in the reply call. Headers
|
merged into the headers given in the reply call. Headers
|
||||||
in the reply call override preset response headers which
|
in the reply call override preset response headers which
|
||||||
override the default Cowboy headers.
|
override the default Cowboy headers.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Req2 = cowboy_req:set_resp_header(<<"allow">>, "GET", Req).
|
Req2 = cowboy_req:set_resp_header(<<"allow">>, "GET", Req).
|
||||||
```
|
|
||||||
|
|
||||||
You can check if a response header has already been set.
|
You can check if a response header has already been set.
|
||||||
This will only check the response headers that you set,
|
This will only check the response headers that you set,
|
||||||
and not the ones Cowboy will add when actually sending
|
and not the ones Cowboy will add when actually sending
|
||||||
the reply.
|
the reply.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
cowboy_req:has_resp_header(<<"allow">>, Req).
|
cowboy_req:has_resp_header(<<"allow">>, Req).
|
||||||
```
|
|
||||||
|
|
||||||
It will return `true` if the header is defined, and `false`
|
It will return `true` if the header is defined, and `false`
|
||||||
otherwise.
|
otherwise.
|
||||||
|
@ -121,19 +123,17 @@ otherwise.
|
||||||
Finally, you can also delete a preset response header if
|
Finally, you can also delete a preset response header if
|
||||||
needed. If you do, it will not be sent.
|
needed. If you do, it will not be sent.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Req2 = cowboy_req:delete_resp_header(<<"allow">>, Req).
|
Req2 = cowboy_req:delete_resp_header(<<"allow">>, Req).
|
||||||
```
|
|
||||||
|
|
||||||
:: Preset response body
|
=== Preset response body
|
||||||
|
|
||||||
You can set the response body in advance. Note that this
|
You can set the response body in advance. Note that this
|
||||||
body will be ignored if you then choose to send a chunked
|
body will be ignored if you then choose to send a chunked
|
||||||
reply, or if you send a reply with an explicit body.
|
reply, or if you send a reply with an explicit body.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Req2 = cowboy_req:set_resp_body("Hello world!", Req).
|
Req2 = cowboy_req:set_resp_body("Hello world!", Req).
|
||||||
```
|
|
||||||
|
|
||||||
You can also set a fun that will be called when it is time
|
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
|
to send the body. There are three different ways of doing
|
||||||
|
@ -144,38 +144,41 @@ you should specify it, as it will help clients determine
|
||||||
the remaining download time and allow them to inform the
|
the remaining download time and allow them to inform the
|
||||||
user.
|
user.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
F = fun (Socket, Transport) ->
|
F = fun (Socket, Transport) ->
|
||||||
Transport:send(Socket, "Hello world!")
|
Transport:send(Socket, "Hello world!")
|
||||||
end,
|
end,
|
||||||
Req2 = cowboy_req:set_resp_body_fun(12, F, Req).
|
Req2 = cowboy_req:set_resp_body_fun(12, F, Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
If you do not know the length of the body, you should use
|
If you do not know the length of the body, you should use
|
||||||
a chunked response body fun instead.
|
a chunked response body fun instead.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
F = fun (SendChunk) ->
|
F = fun (SendChunk) ->
|
||||||
Body = lists:duplicate(random:uniform(1024, $a)),
|
Body = lists:duplicate(random:uniform(1024, $a)),
|
||||||
SendChunk(Body)
|
SendChunk(Body)
|
||||||
end,
|
end,
|
||||||
Req2 = cowboy_req:set_resp_body_fun(chunked, F, Req).
|
Req2 = cowboy_req:set_resp_body_fun(chunked, F, Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
Finally, you can also send data on the socket directly,
|
Finally, you can also send data on the socket directly,
|
||||||
without knowing the length in advance. Cowboy may be
|
without knowing the length in advance. Cowboy may be
|
||||||
forced to close the connection at the end of the response
|
forced to close the connection at the end of the response
|
||||||
though depending on the protocol capabilities.
|
though depending on the protocol capabilities.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
F = fun (Socket, Transport) ->
|
F = fun (Socket, Transport) ->
|
||||||
Body = lists:duplicate(random:uniform(1024, $a)),
|
Body = lists:duplicate(random:uniform(1024, $a)),
|
||||||
Transport:send(Socket, Body)
|
Transport:send(Socket, Body)
|
||||||
end,
|
end,
|
||||||
Req2 = cowboy_req:set_resp_body_fun(F, Req).
|
Req2 = cowboy_req:set_resp_body_fun(F, Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
:: Sending files
|
=== Sending files
|
||||||
|
|
||||||
You can send files directly from disk without having to
|
You can send files directly from disk without having to
|
||||||
read them. Cowboy will use the `sendfile` syscall when
|
read them. Cowboy will use the `sendfile` syscall when
|
||||||
|
@ -186,12 +189,13 @@ than doing it from userland.
|
||||||
Again, it is recommended to set the size of the file if it
|
Again, it is recommended to set the size of the file if it
|
||||||
can be known in advance.
|
can be known in advance.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
F = fun (Socket, Transport) ->
|
F = fun (Socket, Transport) ->
|
||||||
Transport:sendfile(Socket, "priv/styles.css")
|
Transport:sendfile(Socket, "priv/styles.css")
|
||||||
end,
|
end,
|
||||||
Req2 = cowboy_req:set_resp_body_fun(FileSize, F, Req).
|
Req2 = cowboy_req:set_resp_body_fun(FileSize, F, Req).
|
||||||
```
|
----
|
||||||
|
|
||||||
Please see the Ranch guide for more information about
|
Please see the Ranch guide for more information about
|
||||||
sending files.
|
sending files.
|
|
@ -1,4 +1,5 @@
|
||||||
::: REST flowcharts
|
[[rest_flowcharts]]
|
||||||
|
== REST flowcharts
|
||||||
|
|
||||||
This chapter will explain the REST handler state machine through
|
This chapter will explain the REST handler state machine through
|
||||||
a number of different diagrams.
|
a number of different diagrams.
|
||||||
|
@ -17,11 +18,11 @@ indicate a response. Other squares may be either a callback or a
|
||||||
question answered by Cowboy itself. Green arrows tend to indicate
|
question answered by Cowboy itself. Green arrows tend to indicate
|
||||||
the default behavior if the callback is undefined.
|
the default behavior if the callback is undefined.
|
||||||
|
|
||||||
:: Start
|
=== Start
|
||||||
|
|
||||||
All requests start from here.
|
All requests start from here.
|
||||||
|
|
||||||
^"REST starting flowchart^!rest_start.png
|
image::rest_start.png[REST starting flowchart]
|
||||||
|
|
||||||
A series of callbacks are called in succession to perform
|
A series of callbacks are called in succession to perform
|
||||||
a general checkup of the service, the request line and
|
a general checkup of the service, the request line and
|
||||||
|
@ -48,11 +49,11 @@ This diagram is immediately followed by either the
|
||||||
"OPTIONS method" diagram when the request method is
|
"OPTIONS method" diagram when the request method is
|
||||||
OPTIONS, or the "Content negotiation" diagram otherwise.
|
OPTIONS, or the "Content negotiation" diagram otherwise.
|
||||||
|
|
||||||
:: OPTIONS method
|
=== OPTIONS method
|
||||||
|
|
||||||
This diagram only applies to OPTIONS requests.
|
This diagram only applies to OPTIONS requests.
|
||||||
|
|
||||||
^"REST OPTIONS method flowchart^!rest_options.png
|
image::rest_options.png[REST OPTIONS method flowchart]
|
||||||
|
|
||||||
The `options` callback may be used to add information
|
The `options` callback may be used to add information
|
||||||
about the resource, such as media types or languages
|
about the resource, such as media types or languages
|
||||||
|
@ -64,13 +65,13 @@ If the `options` callback is not defined, Cowboy will
|
||||||
send a response containing the list of allowed methods
|
send a response containing the list of allowed methods
|
||||||
by default.
|
by default.
|
||||||
|
|
||||||
:: Content negotiation
|
=== Content negotiation
|
||||||
|
|
||||||
This diagram applies to all request methods other than
|
This diagram applies to all request methods other than
|
||||||
OPTIONS. It is executed right after the "Start" diagram
|
OPTIONS. It is executed right after the "Start" diagram
|
||||||
is completed.
|
is completed.
|
||||||
|
|
||||||
^"REST content negotiation flowchart^!rest_conneg.png
|
image::rest_conneg.png[REST content negotiation flowchart]
|
||||||
|
|
||||||
The purpose of these steps is to determine an appropriate
|
The purpose of these steps is to determine an appropriate
|
||||||
representation to be sent back to the client.
|
representation to be sent back to the client.
|
||||||
|
@ -105,14 +106,14 @@ the "PUT, POST and PATCH methods" diagram,
|
||||||
or the "DELETE method" diagram, depending on the
|
or the "DELETE method" diagram, depending on the
|
||||||
method.
|
method.
|
||||||
|
|
||||||
:: GET and HEAD methods
|
=== GET and HEAD methods
|
||||||
|
|
||||||
This diagram only applies to GET and HEAD requests.
|
This diagram only applies to GET and HEAD requests.
|
||||||
|
|
||||||
For a description of the `cond` step, please see
|
For a description of the `cond` step, please see
|
||||||
the "Conditional requests" diagram.
|
the "Conditional requests" diagram.
|
||||||
|
|
||||||
^"REST GET/HEAD methods flowchart^!rest_get_head.png
|
image::rest_get_head.png[REST GET/HEAD methods flowchart]
|
||||||
|
|
||||||
When the resource exists, and the conditional steps
|
When the resource exists, and the conditional steps
|
||||||
succeed, the resource can be retrieved.
|
succeed, the resource can be retrieved.
|
||||||
|
@ -134,14 +135,14 @@ The `moved_permanently` and `moved_temporarily` callbacks
|
||||||
must return the new location of the resource if it was in
|
must return the new location of the resource if it was in
|
||||||
fact moved.
|
fact moved.
|
||||||
|
|
||||||
:: PUT, POST and PATCH methods
|
=== PUT, POST and PATCH methods
|
||||||
|
|
||||||
This diagram only applies to PUT, POST and PATCH requests.
|
This diagram only applies to PUT, POST and PATCH requests.
|
||||||
|
|
||||||
For a description of the `cond` step, please see
|
For a description of the `cond` step, please see
|
||||||
the "Conditional requests" diagram.
|
the "Conditional requests" diagram.
|
||||||
|
|
||||||
^"REST PUT/POST/PATCH methods flowchart^!rest_put_post_patch.png
|
image::rest_put_post_patch.png[REST PUT/POST/PATCH methods flowchart]
|
||||||
|
|
||||||
When the resource exists, first the conditional steps
|
When the resource exists, first the conditional steps
|
||||||
are executed. When that succeeds, and the method is PUT,
|
are executed. When that succeeds, and the method is PUT,
|
||||||
|
@ -188,14 +189,14 @@ on whether a resource has been created, rather than
|
||||||
modified, and on the availability of a location header
|
modified, and on the availability of a location header
|
||||||
or a body in the response.
|
or a body in the response.
|
||||||
|
|
||||||
:: DELETE method
|
=== DELETE method
|
||||||
|
|
||||||
This diagram only applies to DELETE requests.
|
This diagram only applies to DELETE requests.
|
||||||
|
|
||||||
For a description of the `cond` step, please see
|
For a description of the `cond` step, please see
|
||||||
the "Conditional requests" diagram.
|
the "Conditional requests" diagram.
|
||||||
|
|
||||||
^"REST DELETE method flowchart^!rest_delete.png
|
image::rest_delete.png[REST DELETE method flowchart]
|
||||||
|
|
||||||
When the resource exists, and the conditional steps
|
When the resource exists, and the conditional steps
|
||||||
succeed, the resource can be deleted.
|
succeed, the resource can be deleted.
|
||||||
|
@ -227,13 +228,13 @@ The `moved_permanently` and `moved_temporarily` callbacks
|
||||||
must return the new location of the resource if it was in
|
must return the new location of the resource if it was in
|
||||||
fact moved.
|
fact moved.
|
||||||
|
|
||||||
:: Conditional requests
|
=== Conditional requests
|
||||||
|
|
||||||
This diagram applies to all request methods other than
|
This diagram applies to all request methods other than
|
||||||
OPTIONS. It is executed right after the `resource_exists`
|
OPTIONS. It is executed right after the `resource_exists`
|
||||||
callback, when the resource exists.
|
callback, when the resource exists.
|
||||||
|
|
||||||
^"REST conditional requests flowchart^!rest_cond.png
|
image::rest_cond.png[REST conditional requests flowchart]
|
||||||
|
|
||||||
A request becomes conditional when it includes either of
|
A request becomes conditional when it includes either of
|
||||||
the if-match header; the if-unmodified-since header; the
|
the if-match header; the if-unmodified-since header; the
|
|
@ -1,4 +1,5 @@
|
||||||
::: REST handlers
|
[[rest_handlers]]
|
||||||
|
== REST handlers
|
||||||
|
|
||||||
REST is implemented in Cowboy as a sub protocol. The request
|
REST is implemented in Cowboy as a sub protocol. The request
|
||||||
is handled as a state machine with many optional callbacks
|
is handled as a state machine with many optional callbacks
|
||||||
|
@ -6,16 +7,17 @@ describing the resource and modifying the machine's behavior.
|
||||||
|
|
||||||
The REST handler is the recommended way to handle HTTP requests.
|
The REST handler is the recommended way to handle HTTP requests.
|
||||||
|
|
||||||
:: Initialization
|
=== Initialization
|
||||||
|
|
||||||
First, the `init/2` callback is called. This callback is common
|
First, the `init/2` callback is called. This callback is common
|
||||||
to all handlers. To use REST for the current request, this function
|
to all handlers. To use REST for the current request, this function
|
||||||
must return a `cowboy_rest` tuple.
|
must return a `cowboy_rest` tuple.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, _Opts) ->
|
||||||
{cowboy_rest, Req, #state{}}.
|
{cowboy_rest, Req, #state{}}.
|
||||||
```
|
----
|
||||||
|
|
||||||
Cowboy will then switch to the REST protocol and start executing
|
Cowboy will then switch to the REST protocol and start executing
|
||||||
the state machine.
|
the state machine.
|
||||||
|
@ -23,7 +25,7 @@ the state machine.
|
||||||
After reaching the end of the flowchart, the `terminate/3` callback
|
After reaching the end of the flowchart, the `terminate/3` callback
|
||||||
will be called if it is defined.
|
will be called if it is defined.
|
||||||
|
|
||||||
:: Methods
|
=== Methods
|
||||||
|
|
||||||
The REST component has code for handling the following HTTP methods:
|
The REST component has code for handling the following HTTP methods:
|
||||||
HEAD, GET, POST, PATCH, PUT, DELETE and OPTIONS.
|
HEAD, GET, POST, PATCH, PUT, DELETE and OPTIONS.
|
||||||
|
@ -31,7 +33,7 @@ HEAD, GET, POST, PATCH, PUT, DELETE and OPTIONS.
|
||||||
Other methods can be accepted, however they have no specific callback
|
Other methods can be accepted, however they have no specific callback
|
||||||
defined for them at this time.
|
defined for them at this time.
|
||||||
|
|
||||||
:: Callbacks
|
=== Callbacks
|
||||||
|
|
||||||
All callbacks are optional. Some may become mandatory depending
|
All callbacks are optional. Some may become mandatory depending
|
||||||
on what other defined callbacks return. The various flowcharts
|
on what other defined callbacks return. The various flowcharts
|
||||||
|
@ -53,35 +55,37 @@ In the following table, "skip" means the callback is entirely skipped
|
||||||
if it is undefined, moving directly to the next step. Similarly,
|
if it is undefined, moving directly to the next step. Similarly,
|
||||||
"none" means there is no default value for this callback.
|
"none" means there is no default value for this callback.
|
||||||
|
|
||||||
|| Callback name Default value
|
[cols="<,^",options="header"]
|
||||||
|
|
|===
|
||||||
| allowed_methods `[<<"GET">>, <<"HEAD">>, <<"OPTIONS">>]`
|
| Callback name | Default value
|
||||||
| allow_missing_post `true`
|
| allowed_methods | `[<<"GET">>, <<"HEAD">>, <<"OPTIONS">>]`
|
||||||
| charsets_provided skip
|
| allow_missing_post | `true`
|
||||||
| content_types_accepted none
|
| charsets_provided | skip
|
||||||
| content_types_provided `[{{<<"text">>, <<"html">>, '*'}, to_html}] `
|
| content_types_accepted | none
|
||||||
| delete_completed `true`
|
| content_types_provided | `$$[{{<<"text">>, <<"html">>, '*'}, to_html}]$$`
|
||||||
| delete_resource `false`
|
| delete_completed | `true`
|
||||||
| expires `undefined`
|
| delete_resource | `false`
|
||||||
| forbidden `false`
|
| expires | `undefined`
|
||||||
| generate_etag `undefined`
|
| forbidden | `false`
|
||||||
| is_authorized `true`
|
| generate_etag | `undefined`
|
||||||
| is_conflict `false`
|
| is_authorized | `true`
|
||||||
| known_methods `[<<"GET">>, <<"HEAD">>, <<"POST">>, <<"PUT">>, <<"PATCH">>, <<"DELETE">>, <<"OPTIONS">>]`
|
| is_conflict | `false`
|
||||||
| languages_provided skip
|
| known_methods | `[<<"GET">>, <<"HEAD">>, <<"POST">>, <<"PUT">>, <<"PATCH">>, <<"DELETE">>, <<"OPTIONS">>]`
|
||||||
| last_modified `undefined`
|
| languages_provided | skip
|
||||||
| malformed_request `false`
|
| last_modified | `undefined`
|
||||||
| moved_permanently `false`
|
| malformed_request | `false`
|
||||||
| moved_temporarily `false`
|
| moved_permanently | `false`
|
||||||
| multiple_choices `false`
|
| moved_temporarily | `false`
|
||||||
| options `ok`
|
| multiple_choices | `false`
|
||||||
| previously_existed `false`
|
| options | `ok`
|
||||||
| resource_exists `true`
|
| previously_existed | `false`
|
||||||
| service_available `true`
|
| resource_exists | `true`
|
||||||
| uri_too_long `false`
|
| service_available | `true`
|
||||||
| valid_content_headers `true`
|
| uri_too_long | `false`
|
||||||
| valid_entity_length `true`
|
| valid_content_headers | `true`
|
||||||
| variances `[]`
|
| valid_entity_length | `true`
|
||||||
|
| variances | `[]`
|
||||||
|
|===
|
||||||
|
|
||||||
As you can see, Cowboy tries to move on with the request whenever
|
As you can see, Cowboy tries to move on with the request whenever
|
||||||
possible by using well thought out default values.
|
possible by using well thought out default values.
|
||||||
|
@ -94,32 +98,36 @@ each function. For example, `from_html` and `to_html` indicate
|
||||||
in the first case that we're accepting a resource given as HTML,
|
in the first case that we're accepting a resource given as HTML,
|
||||||
and in the second case that we send one as HTML.
|
and in the second case that we send one as HTML.
|
||||||
|
|
||||||
:: Meta data
|
=== Meta data
|
||||||
|
|
||||||
Cowboy will set informative meta values at various points of the
|
Cowboy will set informative meta values at various points of the
|
||||||
execution. You can retrieve them using `cowboy_req:meta/{2,3}`.
|
execution. You can retrieve them using `cowboy_req:meta/{2,3}`.
|
||||||
The values are defined in the following table.
|
The values are defined in the following table.
|
||||||
|
|
||||||
|| Meta key Details
|
[cols="<,<",options="header"]
|
||||||
|
|
|===
|
||||||
| media_type The content-type negotiated for the response entity.
|
| Meta key | Details
|
||||||
| language The language negotiated for the response entity.
|
| media_type | The content-type negotiated for the response entity.
|
||||||
| charset The charset negotiated for the response entity.
|
| language | The language negotiated for the response entity.
|
||||||
|
| charset | The charset negotiated for the response entity.
|
||||||
|
|===
|
||||||
|
|
||||||
They can be used to send a proper body with the response to a
|
They can be used to send a proper body with the response to a
|
||||||
request that used a method other than HEAD or GET.
|
request that used a method other than HEAD or GET.
|
||||||
|
|
||||||
:: Response headers
|
=== Response headers
|
||||||
|
|
||||||
Cowboy will set response headers automatically over the execution
|
Cowboy will set response headers automatically over the execution
|
||||||
of the REST code. They are listed in the following table.
|
of the REST code. They are listed in the following table.
|
||||||
|
|
||||||
|| Header name Details
|
[cols="<,<",options="header"]
|
||||||
|
|
|===
|
||||||
| content-language Language used in the response body
|
| Header name | Details
|
||||||
| content-type Media type and charset of the response body
|
| content-language | Language used in the response body
|
||||||
| etag Etag of the resource
|
| content-type | Media type and charset of the response body
|
||||||
| expires Expiration date of the resource
|
| etag | Etag of the resource
|
||||||
| last-modified Last modification date for the resource
|
| expires | Expiration date of the resource
|
||||||
| location Relative or absolute URI to the requested resource
|
| last-modified | Last modification date for the resource
|
||||||
| vary List of headers that may change the representation of the resource
|
| location | Relative or absolute URI to the requested resource
|
||||||
|
| vary | List of headers that may change the representation of the resource
|
||||||
|
|===
|
|
@ -1,4 +1,5 @@
|
||||||
::: REST principles
|
[[rest_principles]]
|
||||||
|
== REST principles
|
||||||
|
|
||||||
This chapter will attempt to define the concepts behind REST
|
This chapter will attempt to define the concepts behind REST
|
||||||
and explain what makes a service RESTful.
|
and explain what makes a service RESTful.
|
||||||
|
@ -10,11 +11,11 @@ and POST methods. That's highly misguided at best.
|
||||||
We will first attempt to define REST and will look at what
|
We will first attempt to define REST and will look at what
|
||||||
it means in the context of HTTP and the Web.
|
it means in the context of HTTP and the Web.
|
||||||
For a more in-depth explanation of REST, you can read
|
For a more in-depth explanation of REST, you can read
|
||||||
^"Roy T. Fielding's dissertation^http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
|
http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm[Roy T. Fielding's dissertation]
|
||||||
as it does a great job explaining where it comes from and
|
as it does a great job explaining where it comes from and
|
||||||
what it achieves.
|
what it achieves.
|
||||||
|
|
||||||
:: REST architecture
|
=== REST architecture
|
||||||
|
|
||||||
REST is a *client-server* architecture. The client and the server
|
REST is a *client-server* architecture. The client and the server
|
||||||
both have a different set of concerns. The server stores and/or
|
both have a different set of concerns. The server stores and/or
|
||||||
|
@ -54,7 +55,7 @@ to extend client functionality. This is optional however because
|
||||||
the client may not be able to download or run this code, and so
|
the client may not be able to download or run this code, and so
|
||||||
a REST component cannot rely on it being executed.
|
a REST component cannot rely on it being executed.
|
||||||
|
|
||||||
:: Resources and resource identifiers
|
=== Resources and resource identifiers
|
||||||
|
|
||||||
A resource is an abstract concept. In a REST system, any information
|
A resource is an abstract concept. In a REST system, any information
|
||||||
that can be named may be a resource. This includes documents, images,
|
that can be named may be a resource. This includes documents, images,
|
||||||
|
@ -79,7 +80,7 @@ resources map to a set of one element, for example "user Joe".
|
||||||
Collection of resources map to a set of 0 to N elements,
|
Collection of resources map to a set of 0 to N elements,
|
||||||
for example "all users".
|
for example "all users".
|
||||||
|
|
||||||
:: Resource representations
|
=== Resource representations
|
||||||
|
|
||||||
The representation of a resource is a sequence of bytes associated
|
The representation of a resource is a sequence of bytes associated
|
||||||
with metadata.
|
with metadata.
|
||||||
|
@ -111,7 +112,7 @@ type. Some media types are intended for direct rendering to the
|
||||||
user, while others are intended for automated processing. The
|
user, while others are intended for automated processing. The
|
||||||
media type is a key component of the REST architecture.
|
media type is a key component of the REST architecture.
|
||||||
|
|
||||||
:: Self-descriptive messages
|
=== Self-descriptive messages
|
||||||
|
|
||||||
Messages must be self-descriptive. That means that the data
|
Messages must be self-descriptive. That means that the data
|
||||||
format of a representation must always come with its media
|
format of a representation must always come with its media
|
||||||
|
@ -132,7 +133,7 @@ This means that you can create your own media types, like
|
||||||
specifications for it and that both endpoints agree about
|
specifications for it and that both endpoints agree about
|
||||||
it then the constraint is respected.
|
it then the constraint is respected.
|
||||||
|
|
||||||
:: Hypermedia as the engine of application state
|
=== Hypermedia as the engine of application state
|
||||||
|
|
||||||
The last constraint is generally where services that claim
|
The last constraint is generally where services that claim
|
||||||
to be RESTful fail. Interactions with a server must be
|
to be RESTful fail. Interactions with a server must be
|
|
@ -1,4 +1,5 @@
|
||||||
::: Routing
|
[[routing]]
|
||||||
|
== Routing
|
||||||
|
|
||||||
Cowboy does nothing by default.
|
Cowboy does nothing by default.
|
||||||
|
|
||||||
|
@ -14,42 +15,38 @@ and then try to find a matching path.
|
||||||
|
|
||||||
Routes need to be compiled before they can be used by Cowboy.
|
Routes need to be compiled before they can be used by Cowboy.
|
||||||
|
|
||||||
:: Structure
|
=== Structure
|
||||||
|
|
||||||
The general structure for the routes is defined as follow.
|
The general structure for the routes is defined as follow.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Routes = [Host1, Host2, ... HostN].
|
Routes = [Host1, Host2, ... HostN].
|
||||||
```
|
|
||||||
|
|
||||||
Each host contains matching rules for the host along with optional
|
Each host contains matching rules for the host along with optional
|
||||||
constraints, and a list of routes for the path component.
|
constraints, and a list of routes for the path component.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Host1 = {HostMatch, PathsList}.
|
Host1 = {HostMatch, PathsList}.
|
||||||
Host2 = {HostMatch, Constraints, PathsList}.
|
Host2 = {HostMatch, Constraints, PathsList}.
|
||||||
```
|
|
||||||
|
|
||||||
The list of routes for the path component is defined similar to the
|
The list of routes for the path component is defined similar to the
|
||||||
list of hosts.
|
list of hosts.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
PathsList = [Path1, Path2, ... PathN].
|
PathsList = [Path1, Path2, ... PathN].
|
||||||
```
|
|
||||||
|
|
||||||
Finally, each path contains matching rules for the path along with
|
Finally, each path contains matching rules for the path along with
|
||||||
optional constraints, and gives us the handler module to be used
|
optional constraints, and gives us the handler module to be used
|
||||||
along with options that will be given to it on initialization.
|
along with options that will be given to it on initialization.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
Path1 = {PathMatch, Handler, Opts}.
|
Path1 = {PathMatch, Handler, Opts}.
|
||||||
Path2 = {PathMatch, Constraints, Handler, Opts}.
|
Path2 = {PathMatch, Constraints, Handler, Opts}.
|
||||||
```
|
|
||||||
|
|
||||||
Continue reading to learn more about the match syntax and the optional
|
Continue reading to learn more about the match syntax and the optional
|
||||||
constraints.
|
constraints.
|
||||||
|
|
||||||
:: Match syntax
|
=== Match syntax
|
||||||
|
|
||||||
The match syntax is used to associate host names and paths with their
|
The match syntax is used to associate host names and paths with their
|
||||||
respective handlers.
|
respective handlers.
|
||||||
|
@ -64,30 +61,29 @@ Excluding special values that we will explain at the end of this section,
|
||||||
the simplest match value is a host or a path. It can be given as either
|
the simplest match value is a host or a path. It can be given as either
|
||||||
a `string()` or a `binary()`.
|
a `string()` or a `binary()`.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
PathMatch1 = "/".
|
PathMatch1 = "/".
|
||||||
PathMatch2 = "/path/to/resource".
|
PathMatch2 = "/path/to/resource".
|
||||||
|
|
||||||
HostMatch1 = "cowboy.example.org".
|
HostMatch1 = "cowboy.example.org".
|
||||||
```
|
----
|
||||||
|
|
||||||
As you can see, all paths defined this way must start with a slash
|
As you can see, all paths defined this way must start with a slash
|
||||||
character. Note that these two paths are identical as far as routing
|
character. Note that these two paths are identical as far as routing
|
||||||
is concerned.
|
is concerned.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
PathMatch2 = "/path/to/resource".
|
PathMatch2 = "/path/to/resource".
|
||||||
PathMatch3 = "/path/to/resource/".
|
PathMatch3 = "/path/to/resource/".
|
||||||
```
|
|
||||||
|
|
||||||
Hosts with and without a trailing dot are equivalent for routing.
|
Hosts with and without a trailing dot are equivalent for routing.
|
||||||
Similarly, hosts with and without a leading dot are also equivalent.
|
Similarly, hosts with and without a leading dot are also equivalent.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
HostMatch1 = "cowboy.example.org".
|
HostMatch1 = "cowboy.example.org".
|
||||||
HostMatch2 = "cowboy.example.org.".
|
HostMatch2 = "cowboy.example.org.".
|
||||||
HostMatch3 = ".cowboy.example.org".
|
HostMatch3 = ".cowboy.example.org".
|
||||||
```
|
|
||||||
|
|
||||||
It is possible to extract segments of the host and path and to store
|
It is possible to extract segments of the host and path and to store
|
||||||
the values in the `Req` object for later use. We call these kind of
|
the values in the `Req` object for later use. We call these kind of
|
||||||
|
@ -97,10 +93,9 @@ The syntax for bindings is very simple. A segment that begins with
|
||||||
the `:` character means that what follows until the end of the segment
|
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.
|
is the name of the binding in which the segment value will be stored.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
PathMatch = "/hats/:name/prices".
|
PathMatch = "/hats/:name/prices".
|
||||||
HostMatch = ":subdomain.example.org".
|
HostMatch = ":subdomain.example.org".
|
||||||
```
|
|
||||||
|
|
||||||
If these two end up matching when routing, you will end up with two
|
If these two end up matching when routing, you will end up with two
|
||||||
bindings defined, `subdomain` and `name`, each containing the
|
bindings defined, `subdomain` and `name`, each containing the
|
||||||
|
@ -116,23 +111,20 @@ variable in Erlang. Any match against the `_` binding will succeed
|
||||||
but the data will be discarded. This is especially useful for
|
but the data will be discarded. This is especially useful for
|
||||||
matching against many domain names in one go.
|
matching against many domain names in one go.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
HostMatch = "ninenines.:_".
|
HostMatch = "ninenines.:_".
|
||||||
```
|
|
||||||
|
|
||||||
Similarly, it is possible to have optional segments. Anything
|
Similarly, it is possible to have optional segments. Anything
|
||||||
between brackets is optional.
|
between brackets is optional.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
PathMatch = "/hats/[page/:number]".
|
PathMatch = "/hats/[page/:number]".
|
||||||
HostMatch = "[www.]ninenines.eu".
|
HostMatch = "[www.]ninenines.eu".
|
||||||
```
|
|
||||||
|
|
||||||
You can also have imbricated optional segments.
|
You can also have imbricated optional segments.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
PathMatch = "/hats/[page/[:number]]".
|
PathMatch = "/hats/[page/[:number]]".
|
||||||
```
|
|
||||||
|
|
||||||
You can retrieve the rest of the host or path using `[...]`.
|
You can retrieve the rest of the host or path using `[...]`.
|
||||||
In the case of hosts it will match anything before, in the case
|
In the case of hosts it will match anything before, in the case
|
||||||
|
@ -142,51 +134,45 @@ zero, one or many segments. You can then find the segments using
|
||||||
`cowboy_req:host_info/1` and `cowboy_req:path_info/1` respectively.
|
`cowboy_req:host_info/1` and `cowboy_req:path_info/1` respectively.
|
||||||
They will be represented as a list of segments.
|
They will be represented as a list of segments.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
PathMatch = "/hats/[...]".
|
PathMatch = "/hats/[...]".
|
||||||
HostMatch = "[...]ninenines.eu".
|
HostMatch = "[...]ninenines.eu".
|
||||||
```
|
|
||||||
|
|
||||||
If a binding appears twice in the routing rules, then the match
|
If a binding appears twice in the routing rules, then the match
|
||||||
will succeed only if they share the same value. This copies the
|
will succeed only if they share the same value. This copies the
|
||||||
Erlang pattern matching behavior.
|
Erlang pattern matching behavior.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
PathMatch = "/hats/:name/:name".
|
PathMatch = "/hats/:name/:name".
|
||||||
```
|
|
||||||
|
|
||||||
This is also true when an optional segment is present. In this
|
This is also true when an optional segment is present. In this
|
||||||
case the two values must be identical only if the segment is
|
case the two values must be identical only if the segment is
|
||||||
available.
|
available.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
PathMatch = "/hats/:name/[:name]".
|
PathMatch = "/hats/:name/[:name]".
|
||||||
```
|
|
||||||
|
|
||||||
If a binding is defined in both the host and path, then they must
|
If a binding is defined in both the host and path, then they must
|
||||||
also share the same value.
|
also share the same value.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
PathMatch = "/:user/[...]".
|
PathMatch = "/:user/[...]".
|
||||||
HostMatch = ":user.github.com".
|
HostMatch = ":user.github.com".
|
||||||
```
|
|
||||||
|
|
||||||
Finally, there are two special match values that can be used. The
|
Finally, there are two special match values that can be used. The
|
||||||
first is the atom `'_'` which will match any host or path.
|
first is the atom `'_'` which will match any host or path.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
PathMatch = '_'.
|
PathMatch = '_'.
|
||||||
HostMatch = '_'.
|
HostMatch = '_'.
|
||||||
```
|
|
||||||
|
|
||||||
The second is the special host match `"*"` which will match the
|
The second is the special host match `"*"` which will match the
|
||||||
wildcard path, generally used alongside the `OPTIONS` method.
|
wildcard path, generally used alongside the `OPTIONS` method.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
HostMatch = "*".
|
HostMatch = "*".
|
||||||
```
|
|
||||||
|
|
||||||
:: Constraints
|
=== Constraints
|
||||||
|
|
||||||
After the matching has completed, the resulting bindings can be tested
|
After the matching has completed, the resulting bindings can be tested
|
||||||
against a set of constraints. Constraints are only tested when the
|
against a set of constraints. Constraints are only tested when the
|
||||||
|
@ -200,9 +186,9 @@ one or more constraints. While the router accepts the same format,
|
||||||
it will skip fields with no constraints and will also ignore default
|
it will skip fields with no constraints and will also ignore default
|
||||||
values, if any.
|
values, if any.
|
||||||
|
|
||||||
Read more about ^constraints^.
|
Read more about xref:constraints[constraints].
|
||||||
|
|
||||||
:: Compilation
|
=== Compilation
|
||||||
|
|
||||||
The structure defined in this chapter needs to be compiled before it is
|
The structure defined in this chapter needs to be compiled before it is
|
||||||
passed to Cowboy. This allows Cowboy to efficiently lookup the correct
|
passed to Cowboy. This allows Cowboy to efficiently lookup the correct
|
||||||
|
@ -210,7 +196,8 @@ handler to run instead of having to parse the routes repeatedly.
|
||||||
|
|
||||||
This can be done with a simple call to `cowboy_router:compile/1`.
|
This can be done with a simple call to `cowboy_router:compile/1`.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
Dispatch = cowboy_router:compile([
|
Dispatch = cowboy_router:compile([
|
||||||
%% {HostMatch, list({PathMatch, Handler, Opts})}
|
%% {HostMatch, list({PathMatch, Handler, Opts})}
|
||||||
{'_', [{'_', my_handler, []}]}
|
{'_', [{'_', my_handler, []}]}
|
||||||
|
@ -220,20 +207,18 @@ cowboy:start_http(my_http_listener, 100,
|
||||||
[{port, 8080}],
|
[{port, 8080}],
|
||||||
[{env, [{dispatch, Dispatch}]}]
|
[{env, [{dispatch, Dispatch}]}]
|
||||||
).
|
).
|
||||||
```
|
----
|
||||||
|
|
||||||
Note that this function will return `{error, badarg}` if the structure
|
Note that this function will return `{error, badarg}` if the structure
|
||||||
given is incorrect.
|
given is incorrect.
|
||||||
|
|
||||||
:: Live update
|
=== Live update
|
||||||
|
|
||||||
You can use the `cowboy:set_env/3` function for updating the dispatch
|
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
|
list used by routing. This will apply to all new connections accepted
|
||||||
by the listener.
|
by the listener.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
cowboy:set_env(my_http_listener, dispatch,
|
cowboy:set_env(my_http_listener, dispatch, cowboy_router:compile(Dispatch)).
|
||||||
cowboy_router:compile(Dispatch)).
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that you need to compile the routes before updating.
|
Note that you need to compile the routes before updating.
|
|
@ -1,4 +1,5 @@
|
||||||
::: Static files
|
[[static_files]]
|
||||||
|
== Static files
|
||||||
|
|
||||||
Cowboy comes with a special handler built as a REST handler
|
Cowboy comes with a special handler built as a REST handler
|
||||||
and designed specifically for serving static files. It is
|
and designed specifically for serving static files. It is
|
||||||
|
@ -20,30 +21,28 @@ client-side caching.
|
||||||
To use the static file handler, simply add routes for it
|
To use the static file handler, simply add routes for it
|
||||||
with the appropriate options.
|
with the appropriate options.
|
||||||
|
|
||||||
:: Serve one file
|
=== Serve one file
|
||||||
|
|
||||||
You can use the static handler to serve one specific file
|
You can use the static handler to serve one specific file
|
||||||
from an application's private directory. This is particularly
|
from an application's private directory. This is particularly
|
||||||
useful to serve an `index.html` file when the client requests
|
useful to serve an 'index.html' file when the client requests
|
||||||
the `/` path, for example. The path configured is relative
|
the `/` path, for example. The path configured is relative
|
||||||
to the given application's private directory.
|
to the given application's private directory.
|
||||||
|
|
||||||
The following rule will serve the file `static/index.html`
|
The following rule will serve the file 'static/index.html'
|
||||||
from the application `my_app`'s priv directory whenever the
|
from the application `my_app`'s priv directory whenever the
|
||||||
path `/` is accessed.
|
path `/` is accessed.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
{"/", cowboy_static, {priv_file, my_app, "static/index.html"}}
|
{"/", cowboy_static, {priv_file, my_app, "static/index.html"}}
|
||||||
```
|
|
||||||
|
|
||||||
You can also specify the absolute path to a file, or the
|
You can also specify the absolute path to a file, or the
|
||||||
path to the file relative to the current directory.
|
path to the file relative to the current directory.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
{"/", cowboy_static, {file, "/var/www/index.html"}}
|
{"/", cowboy_static, {file, "/var/www/index.html"}}
|
||||||
```
|
|
||||||
|
|
||||||
:: Serve all files from a directory
|
=== Serve all files from a directory
|
||||||
|
|
||||||
You can also use the static handler to serve all files that
|
You can also use the static handler to serve all files that
|
||||||
can be found in the configured directory. The handler will
|
can be found in the configured directory. The handler will
|
||||||
|
@ -59,18 +58,16 @@ The following rule will serve any file found in the application
|
||||||
`my_app`'s priv directory inside the `static/assets` folder
|
`my_app`'s priv directory inside the `static/assets` folder
|
||||||
whenever the requested path begins with `/assets/`.
|
whenever the requested path begins with `/assets/`.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets"}}
|
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets"}}
|
||||||
```
|
|
||||||
|
|
||||||
You can also specify the absolute path to the directory or
|
You can also specify the absolute path to the directory or
|
||||||
set it relative to the current directory.
|
set it relative to the current directory.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
{"/assets/[...]", cowboy_static, {dir, "/var/www/assets"}}
|
{"/assets/[...]", cowboy_static, {dir, "/var/www/assets"}}
|
||||||
```
|
|
||||||
|
|
||||||
:: Customize the mimetype detection
|
=== Customize the mimetype detection
|
||||||
|
|
||||||
By default, Cowboy will attempt to recognize the mimetype
|
By default, Cowboy will attempt to recognize the mimetype
|
||||||
of your static files by looking at the extension.
|
of your static files by looking at the extension.
|
||||||
|
@ -91,10 +88,11 @@ To use the default function, you should not have to configure
|
||||||
anything, as it is the default. If you insist, though, the
|
anything, as it is the default. If you insist, though, the
|
||||||
following will do the job.
|
following will do the job.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
||||||
[{mimetypes, cow_mimetypes, web}]}}
|
[{mimetypes, cow_mimetypes, web}]}}
|
||||||
```
|
----
|
||||||
|
|
||||||
As you can see, there is an optional field that may contain
|
As you can see, there is an optional field that may contain
|
||||||
a list of less used options, like mimetypes or etag. All option
|
a list of less used options, like mimetypes or etag. All option
|
||||||
|
@ -103,19 +101,21 @@ types have this optional field.
|
||||||
To use the function that will detect almost any mimetype,
|
To use the function that will detect almost any mimetype,
|
||||||
the following configuration will do.
|
the following configuration will do.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
||||||
[{mimetypes, cow_mimetypes, all}]}}
|
[{mimetypes, cow_mimetypes, all}]}}
|
||||||
```
|
----
|
||||||
|
|
||||||
You probably noticed the pattern by now. The configuration
|
You probably noticed the pattern by now. The configuration
|
||||||
expects a module and a function name, so you can use any
|
expects a module and a function name, so you can use any
|
||||||
of your own functions instead.
|
of your own functions instead.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
||||||
[{mimetypes, Module, Function}]}}
|
[{mimetypes, Module, Function}]}}
|
||||||
```
|
----
|
||||||
|
|
||||||
The function that performs the mimetype detection receives
|
The function that performs the mimetype detection receives
|
||||||
a single argument that is the path to the file on disk. It
|
a single argument that is the path to the file on disk. It
|
||||||
|
@ -133,12 +133,13 @@ Finally, the mimetype can be hard-coded for all files.
|
||||||
This is especially useful in combination with the `file`
|
This is especially useful in combination with the `file`
|
||||||
and `priv_file` options as it avoids needless computation.
|
and `priv_file` options as it avoids needless computation.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
{"/", cowboy_static, {priv_file, my_app, "static/index.html",
|
{"/", cowboy_static, {priv_file, my_app, "static/index.html",
|
||||||
[{mimetypes, {<<"text">>, <<"html">>, []}}]}}
|
[{mimetypes, {<<"text">>, <<"html">>, []}}]}}
|
||||||
```
|
----
|
||||||
|
|
||||||
:: Generate an etag
|
=== Generate an etag
|
||||||
|
|
||||||
By default, the static handler will generate an etag header
|
By default, the static handler will generate an etag header
|
||||||
value based on the size and modified time. This solution
|
value based on the size and modified time. This solution
|
||||||
|
@ -149,10 +150,11 @@ different etag on each server.
|
||||||
|
|
||||||
You can however change the way the etag is calculated.
|
You can however change the way the etag is calculated.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
||||||
[{etag, Module, Function}]}}
|
[{etag, Module, Function}]}}
|
||||||
```
|
----
|
||||||
|
|
||||||
This function will receive three arguments: the path to the
|
This function will receive three arguments: the path to the
|
||||||
file on disk, the size of the file and the last modification
|
file on disk, the size of the file and the last modification
|
||||||
|
@ -162,7 +164,8 @@ all your servers.
|
||||||
|
|
||||||
You can also completely disable etag handling.
|
You can also completely disable etag handling.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
||||||
[{etag, false}]}}
|
[{etag, false}]}}
|
||||||
```
|
----
|
|
@ -1,4 +1,5 @@
|
||||||
::: Sub protocols
|
[[sub_protocols]]
|
||||||
|
== Sub protocols
|
||||||
|
|
||||||
Sub protocols are used for creating new types of handlers that
|
Sub protocols are used for creating new types of handlers that
|
||||||
provide extra functionality in a reusable way. Cowboy uses this
|
provide extra functionality in a reusable way. Cowboy uses this
|
||||||
|
@ -7,16 +8,17 @@ mechanism to provide its loop, REST and Websocket handlers.
|
||||||
This chapter will explain how to create your own sub protocols
|
This chapter will explain how to create your own sub protocols
|
||||||
and handler types.
|
and handler types.
|
||||||
|
|
||||||
:: Usage
|
=== Usage
|
||||||
|
|
||||||
To switch to a sub protocol, the `init/2` callback must return
|
To switch to a sub protocol, the `init/2` callback must return
|
||||||
the name of the sub protocol module. Everything past this point
|
the name of the sub protocol module. Everything past this point
|
||||||
is handled by the sub protocol.
|
is handled by the sub protocol.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, _Opts) ->
|
||||||
{cowboy_websocket, Req, #state{}}.
|
{cowboy_websocket, Req, #state{}}.
|
||||||
```
|
----
|
||||||
|
|
||||||
The return value may also have a `Timeout` value and/or the
|
The return value may also have a `Timeout` value and/or the
|
||||||
atom `hibernate`. These options are useful for long living
|
atom `hibernate`. These options are useful for long living
|
||||||
|
@ -27,15 +29,16 @@ The following snippet switches to the `my_protocol` sub
|
||||||
protocol, sets the timeout value to 5 seconds and enables
|
protocol, sets the timeout value to 5 seconds and enables
|
||||||
hibernation:
|
hibernation:
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, _Opts) ->
|
||||||
{my_protocol, Req, #state{}, 5000, hibernate}.
|
{my_protocol, Req, #state{}, 5000, hibernate}.
|
||||||
```
|
----
|
||||||
|
|
||||||
If a sub protocol does not make use of these options, it should
|
If a sub protocol does not make use of these options, it should
|
||||||
crash if it receives anything other than the default values.
|
crash if it receives anything other than the default values.
|
||||||
|
|
||||||
:: Upgrade
|
=== Upgrade
|
||||||
|
|
||||||
After the `init/2` function returns, Cowboy will then call the
|
After the `init/2` function returns, Cowboy will then call the
|
||||||
`upgrade/6` function. This is the only callback defined by the
|
`upgrade/6` function. This is the only callback defined by the
|
||||||
|
@ -51,10 +54,11 @@ The upgrade callback receives the Req object, the middleware
|
||||||
environment, the handler and its options, and the aforementioned
|
environment, the handler and its options, and the aforementioned
|
||||||
timeout and hibernate values.
|
timeout and hibernate values.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
upgrade(Req, Env, Handler, HandlerOpts, Timeout, Hibernate) ->
|
upgrade(Req, Env, Handler, HandlerOpts, Timeout, Hibernate) ->
|
||||||
%% Sub protocol code here.
|
%% Sub protocol code here.
|
||||||
```
|
----
|
||||||
|
|
||||||
This callback is expected to behave like a middleware and to
|
This callback is expected to behave like a middleware and to
|
||||||
return an updated environment and Req object.
|
return an updated environment and Req object.
|
|
@ -1,4 +1,5 @@
|
||||||
::: Handling Websocket connections
|
[[ws_handlers]]
|
||||||
|
== Handling Websocket connections
|
||||||
|
|
||||||
A special handler is required for handling Websocket connections.
|
A special handler is required for handling Websocket connections.
|
||||||
Websocket handlers allow you to initialize the connection,
|
Websocket handlers allow you to initialize the connection,
|
||||||
|
@ -9,16 +10,17 @@ Websocket handlers essentially act as a bridge between the client
|
||||||
and the Erlang system. They will typically do little more than
|
and the Erlang system. They will typically do little more than
|
||||||
socket communication and decoding/encoding of frames.
|
socket communication and decoding/encoding of frames.
|
||||||
|
|
||||||
:: Initialization
|
=== Initialization
|
||||||
|
|
||||||
First, the `init/2` callback is called. This callback is common
|
First, the `init/2` callback is called. This callback is common
|
||||||
to all handlers. To establish a Websocket connection, this function
|
to all handlers. To establish a Websocket connection, this function
|
||||||
must return a `ws` tuple.
|
must return a `ws` tuple.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, _Opts) ->
|
||||||
{cowboy_websocket, Req, #state{}}.
|
{cowboy_websocket, Req, #state{}}.
|
||||||
```
|
----
|
||||||
|
|
||||||
Upon receiving this tuple, Cowboy will switch to the code
|
Upon receiving this tuple, Cowboy will switch to the code
|
||||||
that handles Websocket connections and perform the handshake
|
that handles Websocket connections and perform the handshake
|
||||||
|
@ -30,7 +32,8 @@ handler *must* select one of these subprotocol and send it
|
||||||
back to the client, otherwise the client might decide to close
|
back to the client, otherwise the client might decide to close
|
||||||
the connection, assuming no correct subprotocol was found.
|
the connection, assuming no correct subprotocol was found.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, _Opts) ->
|
||||||
case cowboy_req:parse_header(<<"sec-websocket-protocol">>, Req) of
|
case cowboy_req:parse_header(<<"sec-websocket-protocol">>, Req) of
|
||||||
undefined ->
|
undefined ->
|
||||||
|
@ -45,7 +48,7 @@ init(Req, _Opts) ->
|
||||||
{stop, Req, undefined}
|
{stop, Req, undefined}
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
```
|
----
|
||||||
|
|
||||||
It is not recommended to wait too long inside the `init/2`
|
It is not recommended to wait too long inside the `init/2`
|
||||||
function. Any extra initialization may be done after returning by
|
function. Any extra initialization may be done after returning by
|
||||||
|
@ -57,7 +60,8 @@ It is also very easy to ensure that this message arrives before
|
||||||
any message from other processes by sending it before registering
|
any message from other processes by sending it before registering
|
||||||
or enabling timers.
|
or enabling timers.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, _Opts) ->
|
||||||
self() ! post_init,
|
self() ! post_init,
|
||||||
%% Register process here...
|
%% Register process here...
|
||||||
|
@ -66,9 +70,9 @@ init(Req, _Opts) ->
|
||||||
websocket_info(post_init, Req, State) ->
|
websocket_info(post_init, Req, State) ->
|
||||||
%% Perform post_init initialization here...
|
%% Perform post_init initialization here...
|
||||||
{ok, Req, State}.
|
{ok, Req, State}.
|
||||||
```
|
----
|
||||||
|
|
||||||
:: Handling frames from the client
|
=== Handling frames from the client
|
||||||
|
|
||||||
Cowboy will call `websocket_handle/3` whenever a text, binary,
|
Cowboy will call `websocket_handle/3` whenever a text, binary,
|
||||||
ping or pong frame arrives from the client. Note that in the
|
ping or pong frame arrives from the client. Note that in the
|
||||||
|
@ -81,14 +85,15 @@ or just continue without sending anything.
|
||||||
The following snippet echoes back any text frame received and
|
The following snippet echoes back any text frame received and
|
||||||
ignores all others.
|
ignores all others.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
websocket_handle(Frame = {text, _}, Req, State) ->
|
websocket_handle(Frame = {text, _}, Req, State) ->
|
||||||
{reply, Frame, Req, State};
|
{reply, Frame, Req, State};
|
||||||
websocket_handle(_Frame, Req, State) ->
|
websocket_handle(_Frame, Req, State) ->
|
||||||
{ok, Req, State}.
|
{ok, Req, State}.
|
||||||
```
|
----
|
||||||
|
|
||||||
:: Handling Erlang messages
|
=== Handling Erlang messages
|
||||||
|
|
||||||
Cowboy will call `websocket_info/3` whenever an Erlang message
|
Cowboy will call `websocket_info/3` whenever an Erlang message
|
||||||
arrives.
|
arrives.
|
||||||
|
@ -99,14 +104,15 @@ or just continue without sending anything.
|
||||||
The following snippet forwards any `log` message to the socket
|
The following snippet forwards any `log` message to the socket
|
||||||
and ignores all others.
|
and ignores all others.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
websocket_info({log, Text}, Req, State) ->
|
websocket_info({log, Text}, Req, State) ->
|
||||||
{reply, {text, Text}, Req, State};
|
{reply, {text, Text}, Req, State};
|
||||||
websocket_info(_Info, Req, State) ->
|
websocket_info(_Info, Req, State) ->
|
||||||
{ok, Req, State}.
|
{ok, Req, State}.
|
||||||
```
|
----
|
||||||
|
|
||||||
:: Sending frames to the socket
|
=== Sending frames to the socket
|
||||||
|
|
||||||
Cowboy allows sending either a single frame or a list of
|
Cowboy allows sending either a single frame or a list of
|
||||||
frames to the socket, in which case the frames are sent
|
frames to the socket, in which case the frames are sent
|
||||||
|
@ -116,7 +122,8 @@ pong or close frames.
|
||||||
The following example sends three frames using a single `reply`
|
The following example sends three frames using a single `reply`
|
||||||
tuple.
|
tuple.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
websocket_info(hello_world, Req, State) ->
|
websocket_info(hello_world, Req, State) ->
|
||||||
{reply, [
|
{reply, [
|
||||||
{text, "Hello"},
|
{text, "Hello"},
|
||||||
|
@ -124,7 +131,7 @@ websocket_info(hello_world, Req, State) ->
|
||||||
{binary, <<0:8000>>}
|
{binary, <<0:8000>>}
|
||||||
], Req, State};
|
], Req, State};
|
||||||
%% More websocket_info/3 clauses here...
|
%% More websocket_info/3 clauses here...
|
||||||
```
|
----
|
||||||
|
|
||||||
Note that the payload for text and binary frames is of type
|
Note that the payload for text and binary frames is of type
|
||||||
`iodata()`, meaning it can be either a `binary()` or an
|
`iodata()`, meaning it can be either a `binary()` or an
|
||||||
|
@ -137,7 +144,7 @@ be received will not be processed. Also note that when replying
|
||||||
a list of frames that includes close, any frame found after the
|
a list of frames that includes close, any frame found after the
|
||||||
close frame will not be sent.
|
close frame will not be sent.
|
||||||
|
|
||||||
:: Ping and timeout
|
=== Ping and timeout
|
||||||
|
|
||||||
The biggest performance improvement you can do when dealing
|
The biggest performance improvement you can do when dealing
|
||||||
with a huge number of Websocket connections is to reduce the
|
with a huge number of Websocket connections is to reduce the
|
||||||
|
@ -160,15 +167,16 @@ leave the process alive forever.
|
||||||
|
|
||||||
A good timeout value is 60 seconds.
|
A good timeout value is 60 seconds.
|
||||||
|
|
||||||
``` erlang
|
[source,erlang]
|
||||||
|
----
|
||||||
init(Req, _Opts) ->
|
init(Req, _Opts) ->
|
||||||
{cowboy_websocket, Req, #state{}, 60000}.
|
{cowboy_websocket, Req, #state{}, 60000}.
|
||||||
```
|
----
|
||||||
|
|
||||||
This value cannot be changed once it is set. It defaults to
|
This value cannot be changed once it is set. It defaults to
|
||||||
`infinity`.
|
`infinity`.
|
||||||
|
|
||||||
:: Hibernate
|
=== Hibernate
|
||||||
|
|
||||||
Most tuples returned from handler callbacks can include an
|
Most tuples returned from handler callbacks can include an
|
||||||
extra value `hibernate`. After doing any necessary operations
|
extra value `hibernate`. After doing any necessary operations
|
||||||
|
@ -180,9 +188,9 @@ handle much traffic. It is a good idea to hibernate all
|
||||||
connections by default and investigate only when you start
|
connections by default and investigate only when you start
|
||||||
noticing increased CPU usage.
|
noticing increased CPU usage.
|
||||||
|
|
||||||
:: Supporting older browsers
|
=== Supporting older browsers
|
||||||
|
|
||||||
Unfortunately Websocket is a relatively recent technology,
|
Unfortunately Websocket is a relatively recent technology,
|
||||||
which means that not all browsers support it. A library like
|
which means that not all browsers support it. A library like
|
||||||
^"Bullet^https://github.com/extend/bullet^ can be used to
|
https://github.com/ninenines/bullet[Bullet] can be used to
|
||||||
emulate Websocket connections on older browsers.
|
emulate Websocket connections on older browsers.
|
|
@ -1,9 +1,10 @@
|
||||||
::: The Websocket protocol
|
[[ws_protocol]]
|
||||||
|
== The Websocket protocol
|
||||||
|
|
||||||
This chapter explains what Websocket is and why it is
|
This chapter explains what Websocket is and why it is
|
||||||
a vital component of soft realtime Web applications.
|
a vital component of soft realtime Web applications.
|
||||||
|
|
||||||
:: Description
|
=== Description
|
||||||
|
|
||||||
Websocket is an extension to HTTP that emulates plain TCP
|
Websocket is an extension to HTTP that emulates plain TCP
|
||||||
connections between the client, typically a Web browser,
|
connections between the client, typically a Web browser,
|
||||||
|
@ -22,7 +23,7 @@ and all drafts that were previously implemented by browsers,
|
||||||
excluding the initial flawed draft sometimes known as
|
excluding the initial flawed draft sometimes known as
|
||||||
"version 0".
|
"version 0".
|
||||||
|
|
||||||
:: Implementation
|
=== Implementation
|
||||||
|
|
||||||
Cowboy implements Websocket as a protocol upgrade. Once the
|
Cowboy implements Websocket as a protocol upgrade. Once the
|
||||||
upgrade is performed from the `init/2` callback, Cowboy
|
upgrade is performed from the `init/2` callback, Cowboy
|
98
doc/src/manual/cowboy.asciidoc
Normal file
98
doc/src/manual/cowboy.asciidoc
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
= cowboy(3)
|
||||||
|
|
||||||
|
== Name
|
||||||
|
|
||||||
|
cowboy - HTTP server
|
||||||
|
|
||||||
|
== Description
|
||||||
|
|
||||||
|
The `cowboy` module provides convenience functions for
|
||||||
|
manipulating Ranch listeners.
|
||||||
|
|
||||||
|
== Types
|
||||||
|
|
||||||
|
=== fields() = [Field]
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
----
|
||||||
|
Field = atom()
|
||||||
|
| {atom(), cowboy_constraints:constraint() | [cowboy_constraints:constraint()]}
|
||||||
|
| {atom(), cowboy_constraints:constraint() | [cowboy_constraints:constraint()], any()}]
|
||||||
|
----
|
||||||
|
|
||||||
|
Fields for match operations. Constraint(s) and default value are optional.
|
||||||
|
|
||||||
|
=== http_headers() = [{binary(), iodata()}]
|
||||||
|
|
||||||
|
HTTP headers as a list of key/values.
|
||||||
|
|
||||||
|
=== http_status() = non_neg_integer() | binary()
|
||||||
|
|
||||||
|
HTTP status.
|
||||||
|
|
||||||
|
A binary status can be used to set a custom message.
|
||||||
|
|
||||||
|
=== http_version() = \'HTTP/1.1' | \'HTTP/1.0'
|
||||||
|
|
||||||
|
HTTP version.
|
||||||
|
|
||||||
|
=== `onresponse_fun() = fun((http_status(), http_headers(), iodata(), cowboy_req:req()) -> cowboy_req:req())`
|
||||||
|
|
||||||
|
Fun called immediately before sending the response.
|
||||||
|
|
||||||
|
It can perform any operation on the Req object, including
|
||||||
|
reading the request body or replying. If a reply is sent, it
|
||||||
|
overrides the reply initially sent. The callback will not be
|
||||||
|
called again for the new reply.
|
||||||
|
|
||||||
|
== Exports
|
||||||
|
|
||||||
|
=== start_http(Ref, NbAcceptors, TransOpts, ProtoOpts) -> {ok, pid()}
|
||||||
|
|
||||||
|
Ref = ranch:ref():: Listener name.
|
||||||
|
NbAcceptors = non_neg_integer():: Number of acceptor processes.
|
||||||
|
TransOpts = ranch_tcp:opts():: TCP transport options.
|
||||||
|
ProtoOpts = cowboy_protocol:opts():: HTTP protocol options.
|
||||||
|
|
||||||
|
Start listening for HTTP connections. Returns the pid for this
|
||||||
|
listener's supervisor.
|
||||||
|
|
||||||
|
=== start_https(Ref, NbAcceptors, TransOpts, ProtoOpts) -> {ok, pid()}
|
||||||
|
|
||||||
|
Ref = ranch:ref():: Listener name.
|
||||||
|
NbAcceptors = non_neg_integer():: Number of acceptor processes.
|
||||||
|
TransOpts = ranch_ssl:opts():: SSL transport options.
|
||||||
|
ProtoOpts = cowboy_protocol:opts():: HTTP protocol options.
|
||||||
|
|
||||||
|
Start listening for HTTPS connections. Returns the pid for this
|
||||||
|
listener's supervisor.
|
||||||
|
|
||||||
|
=== start_spdy(Ref, NbAcceptors, TransOpts, ProtoOpts) -> {ok, pid()}
|
||||||
|
|
||||||
|
Ref = ranch:ref():: Listener name.
|
||||||
|
NbAcceptors = non_neg_integer():: Number of acceptor processes.
|
||||||
|
TransOpts = ranch_ssl:opts():: SSL transport options.
|
||||||
|
ProtoOpts = cowboy_spdy:opts():: SPDY protocol options.
|
||||||
|
|
||||||
|
Start listening for SPDY connections. Returns the pid for this
|
||||||
|
listener's supervisor.
|
||||||
|
|
||||||
|
=== stop_listener(Ref) -> ok | {error, not_found}
|
||||||
|
|
||||||
|
Ref = ranch:ref():: Listener name.
|
||||||
|
|
||||||
|
Stop a previously started listener.
|
||||||
|
|
||||||
|
=== set_env(Ref, Name, Value) -> ok
|
||||||
|
|
||||||
|
Ref = ranch:ref():: Listener name.
|
||||||
|
Name = atom():: Name of environment value.
|
||||||
|
Value = any():: Environment value.
|
||||||
|
|
||||||
|
Set or update an environment value for an already running listener.
|
||||||
|
This will take effect on all subsequent connections.
|
||||||
|
|
||||||
|
== See also
|
||||||
|
|
||||||
|
The http://ninenines.eu/docs/en/ranch/HEAD/guide[Ranch guide]
|
||||||
|
provides detailed information about how listeners work.
|
|
@ -1,98 +0,0 @@
|
||||||
::: cowboy
|
|
||||||
|
|
||||||
The `cowboy` module provides convenience functions for
|
|
||||||
manipulating Ranch listeners.
|
|
||||||
|
|
||||||
:: Types
|
|
||||||
|
|
||||||
: fields() = [atom()
|
|
||||||
| {atom(), cowboy_constraints:constraint() | [cowboy_constraints:constraint()]}
|
|
||||||
| {atom(), cowboy_constraints:constraint() | [cowboy_constraints:constraint()], any()}]
|
|
||||||
|
|
||||||
Fields for match operations. Constraint(s) and default value are optional.
|
|
||||||
|
|
||||||
: http_headers() = [{binary(), iodata()}]
|
|
||||||
|
|
||||||
HTTP headers as a list of key/values.
|
|
||||||
|
|
||||||
: http_status() = non_neg_integer() | binary()
|
|
||||||
|
|
||||||
HTTP status.
|
|
||||||
|
|
||||||
A binary status can be used to set a custom message.
|
|
||||||
|
|
||||||
: http_version() = 'HTTP/1.1' | 'HTTP/1.0'
|
|
||||||
|
|
||||||
HTTP version.
|
|
||||||
|
|
||||||
: onresponse_fun() = fun((http_status(), http_headers(),
|
|
||||||
iodata(), cowboy_req:req()) -> cowboy_req:req())
|
|
||||||
|
|
||||||
Fun called immediately before sending the response.
|
|
||||||
|
|
||||||
It can perform any operation on the Req object, including
|
|
||||||
reading the request body or replying. If a reply is sent, it
|
|
||||||
overrides the reply initially sent. The callback will not be
|
|
||||||
called again for the new reply.
|
|
||||||
|
|
||||||
:: Exports
|
|
||||||
|
|
||||||
: start_http(Ref, NbAcceptors, TransOpts, ProtoOpts) -> {ok, pid()}
|
|
||||||
|
|
||||||
Types:
|
|
||||||
|
|
||||||
* Ref = ranch:ref()
|
|
||||||
* NbAcceptors = non_neg_integer()
|
|
||||||
* TransOpts = ranch_tcp:opts()
|
|
||||||
* ProtoOpts = cowboy_protocol:opts()
|
|
||||||
|
|
||||||
Start listening for HTTP connections. Returns the pid for this
|
|
||||||
listener's supervisor.
|
|
||||||
|
|
||||||
: start_https(Ref, NbAcceptors, TransOpts, ProtoOpts) -> {ok, pid()}
|
|
||||||
|
|
||||||
Types:
|
|
||||||
|
|
||||||
* Ref = ranch:ref()
|
|
||||||
* NbAcceptors = non_neg_integer()
|
|
||||||
* TransOpts = ranch_ssl:opts()
|
|
||||||
* ProtoOpts = cowboy_protocol:opts()
|
|
||||||
|
|
||||||
Start listening for HTTPS connections. Returns the pid for this
|
|
||||||
listener's supervisor.
|
|
||||||
|
|
||||||
: start_spdy(Ref, NbAcceptors, TransOpts, ProtoOpts) -> {ok, pid()}
|
|
||||||
|
|
||||||
Types:
|
|
||||||
|
|
||||||
* Ref = ranch:ref()
|
|
||||||
* NbAcceptors = non_neg_integer()
|
|
||||||
* TransOpts = ranch_ssl:opts()
|
|
||||||
* ProtoOpts = cowboy_spdy:opts()
|
|
||||||
|
|
||||||
Start listening for SPDY connections. Returns the pid for this
|
|
||||||
listener's supervisor.
|
|
||||||
|
|
||||||
: stop_listener(Ref) -> ok | {error, not_found}
|
|
||||||
|
|
||||||
Types:
|
|
||||||
|
|
||||||
* Ref = ranch:ref()
|
|
||||||
|
|
||||||
Stop a previously started listener.
|
|
||||||
|
|
||||||
: set_env(Ref, Name, Value) -> ok
|
|
||||||
|
|
||||||
Types:
|
|
||||||
|
|
||||||
* Ref = ranch:ref()
|
|
||||||
* Name = atom()
|
|
||||||
* Value = any()
|
|
||||||
|
|
||||||
Set or update an environment value for an already running listener.
|
|
||||||
This will take effect on all subsequent connections.
|
|
||||||
|
|
||||||
:: See also
|
|
||||||
|
|
||||||
The ^"Ranch guide^http://ninenines.eu/docs/en/ranch/HEAD/guide
|
|
||||||
provides detailed information about how listeners work.
|
|
|
@ -1,8 +1,10 @@
|
||||||
::: The Cowboy Application
|
= cowboy(7)
|
||||||
|
|
||||||
Small, fast, modular HTTP server.
|
== Name
|
||||||
|
|
||||||
:: Dependencies
|
cowboy - Small, fast, modular HTTP server.
|
||||||
|
|
||||||
|
== Dependencies
|
||||||
|
|
||||||
The `cowboy` application uses the Erlang applications `ranch`
|
The `cowboy` application uses the Erlang applications `ranch`
|
||||||
for listening and accepting TCP connections, `crypto` for
|
for listening and accepting TCP connections, `crypto` for
|
||||||
|
@ -17,7 +19,7 @@ The `cowboy` application also uses the Erlang applications
|
||||||
`asn1`, `public_key` and `ssl` when listening for HTTPS connections.
|
`asn1`, `public_key` and `ssl` when listening for HTTPS connections.
|
||||||
These are started automatically if they weren't before.
|
These are started automatically if they weren't before.
|
||||||
|
|
||||||
:: Environment
|
== Environment
|
||||||
|
|
||||||
The `cowboy` application does not define any application
|
The `cowboy` application does not define any application
|
||||||
environment configuration parameters.
|
environment configuration parameters.
|
|
@ -1,4 +1,10 @@
|
||||||
::: cowboy_handler
|
= cowboy_handler(3)
|
||||||
|
|
||||||
|
== Name
|
||||||
|
|
||||||
|
cowboy_handler - handler middleware and behaviour
|
||||||
|
|
||||||
|
== Description
|
||||||
|
|
||||||
The `cowboy_handler` middleware executes the handler passed
|
The `cowboy_handler` middleware executes the handler passed
|
||||||
through the environment values `handler` and `handler_opts`,
|
through the environment values `handler` and `handler_opts`,
|
||||||
|
@ -8,51 +14,42 @@ handled and received a response.
|
||||||
|
|
||||||
Environment input:
|
Environment input:
|
||||||
|
|
||||||
* handler = module()
|
handler = module():: Handler to be executed.
|
||||||
* handler_opts = any()
|
handler_opts = any():: Options to be passed to the handler.
|
||||||
|
|
||||||
Environment output:
|
Environment output:
|
||||||
|
|
||||||
* result = ok
|
result = ok:: Result of the request.
|
||||||
|
|
||||||
This module also defines the `cowboy_handler` behaviour that
|
This module also defines the `cowboy_handler` behaviour that
|
||||||
defines the basic interface for handlers. All Cowboy handlers
|
defines the basic interface for handlers. All Cowboy handlers
|
||||||
implement at least the `init/2` callback, and may implement
|
implement at least the `init/2` callback, and may implement
|
||||||
the `terminate/3` callback optionally.
|
the `terminate/3` callback optionally.
|
||||||
|
|
||||||
:: Terminate reasons
|
== Terminate reasons
|
||||||
|
|
||||||
The following values may be received as the terminate reason
|
The following values may be received as the terminate reason
|
||||||
in the optional `terminate/3` callback. Different handler types
|
in the optional `terminate/3` callback. Different handler types
|
||||||
may define additional terminate reasons.
|
may define additional terminate reasons.
|
||||||
|
|
||||||
: normal
|
normal::
|
||||||
|
The connection was closed normally.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
: {crash, Class, Reason}
|
== Callbacks
|
||||||
|
|
||||||
A crash occurred in the handler. `Class` and `Reason` can be
|
=== init(Req, Opts) -> {ok, Req, State} | {Module, Req, State} | {Module, Req, State, hibernate | Timeout} | {Module, Req, State, Timeout, hibernate}
|
||||||
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
|
Req = cowboy_req:req():: The Req object.
|
||||||
|
Opts = any():: Handler options.
|
||||||
: init(Req, Opts)
|
State = any():: Handler state.
|
||||||
-> {ok, Req, State}
|
Module = module():: Module of the sub-protocol to use.
|
||||||
| {Module, Req, State}
|
Timeout = timeout():: Timeout passed to the sub-protocol, when applicable.
|
||||||
| {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.
|
Process the request.
|
||||||
|
|
||||||
|
@ -68,13 +65,11 @@ A crash in this callback will result in `terminate/3` being
|
||||||
called if it is defined, with the `State` argument set to
|
called if it is defined, with the `State` argument set to
|
||||||
the value of `Opts` originally given to the `init/2` callback.
|
the value of `Opts` originally given to the `init/2` callback.
|
||||||
|
|
||||||
: terminate(Reason, Req, State) -> ok
|
=== terminate(Reason, Req, State) -> ok
|
||||||
|
|
||||||
Types:
|
Reason = any():: Reason for termination.
|
||||||
|
Req = cowboy_req:req():: The Req object.
|
||||||
* Reason = any()
|
State = any():: Handler state.
|
||||||
* Req = cowboy_req:req()
|
|
||||||
* State = any()
|
|
||||||
|
|
||||||
Perform any necessary cleanup of the state.
|
Perform any necessary cleanup of the state.
|
||||||
|
|
||||||
|
@ -88,16 +83,14 @@ A crash in this callback or an invalid return value will
|
||||||
result in the closing of the connection and the termination
|
result in the closing of the connection and the termination
|
||||||
of the process.
|
of the process.
|
||||||
|
|
||||||
:: Exports
|
== Exports
|
||||||
|
|
||||||
: terminate(Reason, Req, State, Handler) -> ok
|
=== terminate(Reason, Req, State, Handler) -> ok
|
||||||
|
|
||||||
Types:
|
Reason = any():: Reason for termination.
|
||||||
|
Req = cowboy_req:req():: The Req object.
|
||||||
* Reason = any()
|
State = any():: Handler state.
|
||||||
* Req = cowboy_req:req()
|
Handler = module():: Handler module.
|
||||||
* State = any()
|
|
||||||
* Handler = module()
|
|
||||||
|
|
||||||
Call the optional `terminate/3` callback if it exists.
|
Call the optional `terminate/3` callback if it exists.
|
||||||
|
|
86
doc/src/manual/cowboy_loop.asciidoc
Normal file
86
doc/src/manual/cowboy_loop.asciidoc
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
= cowboy_loop(3)
|
||||||
|
|
||||||
|
== Name
|
||||||
|
|
||||||
|
cowboy_loop - loop handlers
|
||||||
|
|
||||||
|
== Description
|
||||||
|
|
||||||
|
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 link:cowboy_handler.asciidoc[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.
|
||||||
|
|
||||||
|
== 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.
|
||||||
|
|
||||||
|
stop::
|
||||||
|
The handler requested to close the connection by returning
|
||||||
|
a `stop` 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} | {stop, Req, State}
|
||||||
|
|
||||||
|
Info = any():: Message received by the process.
|
||||||
|
Req = cowboy_req:req():: The Req object.
|
||||||
|
State = any():: Handler state.
|
||||||
|
|
||||||
|
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 `stop` 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.
|
|
@ -1,92 +0,0 @@
|
||||||
::: 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.
|
|
||||||
|
|
||||||
:: 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.
|
|
||||||
|
|
||||||
: stop
|
|
||||||
|
|
||||||
The handler requested to close the connection by returning
|
|
||||||
a `stop` 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}
|
|
||||||
| {stop, 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 `stop` 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.
|
|
|
@ -1,4 +1,10 @@
|
||||||
::: cowboy_middleware
|
= cowboy_middleware(3)
|
||||||
|
|
||||||
|
== Name
|
||||||
|
|
||||||
|
cowboy_middleware - behaviour for middlewares
|
||||||
|
|
||||||
|
== Description
|
||||||
|
|
||||||
The `cowboy_middleware` behaviour defines the interface used
|
The `cowboy_middleware` behaviour defines the interface used
|
||||||
by Cowboy middleware modules.
|
by Cowboy middleware modules.
|
||||||
|
@ -6,9 +12,9 @@ by Cowboy middleware modules.
|
||||||
Middlewares process the request sequentially in the order they
|
Middlewares process the request sequentially in the order they
|
||||||
are configured.
|
are configured.
|
||||||
|
|
||||||
:: Types
|
== Types
|
||||||
|
|
||||||
: env() = [{atom(), any()}]
|
=== env() = [{atom(), any()}]
|
||||||
|
|
||||||
The environment variable.
|
The environment variable.
|
||||||
|
|
||||||
|
@ -16,20 +22,15 @@ One is created for every request. It is passed to each
|
||||||
middleware module executed and subsequently returned,
|
middleware module executed and subsequently returned,
|
||||||
optionally with its contents modified.
|
optionally with its contents modified.
|
||||||
|
|
||||||
:: Callbacks
|
== Callbacks
|
||||||
|
|
||||||
: execute(Req, Env)
|
=== execute(Req, Env) -> {ok, Req, Env} | {suspend, Module, Function, Args} | {stop, Req}
|
||||||
-> {ok, Req, Env}
|
|
||||||
| {suspend, Module, Function, Args}
|
|
||||||
| {stop, Req}
|
|
||||||
|
|
||||||
Types:
|
Req = cowboy_req:req():: The Req object.
|
||||||
|
Env = env():: The request environment.
|
||||||
* Req = cowboy_req:req()
|
Module = module():: MFA to call when resuming the process.
|
||||||
* Env = env()
|
Function = atom():: MFA to call when resuming the process.
|
||||||
* Module = module()
|
Args = [any()]:: MFA to call when resuming the process.
|
||||||
* Function = atom()
|
|
||||||
* Args = [any()]
|
|
||||||
|
|
||||||
Execute the middleware.
|
Execute the middleware.
|
||||||
|
|
75
doc/src/manual/cowboy_protocol.asciidoc
Normal file
75
doc/src/manual/cowboy_protocol.asciidoc
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
= cowboy_protocol(3)
|
||||||
|
|
||||||
|
== Name
|
||||||
|
|
||||||
|
cowboy_protocol - HTTP protocol
|
||||||
|
|
||||||
|
== Description
|
||||||
|
|
||||||
|
The `cowboy_protocol` module implements HTTP/1.1 and HTTP/1.0
|
||||||
|
as a Ranch protocol.
|
||||||
|
|
||||||
|
== Types
|
||||||
|
|
||||||
|
=== opts() = [Option]
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
----
|
||||||
|
Option = {compress, boolean()}
|
||||||
|
| {env, cowboy_middleware:env()}
|
||||||
|
| {max_empty_lines, non_neg_integer()}
|
||||||
|
| {max_header_name_length, non_neg_integer()}
|
||||||
|
| {max_header_value_length, non_neg_integer()}
|
||||||
|
| {max_headers, non_neg_integer()}
|
||||||
|
| {max_keepalive, non_neg_integer()}
|
||||||
|
| {max_request_line_length, non_neg_integer()}
|
||||||
|
| {middlewares, [module()]}
|
||||||
|
| {onresponse, cowboy:onresponse_fun()}
|
||||||
|
| {timeout, timeout()}
|
||||||
|
----
|
||||||
|
|
||||||
|
Configuration for the HTTP protocol handler.
|
||||||
|
|
||||||
|
This configuration is passed to Cowboy when starting listeners
|
||||||
|
using `cowboy:start_http/4` or `cowboy:start_https/4` functions.
|
||||||
|
|
||||||
|
It can be updated without restarting listeners using the
|
||||||
|
Ranch functions `ranch:get_protocol_options/1` and
|
||||||
|
`ranch:set_protocol_options/2`.
|
||||||
|
|
||||||
|
=== Option descriptions
|
||||||
|
|
||||||
|
The default value is given next to the option name.
|
||||||
|
|
||||||
|
compress (false)::
|
||||||
|
When enabled, Cowboy will attempt to compress the response body.
|
||||||
|
|
||||||
|
env ([{listener, Ref}])::
|
||||||
|
Initial middleware environment.
|
||||||
|
|
||||||
|
max_empty_lines (5)::
|
||||||
|
Maximum number of empty lines before a request.
|
||||||
|
|
||||||
|
max_header_name_length (64)::
|
||||||
|
Maximum length of header names.
|
||||||
|
|
||||||
|
max_header_value_length (4096)::
|
||||||
|
Maximum length of header values.
|
||||||
|
|
||||||
|
max_headers (100)::
|
||||||
|
Maximum number of headers allowed per request.
|
||||||
|
|
||||||
|
max_keepalive (100)::
|
||||||
|
Maximum number of requests allowed per connection.
|
||||||
|
|
||||||
|
max_request_line_length (4096)::
|
||||||
|
Maximum length of the request line.
|
||||||
|
|
||||||
|
middlewares ([cowboy_router, cowboy_handler])::
|
||||||
|
List of middlewares to execute for every requests.
|
||||||
|
|
||||||
|
onresponse (undefined)::
|
||||||
|
Fun called every time a response is sent.
|
||||||
|
|
||||||
|
timeout (5000)::
|
||||||
|
Time in ms with no requests before Cowboy closes the connection.
|
|
@ -1,75 +0,0 @@
|
||||||
::: cowboy_protocol
|
|
||||||
|
|
||||||
The `cowboy_protocol` module implements HTTP/1.1 and HTTP/1.0
|
|
||||||
as a Ranch protocol.
|
|
||||||
|
|
||||||
:: Types
|
|
||||||
|
|
||||||
: opts() = [{compress, boolean()}
|
|
||||||
| {env, cowboy_middleware:env()}
|
|
||||||
| {max_empty_lines, non_neg_integer()}
|
|
||||||
| {max_header_name_length, non_neg_integer()}
|
|
||||||
| {max_header_value_length, non_neg_integer()}
|
|
||||||
| {max_headers, non_neg_integer()}
|
|
||||||
| {max_keepalive, non_neg_integer()}
|
|
||||||
| {max_request_line_length, non_neg_integer()}
|
|
||||||
| {middlewares, [module()]}
|
|
||||||
| {onresponse, cowboy:onresponse_fun()}
|
|
||||||
| {timeout, timeout()}]
|
|
||||||
|
|
||||||
Configuration for the HTTP protocol handler.
|
|
||||||
|
|
||||||
This configuration is passed to Cowboy when starting listeners
|
|
||||||
using `cowboy:start_http/4` or `cowboy:start_https/4` functions.
|
|
||||||
|
|
||||||
It can be updated without restarting listeners using the
|
|
||||||
Ranch functions `ranch:get_protocol_options/1` and
|
|
||||||
`ranch:set_protocol_options/2`.
|
|
||||||
|
|
||||||
:: Option descriptions
|
|
||||||
|
|
||||||
The default value is given next to the option name.
|
|
||||||
|
|
||||||
: compress (false)
|
|
||||||
|
|
||||||
When enabled, Cowboy will attempt to compress the response body.
|
|
||||||
|
|
||||||
: env ([{listener, Ref}])
|
|
||||||
|
|
||||||
Initial middleware environment.
|
|
||||||
|
|
||||||
: max_empty_lines (5)
|
|
||||||
|
|
||||||
Maximum number of empty lines before a request.
|
|
||||||
|
|
||||||
: max_header_name_length (64)
|
|
||||||
|
|
||||||
Maximum length of header names.
|
|
||||||
|
|
||||||
: max_header_value_length (4096)
|
|
||||||
|
|
||||||
Maximum length of header values.
|
|
||||||
|
|
||||||
: max_headers (100)
|
|
||||||
|
|
||||||
Maximum number of headers allowed per request.
|
|
||||||
|
|
||||||
: max_keepalive (100)
|
|
||||||
|
|
||||||
Maximum number of requests allowed per connection.
|
|
||||||
|
|
||||||
: max_request_line_length (4096)
|
|
||||||
|
|
||||||
Maximum length of the request line.
|
|
||||||
|
|
||||||
: middlewares ([cowboy_router, cowboy_handler])
|
|
||||||
|
|
||||||
List of middlewares to execute for every requests.
|
|
||||||
|
|
||||||
: onresponse (undefined)
|
|
||||||
|
|
||||||
Fun called every time a response is sent.
|
|
||||||
|
|
||||||
: timeout (5000)
|
|
||||||
|
|
||||||
Time in ms with no requests before Cowboy closes the connection.
|
|
|
@ -1,4 +1,10 @@
|
||||||
::: cowboy_req
|
= cowboy_req(3)
|
||||||
|
|
||||||
|
== Name
|
||||||
|
|
||||||
|
cowboy_req - HTTP request and response
|
||||||
|
|
||||||
|
== Description
|
||||||
|
|
||||||
The `cowboy_req` module provides functions to access, manipulate
|
The `cowboy_req` module provides functions to access, manipulate
|
||||||
and respond to requests.
|
and respond to requests.
|
||||||
|
@ -24,41 +30,54 @@ It is highly discouraged to pass the Req object to another process.
|
||||||
Doing so and calling `cowboy_req` functions from it leads to
|
Doing so and calling `cowboy_req` functions from it leads to
|
||||||
undefined behavior.
|
undefined behavior.
|
||||||
|
|
||||||
:: Types
|
== Types
|
||||||
|
|
||||||
: body_opts() = [{continue, boolean()}
|
=== body_opts() = [Option]
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
----
|
||||||
|
Option = {continue, boolean()}
|
||||||
| {length, non_neg_integer()}
|
| {length, non_neg_integer()}
|
||||||
| {read_length, non_neg_integer()}
|
| {read_length, non_neg_integer()}
|
||||||
| {read_timeout, timeout()}
|
| {read_timeout, timeout()}
|
||||||
| {transfer_decode, transfer_decode_fun(), any()}
|
| {transfer_decode, transfer_decode_fun(), any()}
|
||||||
| {content_decode, content_decode_fun()}]
|
| {content_decode, content_decode_fun()}
|
||||||
|
----
|
||||||
|
|
||||||
Request body reading options.
|
Request body reading options.
|
||||||
|
|
||||||
: cookie_opts() = [{max_age, non_neg_integer()}
|
=== cookie_opts() = [Option]
|
||||||
| {domain, binary()} | {path, binary()}
|
|
||||||
| {secure, boolean()} | {http_only, boolean()}]
|
[source,erlang]
|
||||||
|
----
|
||||||
|
Option = {max_age, non_neg_integer()}
|
||||||
|
| {domain, binary()}
|
||||||
|
| {path, binary()}
|
||||||
|
| {secure, boolean()}
|
||||||
|
| {http_only, boolean()}
|
||||||
|
----
|
||||||
|
|
||||||
Cookie options.
|
Cookie options.
|
||||||
|
|
||||||
: req() - opaque to the user
|
=== req() - opaque to the user
|
||||||
|
|
||||||
The Req object.
|
The Req object.
|
||||||
|
|
||||||
All functions in this module receive a `Req` as argument,
|
All functions in this module receive a `Req` as argument,
|
||||||
and most of them return a new object labelled `Req2` in
|
and some of them return a new object labelled `Req2` in
|
||||||
the function descriptions below.
|
the function descriptions below.
|
||||||
|
|
||||||
:: Request related exports
|
== Request related exports
|
||||||
|
|
||||||
: binding(Name, Req) -> binding(Name, Req, undefined)
|
=== binding(Name, Req) -> binding(Name, Req, undefined)
|
||||||
: binding(Name, Req, Default) -> Value
|
|
||||||
|
|
||||||
Types:
|
Alias of `cowboy_req:binding/3`.
|
||||||
|
|
||||||
* Name = atom()
|
=== binding(Name, Req, Default) -> Value
|
||||||
* Default = any()
|
|
||||||
* Value = any() | Default
|
Name = atom():: Binding name.
|
||||||
|
Default = any():: Default value.
|
||||||
|
Value = any() | Default:: Binding value.
|
||||||
|
|
||||||
Return the value for the given binding.
|
Return the value for the given binding.
|
||||||
|
|
||||||
|
@ -66,12 +85,10 @@ By default the value is a binary, however constraints may change
|
||||||
the type of this value (for example automatically converting
|
the type of this value (for example automatically converting
|
||||||
numbers to integer).
|
numbers to integer).
|
||||||
|
|
||||||
: bindings(Req) -> [{Name, Value}]
|
=== bindings(Req) -> [{Name, Value}]
|
||||||
|
|
||||||
Types:
|
Name = atom():: Binding name.
|
||||||
|
Value = any():: Binding value.
|
||||||
* Name = atom()
|
|
||||||
* Value = any()
|
|
||||||
|
|
||||||
Return all bindings.
|
Return all bindings.
|
||||||
|
|
||||||
|
@ -79,61 +96,52 @@ By default the value is a binary, however constraints may change
|
||||||
the type of this value (for example automatically converting
|
the type of this value (for example automatically converting
|
||||||
numbers to integer).
|
numbers to integer).
|
||||||
|
|
||||||
: header(Name, Req) -> header(Name, Req, undefined)
|
=== header(Name, Req) -> header(Name, Req, undefined)
|
||||||
: header(Name, Req, Default) -> Value
|
|
||||||
|
|
||||||
Types:
|
Alias of `cowboy_req:header/3`.
|
||||||
|
|
||||||
* Name = binary()
|
=== header(Name, Req, Default) -> Value
|
||||||
* Default = any()
|
|
||||||
* Value = binary() | Default
|
Name = binary():: Request header name.
|
||||||
|
Default = any():: Default value.
|
||||||
|
Value = binary() | Default:: Request header value.
|
||||||
|
|
||||||
Return the value for the given header.
|
Return the value for the given header.
|
||||||
|
|
||||||
While header names are case insensitive, this function expects
|
While header names are case insensitive, this function expects
|
||||||
the name to be a lowercase binary.
|
the name to be a lowercase binary.
|
||||||
|
|
||||||
: headers(Req) -> Headers
|
=== headers(Req) -> Headers
|
||||||
|
|
||||||
Types:
|
Headers = cowboy:http_headers():: Request headers.
|
||||||
|
|
||||||
* Headers = cowboy:http_headers()
|
|
||||||
|
|
||||||
Return all headers.
|
Return all headers.
|
||||||
|
|
||||||
: host(Req) -> Host
|
=== host(Req) -> Host
|
||||||
|
|
||||||
Types:
|
Host = binary():: Requested host.
|
||||||
|
|
||||||
* Host = binary()
|
|
||||||
|
|
||||||
Return the requested host.
|
Return the requested host.
|
||||||
|
|
||||||
: host_info(Req) -> HostInfo
|
=== host_info(Req) -> HostInfo
|
||||||
|
|
||||||
Types:
|
HostInfo = cowboy_router:tokens() | undefined:: Extra tokens for the host.
|
||||||
|
|
||||||
* HostInfo = cowboy_router:tokens() | undefined
|
|
||||||
|
|
||||||
Return the extra tokens from matching against `...` during routing.
|
Return the extra tokens from matching against `...` during routing.
|
||||||
|
|
||||||
: host_url(Req) -> HostURL
|
=== host_url(Req) -> HostURL
|
||||||
|
|
||||||
Types:
|
HostURL = binary() | undefined:: Requested URL, without the path component.
|
||||||
|
|
||||||
* HostURL = binary() | undefined
|
|
||||||
|
|
||||||
Return the requested URL excluding the path component.
|
Return the requested URL excluding the path component.
|
||||||
|
|
||||||
This function will always return `undefined` until the
|
This function will always return `undefined` until the
|
||||||
`cowboy_router` middleware has been executed.
|
`cowboy_router` middleware has been executed.
|
||||||
|
|
||||||
: match_cookies(Fields, Req) -> Map
|
=== match_cookies(Fields, Req) -> Map
|
||||||
|
|
||||||
Types:
|
Fields = cowboy:fields():: Cookie fields match rules.
|
||||||
|
Map = map():: Cookie fields matched.
|
||||||
* Fields = cowboy:fields()
|
|
||||||
* Map = map()
|
|
||||||
|
|
||||||
Match cookies against the given fields.
|
Match cookies against the given fields.
|
||||||
|
|
||||||
|
@ -153,12 +161,10 @@ be converted through the use of constraints, making this
|
||||||
function able to extract, validate and convert values all
|
function able to extract, validate and convert values all
|
||||||
in one step.
|
in one step.
|
||||||
|
|
||||||
: match_qs(Fields, Req) -> Map
|
=== match_qs(Fields, Req) -> Map
|
||||||
|
|
||||||
Types:
|
Fields = cowboy:fields():: Query string fields match rules.
|
||||||
|
Map = map():: Query string fields matched.
|
||||||
* Fields = cowboy:fields()
|
|
||||||
* Map = map()
|
|
||||||
|
|
||||||
Match the query string against the given fields.
|
Match the query string against the given fields.
|
||||||
|
|
||||||
|
@ -177,86 +183,88 @@ returned map will be that atom. The value may be converted
|
||||||
through the use of constraints, making this function able
|
through the use of constraints, making this function able
|
||||||
to extract, validate and convert values all in one step.
|
to extract, validate and convert values all in one step.
|
||||||
|
|
||||||
: meta(Name, Req) -> meta(Name, Req, undefined)
|
=== meta(Name, Req) -> meta(Name, Req, undefined)
|
||||||
: meta(Name, Req, Default) -> Value
|
|
||||||
|
|
||||||
Types:
|
Alias for `cowboy_req:meta/3`.
|
||||||
|
|
||||||
* Name = atom()
|
=== meta(Name, Req, Default) -> Value
|
||||||
* Default = any()
|
|
||||||
* Value = any()
|
Name = atom():: Metadata name.
|
||||||
|
Default = any():: Default value.
|
||||||
|
Value = any():: Metadata value.
|
||||||
|
|
||||||
Return metadata about the request.
|
Return metadata about the request.
|
||||||
|
|
||||||
: method(Req) -> Method
|
=== method(Req) -> Method
|
||||||
|
|
||||||
Types:
|
Method = binary():: Request method.
|
||||||
|
|
||||||
* Method = binary()
|
|
||||||
|
|
||||||
Return the method.
|
Return the method.
|
||||||
|
|
||||||
Methods are case sensitive. Standard methods are always uppercase.
|
Methods are case sensitive. Standard methods are always uppercase.
|
||||||
|
|
||||||
: parse_cookies(Req) -> [{Name, Value}]
|
=== parse_cookies(Req) -> [{Name, Value}]
|
||||||
|
|
||||||
Types:
|
Name = binary():: Cookie name.
|
||||||
|
Value = binary():: Cookie value.
|
||||||
* Name = binary()
|
|
||||||
* Value = binary()
|
|
||||||
|
|
||||||
Parse and return all cookies.
|
Parse and return all cookies.
|
||||||
|
|
||||||
Cookie names are case sensitive.
|
Cookie names are case sensitive.
|
||||||
|
|
||||||
: parse_header(Name, Req) -> see below
|
=== parse_header(Name, Req) -> see below
|
||||||
: parse_header(Name, Req, Default) -> ParsedValue | Default
|
|
||||||
|
|
||||||
Types:
|
Alias of `cowboy_req:parse_header/3`.
|
||||||
|
|
||||||
* Name = binary()
|
The `parse_header/2` function will call `parser_header/3` with a
|
||||||
* Default = any()
|
different default value depending on the header being parsed. The
|
||||||
* ParsedValue - see below
|
following table summarizes the default values used.
|
||||||
|
|
||||||
|
[cols="<,^",options="header"]
|
||||||
|
|===
|
||||||
|
| Header name | Header value
|
||||||
|
| content-length | `0`
|
||||||
|
| cookie | `[]`
|
||||||
|
| transfer-encoding | `[<<"identity">>]`
|
||||||
|
| Any other header | `undefined`
|
||||||
|
|===
|
||||||
|
|
||||||
|
=== parse_header(Name, Req, Default) -> ParsedValue | Default
|
||||||
|
|
||||||
|
Name = binary():: Request header name.
|
||||||
|
Default = any():: Default value.
|
||||||
|
ParsedValue - see below:: Parsed request header value.
|
||||||
|
|
||||||
Parse the given header.
|
Parse the given header.
|
||||||
|
|
||||||
While header names are case insensitive, this function expects
|
While header names are case insensitive, this function expects
|
||||||
the name to be a lowercase binary.
|
the name to be a lowercase binary.
|
||||||
|
|
||||||
The `parse_header/2` function will call `parser_header/3` with a
|
|
||||||
different default value depending on the header being parsed. The
|
|
||||||
following table summarizes the default values used.
|
|
||||||
|
|
||||||
|| Header name Default value
|
|
||||||
|
|
|
||||||
| content-length `0`
|
|
||||||
| cookie `[]`
|
|
||||||
| transfer-encoding `[<<"identity">>]`
|
|
||||||
| Any other header `undefined`
|
|
||||||
|
|
||||||
The parsed value differs depending on the header being parsed. The
|
The parsed value differs depending on the header being parsed. The
|
||||||
following table summarizes the different types returned.
|
following table summarizes the different types returned.
|
||||||
|
|
||||||
|| Header name Type
|
[cols="<,^",options="header"]
|
||||||
|
|
|===
|
||||||
| accept `[{{Type, SubType, Params}, Quality, AcceptExt}]`
|
| Header name | Type of parsed header value
|
||||||
| accept-charset `[{Charset, Quality}]`
|
| accept | `[{{Type, SubType, Params}, Quality, AcceptExt}]`
|
||||||
| accept-encoding `[{Encoding, Quality}]`
|
| accept-charset | `[{Charset, Quality}]`
|
||||||
| accept-language `[{LanguageTag, Quality}]`
|
| accept-encoding | `[{Encoding, Quality}]`
|
||||||
| authorization `{AuthType, Credentials}`
|
| accept-language | `[{LanguageTag, Quality}]`
|
||||||
| content-length `non_neg_integer()`
|
| authorization | `{AuthType, Credentials}`
|
||||||
| content-type `{Type, SubType, ContentTypeParams}`
|
| content-length | `non_neg_integer()`
|
||||||
| cookie `[{binary(), binary()}]`
|
| content-type | `{Type, SubType, ContentTypeParams}`
|
||||||
| expect `[Expect | {Expect, ExpectValue, Params}]`
|
| cookie | `[{binary(), binary()}]`
|
||||||
| if-match `'*' | [{weak | strong, OpaqueTag}]`
|
| expect | `[Expect \| {Expect, ExpectValue, Params}]`
|
||||||
| if-modified-since `calendar:datetime()`
|
| if-match | `'*' \| [{weak \| strong, OpaqueTag}]`
|
||||||
| if-none-match `'*' | [{weak | strong, OpaqueTag}]`
|
| if-modified-since | `calendar:datetime()`
|
||||||
| if-unmodified-since `calendar:datetime()`
|
| if-none-match | `'*' \| [{weak \| strong, OpaqueTag}]`
|
||||||
| range `{Unit, [Range]}`
|
| if-unmodified-since | `calendar:datetime()`
|
||||||
| sec-websocket-protocol `[binary()]`
|
| range | `{Unit, [Range]}`
|
||||||
| transfer-encoding `[binary()]`
|
| sec-websocket-protocol | `[binary()]`
|
||||||
| upgrade `[binary()]`
|
| transfer-encoding | `[binary()]`
|
||||||
| x-forwarded-for `[binary()]`
|
| upgrade | `[binary()]`
|
||||||
|
| x-forwarded-for | `[binary()]`
|
||||||
|
|===
|
||||||
|
|
||||||
Types for the above table:
|
Types for the above table:
|
||||||
|
|
||||||
|
@ -292,12 +300,10 @@ The range header value `Range` can take three forms:
|
||||||
An `undefined` tuple will be returned if Cowboy doesn't know how
|
An `undefined` tuple will be returned if Cowboy doesn't know how
|
||||||
to parse the requested header.
|
to parse the requested header.
|
||||||
|
|
||||||
: parse_qs(Req) -> [{Name, Value}]
|
=== parse_qs(Req) -> [{Name, Value}]
|
||||||
|
|
||||||
Types:
|
Name = binary():: Query string field name.
|
||||||
|
Value = binary() | true:: Query string field value.
|
||||||
* Name = binary()
|
|
||||||
* Value = binary() | true
|
|
||||||
|
|
||||||
Return the request's query string as a list of tuples.
|
Return the request's query string as a list of tuples.
|
||||||
|
|
||||||
|
@ -306,35 +312,27 @@ Keys with no value are different from keys with an empty
|
||||||
value in that they do not have a `=` indicating the presence
|
value in that they do not have a `=` indicating the presence
|
||||||
of a value.
|
of a value.
|
||||||
|
|
||||||
: path(Req) -> Path
|
=== path(Req) -> Path
|
||||||
|
|
||||||
Types:
|
Path = binary():: Requested path.
|
||||||
|
|
||||||
* Path = binary()
|
|
||||||
|
|
||||||
Return the requested path.
|
Return the requested path.
|
||||||
|
|
||||||
: path_info(Req) -> PathInfo
|
=== path_info(Req) -> PathInfo
|
||||||
|
|
||||||
Types:
|
PathInfo = cowboy_router:tokens() | undefined:: Extra tokens for the path.
|
||||||
|
|
||||||
* PathInfo = cowboy_router:tokens() | undefined
|
|
||||||
|
|
||||||
Return the extra tokens from matching against `...` during routing.
|
Return the extra tokens from matching against `...` during routing.
|
||||||
|
|
||||||
: peer(Req) -> Peer
|
=== peer(Req) -> Peer
|
||||||
|
|
||||||
Types:
|
Peer = {inet:ip_address(), inet:port_number()}:: Peer IP address and port number.
|
||||||
|
|
||||||
* Peer = {inet:ip_address(), inet:port_number()}
|
|
||||||
|
|
||||||
Return the client's IP address and port number.
|
Return the client's IP address and port number.
|
||||||
|
|
||||||
: port(Req) -> Port
|
=== port(Req) -> Port
|
||||||
|
|
||||||
Types:
|
Port = inet:port_number():: Requested port number.
|
||||||
|
|
||||||
* Port = inet:port_number()
|
|
||||||
|
|
||||||
Return the request's port.
|
Return the request's port.
|
||||||
|
|
||||||
|
@ -342,54 +340,46 @@ The port returned by this function is obtained by parsing
|
||||||
the host header. It may be different than the actual port
|
the host header. It may be different than the actual port
|
||||||
the client used to connect to the Cowboy server.
|
the client used to connect to the Cowboy server.
|
||||||
|
|
||||||
: qs(Req) -> QueryString
|
=== qs(Req) -> QueryString
|
||||||
|
|
||||||
Types:
|
QueryString = binary():: Unprocessed query string.
|
||||||
|
|
||||||
* QueryString = binary()
|
|
||||||
|
|
||||||
Return the request's query string.
|
Return the request's query string.
|
||||||
|
|
||||||
: set_meta(Name, Value, Req) -> Req2
|
=== set_meta(Name, Value, Req) -> Req2
|
||||||
|
|
||||||
Types:
|
Name = atom():: Metadata name.
|
||||||
|
Value = any():: Metadata value.
|
||||||
* Name = atom()
|
|
||||||
* Value = any()
|
|
||||||
|
|
||||||
Set metadata about the request.
|
Set metadata about the request.
|
||||||
|
|
||||||
An existing value will be overwritten.
|
An existing value will be overwritten.
|
||||||
|
|
||||||
: url(Req) -> URL
|
=== url(Req) -> URL
|
||||||
|
|
||||||
Types:
|
URL = binary() | undefined:: Requested URL.
|
||||||
|
|
||||||
* URL = binary() | undefined
|
|
||||||
|
|
||||||
Return the requested URL.
|
Return the requested URL.
|
||||||
|
|
||||||
This function will always return `undefined` until the
|
This function will always return `undefined` until the
|
||||||
`cowboy_router` middleware has been executed.
|
`cowboy_router` middleware has been executed.
|
||||||
|
|
||||||
: version(Req) -> Version
|
=== version(Req) -> Version
|
||||||
|
|
||||||
Types:
|
Version = cowboy:http_version():: Client's advertised HTTP version.
|
||||||
|
|
||||||
* Version = cowboy:http_version()
|
|
||||||
|
|
||||||
Return the HTTP version used for this request.
|
Return the HTTP version used for this request.
|
||||||
|
|
||||||
:: Request body related exports
|
== Request body related exports
|
||||||
|
|
||||||
: body(Req) -> body(Req, [])
|
=== body(Req) -> body(Req, [])
|
||||||
: body(Req, Opts) -> {ok, Data, Req2} | {more, Data, Req2}
|
|
||||||
|
|
||||||
Types:
|
Alias of `cowboy_req:body/2`.
|
||||||
|
|
||||||
* Opts = [body_opt()]
|
=== body(Req, Opts) -> {ok, Data, Req2} | {more, Data, Req2}
|
||||||
* Data = binary()
|
|
||||||
* Reason = atom()
|
Opts = [body_opt()]:: Request body reading options.
|
||||||
|
Data = binary():: Data read from the body.
|
||||||
|
|
||||||
Read the request body.
|
Read the request body.
|
||||||
|
|
||||||
|
@ -422,11 +412,9 @@ the content-length header if it wasn't already there.
|
||||||
This function can only be called once. Cowboy will not cache
|
This function can only be called once. Cowboy will not cache
|
||||||
the result of this call.
|
the result of this call.
|
||||||
|
|
||||||
: body_length(Req) -> Length
|
=== body_length(Req) -> Length
|
||||||
|
|
||||||
Types:
|
Length = non_neg_integer() | undefined:: Length of the request body.
|
||||||
|
|
||||||
* Length = non_neg_integer() | undefined
|
|
||||||
|
|
||||||
Return the length of the request body.
|
Return the length of the request body.
|
||||||
|
|
||||||
|
@ -434,16 +422,15 @@ The length will only be returned if the request does not
|
||||||
use any transfer-encoding and if the content-length header
|
use any transfer-encoding and if the content-length header
|
||||||
is present.
|
is present.
|
||||||
|
|
||||||
: body_qs(Req) -> body_qs(Req,
|
=== body_qs(Req) -> body_qs(Req, [{length, 64000}, {read_length, 64000}, {read_timeout, 5000}])
|
||||||
[{length, 64000}, {read_length, 64000}, {read_timeout, 5000}])
|
|
||||||
: body_qs(Req, Opts) -> {ok, [{Name, Value}], Req2} | {badlength, Req2}
|
|
||||||
|
|
||||||
Types:
|
Alias of `cowboy_req:body_qs/2`.
|
||||||
|
|
||||||
* Opts = [body_opt()]
|
=== body_qs(Req, Opts) -> {ok, [{Name, Value}], Req2} | {badlength, Req2}
|
||||||
* Name = binary()
|
|
||||||
* Value = binary() | true
|
Opts = [body_opt()]:: Request body reading options.
|
||||||
* Reason = chunked | badlength | atom()
|
Name = binary():: Field name.
|
||||||
|
Value = binary() | true:: Field value.
|
||||||
|
|
||||||
Return the request body as a list of tuples.
|
Return the request body as a list of tuples.
|
||||||
|
|
||||||
|
@ -459,18 +446,18 @@ body is larger then a `badlength` tuple is returned.
|
||||||
This function can only be called once. Cowboy will not cache
|
This function can only be called once. Cowboy will not cache
|
||||||
the result of this call.
|
the result of this call.
|
||||||
|
|
||||||
: has_body(Req) -> boolean()
|
=== has_body(Req) -> boolean()
|
||||||
|
|
||||||
Return whether the request has a body.
|
Return whether the request has a body.
|
||||||
|
|
||||||
: part(Req) -> part(Req,
|
=== part(Req) -> part(Req, [{length, 64000}, {read_length, 64000}, {read_timeout, 5000}])
|
||||||
[{length, 64000}, {read_length, 64000}, {read_timeout, 5000}])
|
|
||||||
: part(Req, Opts) -> {ok, Headers, Req2} | {done, Req2}
|
|
||||||
|
|
||||||
Types:
|
Alias of `cowboy_req:part/2`.
|
||||||
|
|
||||||
* Opts = [body_opt()]
|
=== part(Req, Opts) -> {ok, Headers, Req2} | {done, Req2}
|
||||||
* Headers = cow_multipart:headers()
|
|
||||||
|
Opts = [body_opt()]:: Request body reading options.
|
||||||
|
Headers = cow_multipart:headers():: Part's headers.
|
||||||
|
|
||||||
Read the headers for the next part of the multipart message.
|
Read the headers for the next part of the multipart message.
|
||||||
|
|
||||||
|
@ -496,13 +483,14 @@ of 64KB with a timeout of 5s. This is tailored for reading
|
||||||
part headers, not for skipping the previous part's body.
|
part headers, not for skipping the previous part's body.
|
||||||
You might want to consider skipping large parts manually.
|
You might want to consider skipping large parts manually.
|
||||||
|
|
||||||
: part_body(Req) -> part_body(Req, [])
|
=== part_body(Req) -> part_body(Req, [])
|
||||||
: part_body(Req, Opts) -> {ok, Data, Req2} | {more, Data, Req2}
|
|
||||||
|
|
||||||
Types:
|
Alias of `cowboy_req:part_body/2`.
|
||||||
|
|
||||||
* Opts = [body_opt()]
|
=== part_body(Req, Opts) -> {ok, Data, Req2} | {more, Data, Req2}
|
||||||
* Data = binary()
|
|
||||||
|
Opts = [body_opt()]:: Request body reading options.
|
||||||
|
Data = binary():: Part's body.
|
||||||
|
|
||||||
Read the body of the current part of the multipart message.
|
Read the body of the current part of the multipart message.
|
||||||
|
|
||||||
|
@ -520,14 +508,11 @@ returned inside an `ok` tuple.
|
||||||
Note that once the body has been read, fully or partially,
|
Note that once the body has been read, fully or partially,
|
||||||
it cannot be read again.
|
it cannot be read again.
|
||||||
|
|
||||||
:: Response related exports
|
== Response related exports
|
||||||
|
|
||||||
: chunk(Data, Req) -> ok
|
=== chunk(Data, Req) -> ok
|
||||||
|
|
||||||
Types:
|
Data = iodata():: Chunk data to be sent.
|
||||||
|
|
||||||
* Data = iodata()
|
|
||||||
* Reason = atom()
|
|
||||||
|
|
||||||
Send a chunk of data.
|
Send a chunk of data.
|
||||||
|
|
||||||
|
@ -540,13 +525,14 @@ If the request uses HTTP/1.0, the data is sent directly
|
||||||
without wrapping it in an HTTP/1.1 chunk, providing
|
without wrapping it in an HTTP/1.1 chunk, providing
|
||||||
compatibility with older clients.
|
compatibility with older clients.
|
||||||
|
|
||||||
: chunked_reply(StatusCode, Req) -> chunked_reply(StatusCode, [], Req)
|
=== chunked_reply(StatusCode, Req) -> chunked_reply(StatusCode, [], Req)
|
||||||
: chunked_reply(StatusCode, Headers, Req) -> Req2
|
|
||||||
|
|
||||||
Types:
|
Alias of `cowboy_req:chunked_reply/3`.
|
||||||
|
|
||||||
* StatusCode = cowboy:http_status()
|
=== chunked_reply(StatusCode, Headers, Req) -> Req2
|
||||||
* Headers = cowboy:http_headers()
|
|
||||||
|
StatusCode = cowboy:http_status():: Response status code.
|
||||||
|
Headers = cowboy:http_headers():: Response headers.
|
||||||
|
|
||||||
Send a response using chunked transfer-encoding.
|
Send a response using chunked transfer-encoding.
|
||||||
|
|
||||||
|
@ -564,11 +550,7 @@ compatibility with older clients.
|
||||||
This function can only be called once, with the exception
|
This function can only be called once, with the exception
|
||||||
of overriding the response in the `onresponse` hook.
|
of overriding the response in the `onresponse` hook.
|
||||||
|
|
||||||
: continue(Req) -> ok
|
=== continue(Req) -> ok
|
||||||
|
|
||||||
Types:
|
|
||||||
|
|
||||||
* Reason = atom()
|
|
||||||
|
|
||||||
Send a 100 Continue intermediate reply.
|
Send a 100 Continue intermediate reply.
|
||||||
|
|
||||||
|
@ -581,44 +563,44 @@ you may want to do it manually by disabling this behavior
|
||||||
with the `continue` body option and then calling this
|
with the `continue` body option and then calling this
|
||||||
function.
|
function.
|
||||||
|
|
||||||
: delete_resp_header(Name, Req) -> Req2
|
=== delete_resp_header(Name, Req) -> Req2
|
||||||
|
|
||||||
Types:
|
Name = binary():: Response header name.
|
||||||
|
|
||||||
* Name = binary()
|
|
||||||
|
|
||||||
Delete the given response header.
|
Delete the given response header.
|
||||||
|
|
||||||
While header names are case insensitive, this function expects
|
While header names are case insensitive, this function expects
|
||||||
the name to be a lowercase binary.
|
the name to be a lowercase binary.
|
||||||
|
|
||||||
: has_resp_body(Req) -> boolean()
|
=== has_resp_body(Req) -> boolean()
|
||||||
|
|
||||||
Return whether a response body has been set.
|
Return whether a response body has been set.
|
||||||
|
|
||||||
This function will return false if a response body has
|
This function will return false if a response body has
|
||||||
been set with a length of 0.
|
been set with a length of 0.
|
||||||
|
|
||||||
: has_resp_header(Name, Req) -> boolean()
|
=== has_resp_header(Name, Req) -> boolean()
|
||||||
|
|
||||||
Types:
|
Name = binary():: Response header name.
|
||||||
|
|
||||||
* Name = binary()
|
|
||||||
|
|
||||||
Return whether the given response header has been set.
|
Return whether the given response header has been set.
|
||||||
|
|
||||||
While header names are case insensitive, this function expects
|
While header names are case insensitive, this function expects
|
||||||
the name to be a lowercase binary.
|
the name to be a lowercase binary.
|
||||||
|
|
||||||
: reply(StatusCode, Req) -> reply(StatusCode, [], Req)
|
=== reply(StatusCode, Req) -> reply(StatusCode, [], Req)
|
||||||
: reply(StatusCode, Headers, Req) - see below
|
|
||||||
: reply(StatusCode, Headers, Body, Req) -> Req2
|
|
||||||
|
|
||||||
Types:
|
Alias of `cowboy_req:reply/3`.
|
||||||
|
|
||||||
* StatusCode = cowboy:http_status()
|
=== reply(StatusCode, Headers, Req) - see below
|
||||||
* Headers = cowboy:http_headers()
|
|
||||||
* Body = iodata()
|
Alias of `cowboy_req:reply/4`, with caveats.
|
||||||
|
|
||||||
|
=== reply(StatusCode, Headers, Body, Req) -> Req2
|
||||||
|
|
||||||
|
StatusCode = cowboy:http_status():: Response status code.
|
||||||
|
Headers = cowboy:http_headers():: Response headers.
|
||||||
|
Body = iodata():: Response body.
|
||||||
|
|
||||||
Send a response.
|
Send a response.
|
||||||
|
|
||||||
|
@ -639,26 +621,25 @@ returns.
|
||||||
This function can only be called once, with the exception
|
This function can only be called once, with the exception
|
||||||
of overriding the response in the `onresponse` hook.
|
of overriding the response in the `onresponse` hook.
|
||||||
|
|
||||||
: set_resp_body(Body, Req) -> Req2
|
=== set_resp_body(Body, Req) -> Req2
|
||||||
|
|
||||||
Types:
|
Body = iodata():: Response body.
|
||||||
|
|
||||||
* Body = iodata()
|
|
||||||
|
|
||||||
Set a response body.
|
Set a response body.
|
||||||
|
|
||||||
This body will not be sent if `chunked_reply/{2,3}` or
|
This body will not be sent if `chunked_reply/{2,3}` or
|
||||||
`reply/4` is used, as they override it.
|
`reply/4` is used, as they override it.
|
||||||
|
|
||||||
: set_resp_body_fun(Fun, Req) -> Req2
|
=== set_resp_body_fun(Fun, Req) -> Req2
|
||||||
: set_resp_body_fun(Length, Fun, Req) -> Req2
|
|
||||||
|
|
||||||
Types:
|
Alias of `cowboy_req:set_resp_body_fun/3`.
|
||||||
|
|
||||||
* Fun = fun((Socket, Transport) -> ok)
|
=== set_resp_body_fun(Length, Fun, Req) -> Req2
|
||||||
* Socket = inet:socket()
|
|
||||||
* Transport = module()
|
Fun = fun((Socket, Transport) -> ok):: Fun that will send the response body.
|
||||||
* Length = non_neg_integer()
|
Socket = inet:socket():: Socket for this connection.
|
||||||
|
Transport = module():: Transport module for this socket.
|
||||||
|
Length = non_neg_integer():: Length of the response body.
|
||||||
|
|
||||||
Set a fun for sending the response body.
|
Set a fun for sending the response body.
|
||||||
|
|
||||||
|
@ -673,12 +654,10 @@ using the `reply/2` or `reply/3` function.
|
||||||
The fun will receive the Ranch `Socket` and `Transport` as
|
The fun will receive the Ranch `Socket` and `Transport` as
|
||||||
arguments. Only send and sendfile operations are supported.
|
arguments. Only send and sendfile operations are supported.
|
||||||
|
|
||||||
: set_resp_body_fun(chunked, Fun, Req) -> Req2
|
=== set_resp_body_fun(chunked, Fun, Req) -> Req2
|
||||||
|
|
||||||
Types:
|
Fun = fun((ChunkFun) -> ok):: Fun that will send the response body.
|
||||||
|
ChunkFun = fun((iodata()) -> ok):: Fun to call for every chunk to be sent.
|
||||||
* Fun = fun((ChunkFun) -> ok)
|
|
||||||
* ChunkFun = fun((iodata()) -> ok)
|
|
||||||
|
|
||||||
Set a fun for sending the response body using chunked transfer-encoding.
|
Set a fun for sending the response body using chunked transfer-encoding.
|
||||||
|
|
||||||
|
@ -690,24 +669,20 @@ be used to send chunks in a similar way to the `chunk/2` function,
|
||||||
except the fun only takes one argument, the data to be sent in
|
except the fun only takes one argument, the data to be sent in
|
||||||
the chunk.
|
the chunk.
|
||||||
|
|
||||||
: set_resp_cookie(Name, Value, Opts, Req) -> Req2
|
=== set_resp_cookie(Name, Value, Opts, Req) -> Req2
|
||||||
|
|
||||||
Types:
|
Name = iodata():: Cookie name.
|
||||||
|
Value = iodata():: Cookie value.
|
||||||
* Name = iodata()
|
Opts = cookie_opts():: Cookie options.
|
||||||
* Value = iodata()
|
|
||||||
* Opts = cookie_opts()
|
|
||||||
|
|
||||||
Set a cookie in the response.
|
Set a cookie in the response.
|
||||||
|
|
||||||
Cookie names are case sensitive.
|
Cookie names are case sensitive.
|
||||||
|
|
||||||
: set_resp_header(Name, Value, Req) -> Req2
|
=== set_resp_header(Name, Value, Req) -> Req2
|
||||||
|
|
||||||
Types:
|
Name = binary():: Response header name.
|
||||||
|
Value = iodata():: Response header value.
|
||||||
* Name = binary()
|
|
||||||
* Value = iodata()
|
|
||||||
|
|
||||||
Set a response header.
|
Set a response header.
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
::: cowboy_rest
|
= cowboy_rest(3)
|
||||||
|
|
||||||
|
== Name
|
||||||
|
|
||||||
|
cowboy_rest - REST handlers
|
||||||
|
|
||||||
|
== Description
|
||||||
|
|
||||||
The `cowboy_rest` module implements REST semantics on top of
|
The `cowboy_rest` module implements REST semantics on top of
|
||||||
the HTTP protocol.
|
the HTTP protocol.
|
||||||
|
@ -6,66 +12,53 @@ the HTTP protocol.
|
||||||
This module is a sub protocol that defines many callbacks
|
This module is a sub protocol that defines many callbacks
|
||||||
be implemented by handlers. The `init/2` and `terminate/3`
|
be implemented by handlers. The `init/2` and `terminate/3`
|
||||||
callbacks are common to all handler types and are documented
|
callbacks are common to all handler types and are documented
|
||||||
in the manual for the ^cowboy_handler module.
|
in the manual for the link:cowboy_handler.asciidoc[cowboy_handler] module.
|
||||||
|
|
||||||
All other callbacks are optional, though some may become
|
All other callbacks are optional, though some may become
|
||||||
required depending on the return value of previous callbacks.
|
required depending on the return value of previous callbacks.
|
||||||
|
|
||||||
:: Meta values
|
== Meta values
|
||||||
|
|
||||||
: charset
|
charset = binary()::
|
||||||
|
Negotiated charset.
|
||||||
|
+
|
||||||
|
This value may not be defined if no charset was negotiated.
|
||||||
|
|
||||||
Type: binary()
|
language = binary()::
|
||||||
|
Negotiated language.
|
||||||
|
+
|
||||||
|
This value may not be defined if no language was negotiated.
|
||||||
|
|
||||||
Negotiated charset.
|
media_type = {binary(), binary(), '*' | [{binary(), binary()}]}::
|
||||||
|
Negotiated media-type.
|
||||||
|
+
|
||||||
|
The media-type is the content-type, excluding the charset.
|
||||||
|
+
|
||||||
|
This value is always defined after the call to
|
||||||
|
`content_types_provided/2`.
|
||||||
|
|
||||||
This value may not be defined if no charset was negotiated.
|
== Terminate reasons
|
||||||
|
|
||||||
: language
|
|
||||||
|
|
||||||
Type: binary()
|
|
||||||
|
|
||||||
Negotiated language.
|
|
||||||
|
|
||||||
This value may not be defined if no language was negotiated.
|
|
||||||
|
|
||||||
: media_type
|
|
||||||
|
|
||||||
Type: {binary(), binary(), '*' | [{binary(), binary()}]}
|
|
||||||
|
|
||||||
Negotiated media-type.
|
|
||||||
|
|
||||||
The media-type is the content-type, excluding the charset.
|
|
||||||
|
|
||||||
This value is always defined after the call to
|
|
||||||
`content_types_provided/2`.
|
|
||||||
|
|
||||||
:: Terminate reasons
|
|
||||||
|
|
||||||
The following values may be received as the terminate reason
|
The following values may be received as the terminate reason
|
||||||
in the optional `terminate/3` callback.
|
in the optional `terminate/3` callback.
|
||||||
|
|
||||||
: normal
|
normal::
|
||||||
|
The connection was closed normally.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
: {crash, Class, Reason}
|
== Callbacks
|
||||||
|
|
||||||
A crash occurred in the handler. `Class` and `Reason` can be
|
=== Callback(Req, State) -> {Value, Req, State} | {stop, Req, State}
|
||||||
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
|
Callback:: One of the REST callbacks described below.
|
||||||
|
Req = cowboy_req:req():: The Req object.
|
||||||
: Callback(Req, State) -> {Value, Req, State} | {stop, Req, State}
|
State = any():: Handler state.
|
||||||
|
Value:: See the REST callbacks description below.
|
||||||
Types:
|
|
||||||
|
|
||||||
* Callback - one of the REST callbacks described below
|
|
||||||
* Req = cowboy_req:req()
|
|
||||||
* State = any()
|
|
||||||
* Value - see the REST callbacks description below
|
|
||||||
|
|
||||||
Please see the REST callbacks description below for details
|
Please see the REST callbacks description below for details
|
||||||
on the `Value` type, the default value if the callback is
|
on the `Value` type, the default value if the callback is
|
||||||
|
@ -76,23 +69,23 @@ The `stop` tuple can be returned to stop REST processing.
|
||||||
It is up to the resource code to send a reply before that,
|
It is up to the resource code to send a reply before that,
|
||||||
otherwise a `204 No Content` will be sent.
|
otherwise a `204 No Content` will be sent.
|
||||||
|
|
||||||
:: REST callbacks description
|
== REST callbacks description
|
||||||
|
|
||||||
: allowed_methods
|
=== allowed_methods
|
||||||
|
|
||||||
* Methods: all
|
Methods:: all
|
||||||
* Value type: [binary()]
|
Value type:: [binary()]
|
||||||
* Default value: [<<"GET">>, <<"HEAD">>, <<"OPTIONS">>]
|
Default value:: `[<<"GET">>, <<"HEAD">>, <<"OPTIONS">>]`
|
||||||
|
|
||||||
Return the list of allowed methods.
|
Return the list of allowed methods.
|
||||||
|
|
||||||
Methods are case sensitive. Standard methods are always uppercase.
|
Methods are case sensitive. Standard methods are always uppercase.
|
||||||
|
|
||||||
: allow_missing_post
|
=== allow_missing_post
|
||||||
|
|
||||||
* Methods: POST
|
Methods:: POST
|
||||||
* Value type: boolean()
|
Value type:: boolean()
|
||||||
* Default value: true
|
Default value:: true
|
||||||
|
|
||||||
Return whether POST is allowed when the resource doesn't exist.
|
Return whether POST is allowed when the resource doesn't exist.
|
||||||
|
|
||||||
|
@ -100,11 +93,11 @@ Returning `true` here means that a new resource will be
|
||||||
created. The URL to the created resource should also be
|
created. The URL to the created resource should also be
|
||||||
returned from the `AcceptResource` callback.
|
returned from the `AcceptResource` callback.
|
||||||
|
|
||||||
: charsets_provided
|
=== charsets_provided
|
||||||
|
|
||||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||||
* Value type: [binary()]
|
Value type:: [binary()]
|
||||||
* Skip to the next step if undefined
|
Default behavior:: Skip to the next step if undefined.
|
||||||
|
|
||||||
Return the list of charsets the resource provides.
|
Return the list of charsets the resource provides.
|
||||||
|
|
||||||
|
@ -120,14 +113,14 @@ value `charset`.
|
||||||
While charsets are case insensitive, this callback is expected
|
While charsets are case insensitive, this callback is expected
|
||||||
to return them as lowercase binary.
|
to return them as lowercase binary.
|
||||||
|
|
||||||
: content_types_accepted
|
=== content_types_accepted
|
||||||
|
|
||||||
* Methods: POST, PUT, PATCH
|
Methods:: POST, PUT, PATCH
|
||||||
* No default
|
Value type:: [{binary() | {Type, SubType, Params}, AcceptResource}]
|
||||||
|
Default behavior:: Crash if undefined.
|
||||||
|
|
||||||
Types:
|
With types:
|
||||||
|
|
||||||
* Value = [{binary() | {Type, SubType, Params}, AcceptResource}]
|
|
||||||
* Type = SubType = binary()
|
* Type = SubType = binary()
|
||||||
* Params = '*' | [{binary(), binary()}]
|
* Params = '*' | [{binary(), binary()}]
|
||||||
* AcceptResource = atom()
|
* AcceptResource = atom()
|
||||||
|
@ -155,8 +148,8 @@ different list for each methods.
|
||||||
The `AcceptResource` value is the name of the callback that will
|
The `AcceptResource` value is the name of the callback that will
|
||||||
be called if the content-type matches. It is defined as follow.
|
be called if the content-type matches. It is defined as follow.
|
||||||
|
|
||||||
* Value type: true | {true, URL} | false
|
Value type:: true | {true, URL} | false
|
||||||
* No default
|
Default behavior:: Crash if undefined.
|
||||||
|
|
||||||
Process the request body.
|
Process the request body.
|
||||||
|
|
||||||
|
@ -174,14 +167,14 @@ and language can be retrieved using the `cowboy_req:meta/{2,3}`
|
||||||
functions. The respective keys are `media_type`, `charset`
|
functions. The respective keys are `media_type`, `charset`
|
||||||
and `language`. The body can be set using `cowboy_req:set_resp_body/2`.
|
and `language`. The body can be set using `cowboy_req:set_resp_body/2`.
|
||||||
|
|
||||||
: content_types_provided
|
=== content_types_provided
|
||||||
|
|
||||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||||
* Default value: [{{<<"text">>, <<"html">>, '*'}, to_html}]
|
Value type:: [{binary() | {Type, SubType, Params}, ProvideResource}]
|
||||||
|
Default value:: `[{{<<"text">>, <<"html">>, '*'}, to_html}]`
|
||||||
|
|
||||||
Types:
|
With types:
|
||||||
|
|
||||||
* Value = [{binary() | {Type, SubType, Params}, ProvideResource}]
|
|
||||||
* Type = SubType = binary()
|
* Type = SubType = binary()
|
||||||
* Params = '*' | [{binary(), binary()}]
|
* Params = '*' | [{binary(), binary()}]
|
||||||
* ProvideResource = atom()
|
* ProvideResource = atom()
|
||||||
|
@ -205,9 +198,9 @@ be called if the content-type matches. It will only be called when
|
||||||
a representation of the resource needs to be returned. It is defined
|
a representation of the resource needs to be returned. It is defined
|
||||||
as follow.
|
as follow.
|
||||||
|
|
||||||
* Methods: GET, HEAD
|
Methods:: GET, HEAD
|
||||||
* Value type: iodata() | {stream, Fun} | {stream, Len, Fun} | {chunked, ChunkedFun}
|
Value type:: iodata() | {stream, Fun} | {stream, Len, Fun} | {chunked, ChunkedFun}
|
||||||
* No default
|
Default behavior:: Crash if undefined.
|
||||||
|
|
||||||
Return the response body.
|
Return the response body.
|
||||||
|
|
||||||
|
@ -220,11 +213,11 @@ The call to this callback happens a good time after the call to
|
||||||
`content_types_provided/2`, when it is time to start rendering
|
`content_types_provided/2`, when it is time to start rendering
|
||||||
the response body.
|
the response body.
|
||||||
|
|
||||||
: delete_completed
|
=== delete_completed
|
||||||
|
|
||||||
* Methods: DELETE
|
Methods:: DELETE
|
||||||
* Value type: boolean()
|
Value type:: boolean()
|
||||||
* Default value: true
|
Default value:: true
|
||||||
|
|
||||||
Return whether the delete action has been completed.
|
Return whether the delete action has been completed.
|
||||||
|
|
||||||
|
@ -235,11 +228,11 @@ including from any internal cache.
|
||||||
When this function returns `false`, a `202 Accepted`
|
When this function returns `false`, a `202 Accepted`
|
||||||
response will be sent instead of a `200 OK` or `204 No Content`.
|
response will be sent instead of a `200 OK` or `204 No Content`.
|
||||||
|
|
||||||
: delete_resource
|
=== delete_resource
|
||||||
|
|
||||||
* Methods: DELETE
|
Methods:: DELETE
|
||||||
* Value type: boolean()
|
Value type:: boolean()
|
||||||
* Default value: false
|
Default value:: false
|
||||||
|
|
||||||
Delete the resource.
|
Delete the resource.
|
||||||
|
|
||||||
|
@ -247,21 +240,21 @@ The value returned indicates if the action was successful,
|
||||||
regardless of whether the resource is immediately deleted
|
regardless of whether the resource is immediately deleted
|
||||||
from the system.
|
from the system.
|
||||||
|
|
||||||
: expires
|
=== expires
|
||||||
|
|
||||||
* Methods: GET, HEAD
|
Methods:: GET, HEAD
|
||||||
* Value type: calendar:datetime() | binary() | undefined
|
Value type:: calendar:datetime() | binary() | undefined
|
||||||
* Default value: undefined
|
Default value:: undefined
|
||||||
|
|
||||||
Return the date of expiration of the resource.
|
Return the date of expiration of the resource.
|
||||||
|
|
||||||
This date will be sent as the value of the expires header.
|
This date will be sent as the value of the expires header.
|
||||||
|
|
||||||
: forbidden
|
=== forbidden
|
||||||
|
|
||||||
* Methods: all
|
Methods:: all
|
||||||
* Value type: boolean()
|
Value type:: boolean()
|
||||||
* Default value: false
|
Default value:: false
|
||||||
|
|
||||||
Return whether access to the resource is forbidden.
|
Return whether access to the resource is forbidden.
|
||||||
|
|
||||||
|
@ -270,11 +263,11 @@ function returns `true`. This status code means that
|
||||||
access is forbidden regardless of authentication,
|
access is forbidden regardless of authentication,
|
||||||
and that the request shouldn't be repeated.
|
and that the request shouldn't be repeated.
|
||||||
|
|
||||||
: generate_etag
|
=== generate_etag
|
||||||
|
|
||||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||||
* Value type: binary() | {weak | strong, binary()}
|
Value type:: binary() | {weak | strong, binary()}
|
||||||
* Default value: undefined
|
Default value:: undefined
|
||||||
|
|
||||||
Return the entity tag of the resource.
|
Return the entity tag of the resource.
|
||||||
|
|
||||||
|
@ -284,13 +277,13 @@ If a binary is returned, then the value will be parsed
|
||||||
to the tuple form automatically. The value must be in
|
to the tuple form automatically. The value must be in
|
||||||
the same format as the etag header, including quotes.
|
the same format as the etag header, including quotes.
|
||||||
|
|
||||||
: is_authorized
|
=== is_authorized
|
||||||
|
|
||||||
* Methods: all
|
Methods:: all
|
||||||
* Value type: true | {false, AuthHeader}
|
Value type:: true | {false, AuthHeader}
|
||||||
* Default value: true
|
Default value:: true
|
||||||
|
|
||||||
Types:
|
With types:
|
||||||
|
|
||||||
* AuthHead = iodata()
|
* AuthHead = iodata()
|
||||||
|
|
||||||
|
@ -304,22 +297,22 @@ If the authentication fails, the value returned will be sent
|
||||||
as the value for the www-authenticate header in the
|
as the value for the www-authenticate header in the
|
||||||
`401 Unauthorized` response.
|
`401 Unauthorized` response.
|
||||||
|
|
||||||
: is_conflict
|
=== is_conflict
|
||||||
|
|
||||||
* Methods: PUT
|
Methods:: PUT
|
||||||
* Value type: boolean()
|
Value type:: boolean()
|
||||||
* Default value: false
|
Default value:: false
|
||||||
|
|
||||||
Return whether the put action results in a conflict.
|
Return whether the put action results in a conflict.
|
||||||
|
|
||||||
A `409 Conflict` response will be sent if this function
|
A `409 Conflict` response will be sent if this function
|
||||||
returns `true`.
|
returns `true`.
|
||||||
|
|
||||||
: known_methods
|
=== known_methods
|
||||||
|
|
||||||
* Methods: all
|
Methods:: all
|
||||||
* Value type: [binary()]
|
Value type:: [binary()]
|
||||||
* Default value: [<<"GET">>, <<"HEAD">>, <<"POST">>, <<"PUT">>, <<"PATCH">>, <<"DELETE">>, <<"OPTIONS">>]
|
Default value:: `[<<"GET">>, <<"HEAD">>, <<"POST">>, <<"PUT">>, <<"PATCH">>, <<"DELETE">>, <<"OPTIONS">>]`
|
||||||
|
|
||||||
Return the list of known methods.
|
Return the list of known methods.
|
||||||
|
|
||||||
|
@ -331,11 +324,11 @@ implement in `cowboy_rest`.
|
||||||
|
|
||||||
Methods are case sensitive. Standard methods are always uppercase.
|
Methods are case sensitive. Standard methods are always uppercase.
|
||||||
|
|
||||||
: languages_provided
|
=== languages_provided
|
||||||
|
|
||||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||||
* Value type: [binary()]
|
Value type:: [binary()]
|
||||||
* Skip to the next step if undefined
|
Default behavior:: Skip to the next step if undefined.
|
||||||
|
|
||||||
Return the list of languages the resource provides.
|
Return the list of languages the resource provides.
|
||||||
|
|
||||||
|
@ -351,11 +344,11 @@ value `language`.
|
||||||
While languages are case insensitive, this callback is expected
|
While languages are case insensitive, this callback is expected
|
||||||
to return them as lowercase binary.
|
to return them as lowercase binary.
|
||||||
|
|
||||||
: last_modified
|
=== last_modified
|
||||||
|
|
||||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||||
* Value type: calendar:datetime()
|
Value type:: calendar:datetime()
|
||||||
* Default value: undefined
|
Default value:: undefined
|
||||||
|
|
||||||
Return the date of last modification of the resource.
|
Return the date of last modification of the resource.
|
||||||
|
|
||||||
|
@ -363,11 +356,11 @@ This date will be used to test against the if-modified-since
|
||||||
and if-unmodified-since headers, and sent as the last-modified
|
and if-unmodified-since headers, and sent as the last-modified
|
||||||
header in the response of GET and HEAD requests.
|
header in the response of GET and HEAD requests.
|
||||||
|
|
||||||
: malformed_request
|
=== malformed_request
|
||||||
|
|
||||||
* Methods: all
|
Methods:: all
|
||||||
* Value type: boolean()
|
Value type:: boolean()
|
||||||
* Default value: false
|
Default value:: false
|
||||||
|
|
||||||
Return whether the request is malformed.
|
Return whether the request is malformed.
|
||||||
|
|
||||||
|
@ -378,13 +371,13 @@ are expected to implement it.
|
||||||
The check is to be done on the request itself, not on
|
The check is to be done on the request itself, not on
|
||||||
the request body, which is processed later.
|
the request body, which is processed later.
|
||||||
|
|
||||||
: moved_permanently
|
=== moved_permanently
|
||||||
|
|
||||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||||
* Value type: {true, URL} | false
|
Value type:: {true, URL} | false
|
||||||
* Default value: false
|
Default value:: false
|
||||||
|
|
||||||
Types:
|
With types:
|
||||||
|
|
||||||
* URL = iodata()
|
* URL = iodata()
|
||||||
|
|
||||||
|
@ -393,13 +386,13 @@ Return whether the resource was permanently moved.
|
||||||
If it was, its new URL is also returned and sent in the
|
If it was, its new URL is also returned and sent in the
|
||||||
location header in the response.
|
location header in the response.
|
||||||
|
|
||||||
: moved_temporarily
|
=== moved_temporarily
|
||||||
|
|
||||||
* Methods: GET, HEAD, POST, PATCH, DELETE
|
Methods:: GET, HEAD, POST, PATCH, DELETE
|
||||||
* Value type: {true, URL} | false
|
Value type:: {true, URL} | false
|
||||||
* Default value: false
|
Default value:: false
|
||||||
|
|
||||||
Types:
|
With types:
|
||||||
|
|
||||||
* URL = iodata()
|
* URL = iodata()
|
||||||
|
|
||||||
|
@ -408,11 +401,11 @@ Return whether the resource was temporarily moved.
|
||||||
If it was, its new URL is also returned and sent in the
|
If it was, its new URL is also returned and sent in the
|
||||||
location header in the response.
|
location header in the response.
|
||||||
|
|
||||||
: multiple_choices
|
=== multiple_choices
|
||||||
|
|
||||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||||
* Value type: boolean()
|
Value type:: boolean()
|
||||||
* Default value: false
|
Default value:: false
|
||||||
|
|
||||||
Return whether there are multiple representations of the resource.
|
Return whether there are multiple representations of the resource.
|
||||||
|
|
||||||
|
@ -425,11 +418,11 @@ The content-type of the response should be the one previously
|
||||||
negociated and that can be obtained by calling
|
negociated and that can be obtained by calling
|
||||||
`cowboy_req:meta(media_type, Req)`.
|
`cowboy_req:meta(media_type, Req)`.
|
||||||
|
|
||||||
: options
|
=== options
|
||||||
|
|
||||||
* Methods: OPTIONS
|
Methods:: OPTIONS
|
||||||
* Value type: ok
|
Value type:: ok
|
||||||
* Default value: ok
|
Default value:: ok
|
||||||
|
|
||||||
Handle a request for information.
|
Handle a request for information.
|
||||||
|
|
||||||
|
@ -439,19 +432,19 @@ options available for this resource.
|
||||||
By default, Cowboy will send a `200 OK` response with the
|
By default, Cowboy will send a `200 OK` response with the
|
||||||
allow header set.
|
allow header set.
|
||||||
|
|
||||||
: previously_existed
|
=== previously_existed
|
||||||
|
|
||||||
* Methods: GET, HEAD, POST, PATCH, DELETE
|
Methods:: GET, HEAD, POST, PATCH, DELETE
|
||||||
* Value type: boolean()
|
Value type:: boolean()
|
||||||
* Default value: false
|
Default value:: false
|
||||||
|
|
||||||
Return whether the resource existed previously.
|
Return whether the resource existed previously.
|
||||||
|
|
||||||
: resource_exists
|
=== resource_exists
|
||||||
|
|
||||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||||
* Value type: boolean()
|
Value type:: boolean()
|
||||||
* Default value: true
|
Default value:: true
|
||||||
|
|
||||||
Return whether the resource exists.
|
Return whether the resource exists.
|
||||||
|
|
||||||
|
@ -459,11 +452,11 @@ If it exists, conditional headers will be tested before
|
||||||
attempting to perform the action. Otherwise, Cowboy will
|
attempting to perform the action. Otherwise, Cowboy will
|
||||||
check if the resource previously existed first.
|
check if the resource previously existed first.
|
||||||
|
|
||||||
: service_available
|
=== service_available
|
||||||
|
|
||||||
* Methods: all
|
Methods:: all
|
||||||
* Value type: boolean()
|
Value type:: boolean()
|
||||||
* Default value: true
|
Default value:: true
|
||||||
|
|
||||||
Return whether the service is available.
|
Return whether the service is available.
|
||||||
|
|
||||||
|
@ -473,11 +466,11 @@ systems are up and able to handle requests.
|
||||||
A `503 Service Unavailable` response will be sent if this
|
A `503 Service Unavailable` response will be sent if this
|
||||||
function returns `false`.
|
function returns `false`.
|
||||||
|
|
||||||
: uri_too_long
|
=== uri_too_long
|
||||||
|
|
||||||
* Methods: all
|
Methods:: all
|
||||||
* Value type: boolean()
|
Value type:: boolean()
|
||||||
* Default value: false
|
Default value:: false
|
||||||
|
|
||||||
Return whether the requested URI is too long.
|
Return whether the requested URI is too long.
|
||||||
|
|
||||||
|
@ -488,11 +481,11 @@ are expected to implement it.
|
||||||
A `414 Request-URI Too Long` response will be sent if this
|
A `414 Request-URI Too Long` response will be sent if this
|
||||||
function returns `true`.
|
function returns `true`.
|
||||||
|
|
||||||
: valid_content_headers
|
=== valid_content_headers
|
||||||
|
|
||||||
* Methods: all
|
Methods:: all
|
||||||
* Value type: boolean()
|
Value type:: boolean()
|
||||||
* Default value: true
|
Default value:: true
|
||||||
|
|
||||||
Return whether the content-* headers are valid.
|
Return whether the content-* headers are valid.
|
||||||
|
|
||||||
|
@ -505,22 +498,22 @@ quickly check the headers can be parsed.
|
||||||
A `501 Not Implemented` response will be sent if this
|
A `501 Not Implemented` response will be sent if this
|
||||||
function returns `false`.
|
function returns `false`.
|
||||||
|
|
||||||
: valid_entity_length
|
=== valid_entity_length
|
||||||
|
|
||||||
* Methods: all
|
Methods:: all
|
||||||
* Value type: boolean()
|
Value type:: boolean()
|
||||||
* Default value: true
|
Default value:: true
|
||||||
|
|
||||||
Return whether the request body length is within acceptable boundaries.
|
Return whether the request body length is within acceptable boundaries.
|
||||||
|
|
||||||
A `413 Request Entity Too Large` response will be sent if this
|
A `413 Request Entity Too Large` response will be sent if this
|
||||||
function returns `false`.
|
function returns `false`.
|
||||||
|
|
||||||
: variances
|
=== variances
|
||||||
|
|
||||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||||
* Value type: [binary()]
|
Value type:: [binary()]
|
||||||
* Default value: []
|
Default value:: []
|
||||||
|
|
||||||
Return the list of headers that affect the representation of the resource.
|
Return the list of headers that affect the representation of the resource.
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
::: cowboy_router
|
= cowboy_router(3)
|
||||||
|
|
||||||
|
== Name
|
||||||
|
|
||||||
|
cowboy_router - router middleware
|
||||||
|
|
||||||
|
== Description
|
||||||
|
|
||||||
The `cowboy_router` middleware maps the requested host and
|
The `cowboy_router` middleware maps the requested host and
|
||||||
path to the handler to be used for processing the request.
|
path to the handler to be used for processing the request.
|
||||||
|
@ -7,49 +13,44 @@ to the `compile/1` function for this purpose. It adds the
|
||||||
handler name and options to the environment as the values
|
handler name and options to the environment as the values
|
||||||
`handler` and `handler_opts` respectively.
|
`handler` and `handler_opts` respectively.
|
||||||
|
|
||||||
Environment input:
|
=== Environment input
|
||||||
|
|
||||||
* dispatch = dispatch_rules()
|
dispatch = dispatch_rules():: Dispatch table.
|
||||||
|
|
||||||
Environment output:
|
=== Environment output
|
||||||
|
|
||||||
* handler = module()
|
handler = module():: Handler module.
|
||||||
* handler_opts = any()
|
handler_opts = any():: Handler options.
|
||||||
|
|
||||||
:: Types
|
== Types
|
||||||
|
|
||||||
: bindings() = [{atom(), binary()}]
|
=== bindings() = [{atom(), binary()}]
|
||||||
|
|
||||||
List of bindings found during routing.
|
List of bindings found during routing.
|
||||||
|
|
||||||
: dispatch_rules() - opaque to the user
|
=== dispatch_rules() - opaque to the user
|
||||||
|
|
||||||
Rules for dispatching request used by Cowboy.
|
Rules for dispatching request used by Cowboy.
|
||||||
|
|
||||||
: routes() = [{Host, Paths} | {Host, cowboy:fields(), Paths}]
|
=== routes() = [{Host, Paths} | {Host, cowboy:fields(), Paths}]
|
||||||
|
|
||||||
Types:
|
With types:
|
||||||
|
|
||||||
* Host = Path = '_' | iodata()
|
* Host = Path = '_' | iodata()
|
||||||
* Paths = [{Path, Handler, Opts} | {Path, cowboy:fields(), Handler, Opts}]
|
* Paths = [{Path, Handler, Opts} | {Path, cowboy:fields(), Handler, HandlerOpts}]
|
||||||
* Handler = module()
|
* Handler = module()
|
||||||
* Opts = any()
|
* HandlerOpts = any()
|
||||||
|
|
||||||
Human readable list of routes mapping hosts and paths to handlers.
|
Human readable list of routes mapping hosts and paths to handlers.
|
||||||
|
|
||||||
The syntax for routes is defined in the user guide.
|
The syntax for routes is defined in the user guide.
|
||||||
|
|
||||||
: tokens() = [binary()]
|
=== tokens() = [binary()]
|
||||||
|
|
||||||
List of host_info and path_info tokens found during routing.
|
List of host_info and path_info tokens found during routing.
|
||||||
|
|
||||||
:: Exports
|
== Exports
|
||||||
|
|
||||||
: compile(Routes) -> Dispatch
|
=== compile(routes()) -> dispatch_rules()
|
||||||
|
|
||||||
Types:
|
|
||||||
|
|
||||||
* Routes = routes()
|
|
||||||
* Dispatch = dispatch_rules()
|
|
||||||
|
|
||||||
Compile the routes for use by Cowboy.
|
Compile the routes for use by Cowboy.
|
42
doc/src/manual/cowboy_spdy.asciidoc
Normal file
42
doc/src/manual/cowboy_spdy.asciidoc
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
= cowboy_spdy(3)
|
||||||
|
|
||||||
|
== Name
|
||||||
|
|
||||||
|
cowboy_spdy - SPDY protocol
|
||||||
|
|
||||||
|
== Description
|
||||||
|
|
||||||
|
The `cowboy_spdy` module implements SPDY/3 as a Ranch protocol.
|
||||||
|
|
||||||
|
== Types
|
||||||
|
|
||||||
|
=== opts() = [Option]
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
----
|
||||||
|
Option = {env, cowboy_middleware:env()}
|
||||||
|
| {middlewares, [module()]}
|
||||||
|
| {onresponse, cowboy:onresponse_fun()}
|
||||||
|
----
|
||||||
|
|
||||||
|
Configuration for the SPDY protocol handler.
|
||||||
|
|
||||||
|
This configuration is passed to Cowboy when starting listeners
|
||||||
|
using the `cowboy:start_spdy/4` function.
|
||||||
|
|
||||||
|
It can be updated without restarting listeners using the
|
||||||
|
Ranch functions `ranch:get_protocol_options/1` and
|
||||||
|
`ranch:set_protocol_options/2`.
|
||||||
|
|
||||||
|
== Option descriptions
|
||||||
|
|
||||||
|
The default value is given next to the option name.
|
||||||
|
|
||||||
|
env ([{listener, Ref}])::
|
||||||
|
Initial middleware environment.
|
||||||
|
|
||||||
|
middlewares ([cowboy_router, cowboy_handler])::
|
||||||
|
List of middlewares to execute for every requests.
|
||||||
|
|
||||||
|
onresponse (undefined)::
|
||||||
|
Fun called every time a response is sent.
|
|
@ -1,34 +0,0 @@
|
||||||
::: cowboy_spdy
|
|
||||||
|
|
||||||
The `cowboy_spdy` module implements SPDY/3 as a Ranch protocol.
|
|
||||||
|
|
||||||
:: Types
|
|
||||||
|
|
||||||
: opts() = [{env, cowboy_middleware:env()}
|
|
||||||
| {middlewares, [module()]}
|
|
||||||
| {onresponse, cowboy:onresponse_fun()}]
|
|
||||||
|
|
||||||
Configuration for the SPDY protocol handler.
|
|
||||||
|
|
||||||
This configuration is passed to Cowboy when starting listeners
|
|
||||||
using the `cowboy:start_spdy/4` function.
|
|
||||||
|
|
||||||
It can be updated without restarting listeners using the
|
|
||||||
Ranch functions `ranch:get_protocol_options/1` and
|
|
||||||
`ranch:set_protocol_options/2`.
|
|
||||||
|
|
||||||
:: Option descriptions
|
|
||||||
|
|
||||||
The default value is given next to the option name.
|
|
||||||
|
|
||||||
: env ([{listener, Ref}])
|
|
||||||
|
|
||||||
Initial middleware environment.
|
|
||||||
|
|
||||||
: middlewares ([cowboy_router, cowboy_handler])
|
|
||||||
|
|
||||||
List of middlewares to execute for every requests.
|
|
||||||
|
|
||||||
: onresponse (undefined)
|
|
||||||
|
|
||||||
Fun called every time a response is sent.
|
|
41
doc/src/manual/cowboy_static.asciidoc
Normal file
41
doc/src/manual/cowboy_static.asciidoc
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
= cowboy_static(3)
|
||||||
|
|
||||||
|
== Name
|
||||||
|
|
||||||
|
cowboy_static - static file handler
|
||||||
|
|
||||||
|
== Description
|
||||||
|
|
||||||
|
The `cowboy_static` module implements file serving capabilities
|
||||||
|
by using the REST semantics provided by `cowboy_rest`.
|
||||||
|
|
||||||
|
== Types
|
||||||
|
|
||||||
|
=== opts() = [Option]
|
||||||
|
|
||||||
|
[source,erlang]
|
||||||
|
----
|
||||||
|
Option = {priv_file, atom(), string() | binary()}
|
||||||
|
| {priv_file, atom(), string() | binary(), Extra}
|
||||||
|
| {file, string() | binary()}
|
||||||
|
| {file, string() | binary(), Extra}
|
||||||
|
| {priv_dir, atom(), string() | binary()}
|
||||||
|
| {priv_dir, atom(), string() | binary(), Extra}
|
||||||
|
| {dir, string() | binary()}
|
||||||
|
| {dir, string() | binary(), Extra}
|
||||||
|
|
||||||
|
Extra = [ETag | Mimetypes]
|
||||||
|
|
||||||
|
ETag = {etag, module(), function()} | {etag, false}
|
||||||
|
|
||||||
|
Mimetypes = {mimetypes, module(), function()}
|
||||||
|
| {mimetypes, binary() | {binary(), binary(), [{binary(), binary()}]}}
|
||||||
|
----
|
||||||
|
|
||||||
|
Configuration for the static handler.
|
||||||
|
|
||||||
|
The handler can be configured for sending either one file or
|
||||||
|
a directory (including its subdirectories).
|
||||||
|
|
||||||
|
Extra options allow you to define how the etag should be calculated
|
||||||
|
and how the mimetype of files should be detected.
|
|
@ -1,32 +0,0 @@
|
||||||
::: cowboy_static
|
|
||||||
|
|
||||||
The `cowboy_static` module implements file serving capabilities
|
|
||||||
by using the REST semantics provided by `cowboy_rest`.
|
|
||||||
|
|
||||||
:: Types
|
|
||||||
|
|
||||||
: opts() = {priv_file, atom(), string() | binary()}
|
|
||||||
| {priv_file, atom(), string() | binary(), extra()}
|
|
||||||
| {file, string() | binary()}
|
|
||||||
| {file, string() | binary(), extra()}
|
|
||||||
| {priv_dir, atom(), string() | binary()}
|
|
||||||
| {priv_dir, atom(), string() | binary(), extra()}
|
|
||||||
| {dir, string() | binary()}
|
|
||||||
| {dir, string() | binary(), extra()}
|
|
||||||
|
|
||||||
Configuration for the static handler.
|
|
||||||
|
|
||||||
The handler can be configured for sending either one file or
|
|
||||||
a directory (including its subdirectories).
|
|
||||||
|
|
||||||
Extra options allow you to define how the etag should be calculated
|
|
||||||
and how the mimetype of files should be detected. They are defined
|
|
||||||
as follow, but do note that these types are not exported, only the
|
|
||||||
`opts/0` type is public.
|
|
||||||
|
|
||||||
: extra() = [extra_etag() | extra_mimetypes()]
|
|
||||||
|
|
||||||
: extra_etag() = {etag, module(), function()} | {etag, false}
|
|
||||||
|
|
||||||
: extra_mimetypes() = {mimetypes, module(), function()}
|
|
||||||
| {mimetypes, binary() | {binary(), binary(), [{binary(), binary()}]}}
|
|
27
doc/src/manual/cowboy_sub_protocol.asciidoc
Normal file
27
doc/src/manual/cowboy_sub_protocol.asciidoc
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
= cowboy_sub_protocol(3)
|
||||||
|
|
||||||
|
== Name
|
||||||
|
|
||||||
|
cowboy_sub_protocol - sub protocol
|
||||||
|
|
||||||
|
== Description
|
||||||
|
|
||||||
|
The `cowboy_sub_protocol` behaviour defines the interface used
|
||||||
|
by modules that implement a protocol on top of HTTP.
|
||||||
|
|
||||||
|
== Callbacks
|
||||||
|
|
||||||
|
=== upgrade(Req, Env, Handler, HandlerOpts) -> {ok, Req, Env} | {suspend, Module, Function, Args} | {stop, Req}
|
||||||
|
|
||||||
|
Req = cowboy_req:req():: The Req object.
|
||||||
|
Env = env():: The request environment.
|
||||||
|
Handler = module():: Handler module.
|
||||||
|
Opts = any():: Handler options.
|
||||||
|
Module = module():: MFA to call when resuming the process.
|
||||||
|
Function = atom():: MFA to call when resuming the process.
|
||||||
|
Args = [any()]:: MFA to call when resuming the process.
|
||||||
|
|
||||||
|
Upgrade the protocol.
|
||||||
|
|
||||||
|
Please refer to the `cowboy_middleware` manual for a
|
||||||
|
description of the return values.
|
|
@ -1,27 +0,0 @@
|
||||||
::: cowboy_sub_protocol
|
|
||||||
|
|
||||||
The `cowboy_sub_protocol` behaviour defines the interface used
|
|
||||||
by modules that implement a protocol on top of HTTP.
|
|
||||||
|
|
||||||
:: Callbacks
|
|
||||||
|
|
||||||
: upgrade(Req, Env, Handler, Opts)
|
|
||||||
-> {ok, Req, Env}
|
|
||||||
| {suspend, Module, Function, Args}
|
|
||||||
| {stop, Req}
|
|
||||||
|
|
||||||
Types:
|
|
||||||
|
|
||||||
* Req = cowboy_req:req()
|
|
||||||
* Env = env()
|
|
||||||
* Handler = module()
|
|
||||||
* Opts = any()
|
|
||||||
* Module = module()
|
|
||||||
* Function = atom()
|
|
||||||
* Args = [any()]
|
|
||||||
* StatusCode = cowboy:http_status()
|
|
||||||
|
|
||||||
Upgrade the protocol.
|
|
||||||
|
|
||||||
Please refer to the `cowboy_middleware` manual for a
|
|
||||||
description of the return values.
|
|
|
@ -1,11 +1,17 @@
|
||||||
::: cowboy_websocket
|
= cowboy_websocket(3)
|
||||||
|
|
||||||
|
== Name
|
||||||
|
|
||||||
|
cowboy_websocket - Websocket protocol
|
||||||
|
|
||||||
|
== Description
|
||||||
|
|
||||||
The `cowboy_websocket` module implements the Websocket protocol.
|
The `cowboy_websocket` module implements the Websocket protocol.
|
||||||
|
|
||||||
This module is a sub protocol that defines four callbacks to
|
This module is a sub protocol that defines four callbacks to
|
||||||
be implemented by handlers. The `init/2` and `terminate/3`
|
be implemented by handlers. The `init/2` and `terminate/3`
|
||||||
callbacks are common to all handler types and are documented
|
callbacks are common to all handler types and are documented
|
||||||
in the manual for the ^cowboy_handler module.
|
in the manual for the link:cowboy_handler.asciidoc[cowboy_handler] module.
|
||||||
|
|
||||||
The `websocket_handle/3` and `websocket_info/3` callbacks are
|
The `websocket_handle/3` and `websocket_info/3` callbacks are
|
||||||
specific to Websocket handlers and will be called as many times
|
specific to Websocket handlers and will be called as many times
|
||||||
|
@ -22,91 +28,77 @@ Cowboy will terminate the process right after closing the
|
||||||
Websocket connection. This means that there is no real need to
|
Websocket connection. This means that there is no real need to
|
||||||
perform any cleanup in the optional `terminate/3` callback.
|
perform any cleanup in the optional `terminate/3` callback.
|
||||||
|
|
||||||
:: Meta values
|
== Meta values
|
||||||
|
|
||||||
: websocket_compress
|
websocket_compress = boolean()::
|
||||||
|
Whether a websocket compression extension in in use.
|
||||||
|
|
||||||
Type: true | false
|
websocket_version = 7 | 8 | 13::
|
||||||
|
The version of the Websocket protocol being used.
|
||||||
|
|
||||||
Whether a websocket compression extension in in use.
|
== Terminate reasons
|
||||||
|
|
||||||
: websocket_version
|
|
||||||
|
|
||||||
Type: 7 | 8 | 13
|
|
||||||
|
|
||||||
The version of the Websocket protocol being used.
|
|
||||||
|
|
||||||
:: Terminate reasons
|
|
||||||
|
|
||||||
The following values may be received as the terminate reason
|
The following values may be received as the terminate reason
|
||||||
in the optional `terminate/3` callback.
|
in the optional `terminate/3` callback.
|
||||||
|
|
||||||
: normal
|
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.
|
||||||
|
|
||||||
The connection was closed normally before establishing a Websocket
|
remote::
|
||||||
connection. This typically happens if an `ok` tuple is returned
|
The remote endpoint closed the connection without giving any
|
||||||
from the `init/2` callback.
|
further details.
|
||||||
|
|
||||||
: remote
|
{remote, Code, Payload}::
|
||||||
|
The remote endpoint closed the connection with the given
|
||||||
|
`Code` and `Payload` as the reason.
|
||||||
|
|
||||||
The remote endpoint closed the connection without giving any
|
stop::
|
||||||
further details.
|
The handler requested to close the connection, either by returning
|
||||||
|
a `stop` tuple or by sending a `close` frame.
|
||||||
|
|
||||||
: {remote, Code, Payload}
|
timeout::
|
||||||
|
The connection has been closed due to inactivity. The timeout
|
||||||
|
value can be configured from `init/2`.
|
||||||
|
|
||||||
The remote endpoint closed the connection with the given
|
{crash, Class, Reason}::
|
||||||
`Code` and `Payload` as the 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.
|
||||||
|
|
||||||
: stop
|
{error, badencoding}::
|
||||||
|
A text frame was sent by the client with invalid encoding. All
|
||||||
|
text frames must be valid UTF-8.
|
||||||
|
|
||||||
The handler requested to close the connection, either by returning
|
{error, badframe}::
|
||||||
a `stop` tuple or by sending a `close` frame.
|
A protocol error has been detected.
|
||||||
|
|
||||||
: timeout
|
{error, closed}::
|
||||||
|
The socket has been closed brutally without a close frame being
|
||||||
|
received first.
|
||||||
|
|
||||||
The connection has been closed due to inactivity. The timeout
|
{error, Reason}::
|
||||||
value can be configured from `init/2`.
|
A socket error ocurred.
|
||||||
|
|
||||||
: {crash, Class, Reason}
|
== Callbacks
|
||||||
|
|
||||||
A crash occurred in the handler. `Class` and `Reason` can be
|
=== websocket_handle(InFrame, Req, State) -> Ret
|
||||||
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}
|
[source,erlang]
|
||||||
|
----
|
||||||
A text frame was sent by the client with invalid encoding. All
|
Ret = {ok, Req, State}
|
||||||
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}
|
| {ok, Req, State, hibernate}
|
||||||
| {reply, OutFrame | [OutFrame], Req, State}
|
| {reply, OutFrame | [OutFrame], Req, State}
|
||||||
| {reply, OutFrame | [OutFrame], Req, State, hibernate}
|
| {reply, OutFrame | [OutFrame], Req, State, hibernate}
|
||||||
| {stop, Req, State}
|
| {stop, Req, State}
|
||||||
|
|
||||||
Types:
|
InFrame = {text | binary | ping | pong, binary()}
|
||||||
|
Req = cowboy_req:req()
|
||||||
* InFrame = {text | binary | ping | pong, binary()}
|
State = any()
|
||||||
* Req = cowboy_req:req()
|
OutFrame = cow_ws:frame()
|
||||||
* State = any()
|
----
|
||||||
* OutFrame = cow_ws:frame()
|
|
||||||
|
|
||||||
Handle the data received from the Websocket connection.
|
Handle the data received from the Websocket connection.
|
||||||
|
|
||||||
|
@ -121,19 +113,21 @@ The `hibernate` option will hibernate the process until
|
||||||
it receives new data from the Websocket connection or an
|
it receives new data from the Websocket connection or an
|
||||||
Erlang message.
|
Erlang message.
|
||||||
|
|
||||||
: websocket_info(Info, Req, State)
|
=== websocket_info(Info, Req, State) -> Ret
|
||||||
-> {ok, Req, State}
|
|
||||||
|
[source,erlang]
|
||||||
|
----
|
||||||
|
Ret = {ok, Req, State}
|
||||||
| {ok, Req, State, hibernate}
|
| {ok, Req, State, hibernate}
|
||||||
| {reply, OutFrame | [OutFrame], Req, State}
|
| {reply, OutFrame | [OutFrame], Req, State}
|
||||||
| {reply, OutFrame | [OutFrame], Req, State, hibernate}
|
| {reply, OutFrame | [OutFrame], Req, State, hibernate}
|
||||||
| {stop, Req, State}
|
| {stop, Req, State}
|
||||||
|
|
||||||
Types:
|
Info = any()
|
||||||
|
Req = cowboy_req:req()
|
||||||
* Info = any()
|
State = any()
|
||||||
* Req = cowboy_req:req()
|
OutFrame = cow_ws:frame()
|
||||||
* State = any()
|
----
|
||||||
* OutFrame = cow_ws:frame()
|
|
||||||
|
|
||||||
Handle the Erlang message received.
|
Handle the Erlang message received.
|
||||||
|
|
|
@ -1,61 +1,67 @@
|
||||||
::: HTTP status codes
|
= HTTP status codes(7)
|
||||||
|
|
||||||
|
== Name
|
||||||
|
|
||||||
|
HTTP status codes - status codes used by Cowboy
|
||||||
|
|
||||||
|
== Description
|
||||||
|
|
||||||
This chapter aims to list all HTTP status codes that Cowboy
|
This chapter aims to list all HTTP status codes that Cowboy
|
||||||
may return, with details on the reasons why. The list given
|
may return, with details on the reasons why. The list given
|
||||||
here only includes the replies that Cowboy sends, not user
|
here only includes the replies that Cowboy sends, not user
|
||||||
replies.
|
replies.
|
||||||
|
|
||||||
: 100 Continue
|
== 100 Continue
|
||||||
|
|
||||||
When the client sends an `expect: 100-continue` header,
|
When the client sends an `expect: 100-continue` header,
|
||||||
Cowboy automatically sends a this status code before
|
Cowboy automatically sends a this status code before
|
||||||
trying to read the request body. This behavior can be
|
trying to read the request body. This behavior can be
|
||||||
disabled using the appropriate body option.
|
disabled using the appropriate body option.
|
||||||
|
|
||||||
: 101 Switching Protocols
|
== 101 Switching Protocols
|
||||||
|
|
||||||
This is the status code sent when switching to the
|
This is the status code sent when switching to the
|
||||||
Websocket protocol.
|
Websocket protocol.
|
||||||
|
|
||||||
: 200 OK
|
== 200 OK
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 201 Created
|
== 201 Created
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 202 Accepted
|
== 202 Accepted
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 204 No Content
|
== 204 No Content
|
||||||
|
|
||||||
This status code is sent when the processing of a request
|
This status code is sent when the processing of a request
|
||||||
ends without any reply having been sent. It may also be
|
ends without any reply having been sent. It may also be
|
||||||
sent by `cowboy_rest` under normal conditions.
|
sent by `cowboy_rest` under normal conditions.
|
||||||
|
|
||||||
: 300 Multiple Choices
|
== 300 Multiple Choices
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 301 Moved Permanently
|
== 301 Moved Permanently
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 303 See Other
|
== 303 See Other
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 304 Not Modified
|
== 304 Not Modified
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 307 Temporary Redirect
|
== 307 Temporary Redirect
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 400 Bad Request
|
== 400 Bad Request
|
||||||
|
|
||||||
Cowboy will send this status code for any of the
|
Cowboy will send this status code for any of the
|
||||||
following reasons:
|
following reasons:
|
||||||
|
@ -73,78 +79,78 @@ following reasons:
|
||||||
* REST under normal conditions.
|
* REST under normal conditions.
|
||||||
* A Websocket upgrade failed.
|
* A Websocket upgrade failed.
|
||||||
|
|
||||||
: 401 Unauthorized
|
== 401 Unauthorized
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 403 Forbidden
|
== 403 Forbidden
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 404 Not Found
|
== 404 Not Found
|
||||||
|
|
||||||
This status code is sent when the router successfully
|
This status code is sent when the router successfully
|
||||||
resolved the host but didn't find a matching path for
|
resolved the host but didn't find a matching path for
|
||||||
the request. It may also be sent by `cowboy_rest` under
|
the request. It may also be sent by `cowboy_rest` under
|
||||||
normal conditions.
|
normal conditions.
|
||||||
|
|
||||||
: 405 Method Not Allowed
|
== 405 Method Not Allowed
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 406 Not Acceptable
|
== 406 Not Acceptable
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 408 Request Timeout
|
== 408 Request Timeout
|
||||||
|
|
||||||
Cowboy will send this status code to the client if the
|
Cowboy will send this status code to the client if the
|
||||||
client started to send a request, indicated by the
|
client started to send a request, indicated by the
|
||||||
request-line being received fully, but failed to send
|
request-line being received fully, but failed to send
|
||||||
all headers in a reasonable time.
|
all headers in a reasonable time.
|
||||||
|
|
||||||
: 409 Conflict
|
== 409 Conflict
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 410 Gone
|
== 410 Gone
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 412 Precondition Failed
|
== 412 Precondition Failed
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 413 Request Entity Too Large
|
== 413 Request Entity Too Large
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 414 Request-URI Too Long
|
== 414 Request-URI Too Long
|
||||||
|
|
||||||
Cowboy will send this status code to the client if the
|
Cowboy will send this status code to the client if the
|
||||||
request-line is too long. It may also be sent by
|
request-line is too long. It may also be sent by
|
||||||
`cowboy_rest` under normal conditions.
|
`cowboy_rest` under normal conditions.
|
||||||
|
|
||||||
: 415 Unsupported Media Type
|
== 415 Unsupported Media Type
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 500 Internal Server Error
|
== 500 Internal Server Error
|
||||||
|
|
||||||
This status code is sent when a crash occurs in HTTP, loop
|
This status code is sent when a crash occurs in HTTP, loop
|
||||||
or REST handlers, or when an invalid return value is
|
or REST handlers, or when an invalid return value is
|
||||||
returned. It may also be sent by `cowboy_rest` under
|
returned. It may also be sent by `cowboy_rest` under
|
||||||
normal conditions.
|
normal conditions.
|
||||||
|
|
||||||
: 501 Not Implemented
|
== 501 Not Implemented
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 503 Service Unavailable
|
== 503 Service Unavailable
|
||||||
|
|
||||||
This status code is sent by `cowboy_rest`.
|
This status code is sent by `cowboy_rest`.
|
||||||
|
|
||||||
: 505 HTTP Version Not Supported
|
== 505 HTTP Version Not Supported
|
||||||
|
|
||||||
Cowboy only supports the versions 1.0 and 1.1 of HTTP.
|
Cowboy only supports the versions 1.0 and 1.1 of HTTP.
|
||||||
In all other cases this status code is sent back to the
|
In all other cases this status code is sent back to the
|
|
@ -1,18 +0,0 @@
|
||||||
::: Cowboy Function Reference
|
|
||||||
|
|
||||||
The function reference documents the public interface of Cowboy.
|
|
||||||
|
|
||||||
* ^"The Cowboy Application^cowboy_app
|
|
||||||
* ^cowboy
|
|
||||||
* ^cowboy_handler
|
|
||||||
* ^cowboy_loop
|
|
||||||
* ^cowboy_middleware
|
|
||||||
* ^cowboy_protocol
|
|
||||||
* ^cowboy_req
|
|
||||||
* ^cowboy_rest
|
|
||||||
* ^cowboy_router
|
|
||||||
* ^cowboy_spdy
|
|
||||||
* ^cowboy_static
|
|
||||||
* ^cowboy_sub_protocol
|
|
||||||
* ^cowboy_websocket
|
|
||||||
* ^"HTTP status codes^http_status_codes
|
|
Loading…
Add table
Add a link
Reference in a new issue