mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 04:10: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
|
||||
cowboy.d
|
||||
deps
|
||||
doc/guide.pdf
|
||||
doc/html
|
||||
doc/man3
|
||||
doc/man7
|
||||
doc/markdown
|
||||
ebin/*.beam
|
||||
ebin/test
|
||||
examples/*/ebin
|
||||
|
|
52
Makefile
52
Makefile
|
@ -45,55 +45,3 @@ app:: rebar.config
|
|||
|
||||
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/
|
||||
|
||||
# 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.
|
||||
|
||||
It is built on top of Ranch. Please see the Ranch guide for more
|
||||
information.
|
||||
|
||||
:: One process per connection
|
||||
=== One process per connection
|
||||
|
||||
It uses only one process per connection. The process where your
|
||||
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
|
||||
more.
|
||||
|
||||
:: Binaries
|
||||
=== Binaries
|
||||
|
||||
It uses binaries. Binaries are more efficient than lists for
|
||||
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.
|
||||
Please see the HiPE documentation for more details.
|
||||
|
||||
:: Date header
|
||||
=== Date header
|
||||
|
||||
Because querying for the current date and time can be expensive,
|
||||
Cowboy generates one `Date` header value every second, shares it
|
||||
to all other processes, which then simply copy it in the response.
|
||||
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
|
||||
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
|
||||
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
|
||||
course workarounds. This chapter aims to cover them.
|
||||
|
||||
:: Lowercase headers
|
||||
=== Lowercase headers
|
||||
|
||||
Cowboy converts all headers it receives to lowercase, and
|
||||
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
|
||||
that will format the header names with the expected case.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
capitalize_hook(Status, Headers, Body, Req) ->
|
||||
Headers2 = [{cowboy_bstr:capitalize_token(N), V}
|
||||
|| {N, V} <- Headers],
|
||||
cowboy_req:reply(Status, Headers2, Body, Req).
|
||||
```
|
||||
----
|
||||
|
||||
Note that SPDY clients do not have that particular issue
|
||||
because the specification explicitly says all headers are
|
||||
lowercase, unlike HTTP which allows any case but treats
|
||||
them as case insensitive.
|
||||
|
||||
:: Camel-case headers
|
||||
=== Camel-case headers
|
||||
|
||||
Sometimes it is desirable to keep the actual case used by
|
||||
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
|
||||
directly.
|
||||
|
||||
:: Chunked transfer-encoding
|
||||
=== Chunked transfer-encoding
|
||||
|
||||
Sometimes an HTTP client advertises itself as HTTP/1.1 but
|
||||
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
|
||||
when replying, just like if it was an HTTP/1.0 client.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Req2 = cowboy_req:set(resp_state, waiting_stream).
|
||||
```
|
|
@ -1,4 +1,5 @@
|
|||
::: Constraints
|
||||
[[constraints]]
|
||||
== Constraints
|
||||
|
||||
Cowboy provides an optional constraints based validation feature
|
||||
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
|
||||
one step.
|
||||
|
||||
:: Structure
|
||||
=== Structure
|
||||
|
||||
Constraints are provided as a list of fields and for each
|
||||
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
|
||||
constraint, the next constraint receives the updated value.
|
||||
|
||||
:: Built-in constraints
|
||||
=== Built-in constraints
|
||||
|
||||
|| Constraint Description
|
||||
|
|
||||
| int Convert binary value to integer
|
||||
| nonempty Ensures the binary value is non-empty
|
||||
[cols="<,<",options="header"]
|
||||
|===
|
||||
| Constraint | Description
|
||||
| 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
|
||||
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
|
||||
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,
|
||||
essentially disabling their access from client-side scripts.
|
||||
|
||||
:: Setting cookies
|
||||
=== Setting cookies
|
||||
|
||||
By default, cookies you set are defined for the session.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
SessionID = generate_session_id(),
|
||||
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [], Req).
|
||||
```
|
||||
|
||||
You can also make them expire at a specific point in the
|
||||
future.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
SessionID = generate_session_id(),
|
||||
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [
|
||||
{max_age, 3600}
|
||||
], Req).
|
||||
```
|
||||
----
|
||||
|
||||
You can delete cookies that have already been set. The value
|
||||
is ignored.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, <<>>, [
|
||||
{max_age, 0}
|
||||
], Req).
|
||||
```
|
||||
----
|
||||
|
||||
You can restrict them to a specific domain and path.
|
||||
For example, the following cookie will be set for the domain
|
||||
`my.example.org` and all its subdomains, but only on the path
|
||||
`/account` and all its subdirectories.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
Req2 = cowboy_req:set_resp_cookie(<<"inaccount">>, <<"1">>, [
|
||||
{domain, "my.example.org"},
|
||||
{path, "/account"}
|
||||
], Req).
|
||||
```
|
||||
----
|
||||
|
||||
You can restrict the cookie to secure channels, typically HTTPS.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
SessionID = generate_session_id(),
|
||||
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [
|
||||
{secure, true}
|
||||
], Req).
|
||||
```
|
||||
----
|
||||
|
||||
You can restrict the cookie to client-server communication
|
||||
only. Such a cookie will not be available to client-side scripts.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
SessionID = generate_session_id(),
|
||||
Req2 = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, [
|
||||
{http_only, true}
|
||||
], Req).
|
||||
```
|
||||
----
|
||||
|
||||
Cookies may also be set client-side, for example using
|
||||
Javascript.
|
||||
|
||||
:: Reading cookies
|
||||
=== Reading cookies
|
||||
|
||||
As we said, the client sends cookies with every request.
|
||||
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
|
||||
functions to access individual values.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Cookies = cowboy_req:parse_cookies(Req),
|
||||
{_, Lang} = lists:keyfind(<<"lang">>, 1, Cookies).
|
||||
```
|
||||
|
||||
You can match the cookies into a map.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
#{id := ID, lang := Lang} = cowboy_req:match_cookies([id, lang], Req).
|
||||
```
|
||||
|
||||
You can use constraints to validate the values while matching
|
||||
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
|
||||
you a conversion step.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
CookiesMap = cowboy_req:match_cookies([{id, int}, {lang, nonempty}], Req).
|
||||
```
|
||||
|
||||
Note that if two cookies share the same name, then the map value
|
||||
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
|
||||
if the `lang` cookie is not found. It will not be used if
|
||||
the cookie is found but has an empty value.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
#{lang := Lang} = cowboy_req:match_cookies([{lang, [], <<"en-US">>}], Req).
|
||||
```
|
||||
|
||||
If no default is provided and the value is missing, the
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
ebook versions.
|
||||
|
||||
:: Programming Erlang
|
||||
=== Programming Erlang
|
||||
|
||||
After writing some code, you will probably want to understand
|
||||
the very concepts that make Erlang what it is today. These
|
||||
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,
|
||||
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
|
||||
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.
|
||||
|
||||
:: 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
|
||||
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
|
||||
requires.
|
||||
|
||||
:: The Web is asynchronous
|
||||
=== The Web is asynchronous
|
||||
|
||||
Long ago, the Web was synchronous because HTTP was synchronous.
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
quickly get started without having to deal with minute details.
|
||||
|
||||
First, let's create the directory for our application.
|
||||
|
||||
``` bash
|
||||
[source,bash]
|
||||
$ mkdir 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.
|
||||
|
||||
``` bash
|
||||
[source,bash]
|
||||
$ wget https://raw.githubusercontent.com/ninenines/erlang.mk/master/erlang.mk
|
||||
```
|
||||
|
||||
We can now bootstrap our application. Since we are going to generate
|
||||
a release, we will also bootstrap it at the same time.
|
||||
|
||||
``` bash
|
||||
[source,bash]
|
||||
$ make -f erlang.mk bootstrap bootstrap-rel
|
||||
```
|
||||
|
||||
This creates a Makefile, a base application, and the release files
|
||||
necessary for creating the release. We can already build and start
|
||||
this release.
|
||||
|
||||
``` bash
|
||||
$ make
|
||||
...
|
||||
$ ./_rel/hello_erlang_release/bin/hello_erlang_release console
|
||||
[source,bash]
|
||||
----
|
||||
$ make run
|
||||
...
|
||||
(hello_erlang@127.0.0.1)1>
|
||||
```
|
||||
----
|
||||
|
||||
Entering the command `i().` will show the running processes, including
|
||||
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!"
|
||||
handler.
|
||||
|
||||
:: Cowboy setup
|
||||
=== Cowboy setup
|
||||
|
||||
To add Cowboy as a dependency to your application, you need to modify
|
||||
two files: the Makefile and the application resource file.
|
||||
|
||||
Modifying the Makefile allows the build system to know it needs to
|
||||
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
|
||||
to our Makefile to make it look like this:
|
||||
|
||||
``` Makefile
|
||||
[source,make]
|
||||
PROJECT = hello_erlang
|
||||
DEPS = cowboy
|
||||
include erlang.mk
|
||||
```
|
||||
|
||||
Modifying the application resource file, `src/hello_erlang.app.src`,
|
||||
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
|
||||
If you run `make run` now, Cowboy will be included in the release
|
||||
and started automatically. This is not enough however, as Cowboy
|
||||
doesn't do anything by default. We still need to tell Cowboy to
|
||||
listen for connections.
|
||||
|
||||
:: Listening for connections
|
||||
=== Listening for connections
|
||||
|
||||
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
|
||||
routes that Cowboy will use to map requests to handler modules.
|
||||
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:
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
start(_Type, _Args) ->
|
||||
Dispatch = cowboy_router:compile([
|
||||
{'_', [{"/", hello_handler, []}]}
|
||||
|
@ -125,19 +92,19 @@ start(_Type, _Args) ->
|
|||
[{env, [{dispatch, Dispatch}]}]
|
||||
),
|
||||
hello_erlang_sup:start_link().
|
||||
```
|
||||
----
|
||||
|
||||
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
|
||||
doesn't exist yet, we still have to write it.
|
||||
|
||||
If you build the release, start it and open ^http://localhost:8080
|
||||
now, you will get an error because the module is missing. Any
|
||||
other URL, like ^http://localhost:8080/test^, will result in a
|
||||
If you build and start the release, then open http://localhost:8080
|
||||
in your browser, you will get an error because the module is missing.
|
||||
Any other URL, like http://localhost:8080/test, will result in a
|
||||
404 error.
|
||||
|
||||
:: Handling requests
|
||||
=== Handling requests
|
||||
|
||||
Cowboy features different kinds of handlers, including REST
|
||||
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.
|
||||
|
||||
``` bash
|
||||
[source,bash]
|
||||
$ 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.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, Opts) ->
|
||||
Req2 = cowboy_req:reply(200,
|
||||
[{<<"content-type">>, <<"text/plain">>}],
|
||||
<<"Hello Erlang!">>,
|
||||
Req),
|
||||
{ok, Req2, Opts}.
|
||||
```
|
||||
----
|
||||
|
||||
What the above code does is send a `200 OK` reply, with the
|
||||
`content-type` header set to `text/plain` and the response
|
||||
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!
|
|
@ -1,22 +1,24 @@
|
|||
::: Handlers
|
||||
[[handlers]]
|
||||
== Handlers
|
||||
|
||||
Handlers are Erlang modules that handle HTTP requests.
|
||||
|
||||
:: Plain HTTP handlers
|
||||
=== Plain HTTP handlers
|
||||
|
||||
The most basic handler in Cowboy implements the mandatory
|
||||
`init/2` callback, manipulates the request, optionally
|
||||
sends a response and then returns.
|
||||
|
||||
This callback receives the ^"Req object^req and the options
|
||||
defined during the ^"router configuration^routing^.
|
||||
This callback receives the xref:req[Req object] and the options
|
||||
defined during the xref:routing[router configuration].
|
||||
|
||||
A handler that does nothing would look like this:
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
{ok, Req, #state{}}.
|
||||
```
|
||||
----
|
||||
|
||||
Despite sending no reply, a `204 No Content` reply will be
|
||||
sent to the client, as Cowboy makes sure that a reply is
|
||||
|
@ -24,13 +26,14 @@ sent for every request.
|
|||
|
||||
We need to use the Req object for sending a reply.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
Req2 = cowboy_req:reply(200, [
|
||||
{<<"content-type">>, <<"text/plain">>}
|
||||
], <<"Hello World!">>, Req),
|
||||
{ok, Req2, #state{}}.
|
||||
```
|
||||
----
|
||||
|
||||
As you can see we return a 3-tuple. `ok` means that the
|
||||
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
|
||||
`terminate/3`.
|
||||
|
||||
:: Other handlers
|
||||
=== Other handlers
|
||||
|
||||
The `init/2` callback can also be used to inform 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.
|
||||
|
||||
Cowboy comes with three handler types you can switch to:
|
||||
^"cowboy_rest^rest_handlers^, ^"cowboy_websocket^ws_handlers^
|
||||
and ^"cowboy_loop^loop_handlers^. In addition to those you
|
||||
xref:rest_handlers[cowboy_rest], xref:ws_handlers[cowboy_websocket]
|
||||
and xref:loop_handlers[cowboy_loop]. In addition to those you
|
||||
can define your own handler types.
|
||||
|
||||
Switching is simple. Instead of returning `ok`, you simply
|
||||
return the name of the handler type you want to use. The
|
||||
following snippet switches to a Websocket handler:
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
{cowboy_websocket, Req, #state{}}.
|
||||
```
|
||||
----
|
||||
|
||||
You can also switch to your own custom handler type:
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
{my_handler_type, Req, #state{}}.
|
||||
```
|
||||
----
|
||||
|
||||
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
|
||||
`terminate/3` callback.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
terminate(_Reason, Req, State) ->
|
||||
ok.
|
||||
```
|
||||
----
|
||||
|
||||
This callback is strictly reserved for any required cleanup.
|
||||
You cannot send a response from this function. There is no
|
|
@ -1,9 +1,10 @@
|
|||
::: Hooks
|
||||
[[hooks]]
|
||||
== Hooks
|
||||
|
||||
Hooks allow the user to customize Cowboy's behavior during specific
|
||||
operations.
|
||||
|
||||
:: Onresponse
|
||||
=== Onresponse
|
||||
|
||||
The `onresponse` hook is called right before sending the response
|
||||
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.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
cowboy:start_http(my_http_listener, 100,
|
||||
[{port, 8080}],
|
||||
[
|
||||
|
@ -24,13 +26,14 @@ cowboy:start_http(my_http_listener, 100,
|
|||
{onresponse, fun ?MODULE:custom_404_hook/4}
|
||||
]
|
||||
).
|
||||
```
|
||||
----
|
||||
|
||||
The following hook function will provide a custom body for 404 errors
|
||||
when it has not been provided before, and will let Cowboy proceed with
|
||||
the default response otherwise.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
custom_404_hook(404, Headers, <<>>, Req) ->
|
||||
Body = <<"404 Not Found.">>,
|
||||
Headers2 = lists:keyreplace(<<"content-length">>, 1, Headers,
|
||||
|
@ -38,6 +41,6 @@ custom_404_hook(404, Headers, <<>>, Req) ->
|
|||
cowboy_req:reply(404, Headers2, Body, Req);
|
||||
custom_404_hook(_, _, _, Req) ->
|
||||
Req.
|
||||
```
|
||||
----
|
||||
|
||||
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.
|
||||
|
||||
|
@ -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
|
||||
features both a Function Reference and a User Guide.
|
||||
|
||||
:: Prerequisites
|
||||
=== Prerequisites
|
||||
|
||||
Beginner Erlang knowledge is recommended for reading this guide.
|
||||
|
||||
Knowledge of the HTTP protocol is recommended but not required, as it
|
||||
will be detailed throughout the guide.
|
||||
|
||||
:: Supported platforms
|
||||
=== Supported platforms
|
||||
|
||||
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.
|
||||
|
||||
:: 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
|
||||
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
|
||||
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
|
||||
for plain HTTP handlers.
|
||||
|
||||
:: Initialization
|
||||
=== Initialization
|
||||
|
||||
The `init/2` function must return a `cowboy_loop` tuple to enable
|
||||
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.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
{cowboy_loop, Req, #state{}}.
|
||||
```
|
||||
----
|
||||
|
||||
However it is largely recommended that you set a timeout
|
||||
value. The next example sets a timeout value of 30s and
|
||||
also makes the process hibernate.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
{cowboy_loop, Req, #state{}, 30000, hibernate}.
|
||||
```
|
||||
----
|
||||
|
||||
:: Receive loop
|
||||
=== Receive loop
|
||||
|
||||
Once initialized, Cowboy will wait for messages to arrive
|
||||
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
|
||||
message otherwise.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
info({reply, Body}, Req, State) ->
|
||||
Req2 = cowboy_req:reply(200, [], Body, Req),
|
||||
{stop, Req2, State};
|
||||
info(_Msg, Req, State) ->
|
||||
{ok, Req, State, hibernate}.
|
||||
```
|
||||
----
|
||||
|
||||
Do note that the `reply` tuple here may be any message
|
||||
and is simply an example.
|
||||
|
@ -81,7 +85,7 @@ This will instruct Cowboy to end the request.
|
|||
|
||||
Otherwise an `ok` tuple should be returned.
|
||||
|
||||
:: Streaming loop
|
||||
=== Streaming loop
|
||||
|
||||
Another common case well suited for loop handlers is
|
||||
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,
|
||||
and the loop is stopped by sending an `eof` message.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
Req2 = cowboy_req:chunked_reply(200, [], Req),
|
||||
{cowboy_loop, Req2, #state{}}.
|
||||
|
@ -105,18 +110,18 @@ info({chunk, Chunk}, Req, State) ->
|
|||
{ok, Req, State};
|
||||
info(_Msg, Req, State) ->
|
||||
{ok, Req, State}.
|
||||
```
|
||||
----
|
||||
|
||||
:: Cleaning up
|
||||
==== Cleaning up
|
||||
|
||||
It is recommended that you set the connection header to
|
||||
`close` when replying, as this process may be reused for
|
||||
a subsequent request.
|
||||
|
||||
Please refer to the ^"Handlers chapter^handlers
|
||||
Please refer to the xref:handlers[Handlers chapter]
|
||||
for general instructions about cleaning up.
|
||||
|
||||
:: Timeout
|
||||
=== Timeout
|
||||
|
||||
By default Cowboy will not attempt to close the connection
|
||||
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
|
||||
`loop_max_buffer` middleware environment value.
|
||||
|
||||
:: Hibernate
|
||||
=== Hibernate
|
||||
|
||||
To save memory, you may hibernate the process in between
|
||||
messages received. This is done by returning the atom
|
|
@ -1,4 +1,5 @@
|
|||
::: Middlewares
|
||||
[[middlewares]]
|
||||
== Middlewares
|
||||
|
||||
Cowboy delegates the request processing to middleware components.
|
||||
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
|
||||
of them decides to stop processing.
|
||||
|
||||
:: Usage
|
||||
=== Usage
|
||||
|
||||
Middlewares only need to implement a single callback: `execute/2`.
|
||||
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
|
||||
goes wrong.
|
||||
|
||||
:: Configuration
|
||||
=== Configuration
|
||||
|
||||
The middleware environment is defined as the `env` protocol option.
|
||||
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`
|
||||
convenience function, adding or replacing a value in the environment.
|
||||
|
||||
:: Routing middleware
|
||||
=== Routing middleware
|
||||
|
||||
The routing middleware requires the `dispatch` value. If routing
|
||||
succeeds, it will put the handler name and options in the `handler`
|
||||
and `handler_opts` values of the environment, respectively.
|
||||
|
||||
:: Handler middleware
|
||||
=== Handler middleware
|
||||
|
||||
The handler middleware requires the `handler` and `handler_opts`
|
||||
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
|
||||
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
|
||||
in the wild at the time of writing.
|
||||
|
||||
:: The prehistoric Web
|
||||
=== The prehistoric Web
|
||||
|
||||
HTTP was initially created to serve HTML pages and only
|
||||
had the GET method for retrieving them. This initial
|
||||
|
@ -29,7 +30,7 @@ this.
|
|||
Most improvements done in recent years focused on reducing
|
||||
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
|
||||
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
|
||||
be received in the same order as the requests.
|
||||
|
||||
:: REST
|
||||
=== REST
|
||||
|
||||
The design of HTTP/1.1 was influenced by the REST architectural
|
||||
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
|
||||
which are generally meant to be used by executable code directly.
|
||||
|
||||
:: XmlHttpRequest
|
||||
=== XmlHttpRequest
|
||||
|
||||
Also know as AJAX, this technology allows Javascript code running
|
||||
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
|
||||
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
|
||||
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
|
||||
case it doesn't always play well with proxies.
|
||||
|
||||
:: HTML5
|
||||
=== HTML5
|
||||
|
||||
HTML5 is, of course, the HTML version after HTML4. But HTML5
|
||||
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
|
||||
it is being standardized.
|
||||
|
||||
:: EventSource
|
||||
=== EventSource
|
||||
|
||||
EventSource, sometimes also called Server-Sent Events, is a
|
||||
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
|
||||
more generic approach can be found in Websocket.
|
||||
|
||||
:: Websocket
|
||||
=== Websocket
|
||||
|
||||
Websocket is a protocol built on top of HTTP/1.1 that provides
|
||||
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
|
||||
sometimes used for communication between systems.
|
||||
|
||||
:: SPDY
|
||||
=== SPDY
|
||||
|
||||
SPDY is an attempt to reduce page loading time by opening a
|
||||
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
|
||||
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.
|
||||
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
|
||||
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
|
||||
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
|
||||
information about each part and read their contents.
|
||||
|
||||
:: Structure
|
||||
=== Structure
|
||||
|
||||
A multipart message is a list of parts. Parts may
|
||||
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
|
||||
as the Web is concerned.
|
||||
|
||||
:: Form-data
|
||||
=== Form-data
|
||||
|
||||
In the normal case, when a form is submitted, the
|
||||
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.
|
||||
Proper investigation of the contents is recommended.
|
||||
|
||||
:: Checking the content-type
|
||||
=== Checking the content-type
|
||||
|
||||
While there is a variety of multipart messages, the
|
||||
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
|
||||
has been sent by parsing the `content-type` header.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
{<<"multipart">>, <<"form-data">>, _}
|
||||
= 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
|
||||
parts. Then, for each part, you can inspect its headers
|
||||
and read its body.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
multipart(Req) ->
|
||||
case cowboy_req:part(Req) of
|
||||
{ok, _Headers, Req2} ->
|
||||
|
@ -85,7 +88,7 @@ multipart(Req) ->
|
|||
{done, Req2} ->
|
||||
Req2
|
||||
end.
|
||||
```
|
||||
----
|
||||
|
||||
Parts do not have a size limit. When a part body is
|
||||
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
|
||||
for files but crash when a normal field is too large.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
multipart(Req) ->
|
||||
case cowboy_req:part(Req) of
|
||||
{ok, Headers, Req2} ->
|
||||
|
@ -123,14 +127,14 @@ stream_file(Req) ->
|
|||
{more, _Body, Req2} ->
|
||||
stream_file(Req2)
|
||||
end.
|
||||
```
|
||||
----
|
||||
|
||||
By default the body chunk Cowboy will return is limited
|
||||
to 8MB. This can of course be overriden. Both functions
|
||||
can take a second argument, the same list of options that
|
||||
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.
|
||||
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
|
||||
all bodies:
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
multipart(Req) ->
|
||||
case cowboy_req:part(Req) of
|
||||
{ok, _Headers, Req2} ->
|
||||
|
@ -148,7 +153,7 @@ multipart(Req) ->
|
|||
{done, Req2} ->
|
||||
Req2
|
||||
end.
|
||||
```
|
||||
----
|
||||
|
||||
Similarly, if you start reading the body and it ends up
|
||||
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
|
||||
goes through until a response is sent, along with
|
||||
details of the Cowboy implementation.
|
||||
|
||||
:: Request/response
|
||||
=== Request/response
|
||||
|
||||
As you already know, HTTP clients connect to the server and
|
||||
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:
|
||||
|
||||
^"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
|
||||
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
|
||||
default the response is sent directly to the client.
|
||||
|
||||
:: And then?
|
||||
=== And then?
|
||||
|
||||
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
|
||||
chapter.
|
||||
|
||||
:: Keep-alive (HTTP/1.1)
|
||||
=== Keep-alive (HTTP/1.1)
|
||||
|
||||
With HTTP/1.1, the connection may be left open for
|
||||
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.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
Req2 = cowboy_req:reply(200, [
|
||||
{<<"connection">>, <<"close">>},
|
||||
], <<"Closing the socket in 3.. 2.. 1..">>, Req).
|
||||
```
|
||||
----
|
||||
|
||||
Cowboy will only accept a certain number of new requests
|
||||
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
|
||||
HTTP listener.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
cowboy:start_http(my_http_listener, 100, [{port, 8080}], [
|
||||
{env, [{dispatch, Dispatch}]},
|
||||
{max_keepalive, 5}
|
||||
]).
|
||||
```
|
||||
----
|
||||
|
||||
Cowboy implements the keep-alive mechanism by reusing
|
||||
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
|
||||
be used for this purpose.
|
||||
|
||||
:: Pipelining (HTTP/1.1)
|
||||
=== Pipelining (HTTP/1.1)
|
||||
|
||||
While HTTP is designed as a sequential protocol, with
|
||||
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.
|
||||
|
||||
:: Asynchronous requests (SPDY)
|
||||
=== Asynchronous requests (SPDY)
|
||||
|
||||
In SPDY, the client can send a request at any time.
|
||||
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
|
||||
information about a request, read the body of the request
|
||||
and send a response.
|
||||
|
||||
:: A special variable
|
||||
=== A special variable
|
||||
|
||||
While we call it an "object", it is not an object in the
|
||||
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
|
||||
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
|
||||
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
|
||||
own chapters.
|
||||
|
||||
:: Request
|
||||
=== Request
|
||||
|
||||
When a client performs a request, it first sends a few required
|
||||
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
|
||||
are case sensitive.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Method = cowboy_req:method(Req).
|
||||
```
|
||||
|
||||
The host, port and path parts of the URL identify the resource
|
||||
being accessed. The host and port information may not be
|
||||
available if the client uses HTTP/1.0.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Host = cowboy_req:host(Req),
|
||||
Port = cowboy_req:port(Req),
|
||||
Path = cowboy_req:path(Req).
|
||||
```
|
||||
|
||||
The version used by the client can of course also be obtained.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Version = cowboy_req:version(Req).
|
||||
```
|
||||
|
||||
Do note however that clients claiming to implement one version
|
||||
of the protocol does not mean they implement it fully, or even
|
||||
properly.
|
||||
|
||||
:: Bindings
|
||||
=== Bindings
|
||||
|
||||
After routing the request, bindings are available. Bindings
|
||||
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`
|
||||
if the binding doesn't exist.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Binding = cowboy_req:binding(my_binding, Req).
|
||||
```
|
||||
|
||||
If you need a different value when the binding doesn't exist,
|
||||
you can change the default.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Binding = cowboy_req:binding(my_binding, Req, 42).
|
||||
```
|
||||
|
||||
You can also obtain all bindings in one call. They will be
|
||||
returned as a list of key/value tuples.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
AllBindings = cowboy_req:bindings(Req).
|
||||
```
|
||||
|
||||
If you used `...` at the beginning of the route's pattern
|
||||
for the host, you can retrieve the matched part of the host.
|
||||
The value will be `undefined` otherwise.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
HostInfo = cowboy_req:host_info(Req).
|
||||
```
|
||||
|
||||
Similarly, if you used `...` at the end of the route's
|
||||
pattern for the path, you can retrieve the matched part,
|
||||
or get `undefined` otherwise.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
PathInfo = cowboy_req:path_info(Req).
|
||||
```
|
||||
|
||||
:: Query string
|
||||
=== Query string
|
||||
|
||||
The raw query string can be obtained directly.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Qs = cowboy_req:qs(Req).
|
||||
```
|
||||
|
||||
You can parse the query string and then use standard library
|
||||
functions to access individual values.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
QsVals = cowboy_req:parse_qs(Req),
|
||||
{_, Lang} = lists:keyfind(<<"lang">>, 1, QsVals).
|
||||
```
|
||||
|
||||
You can match the query string into a map.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
#{id := ID, lang := Lang} = cowboy_req:match_qs([id, lang], Req).
|
||||
```
|
||||
|
||||
You can use constraints to validate the values while matching
|
||||
them. The following snippet will crash if the `id` value is
|
||||
|
@ -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
|
||||
you a conversion step.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
QsMap = cowboy_req:match_qs([{id, int}, {lang, nonempty}], Req).
|
||||
```
|
||||
|
||||
Note that in the case of duplicate query string keys, the map
|
||||
value will become a list of the different values.
|
||||
|
@ -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
|
||||
the key is found but has an empty value.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
#{lang := Lang} = cowboy_req:match_qs([{lang, [], <<"en-US">>}], Req).
|
||||
```
|
||||
|
||||
If no default is provided and the value is missing, the
|
||||
query string is deemed invalid and the process will crash.
|
||||
|
||||
:: Request URL
|
||||
=== Request URL
|
||||
|
||||
You can reconstruct the full URL of the resource.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
URL = cowboy_req:url(Req).
|
||||
```
|
||||
|
||||
You can also obtain only the base of the URL, excluding the
|
||||
path and query string.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
BaseURL = cowboy_req:host_url(Req).
|
||||
```
|
||||
|
||||
:: Headers
|
||||
=== Headers
|
||||
|
||||
Cowboy allows you to obtain the header values as string,
|
||||
or parsed into a more meaningful representation.
|
||||
|
||||
This will get the string value of a header.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
HeaderVal = cowboy_req:header(<<"content-type">>, Req).
|
||||
```
|
||||
|
||||
You can of course set a default in case the header is missing.
|
||||
|
||||
``` erlang
|
||||
HeaderVal
|
||||
= cowboy_req:header(<<"content-type">>, Req, <<"text/plain">>).
|
||||
```
|
||||
[source,erlang]
|
||||
HeaderVal = cowboy_req:header(<<"content-type">>, Req, <<"text/plain">>).
|
||||
|
||||
And also obtain all headers.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
AllHeaders = cowboy_req:headers(Req).
|
||||
```
|
||||
|
||||
To parse the previous header, simply call `parse_header/{2,3}`
|
||||
where you would call `header/{2,3}` otherwise.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req).
|
||||
```
|
||||
|
||||
Cowboy will crash if it doesn't know how to parse the given
|
||||
header, or if the value is invalid.
|
||||
|
@ -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
|
||||
by default.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req,
|
||||
{<<"text">>, <<"plain">>, []}).
|
||||
```
|
||||
----
|
||||
|
||||
The list of known headers and default values is defined in the
|
||||
manual.
|
||||
|
||||
:: Meta
|
||||
=== Meta
|
||||
|
||||
Cowboy will sometimes associate some meta information with
|
||||
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`
|
||||
if it isn't defined.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
MetaVal = cowboy_req:meta(websocket_version, Req).
|
||||
```
|
||||
|
||||
You can change the default value if needed.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
MetaVal = cowboy_req:meta(websocket_version, Req, 13).
|
||||
```
|
||||
|
||||
You can also define your own meta values. The name must be
|
||||
an `atom()`.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Req2 = cowboy_req:set_meta(the_answer, 42, Req).
|
||||
```
|
||||
|
||||
:: Peer
|
||||
=== Peer
|
||||
|
||||
You can obtain the peer address and port number. This is
|
||||
not necessarily the actual IP and port of the client, but
|
||||
rather the one of the machine that connected to the server.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
{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.
|
||||
|
||||
|
@ -16,13 +17,12 @@ parse in a single call for form urlencoded formats or
|
|||
multipart. All of these except multipart are covered in
|
||||
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.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
cowboy_req:has_body(Req).
|
||||
```
|
||||
|
||||
It will return `true` if there is a request body, and
|
||||
`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
|
||||
having to explicitly check for it.
|
||||
|
||||
:: Request body length
|
||||
=== Request body length
|
||||
|
||||
You can obtain the body length if it was sent with the
|
||||
request.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Length = cowboy_req:body_length(Req).
|
||||
```
|
||||
|
||||
The value returned will be `undefined` if the length
|
||||
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
|
||||
chunked bodies by using the stream functions.
|
||||
|
||||
:: Reading the body
|
||||
=== Reading the body
|
||||
|
||||
You can read the whole body directly in one call.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
{ok, Body, Req2} = cowboy_req:body(Req).
|
||||
```
|
||||
|
||||
By default, Cowboy will attempt to read up to a
|
||||
size of 8MB. You can override this limit as needed.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
{ok, Body, Req2} = cowboy_req:body(Req, [{length, 100000000}]).
|
||||
```
|
||||
|
||||
You can also disable it.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
{ok, Body, Req2} = cowboy_req:body(Req, [{length, infinity}]).
|
||||
```
|
||||
|
||||
It is recommended that you do not disable it for public
|
||||
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
|
||||
would like to.
|
||||
|
||||
:: Streaming the body
|
||||
=== Streaming the body
|
||||
|
||||
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
|
||||
you to loop over all chunks.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
body_to_console(Req) ->
|
||||
case cowboy_req:body(Req) of
|
||||
{ok, Data, Req2} ->
|
||||
|
@ -92,12 +89,12 @@ body_to_console(Req) ->
|
|||
io:format("~s", [Data]),
|
||||
body_to_console(Req2)
|
||||
end.
|
||||
```
|
||||
----
|
||||
|
||||
You can of course set the `length` option to configure the
|
||||
size of chunks.
|
||||
|
||||
:: Rate of data transmission
|
||||
=== Rate of data transmission
|
||||
|
||||
You can control the rate of data transmission by setting
|
||||
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
|
||||
before that amount is received, in milliseconds.
|
||||
|
||||
:: Transfer and content decoding
|
||||
=== Transfer and content decoding
|
||||
|
||||
Cowboy will by default decode the chunked transfer-encoding
|
||||
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.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
{ok, Data, Req2} = cowboy_req:body(Req, [
|
||||
{transfer_decode, fun transfer_decode/2, TransferState},
|
||||
{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
|
||||
body was sent using the application/x-www-form-urlencoded
|
||||
content-type.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
{ok, KeyValues, Req2} = cowboy_req:body_qs(Req).
|
||||
```
|
||||
|
||||
You can then retrieve an individual value from that list.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
{_, Lang} = lists:keyfind(lang, 1, KeyValues).
|
||||
```
|
||||
|
||||
You should not attempt to match on the list as the order
|
||||
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
|
||||
by setting the `length` option.
|
||||
|
||||
``` erlang
|
||||
{ok, KeyValues, Req2} = cowboy_req:body_qs(Req,
|
||||
[{length, 2000000}]).
|
||||
```
|
||||
[source,erlang]
|
||||
{ok, KeyValues, Req2} = cowboy_req:body_qs(Req, [{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
|
||||
you must answer in order to write a good resource handler.
|
||||
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
|
||||
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?
|
||||
Implement the `known_methods` callback.
|
||||
|
||||
:: Type of resource handler
|
||||
=== Type of resource handler
|
||||
|
||||
Am I writing a handler for a collection of resources,
|
||||
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
|
||||
the same handler.
|
||||
|
||||
:: Collection handler
|
||||
=== Collection handler
|
||||
|
||||
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,
|
||||
modifying or deleting parts of the collection.
|
||||
|
||||
:: Single resource handler
|
||||
=== Single resource handler
|
||||
|
||||
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
|
||||
values in the resource.
|
||||
|
||||
:: The resource
|
||||
=== The resource
|
||||
|
||||
Following the above discussion, implement the
|
||||
`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
|
||||
have a limit in length. Implement `uri_too_long`.
|
||||
|
||||
:: Representations
|
||||
=== Representations
|
||||
|
||||
What media types do I provide? If text based, what charsets
|
||||
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
|
||||
the `multiple_choices` callback.
|
||||
|
||||
:: Redirections
|
||||
=== Redirections
|
||||
|
||||
Do I need to keep track of what resources were deleted?
|
||||
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_permanently` callback.
|
||||
|
||||
:: The request
|
||||
=== The request
|
||||
|
||||
Do we need to perform extra checks to make sure the request
|
||||
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
|
||||
methods you are implementing.
|
||||
|
||||
:: OPTIONS method
|
||||
=== OPTIONS method
|
||||
|
||||
Cowboy by default will send back a list of allowed methods.
|
||||
Do I need to add more information to the response? Implement
|
||||
the `options` method.
|
||||
|
||||
:: GET and HEAD methods
|
||||
=== GET and HEAD methods
|
||||
|
||||
If you implement the methods GET and/or HEAD, you must
|
||||
implement one `ProvideResource` callback for each
|
||||
content-type returned by the `content_types_provided`
|
||||
callback.
|
||||
|
||||
:: PUT, POST and PATCH methods
|
||||
=== PUT, POST and PATCH methods
|
||||
|
||||
If you implement the methods PUT, POST and/or PATCH,
|
||||
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
|
||||
`is_conflict` callback.
|
||||
|
||||
:: DELETE methods
|
||||
=== DELETE methods
|
||||
|
||||
If you implement the method DELETE, you must implement
|
||||
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.
|
||||
|
||||
|
@ -9,36 +10,37 @@ with its body streamed by chunks of arbitrary size.
|
|||
You can also set headers or the response body in advance
|
||||
and Cowboy will use them when you finally do reply.
|
||||
|
||||
:: Reply
|
||||
=== Reply
|
||||
|
||||
You can send a reply with no particular headers or body.
|
||||
Cowboy will make sure to send the mandatory headers with
|
||||
the response.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Req2 = cowboy_req:reply(200, Req).
|
||||
```
|
||||
|
||||
You can define headers to be sent with the response. Note
|
||||
that header names must be lowercase. Again, Cowboy will
|
||||
make sure to send the mandatory headers with the response.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
Req2 = cowboy_req:reply(303, [
|
||||
{<<"location">>, <<"http://ninenines.eu">>}
|
||||
], Req).
|
||||
```
|
||||
----
|
||||
|
||||
You can override headers that Cowboy would send otherwise.
|
||||
Any header set by the user will be used over the ones set
|
||||
by Cowboy. For example, you can advertise yourself as a
|
||||
different server.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
Req2 = cowboy_req:reply(200, [
|
||||
{<<"server">>, <<"yaws">>}
|
||||
], Req).
|
||||
```
|
||||
----
|
||||
|
||||
We also saw earlier how to force close the connection by
|
||||
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
|
||||
client may know how to read the body.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
Req2 = cowboy_req:reply(200, [
|
||||
{<<"content-type">>, <<"text/plain">>}
|
||||
], "Hello world!", Req).
|
||||
```
|
||||
----
|
||||
|
||||
Here is the same example but sending HTML this time.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
Req2 = cowboy_req:reply(200, [
|
||||
{<<"content-type">>, <<"text/html">>}
|
||||
], "<html><head>Hello world!</head><body><p>Hats off!</p></body></html>", Req).
|
||||
```
|
||||
----
|
||||
|
||||
Note that the reply is sent immediately.
|
||||
|
||||
:: Chunked reply
|
||||
=== Chunked reply
|
||||
|
||||
You can also stream the response body. First, you need to
|
||||
initiate the reply by sending the response status code.
|
||||
Then you can send the body in chunks of arbitrary size.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Req2 = cowboy_req:chunked_reply(200, Req),
|
||||
cowboy_req:chunk("Hello...", Req2),
|
||||
cowboy_req:chunk("chunked...", Req2),
|
||||
cowboy_req:chunk("world!!", Req2).
|
||||
```
|
||||
|
||||
You should make sure to match on `ok` as an error may be
|
||||
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
|
||||
set this header or any other just like for normal replies.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
Req2 = cowboy_req:chunked_reply(200, [
|
||||
{<<"content-type">>, <<"text/html">>}
|
||||
], Req),
|
||||
cowboy_req:chunk("<html><head>Hello world!</head>", Req2),
|
||||
cowboy_req:chunk("<body><p>Hats off!</p></body></html>", Req2).
|
||||
```
|
||||
----
|
||||
|
||||
Note that the reply and each chunk following it are sent
|
||||
immediately.
|
||||
|
||||
:: Preset response headers
|
||||
=== Preset response headers
|
||||
|
||||
You can define response headers in advance. They will be
|
||||
merged into the headers given in the reply call. Headers
|
||||
in the reply call override preset response headers which
|
||||
override the default Cowboy headers.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Req2 = cowboy_req:set_resp_header(<<"allow">>, "GET", Req).
|
||||
```
|
||||
|
||||
You can check if a response header has already been set.
|
||||
This will only check the response headers that you set,
|
||||
and not the ones Cowboy will add when actually sending
|
||||
the reply.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
cowboy_req:has_resp_header(<<"allow">>, Req).
|
||||
```
|
||||
|
||||
It will return `true` if the header is defined, and `false`
|
||||
otherwise.
|
||||
|
@ -121,19 +123,17 @@ otherwise.
|
|||
Finally, you can also delete a preset response header if
|
||||
needed. If you do, it will not be sent.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
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
|
||||
body will be ignored if you then choose to send a chunked
|
||||
reply, or if you send a reply with an explicit body.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Req2 = cowboy_req:set_resp_body("Hello world!", Req).
|
||||
```
|
||||
|
||||
You can also set a fun that will be called when it is time
|
||||
to send the body. There are three different ways of doing
|
||||
|
@ -144,38 +144,41 @@ you should specify it, as it will help clients determine
|
|||
the remaining download time and allow them to inform the
|
||||
user.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
F = fun (Socket, Transport) ->
|
||||
Transport:send(Socket, "Hello world!")
|
||||
end,
|
||||
Req2 = cowboy_req:set_resp_body_fun(12, F, Req).
|
||||
```
|
||||
----
|
||||
|
||||
If you do not know the length of the body, you should use
|
||||
a chunked response body fun instead.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
F = fun (SendChunk) ->
|
||||
Body = lists:duplicate(random:uniform(1024, $a)),
|
||||
SendChunk(Body)
|
||||
end,
|
||||
Req2 = cowboy_req:set_resp_body_fun(chunked, F, Req).
|
||||
```
|
||||
----
|
||||
|
||||
Finally, you can also send data on the socket directly,
|
||||
without knowing the length in advance. Cowboy may be
|
||||
forced to close the connection at the end of the response
|
||||
though depending on the protocol capabilities.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
F = fun (Socket, Transport) ->
|
||||
Body = lists:duplicate(random:uniform(1024, $a)),
|
||||
Transport:send(Socket, Body)
|
||||
end,
|
||||
Req2 = cowboy_req:set_resp_body_fun(F, Req).
|
||||
```
|
||||
----
|
||||
|
||||
:: Sending files
|
||||
=== Sending files
|
||||
|
||||
You can send files directly from disk without having to
|
||||
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
|
||||
can be known in advance.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
F = fun (Socket, Transport) ->
|
||||
Transport:sendfile(Socket, "priv/styles.css")
|
||||
end,
|
||||
Req2 = cowboy_req:set_resp_body_fun(FileSize, F, Req).
|
||||
```
|
||||
----
|
||||
|
||||
Please see the Ranch guide for more information about
|
||||
sending files.
|
|
@ -1,4 +1,5 @@
|
|||
::: REST flowcharts
|
||||
[[rest_flowcharts]]
|
||||
== REST flowcharts
|
||||
|
||||
This chapter will explain the REST handler state machine through
|
||||
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
|
||||
the default behavior if the callback is undefined.
|
||||
|
||||
:: Start
|
||||
=== Start
|
||||
|
||||
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 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, or the "Content negotiation" diagram otherwise.
|
||||
|
||||
:: OPTIONS method
|
||||
=== OPTIONS method
|
||||
|
||||
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
|
||||
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
|
||||
by default.
|
||||
|
||||
:: Content negotiation
|
||||
=== Content negotiation
|
||||
|
||||
This diagram applies to all request methods other than
|
||||
OPTIONS. It is executed right after the "Start" diagram
|
||||
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
|
||||
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
|
||||
method.
|
||||
|
||||
:: GET and HEAD methods
|
||||
=== GET and HEAD methods
|
||||
|
||||
This diagram only applies to GET and HEAD requests.
|
||||
|
||||
For a description of the `cond` step, please see
|
||||
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
|
||||
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
|
||||
fact moved.
|
||||
|
||||
:: PUT, POST and PATCH methods
|
||||
=== PUT, POST and PATCH methods
|
||||
|
||||
This diagram only applies to PUT, POST and PATCH requests.
|
||||
|
||||
For a description of the `cond` step, please see
|
||||
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
|
||||
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
|
||||
or a body in the response.
|
||||
|
||||
:: DELETE method
|
||||
=== DELETE method
|
||||
|
||||
This diagram only applies to DELETE requests.
|
||||
|
||||
For a description of the `cond` step, please see
|
||||
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
|
||||
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
|
||||
fact moved.
|
||||
|
||||
:: Conditional requests
|
||||
=== Conditional requests
|
||||
|
||||
This diagram applies to all request methods other than
|
||||
OPTIONS. It is executed right after 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
|
||||
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
|
||||
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.
|
||||
|
||||
:: Initialization
|
||||
=== Initialization
|
||||
|
||||
First, the `init/2` callback is called. This callback is common
|
||||
to all handlers. To use REST for the current request, this function
|
||||
must return a `cowboy_rest` tuple.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
{cowboy_rest, Req, #state{}}.
|
||||
```
|
||||
----
|
||||
|
||||
Cowboy will then switch to the REST protocol and start executing
|
||||
the state machine.
|
||||
|
@ -23,7 +25,7 @@ the state machine.
|
|||
After reaching the end of the flowchart, the `terminate/3` callback
|
||||
will be called if it is defined.
|
||||
|
||||
:: Methods
|
||||
=== Methods
|
||||
|
||||
The REST component has code for handling the following HTTP methods:
|
||||
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
|
||||
defined for them at this time.
|
||||
|
||||
:: Callbacks
|
||||
=== Callbacks
|
||||
|
||||
All callbacks are optional. Some may become mandatory depending
|
||||
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,
|
||||
"none" means there is no default value for this callback.
|
||||
|
||||
|| Callback name Default value
|
||||
|
|
||||
| allowed_methods `[<<"GET">>, <<"HEAD">>, <<"OPTIONS">>]`
|
||||
| allow_missing_post `true`
|
||||
| charsets_provided skip
|
||||
| content_types_accepted none
|
||||
| content_types_provided `[{{<<"text">>, <<"html">>, '*'}, to_html}] `
|
||||
| delete_completed `true`
|
||||
| delete_resource `false`
|
||||
| expires `undefined`
|
||||
| forbidden `false`
|
||||
| generate_etag `undefined`
|
||||
| is_authorized `true`
|
||||
| is_conflict `false`
|
||||
| known_methods `[<<"GET">>, <<"HEAD">>, <<"POST">>, <<"PUT">>, <<"PATCH">>, <<"DELETE">>, <<"OPTIONS">>]`
|
||||
| languages_provided skip
|
||||
| last_modified `undefined`
|
||||
| malformed_request `false`
|
||||
| moved_permanently `false`
|
||||
| moved_temporarily `false`
|
||||
| multiple_choices `false`
|
||||
| options `ok`
|
||||
| previously_existed `false`
|
||||
| resource_exists `true`
|
||||
| service_available `true`
|
||||
| uri_too_long `false`
|
||||
| valid_content_headers `true`
|
||||
| valid_entity_length `true`
|
||||
| variances `[]`
|
||||
[cols="<,^",options="header"]
|
||||
|===
|
||||
| Callback name | Default value
|
||||
| allowed_methods | `[<<"GET">>, <<"HEAD">>, <<"OPTIONS">>]`
|
||||
| allow_missing_post | `true`
|
||||
| charsets_provided | skip
|
||||
| content_types_accepted | none
|
||||
| content_types_provided | `$$[{{<<"text">>, <<"html">>, '*'}, to_html}]$$`
|
||||
| delete_completed | `true`
|
||||
| delete_resource | `false`
|
||||
| expires | `undefined`
|
||||
| forbidden | `false`
|
||||
| generate_etag | `undefined`
|
||||
| is_authorized | `true`
|
||||
| is_conflict | `false`
|
||||
| known_methods | `[<<"GET">>, <<"HEAD">>, <<"POST">>, <<"PUT">>, <<"PATCH">>, <<"DELETE">>, <<"OPTIONS">>]`
|
||||
| languages_provided | skip
|
||||
| last_modified | `undefined`
|
||||
| malformed_request | `false`
|
||||
| moved_permanently | `false`
|
||||
| moved_temporarily | `false`
|
||||
| multiple_choices | `false`
|
||||
| options | `ok`
|
||||
| previously_existed | `false`
|
||||
| resource_exists | `true`
|
||||
| service_available | `true`
|
||||
| uri_too_long | `false`
|
||||
| valid_content_headers | `true`
|
||||
| valid_entity_length | `true`
|
||||
| variances | `[]`
|
||||
|===
|
||||
|
||||
As you can see, Cowboy tries to move on with the request whenever
|
||||
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,
|
||||
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
|
||||
execution. You can retrieve them using `cowboy_req:meta/{2,3}`.
|
||||
The values are defined in the following table.
|
||||
|
||||
|| Meta key Details
|
||||
|
|
||||
| media_type The content-type negotiated for the response entity.
|
||||
| language The language negotiated for the response entity.
|
||||
| charset The charset negotiated for the response entity.
|
||||
[cols="<,<",options="header"]
|
||||
|===
|
||||
| Meta key | Details
|
||||
| media_type | The content-type 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
|
||||
request that used a method other than HEAD or GET.
|
||||
|
||||
:: Response headers
|
||||
=== Response headers
|
||||
|
||||
Cowboy will set response headers automatically over the execution
|
||||
of the REST code. They are listed in the following table.
|
||||
|
||||
|| Header name Details
|
||||
|
|
||||
| content-language Language used in the response body
|
||||
| content-type Media type and charset of the response body
|
||||
| etag Etag of the resource
|
||||
| expires Expiration date of the resource
|
||||
| last-modified Last modification date for the resource
|
||||
| location Relative or absolute URI to the requested resource
|
||||
| vary List of headers that may change the representation of the resource
|
||||
[cols="<,<",options="header"]
|
||||
|===
|
||||
| Header name | Details
|
||||
| content-language | Language used in the response body
|
||||
| content-type | Media type and charset of the response body
|
||||
| etag | Etag of the resource
|
||||
| expires | Expiration date of the resource
|
||||
| last-modified | Last modification date for 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
|
||||
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
|
||||
it means in the context of HTTP and the Web.
|
||||
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
|
||||
what it achieves.
|
||||
|
||||
:: REST architecture
|
||||
=== REST architecture
|
||||
|
||||
REST is a *client-server* architecture. The client and the server
|
||||
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
|
||||
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
|
||||
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,
|
||||
for example "all users".
|
||||
|
||||
:: Resource representations
|
||||
=== Resource representations
|
||||
|
||||
The representation of a resource is a sequence of bytes associated
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
to be RESTful fail. Interactions with a server must be
|
|
@ -1,4 +1,5 @@
|
|||
::: Routing
|
||||
[[routing]]
|
||||
== Routing
|
||||
|
||||
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.
|
||||
|
||||
:: Structure
|
||||
=== Structure
|
||||
|
||||
The general structure for the routes is defined as follow.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Routes = [Host1, Host2, ... HostN].
|
||||
```
|
||||
|
||||
Each host contains matching rules for the host along with optional
|
||||
constraints, and a list of routes for the path component.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Host1 = {HostMatch, PathsList}.
|
||||
Host2 = {HostMatch, Constraints, PathsList}.
|
||||
```
|
||||
|
||||
The list of routes for the path component is defined similar to the
|
||||
list of hosts.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
PathsList = [Path1, Path2, ... PathN].
|
||||
```
|
||||
|
||||
Finally, each path contains matching rules for the path along with
|
||||
optional constraints, and gives us the handler module to be used
|
||||
along with options that will be given to it on initialization.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
Path1 = {PathMatch, Handler, Opts}.
|
||||
Path2 = {PathMatch, Constraints, Handler, Opts}.
|
||||
```
|
||||
|
||||
Continue reading to learn more about the match syntax and the optional
|
||||
constraints.
|
||||
|
||||
:: Match syntax
|
||||
=== Match syntax
|
||||
|
||||
The match syntax is used to associate host names and paths with their
|
||||
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
|
||||
a `string()` or a `binary()`.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
PathMatch1 = "/".
|
||||
PathMatch2 = "/path/to/resource".
|
||||
|
||||
HostMatch1 = "cowboy.example.org".
|
||||
```
|
||||
----
|
||||
|
||||
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
|
||||
is concerned.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
PathMatch2 = "/path/to/resource".
|
||||
PathMatch3 = "/path/to/resource/".
|
||||
```
|
||||
|
||||
Hosts with and without a trailing dot are equivalent for routing.
|
||||
Similarly, hosts with and without a leading dot are also equivalent.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
HostMatch1 = "cowboy.example.org".
|
||||
HostMatch2 = "cowboy.example.org.".
|
||||
HostMatch3 = ".cowboy.example.org".
|
||||
```
|
||||
|
||||
It is possible to extract segments of the host and path and to store
|
||||
the values in the `Req` object for later use. 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
|
||||
is the name of the binding in which the segment value will be stored.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
PathMatch = "/hats/:name/prices".
|
||||
HostMatch = ":subdomain.example.org".
|
||||
```
|
||||
|
||||
If these two end up matching when routing, you will end up with two
|
||||
bindings defined, `subdomain` and `name`, each containing the
|
||||
|
@ -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
|
||||
matching against many domain names in one go.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
HostMatch = "ninenines.:_".
|
||||
```
|
||||
|
||||
Similarly, it is possible to have optional segments. Anything
|
||||
between brackets is optional.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
PathMatch = "/hats/[page/:number]".
|
||||
HostMatch = "[www.]ninenines.eu".
|
||||
```
|
||||
|
||||
You can also have imbricated optional segments.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
PathMatch = "/hats/[page/[:number]]".
|
||||
```
|
||||
|
||||
You can retrieve the rest of the host or path using `[...]`.
|
||||
In the case of hosts it will match anything before, in the case
|
||||
|
@ -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.
|
||||
They will be represented as a list of segments.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
PathMatch = "/hats/[...]".
|
||||
HostMatch = "[...]ninenines.eu".
|
||||
```
|
||||
|
||||
If a binding appears twice in the routing rules, then the match
|
||||
will succeed only if they share the same value. This copies the
|
||||
Erlang pattern matching behavior.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
PathMatch = "/hats/:name/:name".
|
||||
```
|
||||
|
||||
This is also true when an optional segment is present. In this
|
||||
case the two values must be identical only if the segment is
|
||||
available.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
PathMatch = "/hats/:name/[:name]".
|
||||
```
|
||||
|
||||
If a binding is defined in both the host and path, then they must
|
||||
also share the same value.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
PathMatch = "/:user/[...]".
|
||||
HostMatch = ":user.github.com".
|
||||
```
|
||||
|
||||
Finally, there are two special match values that can be used. The
|
||||
first is the atom `'_'` which will match any host or path.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
PathMatch = '_'.
|
||||
HostMatch = '_'.
|
||||
```
|
||||
|
||||
The second is the special host match `"*"` which will match the
|
||||
wildcard path, generally used alongside the `OPTIONS` method.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
HostMatch = "*".
|
||||
```
|
||||
|
||||
:: Constraints
|
||||
=== Constraints
|
||||
|
||||
After the matching has completed, the resulting bindings can be tested
|
||||
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
|
||||
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
|
||||
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`.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
Dispatch = cowboy_router:compile([
|
||||
%% {HostMatch, list({PathMatch, Handler, Opts})}
|
||||
{'_', [{'_', my_handler, []}]}
|
||||
|
@ -220,20 +207,18 @@ cowboy:start_http(my_http_listener, 100,
|
|||
[{port, 8080}],
|
||||
[{env, [{dispatch, Dispatch}]}]
|
||||
).
|
||||
```
|
||||
----
|
||||
|
||||
Note that this function will return `{error, badarg}` if the structure
|
||||
given is incorrect.
|
||||
|
||||
:: Live update
|
||||
=== Live update
|
||||
|
||||
You can use the `cowboy:set_env/3` function for updating the dispatch
|
||||
list used by routing. This will apply to all new connections accepted
|
||||
by the listener.
|
||||
|
||||
``` erlang
|
||||
cowboy:set_env(my_http_listener, dispatch,
|
||||
cowboy_router:compile(Dispatch)).
|
||||
```
|
||||
[source,erlang]
|
||||
cowboy:set_env(my_http_listener, dispatch, cowboy_router:compile(Dispatch)).
|
||||
|
||||
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
|
||||
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
|
||||
with the appropriate options.
|
||||
|
||||
:: Serve one file
|
||||
=== Serve one file
|
||||
|
||||
You can use the static handler to serve one specific file
|
||||
from an application's private directory. This is particularly
|
||||
useful to serve an `index.html` file when the client requests
|
||||
useful to serve an 'index.html' file when the client requests
|
||||
the `/` path, for example. The path configured is relative
|
||||
to the given application's private directory.
|
||||
|
||||
The following rule will serve the file `static/index.html`
|
||||
The following rule will serve the file 'static/index.html'
|
||||
from the application `my_app`'s priv directory whenever the
|
||||
path `/` is accessed.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
{"/", cowboy_static, {priv_file, my_app, "static/index.html"}}
|
||||
```
|
||||
|
||||
You can also specify the absolute path to a file, or the
|
||||
path to the file relative to the current directory.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
{"/", 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
|
||||
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
|
||||
whenever the requested path begins with `/assets/`.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets"}}
|
||||
```
|
||||
|
||||
You can also specify the absolute path to the directory or
|
||||
set it relative to the current directory.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
{"/assets/[...]", cowboy_static, {dir, "/var/www/assets"}}
|
||||
```
|
||||
|
||||
:: Customize the mimetype detection
|
||||
=== Customize the mimetype detection
|
||||
|
||||
By default, Cowboy will attempt to recognize the mimetype
|
||||
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
|
||||
following will do the job.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
||||
[{mimetypes, cow_mimetypes, web}]}}
|
||||
```
|
||||
----
|
||||
|
||||
As you can see, there is an optional field that may contain
|
||||
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,
|
||||
the following configuration will do.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
||||
[{mimetypes, cow_mimetypes, all}]}}
|
||||
```
|
||||
----
|
||||
|
||||
You probably noticed the pattern by now. The configuration
|
||||
expects a module and a function name, so you can use any
|
||||
of your own functions instead.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
||||
[{mimetypes, Module, Function}]}}
|
||||
```
|
||||
----
|
||||
|
||||
The function that performs the mimetype detection receives
|
||||
a single argument that is the path to the file on disk. It
|
||||
|
@ -133,12 +133,13 @@ Finally, the mimetype can be hard-coded for all files.
|
|||
This is especially useful in combination with the `file`
|
||||
and `priv_file` options as it avoids needless computation.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
{"/", cowboy_static, {priv_file, my_app, "static/index.html",
|
||||
[{mimetypes, {<<"text">>, <<"html">>, []}}]}}
|
||||
```
|
||||
----
|
||||
|
||||
:: Generate an etag
|
||||
=== Generate an etag
|
||||
|
||||
By default, the static handler will generate an etag header
|
||||
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.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
||||
[{etag, Module, Function}]}}
|
||||
```
|
||||
----
|
||||
|
||||
This function will receive three arguments: the path to the
|
||||
file on disk, the size of the file and the last modification
|
||||
|
@ -162,7 +164,8 @@ all your servers.
|
|||
|
||||
You can also completely disable etag handling.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets",
|
||||
[{etag, false}]}}
|
||||
```
|
||||
----
|
|
@ -1,4 +1,5 @@
|
|||
::: Sub protocols
|
||||
[[sub_protocols]]
|
||||
== Sub protocols
|
||||
|
||||
Sub protocols are used for creating new types of handlers that
|
||||
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
|
||||
and handler types.
|
||||
|
||||
:: Usage
|
||||
=== Usage
|
||||
|
||||
To switch to a sub protocol, the `init/2` callback must return
|
||||
the name of the sub protocol module. Everything past this point
|
||||
is handled by the sub protocol.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
{cowboy_websocket, Req, #state{}}.
|
||||
```
|
||||
----
|
||||
|
||||
The return value may also have a `Timeout` value and/or the
|
||||
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
|
||||
hibernation:
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
{my_protocol, Req, #state{}, 5000, hibernate}.
|
||||
```
|
||||
----
|
||||
|
||||
If a sub protocol does not make use of these options, it should
|
||||
crash if it receives anything other than the default values.
|
||||
|
||||
:: Upgrade
|
||||
=== Upgrade
|
||||
|
||||
After the `init/2` function returns, Cowboy will then call 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
|
||||
timeout and hibernate values.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
upgrade(Req, Env, Handler, HandlerOpts, Timeout, Hibernate) ->
|
||||
%% Sub protocol code here.
|
||||
```
|
||||
----
|
||||
|
||||
This callback is expected to behave like a middleware and to
|
||||
return an updated environment and Req object.
|
|
@ -1,4 +1,5 @@
|
|||
::: Handling Websocket connections
|
||||
[[ws_handlers]]
|
||||
== Handling Websocket connections
|
||||
|
||||
A special handler is required for handling Websocket connections.
|
||||
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
|
||||
socket communication and decoding/encoding of frames.
|
||||
|
||||
:: Initialization
|
||||
=== Initialization
|
||||
|
||||
First, the `init/2` callback is called. This callback is common
|
||||
to all handlers. To establish a Websocket connection, this function
|
||||
must return a `ws` tuple.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
{cowboy_websocket, Req, #state{}}.
|
||||
```
|
||||
----
|
||||
|
||||
Upon receiving this tuple, Cowboy will switch to the code
|
||||
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
|
||||
the connection, assuming no correct subprotocol was found.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
case cowboy_req:parse_header(<<"sec-websocket-protocol">>, Req) of
|
||||
undefined ->
|
||||
|
@ -45,7 +48,7 @@ init(Req, _Opts) ->
|
|||
{stop, Req, undefined}
|
||||
end
|
||||
end.
|
||||
```
|
||||
----
|
||||
|
||||
It is not recommended to wait too long inside the `init/2`
|
||||
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
|
||||
or enabling timers.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
self() ! post_init,
|
||||
%% Register process here...
|
||||
|
@ -66,9 +70,9 @@ init(Req, _Opts) ->
|
|||
websocket_info(post_init, Req, State) ->
|
||||
%% Perform post_init initialization here...
|
||||
{ok, Req, State}.
|
||||
```
|
||||
----
|
||||
|
||||
:: Handling frames from the client
|
||||
=== Handling frames from the client
|
||||
|
||||
Cowboy will call `websocket_handle/3` whenever a text, binary,
|
||||
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
|
||||
ignores all others.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
websocket_handle(Frame = {text, _}, Req, State) ->
|
||||
{reply, Frame, Req, State};
|
||||
websocket_handle(_Frame, Req, State) ->
|
||||
{ok, Req, State}.
|
||||
```
|
||||
----
|
||||
|
||||
:: Handling Erlang messages
|
||||
=== Handling Erlang messages
|
||||
|
||||
Cowboy will call `websocket_info/3` whenever an Erlang message
|
||||
arrives.
|
||||
|
@ -99,14 +104,15 @@ or just continue without sending anything.
|
|||
The following snippet forwards any `log` message to the socket
|
||||
and ignores all others.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
websocket_info({log, Text}, Req, State) ->
|
||||
{reply, {text, Text}, Req, State};
|
||||
websocket_info(_Info, 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
|
||||
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`
|
||||
tuple.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
websocket_info(hello_world, Req, State) ->
|
||||
{reply, [
|
||||
{text, "Hello"},
|
||||
|
@ -124,7 +131,7 @@ websocket_info(hello_world, Req, State) ->
|
|||
{binary, <<0:8000>>}
|
||||
], Req, State};
|
||||
%% More websocket_info/3 clauses here...
|
||||
```
|
||||
----
|
||||
|
||||
Note that the payload for text and binary frames is of type
|
||||
`iodata()`, meaning it can be either a `binary()` or an
|
||||
|
@ -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
|
||||
close frame will not be sent.
|
||||
|
||||
:: Ping and timeout
|
||||
=== Ping and timeout
|
||||
|
||||
The biggest performance improvement you can do when dealing
|
||||
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.
|
||||
|
||||
``` erlang
|
||||
[source,erlang]
|
||||
----
|
||||
init(Req, _Opts) ->
|
||||
{cowboy_websocket, Req, #state{}, 60000}.
|
||||
```
|
||||
----
|
||||
|
||||
This value cannot be changed once it is set. It defaults to
|
||||
`infinity`.
|
||||
|
||||
:: Hibernate
|
||||
=== Hibernate
|
||||
|
||||
Most tuples returned from handler callbacks can include an
|
||||
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
|
||||
noticing increased CPU usage.
|
||||
|
||||
:: Supporting older browsers
|
||||
=== Supporting older browsers
|
||||
|
||||
Unfortunately Websocket is a relatively recent technology,
|
||||
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.
|
|
@ -1,9 +1,10 @@
|
|||
::: The Websocket protocol
|
||||
[[ws_protocol]]
|
||||
== The Websocket protocol
|
||||
|
||||
This chapter explains what Websocket is and why it is
|
||||
a vital component of soft realtime Web applications.
|
||||
|
||||
:: Description
|
||||
=== Description
|
||||
|
||||
Websocket is an extension to HTTP that emulates plain TCP
|
||||
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
|
||||
"version 0".
|
||||
|
||||
:: Implementation
|
||||
=== Implementation
|
||||
|
||||
Cowboy implements Websocket as a protocol upgrade. Once the
|
||||
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`
|
||||
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.
|
||||
These are started automatically if they weren't before.
|
||||
|
||||
:: Environment
|
||||
== Environment
|
||||
|
||||
The `cowboy` application does not define any application
|
||||
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
|
||||
through the environment values `handler` and `handler_opts`,
|
||||
|
@ -8,51 +14,42 @@ handled and received a response.
|
|||
|
||||
Environment input:
|
||||
|
||||
* handler = module()
|
||||
* handler_opts = any()
|
||||
handler = module():: Handler to be executed.
|
||||
handler_opts = any():: Options to be passed to the handler.
|
||||
|
||||
Environment output:
|
||||
|
||||
* result = ok
|
||||
result = ok:: Result of the request.
|
||||
|
||||
This module also defines the `cowboy_handler` behaviour that
|
||||
defines the basic interface for handlers. All Cowboy handlers
|
||||
implement at least the `init/2` callback, and may implement
|
||||
the `terminate/3` callback optionally.
|
||||
|
||||
:: Terminate reasons
|
||||
== Terminate reasons
|
||||
|
||||
The following values may be received as the terminate reason
|
||||
in the optional `terminate/3` callback. Different handler types
|
||||
may define additional terminate reasons.
|
||||
|
||||
: normal
|
||||
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
|
||||
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.
|
||||
=== init(Req, Opts) -> {ok, Req, State} | {Module, Req, State} | {Module, Req, State, hibernate | Timeout} | {Module, Req, State, Timeout, hibernate}
|
||||
|
||||
:: Callbacks
|
||||
|
||||
: init(Req, Opts)
|
||||
-> {ok, Req, State}
|
||||
| {Module, Req, State}
|
||||
| {Module, Req, State, hibernate}
|
||||
| {Module, Req, State, Timeout}
|
||||
| {Module, Req, State, Timeout, hibernate}
|
||||
|
||||
Types:
|
||||
|
||||
* Req = cowboy_req:req()
|
||||
* Opts = any()
|
||||
* State = any()
|
||||
* Module = module()
|
||||
* Timeout = timeout()
|
||||
Req = cowboy_req:req():: The Req object.
|
||||
Opts = any():: Handler options.
|
||||
State = any():: Handler state.
|
||||
Module = module():: Module of the sub-protocol to use.
|
||||
Timeout = timeout():: Timeout passed to the sub-protocol, when applicable.
|
||||
|
||||
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
|
||||
the value of `Opts` originally given to the `init/2` callback.
|
||||
|
||||
: terminate(Reason, Req, State) -> ok
|
||||
=== terminate(Reason, Req, State) -> ok
|
||||
|
||||
Types:
|
||||
|
||||
* Reason = any()
|
||||
* Req = cowboy_req:req()
|
||||
* State = any()
|
||||
Reason = any():: Reason for termination.
|
||||
Req = cowboy_req:req():: The Req object.
|
||||
State = any():: Handler 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
|
||||
of the process.
|
||||
|
||||
:: Exports
|
||||
== Exports
|
||||
|
||||
: terminate(Reason, Req, State, Handler) -> ok
|
||||
=== terminate(Reason, Req, State, Handler) -> ok
|
||||
|
||||
Types:
|
||||
|
||||
* Reason = any()
|
||||
* Req = cowboy_req:req()
|
||||
* State = any()
|
||||
* Handler = module()
|
||||
Reason = any():: Reason for termination.
|
||||
Req = cowboy_req:req():: The Req object.
|
||||
State = any():: Handler state.
|
||||
Handler = module():: Handler module.
|
||||
|
||||
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
|
||||
by Cowboy middleware modules.
|
||||
|
@ -6,9 +12,9 @@ by Cowboy middleware modules.
|
|||
Middlewares process the request sequentially in the order they
|
||||
are configured.
|
||||
|
||||
:: Types
|
||||
== Types
|
||||
|
||||
: env() = [{atom(), any()}]
|
||||
=== env() = [{atom(), any()}]
|
||||
|
||||
The environment variable.
|
||||
|
||||
|
@ -16,20 +22,15 @@ One is created for every request. It is passed to each
|
|||
middleware module executed and subsequently returned,
|
||||
optionally with its contents modified.
|
||||
|
||||
:: Callbacks
|
||||
== Callbacks
|
||||
|
||||
: execute(Req, Env)
|
||||
-> {ok, Req, Env}
|
||||
| {suspend, Module, Function, Args}
|
||||
| {stop, Req}
|
||||
=== execute(Req, Env) -> {ok, Req, Env} | {suspend, Module, Function, Args} | {stop, Req}
|
||||
|
||||
Types:
|
||||
|
||||
* Req = cowboy_req:req()
|
||||
* Env = env()
|
||||
* Module = module()
|
||||
* Function = atom()
|
||||
* Args = [any()]
|
||||
Req = cowboy_req:req():: The Req object.
|
||||
Env = env():: The request environment.
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
undefined behavior.
|
||||
|
||||
:: Types
|
||||
== Types
|
||||
|
||||
: body_opts() = [{continue, boolean()}
|
||||
=== body_opts() = [Option]
|
||||
|
||||
[source,erlang]
|
||||
----
|
||||
Option = {continue, boolean()}
|
||||
| {length, non_neg_integer()}
|
||||
| {read_length, non_neg_integer()}
|
||||
| {read_timeout, timeout()}
|
||||
| {transfer_decode, transfer_decode_fun(), any()}
|
||||
| {content_decode, content_decode_fun()}]
|
||||
| {content_decode, content_decode_fun()}
|
||||
----
|
||||
|
||||
Request body reading options.
|
||||
|
||||
: cookie_opts() = [{max_age, non_neg_integer()}
|
||||
| {domain, binary()} | {path, binary()}
|
||||
| {secure, boolean()} | {http_only, boolean()}]
|
||||
=== cookie_opts() = [Option]
|
||||
|
||||
[source,erlang]
|
||||
----
|
||||
Option = {max_age, non_neg_integer()}
|
||||
| {domain, binary()}
|
||||
| {path, binary()}
|
||||
| {secure, boolean()}
|
||||
| {http_only, boolean()}
|
||||
----
|
||||
|
||||
Cookie options.
|
||||
|
||||
: req() - opaque to the user
|
||||
=== req() - opaque to the user
|
||||
|
||||
The Req object.
|
||||
|
||||
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.
|
||||
|
||||
:: Request related exports
|
||||
== Request related exports
|
||||
|
||||
: binding(Name, Req) -> binding(Name, Req, undefined)
|
||||
: binding(Name, Req, Default) -> Value
|
||||
=== binding(Name, Req) -> binding(Name, Req, undefined)
|
||||
|
||||
Types:
|
||||
Alias of `cowboy_req:binding/3`.
|
||||
|
||||
* Name = atom()
|
||||
* Default = any()
|
||||
* Value = any() | Default
|
||||
=== binding(Name, Req, Default) -> Value
|
||||
|
||||
Name = atom():: Binding name.
|
||||
Default = any():: Default value.
|
||||
Value = any() | Default:: Binding value.
|
||||
|
||||
Return the value for the given binding.
|
||||
|
||||
|
@ -66,12 +85,10 @@ By default the value is a binary, however constraints may change
|
|||
the type of this value (for example automatically converting
|
||||
numbers to integer).
|
||||
|
||||
: bindings(Req) -> [{Name, Value}]
|
||||
=== bindings(Req) -> [{Name, Value}]
|
||||
|
||||
Types:
|
||||
|
||||
* Name = atom()
|
||||
* Value = any()
|
||||
Name = atom():: Binding name.
|
||||
Value = any():: Binding value.
|
||||
|
||||
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
|
||||
numbers to integer).
|
||||
|
||||
: header(Name, Req) -> header(Name, Req, undefined)
|
||||
: header(Name, Req, Default) -> Value
|
||||
=== header(Name, Req) -> header(Name, Req, undefined)
|
||||
|
||||
Types:
|
||||
Alias of `cowboy_req:header/3`.
|
||||
|
||||
* Name = binary()
|
||||
* Default = any()
|
||||
* Value = binary() | Default
|
||||
=== header(Name, Req, Default) -> Value
|
||||
|
||||
Name = binary():: Request header name.
|
||||
Default = any():: Default value.
|
||||
Value = binary() | Default:: Request header value.
|
||||
|
||||
Return the value for the given header.
|
||||
|
||||
While header names are case insensitive, this function expects
|
||||
the name to be a lowercase binary.
|
||||
|
||||
: headers(Req) -> Headers
|
||||
=== headers(Req) -> Headers
|
||||
|
||||
Types:
|
||||
|
||||
* Headers = cowboy:http_headers()
|
||||
Headers = cowboy:http_headers():: Request headers.
|
||||
|
||||
Return all headers.
|
||||
|
||||
: host(Req) -> Host
|
||||
=== host(Req) -> Host
|
||||
|
||||
Types:
|
||||
|
||||
* Host = binary()
|
||||
Host = binary():: Requested host.
|
||||
|
||||
Return the requested host.
|
||||
|
||||
: host_info(Req) -> HostInfo
|
||||
=== host_info(Req) -> HostInfo
|
||||
|
||||
Types:
|
||||
|
||||
* HostInfo = cowboy_router:tokens() | undefined
|
||||
HostInfo = cowboy_router:tokens() | undefined:: Extra tokens for the host.
|
||||
|
||||
Return the extra tokens from matching against `...` during routing.
|
||||
|
||||
: host_url(Req) -> HostURL
|
||||
=== host_url(Req) -> HostURL
|
||||
|
||||
Types:
|
||||
|
||||
* HostURL = binary() | undefined
|
||||
HostURL = binary() | undefined:: Requested URL, without the path component.
|
||||
|
||||
Return the requested URL excluding the path component.
|
||||
|
||||
This function will always return `undefined` until the
|
||||
`cowboy_router` middleware has been executed.
|
||||
|
||||
: match_cookies(Fields, Req) -> Map
|
||||
=== match_cookies(Fields, Req) -> Map
|
||||
|
||||
Types:
|
||||
|
||||
* Fields = cowboy:fields()
|
||||
* Map = map()
|
||||
Fields = cowboy:fields():: Cookie fields match rules.
|
||||
Map = map():: Cookie fields matched.
|
||||
|
||||
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
|
||||
in one step.
|
||||
|
||||
: match_qs(Fields, Req) -> Map
|
||||
=== match_qs(Fields, Req) -> Map
|
||||
|
||||
Types:
|
||||
|
||||
* Fields = cowboy:fields()
|
||||
* Map = map()
|
||||
Fields = cowboy:fields():: Query string fields match rules.
|
||||
Map = map():: Query string fields matched.
|
||||
|
||||
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
|
||||
to extract, validate and convert values all in one step.
|
||||
|
||||
: meta(Name, Req) -> meta(Name, Req, undefined)
|
||||
: meta(Name, Req, Default) -> Value
|
||||
=== meta(Name, Req) -> meta(Name, Req, undefined)
|
||||
|
||||
Types:
|
||||
Alias for `cowboy_req:meta/3`.
|
||||
|
||||
* Name = atom()
|
||||
* Default = any()
|
||||
* Value = any()
|
||||
=== meta(Name, Req, Default) -> Value
|
||||
|
||||
Name = atom():: Metadata name.
|
||||
Default = any():: Default value.
|
||||
Value = any():: Metadata value.
|
||||
|
||||
Return metadata about the request.
|
||||
|
||||
: method(Req) -> Method
|
||||
=== method(Req) -> Method
|
||||
|
||||
Types:
|
||||
|
||||
* Method = binary()
|
||||
Method = binary():: Request method.
|
||||
|
||||
Return the method.
|
||||
|
||||
Methods are case sensitive. Standard methods are always uppercase.
|
||||
|
||||
: parse_cookies(Req) -> [{Name, Value}]
|
||||
=== parse_cookies(Req) -> [{Name, Value}]
|
||||
|
||||
Types:
|
||||
|
||||
* Name = binary()
|
||||
* Value = binary()
|
||||
Name = binary():: Cookie name.
|
||||
Value = binary():: Cookie value.
|
||||
|
||||
Parse and return all cookies.
|
||||
|
||||
Cookie names are case sensitive.
|
||||
|
||||
: parse_header(Name, Req) -> see below
|
||||
: parse_header(Name, Req, Default) -> ParsedValue | Default
|
||||
=== parse_header(Name, Req) -> see below
|
||||
|
||||
Types:
|
||||
Alias of `cowboy_req:parse_header/3`.
|
||||
|
||||
* Name = binary()
|
||||
* Default = any()
|
||||
* ParsedValue - see below
|
||||
The `parse_header/2` function will call `parser_header/3` with a
|
||||
different default value depending on the header being parsed. The
|
||||
following table summarizes the default values used.
|
||||
|
||||
[cols="<,^",options="header"]
|
||||
|===
|
||||
| Header name | Header value
|
||||
| content-length | `0`
|
||||
| cookie | `[]`
|
||||
| transfer-encoding | `[<<"identity">>]`
|
||||
| Any other header | `undefined`
|
||||
|===
|
||||
|
||||
=== parse_header(Name, Req, Default) -> ParsedValue | Default
|
||||
|
||||
Name = binary():: Request header name.
|
||||
Default = any():: Default value.
|
||||
ParsedValue - see below:: Parsed request header value.
|
||||
|
||||
Parse the given header.
|
||||
|
||||
While header names are case insensitive, this function expects
|
||||
the name to be a lowercase binary.
|
||||
|
||||
The `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
|
||||
following table summarizes the different types returned.
|
||||
|
||||
|| Header name Type
|
||||
|
|
||||
| accept `[{{Type, SubType, Params}, Quality, AcceptExt}]`
|
||||
| accept-charset `[{Charset, Quality}]`
|
||||
| accept-encoding `[{Encoding, Quality}]`
|
||||
| accept-language `[{LanguageTag, Quality}]`
|
||||
| authorization `{AuthType, Credentials}`
|
||||
| content-length `non_neg_integer()`
|
||||
| content-type `{Type, SubType, ContentTypeParams}`
|
||||
| cookie `[{binary(), binary()}]`
|
||||
| expect `[Expect | {Expect, ExpectValue, Params}]`
|
||||
| if-match `'*' | [{weak | strong, OpaqueTag}]`
|
||||
| if-modified-since `calendar:datetime()`
|
||||
| if-none-match `'*' | [{weak | strong, OpaqueTag}]`
|
||||
| if-unmodified-since `calendar:datetime()`
|
||||
| range `{Unit, [Range]}`
|
||||
| sec-websocket-protocol `[binary()]`
|
||||
| transfer-encoding `[binary()]`
|
||||
| upgrade `[binary()]`
|
||||
| x-forwarded-for `[binary()]`
|
||||
[cols="<,^",options="header"]
|
||||
|===
|
||||
| Header name | Type of parsed header value
|
||||
| accept | `[{{Type, SubType, Params}, Quality, AcceptExt}]`
|
||||
| accept-charset | `[{Charset, Quality}]`
|
||||
| accept-encoding | `[{Encoding, Quality}]`
|
||||
| accept-language | `[{LanguageTag, Quality}]`
|
||||
| authorization | `{AuthType, Credentials}`
|
||||
| content-length | `non_neg_integer()`
|
||||
| content-type | `{Type, SubType, ContentTypeParams}`
|
||||
| cookie | `[{binary(), binary()}]`
|
||||
| expect | `[Expect \| {Expect, ExpectValue, Params}]`
|
||||
| if-match | `'*' \| [{weak \| strong, OpaqueTag}]`
|
||||
| if-modified-since | `calendar:datetime()`
|
||||
| if-none-match | `'*' \| [{weak \| strong, OpaqueTag}]`
|
||||
| if-unmodified-since | `calendar:datetime()`
|
||||
| range | `{Unit, [Range]}`
|
||||
| sec-websocket-protocol | `[binary()]`
|
||||
| transfer-encoding | `[binary()]`
|
||||
| upgrade | `[binary()]`
|
||||
| x-forwarded-for | `[binary()]`
|
||||
|===
|
||||
|
||||
Types for the above table:
|
||||
|
||||
|
@ -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
|
||||
to parse the requested header.
|
||||
|
||||
: parse_qs(Req) -> [{Name, Value}]
|
||||
=== parse_qs(Req) -> [{Name, Value}]
|
||||
|
||||
Types:
|
||||
|
||||
* Name = binary()
|
||||
* Value = binary() | true
|
||||
Name = binary():: Query string field name.
|
||||
Value = binary() | true:: Query string field value.
|
||||
|
||||
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
|
||||
of a value.
|
||||
|
||||
: path(Req) -> Path
|
||||
=== path(Req) -> Path
|
||||
|
||||
Types:
|
||||
|
||||
* Path = binary()
|
||||
Path = binary():: Requested path.
|
||||
|
||||
Return the requested path.
|
||||
|
||||
: path_info(Req) -> PathInfo
|
||||
=== path_info(Req) -> PathInfo
|
||||
|
||||
Types:
|
||||
|
||||
* PathInfo = cowboy_router:tokens() | undefined
|
||||
PathInfo = cowboy_router:tokens() | undefined:: Extra tokens for the path.
|
||||
|
||||
Return the extra tokens from matching against `...` during routing.
|
||||
|
||||
: peer(Req) -> Peer
|
||||
=== peer(Req) -> Peer
|
||||
|
||||
Types:
|
||||
|
||||
* Peer = {inet:ip_address(), inet:port_number()}
|
||||
Peer = {inet:ip_address(), inet:port_number()}:: Peer IP address and port number.
|
||||
|
||||
Return the client's IP address and port number.
|
||||
|
||||
: port(Req) -> Port
|
||||
=== port(Req) -> Port
|
||||
|
||||
Types:
|
||||
|
||||
* Port = inet:port_number()
|
||||
Port = inet:port_number():: Requested port number.
|
||||
|
||||
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 client used to connect to the Cowboy server.
|
||||
|
||||
: qs(Req) -> QueryString
|
||||
=== qs(Req) -> QueryString
|
||||
|
||||
Types:
|
||||
|
||||
* QueryString = binary()
|
||||
QueryString = binary():: Unprocessed query string.
|
||||
|
||||
Return the request's query string.
|
||||
|
||||
: set_meta(Name, Value, Req) -> Req2
|
||||
=== set_meta(Name, Value, Req) -> Req2
|
||||
|
||||
Types:
|
||||
|
||||
* Name = atom()
|
||||
* Value = any()
|
||||
Name = atom():: Metadata name.
|
||||
Value = any():: Metadata value.
|
||||
|
||||
Set metadata about the request.
|
||||
|
||||
An existing value will be overwritten.
|
||||
|
||||
: url(Req) -> URL
|
||||
=== url(Req) -> URL
|
||||
|
||||
Types:
|
||||
|
||||
* URL = binary() | undefined
|
||||
URL = binary() | undefined:: Requested URL.
|
||||
|
||||
Return the requested URL.
|
||||
|
||||
This function will always return `undefined` until the
|
||||
`cowboy_router` middleware has been executed.
|
||||
|
||||
: version(Req) -> Version
|
||||
=== version(Req) -> Version
|
||||
|
||||
Types:
|
||||
|
||||
* Version = cowboy:http_version()
|
||||
Version = cowboy:http_version():: Client's advertised HTTP version.
|
||||
|
||||
Return the HTTP version used for this request.
|
||||
|
||||
:: Request body related exports
|
||||
== Request body related exports
|
||||
|
||||
: body(Req) -> body(Req, [])
|
||||
: body(Req, Opts) -> {ok, Data, Req2} | {more, Data, Req2}
|
||||
=== body(Req) -> body(Req, [])
|
||||
|
||||
Types:
|
||||
Alias of `cowboy_req:body/2`.
|
||||
|
||||
* Opts = [body_opt()]
|
||||
* Data = binary()
|
||||
* Reason = atom()
|
||||
=== body(Req, Opts) -> {ok, Data, Req2} | {more, Data, Req2}
|
||||
|
||||
Opts = [body_opt()]:: Request body reading options.
|
||||
Data = binary():: Data read from the body.
|
||||
|
||||
Read the request body.
|
||||
|
||||
|
@ -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
|
||||
the result of this call.
|
||||
|
||||
: body_length(Req) -> Length
|
||||
=== body_length(Req) -> Length
|
||||
|
||||
Types:
|
||||
|
||||
* Length = non_neg_integer() | undefined
|
||||
Length = non_neg_integer() | undefined:: 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
|
||||
is present.
|
||||
|
||||
: body_qs(Req) -> body_qs(Req,
|
||||
[{length, 64000}, {read_length, 64000}, {read_timeout, 5000}])
|
||||
: body_qs(Req, Opts) -> {ok, [{Name, Value}], Req2} | {badlength, Req2}
|
||||
=== body_qs(Req) -> body_qs(Req, [{length, 64000}, {read_length, 64000}, {read_timeout, 5000}])
|
||||
|
||||
Types:
|
||||
Alias of `cowboy_req:body_qs/2`.
|
||||
|
||||
* Opts = [body_opt()]
|
||||
* Name = binary()
|
||||
* Value = binary() | true
|
||||
* Reason = chunked | badlength | atom()
|
||||
=== body_qs(Req, Opts) -> {ok, [{Name, Value}], Req2} | {badlength, Req2}
|
||||
|
||||
Opts = [body_opt()]:: Request body reading options.
|
||||
Name = binary():: Field name.
|
||||
Value = binary() | true:: Field value.
|
||||
|
||||
Return the request body as a list of tuples.
|
||||
|
||||
|
@ -459,18 +446,18 @@ body is larger then a `badlength` tuple is returned.
|
|||
This function can only be called once. Cowboy will not cache
|
||||
the result of this call.
|
||||
|
||||
: has_body(Req) -> boolean()
|
||||
=== has_body(Req) -> boolean()
|
||||
|
||||
Return whether the request has a body.
|
||||
|
||||
: part(Req) -> part(Req,
|
||||
[{length, 64000}, {read_length, 64000}, {read_timeout, 5000}])
|
||||
: part(Req, Opts) -> {ok, Headers, Req2} | {done, Req2}
|
||||
=== part(Req) -> part(Req, [{length, 64000}, {read_length, 64000}, {read_timeout, 5000}])
|
||||
|
||||
Types:
|
||||
Alias of `cowboy_req:part/2`.
|
||||
|
||||
* Opts = [body_opt()]
|
||||
* Headers = cow_multipart:headers()
|
||||
=== part(Req, Opts) -> {ok, Headers, Req2} | {done, Req2}
|
||||
|
||||
Opts = [body_opt()]:: Request body reading options.
|
||||
Headers = cow_multipart:headers():: Part's headers.
|
||||
|
||||
Read the headers for the next part of the multipart message.
|
||||
|
||||
|
@ -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.
|
||||
You might want to consider skipping large parts manually.
|
||||
|
||||
: part_body(Req) -> part_body(Req, [])
|
||||
: part_body(Req, Opts) -> {ok, Data, Req2} | {more, Data, Req2}
|
||||
=== part_body(Req) -> part_body(Req, [])
|
||||
|
||||
Types:
|
||||
Alias of `cowboy_req:part_body/2`.
|
||||
|
||||
* Opts = [body_opt()]
|
||||
* Data = binary()
|
||||
=== part_body(Req, Opts) -> {ok, Data, Req2} | {more, Data, Req2}
|
||||
|
||||
Opts = [body_opt()]:: Request body reading options.
|
||||
Data = binary():: Part's body.
|
||||
|
||||
Read the body of the current part of the multipart message.
|
||||
|
||||
|
@ -520,14 +508,11 @@ returned inside an `ok` tuple.
|
|||
Note that once the body has been read, fully or partially,
|
||||
it cannot be read again.
|
||||
|
||||
:: Response related exports
|
||||
== Response related exports
|
||||
|
||||
: chunk(Data, Req) -> ok
|
||||
=== chunk(Data, Req) -> ok
|
||||
|
||||
Types:
|
||||
|
||||
* Data = iodata()
|
||||
* Reason = atom()
|
||||
Data = iodata():: Chunk data to be sent.
|
||||
|
||||
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
|
||||
compatibility with older clients.
|
||||
|
||||
: chunked_reply(StatusCode, Req) -> chunked_reply(StatusCode, [], Req)
|
||||
: chunked_reply(StatusCode, Headers, Req) -> Req2
|
||||
=== chunked_reply(StatusCode, Req) -> chunked_reply(StatusCode, [], Req)
|
||||
|
||||
Types:
|
||||
Alias of `cowboy_req:chunked_reply/3`.
|
||||
|
||||
* StatusCode = cowboy:http_status()
|
||||
* Headers = cowboy:http_headers()
|
||||
=== chunked_reply(StatusCode, Headers, Req) -> Req2
|
||||
|
||||
StatusCode = cowboy:http_status():: Response status code.
|
||||
Headers = cowboy:http_headers():: Response headers.
|
||||
|
||||
Send a response using chunked transfer-encoding.
|
||||
|
||||
|
@ -564,11 +550,7 @@ compatibility with older clients.
|
|||
This function can only be called once, with the exception
|
||||
of overriding the response in the `onresponse` hook.
|
||||
|
||||
: continue(Req) -> ok
|
||||
|
||||
Types:
|
||||
|
||||
* Reason = atom()
|
||||
=== continue(Req) -> ok
|
||||
|
||||
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
|
||||
function.
|
||||
|
||||
: delete_resp_header(Name, Req) -> Req2
|
||||
=== delete_resp_header(Name, Req) -> Req2
|
||||
|
||||
Types:
|
||||
|
||||
* Name = binary()
|
||||
Name = binary():: Response header name.
|
||||
|
||||
Delete the given response header.
|
||||
|
||||
While header names are case insensitive, this function expects
|
||||
the name to be a lowercase binary.
|
||||
|
||||
: has_resp_body(Req) -> boolean()
|
||||
=== has_resp_body(Req) -> boolean()
|
||||
|
||||
Return whether a response body has been set.
|
||||
|
||||
This function will return false if a response body has
|
||||
been set with a length of 0.
|
||||
|
||||
: has_resp_header(Name, Req) -> boolean()
|
||||
=== has_resp_header(Name, Req) -> boolean()
|
||||
|
||||
Types:
|
||||
|
||||
* Name = binary()
|
||||
Name = binary():: Response header name.
|
||||
|
||||
Return whether the given response header has been set.
|
||||
|
||||
While header names are case insensitive, this function expects
|
||||
the name to be a lowercase binary.
|
||||
|
||||
: reply(StatusCode, Req) -> reply(StatusCode, [], Req)
|
||||
: reply(StatusCode, Headers, Req) - see below
|
||||
: reply(StatusCode, Headers, Body, Req) -> Req2
|
||||
=== reply(StatusCode, Req) -> reply(StatusCode, [], Req)
|
||||
|
||||
Types:
|
||||
Alias of `cowboy_req:reply/3`.
|
||||
|
||||
* StatusCode = cowboy:http_status()
|
||||
* Headers = cowboy:http_headers()
|
||||
* Body = iodata()
|
||||
=== reply(StatusCode, Headers, Req) - see below
|
||||
|
||||
Alias of `cowboy_req:reply/4`, with caveats.
|
||||
|
||||
=== reply(StatusCode, Headers, Body, Req) -> Req2
|
||||
|
||||
StatusCode = cowboy:http_status():: Response status code.
|
||||
Headers = cowboy:http_headers():: Response headers.
|
||||
Body = iodata():: Response body.
|
||||
|
||||
Send a response.
|
||||
|
||||
|
@ -639,26 +621,25 @@ returns.
|
|||
This function can only be called once, with the exception
|
||||
of overriding the response in the `onresponse` hook.
|
||||
|
||||
: set_resp_body(Body, Req) -> Req2
|
||||
=== set_resp_body(Body, Req) -> Req2
|
||||
|
||||
Types:
|
||||
|
||||
* Body = iodata()
|
||||
Body = iodata():: Response body.
|
||||
|
||||
Set a response body.
|
||||
|
||||
This body will not be sent if `chunked_reply/{2,3}` or
|
||||
`reply/4` is used, as they override it.
|
||||
|
||||
: set_resp_body_fun(Fun, Req) -> Req2
|
||||
: set_resp_body_fun(Length, Fun, Req) -> Req2
|
||||
=== set_resp_body_fun(Fun, Req) -> Req2
|
||||
|
||||
Types:
|
||||
Alias of `cowboy_req:set_resp_body_fun/3`.
|
||||
|
||||
* Fun = fun((Socket, Transport) -> ok)
|
||||
* Socket = inet:socket()
|
||||
* Transport = module()
|
||||
* Length = non_neg_integer()
|
||||
=== set_resp_body_fun(Length, Fun, Req) -> Req2
|
||||
|
||||
Fun = fun((Socket, Transport) -> ok):: Fun that will send the response body.
|
||||
Socket = inet:socket():: Socket for this connection.
|
||||
Transport = module():: Transport module for this socket.
|
||||
Length = non_neg_integer():: Length of the response body.
|
||||
|
||||
Set a fun for sending the response body.
|
||||
|
||||
|
@ -673,12 +654,10 @@ using the `reply/2` or `reply/3` function.
|
|||
The fun will receive the Ranch `Socket` and `Transport` as
|
||||
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)
|
||||
* ChunkFun = fun((iodata()) -> ok)
|
||||
Fun = fun((ChunkFun) -> ok):: Fun that will send the response body.
|
||||
ChunkFun = fun((iodata()) -> ok):: Fun to call for every chunk to be sent.
|
||||
|
||||
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
|
||||
the chunk.
|
||||
|
||||
: set_resp_cookie(Name, Value, Opts, Req) -> Req2
|
||||
=== set_resp_cookie(Name, Value, Opts, Req) -> Req2
|
||||
|
||||
Types:
|
||||
|
||||
* Name = iodata()
|
||||
* Value = iodata()
|
||||
* Opts = cookie_opts()
|
||||
Name = iodata():: Cookie name.
|
||||
Value = iodata():: Cookie value.
|
||||
Opts = cookie_opts():: Cookie options.
|
||||
|
||||
Set a cookie in the response.
|
||||
|
||||
Cookie names are case sensitive.
|
||||
|
||||
: set_resp_header(Name, Value, Req) -> Req2
|
||||
=== set_resp_header(Name, Value, Req) -> Req2
|
||||
|
||||
Types:
|
||||
|
||||
* Name = binary()
|
||||
* Value = iodata()
|
||||
Name = binary():: Response header name.
|
||||
Value = iodata():: Response header value.
|
||||
|
||||
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 HTTP protocol.
|
||||
|
@ -6,66 +12,53 @@ the HTTP protocol.
|
|||
This module is a sub protocol that defines many callbacks
|
||||
be implemented by handlers. The `init/2` and `terminate/3`
|
||||
callbacks are common to all handler types and are documented
|
||||
in the manual for the ^cowboy_handler module.
|
||||
in the manual for the link:cowboy_handler.asciidoc[cowboy_handler] module.
|
||||
|
||||
All other callbacks are optional, though some may become
|
||||
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.
|
||||
|
||||
: 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
|
||||
== Terminate reasons
|
||||
|
||||
The following values may be received as the terminate reason
|
||||
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
|
||||
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.
|
||||
=== Callback(Req, State) -> {Value, Req, State} | {stop, Req, State}
|
||||
|
||||
:: Callbacks
|
||||
|
||||
: Callback(Req, State) -> {Value, Req, State} | {stop, Req, State}
|
||||
|
||||
Types:
|
||||
|
||||
* Callback - one of the REST callbacks described below
|
||||
* Req = cowboy_req:req()
|
||||
* State = any()
|
||||
* Value - see the REST callbacks description below
|
||||
Callback:: One of the REST callbacks described below.
|
||||
Req = cowboy_req:req():: The Req object.
|
||||
State = any():: Handler state.
|
||||
Value:: See the REST callbacks description below.
|
||||
|
||||
Please see the REST callbacks description below for details
|
||||
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,
|
||||
otherwise a `204 No Content` will be sent.
|
||||
|
||||
:: REST callbacks description
|
||||
== REST callbacks description
|
||||
|
||||
: allowed_methods
|
||||
=== allowed_methods
|
||||
|
||||
* Methods: all
|
||||
* Value type: [binary()]
|
||||
* Default value: [<<"GET">>, <<"HEAD">>, <<"OPTIONS">>]
|
||||
Methods:: all
|
||||
Value type:: [binary()]
|
||||
Default value:: `[<<"GET">>, <<"HEAD">>, <<"OPTIONS">>]`
|
||||
|
||||
Return the list of allowed methods.
|
||||
|
||||
Methods are case sensitive. Standard methods are always uppercase.
|
||||
|
||||
: allow_missing_post
|
||||
=== allow_missing_post
|
||||
|
||||
* Methods: POST
|
||||
* Value type: boolean()
|
||||
* Default value: true
|
||||
Methods:: POST
|
||||
Value type:: boolean()
|
||||
Default value:: true
|
||||
|
||||
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
|
||||
returned from the `AcceptResource` callback.
|
||||
|
||||
: charsets_provided
|
||||
=== charsets_provided
|
||||
|
||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
* Value type: [binary()]
|
||||
* Skip to the next step if undefined
|
||||
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
Value type:: [binary()]
|
||||
Default behavior:: Skip to the next step if undefined.
|
||||
|
||||
Return the list of charsets the resource provides.
|
||||
|
||||
|
@ -120,14 +113,14 @@ value `charset`.
|
|||
While charsets are case insensitive, this callback is expected
|
||||
to return them as lowercase binary.
|
||||
|
||||
: content_types_accepted
|
||||
=== content_types_accepted
|
||||
|
||||
* Methods: POST, PUT, PATCH
|
||||
* No default
|
||||
Methods:: POST, PUT, PATCH
|
||||
Value type:: [{binary() | {Type, SubType, Params}, AcceptResource}]
|
||||
Default behavior:: Crash if undefined.
|
||||
|
||||
Types:
|
||||
With types:
|
||||
|
||||
* Value = [{binary() | {Type, SubType, Params}, AcceptResource}]
|
||||
* Type = SubType = binary()
|
||||
* Params = '*' | [{binary(), binary()}]
|
||||
* AcceptResource = atom()
|
||||
|
@ -155,8 +148,8 @@ different list for each methods.
|
|||
The `AcceptResource` value is the name of the callback that will
|
||||
be called if the content-type matches. It is defined as follow.
|
||||
|
||||
* Value type: true | {true, URL} | false
|
||||
* No default
|
||||
Value type:: true | {true, URL} | false
|
||||
Default behavior:: Crash if undefined.
|
||||
|
||||
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`
|
||||
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
|
||||
* Default value: [{{<<"text">>, <<"html">>, '*'}, to_html}]
|
||||
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
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()
|
||||
* Params = '*' | [{binary(), binary()}]
|
||||
* 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
|
||||
as follow.
|
||||
|
||||
* Methods: GET, HEAD
|
||||
* Value type: iodata() | {stream, Fun} | {stream, Len, Fun} | {chunked, ChunkedFun}
|
||||
* No default
|
||||
Methods:: GET, HEAD
|
||||
Value type:: iodata() | {stream, Fun} | {stream, Len, Fun} | {chunked, ChunkedFun}
|
||||
Default behavior:: Crash if undefined.
|
||||
|
||||
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
|
||||
the response body.
|
||||
|
||||
: delete_completed
|
||||
=== delete_completed
|
||||
|
||||
* Methods: DELETE
|
||||
* Value type: boolean()
|
||||
* Default value: true
|
||||
Methods:: DELETE
|
||||
Value type:: boolean()
|
||||
Default value:: true
|
||||
|
||||
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`
|
||||
response will be sent instead of a `200 OK` or `204 No Content`.
|
||||
|
||||
: delete_resource
|
||||
=== delete_resource
|
||||
|
||||
* Methods: DELETE
|
||||
* Value type: boolean()
|
||||
* Default value: false
|
||||
Methods:: DELETE
|
||||
Value type:: boolean()
|
||||
Default value:: false
|
||||
|
||||
Delete the resource.
|
||||
|
||||
|
@ -247,21 +240,21 @@ The value returned indicates if the action was successful,
|
|||
regardless of whether the resource is immediately deleted
|
||||
from the system.
|
||||
|
||||
: expires
|
||||
=== expires
|
||||
|
||||
* Methods: GET, HEAD
|
||||
* Value type: calendar:datetime() | binary() | undefined
|
||||
* Default value: undefined
|
||||
Methods:: GET, HEAD
|
||||
Value type:: calendar:datetime() | binary() | undefined
|
||||
Default value:: undefined
|
||||
|
||||
Return the date of expiration of the resource.
|
||||
|
||||
This date will be sent as the value of the expires header.
|
||||
|
||||
: forbidden
|
||||
=== forbidden
|
||||
|
||||
* Methods: all
|
||||
* Value type: boolean()
|
||||
* Default value: false
|
||||
Methods:: all
|
||||
Value type:: boolean()
|
||||
Default value:: false
|
||||
|
||||
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,
|
||||
and that the request shouldn't be repeated.
|
||||
|
||||
: generate_etag
|
||||
=== generate_etag
|
||||
|
||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
* Value type: binary() | {weak | strong, binary()}
|
||||
* Default value: undefined
|
||||
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
Value type:: binary() | {weak | strong, binary()}
|
||||
Default value:: undefined
|
||||
|
||||
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
|
||||
the same format as the etag header, including quotes.
|
||||
|
||||
: is_authorized
|
||||
=== is_authorized
|
||||
|
||||
* Methods: all
|
||||
* Value type: true | {false, AuthHeader}
|
||||
* Default value: true
|
||||
Methods:: all
|
||||
Value type:: true | {false, AuthHeader}
|
||||
Default value:: true
|
||||
|
||||
Types:
|
||||
With types:
|
||||
|
||||
* 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
|
||||
`401 Unauthorized` response.
|
||||
|
||||
: is_conflict
|
||||
=== is_conflict
|
||||
|
||||
* Methods: PUT
|
||||
* Value type: boolean()
|
||||
* Default value: false
|
||||
Methods:: PUT
|
||||
Value type:: boolean()
|
||||
Default value:: false
|
||||
|
||||
Return whether the put action results in a conflict.
|
||||
|
||||
A `409 Conflict` response will be sent if this function
|
||||
returns `true`.
|
||||
|
||||
: known_methods
|
||||
=== known_methods
|
||||
|
||||
* Methods: all
|
||||
* Value type: [binary()]
|
||||
* Default value: [<<"GET">>, <<"HEAD">>, <<"POST">>, <<"PUT">>, <<"PATCH">>, <<"DELETE">>, <<"OPTIONS">>]
|
||||
Methods:: all
|
||||
Value type:: [binary()]
|
||||
Default value:: `[<<"GET">>, <<"HEAD">>, <<"POST">>, <<"PUT">>, <<"PATCH">>, <<"DELETE">>, <<"OPTIONS">>]`
|
||||
|
||||
Return the list of known methods.
|
||||
|
||||
|
@ -331,11 +324,11 @@ implement in `cowboy_rest`.
|
|||
|
||||
Methods are case sensitive. Standard methods are always uppercase.
|
||||
|
||||
: languages_provided
|
||||
=== languages_provided
|
||||
|
||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
* Value type: [binary()]
|
||||
* Skip to the next step if undefined
|
||||
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
Value type:: [binary()]
|
||||
Default behavior:: Skip to the next step if undefined.
|
||||
|
||||
Return the list of languages the resource provides.
|
||||
|
||||
|
@ -351,11 +344,11 @@ value `language`.
|
|||
While languages are case insensitive, this callback is expected
|
||||
to return them as lowercase binary.
|
||||
|
||||
: last_modified
|
||||
=== last_modified
|
||||
|
||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
* Value type: calendar:datetime()
|
||||
* Default value: undefined
|
||||
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
Value type:: calendar:datetime()
|
||||
Default value:: undefined
|
||||
|
||||
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
|
||||
header in the response of GET and HEAD requests.
|
||||
|
||||
: malformed_request
|
||||
=== malformed_request
|
||||
|
||||
* Methods: all
|
||||
* Value type: boolean()
|
||||
* Default value: false
|
||||
Methods:: all
|
||||
Value type:: boolean()
|
||||
Default value:: false
|
||||
|
||||
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 request body, which is processed later.
|
||||
|
||||
: moved_permanently
|
||||
=== moved_permanently
|
||||
|
||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
* Value type: {true, URL} | false
|
||||
* Default value: false
|
||||
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
Value type:: {true, URL} | false
|
||||
Default value:: false
|
||||
|
||||
Types:
|
||||
With types:
|
||||
|
||||
* 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
|
||||
location header in the response.
|
||||
|
||||
: moved_temporarily
|
||||
=== moved_temporarily
|
||||
|
||||
* Methods: GET, HEAD, POST, PATCH, DELETE
|
||||
* Value type: {true, URL} | false
|
||||
* Default value: false
|
||||
Methods:: GET, HEAD, POST, PATCH, DELETE
|
||||
Value type:: {true, URL} | false
|
||||
Default value:: false
|
||||
|
||||
Types:
|
||||
With types:
|
||||
|
||||
* 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
|
||||
location header in the response.
|
||||
|
||||
: multiple_choices
|
||||
=== multiple_choices
|
||||
|
||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
* Value type: boolean()
|
||||
* Default value: false
|
||||
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
Value type:: boolean()
|
||||
Default value:: false
|
||||
|
||||
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
|
||||
`cowboy_req:meta(media_type, Req)`.
|
||||
|
||||
: options
|
||||
=== options
|
||||
|
||||
* Methods: OPTIONS
|
||||
* Value type: ok
|
||||
* Default value: ok
|
||||
Methods:: OPTIONS
|
||||
Value type:: ok
|
||||
Default value:: ok
|
||||
|
||||
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
|
||||
allow header set.
|
||||
|
||||
: previously_existed
|
||||
=== previously_existed
|
||||
|
||||
* Methods: GET, HEAD, POST, PATCH, DELETE
|
||||
* Value type: boolean()
|
||||
* Default value: false
|
||||
Methods:: GET, HEAD, POST, PATCH, DELETE
|
||||
Value type:: boolean()
|
||||
Default value:: false
|
||||
|
||||
Return whether the resource existed previously.
|
||||
|
||||
: resource_exists
|
||||
=== resource_exists
|
||||
|
||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
* Value type: boolean()
|
||||
* Default value: true
|
||||
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
Value type:: boolean()
|
||||
Default value:: true
|
||||
|
||||
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
|
||||
check if the resource previously existed first.
|
||||
|
||||
: service_available
|
||||
=== service_available
|
||||
|
||||
* Methods: all
|
||||
* Value type: boolean()
|
||||
* Default value: true
|
||||
Methods:: all
|
||||
Value type:: boolean()
|
||||
Default value:: true
|
||||
|
||||
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
|
||||
function returns `false`.
|
||||
|
||||
: uri_too_long
|
||||
=== uri_too_long
|
||||
|
||||
* Methods: all
|
||||
* Value type: boolean()
|
||||
* Default value: false
|
||||
Methods:: all
|
||||
Value type:: boolean()
|
||||
Default value:: false
|
||||
|
||||
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
|
||||
function returns `true`.
|
||||
|
||||
: valid_content_headers
|
||||
=== valid_content_headers
|
||||
|
||||
* Methods: all
|
||||
* Value type: boolean()
|
||||
* Default value: true
|
||||
Methods:: all
|
||||
Value type:: boolean()
|
||||
Default value:: true
|
||||
|
||||
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
|
||||
function returns `false`.
|
||||
|
||||
: valid_entity_length
|
||||
=== valid_entity_length
|
||||
|
||||
* Methods: all
|
||||
* Value type: boolean()
|
||||
* Default value: true
|
||||
Methods:: all
|
||||
Value type:: boolean()
|
||||
Default value:: true
|
||||
|
||||
Return whether the request body length is within acceptable boundaries.
|
||||
|
||||
A `413 Request Entity Too Large` response will be sent if this
|
||||
function returns `false`.
|
||||
|
||||
: variances
|
||||
=== variances
|
||||
|
||||
* Methods: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
* Value type: [binary()]
|
||||
* Default value: []
|
||||
Methods:: GET, HEAD, POST, PUT, PATCH, DELETE
|
||||
Value type:: [binary()]
|
||||
Default value:: []
|
||||
|
||||
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
|
||||
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` and `handler_opts` respectively.
|
||||
|
||||
Environment input:
|
||||
=== Environment input
|
||||
|
||||
* dispatch = dispatch_rules()
|
||||
dispatch = dispatch_rules():: Dispatch table.
|
||||
|
||||
Environment output:
|
||||
=== Environment output
|
||||
|
||||
* handler = module()
|
||||
* handler_opts = any()
|
||||
handler = module():: Handler module.
|
||||
handler_opts = any():: Handler options.
|
||||
|
||||
:: Types
|
||||
== Types
|
||||
|
||||
: bindings() = [{atom(), binary()}]
|
||||
=== bindings() = [{atom(), binary()}]
|
||||
|
||||
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.
|
||||
|
||||
: routes() = [{Host, Paths} | {Host, cowboy:fields(), Paths}]
|
||||
=== routes() = [{Host, Paths} | {Host, cowboy:fields(), Paths}]
|
||||
|
||||
Types:
|
||||
With types:
|
||||
|
||||
* Host = Path = '_' | iodata()
|
||||
* Paths = [{Path, Handler, Opts} | {Path, cowboy:fields(), Handler, Opts}]
|
||||
* Paths = [{Path, Handler, Opts} | {Path, cowboy:fields(), Handler, HandlerOpts}]
|
||||
* Handler = module()
|
||||
* Opts = any()
|
||||
* HandlerOpts = any()
|
||||
|
||||
Human readable list of routes mapping hosts and paths to handlers.
|
||||
|
||||
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.
|
||||
|
||||
:: Exports
|
||||
== Exports
|
||||
|
||||
: compile(Routes) -> Dispatch
|
||||
|
||||
Types:
|
||||
|
||||
* Routes = routes()
|
||||
* Dispatch = dispatch_rules()
|
||||
=== compile(routes()) -> dispatch_rules()
|
||||
|
||||
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.
|
||||
|
||||
This module is a sub protocol that defines four callbacks to
|
||||
be implemented by handlers. The `init/2` and `terminate/3`
|
||||
callbacks are common to all handler types and are documented
|
||||
in the manual for the ^cowboy_handler module.
|
||||
in the manual for the link:cowboy_handler.asciidoc[cowboy_handler] module.
|
||||
|
||||
The `websocket_handle/3` and `websocket_info/3` callbacks are
|
||||
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
|
||||
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.
|
||||
|
||||
: websocket_version
|
||||
|
||||
Type: 7 | 8 | 13
|
||||
|
||||
The version of the Websocket protocol being used.
|
||||
|
||||
:: Terminate reasons
|
||||
== Terminate reasons
|
||||
|
||||
The following values may be received as the terminate reason
|
||||
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
|
||||
connection. This typically happens if an `ok` tuple is returned
|
||||
from the `init/2` callback.
|
||||
remote::
|
||||
The remote endpoint closed the connection without giving any
|
||||
further details.
|
||||
|
||||
: remote
|
||||
{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
|
||||
further details.
|
||||
stop::
|
||||
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
|
||||
`Code` and `Payload` as the reason.
|
||||
{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.
|
||||
|
||||
: 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
|
||||
a `stop` tuple or by sending a `close` frame.
|
||||
{error, badframe}::
|
||||
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
|
||||
value can be configured from `init/2`.
|
||||
{error, Reason}::
|
||||
A socket error ocurred.
|
||||
|
||||
: {crash, Class, Reason}
|
||||
== Callbacks
|
||||
|
||||
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.
|
||||
=== websocket_handle(InFrame, Req, State) -> Ret
|
||||
|
||||
: {error, badencoding}
|
||||
|
||||
A text frame was sent by the client with invalid encoding. All
|
||||
text frames must be valid UTF-8.
|
||||
|
||||
: {error, badframe}
|
||||
|
||||
A protocol error has been detected.
|
||||
|
||||
: {error, closed}
|
||||
|
||||
The socket has been closed brutally without a close frame being
|
||||
received first.
|
||||
|
||||
: {error, Reason}
|
||||
|
||||
A socket error ocurred.
|
||||
|
||||
:: Callbacks
|
||||
|
||||
: websocket_handle(InFrame, Req, State)
|
||||
-> {ok, Req, State}
|
||||
[source,erlang]
|
||||
----
|
||||
Ret = {ok, Req, State}
|
||||
| {ok, Req, State, hibernate}
|
||||
| {reply, OutFrame | [OutFrame], Req, State}
|
||||
| {reply, OutFrame | [OutFrame], Req, State, hibernate}
|
||||
| {stop, Req, State}
|
||||
|
||||
Types:
|
||||
|
||||
* InFrame = {text | binary | ping | pong, binary()}
|
||||
* Req = cowboy_req:req()
|
||||
* State = any()
|
||||
* OutFrame = cow_ws:frame()
|
||||
InFrame = {text | binary | ping | pong, binary()}
|
||||
Req = cowboy_req:req()
|
||||
State = any()
|
||||
OutFrame = cow_ws:frame()
|
||||
----
|
||||
|
||||
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
|
||||
Erlang message.
|
||||
|
||||
: websocket_info(Info, Req, State)
|
||||
-> {ok, Req, State}
|
||||
=== websocket_info(Info, Req, State) -> Ret
|
||||
|
||||
[source,erlang]
|
||||
----
|
||||
Ret = {ok, Req, State}
|
||||
| {ok, Req, State, hibernate}
|
||||
| {reply, OutFrame | [OutFrame], Req, State}
|
||||
| {reply, OutFrame | [OutFrame], Req, State, hibernate}
|
||||
| {stop, Req, State}
|
||||
|
||||
Types:
|
||||
|
||||
* Info = any()
|
||||
* Req = cowboy_req:req()
|
||||
* State = any()
|
||||
* OutFrame = cow_ws:frame()
|
||||
Info = any()
|
||||
Req = cowboy_req:req()
|
||||
State = any()
|
||||
OutFrame = cow_ws:frame()
|
||||
----
|
||||
|
||||
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
|
||||
may return, with details on the reasons why. The list given
|
||||
here only includes the replies that Cowboy sends, not user
|
||||
replies.
|
||||
|
||||
: 100 Continue
|
||||
== 100 Continue
|
||||
|
||||
When the client sends an `expect: 100-continue` header,
|
||||
Cowboy automatically sends a this status code before
|
||||
trying to read the request body. This behavior can be
|
||||
disabled using the appropriate body option.
|
||||
|
||||
: 101 Switching Protocols
|
||||
== 101 Switching Protocols
|
||||
|
||||
This is the status code sent when switching to the
|
||||
Websocket protocol.
|
||||
|
||||
: 200 OK
|
||||
== 200 OK
|
||||
|
||||
This status code is sent by `cowboy_rest`.
|
||||
|
||||
: 201 Created
|
||||
== 201 Created
|
||||
|
||||
This status code is sent by `cowboy_rest`.
|
||||
|
||||
: 202 Accepted
|
||||
== 202 Accepted
|
||||
|
||||
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
|
||||
ends without any reply having been sent. It may also be
|
||||
sent by `cowboy_rest` under normal conditions.
|
||||
|
||||
: 300 Multiple Choices
|
||||
== 300 Multiple Choices
|
||||
|
||||
This status code is sent by `cowboy_rest`.
|
||||
|
||||
: 301 Moved Permanently
|
||||
== 301 Moved Permanently
|
||||
|
||||
This status code is sent by `cowboy_rest`.
|
||||
|
||||
: 303 See Other
|
||||
== 303 See Other
|
||||
|
||||
This status code is sent by `cowboy_rest`.
|
||||
|
||||
: 304 Not Modified
|
||||
== 304 Not Modified
|
||||
|
||||
This status code is sent by `cowboy_rest`.
|
||||
|
||||
: 307 Temporary Redirect
|
||||
== 307 Temporary Redirect
|
||||
|
||||
This status code is sent by `cowboy_rest`.
|
||||
|
||||
: 400 Bad Request
|
||||
== 400 Bad Request
|
||||
|
||||
Cowboy will send this status code for any of the
|
||||
following reasons:
|
||||
|
@ -73,78 +79,78 @@ following reasons:
|
|||
* REST under normal conditions.
|
||||
* A Websocket upgrade failed.
|
||||
|
||||
: 401 Unauthorized
|
||||
== 401 Unauthorized
|
||||
|
||||
This status code is sent by `cowboy_rest`.
|
||||
|
||||
: 403 Forbidden
|
||||
== 403 Forbidden
|
||||
|
||||
This status code is sent by `cowboy_rest`.
|
||||
|
||||
: 404 Not Found
|
||||
== 404 Not Found
|
||||
|
||||
This status code is sent when the router successfully
|
||||
resolved the host but didn't find a matching path for
|
||||
the request. It may also be sent by `cowboy_rest` under
|
||||
normal conditions.
|
||||
|
||||
: 405 Method Not Allowed
|
||||
== 405 Method Not Allowed
|
||||
|
||||
This status code is sent by `cowboy_rest`.
|
||||
|
||||
: 406 Not Acceptable
|
||||
== 406 Not Acceptable
|
||||
|
||||
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
|
||||
client started to send a request, indicated by the
|
||||
request-line being received fully, but failed to send
|
||||
all headers in a reasonable time.
|
||||
|
||||
: 409 Conflict
|
||||
== 409 Conflict
|
||||
|
||||
This status code is sent by `cowboy_rest`.
|
||||
|
||||
: 410 Gone
|
||||
== 410 Gone
|
||||
|
||||
This status code is sent by `cowboy_rest`.
|
||||
|
||||
: 412 Precondition Failed
|
||||
== 412 Precondition Failed
|
||||
|
||||
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`.
|
||||
|
||||
: 414 Request-URI Too Long
|
||||
== 414 Request-URI Too Long
|
||||
|
||||
Cowboy will send this status code to the client if the
|
||||
request-line is too long. It may also be sent by
|
||||
`cowboy_rest` under normal conditions.
|
||||
|
||||
: 415 Unsupported Media Type
|
||||
== 415 Unsupported Media Type
|
||||
|
||||
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
|
||||
or REST handlers, or when an invalid return value is
|
||||
returned. It may also be sent by `cowboy_rest` under
|
||||
normal conditions.
|
||||
|
||||
: 501 Not Implemented
|
||||
== 501 Not Implemented
|
||||
|
||||
This status code is sent by `cowboy_rest`.
|
||||
|
||||
: 503 Service Unavailable
|
||||
== 503 Service Unavailable
|
||||
|
||||
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.
|
||||
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