diff options
author | Loïc Hoguin <[email protected]> | 2017-12-11 11:27:17 +0100 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2017-12-11 11:27:17 +0100 |
commit | 1b863c350ba1f9b8ad1cb458df514ab0fe6bb127 (patch) | |
tree | f3f88acba06cce7095a047da8163ac0f92b1a64a /docs/en/cowboy/2.2/guide | |
parent | 35825f89b61579d4270d6970609047945277acf7 (diff) | |
download | ninenines.eu-1b863c350ba1f9b8ad1cb458df514ab0fe6bb127.tar.gz ninenines.eu-1b863c350ba1f9b8ad1cb458df514ab0fe6bb127.tar.bz2 ninenines.eu-1b863c350ba1f9b8ad1cb458df514ab0fe6bb127.zip |
Add documentation for Cowboy 2.2
Diffstat (limited to 'docs/en/cowboy/2.2/guide')
74 files changed, 26262 insertions, 0 deletions
diff --git a/docs/en/cowboy/2.2/guide/constraints.asciidoc b/docs/en/cowboy/2.2/guide/constraints.asciidoc new file mode 100644 index 00000000..6cc10752 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/constraints.asciidoc @@ -0,0 +1,123 @@ +[[constraints]] +== Constraints + +Constraints are validation and conversion functions applied +to user input. + +They are used in various places in Cowboy, including the +router and the `cowboy_req` match functions. + +=== Syntax + +Constraints are provided as a list of fields. For each field +in the list, specific constraints can be applied, as well as +a default value if the field is missing. + +A field can take the form of an atom `field`, a tuple with +constraints `{field, Constraints}` or a tuple with constraints +and a default value `{field, Constraints, Default}`. +The `field` form indicates the field is mandatory. + +Note that when used with the router, only the second form +makes sense, as it does not use the default and the field +is always defined. + +Constraints for each field are provided as an ordered list +of atoms or funs to apply. Built-in constraints are provided +as atoms, while custom constraints are provided as funs. + +When multiple constraints are provided, they are applied in +the order given. If the value has been modified by a constraint +then the next one receives the new value. + +For example, the following constraints will first validate +and convert the field `my_value` to an integer, and then +check that the integer is positive: + +[source,erlang] +---- +PositiveFun = fun + (_, V) when V > 0 -> + {ok, V}; + (_, _) -> + {error, not_positive} +end, +{my_value, [int, PositiveFun]}. +---- + +We ignore the first fun argument in this snippet. We shouldn't. +We will simply learn what it is later in this chapter. + +When there's only one constraint, it can be provided directly +without wrapping it into a list: + +[source,erlang] +---- +{my_value, int} +---- + +=== Built-in constraints + +Built-in constraints are specified as an atom: + +[cols="<,<",options="header"] +|=== +| Constraint | Description +| int | Converts binary value to integer. +| nonempty | Ensures the binary value is non-empty. +|=== + +=== Custom constraints + +Custom constraints are specified as a fun. This fun takes +two arguments. The first argument indicates the operation +to be performed, and the second is the value. What the +value is and what must be returned depends on the operation. + +Cowboy currently defines three operations. The operation +used for validating and converting user input is the `forward` +operation. + +[source,erlang] +---- +int(forward, Value) -> + try + {ok, binary_to_integer(Value)} + catch _:_ -> + {error, not_an_integer} + end; +---- + +The value must be returned even if it is not converted +by the constraint. + +The `reverse` operation does the opposite: it +takes a converted value and changes it back to what the +user input would have been. + +[source,erlang] +---- +int(reverse, Value) -> + try + {ok, integer_to_binary(Value)} + catch _:_ -> + {error, not_an_integer} + end; +---- + +Finally, the `format_error` operation takes an error +returned by any other operation and returns a formatted +human-readable error message. + +[source,erlang] +---- +int(format_error, {not_an_integer, Value}) -> + io_lib:format("The value ~p is not an integer.", [Value]). +---- + +Notice that for this case you get both the error and +the value that was given to the constraint that produced +this error. + +Cowboy will not catch exceptions coming from constraint +functions. They should be written to not emit any exceptions. diff --git a/docs/en/cowboy/2.2/guide/constraints/index.html b/docs/en/cowboy/2.2/guide/constraints/index.html new file mode 100644 index 00000000..81865da6 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/constraints/index.html @@ -0,0 +1,300 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Constraints</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Constraints</span></h1> + +<div class="paragraph"><p>Constraints are validation and conversion functions applied +to user input.</p></div> +<div class="paragraph"><p>They are used in various places in Cowboy, including the +router and the <code>cowboy_req</code> match functions.</p></div> +<div class="sect1"> +<h2 id="_syntax">Syntax</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Constraints are provided as a list of fields. For each field +in the list, specific constraints can be applied, as well as +a default value if the field is missing.</p></div> +<div class="paragraph"><p>A field can take the form of an atom <code>field</code>, a tuple with +constraints <code>{field, Constraints}</code> or a tuple with constraints +and a default value <code>{field, Constraints, Default}</code>. +The <code>field</code> form indicates the field is mandatory.</p></div> +<div class="paragraph"><p>Note that when used with the router, only the second form +makes sense, as it does not use the default and the field +is always defined.</p></div> +<div class="paragraph"><p>Constraints for each field are provided as an ordered list +of atoms or funs to apply. Built-in constraints are provided +as atoms, while custom constraints are provided as funs.</p></div> +<div class="paragraph"><p>When multiple constraints are provided, they are applied in +the order given. If the value has been modified by a constraint +then the next one receives the new value.</p></div> +<div class="paragraph"><p>For example, the following constraints will first validate +and convert the field <code>my_value</code> to an integer, and then +check that the integer is positive:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">PositiveFun</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">fun</span></span> + (<span style="color: #990000">_</span>, <span style="color: #009900">V</span>) <span style="font-weight: bold"><span style="color: #0000FF">when</span></span> <span style="color: #009900">V</span> <span style="color: #990000">></span> <span style="color: #993399">0</span> <span style="color: #990000">-></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">V</span>}; + (<span style="color: #990000">_</span>, <span style="color: #990000">_</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">error</span>, <span style="color: #FF6600">not_positive</span>} +<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>, +{<span style="color: #FF6600">my_value</span>, [<span style="color: #FF6600">int</span>, <span style="color: #009900">PositiveFun</span>]}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>We ignore the first fun argument in this snippet. We shouldn’t. +We will simply learn what it is later in this chapter.</p></div> +<div class="paragraph"><p>When there’s only one constraint, it can be provided directly +without wrapping it into a list:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF6600">my_value</span>, <span style="color: #FF6600">int</span>}</tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_built_in_constraints">Built-in constraints</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Built-in constraints are specified as an atom:</p></div> +<div class="tableblock"> +<table rules="all" +width="100%" +frame="border" +cellspacing="0" cellpadding="4"> +<col width="50%" /> +<col width="50%" /> +<thead> +<tr> +<th align="left" valign="top"> Constraint </th> +<th align="left" valign="top"> Description</th> +</tr> +</thead> +<tbody> +<tr> +<td align="left" valign="top"><p class="table">int</p></td> +<td align="left" valign="top"><p class="table">Converts binary value to integer.</p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">nonempty</p></td> +<td align="left" valign="top"><p class="table">Ensures the binary value is non-empty.</p></td> +</tr> +</tbody> +</table> +</div> +</div> +</div> +<div class="sect1"> +<h2 id="_custom_constraints">Custom constraints</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Custom constraints are specified as a fun. This fun takes +two arguments. The first argument indicates the operation +to be performed, and the second is the value. What the +value is and what must be returned depends on the operation.</p></div> +<div class="paragraph"><p>Cowboy currently defines three operations. The operation +used for validating and converting user input is the <code>forward</code> +operation.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">int</span></span>(<span style="color: #FF6600">forward</span>, <span style="color: #009900">Value</span>) <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #0000FF">try</span></span> + {<span style="color: #FF6600">ok</span>, <span style="font-weight: bold"><span style="color: #000000">binary_to_integer</span></span>(<span style="color: #009900">Value</span>)} + <span style="font-weight: bold"><span style="color: #0000FF">catch</span></span> <span style="color: #990000">_:_</span> <span style="color: #990000">-></span> + {<span style="color: #FF6600">error</span>, <span style="color: #FF6600">not_an_integer</span>} + <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>;</tt></pre></div></div> +<div class="paragraph"><p>The value must be returned even if it is not converted +by the constraint.</p></div> +<div class="paragraph"><p>The <code>reverse</code> operation does the opposite: it +takes a converted value and changes it back to what the +user input would have been.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">int</span></span>(<span style="color: #FF6600">reverse</span>, <span style="color: #009900">Value</span>) <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #0000FF">try</span></span> + {<span style="color: #FF6600">ok</span>, <span style="font-weight: bold"><span style="color: #000000">integer_to_binary</span></span>(<span style="color: #009900">Value</span>)} + <span style="font-weight: bold"><span style="color: #0000FF">catch</span></span> <span style="color: #990000">_:_</span> <span style="color: #990000">-></span> + {<span style="color: #FF6600">error</span>, <span style="color: #FF6600">not_an_integer</span>} + <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>;</tt></pre></div></div> +<div class="paragraph"><p>Finally, the <code>format_error</code> operation takes an error +returned by any other operation and returns a formatted +human-readable error message.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">int</span></span>(<span style="color: #FF6600">format_error</span>, {<span style="color: #FF6600">not_an_integer</span>, <span style="color: #009900">Value</span>}) <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #000000">io_lib:format</span></span>(<span style="color: #FF0000">"The value ~p is not an integer."</span>, [<span style="color: #009900">Value</span>])<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Notice that for this case you get both the error and +the value that was given to the constraint that produced +this error.</p></div> +<div class="paragraph"><p>Cowboy will not catch exceptions coming from constraint +functions. They should be written to not emit any exceptions.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/routing/"> + Routing + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/handlers/"> + Handlers + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/cookies.asciidoc b/docs/en/cowboy/2.2/guide/cookies.asciidoc new file mode 100644 index 00000000..4825031b --- /dev/null +++ b/docs/en/cowboy/2.2/guide/cookies.asciidoc @@ -0,0 +1,139 @@ +[[cookies]] +== Using cookies + +Cookies are a mechanism allowing applications to maintain +state on top of the stateless HTTP protocol. + +Cookies are a name/value store where the names and values are +stored in plain text. They expire either after a delay +or when the browser closes. They can be configured on a +specific domain name or path, and restricted to secure +resources (sent or downloaded over HTTPS), or restricted +to the server (disallowing access from client-side scripts). + +Cookie names are de facto case sensitive. + +Cookies are stored client-side and sent with every subsequent +request that matches the domain and path for which they were +stored, until they expire. This can create a non-negligible +cost. + +Cookies should not be considered secure. They are stored on +the user's computer in plain text, and can be read by any +program. They can also be read by proxies when using clear +connections. Always validate the value before using it, +and never store any sensitive information inside it. + +Cookies set by the server are only available in requests +following the client reception of the response containing +them. + +Cookies may be sent repeatedly. This is often useful to +update the expiration time and avoid losing a cookie. + +=== Setting cookies + +By default cookies are defined for the duration of the session: + +[source,erlang] +---- +SessionID = generate_session_id(), +Req = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, Req0). +---- + +They can also be set for a duration in seconds: + +[source,erlang] +---- +SessionID = generate_session_id(), +Req = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, Req0, + #{max_age => 3600}). +---- + +To delete cookies, set `max_age` to 0: + +[source,erlang] +---- +SessionID = generate_session_id(), +Req = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, Req0, + #{max_age => 0}). +---- + +To restrict cookies to a specific domain and path, the options +of the same name can be used: + +[source,erlang] +---- +Req = cowboy_req:set_resp_cookie(<<"inaccount">>, <<"1">>, Req0, + #{domain => "my.example.org", path => "/account"}). +---- + +Cookies will be sent with requests to this domain and all +its subdomains, and to resources on this path or deeper +in the path hierarchy. + +To restrict cookies to secure channels (typically resources +available over HTTPS): + +[source,erlang] +---- +SessionID = generate_session_id(), +Req = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, Req0, + #{secure => true}). +---- + +To prevent client-side scripts from accessing a cookie: + +[source,erlang] +---- +SessionID = generate_session_id(), +Req = cowboy_req:set_resp_cookie(<<"sessionid">>, SessionID, Req0, + #{http_only => true}). +---- + +Cookies may also be set client-side, for example using +Javascript. + +=== Reading cookies + +The client only ever sends back the cookie name and value. +All other options that can be set are never sent back. + +Cowboy provides two functions for reading cookies. Both +involve parsing the cookie header(s) and so should not +be called repeatedly. + +You can get all cookies as a key/value list: + +[source,erlang] +Cookies = cowboy_req:parse_cookies(Req), +{_, Lang} = lists:keyfind(<<"lang">>, 1, Cookies). + +Or you can perform a match against cookies and retrieve +only the ones you need, while at the same time doing +any required post processing using xref:constraints[constraints]. +This function returns a map: + +[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 +not an integer number or if the `lang` cookie is empty. Additionally +the `id` cookie value will be converted to an integer term: + +[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. + +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: + +[source,erlang] +#{lang := Lang} = cowboy_req:match_cookies([{lang, [], <<"en-US">>}], Req). + +If no default is provided and the value is missing, an +exception is thrown. diff --git a/docs/en/cowboy/2.2/guide/cookies/index.html b/docs/en/cowboy/2.2/guide/cookies/index.html new file mode 100644 index 00000000..28a3759c --- /dev/null +++ b/docs/en/cowboy/2.2/guide/cookies/index.html @@ -0,0 +1,303 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Using cookies</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Using cookies</span></h1> + +<div class="paragraph"><p>Cookies are a mechanism allowing applications to maintain +state on top of the stateless HTTP protocol.</p></div> +<div class="paragraph"><p>Cookies are a name/value store where the names and values are +stored in plain text. They expire either after a delay +or when the browser closes. They can be configured on a +specific domain name or path, and restricted to secure +resources (sent or downloaded over HTTPS), or restricted +to the server (disallowing access from client-side scripts).</p></div> +<div class="paragraph"><p>Cookie names are de facto case sensitive.</p></div> +<div class="paragraph"><p>Cookies are stored client-side and sent with every subsequent +request that matches the domain and path for which they were +stored, until they expire. This can create a non-negligible +cost.</p></div> +<div class="paragraph"><p>Cookies should not be considered secure. They are stored on +the user’s computer in plain text, and can be read by any +program. They can also be read by proxies when using clear +connections. Always validate the value before using it, +and never store any sensitive information inside it.</p></div> +<div class="paragraph"><p>Cookies set by the server are only available in requests +following the client reception of the response containing +them.</p></div> +<div class="paragraph"><p>Cookies may be sent repeatedly. This is often useful to +update the expiration time and avoid losing a cookie.</p></div> +<div class="sect1"> +<h2 id="_setting_cookies">Setting cookies</h2> +<div class="sectionbody"> +<div class="paragraph"><p>By default cookies are defined for the duration of the session:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">SessionID</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">generate_session_id</span></span>(), +<span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:set_resp_cookie</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"sessionid"</span><span style="color: #990000">>></span>, <span style="color: #009900">SessionID</span>, <span style="color: #009900">Req0</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>They can also be set for a duration in seconds:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">SessionID</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">generate_session_id</span></span>(), +<span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:set_resp_cookie</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"sessionid"</span><span style="color: #990000">>></span>, <span style="color: #009900">SessionID</span>, <span style="color: #009900">Req0</span>, + #{<span style="color: #0000FF">max_age</span> <span style="color: #990000">=></span> <span style="color: #993399">3600</span>})<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>To delete cookies, set <code>max_age</code> to 0:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">SessionID</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">generate_session_id</span></span>(), +<span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:set_resp_cookie</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"sessionid"</span><span style="color: #990000">>></span>, <span style="color: #009900">SessionID</span>, <span style="color: #009900">Req0</span>, + #{<span style="color: #0000FF">max_age</span> <span style="color: #990000">=></span> <span style="color: #993399">0</span>})<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>To restrict cookies to a specific domain and path, the options +of the same name can be used:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:set_resp_cookie</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"inaccount"</span><span style="color: #990000">>></span>, <span style="color: #990000"><<</span><span style="color: #FF0000">"1"</span><span style="color: #990000">>></span>, <span style="color: #009900">Req0</span>, + #{<span style="color: #0000FF">domain</span> <span style="color: #990000">=></span> <span style="color: #FF0000">"my.example.org"</span>, <span style="color: #0000FF">path</span> <span style="color: #990000">=></span> <span style="color: #FF0000">"/account"</span>})<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Cookies will be sent with requests to this domain and all +its subdomains, and to resources on this path or deeper +in the path hierarchy.</p></div> +<div class="paragraph"><p>To restrict cookies to secure channels (typically resources +available over HTTPS):</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">SessionID</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">generate_session_id</span></span>(), +<span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:set_resp_cookie</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"sessionid"</span><span style="color: #990000">>></span>, <span style="color: #009900">SessionID</span>, <span style="color: #009900">Req0</span>, + #{<span style="color: #0000FF">secure</span> <span style="color: #990000">=></span> <span style="color: #000080">true</span>})<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>To prevent client-side scripts from accessing a cookie:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">SessionID</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">generate_session_id</span></span>(), +<span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:set_resp_cookie</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"sessionid"</span><span style="color: #990000">>></span>, <span style="color: #009900">SessionID</span>, <span style="color: #009900">Req0</span>, + #{<span style="color: #0000FF">http_only</span> <span style="color: #990000">=></span> <span style="color: #000080">true</span>})<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Cookies may also be set client-side, for example using +Javascript.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_reading_cookies">Reading cookies</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The client only ever sends back the cookie name and value. +All other options that can be set are never sent back.</p></div> +<div class="paragraph"><p>Cowboy provides two functions for reading cookies. Both +involve parsing the cookie header(s) and so should not +be called repeatedly.</p></div> +<div class="paragraph"><p>You can get all cookies as a key/value list:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Cookies</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:parse_cookies</span></span>(<span style="color: #009900">Req</span>), +{<span style="color: #990000">_</span>, <span style="color: #009900">Lang</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">lists:keyfind</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"lang"</span><span style="color: #990000">>></span>, <span style="color: #993399">1</span>, <span style="color: #009900">Cookies</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Or you can perform a match against cookies and retrieve +only the ones you need, while at the same time doing +any required post processing using <a href="../constraints">constraints</a>. +This function returns a map:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>#{<span style="color: #FF6600">id</span> <span style="color: #990000">:=</span> <span style="color: #009900">ID</span>, <span style="color: #FF6600">lang</span> <span style="color: #990000">:=</span> <span style="color: #009900">Lang</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:match_cookies</span></span>([<span style="color: #FF6600">id</span>, <span style="color: #FF6600">lang</span>], <span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>You can use constraints to validate the values while matching +them. The following snippet will crash if the <code>id</code> cookie is +not an integer number or if the <code>lang</code> cookie is empty. Additionally +the <code>id</code> cookie value will be converted to an integer term:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">CookiesMap</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:match_cookies</span></span>([{<span style="color: #FF6600">id</span>, <span style="color: #FF6600">int</span>}, {<span style="color: #FF6600">lang</span>, <span style="color: #FF6600">nonempty</span>}], <span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Note that if two cookies share the same name, then the map value +will be a list of the two cookie values.</p></div> +<div class="paragraph"><p>A default value can be provided. The default will be used +if the <code>lang</code> cookie is not found. It will not be used if +the cookie is found but has an empty value:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>#{<span style="color: #FF6600">lang</span> <span style="color: #990000">:=</span> <span style="color: #009900">Lang</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:match_cookies</span></span>([{<span style="color: #FF6600">lang</span>, [], <span style="color: #990000"><<</span><span style="color: #FF0000">"en-US"</span><span style="color: #990000">>></span>}], <span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>If no default is provided and the value is missing, an +exception is thrown.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/resp/"> + Sending a response + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/multipart/"> + Multipart requests + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/cowboy.sty b/docs/en/cowboy/2.2/guide/cowboy.sty new file mode 100644 index 00000000..d5e0d3be --- /dev/null +++ b/docs/en/cowboy/2.2/guide/cowboy.sty @@ -0,0 +1,8 @@ +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{asciidoc-dblatex}[2012/10/24 AsciiDoc DocBook Style] + +%% Just use the original package and pass the options. +\RequirePackageWithOptions{docbook} + +%% Define an alias for make snippets to be compatible with source-highlighter. +\lstalias{makefile}{make} diff --git a/docs/en/cowboy/2.2/guide/erlang_web.asciidoc b/docs/en/cowboy/2.2/guide/erlang_web.asciidoc new file mode 100644 index 00000000..f528adc3 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/erlang_web.asciidoc @@ -0,0 +1,209 @@ +[[erlang_web]] +== Erlang and the Web + +Erlang is the ideal platform for writing Web applications. +Its features are a perfect match for the requirements of +modern Web applications. + +=== The Web is concurrent + +When you access a website there is little concurrency +involved. A few connections are opened and requests +are sent through these connections. Then the web page +is displayed on your screen. Your browser will only +open up to 4 or 8 connections to the server, depending +on your settings. This isn't much. + +But think about it. You are not the only one accessing +the server at the same time. There can be hundreds, if +not thousands, if not millions of connections to the +same server at the same time. + +Even today a lot of systems used in production haven't +solved the C10K problem (ten thousand concurrent connections). +And the ones who did are trying hard to get to the next +step, C100K, and are pretty far from it. + +Erlang meanwhile has no problem handling millions of +connections. At the time of writing there are application +servers written in Erlang that can handle more than two +million connections on a single server in a real production +application, with spare memory and CPU! + +The Web is concurrent, and Erlang is a language designed +for concurrency, so it is a perfect match. + +Of course, various platforms need to scale beyond a few +million connections. This is where Erlang's built-in +distribution mechanisms come in. If one server isn't +enough, add more! Erlang allows you to use the same code +for talking to local processes or to processes in other +parts of your cluster, which means you can scale very +quickly if the need arises. + +The Web has large userbases, and the Erlang platform was +designed to work in a distributed setting, so it is a +perfect match. + +Or is it? Surely you can find solutions to handle that many +concurrent connections with your favorite language... But all +these solutions will break down in the next few years. Why? +Firstly because servers don't get any more powerful, they +instead get a lot more cores and memory. This is only useful +if your application can use them properly, and Erlang is +light-years away from anything else in that area. Secondly, +today your computer and your phone are online, tomorrow your +watch, goggles, bike, car, fridge and tons of other devices +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 + +What does soft real time mean, you ask? It means we want the +operations done as quickly as possible, and in the case of +web applications, it means we want the data propagated fast. + +In comparison, hard real time has a similar meaning, but also +has a hard time constraint, for example an operation needs to +be done in under N milliseconds otherwise the system fails +entirely. + +Users aren't that needy yet, they just want to get access +to their content in a reasonable delay, and they want the +actions they make to register at most a few seconds after +they submitted them, otherwise they'll start worrying about +whether it successfully went through. + +The Web is soft real time because taking longer to perform an +operation would be seen as bad quality of service. + +Erlang is a soft real time system. It will always run +processes fairly, a little at a time, switching to another +process after a while and preventing a single process to +steal resources from all others. This means that Erlang +can guarantee stable low latency of operations. + +Erlang provides the guarantees that the soft real time Web +requires. + +=== 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. +It all began when XmlHttpRequest started being used. It allowed +the client to perform asynchronous calls to the server. + +Then Websocket appeared and allowed both the server and the client +to send data to the other endpoint completely asynchronously. The +data is contained within frames and no response is necessary. + +Erlang processes work the same. They send each other data contained +within messages and then continue running without needing a response. +They tend to spend most of their time inactive, waiting for a new +message, and the Erlang VM happily activate them when one is received. + +It is therefore quite easy to imagine Erlang being good at receiving +Websocket frames, which may come in at unpredictable times, pass the +data to the responsible processes which are always ready waiting for +new messages, and perform the operations required by only activating +the required parts of the system. + +The more recent Web technologies, like Websocket of course, but also +HTTP/2.0, are all fully asynchronous protocols. The concept +of requests and responses is retained of course, but anything could +be sent in between, by both the client or the browser, and the +responses could also be received in a completely different order. + +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 has taken a very important part of our lives. We're +connected at all times, when we're on our phone, using our computer, +passing time using a tablet while in the bathroom... And this +isn't going to slow down, every single device at home or on us +will be connected. + +All these devices are always connected. And with the number of +alternatives to give you access to the content you seek, users +tend to not stick around when problems arise. Users today want +their applications to be always available and if it's having +too many issues they just move on. + +Despite this, when developers choose a product to use for building +web applications, their only concern seems to be "Is it fast?", +and they look around for synthetic benchmarks showing which one +is the fastest at sending "Hello world" with only a handful +concurrent connections. Web benchmarks haven't been representative +of reality in a long time, and are drifting further away as +time goes on. + +What developers should really ask themselves is "Can I service +all my users with no interruption?" and they'd find that they have +two choices. They can either hope for the best, or they can use +Erlang. + +Erlang is built for fault tolerance. When writing code in any other +language, you have to check all the return values and act accordingly +to avoid any unforeseen issues. If you're lucky, you won't miss +anything important. When writing Erlang code, you can just check +the success condition and ignore all errors. If an error happens, +the Erlang process crashes and is then restarted by a special +process called a supervisor. + +Erlang developers thus have no need to fear unhandled +errors, and can focus on handling only the errors that should +give some feedback to the user and let the system take care of +the rest. This also has the advantage of allowing them to write +a lot less code, and let them sleep at night. + +Erlang's fault tolerance oriented design is the first piece of +what makes it the best choice for the omnipresent, always available +Web. + +The second piece is Erlang's built-in distribution. Distribution +is a key part of building a fault tolerant system, because it +allows you to handle bigger failures, like a whole server going +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. + +=== Learn Erlang + +If you are new to Erlang, you may want to grab a book or +two to get started. Those are my recommendations as the +author of Cowboy. + +==== The Erlanger Playbook + +The Erlanger Playbook is an ebook I am currently writing, +which covers a number of different topics from code to +documentation to testing Erlang applications. It also has +an Erlang section where it covers directly the building +blocks and patterns, rather than details like the syntax. + +You can most likely read it as a complete beginner, but +you will need a companion book to make the most of it. +Buy it from the https://ninenines.eu[Nine Nines website]. + +==== Programming Erlang + +This book is from one of the creator of Erlang, Joe +Armstrong. It provides a very good explanation of what +Erlang is and why it is so. It serves as a very good +introduction to the language and platform. + +The book is http://pragprog.com/book/jaerlang2/programming-erlang[Programming Erlang], +and it also features a chapter on Cowboy. + +==== Learn You Some Erlang for Great Good! + +http://learnyousomeerlang.com[LYSE] is a much more complete +book covering many aspects of Erlang, while also providing +stories and humor. Be warned: it's pretty verbose. It comes +with a free online version and a more refined paper and +ebook version. diff --git a/docs/en/cowboy/2.2/guide/erlang_web/index.html b/docs/en/cowboy/2.2/guide/erlang_web/index.html new file mode 100644 index 00000000..e8384489 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/erlang_web/index.html @@ -0,0 +1,353 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Erlang and the Web</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Erlang and the Web</span></h1> + +<div class="paragraph"><p>Erlang is the ideal platform for writing Web applications. +Its features are a perfect match for the requirements of +modern Web applications.</p></div> +<div class="sect1"> +<h2 id="_the_web_is_concurrent">The Web is concurrent</h2> +<div class="sectionbody"> +<div class="paragraph"><p>When you access a website there is little concurrency +involved. A few connections are opened and requests +are sent through these connections. Then the web page +is displayed on your screen. Your browser will only +open up to 4 or 8 connections to the server, depending +on your settings. This isn’t much.</p></div> +<div class="paragraph"><p>But think about it. You are not the only one accessing +the server at the same time. There can be hundreds, if +not thousands, if not millions of connections to the +same server at the same time.</p></div> +<div class="paragraph"><p>Even today a lot of systems used in production haven’t +solved the C10K problem (ten thousand concurrent connections). +And the ones who did are trying hard to get to the next +step, C100K, and are pretty far from it.</p></div> +<div class="paragraph"><p>Erlang meanwhile has no problem handling millions of +connections. At the time of writing there are application +servers written in Erlang that can handle more than two +million connections on a single server in a real production +application, with spare memory and CPU!</p></div> +<div class="paragraph"><p>The Web is concurrent, and Erlang is a language designed +for concurrency, so it is a perfect match.</p></div> +<div class="paragraph"><p>Of course, various platforms need to scale beyond a few +million connections. This is where Erlang’s built-in +distribution mechanisms come in. If one server isn’t +enough, add more! Erlang allows you to use the same code +for talking to local processes or to processes in other +parts of your cluster, which means you can scale very +quickly if the need arises.</p></div> +<div class="paragraph"><p>The Web has large userbases, and the Erlang platform was +designed to work in a distributed setting, so it is a +perfect match.</p></div> +<div class="paragraph"><p>Or is it? Surely you can find solutions to handle that many +concurrent connections with your favorite language… But all +these solutions will break down in the next few years. Why? +Firstly because servers don’t get any more powerful, they +instead get a lot more cores and memory. This is only useful +if your application can use them properly, and Erlang is +light-years away from anything else in that area. Secondly, +today your computer and your phone are online, tomorrow your +watch, goggles, bike, car, fridge and tons of other devices +will also connect to various applications on the Internet.</p></div> +<div class="paragraph"><p>Only Erlang is prepared to deal with what’s coming.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_the_web_is_soft_real_time">The Web is soft real time</h2> +<div class="sectionbody"> +<div class="paragraph"><p>What does soft real time mean, you ask? It means we want the +operations done as quickly as possible, and in the case of +web applications, it means we want the data propagated fast.</p></div> +<div class="paragraph"><p>In comparison, hard real time has a similar meaning, but also +has a hard time constraint, for example an operation needs to +be done in under N milliseconds otherwise the system fails +entirely.</p></div> +<div class="paragraph"><p>Users aren’t that needy yet, they just want to get access +to their content in a reasonable delay, and they want the +actions they make to register at most a few seconds after +they submitted them, otherwise they’ll start worrying about +whether it successfully went through.</p></div> +<div class="paragraph"><p>The Web is soft real time because taking longer to perform an +operation would be seen as bad quality of service.</p></div> +<div class="paragraph"><p>Erlang is a soft real time system. It will always run +processes fairly, a little at a time, switching to another +process after a while and preventing a single process to +steal resources from all others. This means that Erlang +can guarantee stable low latency of operations.</p></div> +<div class="paragraph"><p>Erlang provides the guarantees that the soft real time Web +requires.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_the_web_is_asynchronous">The Web is asynchronous</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Long ago, the Web was synchronous because HTTP was synchronous. +You fired a request, and then waited for a response. Not anymore. +It all began when XmlHttpRequest started being used. It allowed +the client to perform asynchronous calls to the server.</p></div> +<div class="paragraph"><p>Then Websocket appeared and allowed both the server and the client +to send data to the other endpoint completely asynchronously. The +data is contained within frames and no response is necessary.</p></div> +<div class="paragraph"><p>Erlang processes work the same. They send each other data contained +within messages and then continue running without needing a response. +They tend to spend most of their time inactive, waiting for a new +message, and the Erlang VM happily activate them when one is received.</p></div> +<div class="paragraph"><p>It is therefore quite easy to imagine Erlang being good at receiving +Websocket frames, which may come in at unpredictable times, pass the +data to the responsible processes which are always ready waiting for +new messages, and perform the operations required by only activating +the required parts of the system.</p></div> +<div class="paragraph"><p>The more recent Web technologies, like Websocket of course, but also +HTTP/2.0, are all fully asynchronous protocols. The concept +of requests and responses is retained of course, but anything could +be sent in between, by both the client or the browser, and the +responses could also be received in a completely different order.</p></div> +<div class="paragraph"><p>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.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_the_web_is_omnipresent">The Web is omnipresent</h2> +<div class="sectionbody"> +<div class="paragraph"><p>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, +passing time using a tablet while in the bathroom… And this +isn’t going to slow down, every single device at home or on us +will be connected.</p></div> +<div class="paragraph"><p>All these devices are always connected. And with the number of +alternatives to give you access to the content you seek, users +tend to not stick around when problems arise. Users today want +their applications to be always available and if it’s having +too many issues they just move on.</p></div> +<div class="paragraph"><p>Despite this, when developers choose a product to use for building +web applications, their only concern seems to be "Is it fast?", +and they look around for synthetic benchmarks showing which one +is the fastest at sending "Hello world" with only a handful +concurrent connections. Web benchmarks haven’t been representative +of reality in a long time, and are drifting further away as +time goes on.</p></div> +<div class="paragraph"><p>What developers should really ask themselves is "Can I service +all my users with no interruption?" and they’d find that they have +two choices. They can either hope for the best, or they can use +Erlang.</p></div> +<div class="paragraph"><p>Erlang is built for fault tolerance. When writing code in any other +language, you have to check all the return values and act accordingly +to avoid any unforeseen issues. If you’re lucky, you won’t miss +anything important. When writing Erlang code, you can just check +the success condition and ignore all errors. If an error happens, +the Erlang process crashes and is then restarted by a special +process called a supervisor.</p></div> +<div class="paragraph"><p>Erlang developers thus have no need to fear unhandled +errors, and can focus on handling only the errors that should +give some feedback to the user and let the system take care of +the rest. This also has the advantage of allowing them to write +a lot less code, and let them sleep at night.</p></div> +<div class="paragraph"><p>Erlang’s fault tolerance oriented design is the first piece of +what makes it the best choice for the omnipresent, always available +Web.</p></div> +<div class="paragraph"><p>The second piece is Erlang’s built-in distribution. Distribution +is a key part of building a fault tolerant system, because it +allows you to handle bigger failures, like a whole server going +down, or even a data center entirely.</p></div> +<div class="paragraph"><p>Fault tolerance and distribution are important today, and will be +vital in the future of the Web. Erlang is ready.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_learn_erlang">Learn Erlang</h2> +<div class="sectionbody"> +<div class="paragraph"><p>If you are new to Erlang, you may want to grab a book or +two to get started. Those are my recommendations as the +author of Cowboy.</p></div> +<div class="sect3"> +<h4 id="_the_erlanger_playbook">The Erlanger Playbook</h4> +<div class="paragraph"><p>The Erlanger Playbook is an ebook I am currently writing, +which covers a number of different topics from code to +documentation to testing Erlang applications. It also has +an Erlang section where it covers directly the building +blocks and patterns, rather than details like the syntax.</p></div> +<div class="paragraph"><p>You can most likely read it as a complete beginner, but +you will need a companion book to make the most of it. +Buy it from the <a href="https://ninenines.eu">Nine Nines website</a>.</p></div> +</div> +<div class="sect3"> +<h4 id="_programming_erlang">Programming Erlang</h4> +<div class="paragraph"><p>This book is from one of the creator of Erlang, Joe +Armstrong. It provides a very good explanation of what +Erlang is and why it is so. It serves as a very good +introduction to the language and platform.</p></div> +<div class="paragraph"><p>The book is <a href="http://pragprog.com/book/jaerlang2/programming-erlang">Programming Erlang</a>, +and it also features a chapter on Cowboy.</p></div> +</div> +<div class="sect3"> +<h4 id="_learn_you_some_erlang_for_great_good">Learn You Some Erlang for Great Good!</h4> +<div class="paragraph"><p><a href="http://learnyousomeerlang.com">LYSE</a> is a much more complete +book covering many aspects of Erlang, while also providing +stories and humor. Be warned: it’s pretty verbose. It comes +with a free online version and a more refined paper and +ebook version.</p></div> +</div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/modern_web/"> + The modern Web + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/introduction/"> + Introduction + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/flow_diagram.asciidoc b/docs/en/cowboy/2.2/guide/flow_diagram.asciidoc new file mode 100644 index 00000000..2d35d4d6 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/flow_diagram.asciidoc @@ -0,0 +1,109 @@ +[[flow_diagram]] +== Flow diagram + +Cowboy is a lightweight HTTP server with support for HTTP/1.1, +HTTP/2 and Websocket. + +It is built on top of Ranch. Please see the Ranch guide for more +information about how the network connections are handled. + +=== Overview + +image::http_req_resp.png[HTTP request/response flowchart] + +As you can see on the diagram, the client +begins by connecting to the server. This step is handled +by a Ranch acceptor, which is a process dedicated to +accepting new connections. + +After Ranch accepts a new connection, whether it is an +HTTP/1.1 or HTTP/2 connection, Cowboy starts receiving +requests and handling them. + +In HTTP/1.1 all requests come sequentially. In HTTP/2 +the requests may arrive and be processed concurrently. + +When a request comes in, Cowboy creates a stream, which +is a set of request/response and all the events associated +with them. The protocol code in Cowboy defers the handling +of these streams to stream handler modules. When you +configure Cowboy you may define one or more module that +will receive all events associated with a stream, including +the request, response, bodies, Erlang messages and more. + +By default Cowboy comes configured with a stream handler +called `cowboy_stream_h`. This stream handler will create +a new process for every request coming in, and then +communicate with this process to read the body or send +a response back. The request process executes middlewares +which, by default, including the router and then the +execution of handlers. Like stream handlers, middlewares +may also be customized. + +A response may be sent at almost any point in this +diagram. If the response must be sent before the stream +is initialized (because an error occurred early, for +example) then stream handlers receive a special event +indicating this error. + +=== Protocol-specific headers + +Cowboy takes care of protocol-specific headers and prevents +you from sending them manually. For HTTP/1.1 this includes +the `transfer-encoding` and `connection` headers. For HTTP/2 +this includes the colon headers like `:status`. + +Cowboy will also remove protocol-specific headers from +requests before passing them to stream handlers. Cowboy +tries to hide the implementation details of all protocols +as well as possible. + +=== Number of processes per connection + +By default, Cowboy will use one process per connection, +plus one process per set of request/response (called a +stream, internally). + +The reason it creates a new process for every request is due +to the requirements of HTTP/2 where requests are executed +concurrently and independently from the connection. The +frames from the different requests end up interleaved on +the single TCP connection. + +The request processes are never reused. There is therefore +no need to perform any cleanup after the response has been +sent. The process will terminate and Erlang/OTP will reclaim +all memory at once. + +Cowboy ultimately does not require more than one process +per connection. It is possible to interact with the connection +directly from a stream handler, a low level interface to Cowboy. +They are executed from within the connection process, and can +handle the incoming requests and send responses. This is however +not recommended in normal circumstances, as a stream handler +taking too long to execute could have a negative impact on +concurrent requests or the state of the connection itself. + +=== 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. + +=== Binaries + +Cowboy makes extensive use of binaries. + +Binaries are more efficient than lists for representing +strings because they take less memory space. Processing +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. + +Binaries may end up being shared between processes. This +can lead to some large memory usage when one process keeps +the binary data around forever without freeing it. If you +see some weird memory usage in your application, this might +be the cause. diff --git a/docs/en/cowboy/2.2/guide/flow_diagram/index.html b/docs/en/cowboy/2.2/guide/flow_diagram/index.html new file mode 100644 index 00000000..e9790b10 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/flow_diagram/index.html @@ -0,0 +1,272 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Flow diagram</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Flow diagram</span></h1> + +<div class="paragraph"><p>Cowboy is a lightweight HTTP server with support for HTTP/1.1, +HTTP/2 and Websocket.</p></div> +<div class="paragraph"><p>It is built on top of Ranch. Please see the Ranch guide for more +information about how the network connections are handled.</p></div> +<div class="sect1"> +<h2 id="_overview">Overview</h2> +<div class="sectionbody"> +<div class="imageblock"> +<div class="content"> +<img src="../http_req_resp.png" alt="HTTP request/response flowchart" /> +</div> +</div> +<div class="paragraph"><p>As you can see on the diagram, the client +begins by connecting to the server. This step is handled +by a Ranch acceptor, which is a process dedicated to +accepting new connections.</p></div> +<div class="paragraph"><p>After Ranch accepts a new connection, whether it is an +HTTP/1.1 or HTTP/2 connection, Cowboy starts receiving +requests and handling them.</p></div> +<div class="paragraph"><p>In HTTP/1.1 all requests come sequentially. In HTTP/2 +the requests may arrive and be processed concurrently.</p></div> +<div class="paragraph"><p>When a request comes in, Cowboy creates a stream, which +is a set of request/response and all the events associated +with them. The protocol code in Cowboy defers the handling +of these streams to stream handler modules. When you +configure Cowboy you may define one or more module that +will receive all events associated with a stream, including +the request, response, bodies, Erlang messages and more.</p></div> +<div class="paragraph"><p>By default Cowboy comes configured with a stream handler +called <code>cowboy_stream_h</code>. This stream handler will create +a new process for every request coming in, and then +communicate with this process to read the body or send +a response back. The request process executes middlewares +which, by default, including the router and then the +execution of handlers. Like stream handlers, middlewares +may also be customized.</p></div> +<div class="paragraph"><p>A response may be sent at almost any point in this +diagram. If the response must be sent before the stream +is initialized (because an error occurred early, for +example) then stream handlers receive a special event +indicating this error.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_protocol_specific_headers">Protocol-specific headers</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy takes care of protocol-specific headers and prevents +you from sending them manually. For HTTP/1.1 this includes +the <code>transfer-encoding</code> and <code>connection</code> headers. For HTTP/2 +this includes the colon headers like <code>:status</code>.</p></div> +<div class="paragraph"><p>Cowboy will also remove protocol-specific headers from +requests before passing them to stream handlers. Cowboy +tries to hide the implementation details of all protocols +as well as possible.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_number_of_processes_per_connection">Number of processes per connection</h2> +<div class="sectionbody"> +<div class="paragraph"><p>By default, Cowboy will use one process per connection, +plus one process per set of request/response (called a +stream, internally).</p></div> +<div class="paragraph"><p>The reason it creates a new process for every request is due +to the requirements of HTTP/2 where requests are executed +concurrently and independently from the connection. The +frames from the different requests end up interleaved on +the single TCP connection.</p></div> +<div class="paragraph"><p>The request processes are never reused. There is therefore +no need to perform any cleanup after the response has been +sent. The process will terminate and Erlang/OTP will reclaim +all memory at once.</p></div> +<div class="paragraph"><p>Cowboy ultimately does not require more than one process +per connection. It is possible to interact with the connection +directly from a stream handler, a low level interface to Cowboy. +They are executed from within the connection process, and can +handle the incoming requests and send responses. This is however +not recommended in normal circumstances, as a stream handler +taking too long to execute could have a negative impact on +concurrent requests or the state of the connection itself.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_date_header">Date header</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Because querying for the current date and time can be expensive, +Cowboy generates one <em>Date</em> 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.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_binaries">Binaries</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy makes extensive use of binaries.</p></div> +<div class="paragraph"><p>Binaries are more efficient than lists for representing +strings because they take less memory space. Processing +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.</p></div> +<div class="paragraph"><p>Binaries may end up being shared between processes. This +can lead to some large memory usage when one process keeps +the binary data around forever without freeing it. If you +see some weird memory usage in your application, this might +be the cause.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/getting_started/"> + Getting started + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/listeners/"> + Listeners + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/getting_started.asciidoc b/docs/en/cowboy/2.2/guide/getting_started.asciidoc new file mode 100644 index 00000000..3f145bb8 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/getting_started.asciidoc @@ -0,0 +1,147 @@ +[[getting_started]] +== Getting started + +Erlang is more than a language, it is also an operating system +for your applications. Erlang developers rarely write standalone +modules, they write libraries or applications, and then bundle +those into what is called a release. A release contains the +Erlang VM plus all applications required to run the node, so +it can be pushed to production directly. + +This chapter walks you through all the steps of setting up +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. + +=== Prerequisites + +We are going to use the https://github.com/ninenines/erlang.mk[Erlang.mk] +build system. If you are using Windows, please check the +http://erlang.mk/guide/installation.html[Installation instructions] +to get your environment setup before you continue. + +=== Bootstrap + +First, let's create the directory for our application. + +[source,bash] +$ mkdir hello_erlang +$ cd hello_erlang + +Then we need to download Erlang.mk. Either use the following +command or download it manually. + +[source,bash] +$ wget https://erlang.mk/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. + +[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. + +[source,bash] +---- +$ make run +... +([email protected])1> +---- + +Entering the command `i().` will show the running processes, including +one called `hello_erlang_sup`. This is the supervisor for our +application. + +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 + +We will modify the 'Makefile' to tell the build system it needs to +fetch and compile Cowboy: + +[source,makefile] +---- +PROJECT = hello_erlang + +DEPS = cowboy +dep_cowboy_commit = 2.1.0 + +DEP_PLUGINS = cowboy + +include erlang.mk +---- + +We also tell the build system to load the plugins Cowboy provides. +These include predefined templates that we will use soon. + +If you do `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 + +First we define the routes that Cowboy will use to map requests +to handler modules, and then we start the listener. This is best +done at application startup. + +Open the 'src/hello_erlang_app.erl' file and add the necessary +code to the `start/2` function to make it look like this: + +[source,erlang] +---- +start(_Type, _Args) -> + Dispatch = cowboy_router:compile([ + {'_', [{"/", hello_handler, []}]} + ]), + {ok, _} = cowboy:start_clear(my_http_listener, + [{port, 8080}], + #{env => #{dispatch => Dispatch}} + ), + hello_erlang_sup:start_link(). +---- + +Routes are explained in details in the xref:routing[Routing] +chapter. For this tutorial we map the path `/` to the handler +module `hello_handler`. This module doesn't exist yet. + +Build and start the release, then open http://localhost:8080 +in your browser. You will get a 500 error because the module is missing. +Any other URL, like http://localhost:8080/test, will result in a +404 error. + +=== Handling requests + +Cowboy features different kinds of handlers, including REST +and Websocket handlers. For this tutorial we will use a plain +HTTP handler. + +Generate a handler from a template: + +[source,bash] +$ make new t=cowboy.http n=hello_handler + +Then, open the 'src/hello_handler.erl' file and modify +the `init/2` function like this to send a reply. + +[source,erlang] +---- +init(Req0, State) -> + Req = cowboy_req:reply(200, + #{<<"content-type">> => <<"text/plain">>}, + <<"Hello Erlang!">>, + Req0), + {ok, Req, State}. +---- + +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 run the release and open http://localhost:8080 +in your browser, you should get a nice `Hello Erlang!` displayed! diff --git a/docs/en/cowboy/2.2/guide/getting_started/index.html b/docs/en/cowboy/2.2/guide/getting_started/index.html new file mode 100644 index 00000000..5aaedfee --- /dev/null +++ b/docs/en/cowboy/2.2/guide/getting_started/index.html @@ -0,0 +1,320 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Getting started</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Getting started</span></h1> + +<div class="paragraph"><p>Erlang is more than a language, it is also an operating system +for your applications. Erlang developers rarely write standalone +modules, they write libraries or applications, and then bundle +those into what is called a release. A release contains the +Erlang VM plus all applications required to run the node, so +it can be pushed to production directly.</p></div> +<div class="paragraph"><p>This chapter walks you through all the steps of setting up +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.</p></div> +<div class="sect1"> +<h2 id="_prerequisites">Prerequisites</h2> +<div class="sectionbody"> +<div class="paragraph"><p>We are going to use the <a href="https://github.com/ninenines/erlang.mk">Erlang.mk</a> +build system. If you are using Windows, please check the +<a href="http://erlang.mk/guide/installation.html">Installation instructions</a> +to get your environment setup before you continue.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_bootstrap">Bootstrap</h2> +<div class="sectionbody"> +<div class="paragraph"><p>First, let’s create the directory for our application.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>$ mkdir hello_erlang +$ cd hello_erlang</tt></pre></div></div> +<div class="paragraph"><p>Then we need to download Erlang.mk. Either use the following +command or download it manually.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>$ wget https<span style="color: #990000">:</span>//erlang<span style="color: #990000">.</span>mk/erlang<span style="color: #990000">.</span>mk</tt></pre></div></div> +<div class="paragraph"><p>We can now bootstrap our application. Since we are going to generate +a release, we will also bootstrap it at the same time.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>$ make -f erlang<span style="color: #990000">.</span>mk bootstrap bootstrap-rel</tt></pre></div></div> +<div class="paragraph"><p>This creates a Makefile, a base application, and the release files +necessary for creating the release. We can already build and start +this release.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>$ make run +<span style="color: #990000">...</span> +<span style="color: #990000">(</span>hello_erlang@<span style="color: #993399">127.0</span><span style="color: #990000">.</span><span style="color: #993399">0.1</span><span style="color: #990000">)</span><span style="color: #993399">1</span><span style="color: #990000">></span></tt></pre></div></div> +<div class="paragraph"><p>Entering the command <code>i().</code> will show the running processes, including +one called <code>hello_erlang_sup</code>. This is the supervisor for our +application.</p></div> +<div class="paragraph"><p>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.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_cowboy_setup">Cowboy setup</h2> +<div class="sectionbody"> +<div class="paragraph"><p>We will modify the <em>Makefile</em> to tell the build system it needs to +fetch and compile Cowboy:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">PROJECT =</span> hello_erlang + +<span style="color: #009900">DEPS =</span> cowboy +<span style="color: #009900">dep_cowboy_commit =</span> 2.1.0 + +<span style="color: #009900">DEP_PLUGINS =</span> cowboy + +include erlang.mk</tt></pre></div></div> +<div class="paragraph"><p>We also tell the build system to load the plugins Cowboy provides. +These include predefined templates that we will use soon.</p></div> +<div class="paragraph"><p>If you do <code>make run</code> 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.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_listening_for_connections">Listening for connections</h2> +<div class="sectionbody"> +<div class="paragraph"><p>First we define the routes that Cowboy will use to map requests +to handler modules, and then we start the listener. This is best +done at application startup.</p></div> +<div class="paragraph"><p>Open the <em>src/hello_erlang_app.erl</em> file and add the necessary +code to the <code>start/2</code> function to make it look like this:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">start</span></span>(<span style="color: #009900">_Type</span>, <span style="color: #009900">_Args</span>) <span style="color: #990000">-></span> + <span style="color: #009900">Dispatch</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_router:compile</span></span>([ + {<span style="color: #FF6600">'_'</span>, [{<span style="color: #FF0000">"/"</span>, <span style="color: #FF6600">hello_handler</span>, []}]} + ]), + {<span style="color: #FF6600">ok</span>, <span style="color: #990000">_</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy:start_clear</span></span>(<span style="color: #FF6600">my_http_listener</span>, + [{<span style="color: #FF6600">port</span>, <span style="color: #993399">8080</span>}], + #{<span style="color: #0000FF">env</span> <span style="color: #990000">=></span> #{<span style="color: #0000FF">dispatch</span> <span style="color: #990000">=></span> <span style="color: #009900">Dispatch</span>}} + ), + <span style="font-weight: bold"><span style="color: #000000">hello_erlang_sup:start_link</span></span>()<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Routes are explained in details in the <a href="../routing">Routing</a> +chapter. For this tutorial we map the path <code>/</code> to the handler +module <code>hello_handler</code>. This module doesn’t exist yet.</p></div> +<div class="paragraph"><p>Build and start the release, then open <a href="http://localhost:8080">http://localhost:8080</a> +in your browser. You will get a 500 error because the module is missing. +Any other URL, like <a href="http://localhost:8080/test">http://localhost:8080/test</a>, will result in a +404 error.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_handling_requests">Handling requests</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy features different kinds of handlers, including REST +and Websocket handlers. For this tutorial we will use a plain +HTTP handler.</p></div> +<div class="paragraph"><p>Generate a handler from a template:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>$ make new <span style="color: #009900">t</span><span style="color: #990000">=</span>cowboy<span style="color: #990000">.</span>http <span style="color: #009900">n</span><span style="color: #990000">=</span>hello_handler</tt></pre></div></div> +<div class="paragraph"><p>Then, open the <em>src/hello_handler.erl</em> file and modify +the <code>init/2</code> function like this to send a reply.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req0</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + <span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:reply</span></span>(<span style="color: #993399">200</span>, + #{<span style="color: #990000"><<</span><span style="color: #FF0000">"content-type"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"text/plain"</span><span style="color: #990000">>></span>}, + <span style="color: #990000"><<</span><span style="color: #FF0000">"Hello Erlang!"</span><span style="color: #990000">>></span>, + <span style="color: #009900">Req0</span>), + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>What the above code does is send a 200 OK reply, with the +Content-type header set to <code>text/plain</code> and the response +body set to <code>Hello Erlang!</code>.</p></div> +<div class="paragraph"><p>If you run the release and open <a href="http://localhost:8080">http://localhost:8080</a> +in your browser, you should get a nice <code>Hello Erlang!</code> displayed!</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/introduction/"> + Introduction + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/flow_diagram/"> + Flow diagram + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/handlers.asciidoc b/docs/en/cowboy/2.2/guide/handlers.asciidoc new file mode 100644 index 00000000..fe6f4623 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/handlers.asciidoc @@ -0,0 +1,90 @@ +[[handlers]] +== Handlers + +Handlers are Erlang modules that handle HTTP requests. + +=== Plain HTTP handlers + +The most basic handler in Cowboy implements the mandatory +`init/2` callback, manipulates the request, optionally +sends a response and then returns. + +This callback receives the xref:req[Req object] and the initial +state defined in the xref:routing[router configuration]. + +A handler that does nothing would look like this: + +[source,erlang] +---- +init(Req, State) -> + {ok, Req, State}. +---- + +Despite sending no reply, a `204 No Content` response will be +sent to the client, as Cowboy makes sure that a response is +sent for every request. + +We need to use the Req object to reply. + +[source,erlang] +---- +init(Req0, State) -> + Req = cowboy_req:reply(200, #{ + <<"content-type">> => <<"text/plain">> + }, <<"Hello World!">>, Req0), + {ok, Req, State}. +---- + +Cowboy will immediately send a response when `cowboy:reply/4` +is called. + +We then return a 3-tuple. `ok` means that the handler ran +successfully. We also give the modified Req back to Cowboy. + +The last value of the tuple is a state that will be used +in every subsequent callbacks to this handler. Plain HTTP +handlers only have one additional callback, the optional +and rarely used `terminate/3`. + +=== Other handlers + +The `init/2` callback can also be used to inform Cowboy +that this is a different kind of handler and that Cowboy +should switch to it. To do this you simply need to return +the module name of the handler type you want to switch to. + +Cowboy comes with three handler types you can switch to: +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: + +[source,erlang] +---- +init(Req, State) -> + {cowboy_websocket, Req, State}. +---- + +=== Cleaning up + +All handler types provide the optional `terminate/3` callback. + +[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 +other return value. + +This callback is optional because it is rarely necessary. +Cleanup should be done in separate processes directly (by +monitoring the handler process to detect when it exits). + +Cowboy does not reuse processes for different requests. The +process will terminate soon after this call returns. diff --git a/docs/en/cowboy/2.2/guide/handlers/index.html b/docs/en/cowboy/2.2/guide/handlers/index.html new file mode 100644 index 00000000..cdfbf6dd --- /dev/null +++ b/docs/en/cowboy/2.2/guide/handlers/index.html @@ -0,0 +1,250 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Handlers</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Handlers</span></h1> + +<div class="paragraph"><p>Handlers are Erlang modules that handle HTTP requests.</p></div> +<div class="sect1"> +<h2 id="_plain_http_handlers">Plain HTTP handlers</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The most basic handler in Cowboy implements the mandatory +<code>init/2</code> callback, manipulates the request, optionally +sends a response and then returns.</p></div> +<div class="paragraph"><p>This callback receives the <a href="../req">Req object</a> and the initial +state defined in the <a href="../routing">router configuration</a>.</p></div> +<div class="paragraph"><p>A handler that does nothing would look like this:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Despite sending no reply, a <code>204 No Content</code> response will be +sent to the client, as Cowboy makes sure that a response is +sent for every request.</p></div> +<div class="paragraph"><p>We need to use the Req object to reply.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req0</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + <span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:reply</span></span>(<span style="color: #993399">200</span>, #{ + <span style="color: #990000"><<</span><span style="color: #FF0000">"content-type"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"text/plain"</span><span style="color: #990000">>></span> + }, <span style="color: #990000"><<</span><span style="color: #FF0000">"Hello World!"</span><span style="color: #990000">>></span>, <span style="color: #009900">Req0</span>), + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Cowboy will immediately send a response when <code>cowboy:reply/4</code> +is called.</p></div> +<div class="paragraph"><p>We then return a 3-tuple. <code>ok</code> means that the handler ran +successfully. We also give the modified Req back to Cowboy.</p></div> +<div class="paragraph"><p>The last value of the tuple is a state that will be used +in every subsequent callbacks to this handler. Plain HTTP +handlers only have one additional callback, the optional +and rarely used <code>terminate/3</code>.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_other_handlers">Other handlers</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The <code>init/2</code> callback can also be used to inform Cowboy +that this is a different kind of handler and that Cowboy +should switch to it. To do this you simply need to return +the module name of the handler type you want to switch to.</p></div> +<div class="paragraph"><p>Cowboy comes with three handler types you can switch to: +<a href="../rest_handlers">cowboy_rest</a>, <a href="#ws_handlers">cowboy_websocket</a> +and <a href="../loop_handlers">cowboy_loop</a>. In addition to those you +can define your own handler types.</p></div> +<div class="paragraph"><p>Switching is simple. Instead of returning <code>ok</code>, you simply +return the name of the handler type you want to use. The +following snippet switches to a Websocket handler:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">cowboy_websocket</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_cleaning_up">Cleaning up</h2> +<div class="sectionbody"> +<div class="paragraph"><p>All handler types provide the optional <code>terminate/3</code> callback.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">terminate</span></span>(<span style="color: #009900">_Reason</span>, <span style="color: #009900">_Req</span>, <span style="color: #009900">_State</span>) <span style="color: #990000">-></span> + <span style="color: #FF6600">ok</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>This callback is strictly reserved for any required cleanup. +You cannot send a response from this function. There is no +other return value.</p></div> +<div class="paragraph"><p>This callback is optional because it is rarely necessary. +Cleanup should be done in separate processes directly (by +monitoring the handler process to detect when it exits).</p></div> +<div class="paragraph"><p>Cowboy does not reuse processes for different requests. The +process will terminate soon after this call returns.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/constraints/"> + Constraints + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/loop_handlers/"> + Loop handlers + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/http_req_resp.png b/docs/en/cowboy/2.2/guide/http_req_resp.png Binary files differnew file mode 100644 index 00000000..41c17c8a --- /dev/null +++ b/docs/en/cowboy/2.2/guide/http_req_resp.png diff --git a/docs/en/cowboy/2.2/guide/http_req_resp.svg b/docs/en/cowboy/2.2/guide/http_req_resp.svg new file mode 100644 index 00000000..acedb152 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/http_req_resp.svg @@ -0,0 +1,543 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + version="1.1" + inkscape:version="0.92.1 r" + sodipodi:docname="http_req_resp.svg" + inkscape:export-filename="/home/essen/Dropbox/Public/drawing.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs4"> + <linearGradient + id="linearGradient5265"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5267" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.58823532;" + offset="1" + id="stop5269" /> + </linearGradient> + <linearGradient + id="linearGradient5251"> + <stop + style="stop-color:#69d2e7;stop-opacity:0.78431374;" + offset="0" + id="stop5253" /> + <stop + id="stop5263" + offset="0.5" + style="stop-color:#69d2e7;stop-opacity:1;" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.39215687;" + offset="1" + id="stop5255" /> + </linearGradient> + <linearGradient + id="linearGradient5233" + osb:paint="solid"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5235" /> + </linearGradient> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="1" + inkscape:pageshadow="2" + inkscape:zoom="1.4142136" + inkscape:cx="172.08527" + inkscape:cy="762.31079" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="1920" + inkscape:window-height="1043" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:snap-global="true" + showguides="true"> + <inkscape:grid + type="xygrid" + id="grid5357" + empspacing="5" + visible="true" + enabled="true" + snapvisiblegridlinesonly="true" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <g + transform="translate(193.54707,-32.134105)" + id="g5650-5-0"> + <path + inkscape:connector-curvature="0" + id="path5570-3-9" + d="m -57.78256,351.41962 v 52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-5-3" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + sodipodi:type="star" /> + </g> + <g + transform="rotate(180,50.658226,375.46461)" + id="g5650-6-6"> + <path + inkscape:connector-curvature="0" + id="path5570-2-0" + d="m -57.78256,351.41962 v 52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9-6" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + sodipodi:type="star" /> + </g> + <g + transform="translate(193.54707,-119.75468)" + id="g5650-5"> + <path + inkscape:connector-curvature="0" + id="path5570-3" + d="m -57.78256,351.41962 v 52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-5" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + sodipodi:type="star" /> + </g> + <g + transform="rotate(180,50.658226,331.65432)" + id="g5650-6"> + <path + inkscape:connector-curvature="0" + id="path5570-2" + d="m -57.78256,351.41962 v 52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + sodipodi:type="star" /> + </g> + <rect + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:2.44279909;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect5367" + width="207.05719" + height="171.55719" + x="43.721401" + y="384.1973" + rx="11.072577" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <use + x="0" + y="0" + xlink:href="#g5650" + id="use5654" + transform="translate(205.03261,76.66371)" + width="744.09448" + height="1052.3622" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + id="use5660" + transform="translate(205.03261,-207.5)"> + <path + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m -57.78256,351.41962 0,52.3259" + id="path3051" + inkscape:connector-curvature="0" /> + <path + sodipodi:type="star" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="path3053" + sodipodi:sides="3" + sodipodi:cx="-222.73865" + sodipodi:cy="415.25897" + sodipodi:r1="14.849242" + sodipodi:r2="7.4246211" + sodipodi:arg1="1.5707963" + sodipodi:arg2="2.6179939" + inkscape:flatsided="true" + inkscape:rounded="0" + inkscape:randomized="0" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:transform-center-y="2.1823437" + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" /> + </g> + <use + x="0" + y="0" + xlink:href="#use5660" + id="use5662" + transform="translate(0,-86.562562)" + width="744.09448" + height="1052.3622" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + id="g5650"> + <path + inkscape:connector-curvature="0" + id="path5570" + d="m -57.78256,351.41962 0,52.3259" + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;opacity:0.8" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576" + style="fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;opacity:0.8" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273" + width="104.5895" + height="36.392323" + x="-224.02068" + y="29.41218" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7" + width="104.5895" + height="36.392323" + x="-224.02068" + y="90.691978" + rx="15" /> + <rect + style="fill:#ffc48c;fill-opacity:1;fill-rule:nonzero;stroke:#d79c64;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-2" + width="104.5895" + height="36.392323" + x="-224.02068" + y="151.97169" + rx="15" /> + <rect + style="fill:#ff9f80;fill-opacity:1;fill-rule:nonzero;stroke:#d77758;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-22" + width="104.5895" + height="36.392323" + x="-224.02068" + y="213.25146" + rx="15" /> + <rect + style="fill:#f56991;fill-opacity:1;fill-rule:nonzero;stroke:#cd4169;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-8" + width="104.5895" + height="36.392323" + x="-224.02068" + y="274.53128" + rx="15" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="-58.692513" + y="114.39204" + id="text5371"><tspan + sodipodi:role="line" + id="tspan5373" + x="-58.692513" + y="114.39204" + style="font-size:16px;line-height:1.25;font-family:sans-serif">some text</tspan></text> + <g + id="g3850"> + <use + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + height="1052.3622" + width="744.09448" + transform="translate(318.97597,32.837526)" + id="use5359" + xlink:href="#rect5273-7" + y="0" + x="0" /> + <a + id="a3826"> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="146.77739" + y="145.67879" + id="text5371-7" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3" + x="146.77739" + y="145.67879" + style="font-size:16px;line-height:1.25;font-family:sans-serif">acceptor</tspan></text> + </a> + </g> + <g + id="g3860"> + <use + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + height="1052.3622" + width="744.09448" + transform="translate(1.630859e-6,86.777953)" + id="use5361" + xlink:href="#use5359" + y="0" + x="0" /> + <text + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + id="text5371-74" + y="232.91768" + x="147.26958" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + xml:space="preserve"><tspan + id="tspan3770" + style="font-size:16px;line-height:1.25;font-family:sans-serif" + y="232.91768" + x="147.26958" + sodipodi:role="line">protocol</tspan></text> + </g> + <g + id="g3904"> + <use + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + height="1052.3622" + width="744.09448" + transform="translate(0,197.08458)" + id="use5365" + xlink:href="#use5361" + y="0" + x="0" /> + <text + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + id="text5371-5" + y="431.0921" + x="146.53125" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + xml:space="preserve"><tspan + style="font-size:16px;line-height:1.25;font-family:sans-serif" + y="431.0921" + x="146.53125" + id="tspan5373-0" + sodipodi:role="line">router</tspan></text> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="-58.692513" + y="53.112247" + id="text5371-2"><tspan + sodipodi:role="line" + id="tspan5373-6" + x="-58.692513" + y="53.112247" + style="font-size:16px;line-height:1.25;font-family:sans-serif">some text</tspan></text> + <g + id="g3909"> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="use5363" + width="104.5895" + height="36.392323" + x="94.955292" + y="494.37244" + rx="15" /> + <text + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + id="text5371-2-3-0" + y="518.38519" + x="146.53125" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + xml:space="preserve"><tspan + style="font-size:16px;line-height:1.25;font-family:sans-serif" + y="518.38519" + x="146.53125" + id="tspan5373-6-7-3" + sodipodi:role="line">handler</tspan></text> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="-470.30792" + y="63.078125" + id="text5371-2-3-0-7" + transform="rotate(-90)" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7-3-9" + x="-470.30792" + y="63.078125" + style="font-size:16px;line-height:1.25;font-family:sans-serif">middlewares</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="-58.692513" + y="236.95154" + id="text5371-4"><tspan + sodipodi:role="line" + id="tspan5373-9" + x="-58.692513" + y="236.95154" + style="font-size:16px;line-height:1.25;font-family:sans-serif">some text</tspan></text> + <g + id="g3855"> + <use + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + height="1052.3622" + width="744.09448" + transform="translate(318.97592,-176.5)" + id="use5355" + xlink:href="#rect5273-22" + y="0" + x="0" /> + <text + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + id="text5371-4-0" + y="60.912468" + x="147.00391" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + xml:space="preserve"><tspan + style="font-size:16px;line-height:1.25;font-family:sans-serif" + y="60.912468" + x="147.00391" + id="tspan5373-9-2" + sodipodi:role="line">client</tspan></text> + </g> + <g + id="g3865"> + <rect + rx="15" + y="297.08545" + x="94.955299" + height="36.392323" + width="104.5895" + id="rect5273-3" + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> + <text + id="text5371-2-6" + y="320.78552" + x="147.50005" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + xml:space="preserve"><tspan + style="font-size:16px;line-height:1.25;font-family:sans-serif" + y="320.78552" + x="147.50005" + id="tspan5373-6-7" + sodipodi:role="line">stream</tspan></text> + </g> + </g> +</svg> diff --git a/docs/en/cowboy/2.2/guide/index.html b/docs/en/cowboy/2.2/guide/index.html new file mode 100644 index 00000000..fb888525 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/index.html @@ -0,0 +1,346 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Cowboy User Guide</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Cowboy User Guide</span></h1> + +<div class="sect1"> +<h2 id="_rationale">Rationale</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +<a href="modern_web/">The modern Web</a> +</p> +</li> +<li> +<p> +<a href="erlang_web/">Erlang and the Web</a> +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_introduction">Introduction</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +<a href="introduction/">Introduction</a> +</p> +</li> +<li> +<p> +<a href="getting_started/">Getting started</a> +</p> +</li> +<li> +<p> +<a href="flow_diagram/">Flow diagram</a> +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_configuration">Configuration</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +<a href="listeners/">Listeners</a> +</p> +</li> +<li> +<p> +<a href="routing/">Routing</a> +</p> +</li> +<li> +<p> +<a href="constraints/">Constraints</a> +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_handlers">Handlers</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +<a href="handlers/">Handlers</a> +</p> +</li> +<li> +<p> +<a href="loop_handlers/">Loop handlers</a> +</p> +</li> +<li> +<p> +<a href="static_files/">Static files</a> +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_request_and_response">Request and response</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +<a href="req/">Request details</a> +</p> +</li> +<li> +<p> +<a href="req_body/">Reading the request body</a> +</p> +</li> +<li> +<p> +<a href="resp/">Sending a response</a> +</p> +</li> +<li> +<p> +<a href="cookies/">Using cookies</a> +</p> +</li> +<li> +<p> +<a href="multipart/">Multipart</a> +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_rest">REST</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +<a href="rest_principles/">REST principles</a> +</p> +</li> +<li> +<p> +<a href="rest_handlers/">Handling REST requests</a> +</p> +</li> +<li> +<p> +<a href="rest_flowcharts/">REST flowcharts</a> +</p> +</li> +<li> +<p> +<a href="resource_design/">Designing a resource handler</a> +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_websocket">Websocket</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +<a href="ws_protocol/">The Websocket protocol</a> +</p> +</li> +<li> +<p> +<a href="ws_handlers/">Websocket handlers</a> +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_advanced">Advanced</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +<a href="streams/">Streams</a> +</p> +</li> +<li> +<p> +<a href="middlewares/">Middlewares</a> +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_additional_information">Additional information</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +<a href="migrating_from_2.1/">Migrating from Cowboy 2.1 to 2.2</a> +</p> +</li> +<li> +<p> +<a href="migrating_from_2.0/">Migrating from Cowboy 2.0 to 2.1</a> +</p> +</li> +<li> +<p> +<a href="migrating_from_1.0/">Migrating from Cowboy 1.0 to 2.0</a> +</p> +</li> +<li> +<p> +<a href="specs/">HTTP and other specifications</a> +</p> +</li> +</ul></div> +</div> +</div> + + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/introduction.asciidoc b/docs/en/cowboy/2.2/guide/introduction.asciidoc new file mode 100644 index 00000000..1f9b52e4 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/introduction.asciidoc @@ -0,0 +1,75 @@ +[[introduction]] +== Introduction + +Cowboy is a small, fast and modern HTTP server for Erlang/OTP. + +Cowboy aims to provide a complete xref:modern_web[modern Web stack]. +This includes HTTP/1.1, HTTP/2, Websocket, Server-Sent Events and +Webmachine-based REST. + +Cowboy comes with functions for introspection and tracing, enabling +developers to know precisely what is happening at any time. Its modular +design also easily enable developers to add instrumentation. + +Cowboy is a high quality project. It has a small code base, is very +efficient (both in latency and memory use) and can easily be embedded +in another application. + +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 a Function Reference, a User Guide and numerous Tutorials. + +=== 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 + +Cowboy is tested and supported on Linux, FreeBSD, Windows and OSX. + +Cowboy has been reported to work on other platforms, but we make no +guarantee that the experience will be safe and smooth. You are advised +to perform the necessary testing and security audits prior to deploying +on other platforms. + +Cowboy is developed for Erlang/OTP 19.0 and newer. + +=== License + +Cowboy uses the ISC License. + +---- +Copyright (c) 2011-2017, Loïc Hoguin <[email protected]> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +---- + +=== Versioning + +Cowboy uses http://semver.org/[Semantic Versioning 2.0.0]. + +=== Conventions + +In the HTTP protocol, the method name is case sensitive. All standard +method names are uppercase. + +Header names are case insensitive. When using HTTP/1.1, Cowboy converts +all the request header names to lowercase. HTTP/2 requires clients to +send them as lowercase. Any other header name is expected to be provided +lowercased, including when querying information about the request or +when sending responses. + +The same applies to any other case insensitive value. diff --git a/docs/en/cowboy/2.2/guide/introduction/index.html b/docs/en/cowboy/2.2/guide/introduction/index.html new file mode 100644 index 00000000..e5eb5e2c --- /dev/null +++ b/docs/en/cowboy/2.2/guide/introduction/index.html @@ -0,0 +1,238 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Introduction</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Introduction</span></h1> + +<div class="paragraph"><p>Cowboy is a small, fast and modern HTTP server for Erlang/OTP.</p></div> +<div class="paragraph"><p>Cowboy aims to provide a complete <a href="../modern_web">modern Web stack</a>. +This includes HTTP/1.1, HTTP/2, Websocket, Server-Sent Events and +Webmachine-based REST.</p></div> +<div class="paragraph"><p>Cowboy comes with functions for introspection and tracing, enabling +developers to know precisely what is happening at any time. Its modular +design also easily enable developers to add instrumentation.</p></div> +<div class="paragraph"><p>Cowboy is a high quality project. It has a small code base, is very +efficient (both in latency and memory use) and can easily be embedded +in another application.</p></div> +<div class="paragraph"><p>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 a Function Reference, a User Guide and numerous Tutorials.</p></div> +<div class="sect1"> +<h2 id="_prerequisites">Prerequisites</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Beginner Erlang knowledge is recommended for reading this guide.</p></div> +<div class="paragraph"><p>Knowledge of the HTTP protocol is recommended but not required, as it +will be detailed throughout the guide.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_supported_platforms">Supported platforms</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy is tested and supported on Linux, FreeBSD, Windows and OSX.</p></div> +<div class="paragraph"><p>Cowboy has been reported to work on other platforms, but we make no +guarantee that the experience will be safe and smooth. You are advised +to perform the necessary testing and security audits prior to deploying +on other platforms.</p></div> +<div class="paragraph"><p>Cowboy is developed for Erlang/OTP 19.0 and newer.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_license">License</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy uses the ISC License.</p></div> +<div class="listingblock"> +<div class="content"> +<pre><code>Copyright (c) 2011-2017, Loïc Hoguin <[email protected]> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.</code></pre> +</div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_versioning">Versioning</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy uses <a href="http://semver.org/">Semantic Versioning 2.0.0</a>.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_conventions">Conventions</h2> +<div class="sectionbody"> +<div class="paragraph"><p>In the HTTP protocol, the method name is case sensitive. All standard +method names are uppercase.</p></div> +<div class="paragraph"><p>Header names are case insensitive. When using HTTP/1.1, Cowboy converts +all the request header names to lowercase. HTTP/2 requires clients to +send them as lowercase. Any other header name is expected to be provided +lowercased, including when querying information about the request or +when sending responses.</p></div> +<div class="paragraph"><p>The same applies to any other case insensitive value.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/erlang_web/"> + Erlang and the Web + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/getting_started/"> + Getting started + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/listeners.asciidoc b/docs/en/cowboy/2.2/guide/listeners.asciidoc new file mode 100644 index 00000000..10ac4aad --- /dev/null +++ b/docs/en/cowboy/2.2/guide/listeners.asciidoc @@ -0,0 +1,115 @@ +[[listeners]] +== Listeners + +A listener is a set of processes that listens on a port for +new connections. Incoming connections get handled by Cowboy. +Depending on the connection handshake, one or another protocol +may be used. + +This chapter is specific to Cowboy. Please refer to the +https://ninenines.eu/docs/en/ranch/1.3/guide/listeners/[Ranch User Guide] +for more information about listeners. + +Cowboy provides two types of listeners: one listening for +clear TCP connections, and one listening for secure TLS +connections. Both of them support the HTTP/1.1 and HTTP/2 +protocols. + +=== Clear TCP listener + +The clear TCP listener will accept connections on the +given port. A typical HTTP server would listen on port 80. +Port 80 requires special permissions on most platforms +however so a common alternative is port 8080. + +The following snippet starts listening for connections +on port 8080: + +[source,erlang] +---- +start(_Type, _Args) -> + Dispatch = cowboy_router:compile([ + {'_', [{"/", hello_handler, []}]} + ]), + {ok, _} = cowboy:start_clear(my_http_listener, + [{port, 8080}], + #{env => #{dispatch => Dispatch}} + ), + hello_erlang_sup:start_link(). +---- + +The xref:getting_started[Getting Started] chapter uses a +clear TCP listener. + +Clients connecting to Cowboy on the clear listener port are +expected to use either HTTP/1.1 or HTTP/2. + +Cowboy supports both methods of initiating a clear +HTTP/2 connection: through the Upgrade mechanism +(https://tools.ietf.org/html/rfc7540#section-3.2[RFC 7540 3.2]) +or by sending the preface directly +(https://tools.ietf.org/html/rfc7540#section-3.4[RFC 7540 3.4]). + +Compatibility with HTTP/1.0 is provided by Cowboy's HTTP/1.1 +implementation. + +=== Secure TLS listener + +The secure TLS listener will accept connections on the +given port. A typical HTTPS server would listen on port 443. +Port 443 requires special permissions on most platforms +however so a common alternative is port 8443. + +// @todo Make a complete list of restrictions. + +The function provided by Cowboy will ensure that the TLS +options given are following the HTTP/2 RFC with regards +to security. For example some TLS extensions or ciphers +may be disabled. This also applies to HTTP/1.1 connections +on this listener. If this is not desirable, Ranch can be +used directly to setup a custom listener. + +[source,erlang] +---- +start(_Type, _Args) -> + Dispatch = cowboy_router:compile([ + {'_', [{"/", hello_handler, []}]} + ]), + {ok, _} = cowboy:start_tls(my_http_listener, + [ + {port, 8443}, + {certfile, "/path/to/certfile"}, + {keyfile, "/path/to/keyfile"} + ], + #{env => #{dispatch => Dispatch}} + ), + hello_erlang_sup:start_link(). +---- + +Clients connecting to Cowboy on the secure listener are +expected to use the ALPN TLS extension to indicate what +protocols they understand. Cowboy always prefers HTTP/2 +over HTTP/1.1 when both are supported. When neither are +supported by the client, or when the ALPN extension was +missing, Cowboy expects HTTP/1.1 to be used. + +Cowboy also advertises HTTP/2 support through the older +NPN TLS extension for compatibility. Note however that +this support will likely not be enabled by default when +Cowboy 2.0 gets released. + +Compatibility with HTTP/1.0 is provided by Cowboy's HTTP/1.1 +implementation. + +=== Protocol configuration + +The HTTP/1.1 and HTTP/2 protocols share the same semantics; +only their framing differs. The first is a text protocol and +the second a binary protocol. + +Cowboy doesn't separate the configuration for HTTP/1.1 and +HTTP/2. Everything goes into the same map. Many options are +shared. + +// @todo Describe good to know options for both protocols? +// Maybe do that in separate chapters? diff --git a/docs/en/cowboy/2.2/guide/listeners/index.html b/docs/en/cowboy/2.2/guide/listeners/index.html new file mode 100644 index 00000000..68a2097f --- /dev/null +++ b/docs/en/cowboy/2.2/guide/listeners/index.html @@ -0,0 +1,268 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Listeners</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Listeners</span></h1> + +<div class="paragraph"><p>A listener is a set of processes that listens on a port for +new connections. Incoming connections get handled by Cowboy. +Depending on the connection handshake, one or another protocol +may be used.</p></div> +<div class="paragraph"><p>This chapter is specific to Cowboy. Please refer to the +<a href="https://ninenines.eu/docs/en/ranch/1.3/guide/listeners/">Ranch User Guide</a> +for more information about listeners.</p></div> +<div class="paragraph"><p>Cowboy provides two types of listeners: one listening for +clear TCP connections, and one listening for secure TLS +connections. Both of them support the HTTP/1.1 and HTTP/2 +protocols.</p></div> +<div class="sect1"> +<h2 id="_clear_tcp_listener">Clear TCP listener</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The clear TCP listener will accept connections on the +given port. A typical HTTP server would listen on port 80. +Port 80 requires special permissions on most platforms +however so a common alternative is port 8080.</p></div> +<div class="paragraph"><p>The following snippet starts listening for connections +on port 8080:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">start</span></span>(<span style="color: #009900">_Type</span>, <span style="color: #009900">_Args</span>) <span style="color: #990000">-></span> + <span style="color: #009900">Dispatch</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_router:compile</span></span>([ + {<span style="color: #FF6600">'_'</span>, [{<span style="color: #FF0000">"/"</span>, <span style="color: #FF6600">hello_handler</span>, []}]} + ]), + {<span style="color: #FF6600">ok</span>, <span style="color: #990000">_</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy:start_clear</span></span>(<span style="color: #FF6600">my_http_listener</span>, + [{<span style="color: #FF6600">port</span>, <span style="color: #993399">8080</span>}], + #{<span style="color: #0000FF">env</span> <span style="color: #990000">=></span> #{<span style="color: #0000FF">dispatch</span> <span style="color: #990000">=></span> <span style="color: #009900">Dispatch</span>}} + ), + <span style="font-weight: bold"><span style="color: #000000">hello_erlang_sup:start_link</span></span>()<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>The <a href="../getting_started">Getting Started</a> chapter uses a +clear TCP listener.</p></div> +<div class="paragraph"><p>Clients connecting to Cowboy on the clear listener port are +expected to use either HTTP/1.1 or HTTP/2.</p></div> +<div class="paragraph"><p>Cowboy supports both methods of initiating a clear +HTTP/2 connection: through the Upgrade mechanism +(<a href="https://tools.ietf.org/html/rfc7540#section-3.2">RFC 7540 3.2</a>) +or by sending the preface directly +(<a href="https://tools.ietf.org/html/rfc7540#section-3.4">RFC 7540 3.4</a>).</p></div> +<div class="paragraph"><p>Compatibility with HTTP/1.0 is provided by Cowboy’s HTTP/1.1 +implementation.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_secure_tls_listener">Secure TLS listener</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The secure TLS listener will accept connections on the +given port. A typical HTTPS server would listen on port 443. +Port 443 requires special permissions on most platforms +however so a common alternative is port 8443.</p></div> +<div class="paragraph"><p>The function provided by Cowboy will ensure that the TLS +options given are following the HTTP/2 RFC with regards +to security. For example some TLS extensions or ciphers +may be disabled. This also applies to HTTP/1.1 connections +on this listener. If this is not desirable, Ranch can be +used directly to setup a custom listener.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">start</span></span>(<span style="color: #009900">_Type</span>, <span style="color: #009900">_Args</span>) <span style="color: #990000">-></span> + <span style="color: #009900">Dispatch</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_router:compile</span></span>([ + {<span style="color: #FF6600">'_'</span>, [{<span style="color: #FF0000">"/"</span>, <span style="color: #FF6600">hello_handler</span>, []}]} + ]), + {<span style="color: #FF6600">ok</span>, <span style="color: #990000">_</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy:start_tls</span></span>(<span style="color: #FF6600">my_http_listener</span>, + [ + {<span style="color: #FF6600">port</span>, <span style="color: #993399">8443</span>}, + {<span style="color: #FF6600">certfile</span>, <span style="color: #FF0000">"/path/to/certfile"</span>}, + {<span style="color: #FF6600">keyfile</span>, <span style="color: #FF0000">"/path/to/keyfile"</span>} + ], + #{<span style="color: #0000FF">env</span> <span style="color: #990000">=></span> #{<span style="color: #0000FF">dispatch</span> <span style="color: #990000">=></span> <span style="color: #009900">Dispatch</span>}} + ), + <span style="font-weight: bold"><span style="color: #000000">hello_erlang_sup:start_link</span></span>()<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Clients connecting to Cowboy on the secure listener are +expected to use the ALPN TLS extension to indicate what +protocols they understand. Cowboy always prefers HTTP/2 +over HTTP/1.1 when both are supported. When neither are +supported by the client, or when the ALPN extension was +missing, Cowboy expects HTTP/1.1 to be used.</p></div> +<div class="paragraph"><p>Cowboy also advertises HTTP/2 support through the older +NPN TLS extension for compatibility. Note however that +this support will likely not be enabled by default when +Cowboy 2.0 gets released.</p></div> +<div class="paragraph"><p>Compatibility with HTTP/1.0 is provided by Cowboy’s HTTP/1.1 +implementation.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_protocol_configuration">Protocol configuration</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The HTTP/1.1 and HTTP/2 protocols share the same semantics; +only their framing differs. The first is a text protocol and +the second a binary protocol.</p></div> +<div class="paragraph"><p>Cowboy doesn’t separate the configuration for HTTP/1.1 and +HTTP/2. Everything goes into the same map. Many options are +shared.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/flow_diagram/"> + Flow diagram + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/routing/"> + Routing + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/loop_handlers.asciidoc b/docs/en/cowboy/2.2/guide/loop_handlers.asciidoc new file mode 100644 index 00000000..21bf8424 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/loop_handlers.asciidoc @@ -0,0 +1,128 @@ +[[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 +a receive loop waiting for the right message before it can send +a response. + +Loop handlers are used for requests where a response might not +be immediately available, but where you would like to keep the +connection open for a while in case the response arrives. The +most known example of such practice is known as long polling. + +Loop handlers can also be used for requests where a response is +partially available and you need to stream the response body +while the connection is open. The most known example of such +practice is server-sent events. + +While the same can be accomplished using plain HTTP handlers, +it is recommended to use loop handlers because they are well-tested +and allow using built-in features like hibernation and timeouts. + +Loop handlers essentially wait for one or more Erlang messages +and feed these messages to the `info/3` callback. It also features +the `init/2` and `terminate/3` callbacks which work the same as +for plain HTTP handlers. + +=== Initialization + +The `init/2` function must return a `cowboy_loop` tuple to enable +loop handler behavior. This tuple may optionally contain +a timeout value and/or the atom `hibernate` to make the +process enter hibernation until a message is received. + +This snippet enables the loop handler: + +[source,erlang] +---- +init(Req, State) -> + {cowboy_loop, Req, State}. +---- + +This also makes the process hibernate: + +[source,erlang] +---- +init(Req, State) -> + {cowboy_loop, Req, State, hibernate}. +---- + +=== Receive loop + +Once initialized, Cowboy will wait for messages to arrive +in the process' mailbox. When a message arrives, Cowboy +calls the `info/3` function with the message, the Req object +and the handler's state. + +The following snippet sends a reply when it receives a +`reply` message from another process, or waits for another +message otherwise. + +[source,erlang] +---- +info({reply, Body}, Req, State) -> + cowboy_req:reply(200, #{}, Body, Req), + {stop, Req, 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. + +This callback may perform any necessary operation including +sending all or parts of a reply, and will subsequently +return a tuple indicating if more messages are to be expected. + +The callback may also choose to do nothing at all and just +skip the message received. + +If a reply is sent, then the `stop` tuple should be returned. +This will instruct Cowboy to end the request. + +Otherwise an `ok` tuple should be returned. + +=== Streaming loop + +Another common case well suited for loop handlers is +streaming data received in the form of Erlang messages. +This can be done by initiating a chunked reply in the +`init/2` callback and then using `cowboy_req:chunk/2` +every time a message is received. + +The following snippet does exactly that. As you can see +a chunk is sent every time an `event` message is received, +and the loop is stopped by sending an `eof` message. + +[source,erlang] +---- +init(Req, State) -> + Req2 = cowboy_req:stream_reply(200, Req), + {cowboy_loop, Req2, State}. + +info(eof, Req, State) -> + {stop, Req, State}; +info({event, Data}, Req, State) -> + cowboy_req:stream_body(Data, nofin, Req), + {ok, Req, State}; +info(_Msg, Req, State) -> + {ok, Req, State}. +---- + +=== 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 xref:handlers[Handlers chapter] +for general instructions about cleaning up. + +=== Hibernate + +To save memory, you may hibernate the process in between +messages received. This is done by returning the atom +`hibernate` as part of the `loop` tuple callbacks normally +return. Just add the atom at the end and Cowboy will hibernate +accordingly. diff --git a/docs/en/cowboy/2.2/guide/loop_handlers/index.html b/docs/en/cowboy/2.2/guide/loop_handlers/index.html new file mode 100644 index 00000000..db5c4ac3 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/loop_handlers/index.html @@ -0,0 +1,290 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Loop handlers</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Loop handlers</span></h1> + +<div class="paragraph"><p>Loop handlers are a special kind of HTTP handlers used when the +response can not be sent right away. The handler enters instead +a receive loop waiting for the right message before it can send +a response.</p></div> +<div class="paragraph"><p>Loop handlers are used for requests where a response might not +be immediately available, but where you would like to keep the +connection open for a while in case the response arrives. The +most known example of such practice is known as long polling.</p></div> +<div class="paragraph"><p>Loop handlers can also be used for requests where a response is +partially available and you need to stream the response body +while the connection is open. The most known example of such +practice is server-sent events.</p></div> +<div class="paragraph"><p>While the same can be accomplished using plain HTTP handlers, +it is recommended to use loop handlers because they are well-tested +and allow using built-in features like hibernation and timeouts.</p></div> +<div class="paragraph"><p>Loop handlers essentially wait for one or more Erlang messages +and feed these messages to the <code>info/3</code> callback. It also features +the <code>init/2</code> and <code>terminate/3</code> callbacks which work the same as +for plain HTTP handlers.</p></div> +<div class="sect1"> +<h2 id="_initialization">Initialization</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The <code>init/2</code> function must return a <code>cowboy_loop</code> tuple to enable +loop handler behavior. This tuple may optionally contain +a timeout value and/or the atom <code>hibernate</code> to make the +process enter hibernation until a message is received.</p></div> +<div class="paragraph"><p>This snippet enables the loop handler:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">cowboy_loop</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>This also makes the process hibernate:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">cowboy_loop</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>, <span style="color: #FF6600">hibernate</span>}<span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_receive_loop">Receive loop</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Once initialized, Cowboy will wait for messages to arrive +in the process' mailbox. When a message arrives, Cowboy +calls the <code>info/3</code> function with the message, the Req object +and the handler’s state.</p></div> +<div class="paragraph"><p>The following snippet sends a reply when it receives a +<code>reply</code> message from another process, or waits for another +message otherwise.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">info</span></span>({<span style="color: #FF6600">reply</span>, <span style="color: #009900">Body</span>}, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #000000">cowboy_req:reply</span></span>(<span style="color: #993399">200</span>, #{}, <span style="color: #009900">Body</span>, <span style="color: #009900">Req</span>), + {<span style="color: #FF6600">stop</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}; +<span style="font-weight: bold"><span style="color: #000000">info</span></span>(<span style="color: #009900">_Msg</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>, <span style="color: #FF6600">hibernate</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Do note that the <code>reply</code> tuple here may be any message +and is simply an example.</p></div> +<div class="paragraph"><p>This callback may perform any necessary operation including +sending all or parts of a reply, and will subsequently +return a tuple indicating if more messages are to be expected.</p></div> +<div class="paragraph"><p>The callback may also choose to do nothing at all and just +skip the message received.</p></div> +<div class="paragraph"><p>If a reply is sent, then the <code>stop</code> tuple should be returned. +This will instruct Cowboy to end the request.</p></div> +<div class="paragraph"><p>Otherwise an <code>ok</code> tuple should be returned.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_streaming_loop">Streaming loop</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Another common case well suited for loop handlers is +streaming data received in the form of Erlang messages. +This can be done by initiating a chunked reply in the +<code>init/2</code> callback and then using <code>cowboy_req:chunk/2</code> +every time a message is received.</p></div> +<div class="paragraph"><p>The following snippet does exactly that. As you can see +a chunk is sent every time an <code>event</code> message is received, +and the loop is stopped by sending an <code>eof</code> message.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + <span style="color: #009900">Req2</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:stream_reply</span></span>(<span style="color: #993399">200</span>, <span style="color: #009900">Req</span>), + {<span style="color: #FF6600">cowboy_loop</span>, <span style="color: #009900">Req2</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span> + +<span style="font-weight: bold"><span style="color: #000000">info</span></span>(<span style="color: #FF6600">eof</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">stop</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}; +<span style="font-weight: bold"><span style="color: #000000">info</span></span>({<span style="color: #FF6600">event</span>, <span style="color: #009900">Data</span>}, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #000000">cowboy_req:stream_body</span></span>(<span style="color: #009900">Data</span>, <span style="color: #FF6600">nofin</span>, <span style="color: #009900">Req</span>), + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}; +<span style="font-weight: bold"><span style="color: #000000">info</span></span>(<span style="color: #009900">_Msg</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_cleaning_up">Cleaning up</h2> +<div class="sectionbody"> +<div class="paragraph"><p>It is recommended that you set the connection header to +<code>close</code> when replying, as this process may be reused for +a subsequent request.</p></div> +<div class="paragraph"><p>Please refer to the <a href="../handlers">Handlers chapter</a> +for general instructions about cleaning up.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_hibernate">Hibernate</h2> +<div class="sectionbody"> +<div class="paragraph"><p>To save memory, you may hibernate the process in between +messages received. This is done by returning the atom +<code>hibernate</code> as part of the <code>loop</code> tuple callbacks normally +return. Just add the atom at the end and Cowboy will hibernate +accordingly.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/handlers/"> + Handlers + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/static_files/"> + Static files + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/middlewares.asciidoc b/docs/en/cowboy/2.2/guide/middlewares.asciidoc new file mode 100644 index 00000000..e6be30dd --- /dev/null +++ b/docs/en/cowboy/2.2/guide/middlewares.asciidoc @@ -0,0 +1,69 @@ +[[middlewares]] +== Middlewares + +Cowboy delegates the request processing to middleware components. +By default, two middlewares are defined, for the routing and handling +of the request, as is detailed in most of this guide. + +Middlewares give you complete control over how requests are to be +processed. You can add your own middlewares to the mix or completely +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 + +Middlewares only need to implement a single callback: `execute/2`. +It is defined in the `cowboy_middleware` behavior. + +This callback has two arguments. The first is the `Req` object. +The second is the environment. + +Middlewares can return one of three different values: + +* `{ok, Req, Env}` to continue the request processing +* `{suspend, Module, Function, Args}` to hibernate +* `{stop, Req}` to stop processing and move on to the next request + +Of note is that when hibernating, processing will resume on the given +MFA, discarding all previous stacktrace. Make sure you keep the `Req` +and `Env` in the arguments of this MFA for later use. + +If an error happens during middleware processing, Cowboy will not try +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 + +The middleware environment is defined as the `env` protocol option. +In the previous chapters we saw it briefly when we needed to pass +the routing information. It is a list of tuples with the first +element being an atom and the second any Erlang term. + +Two values in the environment are reserved: + +* `listener` contains the name of the listener +* `result` contains the result of the processing + +The `listener` value is always defined. The `result` value can be +set by any middleware. If set to anything other than `ok`, Cowboy +will not process any subsequent requests on this connection. + +The middlewares that come with Cowboy may define or require other +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 + +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 + +The handler middleware requires the `handler` and `handler_opts` +values. It puts the result of the request handling into `result`. diff --git a/docs/en/cowboy/2.2/guide/middlewares/index.html b/docs/en/cowboy/2.2/guide/middlewares/index.html new file mode 100644 index 00000000..f0c604e5 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/middlewares/index.html @@ -0,0 +1,251 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Middlewares</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Middlewares</span></h1> + +<div class="paragraph"><p>Cowboy delegates the request processing to middleware components. +By default, two middlewares are defined, for the routing and handling +of the request, as is detailed in most of this guide.</p></div> +<div class="paragraph"><p>Middlewares give you complete control over how requests are to be +processed. You can add your own middlewares to the mix or completely +change the chain of middlewares as needed.</p></div> +<div class="paragraph"><p>Cowboy will execute all middlewares in the given order, unless one +of them decides to stop processing.</p></div> +<div class="sect1"> +<h2 id="_usage">Usage</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Middlewares only need to implement a single callback: <code>execute/2</code>. +It is defined in the <code>cowboy_middleware</code> behavior.</p></div> +<div class="paragraph"><p>This callback has two arguments. The first is the <code>Req</code> object. +The second is the environment.</p></div> +<div class="paragraph"><p>Middlewares can return one of three different values:</p></div> +<div class="ulist"><ul> +<li> +<p> +<code>{ok, Req, Env}</code> to continue the request processing +</p> +</li> +<li> +<p> +<code>{suspend, Module, Function, Args}</code> to hibernate +</p> +</li> +<li> +<p> +<code>{stop, Req}</code> to stop processing and move on to the next request +</p> +</li> +</ul></div> +<div class="paragraph"><p>Of note is that when hibernating, processing will resume on the given +MFA, discarding all previous stacktrace. Make sure you keep the <code>Req</code> +and <code>Env</code> in the arguments of this MFA for later use.</p></div> +<div class="paragraph"><p>If an error happens during middleware processing, Cowboy will not try +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.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_configuration">Configuration</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The middleware environment is defined as the <code>env</code> protocol option. +In the previous chapters we saw it briefly when we needed to pass +the routing information. It is a list of tuples with the first +element being an atom and the second any Erlang term.</p></div> +<div class="paragraph"><p>Two values in the environment are reserved:</p></div> +<div class="ulist"><ul> +<li> +<p> +<code>listener</code> contains the name of the listener +</p> +</li> +<li> +<p> +<code>result</code> contains the result of the processing +</p> +</li> +</ul></div> +<div class="paragraph"><p>The <code>listener</code> value is always defined. The <code>result</code> value can be +set by any middleware. If set to anything other than <code>ok</code>, Cowboy +will not process any subsequent requests on this connection.</p></div> +<div class="paragraph"><p>The middlewares that come with Cowboy may define or require other +environment values to perform.</p></div> +<div class="paragraph"><p>You can update the environment by calling the <code>cowboy:set_env/3</code> +convenience function, adding or replacing a value in the environment.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_routing_middleware">Routing middleware</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The routing middleware requires the <code>dispatch</code> value. If routing +succeeds, it will put the handler name and options in the <code>handler</code> +and <code>handler_opts</code> values of the environment, respectively.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_handler_middleware">Handler middleware</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The handler middleware requires the <code>handler</code> and <code>handler_opts</code> +values. It puts the result of the request handling into <code>result</code>.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/streams/"> + Streams + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/migrating_from_2.1/"> + Migrating from Cowboy 2.1 to 2.2 + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/migrating_from_1.0.asciidoc b/docs/en/cowboy/2.2/guide/migrating_from_1.0.asciidoc new file mode 100644 index 00000000..4f4ea5bf --- /dev/null +++ b/docs/en/cowboy/2.2/guide/migrating_from_1.0.asciidoc @@ -0,0 +1,214 @@ +[appendix] +== Migrating from Cowboy 1.0 to 2.0 + +A lot has changed between Cowboy 1.0 and 2.0. The `cowboy_req` +interface in particular has seen a massive revamp. Hooks are +gone, their functionality can now be achieved via stream +handlers. + +The documentation has seen great work, in particular the +manual. Each module and each function now has its own dedicated +manual page with full details and examples. + +=== Compatibility + +Compatibility with Erlang/OTP R16, 17 and 18 has been dropped. +Erlang/OTP 19.0 or above is required. It is non-trivial to +make Cowboy 2.0 work with older Erlang/OTP versions. + +Cowboy 2.0 is not compatible with Cowlib versions older than +2.0. It should be compatible with Ranch 1.0 or above, however +it has not been tested with Ranch versions older than 1.4. + +Cowboy 2.0 is tested on Arch Linux, Ubuntu, FreeBSD, Windows +and OSX. It is tested with every point release (latest patch +release) and also with HiPE on the most recent release. + +Cowboy 2.0 now comes with Erlang.mk templates. + +=== Features added + +* The HTTP/2 protocol is now supported. + +* Cowboy no longer uses only one process per connection. + It now uses one process per connection plus one process + per request by default. This is necessary for HTTP/2. + There might be a slight drop in performance for HTTP/1.1 + connections due to this change. + +* Cowboy internals have largely been reworked in order to + support HTTP/2. This opened the way to stream handlers, + which are a chain of modules that are called whenever + something happens relating to a request/response. + +* The `cowboy_stream_h` stream handler has been added. + It provides most of Cowboy's default behavior. + +* The `cowboy_compress_h` stream handler has been added. + It compresses responses when possible. It's worth noting + that it compresses in more cases than Cowboy 1.0 ever did. + +* Because of the many changes in the internals of Cowboy, + many options have been added or modified. Of note is that + the Websocket options are now given per handler rather + than for the entire listener. + +* Websocket permessage-deflate compression is now supported + via the `compress` option. + +* Static file handlers will now correctly find files found + in '.ez' archives. + +* Constraints have been generalized and are now used not only + in the router but also in some `cowboy_req` functions. Their + interface has also been modified to allow for reverse + operations and formatting of errors. + +=== Features removed + +* SPDY support has been removed. Use HTTP/2 instead. + +* Hooks have been removed. Use xref:streams[stream handlers] instead. + +* The undocumented `waiting_stream` hack has been removed. + It allowed disabling chunked transfer-encoding for HTTP/1.1. + It has no equivalent in Cowboy 2.0. Open a ticket if necessary. + +* Sub protocols still exist, but their interface has largely changed + and they are no longer documented for the time being. + +=== Changed behaviors + +* The handler behaviors have been renamed and are now `cowboy_handler`, + `cowboy_loop`, `cowboy_rest` and `cowboy_websocket`. + +* Plain HTTP, loop, REST and Websocket handlers have had their + init and terminate callbacks unified. They now all use the + `init/2` and `terminate/3` callbacks. The latter is now optional. + The terminate reason has now been documented for all handlers. + +* The tuple returned to switch to a different handler type has + changed. It now takes the form `{Module, Req, State}` or + `{Module, Req, State, Opts}`, where `Opts` is a map of options + to configure the handler. The timeout and hibernate options + must now be specified using this map, where applicable. + +* All behaviors that used to accept `halt` or `shutdown` tuples + as a return value no longer do so. The return value is now + a `stop` tuple, consistent across Cowboy. + +* Middlewares can no longer return an `error` tuple. They have + to send the response and return a `stop` tuple instead. + +* The `known_content_type` REST handler callback has been removed + as it was found unnecessary. + +* Websocket handlers have both the normal `init/2` and + an optional `websocket_init/1` function. The reason for + that exception is that the `websocket_*` callbacks execute + in a separate process from the `init/2` callback, and it + was therefore not obvious how timers or monitors should + be setup properly. They are effectively initializing the + handler before and after the HTTP/1.1 upgrade. + +* Websocket handlers can now send frames directly from + `websocket_init/1`. The frames will be sent immediately + after the handshake. + +* Websocket handler callbacks no longer receive the Req + argument. The `init/2` callback still receives it and + can be used to extract relevant information. The `terminate/3` + callback, if implemented, may still receive the Req + (see next bullet point). + +* Websocket handlers have a new `req_filter` option that + can be used to customize how much information should be + discarded from the Req object after the handshake. Note + that the Req object is only available in `terminate/3` + past that point. + +* Websocket handlers have their timeout default changed + from infinity to 60 seconds. + +=== New functions + +* The `cowboy_req:scheme/1` function has been added. + +* The `cowboy_req:uri/1,2` function has been added, replacing the + less powerful functions `cowboy_req:url/1` and `cowboy_req:host_url/1`. + +* The functions `cowboy_req:match_qs/2` and `cowboy_req:match_cookies/2` + allow matching query string and cookies against constraints. + +* The function `cowboy_req:set_resp_cookie/3` has been added to + complement `cowboy_req:set_resp_cookie/4`. + +* The functions `cowboy_req:resp_header/2,3` and `cowboy_req:resp_headers/1` + have been added. They can be used to retrieve response headers + that were previously set. + +* The function `cowboy_req:set_resp_headers/2` has been added. It + allows setting many response headers at once. + +* The functions `cowboy_req:push/3,4` can be used to push resources + for protocols that support it (by default only HTTP/2). + +=== Changed functions + +* The `cowboy:start_http/4` function was renamed to `cowboy:start_clear/3`. + +* The `cowboy:start_https/4` function was renamed to `cowboy:start_tls/3`. + +* Most, if not all, functions in the `cowboy_req` module have been modified. + Please consult the changelog of each individual functions. The changes + are mainly about simplifying and clarifying the interface. The Req is no + longer returned when not necessary, maps are used wherever possible, + and some functions have been renamed. + +* The position of the `Opts` argument for `cowboy_req:set_resp_cookie/4` + has changed to improve consistency. It is now the last argument. + +=== Removed functions + +* The functions `cowboy_req:url/1` and `cowboy_req:host_url/1` have been + removed in favor of the new function `cowboy_req:uri/1,2`. + +* The functions `cowboy_req:meta/2,3` and `cowboy_req:set_meta/3` have + been removed. The Req object is now a public map, therefore they became + unnecessary. + +* The functions `cowboy_req:set_resp_body_fun/2,3` have been removed. + For sending files, the function `cowboy_req:set_resp_body/2` can now + take a sendfile tuple. + +* Remove many undocumented functions from `cowboy_req`, including the + functions `cowboy_req:get/2` and `cowboy_req:set/3`. + +=== Other changes + +* The correct percent-decoding algorithm is now used for path elements + during routing. It will no longer decode `+` characters. + +* The router will now properly handle path segments `.` and `..`. + +* Routing behavior has changed for URIs containing latin1 characters. + They are no longer allowed. URIs are expected to be in UTF-8 once + they are percent-decoded. + +* Clients that send multiple headers of the same name + will have the values of those headers concatenated into a + comma-separated list. This is of special importance in the + case of the content-type header, as previously only the + first value was used in the `content_types_accepted/2` step + in REST handlers. + +* Etag comparison in REST handlers has been fixed. Some requests may + now fail when they succeeded in the past. + +* The `If-*-Since` headers are now ignored in REST handlers if + the corresponding `If*-Match` header exist. The former is + largely a backward compatible header and this shouldn't create + any issue. The new behavior follows the current RFCs more closely. + +* The static file handler has been improved to handle more special + characters on systems that accept them. diff --git a/docs/en/cowboy/2.2/guide/migrating_from_1.0/index.html b/docs/en/cowboy/2.2/guide/migrating_from_1.0/index.html new file mode 100644 index 00000000..27f06b5a --- /dev/null +++ b/docs/en/cowboy/2.2/guide/migrating_from_1.0/index.html @@ -0,0 +1,547 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Migrating from Cowboy 1.0 to 2.0</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Migrating from Cowboy 1.0 to 2.0</span></h1> + +<div class="paragraph"><p>A lot has changed between Cowboy 1.0 and 2.0. The <code>cowboy_req</code> +interface in particular has seen a massive revamp. Hooks are +gone, their functionality can now be achieved via stream +handlers.</p></div> +<div class="paragraph"><p>The documentation has seen great work, in particular the +manual. Each module and each function now has its own dedicated +manual page with full details and examples.</p></div> +<div class="sect1"> +<h2 id="_compatibility">Compatibility</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Compatibility with Erlang/OTP R16, 17 and 18 has been dropped. +Erlang/OTP 19.0 or above is required. It is non-trivial to +make Cowboy 2.0 work with older Erlang/OTP versions.</p></div> +<div class="paragraph"><p>Cowboy 2.0 is not compatible with Cowlib versions older than +2.0. It should be compatible with Ranch 1.0 or above, however +it has not been tested with Ranch versions older than 1.4.</p></div> +<div class="paragraph"><p>Cowboy 2.0 is tested on Arch Linux, Ubuntu, FreeBSD, Windows +and OSX. It is tested with every point release (latest patch +release) and also with HiPE on the most recent release.</p></div> +<div class="paragraph"><p>Cowboy 2.0 now comes with Erlang.mk templates.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_features_added">Features added</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +The HTTP/2 protocol is now supported. +</p> +</li> +<li> +<p> +Cowboy no longer uses only one process per connection. + It now uses one process per connection plus one process + per request by default. This is necessary for HTTP/2. + There might be a slight drop in performance for HTTP/1.1 + connections due to this change. +</p> +</li> +<li> +<p> +Cowboy internals have largely been reworked in order to + support HTTP/2. This opened the way to stream handlers, + which are a chain of modules that are called whenever + something happens relating to a request/response. +</p> +</li> +<li> +<p> +The <code>cowboy_stream_h</code> stream handler has been added. + It provides most of Cowboy’s default behavior. +</p> +</li> +<li> +<p> +The <code>cowboy_compress_h</code> stream handler has been added. + It compresses responses when possible. It’s worth noting + that it compresses in more cases than Cowboy 1.0 ever did. +</p> +</li> +<li> +<p> +Because of the many changes in the internals of Cowboy, + many options have been added or modified. Of note is that + the Websocket options are now given per handler rather + than for the entire listener. +</p> +</li> +<li> +<p> +Websocket permessage-deflate compression is now supported + via the <code>compress</code> option. +</p> +</li> +<li> +<p> +Static file handlers will now correctly find files found + in <em>.ez</em> archives. +</p> +</li> +<li> +<p> +Constraints have been generalized and are now used not only + in the router but also in some <code>cowboy_req</code> functions. Their + interface has also been modified to allow for reverse + operations and formatting of errors. +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_features_removed">Features removed</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +SPDY support has been removed. Use HTTP/2 instead. +</p> +</li> +<li> +<p> +Hooks have been removed. Use <a href="../streams">stream handlers</a> instead. +</p> +</li> +<li> +<p> +The undocumented <code>waiting_stream</code> hack has been removed. + It allowed disabling chunked transfer-encoding for HTTP/1.1. + It has no equivalent in Cowboy 2.0. Open a ticket if necessary. +</p> +</li> +<li> +<p> +Sub protocols still exist, but their interface has largely changed + and they are no longer documented for the time being. +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_changed_behaviors">Changed behaviors</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +The handler behaviors have been renamed and are now <code>cowboy_handler</code>, + <code>cowboy_loop</code>, <code>cowboy_rest</code> and <code>cowboy_websocket</code>. +</p> +</li> +<li> +<p> +Plain HTTP, loop, REST and Websocket handlers have had their + init and terminate callbacks unified. They now all use the + <code>init/2</code> and <code>terminate/3</code> callbacks. The latter is now optional. + The terminate reason has now been documented for all handlers. +</p> +</li> +<li> +<p> +The tuple returned to switch to a different handler type has + changed. It now takes the form <code>{Module, Req, State}</code> or + <code>{Module, Req, State, Opts}</code>, where <code>Opts</code> is a map of options + to configure the handler. The timeout and hibernate options + must now be specified using this map, where applicable. +</p> +</li> +<li> +<p> +All behaviors that used to accept <code>halt</code> or <code>shutdown</code> tuples + as a return value no longer do so. The return value is now + a <code>stop</code> tuple, consistent across Cowboy. +</p> +</li> +<li> +<p> +Middlewares can no longer return an <code>error</code> tuple. They have + to send the response and return a <code>stop</code> tuple instead. +</p> +</li> +<li> +<p> +The <code>known_content_type</code> REST handler callback has been removed + as it was found unnecessary. +</p> +</li> +<li> +<p> +Websocket handlers have both the normal <code>init/2</code> and + an optional <code>websocket_init/1</code> function. The reason for + that exception is that the <code>websocket_*</code> callbacks execute + in a separate process from the <code>init/2</code> callback, and it + was therefore not obvious how timers or monitors should + be setup properly. They are effectively initializing the + handler before and after the HTTP/1.1 upgrade. +</p> +</li> +<li> +<p> +Websocket handlers can now send frames directly from + <code>websocket_init/1</code>. The frames will be sent immediately + after the handshake. +</p> +</li> +<li> +<p> +Websocket handler callbacks no longer receive the Req + argument. The <code>init/2</code> callback still receives it and + can be used to extract relevant information. The <code>terminate/3</code> + callback, if implemented, may still receive the Req + (see next bullet point). +</p> +</li> +<li> +<p> +Websocket handlers have a new <code>req_filter</code> option that + can be used to customize how much information should be + discarded from the Req object after the handshake. Note + that the Req object is only available in <code>terminate/3</code> + past that point. +</p> +</li> +<li> +<p> +Websocket handlers have their timeout default changed + from infinity to 60 seconds. +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_new_functions">New functions</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +The <code>cowboy_req:scheme/1</code> function has been added. +</p> +</li> +<li> +<p> +The <code>cowboy_req:uri/1,2</code> function has been added, replacing the + less powerful functions <code>cowboy_req:url/1</code> and <code>cowboy_req:host_url/1</code>. +</p> +</li> +<li> +<p> +The functions <code>cowboy_req:match_qs/2</code> and <code>cowboy_req:match_cookies/2</code> + allow matching query string and cookies against constraints. +</p> +</li> +<li> +<p> +The function <code>cowboy_req:set_resp_cookie/3</code> has been added to + complement <code>cowboy_req:set_resp_cookie/4</code>. +</p> +</li> +<li> +<p> +The functions <code>cowboy_req:resp_header/2,3</code> and <code>cowboy_req:resp_headers/1</code> + have been added. They can be used to retrieve response headers + that were previously set. +</p> +</li> +<li> +<p> +The function <code>cowboy_req:set_resp_headers/2</code> has been added. It + allows setting many response headers at once. +</p> +</li> +<li> +<p> +The functions <code>cowboy_req:push/3,4</code> can be used to push resources + for protocols that support it (by default only HTTP/2). +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_changed_functions">Changed functions</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +The <code>cowboy:start_http/4</code> function was renamed to <code>cowboy:start_clear/3</code>. +</p> +</li> +<li> +<p> +The <code>cowboy:start_https/4</code> function was renamed to <code>cowboy:start_tls/3</code>. +</p> +</li> +<li> +<p> +Most, if not all, functions in the <code>cowboy_req</code> module have been modified. + Please consult the changelog of each individual functions. The changes + are mainly about simplifying and clarifying the interface. The Req is no + longer returned when not necessary, maps are used wherever possible, + and some functions have been renamed. +</p> +</li> +<li> +<p> +The position of the <code>Opts</code> argument for <code>cowboy_req:set_resp_cookie/4</code> + has changed to improve consistency. It is now the last argument. +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_removed_functions">Removed functions</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +The functions <code>cowboy_req:url/1</code> and <code>cowboy_req:host_url/1</code> have been + removed in favor of the new function <code>cowboy_req:uri/1,2</code>. +</p> +</li> +<li> +<p> +The functions <code>cowboy_req:meta/2,3</code> and <code>cowboy_req:set_meta/3</code> have + been removed. The Req object is now a public map, therefore they became + unnecessary. +</p> +</li> +<li> +<p> +The functions <code>cowboy_req:set_resp_body_fun/2,3</code> have been removed. + For sending files, the function <code>cowboy_req:set_resp_body/2</code> can now + take a sendfile tuple. +</p> +</li> +<li> +<p> +Remove many undocumented functions from <code>cowboy_req</code>, including the + functions <code>cowboy_req:get/2</code> and <code>cowboy_req:set/3</code>. +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_other_changes">Other changes</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +The correct percent-decoding algorithm is now used for path elements + during routing. It will no longer decode <code>+</code> characters. +</p> +</li> +<li> +<p> +The router will now properly handle path segments <code>.</code> and <code>..</code>. +</p> +</li> +<li> +<p> +Routing behavior has changed for URIs containing latin1 characters. + They are no longer allowed. URIs are expected to be in UTF-8 once + they are percent-decoded. +</p> +</li> +<li> +<p> +Clients that send multiple headers of the same name + will have the values of those headers concatenated into a + comma-separated list. This is of special importance in the + case of the content-type header, as previously only the + first value was used in the <code>content_types_accepted/2</code> step + in REST handlers. +</p> +</li> +<li> +<p> +Etag comparison in REST handlers has been fixed. Some requests may + now fail when they succeeded in the past. +</p> +</li> +<li> +<p> +The <code>If-*-Since</code> headers are now ignored in REST handlers if + the corresponding <code>If*-Match</code> header exist. The former is + largely a backward compatible header and this shouldn’t create + any issue. The new behavior follows the current RFCs more closely. +</p> +</li> +<li> +<p> +The static file handler has been improved to handle more special + characters on systems that accept them. +</p> +</li> +</ul></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/migrating_from_2.0/"> + Migrating from Cowboy 2.0 to 2.1 + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/specs/"> + HTTP and other specifications + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/migrating_from_2.0.asciidoc b/docs/en/cowboy/2.2/guide/migrating_from_2.0.asciidoc new file mode 100644 index 00000000..c76430c2 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/migrating_from_2.0.asciidoc @@ -0,0 +1,107 @@ +[appendix] +== Migrating from Cowboy 2.0 to 2.1 + +Cowboy 2.1 focused on adding features that were temporarily +removed in Cowboy 2.0. A number of bugs found in the 2.0 +release were also fixed. + +=== Features added + +* It is now possible to obtain the client TLS certificate + and the local IP/port for the connection from the Req object. + +* Informational responses (1XX responses) can now be sent. + They must be sent before initiating the final response. + +* The `expect: 100-continue` header is now handled + automatically. The 100 response will be sent on the + first `cowboy_req:read_body/2,3,4` call. This only applies + when using the default `cowboy_stream_h` stream handler. + +=== Experimental features added + +Experimental features are previews of features that will be +added in a future release. They are not documented and their +interface may change at any time. You are welcome to try them +and provide feedback. + +* The `cowboy_metrics_h` stream handler can be used to + extract metrics out of Cowboy. It must be used first in + the list of stream handlers, and will record all events + related to requests, responses and spawned processes. + When the stream terminates it will pass this information + to a user-defined callback. + +* The `cowboy_tracer_h` stream handler can be used to setup + automatic tracing of specific requests. You can conditionally + enable tracing based on a function, header, path or any other + element from the request and the trace will apply to the + entire connection and any processes created by it. This is + meant to be used for debugging both in tests and production. + +=== Changed behaviors + +* The `cowboy_rest` handler now implements a mechanism for + switching to a different type of handler from any callback + where `stop` is also allowed. Switch by returning + `{switch_handler, Module}` or `{switch_handler, Module, Opts}`. + This is especially useful for switching to `cowboy_loop` + for streaming the request or response body. + +* REST callbacks that do not allow `stop` as a return value + are now explicitly listed in the documentation. + +=== New functions + +* The function `cowboy_req:sock/1` returns the IP/port + of the local socket. + +* The function `cowboy_req:cert/1` returns the client + TLS certificate or `undefined` if it isn't available. + +* The function `cowboy_req:inform/2,3` sends an + informational response. + +=== Bugs fixed + +* Ensure HTTP/2 connections are not closed prematurely + when the user code does not read the request body. + +* Ensure HTTP/1.1 streams are not terminated too early. + Their behavior is now consistent with the HTTP/2 code + where the stream handler is only terminated when the + `stop` command is returned. + +* Sending zero-sized data from stream handlers or from + `cowboy_req:stream_body/3` could lead to issues with + HTTP/1.1. This has been fixed. + +* The final chunk sent by Cowboy when it terminates a + chunked body after the handler process exits was not + passed through stream handlers, which could lead to + issues when `cowboy_compress_h` was being used. This + is now corrected. + +* The stream handler state was discarded in some cases + where Cowboy had to send a response or response data + automatically when ending a stream. This has now + been corrected. + +* The stream handler callback `terminate/3` will now be + called when switching to another protocol using the + command `switch_protocol`. This doesn't apply when + doing upgrades to HTTP/2 as those occur before the + stream is initialized. + +* Cowlib has been updated to 2.0.1 to fix an issue with + Websocket compression when using Erlang/OTP 20.1. Note + that at the time of writing all 20.1 versions (from + 20.1 to 20.1.4) have issues when compression is enabled. + It is expected to work properly from 20.1.5 onward. In + the meantime it is recommended to run the plain 20.1 + release and disable Websocket compression, or use a + release before 20.1. + +* Cowboy will no longer crash when the `cowboy_clock` + process is not running. This can happen when Cowboy + is being restarted during upgrades, for example. diff --git a/docs/en/cowboy/2.2/guide/migrating_from_2.0/index.html b/docs/en/cowboy/2.2/guide/migrating_from_2.0/index.html new file mode 100644 index 00000000..4326200a --- /dev/null +++ b/docs/en/cowboy/2.2/guide/migrating_from_2.0/index.html @@ -0,0 +1,347 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Migrating from Cowboy 2.0 to 2.1</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Migrating from Cowboy 2.0 to 2.1</span></h1> + +<div class="paragraph"><p>Cowboy 2.1 focused on adding features that were temporarily +removed in Cowboy 2.0. A number of bugs found in the 2.0 +release were also fixed.</p></div> +<div class="sect1"> +<h2 id="_features_added">Features added</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +It is now possible to obtain the client TLS certificate + and the local IP/port for the connection from the Req object. +</p> +</li> +<li> +<p> +Informational responses (1XX responses) can now be sent. + They must be sent before initiating the final response. +</p> +</li> +<li> +<p> +The <code>expect: 100-continue</code> header is now handled + automatically. The 100 response will be sent on the + first <code>cowboy_req:read_body/2,3,4</code> call. This only applies + when using the default <code>cowboy_stream_h</code> stream handler. +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_experimental_features_added">Experimental features added</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Experimental features are previews of features that will be +added in a future release. They are not documented and their +interface may change at any time. You are welcome to try them +and provide feedback.</p></div> +<div class="ulist"><ul> +<li> +<p> +The <code>cowboy_metrics_h</code> stream handler can be used to + extract metrics out of Cowboy. It must be used first in + the list of stream handlers, and will record all events + related to requests, responses and spawned processes. + When the stream terminates it will pass this information + to a user-defined callback. +</p> +</li> +<li> +<p> +The <code>cowboy_tracer_h</code> stream handler can be used to setup + automatic tracing of specific requests. You can conditionally + enable tracing based on a function, header, path or any other + element from the request and the trace will apply to the + entire connection and any processes created by it. This is + meant to be used for debugging both in tests and production. +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_changed_behaviors">Changed behaviors</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +The <code>cowboy_rest</code> handler now implements a mechanism for + switching to a different type of handler from any callback + where <code>stop</code> is also allowed. Switch by returning + <code>{switch_handler, Module}</code> or <code>{switch_handler, Module, Opts}</code>. + This is especially useful for switching to <code>cowboy_loop</code> + for streaming the request or response body. +</p> +</li> +<li> +<p> +REST callbacks that do not allow <code>stop</code> as a return value + are now explicitly listed in the documentation. +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_new_functions">New functions</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +The function <code>cowboy_req:sock/1</code> returns the IP/port + of the local socket. +</p> +</li> +<li> +<p> +The function <code>cowboy_req:cert/1</code> returns the client + TLS certificate or <code>undefined</code> if it isn’t available. +</p> +</li> +<li> +<p> +The function <code>cowboy_req:inform/2,3</code> sends an + informational response. +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_bugs_fixed">Bugs fixed</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +Ensure HTTP/2 connections are not closed prematurely + when the user code does not read the request body. +</p> +</li> +<li> +<p> +Ensure HTTP/1.1 streams are not terminated too early. + Their behavior is now consistent with the HTTP/2 code + where the stream handler is only terminated when the + <code>stop</code> command is returned. +</p> +</li> +<li> +<p> +Sending zero-sized data from stream handlers or from + <code>cowboy_req:stream_body/3</code> could lead to issues with + HTTP/1.1. This has been fixed. +</p> +</li> +<li> +<p> +The final chunk sent by Cowboy when it terminates a + chunked body after the handler process exits was not + passed through stream handlers, which could lead to + issues when <code>cowboy_compress_h</code> was being used. This + is now corrected. +</p> +</li> +<li> +<p> +The stream handler state was discarded in some cases + where Cowboy had to send a response or response data + automatically when ending a stream. This has now + been corrected. +</p> +</li> +<li> +<p> +The stream handler callback <code>terminate/3</code> will now be + called when switching to another protocol using the + command <code>switch_protocol</code>. This doesn’t apply when + doing upgrades to HTTP/2 as those occur before the + stream is initialized. +</p> +</li> +<li> +<p> +Cowlib has been updated to 2.0.1 to fix an issue with + Websocket compression when using Erlang/OTP 20.1. Note + that at the time of writing all 20.1 versions (from + 20.1 to 20.1.4) have issues when compression is enabled. + It is expected to work properly from 20.1.5 onward. In + the meantime it is recommended to run the plain 20.1 + release and disable Websocket compression, or use a + release before 20.1. +</p> +</li> +<li> +<p> +Cowboy will no longer crash when the <code>cowboy_clock</code> + process is not running. This can happen when Cowboy + is being restarted during upgrades, for example. +</p> +</li> +</ul></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/migrating_from_2.1/"> + Migrating from Cowboy 2.1 to 2.2 + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/migrating_from_1.0/"> + Migrating from Cowboy 1.0 to 2.0 + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/migrating_from_2.1.asciidoc b/docs/en/cowboy/2.2/guide/migrating_from_2.1.asciidoc new file mode 100644 index 00000000..3c0681ff --- /dev/null +++ b/docs/en/cowboy/2.2/guide/migrating_from_2.1.asciidoc @@ -0,0 +1,107 @@ +[appendix] +== Migrating from Cowboy 2.1 to 2.2 + +Cowboy 2.2 focused on adding features required for writing +gRPC servers and on completing test suites for the core +HTTP RFCs, fixing many bugs along the way. + +=== Features added + +* Add support for sending trailers at the end of response bodies. + Trailers are additional header fields that may be sent after the + body to add more information to the response. Their usage is + required in gRPC servers. They are optional and may be discarded + in other scenarios (for example if the request goes through an + HTTP/1.0 proxy, as HTTP/1.0 does not support trailers). + +* The `max_skip_body_length` option was added to `cowboy_http`. + It controls how much of a request body Cowboy is willing to skip + when the handler did not touch it. If the remaining body size is + too large Cowboy instead closes the connection. It defaults to 1MB. + +* The CONNECT and TRACE methods are now rejected as they are + currently not implemented and must be handled differently than + other methods. They will be implemented in a future release. + +=== New functions + +* The function `stream_trailers/2` has been added. It terminates + a stream and adds trailer fields at the end of the response. A + corresponding stream handler command `{trailers, Trailers}` + has also been added. + +=== Bugs fixed + +* Test suites for the core HTTP RFCs RFC7230, RFC7231 and RFC7540 + have been completed. Many of the bugs listed here were fixed as + a result of this work. + +* Many HTTP/2 edge cases when clients are misbehaving have been + corrected. This includes many cases where the request is malformed + (for example when a pseudo-header is present twice). + +* When the HTTP/2 SETTINGS_INITIAL_WINDOW_SIZE value changes, + Cowboy now properly updates the flow control windows. + +* HTTP/2 could mistakenly log stray messages that actually were + expected. This is no longer the case. + +* We no longer send a GOAWAY frame when the HTTP/2 preface is invalid. + +* Some values in the Req object of pushed requests were in the + wrong type. They are now the expected binary instead of iolist. + +* A response body was sometimes sent in response to HEAD requests + when using HTTP/2. The body is now ignored. + +* The `max_headers` option for `cowboy_http` was not always respected + depending on the contents of the buffer. The limit is now strict. + +* When an early error occurred on the HTTP/1.1 request line, the + partial Req given to stream handlers was missing the `ref` and + `peer` information. This has been corrected. + +* Absolute URIs with a userinfo component, or without an authority + component, are now properly rejected for HTTP/1.0 and HTTP/1.1. + +* Whitespace is no longer allowed in header lines before the colon. + +* 408 responses to HTTP/1.1 requests now properly include a + connection: close header indicating that we are going to + close the connection. This header will also be sent for + other early errors resulting in the closing of the connection. + +* When both the transfer-encoding and content-length headers are + sent in an HTTP/1.1 request, the transfer-encoding now takes + precedence over the content-length header and the latter is + removed from the Req object. + +* A 400 response is now returned when the transfer-encoding + header is invalid or contains any transfer-coding other + than chunked. + +* Invalid chunk sizes are now rejected immediately. + +* Chunk extensions are now limited to 129 characters. They are + not used in practice and are still ignored by Cowboy. The limit + is not configurable. + +* The final chunk was mistakenly sent in responses to HEAD + requests. This is now corrected. + +* `OPTIONS *` requests were broken in Cowboy 2.0. They are now + working again. Both the routing and `cowboy_req:uri/1,2` have + been corrected. + +* 204 responses no longer include a content-length header. + +* A packet could be lost when switching to Websocket or any + other protocol via the `switch_protocol` command. This is + now fixed. + +* A 426 response will now be sent when a handler requires + the client to upgrade to Websocket and the request did not + include the required headers. + +* Both experimental stream handlers `cowboy_metrics_h` and + `cowboy_tracer_h` received a number of fixes and improvements. diff --git a/docs/en/cowboy/2.2/guide/migrating_from_2.1/index.html b/docs/en/cowboy/2.2/guide/migrating_from_2.1/index.html new file mode 100644 index 00000000..79bcc13a --- /dev/null +++ b/docs/en/cowboy/2.2/guide/migrating_from_2.1/index.html @@ -0,0 +1,362 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Migrating from Cowboy 2.1 to 2.2</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Migrating from Cowboy 2.1 to 2.2</span></h1> + +<div class="paragraph"><p>Cowboy 2.2 focused on adding features required for writing +gRPC servers and on completing test suites for the core +HTTP RFCs, fixing many bugs along the way.</p></div> +<div class="sect1"> +<h2 id="_features_added">Features added</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +Add support for sending trailers at the end of response bodies. + Trailers are additional header fields that may be sent after the + body to add more information to the response. Their usage is + required in gRPC servers. They are optional and may be discarded + in other scenarios (for example if the request goes through an + HTTP/1.0 proxy, as HTTP/1.0 does not support trailers). +</p> +</li> +<li> +<p> +The <code>max_skip_body_length</code> option was added to <code>cowboy_http</code>. + It controls how much of a request body Cowboy is willing to skip + when the handler did not touch it. If the remaining body size is + too large Cowboy instead closes the connection. It defaults to 1MB. +</p> +</li> +<li> +<p> +The CONNECT and TRACE methods are now rejected as they are + currently not implemented and must be handled differently than + other methods. They will be implemented in a future release. +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_new_functions">New functions</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +The function <code>stream_trailers/2</code> has been added. It terminates + a stream and adds trailer fields at the end of the response. A + corresponding stream handler command <code>{trailers, Trailers}</code> + has also been added. +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_bugs_fixed">Bugs fixed</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +Test suites for the core HTTP RFCs RFC7230, RFC7231 and RFC7540 + have been completed. Many of the bugs listed here were fixed as + a result of this work. +</p> +</li> +<li> +<p> +Many HTTP/2 edge cases when clients are misbehaving have been + corrected. This includes many cases where the request is malformed + (for example when a pseudo-header is present twice). +</p> +</li> +<li> +<p> +When the HTTP/2 SETTINGS_INITIAL_WINDOW_SIZE value changes, + Cowboy now properly updates the flow control windows. +</p> +</li> +<li> +<p> +HTTP/2 could mistakenly log stray messages that actually were + expected. This is no longer the case. +</p> +</li> +<li> +<p> +We no longer send a GOAWAY frame when the HTTP/2 preface is invalid. +</p> +</li> +<li> +<p> +Some values in the Req object of pushed requests were in the + wrong type. They are now the expected binary instead of iolist. +</p> +</li> +<li> +<p> +A response body was sometimes sent in response to HEAD requests + when using HTTP/2. The body is now ignored. +</p> +</li> +<li> +<p> +The <code>max_headers</code> option for <code>cowboy_http</code> was not always respected + depending on the contents of the buffer. The limit is now strict. +</p> +</li> +<li> +<p> +When an early error occurred on the HTTP/1.1 request line, the + partial Req given to stream handlers was missing the <code>ref</code> and + <code>peer</code> information. This has been corrected. +</p> +</li> +<li> +<p> +Absolute URIs with a userinfo component, or without an authority + component, are now properly rejected for HTTP/1.0 and HTTP/1.1. +</p> +</li> +<li> +<p> +Whitespace is no longer allowed in header lines before the colon. +</p> +</li> +<li> +<p> +408 responses to HTTP/1.1 requests now properly include a + connection: close header indicating that we are going to + close the connection. This header will also be sent for + other early errors resulting in the closing of the connection. +</p> +</li> +<li> +<p> +When both the transfer-encoding and content-length headers are + sent in an HTTP/1.1 request, the transfer-encoding now takes + precedence over the content-length header and the latter is + removed from the Req object. +</p> +</li> +<li> +<p> +A 400 response is now returned when the transfer-encoding + header is invalid or contains any transfer-coding other + than chunked. +</p> +</li> +<li> +<p> +Invalid chunk sizes are now rejected immediately. +</p> +</li> +<li> +<p> +Chunk extensions are now limited to 129 characters. They are + not used in practice and are still ignored by Cowboy. The limit + is not configurable. +</p> +</li> +<li> +<p> +The final chunk was mistakenly sent in responses to HEAD + requests. This is now corrected. +</p> +</li> +<li> +<p> +<code>OPTIONS *</code> requests were broken in Cowboy 2.0. They are now + working again. Both the routing and <code>cowboy_req:uri/1,2</code> have + been corrected. +</p> +</li> +<li> +<p> +204 responses no longer include a content-length header. +</p> +</li> +<li> +<p> +A packet could be lost when switching to Websocket or any + other protocol via the <code>switch_protocol</code> command. This is + now fixed. +</p> +</li> +<li> +<p> +A 426 response will now be sent when a handler requires + the client to upgrade to Websocket and the request did not + include the required headers. +</p> +</li> +<li> +<p> +Both experimental stream handlers <code>cowboy_metrics_h</code> and + <code>cowboy_tracer_h</code> received a number of fixes and improvements. +</p> +</li> +</ul></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/middlewares/"> + Middlewares + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/migrating_from_2.0/"> + Migrating from Cowboy 2.0 to 2.1 + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/modern_web.asciidoc b/docs/en/cowboy/2.2/guide/modern_web.asciidoc new file mode 100644 index 00000000..48525732 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/modern_web.asciidoc @@ -0,0 +1,122 @@ +[[modern_web]] +== The modern Web + +Cowboy is a server for the modern Web. This chapter explains +what it means and details all the standards involved. + +Cowboy supports all the standards listed in this document. + +=== HTTP/2 + +HTTP/2 is the most efficient protocol for consuming Web +services. It enables clients to keep a connection open +for long periods of time; to send requests concurrently; +to reduce the size of requests through HTTP headers +compression; and more. The protocol is binary, greatly +reducing the resources needed to parse it. + +HTTP/2 also enables the server to push messages to the +client. This can be used for various purposes, including +the sending of related resources before the client requests +them, in an effort to reduce latency. This can also be used +to enable bidirectional communication. + +Cowboy provides transparent support for HTTP/2. Clients +that know it can use it; others fall back to HTTP/1.1 +automatically. + +HTTP/2 is compatible with the HTTP/1.1 semantics. + +HTTP/2 is defined by RFC 7540 and RFC 7541. + +=== HTTP/1.1 + +HTTP/1.1 is the previous version of the HTTP protocol. +The protocol itself is text-based and suffers from numerous +issues and limitations. In particular it is not possible +to execute requests concurrently (though pipelining is +sometimes possible), and it's also sometimes difficult +to detect that a client disconnected. + +HTTP/1.1 does provide very good semantics for interacting +with Web services. It defines the standard methods, headers +and status codes used by HTTP/1.1 and HTTP/2 clients and +servers. + +HTTP/1.1 also defines compatibility with an older version +of the protocol, HTTP/1.0, which was never really standardized +across implementations. + +The core of HTTP/1.1 is defined by RFC 7230, RFC 7231, +RFC 7232, RFC 7233, RFC 7234 and RFC 7235. Numerous RFCs +and other specifications exist defining additional HTTP +methods, status codes, headers or semantics. + +=== Websocket + +xref:ws_protocol[Websocket] is a protocol built on top of HTTP/1.1 +that provides a two-ways communication channel between the client and +the server. Communication is asynchronous and can occur concurrently. + +It consists of a Javascript object allowing setting up a +Websocket connection to the server, and a binary based +protocol for sending data to the server or the client. + +Websocket connections can transfer either UTF-8 encoded text +data or binary data. The protocol also includes support for +implementing a ping/pong mechanism, allowing the server and +the client to have more confidence that the connection is still +alive. + +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. + +Websocket messages have no semantics on their own. Websocket +is closer to TCP in that aspect, and requires you to design +and implement your own protocol on top of it; or adapt an +existing protocol to Websocket. + +Cowboy provides an interface known as xref:ws_handlers[Websocket handlers] +that gives complete control over a Websocket connection. + +The Websocket protocol is defined by RFC 6455. + +=== Long-lived requests + +Cowboy provides an interface that can be used to support +long-polling or to stream large amounts of data reliably, +including using Server-Sent Events. + +Long-polling is a mechanism in which the client performs +a request which may not be immediately answered by the +server. It allows clients to request resources that may +not currently exist, but are expected to be created soon, +and which will be returned as soon as they are. + +Long-polling is essentially a hack, but it is widely used +to overcome limitations on older clients and servers. + +Server-Sent Events is a small protocol defined as a media +type, `text/event-stream`, along with a new HTTP header, +`Last-Event-ID`. It is defined in the EventSource W3C +specification. + +Cowboy provides an interface known as xref:loop_handlers[loop handlers] +that facilitates the implementation of long-polling or stream +mechanisms. It works regardless of the underlying protocol. + +=== REST + +xref:rest_principles[REST, or REpresentational State Transfer], +is a style of architecture for loosely connected distributed +systems. It can easily be implemented on top of HTTP. + +REST is essentially a set of constraints to be followed. +Many of these constraints are purely architectural and +solved by simply using HTTP. Some constraints must be +explicitly followed by the developer. + +Cowboy provides an interface known as xref:rest_handlers[REST handlers] +that simplifies the implementation of a REST API on top of +the HTTP protocol. diff --git a/docs/en/cowboy/2.2/guide/modern_web/index.html b/docs/en/cowboy/2.2/guide/modern_web/index.html new file mode 100644 index 00000000..a44048b3 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/modern_web/index.html @@ -0,0 +1,270 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: The modern Web</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>The modern Web</span></h1> + +<div class="paragraph"><p>Cowboy is a server for the modern Web. This chapter explains +what it means and details all the standards involved.</p></div> +<div class="paragraph"><p>Cowboy supports all the standards listed in this document.</p></div> +<div class="sect1"> +<h2 id="_http_2">HTTP/2</h2> +<div class="sectionbody"> +<div class="paragraph"><p>HTTP/2 is the most efficient protocol for consuming Web +services. It enables clients to keep a connection open +for long periods of time; to send requests concurrently; +to reduce the size of requests through HTTP headers +compression; and more. The protocol is binary, greatly +reducing the resources needed to parse it.</p></div> +<div class="paragraph"><p>HTTP/2 also enables the server to push messages to the +client. This can be used for various purposes, including +the sending of related resources before the client requests +them, in an effort to reduce latency. This can also be used +to enable bidirectional communication.</p></div> +<div class="paragraph"><p>Cowboy provides transparent support for HTTP/2. Clients +that know it can use it; others fall back to HTTP/1.1 +automatically.</p></div> +<div class="paragraph"><p>HTTP/2 is compatible with the HTTP/1.1 semantics.</p></div> +<div class="paragraph"><p>HTTP/2 is defined by RFC 7540 and RFC 7541.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_http_1_1">HTTP/1.1</h2> +<div class="sectionbody"> +<div class="paragraph"><p>HTTP/1.1 is the previous version of the HTTP protocol. +The protocol itself is text-based and suffers from numerous +issues and limitations. In particular it is not possible +to execute requests concurrently (though pipelining is +sometimes possible), and it’s also sometimes difficult +to detect that a client disconnected.</p></div> +<div class="paragraph"><p>HTTP/1.1 does provide very good semantics for interacting +with Web services. It defines the standard methods, headers +and status codes used by HTTP/1.1 and HTTP/2 clients and +servers.</p></div> +<div class="paragraph"><p>HTTP/1.1 also defines compatibility with an older version +of the protocol, HTTP/1.0, which was never really standardized +across implementations.</p></div> +<div class="paragraph"><p>The core of HTTP/1.1 is defined by RFC 7230, RFC 7231, +RFC 7232, RFC 7233, RFC 7234 and RFC 7235. Numerous RFCs +and other specifications exist defining additional HTTP +methods, status codes, headers or semantics.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_websocket">Websocket</h2> +<div class="sectionbody"> +<div class="paragraph"><p><a href="../ws_protocol">Websocket</a> is a protocol built on top of HTTP/1.1 +that provides a two-ways communication channel between the client and +the server. Communication is asynchronous and can occur concurrently.</p></div> +<div class="paragraph"><p>It consists of a Javascript object allowing setting up a +Websocket connection to the server, and a binary based +protocol for sending data to the server or the client.</p></div> +<div class="paragraph"><p>Websocket connections can transfer either UTF-8 encoded text +data or binary data. The protocol also includes support for +implementing a ping/pong mechanism, allowing the server and +the client to have more confidence that the connection is still +alive.</p></div> +<div class="paragraph"><p>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.</p></div> +<div class="paragraph"><p>Websocket messages have no semantics on their own. Websocket +is closer to TCP in that aspect, and requires you to design +and implement your own protocol on top of it; or adapt an +existing protocol to Websocket.</p></div> +<div class="paragraph"><p>Cowboy provides an interface known as <a href="../ws_handlers">Websocket handlers</a> +that gives complete control over a Websocket connection.</p></div> +<div class="paragraph"><p>The Websocket protocol is defined by RFC 6455.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_long_lived_requests">Long-lived requests</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy provides an interface that can be used to support +long-polling or to stream large amounts of data reliably, +including using Server-Sent Events.</p></div> +<div class="paragraph"><p>Long-polling is a mechanism in which the client performs +a request which may not be immediately answered by the +server. It allows clients to request resources that may +not currently exist, but are expected to be created soon, +and which will be returned as soon as they are.</p></div> +<div class="paragraph"><p>Long-polling is essentially a hack, but it is widely used +to overcome limitations on older clients and servers.</p></div> +<div class="paragraph"><p>Server-Sent Events is a small protocol defined as a media +type, <code>text/event-stream</code>, along with a new HTTP header, +<code>Last-Event-ID</code>. It is defined in the EventSource W3C +specification.</p></div> +<div class="paragraph"><p>Cowboy provides an interface known as <a href="../loop_handlers">loop handlers</a> +that facilitates the implementation of long-polling or stream +mechanisms. It works regardless of the underlying protocol.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_rest">REST</h2> +<div class="sectionbody"> +<div class="paragraph"><p><a href="../rest_principles">REST, or REpresentational State Transfer</a>, +is a style of architecture for loosely connected distributed +systems. It can easily be implemented on top of HTTP.</p></div> +<div class="paragraph"><p>REST is essentially a set of constraints to be followed. +Many of these constraints are purely architectural and +solved by simply using HTTP. Some constraints must be +explicitly followed by the developer.</p></div> +<div class="paragraph"><p>Cowboy provides an interface known as <a href="../rest_handlers">REST handlers</a> +that simplifies the implementation of a REST API on top of +the HTTP protocol.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/erlang_web/"> + Erlang and the Web + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/multipart.asciidoc b/docs/en/cowboy/2.2/guide/multipart.asciidoc new file mode 100644 index 00000000..0825244c --- /dev/null +++ b/docs/en/cowboy/2.2/guide/multipart.asciidoc @@ -0,0 +1,169 @@ +[[multipart]] +== Multipart requests + +Multipart originates from MIME, an Internet standard that +extends the format of emails. + +A multipart message is a list of parts. A part contains +headers and a body. The body of the parts may be +of any media type, and contain text or binary data. +It is possible for parts to contain a multipart media +type. + +In the context of HTTP, multipart is most often used +with the `multipart/form-data` media type. It is what +browsers use to upload files through HTML forms. + +The `multipart/byteranges` is also common. It is the +media type used to send arbitrary bytes from a resource, +enabling clients to resume downloads. + +=== Form-data + +In the normal case, when a form is submitted, the +browser will use the `application/x-www-form-urlencoded` +content-type. This type is just a list of keys and +values and is therefore not fit for uploading files. + +That's where the `multipart/form-data` content-type +comes in. When the form is configured to use this +content-type, the browser will create a multipart +message where each part corresponds to a field on +the form. For files, it also adds some metadata in +the part headers, like the file name. + +A form with a text input, a file input and a select +choice box will result in a multipart message with +three parts, one for each field. + +The browser does its best to determine the media type +of the files it sends this way, but you should not +rely on it for determining the contents of the file. +Proper investigation of the contents is recommended. + +=== Checking for multipart messages + +The content-type header indicates the presence of +a multipart message: + +[source,erlang] +---- +{<<"multipart">>, <<"form-data">>, _} + = cowboy_req:parse_header(<<"content-type">>, Req). +---- + +=== Reading a multipart message + +Cowboy provides two sets of functions for reading +request bodies as multipart messages. + +The `cowboy_req:read_part/1,2` functions return the +next part's headers, if any. + +The `cowboy_req:read_part_body/1,2` functions return +the current part's body. For large bodies you may +need to call the function multiple times. + +To read a multipart message you need to iterate over +all its parts: + +[source,erlang] +---- +multipart(Req0) -> + case cowboy_req:read_part(Req0) of + {ok, _Headers, Req1} -> + {ok, _Body, Req} = cowboy_req:read_part_body(Req1), + multipart(Req); + {done, Req} -> + Req + end. +---- + +When part bodies are too large, Cowboy will return +a `more` tuple, and allow you to loop until the part +body has been fully read. + +The function `cow_multipart:form_data/1` can be used +to quickly obtain information about a part from a +`multipart/form-data` message. The function returns +a `data` or a `file` tuple depending on whether this +is a normal field or a file being uploaded. + +The following snippet will use this function and +use different strategies depending on whether the +part is a file: + +[source,erlang] +---- +multipart(Req0) -> + case cowboy_req:read_part(Req0) of + {ok, Headers, Req1} -> + Req = case cow_multipart:form_data(Headers) of + {data, _FieldName} -> + {ok, _Body, Req2} = cowboy_req:read_part_body(Req1), + Req2; + {file, _FieldName, _Filename, _CType} -> + stream_file(Req1) + end, + multipart(Req); + {done, Req} -> + Req + end. + +stream_file(Req0) -> + case cowboy_req:read_part_body(Req0) of + {ok, _LastBodyChunk, Req} -> + Req; + {more, _BodyChunk, Req} -> + stream_file(Req) + end. +---- + +Both the part header and body reading functions can take +options that will be given to the request body reading +functions. By default, `cowboy_req:read_part/1` reads +up to 64KB for up to 5 seconds. `cowboy_req:read_part_body/1` +has the same defaults as `cowboy_req:read_body/1`. + +To change the defaults for part headers: + +[source,erlang] +cowboy_req:read_part(Req, #{length => 128000}). + +And for part bodies: + +[source,erlang] +cowboy_req:read_part_body(Req, #{length => 1000000, period => 7000}). + +=== Skipping unwanted parts + +Part bodies do not have to be read. Cowboy will automatically +skip it when you request the next part's body. + +The following snippet reads all part headers and skips +all bodies: + +[source,erlang] +---- +multipart(Req0) -> + case cowboy_req:read_part(Req0) of + {ok, _Headers, Req} -> + multipart(Req); + {done, Req} -> + Req + end. +---- + +Similarly, if you start reading the body and it ends up +being too big, you can simply continue with the next part. +Cowboy will automatically skip what remains. + +While Cowboy can skip part bodies automatically, the read +rate is not configurable. Depending on your application +you may want to skip manually, in particular if you observe +poor performance while skipping. + +You do not have to read all parts either. You can stop +reading as soon as you find the data you need. + +// @todo Cover the building of multipart messages. diff --git a/docs/en/cowboy/2.2/guide/multipart/index.html b/docs/en/cowboy/2.2/guide/multipart/index.html new file mode 100644 index 00000000..c1b3b8c2 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/multipart/index.html @@ -0,0 +1,328 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Multipart requests</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Multipart requests</span></h1> + +<div class="paragraph"><p>Multipart originates from MIME, an Internet standard that +extends the format of emails.</p></div> +<div class="paragraph"><p>A multipart message is a list of parts. A part contains +headers and a body. The body of the parts may be +of any media type, and contain text or binary data. +It is possible for parts to contain a multipart media +type.</p></div> +<div class="paragraph"><p>In the context of HTTP, multipart is most often used +with the <code>multipart/form-data</code> media type. It is what +browsers use to upload files through HTML forms.</p></div> +<div class="paragraph"><p>The <code>multipart/byteranges</code> is also common. It is the +media type used to send arbitrary bytes from a resource, +enabling clients to resume downloads.</p></div> +<div class="sect1"> +<h2 id="_form_data">Form-data</h2> +<div class="sectionbody"> +<div class="paragraph"><p>In the normal case, when a form is submitted, the +browser will use the <code>application/x-www-form-urlencoded</code> +content-type. This type is just a list of keys and +values and is therefore not fit for uploading files.</p></div> +<div class="paragraph"><p>That’s where the <code>multipart/form-data</code> content-type +comes in. When the form is configured to use this +content-type, the browser will create a multipart +message where each part corresponds to a field on +the form. For files, it also adds some metadata in +the part headers, like the file name.</p></div> +<div class="paragraph"><p>A form with a text input, a file input and a select +choice box will result in a multipart message with +three parts, one for each field.</p></div> +<div class="paragraph"><p>The browser does its best to determine the media type +of the files it sends this way, but you should not +rely on it for determining the contents of the file. +Proper investigation of the contents is recommended.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_checking_for_multipart_messages">Checking for multipart messages</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The content-type header indicates the presence of +a multipart message:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #990000"><<</span><span style="color: #FF0000">"multipart"</span><span style="color: #990000">>></span>, <span style="color: #990000"><<</span><span style="color: #FF0000">"form-data"</span><span style="color: #990000">>></span>, <span style="color: #990000">_</span>} + <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:parse_header</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"content-type"</span><span style="color: #990000">>></span>, <span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_reading_a_multipart_message">Reading a multipart message</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy provides two sets of functions for reading +request bodies as multipart messages.</p></div> +<div class="paragraph"><p>The <code>cowboy_req:read_part/1,2</code> functions return the +next part’s headers, if any.</p></div> +<div class="paragraph"><p>The <code>cowboy_req:read_part_body/1,2</code> functions return +the current part’s body. For large bodies you may +need to call the function multiple times.</p></div> +<div class="paragraph"><p>To read a multipart message you need to iterate over +all its parts:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">multipart</span></span>(<span style="color: #009900">Req0</span>) <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #0000FF">case</span></span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:read_part</span></span>(<span style="color: #009900">Req0</span>) <span style="font-weight: bold"><span style="color: #0000FF">of</span></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">_Headers</span>, <span style="color: #009900">Req1</span>} <span style="color: #990000">-></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">_Body</span>, <span style="color: #009900">Req</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:read_part_body</span></span>(<span style="color: #009900">Req1</span>), + <span style="font-weight: bold"><span style="color: #000000">multipart</span></span>(<span style="color: #009900">Req</span>); + {<span style="color: #FF6600">done</span>, <span style="color: #009900">Req</span>} <span style="color: #990000">-></span> + <span style="color: #009900">Req</span> + <span style="font-weight: bold"><span style="color: #0000FF">end</span></span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>When part bodies are too large, Cowboy will return +a <code>more</code> tuple, and allow you to loop until the part +body has been fully read.</p></div> +<div class="paragraph"><p>The function <code>cow_multipart:form_data/1</code> can be used +to quickly obtain information about a part from a +<code>multipart/form-data</code> message. The function returns +a <code>data</code> or a <code>file</code> tuple depending on whether this +is a normal field or a file being uploaded.</p></div> +<div class="paragraph"><p>The following snippet will use this function and +use different strategies depending on whether the +part is a file:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">multipart</span></span>(<span style="color: #009900">Req0</span>) <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #0000FF">case</span></span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:read_part</span></span>(<span style="color: #009900">Req0</span>) <span style="font-weight: bold"><span style="color: #0000FF">of</span></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">Headers</span>, <span style="color: #009900">Req1</span>} <span style="color: #990000">-></span> + <span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">case</span></span> <span style="font-weight: bold"><span style="color: #000000">cow_multipart:form_data</span></span>(<span style="color: #009900">Headers</span>) <span style="font-weight: bold"><span style="color: #0000FF">of</span></span> + {<span style="color: #FF6600">data</span>, <span style="color: #009900">_FieldName</span>} <span style="color: #990000">-></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">_Body</span>, <span style="color: #009900">Req2</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:read_part_body</span></span>(<span style="color: #009900">Req1</span>), + <span style="color: #009900">Req2</span>; + {<span style="color: #FF6600">file</span>, <span style="color: #009900">_FieldName</span>, <span style="color: #009900">_Filename</span>, <span style="color: #009900">_CType</span>} <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #000000">stream_file</span></span>(<span style="color: #009900">Req1</span>) + <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>, + <span style="font-weight: bold"><span style="color: #000000">multipart</span></span>(<span style="color: #009900">Req</span>); + {<span style="color: #FF6600">done</span>, <span style="color: #009900">Req</span>} <span style="color: #990000">-></span> + <span style="color: #009900">Req</span> + <span style="font-weight: bold"><span style="color: #0000FF">end</span></span><span style="color: #990000">.</span> + +<span style="font-weight: bold"><span style="color: #000000">stream_file</span></span>(<span style="color: #009900">Req0</span>) <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #0000FF">case</span></span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:read_part_body</span></span>(<span style="color: #009900">Req0</span>) <span style="font-weight: bold"><span style="color: #0000FF">of</span></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">_LastBodyChunk</span>, <span style="color: #009900">Req</span>} <span style="color: #990000">-></span> + <span style="color: #009900">Req</span>; + {<span style="color: #FF6600">more</span>, <span style="color: #009900">_BodyChunk</span>, <span style="color: #009900">Req</span>} <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #000000">stream_file</span></span>(<span style="color: #009900">Req</span>) + <span style="font-weight: bold"><span style="color: #0000FF">end</span></span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Both the part header and body reading functions can take +options that will be given to the request body reading +functions. By default, <code>cowboy_req:read_part/1</code> reads +up to 64KB for up to 5 seconds. <code>cowboy_req:read_part_body/1</code> +has the same defaults as <code>cowboy_req:read_body/1</code>.</p></div> +<div class="paragraph"><p>To change the defaults for part headers:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">cowboy_req:read_part</span></span>(<span style="color: #009900">Req</span>, #{<span style="font-weight: bold"><span style="color: #000080">length</span></span> <span style="color: #990000">=></span> <span style="color: #993399">128000</span>})<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>And for part bodies:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">cowboy_req:read_part_body</span></span>(<span style="color: #009900">Req</span>, #{<span style="font-weight: bold"><span style="color: #000080">length</span></span> <span style="color: #990000">=></span> <span style="color: #993399">1000000</span>, <span style="color: #0000FF">period</span> <span style="color: #990000">=></span> <span style="color: #993399">7000</span>})<span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_skipping_unwanted_parts">Skipping unwanted parts</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Part bodies do not have to be read. Cowboy will automatically +skip it when you request the next part’s body.</p></div> +<div class="paragraph"><p>The following snippet reads all part headers and skips +all bodies:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">multipart</span></span>(<span style="color: #009900">Req0</span>) <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #0000FF">case</span></span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:read_part</span></span>(<span style="color: #009900">Req0</span>) <span style="font-weight: bold"><span style="color: #0000FF">of</span></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">_Headers</span>, <span style="color: #009900">Req</span>} <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #000000">multipart</span></span>(<span style="color: #009900">Req</span>); + {<span style="color: #FF6600">done</span>, <span style="color: #009900">Req</span>} <span style="color: #990000">-></span> + <span style="color: #009900">Req</span> + <span style="font-weight: bold"><span style="color: #0000FF">end</span></span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Similarly, if you start reading the body and it ends up +being too big, you can simply continue with the next part. +Cowboy will automatically skip what remains.</p></div> +<div class="paragraph"><p>While Cowboy can skip part bodies automatically, the read +rate is not configurable. Depending on your application +you may want to skip manually, in particular if you observe +poor performance while skipping.</p></div> +<div class="paragraph"><p>You do not have to read all parts either. You can stop +reading as soon as you find the data you need.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/cookies/"> + Using cookies + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/rest_principles/"> + REST principles + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/req.asciidoc b/docs/en/cowboy/2.2/guide/req.asciidoc new file mode 100644 index 00000000..b879fa3d --- /dev/null +++ b/docs/en/cowboy/2.2/guide/req.asciidoc @@ -0,0 +1,366 @@ +[[req]] +== The Req object + +The Req object is a variable used for obtaining information +about a request, read its body or send a response. + +It is not really an object in the object-oriented sense. +It is a simple map that can be directly accessed or +used when calling functions from the `cowboy_req` module. + +The Req object is the subject of a few different chapters. +In this chapter we will learn about the Req object and +look at how to retrieve information about the request. + +=== Direct access + +The Req map contains a number of fields which are documented +and can be accessed directly. They are the fields that have +a direct mapping to HTTP: the request `method`; the HTTP +`version` used; the effective URI components `scheme`, +`host`, `port`, `path` and `qs`; the request `headers`; +and the connection `peer` address and port. + +Note that the `version` field can be used to determine +whether a connection is using HTTP/2. + +To access a field, you can simply match in the function +head. The following example sends a simple "Hello world!" +response when the `method` is GET, and a 405 error +otherwise. + +[source,erlang] +---- +init(Req0=#{method := <<"GET">>}, State) -> + Req = cowboy_req:reply(200, #{ + <<"content-type">> => <<"text/plain">> + }, <<"Hello world!">>, Req0), + {ok, Req, State}; +init(Req0, State) -> + Req = cowboy_req:reply(405, #{ + <<"allow">> => <<"GET">> + }, Req0), + {ok, Req, State}. +---- + +Any other field is internal and should not be accessed. +They may change in future releases, including maintenance +releases, without notice. + +Modifying the Req object, while allowed, is not recommended +unless strictly necessary. If adding new fields, make sure +to namespace the field names so that no conflict can occur +with future Cowboy updates or third party projects. + +// @todo There are currently no tests for direct access. + +=== Introduction to the cowboy_req interface + +// @todo Link to cowboy_req manual + +Functions in the `cowboy_req` module provide access to +the request information but also various operations that +are common when dealing with HTTP requests. + +All the functions that begin with a verb indicate an action. +Other functions simply return the corresponding value +(sometimes that value does need to be built, but the +cost of the operation is equivalent to retrieving a value). + +Some of the `cowboy_req` functions return an updated Req +object. They are the read, reply, set and delete functions. +While ignoring the returned Req will not cause incorrect +behavior for some of them, it is highly recommended to +always keep and use the last returned Req object. The +manual for `cowboy_req` details these functions and what +modifications are done to the Req object. + +Some of the calls to `cowboy_req` have side effects. This +is the case of the read and reply functions. Cowboy reads +the request body or replies immediately when the function +is called. + +All functions will crash if something goes wrong. There +is usually no need to catch these errors, Cowboy will +send the appropriate 4xx or 5xx response depending on +where the crash occurred. + +=== Request method + +The request method can be retrieved directly: + +[source, erlang] +#{method := Method} = Req. + +Or using a function: + +[source,erlang] +Method = cowboy_req:method(Req). + +The method is a case sensitive binary string. Standard +methods include GET, HEAD, OPTIONS, PATCH, POST, PUT +or DELETE. + +=== HTTP version + +The HTTP version is informational. It does not indicate that +the client implements the protocol well or fully. + +There is typically no need to change behavior based on the +HTTP version: Cowboy already does it for you. + +It can be useful in some cases, though. For example, one may +want to redirect HTTP/1.1 clients to use Websocket, while HTTP/2 +clients keep using HTTP/2. + +The HTTP version can be retrieved directly: + +[source,erlang] +#{version := Version} = Req. + +Or using a function: + +[source,erlang] +Version = cowboy_req:version(Req). + +Cowboy defines the `'HTTP/1.0'`, `'HTTP/1.1'` and `'HTTP/2'` +versions. Custom protocols can define their own values as +atoms. + +=== Effective request URI + +The scheme, host, port, path and query string components +of the effective request URI can all be retrieved directly: + +[source,erlang] +---- +#{ + scheme := Scheme, + host := Host, + port := Port, + path := Path, + qs := Qs +} = Req. +---- + +Or using the related functions: + +[source,erlang] +Scheme = cowboy_req:scheme(Req), +Host = cowboy_req:host(Req), +Port = cowboy_req:port(Req), +Path = cowboy_req:path(Req). +Qs = cowboy_req:qs(Req). + +The scheme and host are lowercased case insensitive binary +strings. The port is an integer representing the port number. +The path and query string are case sensitive binary strings. + +Cowboy defines only the `<<"http">>` and `<<"https">>` schemes. +They are chosen so that the scheme will only be `<<"https">>` +for requests on secure HTTP/1.1 or HTTP/2 connections. +// @todo Is that tested well? + +The effective request URI itself can be reconstructed with +the `cowboy_req:uri/1,2` function. By default, an absolute +URI is returned: + +[source,erlang] +%% scheme://host[:port]/path[?qs] +URI = cowboy_req:uri(Req). + +Options are available to either disable or replace some +or all of the components. Various URIs or URI formats can +be generated this way, including the origin form: + +[source,erlang] +%% /path[?qs] +URI = cowboy_req:uri(Req, #{host => undefined}). + +The protocol relative form: + +[source,erlang] +%% //host[:port]/path[?qs] +URI = cowboy_req:uri(Req, #{scheme => undefined}). + +The absolute URI without a query string: + +[source,erlang] +URI = cowboy_req:uri(Req, #{qs => undefined}). + +A different host: + +[source,erlang] +URI = cowboy_req:uri(Req, #{host => <<"example.org">>}). + +And any other combination. + +=== Bindings + +Bindings are the host and path components that you chose +to extract when defining the routes of your application. +They are only available after the routing. + +Cowboy provides functions to retrieve one or all bindings. + +To retrieve a single value: + +[source,erlang] +Value = cowboy_req:binding(userid, Req). + +When attempting to retrieve a value that was not bound, +`undefined` will be returned. A different default value +can be provided: + +[source,erlang] +Value = cowboy_req:binding(userid, Req, 42). + +To retrieve everything that was bound: + +[source,erlang] +Bindings = cowboy_req:bindings(Req). + +They are returned as a map, with keys being atoms. + +The Cowboy router also allows you to capture many host +or path segments at once using the `...` qualifier. + +To retrieve the segments captured from the host name: + +[source,erlang] +HostInfo = cowboy_req:host_info(Req). + +And the path segments: + +[source,erlang] +PathInfo = cowboy_req:path_info(Req). + +Cowboy will return `undefined` if `...` was not used +in the route. + +=== Query parameters + +Cowboy provides two functions to access query parameters. +You can use the first to get the entire list of parameters. + +[source,erlang] +QsVals = cowboy_req:parse_qs(Req), +{_, Lang} = lists:keyfind(<<"lang">>, 1, QsVals). + +Cowboy will only parse the query string, and not do any +transformation. This function may therefore return duplicates, +or parameter names without an associated value. The order of +the list returned is undefined. + +When a query string is `key=1&key=2`, the list returned will +contain two parameters of name `key`. + +The same is true when trying to use the PHP-style suffix `[]`. +When a query string is `key[]=1&key[]=2`, the list returned will +contain two parameters of name `key[]`. + +When a query string is simply `key`, Cowboy will return the +list `[{<<"key">>, true}]`, using `true` to indicate that the +parameter `key` was defined, but with no value. + +The second function Cowboy provides allows you to match out +only the parameters you are interested in, and at the same +time do any post processing you require using xref:constraints[constraints]. +This function returns a map. + +[source,erlang] +#{id := ID, lang := Lang} = cowboy_req:match_qs([id, lang], Req). + +Constraints can be applied automatically. The following +snippet will crash when the `id` parameter is not an integer, +or when the `lang` parameter is empty. At the same time, the +value for `id` will be converted to an integer term: + +[source,erlang] +QsMap = cowboy_req:match_qs([{id, int}, {lang, nonempty}], Req). + +A default value may also be provided. The default will be used +if the `lang` key is not found. It will not be used if +the key is found but has an empty value. + +[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. + +When the query string is `key=1&key=2`, the value for `key` +will be the list `[1, 2]`. Parameter names do not need to +include the PHP-style suffix. Constraints may be used to +ensure that only one value was passed through. + +=== Headers + +Header values can be retrieved either as a binary string +or parsed into a more meaningful representation. + +The get the raw value: + +[source,erlang] +HeaderVal = cowboy_req:header(<<"content-type">>, Req). + +Cowboy expects all header names to be provided as lowercase +binary strings. This is true for both requests and responses, +regardless of the underlying protocol. + +When the header is missing from the request, `undefined` +will be returned. A different default can be provided: + +[source,erlang] +HeaderVal = cowboy_req:header(<<"content-type">>, Req, <<"text/plain">>). + +All headers can be retrieved at once, either directly: + +[source,erlang] +#{headers := AllHeaders} = Req. + +Or using a function: + +[source,erlang] +AllHeaders = cowboy_req:headers(Req). + +Cowboy provides equivalent functions to parse individual +headers. There is no function to parse all headers at once. + +To parse a specific header: + +[source,erlang] +ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req). + +An exception will be thrown if it doesn't know how to parse the +given header, or if the value is invalid. The list of known headers +and default values can be found in the manual. + +When the header is missing, `undefined` is returned. You can +change the default value. Note that it should be the parsed value +directly: + +[source,erlang] +---- +ParsedVal = cowboy_req:parse_header(<<"content-type">>, Req, + {<<"text">>, <<"plain">>, []}). +---- + +=== Peer + +The peer address and port number for the connection can be +retrieved either directly or using a function. + +To retrieve the peer directly: + +[source,erlang] +#{peer := {IP, Port}} = Req. + +And using a function: + +[source,erlang] +{IP, Port} = cowboy_req:peer(Req). + +Note that the peer corresponds to the remote end of the +connection to the server, which may or may not be the +client itself. It may also be a proxy or a gateway. diff --git a/docs/en/cowboy/2.2/guide/req/index.html b/docs/en/cowboy/2.2/guide/req/index.html new file mode 100644 index 00000000..01a95f45 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/req/index.html @@ -0,0 +1,566 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: The Req object</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>The Req object</span></h1> + +<div class="paragraph"><p>The Req object is a variable used for obtaining information +about a request, read its body or send a response.</p></div> +<div class="paragraph"><p>It is not really an object in the object-oriented sense. +It is a simple map that can be directly accessed or +used when calling functions from the <code>cowboy_req</code> module.</p></div> +<div class="paragraph"><p>The Req object is the subject of a few different chapters. +In this chapter we will learn about the Req object and +look at how to retrieve information about the request.</p></div> +<div class="sect1"> +<h2 id="_direct_access">Direct access</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The Req map contains a number of fields which are documented +and can be accessed directly. They are the fields that have +a direct mapping to HTTP: the request <code>method</code>; the HTTP +<code>version</code> used; the effective URI components <code>scheme</code>, +<code>host</code>, <code>port</code>, <code>path</code> and <code>qs</code>; the request <code>headers</code>; +and the connection <code>peer</code> address and port.</p></div> +<div class="paragraph"><p>Note that the <code>version</code> field can be used to determine +whether a connection is using HTTP/2.</p></div> +<div class="paragraph"><p>To access a field, you can simply match in the function +head. The following example sends a simple "Hello world!" +response when the <code>method</code> is GET, and a 405 error +otherwise.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req0</span><span style="color: #990000">=</span>#{<span style="color: #FF6600">method</span> <span style="color: #990000">:=</span> <span style="color: #990000"><<</span><span style="color: #FF0000">"GET"</span><span style="color: #990000">>></span>}, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + <span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:reply</span></span>(<span style="color: #993399">200</span>, #{ + <span style="color: #990000"><<</span><span style="color: #FF0000">"content-type"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"text/plain"</span><span style="color: #990000">>></span> + }, <span style="color: #990000"><<</span><span style="color: #FF0000">"Hello world!"</span><span style="color: #990000">>></span>, <span style="color: #009900">Req0</span>), + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}; +<span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req0</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + <span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:reply</span></span>(<span style="color: #993399">405</span>, #{ + <span style="color: #990000"><<</span><span style="color: #FF0000">"allow"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"GET"</span><span style="color: #990000">>></span> + }, <span style="color: #009900">Req0</span>), + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Any other field is internal and should not be accessed. +They may change in future releases, including maintenance +releases, without notice.</p></div> +<div class="paragraph"><p>Modifying the Req object, while allowed, is not recommended +unless strictly necessary. If adding new fields, make sure +to namespace the field names so that no conflict can occur +with future Cowboy updates or third party projects.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_introduction_to_the_cowboy_req_interface">Introduction to the cowboy_req interface</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Functions in the <code>cowboy_req</code> module provide access to +the request information but also various operations that +are common when dealing with HTTP requests.</p></div> +<div class="paragraph"><p>All the functions that begin with a verb indicate an action. +Other functions simply return the corresponding value +(sometimes that value does need to be built, but the +cost of the operation is equivalent to retrieving a value).</p></div> +<div class="paragraph"><p>Some of the <code>cowboy_req</code> functions return an updated Req +object. They are the read, reply, set and delete functions. +While ignoring the returned Req will not cause incorrect +behavior for some of them, it is highly recommended to +always keep and use the last returned Req object. The +manual for <code>cowboy_req</code> details these functions and what +modifications are done to the Req object.</p></div> +<div class="paragraph"><p>Some of the calls to <code>cowboy_req</code> have side effects. This +is the case of the read and reply functions. Cowboy reads +the request body or replies immediately when the function +is called.</p></div> +<div class="paragraph"><p>All functions will crash if something goes wrong. There +is usually no need to catch these errors, Cowboy will +send the appropriate 4xx or 5xx response depending on +where the crash occurred.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_request_method">Request method</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The request method can be retrieved directly:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>#{<span style="color: #FF6600">method</span> <span style="color: #990000">:=</span> <span style="color: #009900">Method</span>} <span style="color: #990000">=</span> <span style="color: #009900">Req</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Or using a function:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Method</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:method</span></span>(<span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>The method is a case sensitive binary string. Standard +methods include GET, HEAD, OPTIONS, PATCH, POST, PUT +or DELETE.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_http_version">HTTP version</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The HTTP version is informational. It does not indicate that +the client implements the protocol well or fully.</p></div> +<div class="paragraph"><p>There is typically no need to change behavior based on the +HTTP version: Cowboy already does it for you.</p></div> +<div class="paragraph"><p>It can be useful in some cases, though. For example, one may +want to redirect HTTP/1.1 clients to use Websocket, while HTTP/2 +clients keep using HTTP/2.</p></div> +<div class="paragraph"><p>The HTTP version can be retrieved directly:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>#{<span style="color: #FF6600">version</span> <span style="color: #990000">:=</span> <span style="color: #009900">Version</span>} <span style="color: #990000">=</span> <span style="color: #009900">Req</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Or using a function:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Version</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:version</span></span>(<span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Cowboy defines the <code>'HTTP/1.0'</code>, <code>'HTTP/1.1'</code> and <code>'HTTP/2'</code> +versions. Custom protocols can define their own values as +atoms.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_effective_request_uri">Effective request URI</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The scheme, host, port, path and query string components +of the effective request URI can all be retrieved directly:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>#{ + <span style="color: #FF6600">scheme</span> <span style="color: #990000">:=</span> <span style="color: #009900">Scheme</span>, + <span style="color: #FF6600">host</span> <span style="color: #990000">:=</span> <span style="color: #009900">Host</span>, + <span style="color: #FF6600">port</span> <span style="color: #990000">:=</span> <span style="color: #009900">Port</span>, + <span style="color: #FF6600">path</span> <span style="color: #990000">:=</span> <span style="color: #009900">Path</span>, + <span style="color: #FF6600">qs</span> <span style="color: #990000">:=</span> <span style="color: #009900">Qs</span> +} <span style="color: #990000">=</span> <span style="color: #009900">Req</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Or using the related functions:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Scheme</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:scheme</span></span>(<span style="color: #009900">Req</span>), +<span style="color: #009900">Host</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:host</span></span>(<span style="color: #009900">Req</span>), +<span style="color: #009900">Port</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:port</span></span>(<span style="color: #009900">Req</span>), +<span style="color: #009900">Path</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:path</span></span>(<span style="color: #009900">Req</span>)<span style="color: #990000">.</span> +<span style="color: #009900">Qs</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:qs</span></span>(<span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>The scheme and host are lowercased case insensitive binary +strings. The port is an integer representing the port number. +The path and query string are case sensitive binary strings.</p></div> +<div class="paragraph"><p>Cowboy defines only the <code><<"http">></code> and <code><<"https">></code> schemes. +They are chosen so that the scheme will only be <code><<"https">></code> +for requests on secure HTTP/1.1 or HTTP/2 connections.</p></div> +<div class="paragraph"><p>The effective request URI itself can be reconstructed with +the <code>cowboy_req:uri/1,2</code> function. By default, an absolute +URI is returned:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-style: italic"><span style="color: #9A1900">%% </span></span><span style="text-decoration: underline"><span style="color: #0000FF">scheme://host</span></span><span style="font-style: italic"><span style="color: #9A1900">[:port]/path[?qs]</span></span> +<span style="color: #009900">URI</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:uri</span></span>(<span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Options are available to either disable or replace some +or all of the components. Various URIs or URI formats can +be generated this way, including the origin form:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-style: italic"><span style="color: #9A1900">%% /path[?qs]</span></span> +<span style="color: #009900">URI</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:uri</span></span>(<span style="color: #009900">Req</span>, #{<span style="color: #0000FF">host</span> <span style="color: #990000">=></span> <span style="color: #000080">undefined</span>})<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>The protocol relative form:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-style: italic"><span style="color: #9A1900">%% //host[:port]/path[?qs]</span></span> +<span style="color: #009900">URI</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:uri</span></span>(<span style="color: #009900">Req</span>, #{<span style="color: #0000FF">scheme</span> <span style="color: #990000">=></span> <span style="color: #000080">undefined</span>})<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>The absolute URI without a query string:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">URI</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:uri</span></span>(<span style="color: #009900">Req</span>, #{<span style="color: #0000FF">qs</span> <span style="color: #990000">=></span> <span style="color: #000080">undefined</span>})<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>A different host:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">URI</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:uri</span></span>(<span style="color: #009900">Req</span>, #{<span style="color: #0000FF">host</span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"example.org"</span><span style="color: #990000">>></span>})<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>And any other combination.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_bindings">Bindings</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Bindings are the host and path components that you chose +to extract when defining the routes of your application. +They are only available after the routing.</p></div> +<div class="paragraph"><p>Cowboy provides functions to retrieve one or all bindings.</p></div> +<div class="paragraph"><p>To retrieve a single value:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Value</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:binding</span></span>(<span style="color: #FF6600">userid</span>, <span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>When attempting to retrieve a value that was not bound, +<code>undefined</code> will be returned. A different default value +can be provided:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Value</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:binding</span></span>(<span style="color: #FF6600">userid</span>, <span style="color: #009900">Req</span>, <span style="color: #993399">42</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>To retrieve everything that was bound:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Bindings</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:bindings</span></span>(<span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>They are returned as a map, with keys being atoms.</p></div> +<div class="paragraph"><p>The Cowboy router also allows you to capture many host +or path segments at once using the <code>...</code> qualifier.</p></div> +<div class="paragraph"><p>To retrieve the segments captured from the host name:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">HostInfo</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:host_info</span></span>(<span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>And the path segments:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">PathInfo</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:path_info</span></span>(<span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Cowboy will return <code>undefined</code> if <code>...</code> was not used +in the route.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_query_parameters">Query parameters</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy provides two functions to access query parameters. +You can use the first to get the entire list of parameters.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">QsVals</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:parse_qs</span></span>(<span style="color: #009900">Req</span>), +{<span style="color: #990000">_</span>, <span style="color: #009900">Lang</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">lists:keyfind</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"lang"</span><span style="color: #990000">>></span>, <span style="color: #993399">1</span>, <span style="color: #009900">QsVals</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Cowboy will only parse the query string, and not do any +transformation. This function may therefore return duplicates, +or parameter names without an associated value. The order of +the list returned is undefined.</p></div> +<div class="paragraph"><p>When a query string is <code>key=1&key=2</code>, the list returned will +contain two parameters of name <code>key</code>.</p></div> +<div class="paragraph"><p>The same is true when trying to use the PHP-style suffix <code>[]</code>. +When a query string is <code>key[]=1&key[]=2</code>, the list returned will +contain two parameters of name <code>key[]</code>.</p></div> +<div class="paragraph"><p>When a query string is simply <code>key</code>, Cowboy will return the +list <code>[{<<"key">>, true}]</code>, using <code>true</code> to indicate that the +parameter <code>key</code> was defined, but with no value.</p></div> +<div class="paragraph"><p>The second function Cowboy provides allows you to match out +only the parameters you are interested in, and at the same +time do any post processing you require using <a href="../constraints">constraints</a>. +This function returns a map.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>#{<span style="color: #FF6600">id</span> <span style="color: #990000">:=</span> <span style="color: #009900">ID</span>, <span style="color: #FF6600">lang</span> <span style="color: #990000">:=</span> <span style="color: #009900">Lang</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:match_qs</span></span>([<span style="color: #FF6600">id</span>, <span style="color: #FF6600">lang</span>], <span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Constraints can be applied automatically. The following +snippet will crash when the <code>id</code> parameter is not an integer, +or when the <code>lang</code> parameter is empty. At the same time, the +value for <code>id</code> will be converted to an integer term:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">QsMap</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:match_qs</span></span>([{<span style="color: #FF6600">id</span>, <span style="color: #FF6600">int</span>}, {<span style="color: #FF6600">lang</span>, <span style="color: #FF6600">nonempty</span>}], <span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>A default value may also be provided. The default will be used +if the <code>lang</code> key is not found. It will not be used if +the key is found but has an empty value.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>#{<span style="color: #FF6600">lang</span> <span style="color: #990000">:=</span> <span style="color: #009900">Lang</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:match_qs</span></span>([{<span style="color: #FF6600">lang</span>, [], <span style="color: #990000"><<</span><span style="color: #FF0000">"en-US"</span><span style="color: #990000">>></span>}], <span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>If no default is provided and the value is missing, the +query string is deemed invalid and the process will crash.</p></div> +<div class="paragraph"><p>When the query string is <code>key=1&key=2</code>, the value for <code>key</code> +will be the list <code>[1, 2]</code>. Parameter names do not need to +include the PHP-style suffix. Constraints may be used to +ensure that only one value was passed through.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_headers">Headers</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Header values can be retrieved either as a binary string +or parsed into a more meaningful representation.</p></div> +<div class="paragraph"><p>The get the raw value:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">HeaderVal</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:header</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"content-type"</span><span style="color: #990000">>></span>, <span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Cowboy expects all header names to be provided as lowercase +binary strings. This is true for both requests and responses, +regardless of the underlying protocol.</p></div> +<div class="paragraph"><p>When the header is missing from the request, <code>undefined</code> +will be returned. A different default can be provided:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">HeaderVal</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:header</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"content-type"</span><span style="color: #990000">>></span>, <span style="color: #009900">Req</span>, <span style="color: #990000"><<</span><span style="color: #FF0000">"text/plain"</span><span style="color: #990000">>></span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>All headers can be retrieved at once, either directly:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>#{<span style="color: #FF6600">headers</span> <span style="color: #990000">:=</span> <span style="color: #009900">AllHeaders</span>} <span style="color: #990000">=</span> <span style="color: #009900">Req</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Or using a function:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">AllHeaders</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:headers</span></span>(<span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Cowboy provides equivalent functions to parse individual +headers. There is no function to parse all headers at once.</p></div> +<div class="paragraph"><p>To parse a specific header:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">ParsedVal</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:parse_header</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"content-type"</span><span style="color: #990000">>></span>, <span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>An exception will be thrown if it doesn’t know how to parse the +given header, or if the value is invalid. The list of known headers +and default values can be found in the manual.</p></div> +<div class="paragraph"><p>When the header is missing, <code>undefined</code> is returned. You can +change the default value. Note that it should be the parsed value +directly:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">ParsedVal</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:parse_header</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"content-type"</span><span style="color: #990000">>></span>, <span style="color: #009900">Req</span>, + {<span style="color: #990000"><<</span><span style="color: #FF0000">"text"</span><span style="color: #990000">>></span>, <span style="color: #990000"><<</span><span style="color: #FF0000">"plain"</span><span style="color: #990000">>></span>, []})<span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_peer">Peer</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The peer address and port number for the connection can be +retrieved either directly or using a function.</p></div> +<div class="paragraph"><p>To retrieve the peer directly:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>#{<span style="color: #FF6600">peer</span> <span style="color: #990000">:=</span> {<span style="color: #009900">IP</span>, <span style="color: #009900">Port</span>}} <span style="color: #990000">=</span> <span style="color: #009900">Req</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>And using a function:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #009900">IP</span>, <span style="color: #009900">Port</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:peer</span></span>(<span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Note that the peer corresponds to the remote end of the +connection to the server, which may or may not be the +client itself. It may also be a proxy or a gateway.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/static_files/"> + Static files + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/req_body/"> + Reading the request body + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/req_body.asciidoc b/docs/en/cowboy/2.2/guide/req_body.asciidoc new file mode 100644 index 00000000..4906811e --- /dev/null +++ b/docs/en/cowboy/2.2/guide/req_body.asciidoc @@ -0,0 +1,130 @@ +[[req_body]] +== Reading the request body + +The request body can be read using the Req object. + +Cowboy will not attempt to read the body until requested. +You need to call the body reading functions in order to +retrieve it. + +Cowboy will not cache the body, it is therefore only +possible to read it once. + +You are not required to read it, however. If a body is +present and was not read, Cowboy will either cancel or +skip its download, depending on the protocol. + +Cowboy provides functions for reading the body raw, +and read and parse form urlencoded or xref:multipart[multipart bodies]. +The latter is covered in its own chapter. + +=== Request body presence + +Not all requests come with a body. You can check for +the presence of a request body with this function: + +[source,erlang] +cowboy_req:has_body(Req). + +It returns `true` if there is a body; `false` otherwise. + +In practice, this function is rarely used. When the +method is `POST`, `PUT` or `PATCH`, the request body +is often required by the application, which should +just attempt to read it directly. + +=== Request body length + +You can obtain the length of the body: + +[source,erlang] +Length = cowboy_req:body_length(Req). + +Note that the length may not be known in advance. In +that case `undefined` will be returned. This can happen +with HTTP/1.1's chunked transfer-encoding, or HTTP/2 +when no content-length was provided. + +Cowboy will update the body length in the Req object +once the body has been read completely. A length will +always be returned when attempting to call this function +after reading the body completely. + +=== Reading the body + +You can read the entire body with one function call: + +[source,erlang] +{ok, Data, Req} = cowboy_req:read_body(Req0). + +Cowboy returns an `ok` tuple when the body has been +read fully. + +By default, Cowboy will attempt to read up to 8MB +of data, for up to 15 seconds. The call will return +once Cowboy has read at least 8MB of data, or at +the end of the 15 seconds period. + +These values can be customized. For example, to read +only up to 1MB for up to 5 seconds: + +[source,erlang] +---- +{ok, Data, Req} = cowboy_req:read_body(Req0, + #{length => 1000000, period => 5000}). +---- + +You may also disable the length limit: + +[source,erlang] +{ok, Data, Req} = cowboy_req:read_body(Req0, #{length => infinity}). + +This makes the function wait 15 seconds and return with +whatever arrived during that period. This is not +recommended for public facing applications. + +These two options can effectively be used to control +the rate of transmission of the request body. + +=== Streaming the body + +When the body is too large, the first call will return +a `more` tuple instead of `ok`. You can call the +function again to read more of the body, reading +it one chunk at a time. + +[source,erlang] +---- +read_body_to_console(Req0) -> + case cowboy_req:read_body(Req0) of + {ok, Data, Req} -> + io:format("~s", [Data]), + Req; + {more, Data, Req} -> + io:format("~s", [Data]), + read_body_to_console(Req) + end. +---- + +The `length` and `period` options can also be used. +They need to be passed for every call. + +=== Reading a form urlencoded body + +Cowboy provides a convenient function for reading and +parsing bodies sent as application/x-www-form-urlencoded. + +[source,erlang] +{ok, KeyValues, Req} = cowboy_req:read_urlencoded_body(Req0). + +This function returns a list of key/values, exactly like +the function `cowboy_req:parse_qs/1`. + +The defaults for this function are different. Cowboy will +read for up to 64KB and up to 5 seconds. They can be modified: + +[source,erlang] +---- +{ok, KeyValues, Req} = cowboy_req:read_urlencoded_body(Req0, + #{length => 4096, period => 3000}). +---- diff --git a/docs/en/cowboy/2.2/guide/req_body/index.html b/docs/en/cowboy/2.2/guide/req_body/index.html new file mode 100644 index 00000000..268c62a1 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/req_body/index.html @@ -0,0 +1,303 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Reading the request body</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Reading the request body</span></h1> + +<div class="paragraph"><p>The request body can be read using the Req object.</p></div> +<div class="paragraph"><p>Cowboy will not attempt to read the body until requested. +You need to call the body reading functions in order to +retrieve it.</p></div> +<div class="paragraph"><p>Cowboy will not cache the body, it is therefore only +possible to read it once.</p></div> +<div class="paragraph"><p>You are not required to read it, however. If a body is +present and was not read, Cowboy will either cancel or +skip its download, depending on the protocol.</p></div> +<div class="paragraph"><p>Cowboy provides functions for reading the body raw, +and read and parse form urlencoded or <a href="../multipart">multipart bodies</a>. +The latter is covered in its own chapter.</p></div> +<div class="sect1"> +<h2 id="_request_body_presence">Request body presence</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Not all requests come with a body. You can check for +the presence of a request body with this function:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">cowboy_req:has_body</span></span>(<span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>It returns <code>true</code> if there is a body; <code>false</code> otherwise.</p></div> +<div class="paragraph"><p>In practice, this function is rarely used. When the +method is <code>POST</code>, <code>PUT</code> or <code>PATCH</code>, the request body +is often required by the application, which should +just attempt to read it directly.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_request_body_length">Request body length</h2> +<div class="sectionbody"> +<div class="paragraph"><p>You can obtain the length of the body:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Length</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:body_length</span></span>(<span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Note that the length may not be known in advance. In +that case <code>undefined</code> will be returned. This can happen +with HTTP/1.1’s chunked transfer-encoding, or HTTP/2 +when no content-length was provided.</p></div> +<div class="paragraph"><p>Cowboy will update the body length in the Req object +once the body has been read completely. A length will +always be returned when attempting to call this function +after reading the body completely.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_reading_the_body">Reading the body</h2> +<div class="sectionbody"> +<div class="paragraph"><p>You can read the entire body with one function call:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF6600">ok</span>, <span style="color: #009900">Data</span>, <span style="color: #009900">Req</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:read_body</span></span>(<span style="color: #009900">Req0</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Cowboy returns an <code>ok</code> tuple when the body has been +read fully.</p></div> +<div class="paragraph"><p>By default, Cowboy will attempt to read up to 8MB +of data, for up to 15 seconds. The call will return +once Cowboy has read at least 8MB of data, or at +the end of the 15 seconds period.</p></div> +<div class="paragraph"><p>These values can be customized. For example, to read +only up to 1MB for up to 5 seconds:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF6600">ok</span>, <span style="color: #009900">Data</span>, <span style="color: #009900">Req</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:read_body</span></span>(<span style="color: #009900">Req0</span>, + #{<span style="font-weight: bold"><span style="color: #000080">length</span></span> <span style="color: #990000">=></span> <span style="color: #993399">1000000</span>, <span style="color: #0000FF">period</span> <span style="color: #990000">=></span> <span style="color: #993399">5000</span>})<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>You may also disable the length limit:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF6600">ok</span>, <span style="color: #009900">Data</span>, <span style="color: #009900">Req</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:read_body</span></span>(<span style="color: #009900">Req0</span>, #{<span style="font-weight: bold"><span style="color: #000080">length</span></span> <span style="color: #990000">=></span> <span style="color: #FF6600">infinity</span>})<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>This makes the function wait 15 seconds and return with +whatever arrived during that period. This is not +recommended for public facing applications.</p></div> +<div class="paragraph"><p>These two options can effectively be used to control +the rate of transmission of the request body.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_streaming_the_body">Streaming the body</h2> +<div class="sectionbody"> +<div class="paragraph"><p>When the body is too large, the first call will return +a <code>more</code> tuple instead of <code>ok</code>. You can call the +function again to read more of the body, reading +it one chunk at a time.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">read_body_to_console</span></span>(<span style="color: #009900">Req0</span>) <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #0000FF">case</span></span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:read_body</span></span>(<span style="color: #009900">Req0</span>) <span style="font-weight: bold"><span style="color: #0000FF">of</span></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">Data</span>, <span style="color: #009900">Req</span>} <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #000000">io:format</span></span>(<span style="color: #FF0000">"~s"</span>, [<span style="color: #009900">Data</span>]), + <span style="color: #009900">Req</span>; + {<span style="color: #FF6600">more</span>, <span style="color: #009900">Data</span>, <span style="color: #009900">Req</span>} <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #000000">io:format</span></span>(<span style="color: #FF0000">"~s"</span>, [<span style="color: #009900">Data</span>]), + <span style="font-weight: bold"><span style="color: #000000">read_body_to_console</span></span>(<span style="color: #009900">Req</span>) + <span style="font-weight: bold"><span style="color: #0000FF">end</span></span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>The <code>length</code> and <code>period</code> options can also be used. +They need to be passed for every call.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_reading_a_form_urlencoded_body">Reading a form urlencoded body</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy provides a convenient function for reading and +parsing bodies sent as application/x-www-form-urlencoded.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF6600">ok</span>, <span style="color: #009900">KeyValues</span>, <span style="color: #009900">Req</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:read_urlencoded_body</span></span>(<span style="color: #009900">Req0</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>This function returns a list of key/values, exactly like +the function <code>cowboy_req:parse_qs/1</code>.</p></div> +<div class="paragraph"><p>The defaults for this function are different. Cowboy will +read for up to 64KB and up to 5 seconds. They can be modified:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF6600">ok</span>, <span style="color: #009900">KeyValues</span>, <span style="color: #009900">Req</span>} <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:read_urlencoded_body</span></span>(<span style="color: #009900">Req0</span>, + #{<span style="font-weight: bold"><span style="color: #000080">length</span></span> <span style="color: #990000">=></span> <span style="color: #993399">4096</span>, <span style="color: #0000FF">period</span> <span style="color: #990000">=></span> <span style="color: #993399">3000</span>})<span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/req/"> + The Req object + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/resp/"> + Sending a response + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/resource_design.asciidoc b/docs/en/cowboy/2.2/guide/resource_design.asciidoc new file mode 100644 index 00000000..fa0c6122 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/resource_design.asciidoc @@ -0,0 +1,220 @@ +[[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 + +Can the service become unavailable, and when it does, can +we detect it? For example, database connectivity problems +may be detected early. We may also have planned outages +of all or parts of the system. Implement the +`service_available` callback. + +What HTTP methods does the service implement? Do we need +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 + +Am I writing a handler for a collection of resources, +or for a single resource? + +The semantics for each of these are quite different. +You should not mix collection and single resource in +the same handler. + +=== Collection handler + +Skip this section if you are not doing a collection. + +Is the collection hardcoded or dynamic? For example, +if you use the route `/users` for the collection of +users then the collection is hardcoded; if you use +`/forums/:category` for the collection of threads +then it isn't. When the collection is hardcoded you +can safely assume the resource always exists. + +What methods should I implement? + +OPTIONS is used to get some information about the +collection. It is recommended to allow it even if you +do not implement it, as Cowboy has a default +implementation built-in. + +HEAD and GET are used to retrieve the collection. +If you allow GET, also allow HEAD as there's no extra +work required to make it work. + +POST is used to create a new resource inside the +collection. Creating a resource by using POST on +the collection is useful when resources may be +created before knowing their URI, usually because +parts of it are generated dynamically. A common +case is some kind of auto incremented integer +identifier. + +The next methods are more rarely allowed. + +PUT is used to create a new collection (when +the collection isn't hardcoded), or replace +the entire collection. + +DELETE is used to delete the entire collection. + +PATCH is used to modify the collection using +instructions given in the request body. A PATCH +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 + +Skip this section if you are doing a collection. + +What methods should I implement? + +OPTIONS is used to get some information about the +resource. It is recommended to allow it even if you +do not implement it, as Cowboy has a default +implementation built-in. + +HEAD and GET are used to retrieve the resource. +If you allow GET, also allow HEAD as there's no extra +work required to make it work. + +POST is used to update the resource. + +PUT is used to create a new resource (when it doesn't +already exist) or replace the resource. + +DELETE is used to delete the resource. + +PATCH is used to modify the resource using +instructions given in the request body. A PATCH +operation is atomic. The PATCH operation may +be used for adding, removing or modifying specific +values in the resource. + +=== The resource + +Following the above discussion, implement the +`allowed_methods` callback. + +Does the resource always exist? If it may not, implement +the `resource_exists` callback. + +Do I need to authenticate the client before they can +access the resource? What authentication mechanisms +should I provide? This may include form-based, token-based +(in the URL or a cookie), HTTP basic, HTTP digest, +SSL certificate or any other form of authentication. +Implement the `is_authorized` callback. + +Do I need fine-grained access control? How do I determine +that they are authorized access? Handle that in your +`is_authorized` callback. + +Can access to a resource be forbidden regardless of access +being authorized? A simple example of that is censorship +of a resource. Implement the `forbidden` callback. + +Are 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 + +What media types do I provide? If text based, what charsets +are provided? What languages do I provide? + +Implement the mandatory `content_types_provided`. Prefix +the callbacks with `to_` for clarity. For example, `to_html` +or `to_text`. + +Implement the `languages_provided` or `charsets_provided` +callbacks if applicable. + +Is there any other header that may make the representation +of the resource vary? Implement the `variances` callback. + +Depending on your choices for caching content, you may +want to implement one or more of the `generate_etag`, +`last_modified` and `expires` callbacks. + +Do I want the user or user agent to actively choose a +representation available? Send a list of available +representations in the response body and implement +the `multiple_choices` callback. + +=== Redirections + +Do I need to keep track of what resources were deleted? +For example, you may have a mechanism where moving a +resource leaves a redirect link to its new location. +Implement the `previously_existed` callback. + +Was the resource moved, and is the move temporary? If +it is explicitly temporary, for example due to maintenance, +implement the `moved_temporarily` callback. Otherwise, +implement the `moved_permanently` callback. + +=== The request + +Do you need to read the query string? Individual headers? +Implement `malformed_request` and do all the parsing and +validation in this function. Note that the body should not +be read at this point. + +May there be a request body? Will I know its size? +What's the maximum size of the request body I'm willing +to accept? Implement `valid_entity_length`. + +Finally, take a look at the sections corresponding to the +methods you are implementing. + +=== 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 + +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 + +If you implement the methods PUT, POST and/or PATCH, +you must implement the `content_types_accepted` callback, +and one `AcceptCallback` callback for each content-type +it returns. Prefix the `AcceptCallback` callback names +with `from_` for clarity. For example, `from_html` or +`from_json`. + +Do we want to allow the POST method to create individual +resources directly through their URI (like PUT)? Implement +the `allow_missing_post` callback. It is recommended to +explicitly use PUT in these cases instead. + +May there be conflicts when using PUT to create or replace +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 + +If you implement the method DELETE, you must implement +the `delete_resource` callback. + +When `delete_resource` returns, is the resource completely +removed from the server, including from any caching service? +If not, and/or if the deletion is asynchronous and we have +no way of knowing it has been completed yet, implement the +`delete_completed` callback. diff --git a/docs/en/cowboy/2.2/guide/resource_design/index.html b/docs/en/cowboy/2.2/guide/resource_design/index.html new file mode 100644 index 00000000..4823d848 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/resource_design/index.html @@ -0,0 +1,372 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Designing a resource handler</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Designing a resource handler</span></h1> + +<div class="paragraph"><p>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.</p></div> +<div class="sect1"> +<h2 id="_the_service">The service</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Can the service become unavailable, and when it does, can +we detect it? For example, database connectivity problems +may be detected early. We may also have planned outages +of all or parts of the system. Implement the +<code>service_available</code> callback.</p></div> +<div class="paragraph"><p>What HTTP methods does the service implement? Do we need +more than the standard OPTIONS, HEAD, GET, PUT, POST, +PATCH and DELETE? Are we not using one of those at all? +Implement the <code>known_methods</code> callback.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_type_of_resource_handler">Type of resource handler</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Am I writing a handler for a collection of resources, +or for a single resource?</p></div> +<div class="paragraph"><p>The semantics for each of these are quite different. +You should not mix collection and single resource in +the same handler.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_collection_handler">Collection handler</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Skip this section if you are not doing a collection.</p></div> +<div class="paragraph"><p>Is the collection hardcoded or dynamic? For example, +if you use the route <code>/users</code> for the collection of +users then the collection is hardcoded; if you use +<code>/forums/:category</code> for the collection of threads +then it isn’t. When the collection is hardcoded you +can safely assume the resource always exists.</p></div> +<div class="paragraph"><p>What methods should I implement?</p></div> +<div class="paragraph"><p>OPTIONS is used to get some information about the +collection. It is recommended to allow it even if you +do not implement it, as Cowboy has a default +implementation built-in.</p></div> +<div class="paragraph"><p>HEAD and GET are used to retrieve the collection. +If you allow GET, also allow HEAD as there’s no extra +work required to make it work.</p></div> +<div class="paragraph"><p>POST is used to create a new resource inside the +collection. Creating a resource by using POST on +the collection is useful when resources may be +created before knowing their URI, usually because +parts of it are generated dynamically. A common +case is some kind of auto incremented integer +identifier.</p></div> +<div class="paragraph"><p>The next methods are more rarely allowed.</p></div> +<div class="paragraph"><p>PUT is used to create a new collection (when +the collection isn’t hardcoded), or replace +the entire collection.</p></div> +<div class="paragraph"><p>DELETE is used to delete the entire collection.</p></div> +<div class="paragraph"><p>PATCH is used to modify the collection using +instructions given in the request body. A PATCH +operation is atomic. The PATCH operation may +be used for such things as reordering; adding, +modifying or deleting parts of the collection.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_single_resource_handler">Single resource handler</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Skip this section if you are doing a collection.</p></div> +<div class="paragraph"><p>What methods should I implement?</p></div> +<div class="paragraph"><p>OPTIONS is used to get some information about the +resource. It is recommended to allow it even if you +do not implement it, as Cowboy has a default +implementation built-in.</p></div> +<div class="paragraph"><p>HEAD and GET are used to retrieve the resource. +If you allow GET, also allow HEAD as there’s no extra +work required to make it work.</p></div> +<div class="paragraph"><p>POST is used to update the resource.</p></div> +<div class="paragraph"><p>PUT is used to create a new resource (when it doesn’t +already exist) or replace the resource.</p></div> +<div class="paragraph"><p>DELETE is used to delete the resource.</p></div> +<div class="paragraph"><p>PATCH is used to modify the resource using +instructions given in the request body. A PATCH +operation is atomic. The PATCH operation may +be used for adding, removing or modifying specific +values in the resource.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_the_resource">The resource</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Following the above discussion, implement the +<code>allowed_methods</code> callback.</p></div> +<div class="paragraph"><p>Does the resource always exist? If it may not, implement +the <code>resource_exists</code> callback.</p></div> +<div class="paragraph"><p>Do I need to authenticate the client before they can +access the resource? What authentication mechanisms +should I provide? This may include form-based, token-based +(in the URL or a cookie), HTTP basic, HTTP digest, +SSL certificate or any other form of authentication. +Implement the <code>is_authorized</code> callback.</p></div> +<div class="paragraph"><p>Do I need fine-grained access control? How do I determine +that they are authorized access? Handle that in your +<code>is_authorized</code> callback.</p></div> +<div class="paragraph"><p>Can access to a resource be forbidden regardless of access +being authorized? A simple example of that is censorship +of a resource. Implement the <code>forbidden</code> callback.</p></div> +<div class="paragraph"><p>Are 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 <code>uri_too_long</code>.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_representations">Representations</h2> +<div class="sectionbody"> +<div class="paragraph"><p>What media types do I provide? If text based, what charsets +are provided? What languages do I provide?</p></div> +<div class="paragraph"><p>Implement the mandatory <code>content_types_provided</code>. Prefix +the callbacks with <code>to_</code> for clarity. For example, <code>to_html</code> +or <code>to_text</code>.</p></div> +<div class="paragraph"><p>Implement the <code>languages_provided</code> or <code>charsets_provided</code> +callbacks if applicable.</p></div> +<div class="paragraph"><p>Is there any other header that may make the representation +of the resource vary? Implement the <code>variances</code> callback.</p></div> +<div class="paragraph"><p>Depending on your choices for caching content, you may +want to implement one or more of the <code>generate_etag</code>, +<code>last_modified</code> and <code>expires</code> callbacks.</p></div> +<div class="paragraph"><p>Do I want the user or user agent to actively choose a +representation available? Send a list of available +representations in the response body and implement +the <code>multiple_choices</code> callback.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_redirections">Redirections</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Do I need to keep track of what resources were deleted? +For example, you may have a mechanism where moving a +resource leaves a redirect link to its new location. +Implement the <code>previously_existed</code> callback.</p></div> +<div class="paragraph"><p>Was the resource moved, and is the move temporary? If +it is explicitly temporary, for example due to maintenance, +implement the <code>moved_temporarily</code> callback. Otherwise, +implement the <code>moved_permanently</code> callback.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_the_request">The request</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Do you need to read the query string? Individual headers? +Implement <code>malformed_request</code> and do all the parsing and +validation in this function. Note that the body should not +be read at this point.</p></div> +<div class="paragraph"><p>May there be a request body? Will I know its size? +What’s the maximum size of the request body I’m willing +to accept? Implement <code>valid_entity_length</code>.</p></div> +<div class="paragraph"><p>Finally, take a look at the sections corresponding to the +methods you are implementing.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_options_method">OPTIONS method</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy by default will send back a list of allowed methods. +Do I need to add more information to the response? Implement +the <code>options</code> method.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_get_and_head_methods">GET and HEAD methods</h2> +<div class="sectionbody"> +<div class="paragraph"><p>If you implement the methods GET and/or HEAD, you must +implement one <code>ProvideResource</code> callback for each +content-type returned by the <code>content_types_provided</code> +callback.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_put_post_and_patch_methods">PUT, POST and PATCH methods</h2> +<div class="sectionbody"> +<div class="paragraph"><p>If you implement the methods PUT, POST and/or PATCH, +you must implement the <code>content_types_accepted</code> callback, +and one <code>AcceptCallback</code> callback for each content-type +it returns. Prefix the <code>AcceptCallback</code> callback names +with <code>from_</code> for clarity. For example, <code>from_html</code> or +<code>from_json</code>.</p></div> +<div class="paragraph"><p>Do we want to allow the POST method to create individual +resources directly through their URI (like PUT)? Implement +the <code>allow_missing_post</code> callback. It is recommended to +explicitly use PUT in these cases instead.</p></div> +<div class="paragraph"><p>May there be conflicts when using PUT to create or replace +a resource? Do we want to make sure that two updates around +the same time are not cancelling one another? Implement the +<code>is_conflict</code> callback.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_delete_methods">DELETE methods</h2> +<div class="sectionbody"> +<div class="paragraph"><p>If you implement the method DELETE, you must implement +the <code>delete_resource</code> callback.</p></div> +<div class="paragraph"><p>When <code>delete_resource</code> returns, is the resource completely +removed from the server, including from any caching service? +If not, and/or if the deletion is asynchronous and we have +no way of knowing it has been completed yet, implement the +<code>delete_completed</code> callback.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/rest_flowcharts/"> + REST flowcharts + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/ws_protocol/"> + The Websocket protocol + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/resp.asciidoc b/docs/en/cowboy/2.2/guide/resp.asciidoc new file mode 100644 index 00000000..6d4967e0 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/resp.asciidoc @@ -0,0 +1,341 @@ +[[resp]] +== Sending a response + +The response must be sent using the Req object. + +Cowboy provides two different ways of sending responses: +either directly or by streaming the body. Response headers +and body may be set in advance. The response is sent as +soon as one of the reply or stream reply function is +called. + +Cowboy also provides a simplified interface for sending +files. It can also send only specific parts of a file. + +While only one response is allowed for every request, +HTTP/2 introduced a mechanism that allows the server +to push additional resources related to the response. +This chapter also describes how this feature works in +Cowboy. + +=== Reply + +Cowboy provides three functions for sending the entire reply, +depending on whether you need to set headers and body. In all +cases, Cowboy will add any headers required by the protocol +(for example the date header will always be sent). + +When you need to set only the status code, +use `cowboy_req:reply/2`: + +[source,erlang] +Req = cowboy_req:reply(200, Req0). + +When you need to set response headers at the same time, +use `cowboy_req:reply/3`: + +[source,erlang] +---- +Req = cowboy_req:reply(303, #{ + <<"location">> => <<"https://ninenines.eu">> +}, Req0). +---- + +Note that the header name must always be a lowercase +binary. + +When you also need to set the response body, +use `cowboy_req:reply/4`: + +[source,erlang] +---- +Req = cowboy_req:reply(200, #{ + <<"content-type">> => <<"text/plain">> +}, "Hello world!", Req0). +---- + +You should always set the content-type header when the +response has a body. There is however no need to set +the content-length header; Cowboy does it automatically. + +The response body and the header values must be either +a binary or an iolist. An iolist is a list containing +binaries, characters, strings or other iolists. This +allows you to build a response from different parts +without having to do any concatenation: + +[source,erlang] +---- +Title = "Hello world!", +Body = <<"Hats off!">>, +Req = cowboy_req:reply(200, #{ + <<"content-type">> => <<"text/html">> +}, ["<html><head><title>", Title, "</title></head>", + "<body><p>", Body, "</p></body></html>"], Req0). +---- + +This method of building responses is more efficient than +concatenating. Behind the scenes, each element of the list +is simply a pointer, and those pointers are used directly +when writing to the socket. + +=== Stream reply + +Cowboy provides two functions for initiating a response, +and an additional function for streaming the response body. +Cowboy will add any required headers to the response. + +// @todo For HTTP/1.1 Cowboy should probably not use chunked transfer-encoding if the content-length is set. + +When you need to set only the status code, +use `cowboy_req:stream_reply/2`: + +[source,erlang] +---- +Req = cowboy_req:stream_reply(200, Req0), + +cowboy_req:stream_body("Hello...", nofin, Req), +cowboy_req:stream_body("chunked...", nofin, Req), +cowboy_req:stream_body("world!!", fin, Req). +---- + +The second argument to `cowboy_req:stream_body/3` indicates +whether this data terminates the body. Use `fin` for the +final flag, and `nofin` otherwise. + +This snippet does not set a content-type header. This is +not recommended. All responses with a body should have +a content-type. The header can be set beforehand, or +using the `cowboy_req:stream_reply/3`: + +[source,erlang] +---- +Req = cowboy_req:stream_reply(200, #{ + <<"content-type">> => <<"text/html">> +}, Req0), + +cowboy_req:stream_body("<html><head>Hello world!</head>", nofin, Req), +cowboy_req:stream_body("<body><p>Hats off!</p></body></html>", fin, Req). +---- + +HTTP provides a few different ways to stream response bodies. +Cowboy will select the most appropriate one based on the HTTP +version and the request and response headers. + +While not required by any means, it is recommended that you +set the content-length header in the response if you know it +in advance. This will ensure that the best response method +is selected and help clients understand when the response +is fully received. + +// @todo Document trailers here. + +=== Preset response headers + +Cowboy provides functions to set response headers without +immediately sending them. They are stored in the Req object +and sent as part of the response when a reply function is +called. + +To set response headers: + +[source,erlang] +Req = cowboy_req:set_resp_header(<<"allow">>, "GET", Req0). + +Header names must be a lowercase binary. + +Do not use this function for setting cookies. Refer to +the xref:cookies[Cookies] chapter for more information. + +To check if a response header has already been set: + +[source,erlang] +cowboy_req:has_resp_header(<<"allow">>, Req). + +It returns `true` if the header was set, `false` otherwise. + +To delete a response header that was set previously: + +[source,erlang] +Req = cowboy_req:delete_resp_header(<<"allow">>, Req0). + +=== Overriding headers + +As Cowboy provides different ways of setting response +headers and body, clashes may occur, so it's important +to understand what happens when a header is set twice. + +Headers come from five different origins: + +* Protocol-specific headers (for example HTTP/1.1's connection header) +* Other required headers (for example the date header) +* Preset headers +* Headers given to the reply function +* Set-cookie headers + +Cowboy does not allow overriding protocol-specific headers. + +Set-cookie headers will always be appended at the end of +the list of headers before sending the response. + +Headers given to the reply function will always override +preset headers and required headers. If a header is found +in two or three of these, then the one in the reply function +is picked and the others are dropped. + +Similarly, preset headers will always override required +headers. + +To illustrate, look at the following snippet. Cowboy by +default sends the server header with the value "Cowboy". +We can override it: + +[source,erlang] +---- +Req = cowboy_req:reply(200, #{ + <<"server">> => <<"yaws">> +}, Req0). +---- + +=== Preset response body + +Cowboy provides functions to set the response body without +immediately sending it. It is stored in the Req object and +sent when the reply function is called. + +To set the response body: + +[source,erlang] +Req = cowboy_req:set_resp_body("Hello world!", Req0). + +// @todo Yeah we probably should add that function that +// also sets the content-type at the same time... + +To check if a response body has already been set: + +[source,erlang] +cowboy_req:has_resp_body(Req). + +It returns `true` if the body was set and is non-empty, +`false` otherwise. + +// @todo We probably should also have a function that +// properly removes the response body, including any +// content-* headers. + +The preset response body is only sent if the reply function +used is `cowboy_req:reply/2` or `cowboy_req:reply/3`. + +=== Sending files + +Cowboy provides a shortcut for sending files. When +using `cowboy_req:reply/4`, or when presetting the +response header, you can give a `sendfile` tuple to +Cowboy: + +[source,erlang] +{sendfile, Offset, Length, Filename} + +Depending on the values for `Offset` or `Length`, the +entire file may be sent, or just a part of it. + +The length is required even for sending the entire file. +Cowboy sends it in the content-length header. + +To send a file while replying: + +[source,erlang] +---- +Req = cowboy_req:reply(200, #{ + <<"content-type">> => "image/png" +}, {sendfile, 0, 12345, "path/to/logo.png"}, Req0). +---- + +// @todo An example of presetting a file would be useful, +// but let's wait for the function that can set the +// content-type at the same time. + +// @todo What about streaming many files? For example +// it should be possible to build a tar file on the fly +// while still using sendfile. Another example could be +// proper support for multipart byte ranges. Yet another +// example would be automatic concatenation of CSS or JS +// files. + +=== Informational responses + +Cowboy allows you to send informational responses. + +Informational responses are responses that have a status +code between 100 and 199. Any number can be sent before +the proper response. Sending an informational response +does not change the behavior of the proper response, and +clients are expected to ignore any informational response +they do not understand. + +The following snippet sends a 103 informational response +with some headers that are expected to be in the final +response. + +[source,erlang] +---- +Req = cowboy_req:inform(103, #{ + <<"link">> => <<"</style.css>; rel=preload; as=style">>, + <<"link">> => <<"</script.js>; rel=preload; as=script">> +}, Req0). +---- + +=== Push + +The HTTP/2 protocol introduced the ability to push resources +related to the one sent in the response. Cowboy provides two +functions for that purpose: `cowboy_req:push/3,4`. + +Push is only available for HTTP/2. Cowboy will automatically +ignore push requests if the protocol doesn't support it. + +The push function must be called before any of the reply +functions. Doing otherwise will result in a crash. + +To push a resource, you need to provide the same information +as a client performing a request would. This includes the +HTTP method, the URI and any necessary request headers. + +Cowboy by default only requires you to give the path to +the resource and the request headers. The rest of the URI +is taken from the current request (excluding the query +string, set to empty) and the method is GET by default. + +The following snippet pushes a CSS file that is linked to +in the response: + +[source,erlang] +---- +cowboy_req:push("/static/style.css", #{ + <<"accept">> => <<"text/css">> +}, Req0), +Req = cowboy_req:reply(200, #{ + <<"content-type">> => <<"text/html">> +}, ["<html><head><title>My web page</title>", + "<link rel='stylesheet' type='text/css' href='/static/style.css'>", + "<body><p>Welcome to Erlang!</p></body></html>"], Req0). +---- + +To override the method, scheme, host, port or query string, +simply pass in a fourth argument. The following snippet +uses a different host name: + +[source,erlang] +---- +cowboy_req:push("/static/style.css", #{ + <<"accept">> => <<"text/css">> +}, #{host => <<"cdn.example.org">>}, Req), +---- + +Pushed resources don't have to be files. As long as the push +request is cacheable, safe and does not include a body, the +resource can be pushed. + +Under the hood, Cowboy handles pushed requests the same as +normal requests: a different process is created which will +ultimately send a response to the client. diff --git a/docs/en/cowboy/2.2/guide/resp/index.html b/docs/en/cowboy/2.2/guide/resp/index.html new file mode 100644 index 00000000..0b18cc4c --- /dev/null +++ b/docs/en/cowboy/2.2/guide/resp/index.html @@ -0,0 +1,505 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Sending a response</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Sending a response</span></h1> + +<div class="paragraph"><p>The response must be sent using the Req object.</p></div> +<div class="paragraph"><p>Cowboy provides two different ways of sending responses: +either directly or by streaming the body. Response headers +and body may be set in advance. The response is sent as +soon as one of the reply or stream reply function is +called.</p></div> +<div class="paragraph"><p>Cowboy also provides a simplified interface for sending +files. It can also send only specific parts of a file.</p></div> +<div class="paragraph"><p>While only one response is allowed for every request, +HTTP/2 introduced a mechanism that allows the server +to push additional resources related to the response. +This chapter also describes how this feature works in +Cowboy.</p></div> +<div class="sect1"> +<h2 id="_reply">Reply</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy provides three functions for sending the entire reply, +depending on whether you need to set headers and body. In all +cases, Cowboy will add any headers required by the protocol +(for example the date header will always be sent).</p></div> +<div class="paragraph"><p>When you need to set only the status code, +use <code>cowboy_req:reply/2</code>:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:reply</span></span>(<span style="color: #993399">200</span>, <span style="color: #009900">Req0</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>When you need to set response headers at the same time, +use <code>cowboy_req:reply/3</code>:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:reply</span></span>(<span style="color: #993399">303</span>, #{ + <span style="color: #990000"><<</span><span style="color: #FF0000">"location"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"https://ninenines.eu"</span><span style="color: #990000">>></span> +}, <span style="color: #009900">Req0</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Note that the header name must always be a lowercase +binary.</p></div> +<div class="paragraph"><p>When you also need to set the response body, +use <code>cowboy_req:reply/4</code>:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:reply</span></span>(<span style="color: #993399">200</span>, #{ + <span style="color: #990000"><<</span><span style="color: #FF0000">"content-type"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"text/plain"</span><span style="color: #990000">>></span> +}, <span style="color: #FF0000">"Hello world!"</span>, <span style="color: #009900">Req0</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>You should always set the content-type header when the +response has a body. There is however no need to set +the content-length header; Cowboy does it automatically.</p></div> +<div class="paragraph"><p>The response body and the header values must be either +a binary or an iolist. An iolist is a list containing +binaries, characters, strings or other iolists. This +allows you to build a response from different parts +without having to do any concatenation:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Title</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"Hello world!"</span>, +<span style="color: #009900">Body</span> <span style="color: #990000">=</span> <span style="color: #990000"><<</span><span style="color: #FF0000">"Hats off!"</span><span style="color: #990000">>></span>, +<span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:reply</span></span>(<span style="color: #993399">200</span>, #{ + <span style="color: #990000"><<</span><span style="color: #FF0000">"content-type"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"text/html"</span><span style="color: #990000">>></span> +}, [<span style="color: #FF0000">"<html><head><title>"</span>, <span style="color: #009900">Title</span>, <span style="color: #FF0000">"</title></head>"</span>, + <span style="color: #FF0000">"<body><p>"</span>, <span style="color: #009900">Body</span>, <span style="color: #FF0000">"</p></body></html>"</span>], <span style="color: #009900">Req0</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>This method of building responses is more efficient than +concatenating. Behind the scenes, each element of the list +is simply a pointer, and those pointers are used directly +when writing to the socket.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_stream_reply">Stream reply</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy provides two functions for initiating a response, +and an additional function for streaming the response body. +Cowboy will add any required headers to the response.</p></div> +<div class="paragraph"><p>When you need to set only the status code, +use <code>cowboy_req:stream_reply/2</code>:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:stream_reply</span></span>(<span style="color: #993399">200</span>, <span style="color: #009900">Req0</span>), + +<span style="font-weight: bold"><span style="color: #000000">cowboy_req:stream_body</span></span>(<span style="color: #FF0000">"Hello..."</span>, <span style="color: #FF6600">nofin</span>, <span style="color: #009900">Req</span>), +<span style="font-weight: bold"><span style="color: #000000">cowboy_req:stream_body</span></span>(<span style="color: #FF0000">"chunked..."</span>, <span style="color: #FF6600">nofin</span>, <span style="color: #009900">Req</span>), +<span style="font-weight: bold"><span style="color: #000000">cowboy_req:stream_body</span></span>(<span style="color: #FF0000">"world!!"</span>, <span style="color: #FF6600">fin</span>, <span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>The second argument to <code>cowboy_req:stream_body/3</code> indicates +whether this data terminates the body. Use <code>fin</code> for the +final flag, and <code>nofin</code> otherwise.</p></div> +<div class="paragraph"><p>This snippet does not set a content-type header. This is +not recommended. All responses with a body should have +a content-type. The header can be set beforehand, or +using the <code>cowboy_req:stream_reply/3</code>:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:stream_reply</span></span>(<span style="color: #993399">200</span>, #{ + <span style="color: #990000"><<</span><span style="color: #FF0000">"content-type"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"text/html"</span><span style="color: #990000">>></span> +}, <span style="color: #009900">Req0</span>), + +<span style="font-weight: bold"><span style="color: #000000">cowboy_req:stream_body</span></span>(<span style="color: #FF0000">"<html><head>Hello world!</head>"</span>, <span style="color: #FF6600">nofin</span>, <span style="color: #009900">Req</span>), +<span style="font-weight: bold"><span style="color: #000000">cowboy_req:stream_body</span></span>(<span style="color: #FF0000">"<body><p>Hats off!</p></body></html>"</span>, <span style="color: #FF6600">fin</span>, <span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>HTTP provides a few different ways to stream response bodies. +Cowboy will select the most appropriate one based on the HTTP +version and the request and response headers.</p></div> +<div class="paragraph"><p>While not required by any means, it is recommended that you +set the content-length header in the response if you know it +in advance. This will ensure that the best response method +is selected and help clients understand when the response +is fully received.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_preset_response_headers">Preset response headers</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy provides functions to set response headers without +immediately sending them. They are stored in the Req object +and sent as part of the response when a reply function is +called.</p></div> +<div class="paragraph"><p>To set response headers:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:set_resp_header</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"allow"</span><span style="color: #990000">>></span>, <span style="color: #FF0000">"GET"</span>, <span style="color: #009900">Req0</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Header names must be a lowercase binary.</p></div> +<div class="paragraph"><p>Do not use this function for setting cookies. Refer to +the <a href="../cookies">Cookies</a> chapter for more information.</p></div> +<div class="paragraph"><p>To check if a response header has already been set:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">cowboy_req:has_resp_header</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"allow"</span><span style="color: #990000">>></span>, <span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>It returns <code>true</code> if the header was set, <code>false</code> otherwise.</p></div> +<div class="paragraph"><p>To delete a response header that was set previously:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:delete_resp_header</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"allow"</span><span style="color: #990000">>></span>, <span style="color: #009900">Req0</span>)<span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_overriding_headers">Overriding headers</h2> +<div class="sectionbody"> +<div class="paragraph"><p>As Cowboy provides different ways of setting response +headers and body, clashes may occur, so it’s important +to understand what happens when a header is set twice.</p></div> +<div class="paragraph"><p>Headers come from five different origins:</p></div> +<div class="ulist"><ul> +<li> +<p> +Protocol-specific headers (for example HTTP/1.1’s connection header) +</p> +</li> +<li> +<p> +Other required headers (for example the date header) +</p> +</li> +<li> +<p> +Preset headers +</p> +</li> +<li> +<p> +Headers given to the reply function +</p> +</li> +<li> +<p> +Set-cookie headers +</p> +</li> +</ul></div> +<div class="paragraph"><p>Cowboy does not allow overriding protocol-specific headers.</p></div> +<div class="paragraph"><p>Set-cookie headers will always be appended at the end of +the list of headers before sending the response.</p></div> +<div class="paragraph"><p>Headers given to the reply function will always override +preset headers and required headers. If a header is found +in two or three of these, then the one in the reply function +is picked and the others are dropped.</p></div> +<div class="paragraph"><p>Similarly, preset headers will always override required +headers.</p></div> +<div class="paragraph"><p>To illustrate, look at the following snippet. Cowboy by +default sends the server header with the value "Cowboy". +We can override it:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:reply</span></span>(<span style="color: #993399">200</span>, #{ + <span style="color: #990000"><<</span><span style="color: #FF0000">"server"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"yaws"</span><span style="color: #990000">>></span> +}, <span style="color: #009900">Req0</span>)<span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_preset_response_body">Preset response body</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy provides functions to set the response body without +immediately sending it. It is stored in the Req object and +sent when the reply function is called.</p></div> +<div class="paragraph"><p>To set the response body:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:set_resp_body</span></span>(<span style="color: #FF0000">"Hello world!"</span>, <span style="color: #009900">Req0</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>To check if a response body has already been set:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">cowboy_req:has_resp_body</span></span>(<span style="color: #009900">Req</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>It returns <code>true</code> if the body was set and is non-empty, +<code>false</code> otherwise.</p></div> +<div class="paragraph"><p>The preset response body is only sent if the reply function +used is <code>cowboy_req:reply/2</code> or <code>cowboy_req:reply/3</code>.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_sending_files">Sending files</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy provides a shortcut for sending files. When +using <code>cowboy_req:reply/4</code>, or when presetting the +response header, you can give a <code>sendfile</code> tuple to +Cowboy:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF6600">sendfile</span>, <span style="color: #009900">Offset</span>, <span style="color: #009900">Length</span>, <span style="color: #009900">Filename</span>}</tt></pre></div></div> +<div class="paragraph"><p>Depending on the values for <code>Offset</code> or <code>Length</code>, the +entire file may be sent, or just a part of it.</p></div> +<div class="paragraph"><p>The length is required even for sending the entire file. +Cowboy sends it in the content-length header.</p></div> +<div class="paragraph"><p>To send a file while replying:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:reply</span></span>(<span style="color: #993399">200</span>, #{ + <span style="color: #990000"><<</span><span style="color: #FF0000">"content-type"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #FF0000">"image/png"</span> +}, {<span style="color: #FF6600">sendfile</span>, <span style="color: #993399">0</span>, <span style="color: #993399">12345</span>, <span style="color: #FF0000">"path/to/logo.png"</span>}, <span style="color: #009900">Req0</span>)<span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_informational_responses">Informational responses</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy allows you to send informational responses.</p></div> +<div class="paragraph"><p>Informational responses are responses that have a status +code between 100 and 199. Any number can be sent before +the proper response. Sending an informational response +does not change the behavior of the proper response, and +clients are expected to ignore any informational response +they do not understand.</p></div> +<div class="paragraph"><p>The following snippet sends a 103 informational response +with some headers that are expected to be in the final +response.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:inform</span></span>(<span style="color: #993399">103</span>, #{ + <span style="color: #990000"><<</span><span style="color: #FF0000">"link"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"</style.css>; rel=preload; as=style"</span><span style="color: #990000">>></span>, + <span style="color: #990000"><<</span><span style="color: #FF0000">"link"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"</script.js>; rel=preload; as=script"</span><span style="color: #990000">>></span> +}, <span style="color: #009900">Req0</span>)<span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_push">Push</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The HTTP/2 protocol introduced the ability to push resources +related to the one sent in the response. Cowboy provides two +functions for that purpose: <code>cowboy_req:push/3,4</code>.</p></div> +<div class="paragraph"><p>Push is only available for HTTP/2. Cowboy will automatically +ignore push requests if the protocol doesn’t support it.</p></div> +<div class="paragraph"><p>The push function must be called before any of the reply +functions. Doing otherwise will result in a crash.</p></div> +<div class="paragraph"><p>To push a resource, you need to provide the same information +as a client performing a request would. This includes the +HTTP method, the URI and any necessary request headers.</p></div> +<div class="paragraph"><p>Cowboy by default only requires you to give the path to +the resource and the request headers. The rest of the URI +is taken from the current request (excluding the query +string, set to empty) and the method is GET by default.</p></div> +<div class="paragraph"><p>The following snippet pushes a CSS file that is linked to +in the response:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">cowboy_req:push</span></span>(<span style="color: #FF0000">"/static/style.css"</span>, #{ + <span style="color: #990000"><<</span><span style="color: #FF0000">"accept"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"text/css"</span><span style="color: #990000">>></span> +}, <span style="color: #009900">Req0</span>), +<span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:reply</span></span>(<span style="color: #993399">200</span>, #{ + <span style="color: #990000"><<</span><span style="color: #FF0000">"content-type"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"text/html"</span><span style="color: #990000">>></span> +}, [<span style="color: #FF0000">"<html><head><title>My web page</title>"</span>, + <span style="color: #FF0000">"<link rel='stylesheet' type='text/css' href='/static/style.css'>"</span>, + <span style="color: #FF0000">"<body><p>Welcome to Erlang!</p></body></html>"</span>], <span style="color: #009900">Req0</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>To override the method, scheme, host, port or query string, +simply pass in a fourth argument. The following snippet +uses a different host name:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">cowboy_req:push</span></span>(<span style="color: #FF0000">"/static/style.css"</span>, #{ + <span style="color: #990000"><<</span><span style="color: #FF0000">"accept"</span><span style="color: #990000">>></span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"text/css"</span><span style="color: #990000">>></span> +}, #{<span style="color: #0000FF">host</span> <span style="color: #990000">=></span> <span style="color: #990000"><<</span><span style="color: #FF0000">"cdn.example.org"</span><span style="color: #990000">>></span>}, <span style="color: #009900">Req</span>),</tt></pre></div></div> +<div class="paragraph"><p>Pushed resources don’t have to be files. As long as the push +request is cacheable, safe and does not include a body, the +resource can be pushed.</p></div> +<div class="paragraph"><p>Under the hood, Cowboy handles pushed requests the same as +normal requests: a different process is created which will +ultimately send a response to the client.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/req_body/"> + Reading the request body + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/cookies/"> + Using cookies + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/rest_cond.png b/docs/en/cowboy/2.2/guide/rest_cond.png Binary files differnew file mode 100644 index 00000000..64cda347 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_cond.png diff --git a/docs/en/cowboy/2.2/guide/rest_cond.svg b/docs/en/cowboy/2.2/guide/rest_cond.svg new file mode 100644 index 00000000..542ae17d --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_cond.svg @@ -0,0 +1,1656 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + version="1.1" + inkscape:version="0.48.4 r9939" + sodipodi:docname="rest_cond.svg" + inkscape:export-filename="/home/essen/Dropbox/Public/drawing.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs4"> + <linearGradient + id="linearGradient5265"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5267" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.58823532;" + offset="1" + id="stop5269" /> + </linearGradient> + <linearGradient + id="linearGradient5251"> + <stop + style="stop-color:#69d2e7;stop-opacity:0.78431374;" + offset="0" + id="stop5253" /> + <stop + id="stop5263" + offset="0.5" + style="stop-color:#69d2e7;stop-opacity:1;" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.39215687;" + offset="1" + id="stop5255" /> + </linearGradient> + <linearGradient + id="linearGradient5233" + osb:paint="solid"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5235" /> + </linearGradient> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="1" + inkscape:pageshadow="2" + inkscape:zoom="2.0000001" + inkscape:cx="351.17815" + inkscape:cy="292.20555" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="2560" + inkscape:window-height="1402" + inkscape:window-x="0" + inkscape:window-y="38" + inkscape:window-maximized="1" + inkscape:snap-global="true" + showguides="true"> + <inkscape:grid + type="xygrid" + id="grid5357" + empspacing="5" + visible="true" + enabled="true" + snapvisiblegridlinesonly="true" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <path + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:connector-curvature="0" + id="use5777" + d="m -360.31658,371.70113 203.00246,0.045" + style="fill:none;stroke:#6d8e41;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.99999999, 3.99999998;stroke-dashoffset:0" /> + <g + transform="translate(303.92143,-296.03137)" + id="g5650-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-9" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-0" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(303.92143,-212.00698)" + id="g5650-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-7" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-09" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(303.92143,-129.04326)" + id="g5650-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-5" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-1" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(303.92143,-44.866334)" + id="g5650-94" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-71" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-5" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(303.92143,38.329623)" + id="g5650-93" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-3" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-4" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(303.92143,122.59665)" + id="g5650-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-93" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-04" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(303.92143,206.62103)" + id="g5650-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-276.88574,248.85545)" + id="g5650-2-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <g + transform="matrix(0,-1,1,0,72.326854,331.8341)" + id="g5650-2-04" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-2-9" + d="m -57.78256,274.83062 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-0" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28" + width="210.17955" + height="35.209244" + x="141.04909" + y="204.49196" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-5" + width="210.17955" + height="35.209244" + x="141.04909" + y="288.06644" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8" + width="210.17955" + height="35.209244" + x="141.04909" + y="371.6409" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-4" + width="210.17955" + height="35.209244" + x="141.04909" + y="455.21542" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + transform="matrix(0,-1,1,0,72.019862,498.61197)" + id="g5650-2-04-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-2-9-6" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-0-7" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-87" + width="210.17955" + height="35.209244" + x="141.04909" + y="538.78992" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + transform="translate(303.92156,289.38374)" + id="g5650-6-2" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78-4" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9-2" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-273.77202,830.73267)" + id="g5650-2-0-4-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-9" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-3" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <g + transform="matrix(0,-1,1,0,-276.00956,743.77999)" + id="g5650-2-0-4-9-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 100.30195,432.97597 c 0,0 -104.1879007,-96.82159 -227.75958,-12.49311" + id="path20172-9-6-0" + inkscape:connector-curvature="0" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,146.48523,357.79168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-5-7" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-41" + width="210.17955" + height="35.209244" + x="140.98338" + y="622.36444" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1" + width="210.17955" + height="35.209244" + x="141.04909" + y="120.91741" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + id="g5650" + transform="translate(0,-0.47597102)"> + <path + inkscape:connector-curvature="0" + id="path5570" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273" + width="104.5895" + height="36.392323" + x="-224.02068" + y="29.41218" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7" + width="104.5895" + height="36.392323" + x="-224.02068" + y="90.691978" + rx="15" /> + <rect + style="fill:#ffc48c;fill-opacity:1;fill-rule:nonzero;stroke:#d79c64;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-2" + width="104.5895" + height="36.392323" + x="-224.02068" + y="151.97169" + rx="15" /> + <rect + style="fill:#ff9f80;fill-opacity:1;fill-rule:nonzero;stroke:#d77758;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-22" + width="104.5895" + height="36.392323" + x="-224.02068" + y="213.25146" + rx="15" /> + <rect + style="fill:#f56991;fill-opacity:1;fill-rule:nonzero;stroke:#cd4169;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-8" + width="104.5895" + height="36.392323" + x="-224.02068" + y="274.53128" + rx="15" /> + <use + x="0" + y="0" + xlink:href="#rect5273-22" + id="use5355" + transform="translate(417.86479,-176.50006)" + width="744.09448" + height="1052.3622" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="114.39204" + id="text5371" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373" + x="-58.692513" + y="114.39204">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="53.112247" + id="text5371-2" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6" + x="-58.692513" + y="53.112247">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.18575" + y="311.63589" + id="text5371-2-3" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7" + x="246.18575" + y="311.63589">has if-unmodified-since?</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="245.60762" + y="478.78488" + id="text5371-2-3-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7-3" + x="245.60762" + y="478.78488">has if-none-match?</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="236.95154" + id="text5371-4" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-9" + x="-58.692513" + y="236.95154">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.15059" + y="55.939754" + id="text5371-4-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + x="246.15059" + y="55.939754" + id="tspan17171">...</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.11153" + y="560.125" + id="text5371-2-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-8" + x="246.11153" + y="560.125">generate_etag</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.64278" + y="645.9339" + id="text5371-2-7" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-2" + x="246.64278" + y="645.9339">has if-modified-since?</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.13106" + y="144.48688" + id="text5371-2-95" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-80" + x="246.13106" + y="144.48688">has if-match?</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="245.80684" + y="225.82706" + id="text5371-2-32" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-27" + x="245.80684" + y="225.82706">generate_etag</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.05293" + y="393.43692" + id="text5371-2-74" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18" + x="246.05293" + y="393.43692">last_modified</tspan></text> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-2" + width="210.17955" + height="35.209244" + x="-489.75586" + y="33.4944" + rx="15" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="262.26562" + y="185.95248" + id="text5371-2-391" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63" + x="262.26562" + y="185.95248">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="262.26562" + y="269.61978" + id="text5371-2-954" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-808" + x="262.26562" + y="269.61978">match*</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="262.26562" + y="353.28702" + id="text5371-2-4" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-11" + x="262.26562" + y="353.28702">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="262.26562" + y="436.95425" + id="text5371-2-92" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-4" + x="262.26562" + y="436.95425">not modified*</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="262.26562" + y="520.62152" + id="text5371-2-739" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-0" + x="262.26562" + y="520.62152">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="261.24219" + y="604.14661" + id="text5371-2-8" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3" + x="261.24219" + y="604.14661">no match*</tspan></text> + <g + transform="matrix(0,-1,1,0,-513.31414,353.05561)" + id="g5650-2"> + <path + inkscape:connector-curvature="0" + id="path5570-2" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="66.515488" + y="227.88033" + id="text5371-4-6" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-0" + x="66.515488" + y="227.88033">false</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="66.097519" + y="385.50708" + id="text5371-4-2" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-01" + x="66.097519" + y="385.50708">false, or</tspan><tspan + sodipodi:role="line" + x="66.097519" + y="405.50708" + id="tspan21678">invalid</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="413.26172" + y="414.19577" + id="text5371-4-3" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-62" + x="413.26172" + y="414.19577">modified*</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="66.515488" + y="563.13391" + id="text5371-4-4" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2" + x="66.515488" + y="563.13391">false</tspan></text> + <g + transform="matrix(-1,0,0,-1,541.38289,824.55574)" + id="g5650-2-2"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1" + width="218.52127" + height="34.993004" + x="489.90482" + y="372.18814" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="599.20062" + y="394.09869" + id="text5371-43" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3" + x="599.20062" + y="394.09869">412 precondition failed</tspan></text> + <rect + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:2.44279909;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5367" + width="207.05719" + height="171.55719" + x="-373.52859" + y="458.58362" + rx="11.072577" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-544.69421" + y="-354.17184" + id="text5371-2-3-0-7" + sodipodi:linespacing="125%" + transform="matrix(0,-1,1,0,0,0)" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7-3-9" + x="-544.69421" + y="-354.17184">middlewares</tspan></text> + <g + transform="matrix(0,-1,1,0,-508.93096,565.23553)" + id="g5650-2-0-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <g + transform="matrix(0,-1,1,0,-276.88574,416.17722)" + id="g5650-2-0-4-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-6" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-5" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <g + transform="matrix(0,-1,1,0,-276.88574,583.49898)" + id="g5650-2-0-4-5" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-0" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-6" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <g + transform="matrix(0.70472302,-0.70948254,0.70948254,0.70472302,241.97558,40.02582)" + id="g5650-2-1-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-2-2-8" + d="m -64.113139,212.68162 6.332851,190.92097" + style="opacity:0.80000000000000004;fill:none;stroke:#9b3b1c;stroke-width:1.99999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-9-3" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="511.01306" + y="-49.514503" + id="text5371-4-5-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" + transform="matrix(0.72036037,0.69359998,-0.69359998,0.72036037,0,0)"><tspan + sodipodi:role="line" + id="tspan5373-9-09-1" + x="511.01306" + y="-49.514503">no match*</tspan></text> + <g + transform="translate(303.92156,371.88426)" + id="g5650-6-2-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78-4-2" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9-2-0" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-41-0" + width="210.17955" + height="35.209244" + x="140.98338" + y="705.93896" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.11142" + y="729.50842" + id="text5371-2-7-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-2-1" + x="246.11142" + y="729.50842">date is in the future?</tspan></text> + <g + transform="translate(303.92156,455.39272)" + id="g5650-6-2-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78-4-6" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9-2-2" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,72.385532,749.33549)" + id="g5650-2-04-1-2" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-2-9-6-9" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-0-7-5" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-2-6" + width="210.17955" + height="35.209244" + x="140.98338" + y="789.51343" + rx="15" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.04581" + y="811.30945" + id="text5371-2-7-9-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-2-1-1" + x="246.04581" + y="811.30945">last_modified</tspan></text> + <g + id="g5650-39" + transform="translate(656.94774,376.09516)"> + <path + inkscape:connector-curvature="0" + id="path5570-0" + d="m -57.78256,195.3221 0,204.64594" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,159.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-124" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-7" + width="218.52127" + height="34.993004" + x="489.90482" + y="957.01166" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="599.28265" + y="980.47302" + id="text5371-43-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-6" + x="599.28265" + y="980.47302">304 not modified</tspan></text> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-2-6-4" + width="210.17955" + height="35.209244" + x="140.98338" + y="873.08795" + rx="15" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.08487" + y="891.68475" + id="text5371-2-7-9-0-3" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-2-1-1-0" + x="246.08487" + y="891.68475">...</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="66.097519" + y="720.76068" + id="text5371-4-2-5" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-01-9" + x="66.097519" + y="720.76068">false, or</tspan><tspan + sodipodi:role="line" + x="66.097519" + y="740.76068" + id="tspan21678-9">invalid</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="412.95471" + y="580.78271" + id="text5371-4-3-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-62-9" + x="412.95471" + y="580.78271">match*</tspan></text> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3.05435514;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-41-0-7" + width="218.20164" + height="35.154888" + x="490.06448" + y="538.81708" + rx="15.572517" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="599.00122" + y="562.35938" + id="text5371-2-7-9-04" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-2-1-6" + x="599.00122" + y="562.35938">method is GET/HEAD?</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="621.08008" + y="607.0827" + id="text5371-2-739-3" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-0-0" + x="621.08008" + y="607.0827">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="640.17383" + y="518.34009" + id="text5371-4-4-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6" + x="640.17383" + y="518.34009">false</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="157.927" + y="770.83472" + id="text5371-4-4-4" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-4" + x="157.927" + y="770.83472">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="262.32812" + y="771.29565" + id="text5371-2-739-5" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-0-1" + x="262.32812" + y="771.29565">false</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="262.26562" + y="687.26025" + id="text5371-2-739-56" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-0-8" + x="262.26562" + y="687.26025">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="261.24219" + y="854.87012" + id="text5371-2-739-5-6" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-0-1-3" + x="261.24219" + y="854.87012">modified*</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="417.07037" + y="834.64905" + id="text5371-4-3-9-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-62-9-4" + x="417.07037" + y="834.64905">not modified*</tspan></text> + <g + transform="translate(656.94774,455.40497)" + id="g5650-6-2-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78-4-1" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9-2-09" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28-5" + width="210.17955" + height="35.209244" + x="490.03729" + y="789.51343" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="595.41223" + y="810.84851" + id="text5371-2-32-1" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-27-8" + x="595.41223" + y="810.84851">generate_etag</tspan></text> + <g + transform="translate(656.94774,539.41312)" + id="g5650-6-2-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78-4-7" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9-2-5" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28-5-0" + width="210.17955" + height="35.209244" + x="490.03729" + y="873.08795" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="595.41223" + y="894.42303" + id="text5371-2-32-1-2" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-27-8-6" + x="595.41223" + y="894.42303">expires</tspan></text> + </g> +</svg> diff --git a/docs/en/cowboy/2.2/guide/rest_conneg.png b/docs/en/cowboy/2.2/guide/rest_conneg.png Binary files differnew file mode 100644 index 00000000..65ecdcf3 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_conneg.png diff --git a/docs/en/cowboy/2.2/guide/rest_conneg.svg b/docs/en/cowboy/2.2/guide/rest_conneg.svg new file mode 100644 index 00000000..247567a0 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_conneg.svg @@ -0,0 +1,1135 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + version="1.1" + inkscape:version="0.48.4 r9939" + sodipodi:docname="rest_conneg.svg" + inkscape:export-filename="/home/essen/Dropbox/Public/drawing.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs4"> + <linearGradient + id="linearGradient5265"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5267" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.58823532;" + offset="1" + id="stop5269" /> + </linearGradient> + <linearGradient + id="linearGradient5251"> + <stop + style="stop-color:#69d2e7;stop-opacity:0.78431374;" + offset="0" + id="stop5253" /> + <stop + id="stop5263" + offset="0.5" + style="stop-color:#69d2e7;stop-opacity:1;" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.39215687;" + offset="1" + id="stop5255" /> + </linearGradient> + <linearGradient + id="linearGradient5233" + osb:paint="solid"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5235" /> + </linearGradient> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="1" + inkscape:pageshadow="2" + inkscape:zoom="1.4142136" + inkscape:cx="222.80947" + inkscape:cy="634.56615" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="2560" + inkscape:window-height="1402" + inkscape:window-x="0" + inkscape:window-y="38" + inkscape:window-maximized="1" + inkscape:snap-global="true" + showguides="true"> + <inkscape:grid + type="xygrid" + id="grid5357" + empspacing="5" + visible="true" + enabled="true" + snapvisiblegridlinesonly="true" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <path + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:connector-curvature="0" + id="use5777" + d="m -360.31658,371.70113 203.00246,0.045" + style="fill:none;stroke:#6d8e41;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.99999999, 3.99999998;stroke-dashoffset:0" /> + <g + transform="translate(303.92143,-296.03137)" + id="g5650-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-9" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-0" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(303.92143,-212.00698)" + id="g5650-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-7" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-09" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(303.92143,-129.04326)" + id="g5650-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-5" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-1" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(303.92143,-44.866334)" + id="g5650-94" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-71" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-5" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(303.92143,38.329623)" + id="g5650-93" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-3" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-4" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(303.92143,122.59665)" + id="g5650-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-93" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-04" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(303.92143,206.62103)" + id="g5650-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-276.88574,248.85545)" + id="g5650-2-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <g + transform="matrix(0,-1,1,0,72.326854,331.8341)" + id="g5650-2-04" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-2-9" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-0" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28" + width="210.17955" + height="35.209244" + x="141.04909" + y="204.67757" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-5" + width="210.17955" + height="35.209244" + x="141.04909" + y="288.40311" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8" + width="210.17955" + height="35.209244" + x="141.04909" + y="372.01199" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-4" + width="210.17955" + height="35.209244" + x="141.04909" + y="455.67929" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-87" + width="210.17955" + height="35.209244" + x="141.04909" + y="539.34656" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + transform="translate(303.92156,289.38374)" + id="g5650-6-2" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78-4" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9-2" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-41" + width="210.17955" + height="35.209244" + x="141.04909" + y="623.01385" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1" + width="210.17955" + height="35.209244" + x="141.04909" + y="121.0042" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + id="g5650" + transform="translate(0,-0.47597102)"> + <path + inkscape:connector-curvature="0" + id="path5570" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273" + width="104.5895" + height="36.392323" + x="-224.02068" + y="29.41218" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7" + width="104.5895" + height="36.392323" + x="-224.02068" + y="90.691978" + rx="15" /> + <rect + style="fill:#ffc48c;fill-opacity:1;fill-rule:nonzero;stroke:#d79c64;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-2" + width="104.5895" + height="36.392323" + x="-224.02068" + y="151.97169" + rx="15" /> + <rect + style="fill:#ff9f80;fill-opacity:1;fill-rule:nonzero;stroke:#d77758;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-22" + width="104.5895" + height="36.392323" + x="-224.02068" + y="213.25146" + rx="15" /> + <rect + style="fill:#f56991;fill-opacity:1;fill-rule:nonzero;stroke:#cd4169;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-8" + width="104.5895" + height="36.392323" + x="-224.02068" + y="274.53128" + rx="15" /> + <use + x="0" + y="0" + xlink:href="#rect5273-22" + id="use5355" + transform="translate(417.86479,-176.50006)" + width="744.09448" + height="1052.3622" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="114.39204" + id="text5371" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373" + x="-58.692513" + y="114.39204">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="53.112247" + id="text5371-2" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6" + x="-58.692513" + y="53.112247">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.18575" + y="310.19913" + id="text5371-2-3" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7" + x="246.18575" + y="310.19913">has accept-language?</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="245.60762" + y="477.47531" + id="text5371-2-3-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7-3" + x="245.60762" + y="477.47531">has accept-charset?</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="236.95154" + id="text5371-4" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-9" + x="-58.692513" + y="236.95154">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="245.00391" + y="60.912468" + id="text5371-4-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + x="245.00391" + y="60.912468" + id="tspan17171">start</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.11153" + y="561.14258" + id="text5371-2-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-8" + x="246.11153" + y="561.14258">charsets_provided</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.64278" + y="646.58331" + id="text5371-2-7" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-2" + x="246.64278" + y="646.58331">variances</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.13106" + y="142.80627" + id="text5371-2-95" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-80" + x="246.13106" + y="142.80627">has accept?</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="245.80684" + y="226.4736" + id="text5371-2-32" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-27" + x="245.80684" + y="226.4736">content_types_provided</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.05293" + y="393.80801" + id="text5371-2-74" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18" + x="246.05293" + y="393.80801">languages_provided</tspan></text> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-2" + width="210.17955" + height="35.209244" + x="-489.75586" + y="33.4944" + rx="15" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="262.26562" + y="185.95248" + id="text5371-2-391" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63" + x="262.26562" + y="185.95248">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="262.26562" + y="269.61978" + id="text5371-2-954" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-808" + x="262.26562" + y="269.61978">provided*</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="262.26562" + y="353.28702" + id="text5371-2-4" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-11" + x="262.26562" + y="353.28702">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="262.26562" + y="436.95425" + id="text5371-2-92" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-4" + x="262.26562" + y="436.95425">provided*</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="262.26562" + y="520.62152" + id="text5371-2-739" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-0" + x="262.26562" + y="520.62152">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="262.26562" + y="604.28876" + id="text5371-2-8" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3" + x="262.26562" + y="604.28876">provided*</tspan></text> + <g + transform="matrix(0,-1,1,0,-513.31414,353.05561)" + id="g5650-2"> + <path + inkscape:connector-curvature="0" + id="path5570-2" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="76.761719" + y="227.88033" + id="text5371-4-6" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-0" + x="76.761719" + y="227.88033">false</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="76.761719" + y="395.20209" + id="text5371-4-2" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-01" + x="76.761719" + y="395.20209">false</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="413.26172" + y="374.19577" + id="text5371-4-3" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-62" + x="413.26172" + y="374.19577">not provided*</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="76.761719" + y="562.52386" + id="text5371-4-4" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2" + x="76.761719" + y="562.52386">false</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-8.8034744" + y="663.24762" + id="text5371-4-5" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" + transform="matrix(0.7410941,-0.67140117,0.67140117,0.7410941,0,0)"><tspan + sodipodi:role="line" + id="tspan5373-9-09" + x="-8.8034744" + y="663.24762">not provided*</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1" + width="218.52127" + height="34.993004" + x="489.90482" + y="372.18814" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + transform="matrix(-0.65781496,-0.75317958,0.75317958,-0.65781496,150.24236,637.46542)" + id="g5650-2-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-2-2" + d="m -59.488319,210.57681 1.65844,193.00059" + style="opacity:0.80000000000000004;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-9" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="599.20062" + y="394.09869" + id="text5371-43" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3" + x="599.20062" + y="394.09869">406 not acceptable</tspan></text> + <rect + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:2.44279909;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5367" + width="207.05719" + height="171.55719" + x="-373.52859" + y="458.58362" + rx="11.072577" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-544.69421" + y="-354.17184" + id="text5371-2-3-0-7" + sodipodi:linespacing="125%" + transform="matrix(0,-1,1,0,0,0)" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7-3-9" + x="-544.69421" + y="-354.17184">middlewares</tspan></text> + <g + transform="matrix(0,-1,1,0,-508.93096,565.23553)" + id="g5650-2-0-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <g + transform="matrix(0,-1,1,0,-276.88574,416.17722)" + id="g5650-2-0-4-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-6" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-5" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <g + transform="matrix(0,-1,1,0,-276.88574,583.49898)" + id="g5650-2-0-4-5" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-0" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-6" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <g + transform="matrix(0.70472302,-0.70948254,0.70948254,0.70472302,241.97558,40.02582)" + id="g5650-2-1-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-2-2-8" + d="m -64.113139,212.68162 6.332851,190.92097" + style="opacity:0.80000000000000004;fill:none;stroke:#9b3b1c;stroke-width:1.99999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-9-3" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="509.41452" + y="-106.16136" + id="text5371-4-5-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" + transform="matrix(0.69480867,0.71919462,-0.71919462,0.69480867,0,0)"><tspan + sodipodi:role="line" + id="tspan5373-9-09-1" + x="509.41452" + y="-106.16136">not provided*</tspan></text> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-41-0" + width="210.17955" + height="35.209244" + x="141.049" + y="706.68097" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="246.15048" + y="725.27777" + id="text5371-2-7-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-2-1" + x="246.15048" + y="725.27777">...</tspan></text> + </g> +</svg> diff --git a/docs/en/cowboy/2.2/guide/rest_delete.png b/docs/en/cowboy/2.2/guide/rest_delete.png Binary files differnew file mode 100644 index 00000000..56a861c0 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_delete.png diff --git a/docs/en/cowboy/2.2/guide/rest_delete.svg b/docs/en/cowboy/2.2/guide/rest_delete.svg new file mode 100644 index 00000000..2f5513cd --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_delete.svg @@ -0,0 +1,1718 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + version="1.1" + inkscape:version="0.48.4 r9939" + sodipodi:docname="rest_delete.svg" + inkscape:export-filename="/home/essen/Dropbox/Public/drawing.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs4"> + <linearGradient + id="linearGradient5265"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5267" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.58823532;" + offset="1" + id="stop5269" /> + </linearGradient> + <linearGradient + id="linearGradient5251"> + <stop + style="stop-color:#69d2e7;stop-opacity:0.78431374;" + offset="0" + id="stop5253" /> + <stop + id="stop5263" + offset="0.5" + style="stop-color:#69d2e7;stop-opacity:1;" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.39215687;" + offset="1" + id="stop5255" /> + </linearGradient> + <linearGradient + id="linearGradient5233" + osb:paint="solid"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5235" /> + </linearGradient> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="1" + inkscape:pageshadow="2" + inkscape:zoom="1.4142136" + inkscape:cx="187.51922" + inkscape:cy="446.38557" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="2560" + inkscape:window-height="1402" + inkscape:window-x="0" + inkscape:window-y="38" + inkscape:window-maximized="1" + inkscape:snap-global="true" + showguides="true"> + <inkscape:grid + type="xygrid" + id="grid5357" + empspacing="5" + visible="true" + enabled="true" + snapvisiblegridlinesonly="true" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <path + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:connector-curvature="0" + id="use5777" + d="m -360.31658,371.70113 203.00246,0.045" + style="fill:none;stroke:#6d8e41;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.99999999, 3.99999998;stroke-dashoffset:0" /> + <g + transform="translate(416.63925,-305.0045)" + id="g5650-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-9" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-0" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(270.88515,270.15614)" + id="g5650-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-93" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-04" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(270.88515,435.68973)" + id="g5650-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(270.88515,-141.93971)" + id="g5650-0-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-5-3" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-1-1" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(270.88515,-59.713866)" + id="g5650-0-6-5" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-5-7-7" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-1-3-8" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-307.35528,398.54403)" + id="g5650-2-0-4-8-8-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-5-6-2" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-2-8-3" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28" + width="210.17955" + height="35.209244" + x="108.01281" + y="275.4668" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + transform="translate(270.88515,105.33602)" + id="g5650-2-2-7"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-3" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-9" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-310.05718,566.15049)" + id="g5650-2-0-4-3-8-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8-9-8" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6-7" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-5" + width="210.17955" + height="35.209244" + x="108.01281" + y="440.50873" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + transform="matrix(0,-1,1,0,-308.28941,729.66893)" + id="g5650-2-0-4-8-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-5-6" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-2-8" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-4" + width="210.17955" + height="35.209244" + x="108.01281" + y="605.5506" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + transform="matrix(0,-1,1,0,-313.39862,891.55835)" + id="g5650-2-0-4-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-5" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-2" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-87" + width="210.17955" + height="35.209244" + x="108.01281" + y="770.83313" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,261.76354,-143.71473)" + id="g5650-2-2-8"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-4" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-3" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1" + width="210.17955" + height="35.209244" + x="253.76691" + y="112.69559" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + id="g5650" + transform="translate(0,-0.47597102)"> + <path + inkscape:connector-curvature="0" + id="path5570" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273" + width="104.5895" + height="36.392323" + x="-224.02068" + y="29.41218" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7" + width="104.5895" + height="36.392323" + x="-224.02068" + y="90.691978" + rx="15" /> + <rect + style="fill:#ffc48c;fill-opacity:1;fill-rule:nonzero;stroke:#d79c64;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-2" + width="104.5895" + height="36.392323" + x="-224.02068" + y="151.97169" + rx="15" /> + <rect + style="fill:#ff9f80;fill-opacity:1;fill-rule:nonzero;stroke:#d77758;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-22" + width="104.5895" + height="36.392323" + x="-224.02068" + y="213.25146" + rx="15" /> + <rect + style="fill:#f56991;fill-opacity:1;fill-rule:nonzero;stroke:#cd4169;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-8" + width="104.5895" + height="36.392323" + x="-224.02068" + y="274.53128" + rx="15" /> + <use + x="0" + y="0" + xlink:href="#rect5273-22" + id="use5355" + transform="translate(530.58261,-183.7816)" + width="744.09448" + height="1052.3622" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="114.39204" + id="text5371" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373" + x="-58.692513" + y="114.39204">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="53.112247" + id="text5371-2" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6" + x="-58.692513" + y="53.112247">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="213.38774" + y="462.30475" + id="text5371-2-3" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7" + x="213.38774" + y="462.30475">delete_completed</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="212.93852" + y="627.56927" + id="text5371-2-3-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7-3" + x="212.93852" + y="627.56927">has response body?</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="236.95154" + id="text5371-4" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-9" + x="-58.692513" + y="236.95154">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="359.14185" + y="50.482433" + id="text5371-4-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + x="359.14185" + y="50.482433" + id="tspan17171">conneg</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="212.77055" + y="792.62915" + id="text5371-2-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-8" + x="212.77055" + y="792.62915">multiple_choices</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="358.52466" + y="134.49161" + id="text5371-2-95" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-80" + x="358.52466" + y="134.49161">resource_exists</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="213.08696" + y="297.26282" + id="text5371-2-32" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-27" + x="213.08696" + y="297.26282">delete_resource</tspan></text> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-2" + width="210.17955" + height="35.209244" + x="-489.75586" + y="33.4944" + rx="15" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="251.83722" + y="175.92931" + id="text5371-2-391" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63" + x="251.83722" + y="175.92931">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="159.54012" + y="835.54285" + id="text5371-2-8" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3" + x="159.54012" + y="835.54285">false</tspan></text> + <g + transform="matrix(0,-1,1,0,-513.31414,353.05561)" + id="g5650-2"> + <path + inkscape:connector-curvature="0" + id="path5570-2" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="447.26678" + y="176.39024" + id="text5371-4-6" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-0" + x="447.26678" + y="176.39024">false</tspan></text> + <g + transform="translate(563.72619,-141.76777)" + id="g5650-2-2"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:2.44279909;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5367" + width="207.05719" + height="171.55719" + x="-373.52859" + y="458.58362" + rx="11.072577" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-544.69421" + y="-354.17184" + id="text5371-2-3-0-7" + sodipodi:linespacing="125%" + transform="matrix(0,-1,1,0,0,0)" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7-3-9" + x="-544.69421" + y="-354.17184">middlewares</tspan></text> + <g + transform="matrix(0,-1,1,0,-508.93096,565.23553)" + id="g5650-2-0-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="47.338913" + y="876.22211" + id="text5371-4-3-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-62-9" + x="47.338913" + y="876.22211">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="545.12921" + y="257.43518" + id="text5371-4-4-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6" + x="545.12921" + y="257.43518">true</tspan></text> + <g + transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,547.47379,-62.310424)" + id="g5650-9-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-7-6" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-09-5" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <use + x="0" + y="0" + xlink:href="#rect5273-22" + id="use5355-0" + transform="translate(384.82851,-20.897068)" + width="744.09448" + height="1052.3622" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="213.38774" + y="216.5154" + id="text5371-4-0-8" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + x="213.38774" + y="216.5154" + id="tspan17171-6">cond</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-1" + width="218.52127" + height="34.993004" + x="99.803589" + y="935.6217" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="208.84938" + y="957.53229" + id="text5371-43-5" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-62" + x="208.84938" + y="957.53229">300 multiple choices</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-8" + width="218.52127" + height="34.993004" + x="99.803589" + y="853.22168" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="208.31422" + y="876.54242" + id="text5371-43-3" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-1" + x="208.31422" + y="876.54242">200 OK</tspan></text> + <g + transform="matrix(0,-1,-1,0,1028.2004,317.70407)" + id="g5650-2-0-4-3-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8-9" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28-4" + width="210.17955" + height="35.209244" + x="400.85385" + y="192.94594" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="505.77957" + y="216.51541" + id="text5371-2-32-6" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-27-8" + x="505.77957" + y="216.51541">has if-match?</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="651.74426" + y="299.27689" + id="text5371-2-391-5" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63-7" + x="651.74426" + y="299.27689">false</tspan></text> + <g + transform="translate(563.72619,22.800669)" + id="g5650-0-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-5-7" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-1-3" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,-1,0,1027.6701,482.30508)" + id="g5650-2-0-4-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28-7" + width="210.17955" + height="35.209244" + x="400.85385" + y="357.98779" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="505.94363" + y="379.78381" + id="text5371-2-32-8" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-27-1" + x="505.94363" + y="379.78381">previously_existed</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-5" + width="218.52127" + height="34.993004" + x="396.68301" + y="440.37622" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="506.2796" + y="463.83755" + id="text5371-43-2" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-9" + x="506.2796" + y="463.83755">404 not found</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="528.75421" + y="422.69736" + id="text5371-2-8-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-4" + x="528.75421" + y="422.69736">false</tspan></text> + <g + transform="translate(563.72619,187.85116)" + id="g5650-2-2-17"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-0" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-45" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,-1,0,1027.4933,646.81763)" + id="g5650-2-0-4-3-8-0-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8-9-31-8" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6-3-6" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9" + width="210.17955" + height="35.209244" + x="400.85385" + y="523.02966" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="505.45535" + y="544.82568" + id="text5371-2-74-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2" + x="505.45535" + y="544.82568">moved_permanently</tspan></text> + <g + transform="matrix(0,-1,-1,0,347.00351,567.35686)" + id="g5650-2-0-4-3-8-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8-9-3" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6-1" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1" + width="218.52127" + height="34.993004" + x="396.68301" + y="275.81555" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="506.2796" + y="297.7261" + id="text5371-43" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3" + x="506.2796" + y="297.7261">412 precondition failed</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="668.11926" + y="463.37662" + id="text5371-4-3-9-8" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-62-9-9" + x="668.11926" + y="463.37662">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="549.12921" + y="587.59863" + id="text5371-4-4-9-3" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-2" + x="549.12921" + y="587.59863">true*</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="651.74426" + y="628.87946" + id="text5371-2-391-5-5-1" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63-7-9-9" + x="651.74426" + y="628.87946">false</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-5-9" + width="218.52127" + height="34.993004" + x="396.68301" + y="605.41809" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="505.57257" + y="627.32867" + id="text5371-43-2-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-9-7" + x="505.57257" + y="627.32867">301 moved permanently</tspan></text> + <g + transform="translate(563.72619,353.12604)" + id="g5650-2-2-65"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-5" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-5" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,-1,0,1032.2004,811.50699)" + id="g5650-2-0-4-3-8-0-3-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8-9-31-8-1" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6-3-6-3" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9-1" + width="210.17955" + height="35.209244" + x="400.85385" + y="687.83093" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="505.45535" + y="709.62695" + id="text5371-2-74-0-7" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2-8" + x="505.45535" + y="709.62695">moved_temporarily</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="549.12921" + y="752.64056" + id="text5371-4-4-9-3-2" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-2-6" + x="549.12921" + y="752.64056">true*</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="651.74426" + y="794.16199" + id="text5371-2-391-5-5-1-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63-7-9-9-2" + x="651.74426" + y="794.16199">false</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-5-9-2" + width="218.52127" + height="34.993004" + x="396.68301" + y="770.70062" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="505.57257" + y="792.61121" + id="text5371-43-2-9-7" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-9-7-8" + x="505.57257" + y="792.61121">307 moved temporarily</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-5-9-2-4" + width="218.52127" + height="34.993004" + x="396.68301" + y="853.22168" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="505.97882" + y="874.99164" + id="text5371-43-2-9-7-3" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-9-7-8-7" + x="505.97882" + y="874.99164">410 gone</tspan></text> + <g + transform="translate(31.619614,4.2328831)" + id="g5650-2-2-6"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-6" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-1" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="178.57137" + y="505.21829" + id="text5371-4-6-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-0-9" + x="178.57137" + y="505.21829">false</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-8-7" + width="218.52127" + height="34.993004" + x="99.803589" + y="522.89716" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="209.20485" + y="544.80774" + id="text5371-43-3-1" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-1-5" + x="209.20485" + y="544.80774">202 accepted</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-8-5" + width="218.52127" + height="34.993004" + x="99.803589" + y="687.69843" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="208.6736" + y="711.01917" + id="text5371-43-3-9" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-1-8" + x="208.6736" + y="711.01917">204 no content</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="47.338913" + y="711.15979" + id="text5371-4-6-0-4" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-0-9-4" + x="47.338913" + y="711.15979">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="30.901413" + y="545.89758" + id="text5371-2-391-6" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63-9" + x="30.901413" + y="545.89758">true</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-8-7-1" + width="218.52127" + height="34.993004" + x="99.803589" + y="357.85529" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="208.45485" + y="381.31662" + id="text5371-43-3-1-2" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-1-5-9" + x="208.45485" + y="381.31662">500 internal server error</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="159.54012" + y="340.17645" + id="text5371-2-8-9-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-4-4" + x="159.54012" + y="340.17645">false</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="47.338913" + y="380.85568" + id="text5371-4-4-9-2" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-1" + x="47.338913" + y="380.85568">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="159.54012" + y="670.13989" + id="text5371-2-391-6-3" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63-9-1" + x="159.54012" + y="670.13989">false</tspan></text> + </g> +</svg> diff --git a/docs/en/cowboy/2.2/guide/rest_flowcharts.asciidoc b/docs/en/cowboy/2.2/guide/rest_flowcharts.asciidoc new file mode 100644 index 00000000..b5697825 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_flowcharts.asciidoc @@ -0,0 +1,248 @@ +[[rest_flowcharts]] +== REST flowcharts + +This chapter will explain the REST handler state machine through +a number of different diagrams. + +There are four main paths that requests may follow. One for the +method OPTIONS; one for the methods GET and HEAD; one for the +methods PUT, POST and PATCH; and one for the method DELETE. + +All paths start with the "Start" diagram, and all paths excluding +the OPTIONS path go through the "Content negotiation" diagram +and optionally the "Conditional requests" diagram if the resource +exists. + +The red squares refer to another diagram. The light green squares +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 + +All requests start from here. + +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 +request headers. + +The request body, if any, is not expected to have been +received for any of these steps. It is only processed +at the end of the "PUT, POST and PATCH methods" diagram, +when all conditions have been met. + +The `known_methods` and `allowed_methods` callbacks +return a list of methods. Cowboy then checks if the request +method is in the list, and stops otherwise. + +The `is_authorized` callback may be used to check that +access to the resource is authorized. Authentication +may also be performed as needed. When authorization is +denied, the return value from the callback must include +a challenge applicable to the requested resource, which +will be sent back to the client in the www-authenticate +header. + +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 + +This diagram only applies to OPTIONS requests. + +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 +provided; allowed methods; any extra information. A +response body may also be set, although clients should +not be expected to read it. + +If the `options` callback is not defined, Cowboy will +send a response containing the list of allowed methods +by default. + +=== Content negotiation + +This diagram applies to all request methods other than +OPTIONS. It is executed right after the "Start" diagram +is completed. + +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. + +The request may contain any of the accept header; the +accept-language header; or the accept-charset header. +When present, Cowboy will parse the headers and then +call the corresponding callback to obtain the list +of provided content-type, language or charset for this +resource. It then automatically select the best match +based on the request. + +If a callback is not defined, Cowboy will select the +content-type, language or charset that the client +prefers. + +The `content_types_provided` also returns the name of +a callback for every content-type it accepts. This +callback will only be called at the end of the +"GET and HEAD methods" diagram, when all conditions +have been met. + +The selected content-type, language and charset are +saved as meta values in the Req object. You *should* +use the appropriate representation if you set a +response body manually (alongside an error code, +for example). + +This diagram is immediately followed by +the "GET and HEAD methods" diagram, +the "PUT, POST and PATCH methods" diagram, +or the "DELETE method" diagram, depending on the +method. + +=== 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. + +image::rest_get_head.png[REST GET/HEAD methods flowchart] + +When the resource exists, and the conditional steps +succeed, the resource can be retrieved. + +Cowboy prepares the response by first retrieving +metadata about the representation, then by calling +the `ProvideResource` callback. This is the callback +you defined for each content-types you returned from +`content_types_provided`. This callback returns the body +that will be sent back to the client, or a fun if the +body must be streamed. + +When the resource does not exist, Cowboy will figure out +whether the resource existed previously, and if so whether +it was moved elsewhere in order to redirect the client to +the new URI. + +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 + +This diagram only applies to PUT, POST and PATCH requests. + +For a description of the `cond` step, please see +the "Conditional requests" diagram. + +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, +Cowboy will call the `is_conflict` callback. This function +can be used to prevent potential race conditions, by locking +the resource for example. + +Then all three methods reach the `content_types_accepted` +step that we will describe in a few paragraphs. + +When the resource does not exist, and the method is PUT, +Cowboy will check for conflicts and then move on to the +`content_types_accepted` step. For other methods, Cowboy +will figure out whether the resource existed previously, +and if so whether it was moved elsewhere. If the resource +is truly non-existent, the method is POST and the call +for `allow_missing_post` returns `true`, then Cowboy will +move on to the `content_types_accepted` step. Otherwise +the request processing ends there. + +The `moved_permanently` and `moved_temporarily` callbacks +must return the new location of the resource if it was in +fact moved. + +The `content_types_accepted` returns a list of +content-types it accepts, but also the name of a callback +for each of them. Cowboy will select the appropriate +callback for processing the request body and call it. + +This callback may return one of three different return +values. + +If an error occurred while processing the request body, +it must return `false` and Cowboy will send an +appropriate error response. + +If the method is POST, then you may return `true` with +an URI of where the resource has been created. This is +especially useful for writing handlers for collections. + +Otherwise, return `true` to indicate success. Cowboy +will select the appropriate response to be sent depending +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 + +This diagram only applies to DELETE requests. + +For a description of the `cond` step, please see +the "Conditional requests" diagram. + +image::rest_delete.png[REST DELETE method flowchart] + +When the resource exists, and the conditional steps +succeed, the resource can be deleted. + +Deleting the resource is a two steps process. First +the callback `delete_resource` is executed. Use this +callback to delete the resource. + +Because the resource may be cached, you must also +delete all cached representations of this resource +in the system. This operation may take a while though, +so you may return before it finished. + +Cowboy will then call the `delete_completed` callback. +If you know that the resource has been completely +deleted from your system, including from caches, then +you can return `true`. If any doubts persist, return +`false`. Cowboy will assume `true` by default. + +To finish, Cowboy checks if you set a response body, +and depending on that, sends the appropriate response. + +When the resource does not exist, Cowboy will figure out +whether the resource existed previously, and if so whether +it was moved elsewhere in order to redirect the client to +the new URI. + +The `moved_permanently` and `moved_temporarily` callbacks +must return the new location of the resource if it was in +fact moved. + +=== 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. + +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 +if-none-match header; or the if-modified-since header. + +If the condition fails, the request ends immediately +without any retrieval or modification of the resource. + +The `generate_etag` and `last_modified` are called as +needed. Cowboy will only call them once and then cache +the results for subsequent use. diff --git a/docs/en/cowboy/2.2/guide/rest_flowcharts/index.html b/docs/en/cowboy/2.2/guide/rest_flowcharts/index.html new file mode 100644 index 00000000..fd9e66f2 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_flowcharts/index.html @@ -0,0 +1,403 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: REST flowcharts</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>REST flowcharts</span></h1> + +<div class="paragraph"><p>This chapter will explain the REST handler state machine through +a number of different diagrams.</p></div> +<div class="paragraph"><p>There are four main paths that requests may follow. One for the +method OPTIONS; one for the methods GET and HEAD; one for the +methods PUT, POST and PATCH; and one for the method DELETE.</p></div> +<div class="paragraph"><p>All paths start with the "Start" diagram, and all paths excluding +the OPTIONS path go through the "Content negotiation" diagram +and optionally the "Conditional requests" diagram if the resource +exists.</p></div> +<div class="paragraph"><p>The red squares refer to another diagram. The light green squares +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.</p></div> +<div class="sect1"> +<h2 id="_start">Start</h2> +<div class="sectionbody"> +<div class="paragraph"><p>All requests start from here.</p></div> +<div class="imageblock"> +<div class="content"> +<img src="../rest_start.png" alt="REST starting flowchart" /> +</div> +</div> +<div class="paragraph"><p>A series of callbacks are called in succession to perform +a general checkup of the service, the request line and +request headers.</p></div> +<div class="paragraph"><p>The request body, if any, is not expected to have been +received for any of these steps. It is only processed +at the end of the "PUT, POST and PATCH methods" diagram, +when all conditions have been met.</p></div> +<div class="paragraph"><p>The <code>known_methods</code> and <code>allowed_methods</code> callbacks +return a list of methods. Cowboy then checks if the request +method is in the list, and stops otherwise.</p></div> +<div class="paragraph"><p>The <code>is_authorized</code> callback may be used to check that +access to the resource is authorized. Authentication +may also be performed as needed. When authorization is +denied, the return value from the callback must include +a challenge applicable to the requested resource, which +will be sent back to the client in the www-authenticate +header.</p></div> +<div class="paragraph"><p>This diagram is immediately followed by either the +"OPTIONS method" diagram when the request method is +OPTIONS, or the "Content negotiation" diagram otherwise.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_options_method">OPTIONS method</h2> +<div class="sectionbody"> +<div class="paragraph"><p>This diagram only applies to OPTIONS requests.</p></div> +<div class="imageblock"> +<div class="content"> +<img src="../rest_options.png" alt="REST OPTIONS method flowchart" /> +</div> +</div> +<div class="paragraph"><p>The <code>options</code> callback may be used to add information +about the resource, such as media types or languages +provided; allowed methods; any extra information. A +response body may also be set, although clients should +not be expected to read it.</p></div> +<div class="paragraph"><p>If the <code>options</code> callback is not defined, Cowboy will +send a response containing the list of allowed methods +by default.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_content_negotiation">Content negotiation</h2> +<div class="sectionbody"> +<div class="paragraph"><p>This diagram applies to all request methods other than +OPTIONS. It is executed right after the "Start" diagram +is completed.</p></div> +<div class="imageblock"> +<div class="content"> +<img src="../rest_conneg.png" alt="REST content negotiation flowchart" /> +</div> +</div> +<div class="paragraph"><p>The purpose of these steps is to determine an appropriate +representation to be sent back to the client.</p></div> +<div class="paragraph"><p>The request may contain any of the accept header; the +accept-language header; or the accept-charset header. +When present, Cowboy will parse the headers and then +call the corresponding callback to obtain the list +of provided content-type, language or charset for this +resource. It then automatically select the best match +based on the request.</p></div> +<div class="paragraph"><p>If a callback is not defined, Cowboy will select the +content-type, language or charset that the client +prefers.</p></div> +<div class="paragraph"><p>The <code>content_types_provided</code> also returns the name of +a callback for every content-type it accepts. This +callback will only be called at the end of the +"GET and HEAD methods" diagram, when all conditions +have been met.</p></div> +<div class="paragraph"><p>The selected content-type, language and charset are +saved as meta values in the Req object. You <strong>should</strong> +use the appropriate representation if you set a +response body manually (alongside an error code, +for example).</p></div> +<div class="paragraph"><p>This diagram is immediately followed by +the "GET and HEAD methods" diagram, +the "PUT, POST and PATCH methods" diagram, +or the "DELETE method" diagram, depending on the +method.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_get_and_head_methods">GET and HEAD methods</h2> +<div class="sectionbody"> +<div class="paragraph"><p>This diagram only applies to GET and HEAD requests.</p></div> +<div class="paragraph"><p>For a description of the <code>cond</code> step, please see +the "Conditional requests" diagram.</p></div> +<div class="imageblock"> +<div class="content"> +<img src="../rest_get_head.png" alt="REST GET/HEAD methods flowchart" /> +</div> +</div> +<div class="paragraph"><p>When the resource exists, and the conditional steps +succeed, the resource can be retrieved.</p></div> +<div class="paragraph"><p>Cowboy prepares the response by first retrieving +metadata about the representation, then by calling +the <code>ProvideResource</code> callback. This is the callback +you defined for each content-types you returned from +<code>content_types_provided</code>. This callback returns the body +that will be sent back to the client, or a fun if the +body must be streamed.</p></div> +<div class="paragraph"><p>When the resource does not exist, Cowboy will figure out +whether the resource existed previously, and if so whether +it was moved elsewhere in order to redirect the client to +the new URI.</p></div> +<div class="paragraph"><p>The <code>moved_permanently</code> and <code>moved_temporarily</code> callbacks +must return the new location of the resource if it was in +fact moved.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_put_post_and_patch_methods">PUT, POST and PATCH methods</h2> +<div class="sectionbody"> +<div class="paragraph"><p>This diagram only applies to PUT, POST and PATCH requests.</p></div> +<div class="paragraph"><p>For a description of the <code>cond</code> step, please see +the "Conditional requests" diagram.</p></div> +<div class="imageblock"> +<div class="content"> +<img src="../rest_put_post_patch.png" alt="REST PUT/POST/PATCH methods flowchart" /> +</div> +</div> +<div class="paragraph"><p>When the resource exists, first the conditional steps +are executed. When that succeeds, and the method is PUT, +Cowboy will call the <code>is_conflict</code> callback. This function +can be used to prevent potential race conditions, by locking +the resource for example.</p></div> +<div class="paragraph"><p>Then all three methods reach the <code>content_types_accepted</code> +step that we will describe in a few paragraphs.</p></div> +<div class="paragraph"><p>When the resource does not exist, and the method is PUT, +Cowboy will check for conflicts and then move on to the +<code>content_types_accepted</code> step. For other methods, Cowboy +will figure out whether the resource existed previously, +and if so whether it was moved elsewhere. If the resource +is truly non-existent, the method is POST and the call +for <code>allow_missing_post</code> returns <code>true</code>, then Cowboy will +move on to the <code>content_types_accepted</code> step. Otherwise +the request processing ends there.</p></div> +<div class="paragraph"><p>The <code>moved_permanently</code> and <code>moved_temporarily</code> callbacks +must return the new location of the resource if it was in +fact moved.</p></div> +<div class="paragraph"><p>The <code>content_types_accepted</code> returns a list of +content-types it accepts, but also the name of a callback +for each of them. Cowboy will select the appropriate +callback for processing the request body and call it.</p></div> +<div class="paragraph"><p>This callback may return one of three different return +values.</p></div> +<div class="paragraph"><p>If an error occurred while processing the request body, +it must return <code>false</code> and Cowboy will send an +appropriate error response.</p></div> +<div class="paragraph"><p>If the method is POST, then you may return <code>true</code> with +an URI of where the resource has been created. This is +especially useful for writing handlers for collections.</p></div> +<div class="paragraph"><p>Otherwise, return <code>true</code> to indicate success. Cowboy +will select the appropriate response to be sent depending +on whether a resource has been created, rather than +modified, and on the availability of a location header +or a body in the response.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_delete_method">DELETE method</h2> +<div class="sectionbody"> +<div class="paragraph"><p>This diagram only applies to DELETE requests.</p></div> +<div class="paragraph"><p>For a description of the <code>cond</code> step, please see +the "Conditional requests" diagram.</p></div> +<div class="imageblock"> +<div class="content"> +<img src="../rest_delete.png" alt="REST DELETE method flowchart" /> +</div> +</div> +<div class="paragraph"><p>When the resource exists, and the conditional steps +succeed, the resource can be deleted.</p></div> +<div class="paragraph"><p>Deleting the resource is a two steps process. First +the callback <code>delete_resource</code> is executed. Use this +callback to delete the resource.</p></div> +<div class="paragraph"><p>Because the resource may be cached, you must also +delete all cached representations of this resource +in the system. This operation may take a while though, +so you may return before it finished.</p></div> +<div class="paragraph"><p>Cowboy will then call the <code>delete_completed</code> callback. +If you know that the resource has been completely +deleted from your system, including from caches, then +you can return <code>true</code>. If any doubts persist, return +<code>false</code>. Cowboy will assume <code>true</code> by default.</p></div> +<div class="paragraph"><p>To finish, Cowboy checks if you set a response body, +and depending on that, sends the appropriate response.</p></div> +<div class="paragraph"><p>When the resource does not exist, Cowboy will figure out +whether the resource existed previously, and if so whether +it was moved elsewhere in order to redirect the client to +the new URI.</p></div> +<div class="paragraph"><p>The <code>moved_permanently</code> and <code>moved_temporarily</code> callbacks +must return the new location of the resource if it was in +fact moved.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_conditional_requests">Conditional requests</h2> +<div class="sectionbody"> +<div class="paragraph"><p>This diagram applies to all request methods other than +OPTIONS. It is executed right after the <code>resource_exists</code> +callback, when the resource exists.</p></div> +<div class="imageblock"> +<div class="content"> +<img src="../rest_cond.png" alt="REST conditional requests flowchart" /> +</div> +</div> +<div class="paragraph"><p>A request becomes conditional when it includes either of +the if-match header; the if-unmodified-since header; the +if-none-match header; or the if-modified-since header.</p></div> +<div class="paragraph"><p>If the condition fails, the request ends immediately +without any retrieval or modification of the resource.</p></div> +<div class="paragraph"><p>The <code>generate_etag</code> and <code>last_modified</code> are called as +needed. Cowboy will only call them once and then cache +the results for subsequent use.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/rest_handlers/"> + REST handlers + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/resource_design/"> + Designing a resource handler + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/rest_get_head.png b/docs/en/cowboy/2.2/guide/rest_get_head.png Binary files differnew file mode 100644 index 00000000..211ab603 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_get_head.png diff --git a/docs/en/cowboy/2.2/guide/rest_get_head.svg b/docs/en/cowboy/2.2/guide/rest_get_head.svg new file mode 100644 index 00000000..92030cf3 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_get_head.svg @@ -0,0 +1,1523 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + version="1.1" + inkscape:version="0.92.1 r" + sodipodi:docname="rest_get_head.svg" + inkscape:export-filename="/home/essen/Dropbox/Public/drawing.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs4"> + <linearGradient + id="linearGradient5265"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5267" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.58823532;" + offset="1" + id="stop5269" /> + </linearGradient> + <linearGradient + id="linearGradient5251"> + <stop + style="stop-color:#69d2e7;stop-opacity:0.78431374;" + offset="0" + id="stop5253" /> + <stop + id="stop5263" + offset="0.5" + style="stop-color:#69d2e7;stop-opacity:1;" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.39215687;" + offset="1" + id="stop5255" /> + </linearGradient> + <linearGradient + id="linearGradient5233" + osb:paint="solid"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5235" /> + </linearGradient> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="1" + inkscape:pageshadow="2" + inkscape:zoom="1.4142136" + inkscape:cx="353.51266" + inkscape:cy="522.73683" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="1920" + inkscape:window-height="1043" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:snap-global="true" + showguides="true"> + <inkscape:grid + type="xygrid" + id="grid5357" + empspacing="5" + visible="true" + enabled="true" + snapvisiblegridlinesonly="true" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <path + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:connector-curvature="0" + id="use5777" + d="m -360.31658,371.70113 203.00246,0.045" + style="fill:none;stroke:#6d8e41;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.99999999, 3.99999998;stroke-dashoffset:0" /> + <g + transform="translate(416.63925,-305.0045)" + id="g5650-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-9" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-0" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(270.88515,-59.451492)" + id="g5650-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-5" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-1" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(270.88515,22.975441)" + id="g5650-94" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-71" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-5" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(270.88515,105.29639)" + id="g5650-93" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-3" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-4" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(270.88515,187.81342)" + id="g5650-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-93" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-04" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(270.88515,270.7128)" + id="g5650-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(270.88515,-141.93971)" + id="g5650-0-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-5-3" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-1-1" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28" + width="210.17955" + height="35.209244" + x="108.01281" + y="275.4668" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-5" + width="210.17955" + height="35.209244" + x="108.01281" + y="357.98779" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8" + width="210.17955" + height="35.209244" + x="108.01281" + y="440.50873" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-4" + width="210.17955" + height="35.209244" + x="108.01281" + y="523.02966" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + transform="matrix(0,-1,1,0,-314.06239,730.23773)" + id="g5650-2-0-4-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-5" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-2" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-87" + width="210.17955" + height="35.209244" + x="108.01281" + y="605.5506" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,261.76354,-143.71473)" + id="g5650-2-2-8"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-4" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-3" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1" + width="210.17955" + height="35.209244" + x="253.76691" + y="112.69559" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + id="g5650" + transform="translate(0,-0.47597102)"> + <path + inkscape:connector-curvature="0" + id="path5570" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273" + width="104.5895" + height="36.392323" + x="-224.02068" + y="29.41218" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7" + width="104.5895" + height="36.392323" + x="-224.02068" + y="90.691978" + rx="15" /> + <rect + style="fill:#ffc48c;fill-opacity:1;fill-rule:nonzero;stroke:#d79c64;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-2" + width="104.5895" + height="36.392323" + x="-224.02068" + y="151.97169" + rx="15" /> + <rect + style="fill:#ff9f80;fill-opacity:1;fill-rule:nonzero;stroke:#d77758;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-22" + width="104.5895" + height="36.392323" + x="-224.02068" + y="213.25146" + rx="15" /> + <rect + style="fill:#f56991;fill-opacity:1;fill-rule:nonzero;stroke:#cd4169;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-8" + width="104.5895" + height="36.392323" + x="-224.02068" + y="274.53128" + rx="15" /> + <use + x="0" + y="0" + xlink:href="#rect5273-22" + id="use5355" + transform="translate(530.58261,-183.7816)" + width="744.09448" + height="1052.3622" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="-58.692513" + y="114.39204" + id="text5371"><tspan + sodipodi:role="line" + id="tspan5373" + x="-58.692513" + y="114.39204" + style="font-size:16px;line-height:1.25;font-family:sans-serif">some text</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="-58.692513" + y="53.112247" + id="text5371-2"><tspan + sodipodi:role="line" + id="tspan5373-6" + x="-58.692513" + y="53.112247" + style="font-size:16px;line-height:1.25;font-family:sans-serif">some text</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="213.07524" + y="379.78381" + id="text5371-2-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7" + x="213.07524" + y="379.78381" + style="font-size:16px;line-height:1.25;font-family:sans-serif">last_modified</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="212.74321" + y="546.59912" + id="text5371-2-3-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7-3" + x="212.74321" + y="546.59912" + style="font-size:16px;line-height:1.25;font-family:sans-serif">ProvideCallback</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="-58.692513" + y="236.95154" + id="text5371-4"><tspan + sodipodi:role="line" + id="tspan5373-9" + x="-58.692513" + y="236.95154" + style="font-size:16px;line-height:1.25;font-family:sans-serif">some text</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="359.14185" + y="50.482433" + id="text5371-4-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + x="359.14185" + y="50.482433" + id="tspan17171" + style="font-size:16px;line-height:1.25;font-family:sans-serif">conneg</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="212.77055" + y="627.34662" + id="text5371-2-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-8" + x="212.77055" + y="627.34662" + style="font-size:16px;line-height:1.25;font-family:sans-serif">multiple_choices</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="358.52466" + y="134.49161" + id="text5371-2-95" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-80" + x="358.52466" + y="134.49161" + style="font-size:16px;line-height:1.25;font-family:sans-serif">resource_exists</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="213.38774" + y="296.80188" + id="text5371-2-32" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-27" + x="213.38774" + y="296.80188" + style="font-size:16px;line-height:1.25;font-family:sans-serif">generate_etag</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="213.05571" + y="462.5274" + id="text5371-2-74" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18" + x="213.05571" + y="462.5274" + style="font-size:16px;line-height:1.25;font-family:sans-serif">expires</tspan></text> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-2" + width="210.17955" + height="35.209244" + x="-489.75586" + y="33.4944" + rx="15" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="251.83722" + y="175.92931" + id="text5371-2-391" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63" + x="251.83722" + y="175.92931" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="161.54012" + y="670.38055" + id="text5371-2-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3" + x="161.54012" + y="670.38055" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <g + transform="matrix(0,-1,1,0,-513.31414,353.05561)" + id="g5650-2"> + <path + inkscape:connector-curvature="0" + id="path5570-2" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="447.26678" + y="176.39024" + id="text5371-4-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-0" + x="447.26678" + y="176.39024" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <g + transform="translate(563.72619,-141.76777)" + id="g5650-2-2"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:2.44279909;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5367" + width="207.05719" + height="171.55719" + x="-373.52859" + y="458.58362" + rx="11.072577" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="-544.69421" + y="-354.17184" + id="text5371-2-3-0-7" + transform="rotate(-90)" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7-3-9" + x="-544.69421" + y="-354.17184" + style="font-size:16px;line-height:1.25;font-family:sans-serif">middlewares</tspan></text> + <g + transform="matrix(0,-1,1,0,-508.93096,565.23553)" + id="g5650-2-0-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="46.409981" + y="711.18011" + id="text5371-4-3-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-62-9" + x="46.409981" + y="711.18011" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="545.12921" + y="257.43518" + id="text5371-4-4-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6" + x="545.12921" + y="257.43518" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <g + transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,547.47379,-62.310424)" + id="g5650-9-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-7-6" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-09-5" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <use + x="0" + y="0" + xlink:href="#rect5273-22" + id="use5355-0" + transform="translate(384.82851,-20.897068)" + width="744.09448" + height="1052.3622" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="213.38774" + y="216.5154" + id="text5371-4-0-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + x="213.38774" + y="216.5154" + id="tspan17171-6" + style="font-size:16px;line-height:1.25;font-family:sans-serif">cond</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-1" + width="218.52127" + height="34.993004" + x="103.84195" + y="770.70062" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="212.88774" + y="792.61121" + id="text5371-43-5" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-62" + x="212.88774" + y="792.61121" + style="font-size:16px;line-height:1.25;font-family:sans-serif">300 multiple choices</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-8" + width="218.52127" + height="34.993004" + x="103.84195" + y="688.17969" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="212.35258" + y="711.50043" + id="text5371-43-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-1" + x="212.35258" + y="711.50043" + style="font-size:16px;line-height:1.25;font-family:sans-serif">200 OK</tspan></text> + <g + transform="matrix(0,-1,-1,0,1028.2004,317.70407)" + id="g5650-2-0-4-3-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8-9" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28-4" + width="210.17955" + height="35.209244" + x="400.85385" + y="192.94594" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="505.77957" + y="216.51541" + id="text5371-2-32-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-27-8" + x="505.77957" + y="216.51541" + style="font-size:16px;line-height:1.25;font-family:sans-serif">has if-match?</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="651.74426" + y="299.27689" + id="text5371-2-391-5" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63-7" + x="651.74426" + y="299.27689" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <g + transform="translate(563.72619,22.800669)" + id="g5650-0-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-5-7" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-1-3" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,-1,0,1027.6701,482.30508)" + id="g5650-2-0-4-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28-7" + width="210.17955" + height="35.209244" + x="400.85385" + y="357.98779" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="505.94363" + y="379.78381" + id="text5371-2-32-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-27-1" + x="505.94363" + y="379.78381" + style="font-size:16px;line-height:1.25;font-family:sans-serif">previously_existed</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-5" + width="218.52127" + height="34.993004" + x="396.68301" + y="440.37622" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="506.2796" + y="463.83755" + id="text5371-43-2" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-9" + x="506.2796" + y="463.83755" + style="font-size:16px;line-height:1.25;font-family:sans-serif">404 not found</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="528.75421" + y="422.69736" + id="text5371-2-8-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-4" + x="528.75421" + y="422.69736" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <g + transform="translate(563.72619,187.85116)" + id="g5650-2-2-17"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-0" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-45" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,-1,0,1027.4933,646.81763)" + id="g5650-2-0-4-3-8-0-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8-9-31-8" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6-3-6" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9" + width="210.17955" + height="35.209244" + x="400.85385" + y="523.02966" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="505.45535" + y="544.82568" + id="text5371-2-74-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2" + x="505.45535" + y="544.82568" + style="font-size:16px;line-height:1.25;font-family:sans-serif">moved_permanently</tspan></text> + <g + transform="matrix(0,-1,-1,0,347.00351,567.35686)" + id="g5650-2-0-4-3-8-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8-9-3" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6-1" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1" + width="218.52127" + height="34.993004" + x="396.68301" + y="275.81555" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="506.2796" + y="297.7261" + id="text5371-43" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3" + x="506.2796" + y="297.7261" + style="font-size:16px;line-height:1.25;font-family:sans-serif">412 precondition failed</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="668.11926" + y="463.37662" + id="text5371-4-3-9-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-62-9-9" + x="668.11926" + y="463.37662" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="549.12921" + y="587.59863" + id="text5371-4-4-9-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-2" + x="549.12921" + y="587.59863" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true*</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="651.74426" + y="628.87946" + id="text5371-2-391-5-5-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63-7-9-9" + x="651.74426" + y="628.87946" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-5-9" + width="218.52127" + height="34.993004" + x="396.68301" + y="605.41809" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="505.57257" + y="627.32867" + id="text5371-43-2-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-9-7" + x="505.57257" + y="627.32867" + style="font-size:16px;line-height:1.25;font-family:sans-serif">301 moved permanently</tspan></text> + <g + transform="translate(563.72619,353.12604)" + id="g5650-2-2-65"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-5" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-5" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,-1,0,1032.2004,811.50699)" + id="g5650-2-0-4-3-8-0-3-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8-9-31-8-1" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6-3-6-3" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9-1" + width="210.17955" + height="35.209244" + x="400.85385" + y="687.83093" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="505.45535" + y="709.62695" + id="text5371-2-74-0-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2-8" + x="505.45535" + y="709.62695" + style="font-size:16px;line-height:1.25;font-family:sans-serif">moved_temporarily</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="549.12921" + y="752.64056" + id="text5371-4-4-9-3-2" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-2-6" + x="549.12921" + y="752.64056" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true*</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="651.74426" + y="794.16199" + id="text5371-2-391-5-5-1-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63-7-9-9-2" + x="651.74426" + y="794.16199" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-5-9-2" + width="218.52127" + height="34.993004" + x="396.68301" + y="770.70062" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="505.57257" + y="792.61121" + id="text5371-43-2-9-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-9-7-8" + x="505.57257" + y="792.61121" + style="font-size:16px;line-height:1.25;font-family:sans-serif">307 moved temporarily</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-5-9-2-4" + width="218.52127" + height="34.993004" + x="396.68301" + y="853.22168" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="505.97882" + y="874.99164" + id="text5371-43-2-9-7-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-9-7-8-7" + x="505.97882" + y="874.99164" + style="font-size:16px;line-height:1.25;font-family:sans-serif">410 gone</tspan></text> + <g + transform="translate(31.619614,4.2328831)" + id="g5650-2-2-6"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-6" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-1" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + </g> +</svg> diff --git a/docs/en/cowboy/2.2/guide/rest_handlers.asciidoc b/docs/en/cowboy/2.2/guide/rest_handlers.asciidoc new file mode 100644 index 00000000..dab5bead --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_handlers.asciidoc @@ -0,0 +1,138 @@ +[[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 +describing the resource and modifying the machine's behavior. + +The REST handler is the recommended way to handle HTTP requests. + +=== Initialization + +First, the `init/2` callback is called. This callback is common +to all handlers. To use REST for the current request, this function +must return a `cowboy_rest` tuple. + +[source,erlang] +---- +init(Req, State) -> + {cowboy_rest, Req, State}. +---- + +Cowboy will then switch to the REST protocol and start executing +the state machine. + +After reaching the end of the flowchart, the `terminate/3` callback +will be called if it is defined. + +=== Methods + +The REST component has code for handling the following HTTP methods: +HEAD, GET, POST, PATCH, PUT, DELETE and OPTIONS. + +Other methods can be accepted, however they have no specific callback +defined for them at this time. + +=== Callbacks + +All callbacks are optional. Some may become mandatory depending +on what other defined callbacks return. The various flowcharts +in the next chapter should be a useful to determine which callbacks +you need. + +All callbacks take two arguments, the Req object and the State, +and return a three-element tuple of the form `{Value, Req, State}`. + +Nearly all callbacks can also return `{stop, Req, State}` to +stop execution of the request, and +`{{switch_handler, Module}, Req, State}` or +`{{switch_handler, Module, Opts}, Req, State}` to switch to +a different handler type. The exceptions are `expires` +`generate_etag`, `last_modified` and `variances`. + +The following table summarizes the callbacks and their default values. +If the callback isn't defined, then the default value will be used. +Please look at the flowcharts to find out the result of each return +value. + +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. + +[cols="<,^",options="header"] +|=== +| Callback name | Default value +| allowed_methods | `[<<"GET">>, <<"HEAD">>, <<"OPTIONS">>]` +| allow_missing_post | `true` +| charsets_provided | skip +| content_types_accepted | none +// @todo Space required for the time being: https://github.com/spf13/hugo/issues/2398 +| 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. + +In addition to these, there can be any number of user-defined +callbacks that are specified through `content_types_accepted/2` +and `content_types_provided/2`. They can take any name, however +it is recommended to use a separate prefix for the callbacks of +each function. 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 + +Cowboy will set informative values to the Req object at various +points of the execution. You can retrieve them by matching the +Req object directly. The values are defined in the following table: + +[cols="<,<",options="header"] +|=== +| 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 + +Cowboy will set response headers automatically over the execution +of the REST code. They are listed in the following table. + +[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 +|=== diff --git a/docs/en/cowboy/2.2/guide/rest_handlers/index.html b/docs/en/cowboy/2.2/guide/rest_handlers/index.html new file mode 100644 index 00000000..5e1d370b --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_handlers/index.html @@ -0,0 +1,446 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: REST handlers</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>REST handlers</span></h1> + +<div class="paragraph"><p>REST is implemented in Cowboy as a sub protocol. The request +is handled as a state machine with many optional callbacks +describing the resource and modifying the machine’s behavior.</p></div> +<div class="paragraph"><p>The REST handler is the recommended way to handle HTTP requests.</p></div> +<div class="sect1"> +<h2 id="_initialization">Initialization</h2> +<div class="sectionbody"> +<div class="paragraph"><p>First, the <code>init/2</code> callback is called. This callback is common +to all handlers. To use REST for the current request, this function +must return a <code>cowboy_rest</code> tuple.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">cowboy_rest</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Cowboy will then switch to the REST protocol and start executing +the state machine.</p></div> +<div class="paragraph"><p>After reaching the end of the flowchart, the <code>terminate/3</code> callback +will be called if it is defined.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_methods">Methods</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The REST component has code for handling the following HTTP methods: +HEAD, GET, POST, PATCH, PUT, DELETE and OPTIONS.</p></div> +<div class="paragraph"><p>Other methods can be accepted, however they have no specific callback +defined for them at this time.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_callbacks">Callbacks</h2> +<div class="sectionbody"> +<div class="paragraph"><p>All callbacks are optional. Some may become mandatory depending +on what other defined callbacks return. The various flowcharts +in the next chapter should be a useful to determine which callbacks +you need.</p></div> +<div class="paragraph"><p>All callbacks take two arguments, the Req object and the State, +and return a three-element tuple of the form <code>{Value, Req, State}</code>.</p></div> +<div class="paragraph"><p>Nearly all callbacks can also return <code>{stop, Req, State}</code> to +stop execution of the request, and +<code>{{switch_handler, Module}, Req, State}</code> or +<code>{{switch_handler, Module, Opts}, Req, State}</code> to switch to +a different handler type. The exceptions are <code>expires</code> +<code>generate_etag</code>, <code>last_modified</code> and <code>variances</code>.</p></div> +<div class="paragraph"><p>The following table summarizes the callbacks and their default values. +If the callback isn’t defined, then the default value will be used. +Please look at the flowcharts to find out the result of each return +value.</p></div> +<div class="paragraph"><p>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.</p></div> +<div class="tableblock"> +<table rules="all" +width="100%" +frame="border" +cellspacing="0" cellpadding="4"> +<col width="50%" /> +<col width="50%" /> +<thead> +<tr> +<th align="left" valign="top"> Callback name </th> +<th align="center" valign="top"> Default value</th> +</tr> +</thead> +<tbody> +<tr> +<td align="left" valign="top"><p class="table">allowed_methods</p></td> +<td align="center" valign="top"><p class="table"><code>[<<"GET">>, <<"HEAD">>, <<"OPTIONS">>]</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">allow_missing_post</p></td> +<td align="center" valign="top"><p class="table"><code>true</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">charsets_provided</p></td> +<td align="center" valign="top"><p class="table">skip</p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">content_types_accepted</p></td> +<td align="center" valign="top"><p class="table">none</p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">content_types_provided</p></td> +<td align="center" valign="top"><p class="table"><code>[{{ <<"text">>, <<"html">>, '*'}, to_html}]</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">delete_completed</p></td> +<td align="center" valign="top"><p class="table"><code>true</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">delete_resource</p></td> +<td align="center" valign="top"><p class="table"><code>false</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">expires</p></td> +<td align="center" valign="top"><p class="table"><code>undefined</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">forbidden</p></td> +<td align="center" valign="top"><p class="table"><code>false</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">generate_etag</p></td> +<td align="center" valign="top"><p class="table"><code>undefined</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">is_authorized</p></td> +<td align="center" valign="top"><p class="table"><code>true</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">is_conflict</p></td> +<td align="center" valign="top"><p class="table"><code>false</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">known_methods</p></td> +<td align="center" valign="top"><p class="table"><code>[<<"GET">>, <<"HEAD">>, <<"POST">>, <<"PUT">>, <<"PATCH">>, <<"DELETE">>, <<"OPTIONS">>]</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">languages_provided</p></td> +<td align="center" valign="top"><p class="table">skip</p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">last_modified</p></td> +<td align="center" valign="top"><p class="table"><code>undefined</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">malformed_request</p></td> +<td align="center" valign="top"><p class="table"><code>false</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">moved_permanently</p></td> +<td align="center" valign="top"><p class="table"><code>false</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">moved_temporarily</p></td> +<td align="center" valign="top"><p class="table"><code>false</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">multiple_choices</p></td> +<td align="center" valign="top"><p class="table"><code>false</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">options</p></td> +<td align="center" valign="top"><p class="table"><code>ok</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">previously_existed</p></td> +<td align="center" valign="top"><p class="table"><code>false</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">resource_exists</p></td> +<td align="center" valign="top"><p class="table"><code>true</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">service_available</p></td> +<td align="center" valign="top"><p class="table"><code>true</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">uri_too_long</p></td> +<td align="center" valign="top"><p class="table"><code>false</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">valid_content_headers</p></td> +<td align="center" valign="top"><p class="table"><code>true</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">valid_entity_length</p></td> +<td align="center" valign="top"><p class="table"><code>true</code></p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">variances</p></td> +<td align="center" valign="top"><p class="table"><code>[]</code></p></td> +</tr> +</tbody> +</table> +</div> +<div class="paragraph"><p>As you can see, Cowboy tries to move on with the request whenever +possible by using well thought out default values.</p></div> +<div class="paragraph"><p>In addition to these, there can be any number of user-defined +callbacks that are specified through <code>content_types_accepted/2</code> +and <code>content_types_provided/2</code>. They can take any name, however +it is recommended to use a separate prefix for the callbacks of +each function. For example, <code>from_html</code> and <code>to_html</code> 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.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_meta_data">Meta data</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy will set informative values to the Req object at various +points of the execution. You can retrieve them by matching the +Req object directly. The values are defined in the following table:</p></div> +<div class="tableblock"> +<table rules="all" +width="100%" +frame="border" +cellspacing="0" cellpadding="4"> +<col width="50%" /> +<col width="50%" /> +<thead> +<tr> +<th align="left" valign="top"> Key </th> +<th align="left" valign="top"> Details</th> +</tr> +</thead> +<tbody> +<tr> +<td align="left" valign="top"><p class="table">media_type</p></td> +<td align="left" valign="top"><p class="table">The content-type negotiated for the response entity.</p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">language</p></td> +<td align="left" valign="top"><p class="table">The language negotiated for the response entity.</p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">charset</p></td> +<td align="left" valign="top"><p class="table">The charset negotiated for the response entity.</p></td> +</tr> +</tbody> +</table> +</div> +<div class="paragraph"><p>They can be used to send a proper body with the response to a +request that used a method other than HEAD or GET.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_response_headers">Response headers</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy will set response headers automatically over the execution +of the REST code. They are listed in the following table.</p></div> +<div class="tableblock"> +<table rules="all" +width="100%" +frame="border" +cellspacing="0" cellpadding="4"> +<col width="50%" /> +<col width="50%" /> +<thead> +<tr> +<th align="left" valign="top"> Header name </th> +<th align="left" valign="top"> Details</th> +</tr> +</thead> +<tbody> +<tr> +<td align="left" valign="top"><p class="table">content-language</p></td> +<td align="left" valign="top"><p class="table">Language used in the response body</p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">content-type</p></td> +<td align="left" valign="top"><p class="table">Media type and charset of the response body</p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">etag</p></td> +<td align="left" valign="top"><p class="table">Etag of the resource</p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">expires</p></td> +<td align="left" valign="top"><p class="table">Expiration date of the resource</p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">last-modified</p></td> +<td align="left" valign="top"><p class="table">Last modification date for the resource</p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">location</p></td> +<td align="left" valign="top"><p class="table">Relative or absolute URI to the requested resource</p></td> +</tr> +<tr> +<td align="left" valign="top"><p class="table">vary</p></td> +<td align="left" valign="top"><p class="table">List of headers that may change the representation of the resource</p></td> +</tr> +</tbody> +</table> +</div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/rest_principles/"> + REST principles + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/rest_flowcharts/"> + REST flowcharts + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/rest_options.png b/docs/en/cowboy/2.2/guide/rest_options.png Binary files differnew file mode 100644 index 00000000..90fd6f06 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_options.png diff --git a/docs/en/cowboy/2.2/guide/rest_options.svg b/docs/en/cowboy/2.2/guide/rest_options.svg new file mode 100644 index 00000000..496c050c --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_options.svg @@ -0,0 +1,387 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + version="1.1" + inkscape:version="0.48.4 r9939" + sodipodi:docname="rest_options.svg" + inkscape:export-filename="/home/essen/Dropbox/Public/drawing.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs4"> + <linearGradient + id="linearGradient5265"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5267" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.58823532;" + offset="1" + id="stop5269" /> + </linearGradient> + <linearGradient + id="linearGradient5251"> + <stop + style="stop-color:#69d2e7;stop-opacity:0.78431374;" + offset="0" + id="stop5253" /> + <stop + id="stop5263" + offset="0.5" + style="stop-color:#69d2e7;stop-opacity:1;" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.39215687;" + offset="1" + id="stop5255" /> + </linearGradient> + <linearGradient + id="linearGradient5233" + osb:paint="solid"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5235" /> + </linearGradient> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="1" + inkscape:pageshadow="2" + inkscape:zoom="1.0000001" + inkscape:cx="166.77748" + inkscape:cy="548.36436" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="2560" + inkscape:window-height="1402" + inkscape:window-x="0" + inkscape:window-y="38" + inkscape:window-maximized="1" + inkscape:snap-global="true" + showguides="true"> + <inkscape:grid + type="xygrid" + id="grid5357" + empspacing="5" + visible="true" + enabled="true" + snapvisiblegridlinesonly="true" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <path + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:connector-curvature="0" + id="use5777" + d="m -360.31658,371.70113 203.00246,0.045" + style="fill:none;stroke:#6d8e41;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.99999999, 3.99999998;stroke-dashoffset:0" /> + <g + transform="translate(205.92143,-296.03137)" + id="g5650-7"> + <path + inkscape:connector-curvature="0" + id="path5570-9" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-0" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(205.92143,-212.00698)" + id="g5650-9"> + <path + inkscape:connector-curvature="0" + id="path5570-7" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-09" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28" + width="210.17955" + height="35.209244" + x="43.049091" + y="204.67757" + rx="15" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1" + width="210.17955" + height="35.209244" + x="43.049091" + y="121.0042" + rx="15" /> + <g + id="g5650" + transform="translate(0,-0.47597102)"> + <path + inkscape:connector-curvature="0" + id="path5570" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273" + width="104.5895" + height="36.392323" + x="-224.02068" + y="29.41218" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7" + width="104.5895" + height="36.392323" + x="-224.02068" + y="90.691978" + rx="15" /> + <rect + style="fill:#ffc48c;fill-opacity:1;fill-rule:nonzero;stroke:#d79c64;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-2" + width="104.5895" + height="36.392323" + x="-224.02068" + y="151.97169" + rx="15" /> + <rect + style="fill:#ff9f80;fill-opacity:1;fill-rule:nonzero;stroke:#d77758;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-22" + width="104.5895" + height="36.392323" + x="-224.02068" + y="213.25146" + rx="15" /> + <rect + style="fill:#f56991;fill-opacity:1;fill-rule:nonzero;stroke:#cd4169;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-8" + width="104.5895" + height="36.392323" + x="-224.02068" + y="274.53128" + rx="15" /> + <use + x="0" + y="0" + xlink:href="#rect5273-22" + id="use5355" + transform="translate(319.86479,-176.50006)" + width="744.09448" + height="1052.3622" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="114.39204" + id="text5371" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373" + x="-58.692513" + y="114.39204">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="53.112247" + id="text5371-2" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6" + x="-58.692513" + y="53.112247">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="236.95154" + id="text5371-4" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-9" + x="-58.692513" + y="236.95154">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="147.00391" + y="60.912468" + id="text5371-4-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + x="147.00391" + y="60.912468" + id="tspan17171">start</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="148.13106" + y="142.80627" + id="text5371-2-95" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-80" + x="148.13106" + y="142.80627">options</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="147.80684" + y="226.4736" + id="text5371-2-32" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-27" + x="147.80684" + y="226.4736">200 OK</tspan></text> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-2" + width="210.17955" + height="35.209244" + x="-489.75586" + y="33.4944" + rx="15" /> + <g + transform="matrix(0,-1,1,0,-513.31414,353.05561)" + id="g5650-2"> + <path + inkscape:connector-curvature="0" + id="path5570-2" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:2.44279909;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5367" + width="207.05719" + height="171.55719" + x="-373.52859" + y="458.58362" + rx="11.072577" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-544.69421" + y="-354.17184" + id="text5371-2-3-0-7" + sodipodi:linespacing="125%" + transform="matrix(0,-1,1,0,0,0)" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7-3-9" + x="-544.69421" + y="-354.17184">middlewares</tspan></text> + </g> +</svg> diff --git a/docs/en/cowboy/2.2/guide/rest_principles.asciidoc b/docs/en/cowboy/2.2/guide/rest_principles.asciidoc new file mode 100644 index 00000000..66939cb7 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_principles.asciidoc @@ -0,0 +1,160 @@ +[[rest_principles]] +== REST principles + +This chapter will attempt to define the concepts behind REST +and explain what makes a service RESTful. + +REST is often confused with performing a distinct operation +depending on the HTTP method, while using more than the GET +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 +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 is a *client-server* architecture. The client and the server +both have a different set of concerns. The server stores and/or +manipulates information and makes it available to the user in +an efficient manner. The client takes that information and +displays it to the user and/or uses it to perform subsequent +requests for information. This separation of concerns allows both +the client and the server to evolve independently as it only +requires that the interface stays the same. + +REST is *stateless*. That means the communication between the +client and the server always contains all the information needed +to perform the request. There is no session state in the server, +it is kept entirely on the client's side. If access to a resource +requires authentication, then the client needs to authenticate +itself with every request. + +REST is *cacheable*. The client, the server and any intermediary +components can all cache resources in order to improve performance. + +REST provides a *uniform interface* between components. This +simplifies the architecture, as all components follow the same +rules to speak to one another. It also makes it easier to understand +the interactions between the different components of the system. +A number of constraints are required to achieve this. They are +covered in the rest of the chapter. + +REST is a *layered system*. Individual components cannot see +beyond the immediate layer with which they are interacting. This +means that a client connecting to an intermediate component, like +a proxy, has no knowledge of what lies beyond. This allows +components to be independent and thus easily replaceable or +extendable. + +REST optionally provides *code on demand*. Code may be downloaded +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 + +A resource is an abstract concept. In a REST system, any information +that can be named may be a resource. This includes documents, images, +a collection of resources and any other information. Any information +that can be the target of an hypertext link can be a resource. + +A resource is a conceptual mapping to a set of entities. The set of +entities evolves over time; a resource doesn't. For example, a resource +can map to "users who have logged in this past month" and another +to "all users". At some point in time they may map to the same set of +entities, because all users logged in this past month. But they are +still different resources. Similarly, if nobody logged in recently, +then the first resource may map to the empty set. This resource exists +regardless of the information it maps to. + +Resources are identified by uniform resource identifiers, also known +as URIs. Sometimes internationalized resource identifiers, or IRIs, +may also be used, but these can be directly translated into a URI. + +In practice we will identify two kinds of resources. Individual +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 + +The representation of a resource is a sequence of bytes associated +with metadata. + +The metadata comes as a list of key-value pairs, where the name +corresponds to a standard that defines the value's structure and +semantics. With HTTP, the metadata comes in the form of request +or response headers. The headers' structure and semantics are well +defined in the HTTP standard. Metadata includes representation +metadata, resource metadata and control data. + +The representation metadata gives information about the +representation, such as its media type, the date of last +modification, or even a checksum. + +Resource metadata could be link to related resources or +information about additional representations of the resource. + +Control data allows parameterizing the request or response. +For example, we may only want the representation returned if +it is more recent than the one we have in cache. Similarly, +we may want to instruct the client about how it should cache +the representation. This isn't restricted to caching. We may, +for example, want to store a new representation of a resource +only if it wasn't modified since we first retrieved it. + +The data format of a representation is also known as the media +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 + +Messages must be self-descriptive. That means that the data +format of a representation must always come with its media +type (and similarly requesting a resource involves choosing +the media type of the representation returned). If you are +sending HTML, then you must say it is HTML by sending the +media type with the representation. In HTTP this is done +using the content-type header. + +The media type is often an IANA registered media type, like +`text/html` or `image/png`, but does not need to be. Exactly +two things are important for respecting this constraint: that +the media type is well specified, and that the sender and +recipient agree about what the media type refers to. + +This means that you can create your own media types, like +`application/x-mine`, and that as long as you write the +specifications for it and that both endpoints agree about +it then the constraint is respected. + +=== 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 +entirely driven by hypermedia. The client does not need +any prior knowledge of the service in order to use it, +other than an entry point and of course basic understanding +of the media type of the representations, at the very least +enough to find and identify hyperlinks and link relations. + +To give a simple example, if your service only works with +the `application/json` media type then this constraint +cannot be respected (as there are no concept of links in +JSON) and thus your service isn't RESTful. This is the case +for the majority of self-proclaimed REST services. + +On the other hand if you create a JSON based media type +that has a concept of links and link relations, then +your service might be RESTful. + +Respecting this constraint means that the entirety of the +service becomes self-discoverable, not only the resources +in it, but also the operations you can perform on it. This +makes clients very thin as there is no need to implement +anything specific to the service to operate on it. diff --git a/docs/en/cowboy/2.2/guide/rest_principles/index.html b/docs/en/cowboy/2.2/guide/rest_principles/index.html new file mode 100644 index 00000000..85821c36 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_principles/index.html @@ -0,0 +1,312 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: REST principles</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>REST principles</span></h1> + +<div class="paragraph"><p>This chapter will attempt to define the concepts behind REST +and explain what makes a service RESTful.</p></div> +<div class="paragraph"><p>REST is often confused with performing a distinct operation +depending on the HTTP method, while using more than the GET +and POST methods. That’s highly misguided at best.</p></div> +<div class="paragraph"><p>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 +<a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm">Roy T. Fielding’s dissertation</a> +as it does a great job explaining where it comes from and +what it achieves.</p></div> +<div class="sect1"> +<h2 id="_rest_architecture">REST architecture</h2> +<div class="sectionbody"> +<div class="paragraph"><p>REST is a <strong>client-server</strong> architecture. The client and the server +both have a different set of concerns. The server stores and/or +manipulates information and makes it available to the user in +an efficient manner. The client takes that information and +displays it to the user and/or uses it to perform subsequent +requests for information. This separation of concerns allows both +the client and the server to evolve independently as it only +requires that the interface stays the same.</p></div> +<div class="paragraph"><p>REST is <strong>stateless</strong>. That means the communication between the +client and the server always contains all the information needed +to perform the request. There is no session state in the server, +it is kept entirely on the client’s side. If access to a resource +requires authentication, then the client needs to authenticate +itself with every request.</p></div> +<div class="paragraph"><p>REST is <strong>cacheable</strong>. The client, the server and any intermediary +components can all cache resources in order to improve performance.</p></div> +<div class="paragraph"><p>REST provides a <strong>uniform interface</strong> between components. This +simplifies the architecture, as all components follow the same +rules to speak to one another. It also makes it easier to understand +the interactions between the different components of the system. +A number of constraints are required to achieve this. They are +covered in the rest of the chapter.</p></div> +<div class="paragraph"><p>REST is a <strong>layered system</strong>. Individual components cannot see +beyond the immediate layer with which they are interacting. This +means that a client connecting to an intermediate component, like +a proxy, has no knowledge of what lies beyond. This allows +components to be independent and thus easily replaceable or +extendable.</p></div> +<div class="paragraph"><p>REST optionally provides <strong>code on demand</strong>. Code may be downloaded +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.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_resources_and_resource_identifiers">Resources and resource identifiers</h2> +<div class="sectionbody"> +<div class="paragraph"><p>A resource is an abstract concept. In a REST system, any information +that can be named may be a resource. This includes documents, images, +a collection of resources and any other information. Any information +that can be the target of an hypertext link can be a resource.</p></div> +<div class="paragraph"><p>A resource is a conceptual mapping to a set of entities. The set of +entities evolves over time; a resource doesn’t. For example, a resource +can map to "users who have logged in this past month" and another +to "all users". At some point in time they may map to the same set of +entities, because all users logged in this past month. But they are +still different resources. Similarly, if nobody logged in recently, +then the first resource may map to the empty set. This resource exists +regardless of the information it maps to.</p></div> +<div class="paragraph"><p>Resources are identified by uniform resource identifiers, also known +as URIs. Sometimes internationalized resource identifiers, or IRIs, +may also be used, but these can be directly translated into a URI.</p></div> +<div class="paragraph"><p>In practice we will identify two kinds of resources. Individual +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".</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_resource_representations">Resource representations</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The representation of a resource is a sequence of bytes associated +with metadata.</p></div> +<div class="paragraph"><p>The metadata comes as a list of key-value pairs, where the name +corresponds to a standard that defines the value’s structure and +semantics. With HTTP, the metadata comes in the form of request +or response headers. The headers' structure and semantics are well +defined in the HTTP standard. Metadata includes representation +metadata, resource metadata and control data.</p></div> +<div class="paragraph"><p>The representation metadata gives information about the +representation, such as its media type, the date of last +modification, or even a checksum.</p></div> +<div class="paragraph"><p>Resource metadata could be link to related resources or +information about additional representations of the resource.</p></div> +<div class="paragraph"><p>Control data allows parameterizing the request or response. +For example, we may only want the representation returned if +it is more recent than the one we have in cache. Similarly, +we may want to instruct the client about how it should cache +the representation. This isn’t restricted to caching. We may, +for example, want to store a new representation of a resource +only if it wasn’t modified since we first retrieved it.</p></div> +<div class="paragraph"><p>The data format of a representation is also known as the media +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.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_self_descriptive_messages">Self-descriptive messages</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Messages must be self-descriptive. That means that the data +format of a representation must always come with its media +type (and similarly requesting a resource involves choosing +the media type of the representation returned). If you are +sending HTML, then you must say it is HTML by sending the +media type with the representation. In HTTP this is done +using the content-type header.</p></div> +<div class="paragraph"><p>The media type is often an IANA registered media type, like +<code>text/html</code> or <code>image/png</code>, but does not need to be. Exactly +two things are important for respecting this constraint: that +the media type is well specified, and that the sender and +recipient agree about what the media type refers to.</p></div> +<div class="paragraph"><p>This means that you can create your own media types, like +<code>application/x-mine</code>, and that as long as you write the +specifications for it and that both endpoints agree about +it then the constraint is respected.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_hypermedia_as_the_engine_of_application_state">Hypermedia as the engine of application state</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The last constraint is generally where services that claim +to be RESTful fail. Interactions with a server must be +entirely driven by hypermedia. The client does not need +any prior knowledge of the service in order to use it, +other than an entry point and of course basic understanding +of the media type of the representations, at the very least +enough to find and identify hyperlinks and link relations.</p></div> +<div class="paragraph"><p>To give a simple example, if your service only works with +the <code>application/json</code> media type then this constraint +cannot be respected (as there are no concept of links in +JSON) and thus your service isn’t RESTful. This is the case +for the majority of self-proclaimed REST services.</p></div> +<div class="paragraph"><p>On the other hand if you create a JSON based media type +that has a concept of links and link relations, then +your service might be RESTful.</p></div> +<div class="paragraph"><p>Respecting this constraint means that the entirety of the +service becomes self-discoverable, not only the resources +in it, but also the operations you can perform on it. This +makes clients very thin as there is no need to implement +anything specific to the service to operate on it.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/multipart/"> + Multipart requests + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/rest_handlers/"> + REST handlers + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/rest_put_post_patch.png b/docs/en/cowboy/2.2/guide/rest_put_post_patch.png Binary files differnew file mode 100644 index 00000000..176650e9 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_put_post_patch.png diff --git a/docs/en/cowboy/2.2/guide/rest_put_post_patch.svg b/docs/en/cowboy/2.2/guide/rest_put_post_patch.svg new file mode 100644 index 00000000..06d55052 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_put_post_patch.svg @@ -0,0 +1,2856 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448" + height="1052.3622" + id="svg2" + version="1.1" + inkscape:version="0.92.1 r" + sodipodi:docname="rest_put_post_patch.svg" + inkscape:export-filename="/home/essen/Dropbox/Public/drawing.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs4"> + <linearGradient + id="linearGradient5265"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5267" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.58823532;" + offset="1" + id="stop5269" /> + </linearGradient> + <linearGradient + id="linearGradient5251"> + <stop + style="stop-color:#69d2e7;stop-opacity:0.78431374;" + offset="0" + id="stop5253" /> + <stop + id="stop5263" + offset="0.5" + style="stop-color:#69d2e7;stop-opacity:1;" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.39215687;" + offset="1" + id="stop5255" /> + </linearGradient> + <linearGradient + id="linearGradient5233" + osb:paint="solid"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5235" /> + </linearGradient> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="1" + inkscape:pageshadow="2" + inkscape:zoom="0.70710678" + inkscape:cx="201.51415" + inkscape:cy="-214.71801" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="1920" + inkscape:window-height="1043" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:snap-global="true" + showguides="true"> + <inkscape:grid + type="xygrid" + id="grid5357" + empspacing="5" + visible="true" + enabled="true" + snapvisiblegridlinesonly="true" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,1.5472441e-4)"> + <path + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:connector-curvature="0" + id="use5777" + d="m -360.31658,371.70113 203.00246,0.045" + style="fill:none;stroke:#6d8e41;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.99999999, 3.99999998;stroke-dashoffset:0" /> + <g + transform="translate(370.63925,-305.0045)" + id="g5650-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-9" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-0" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,215.76354,-143.71473)" + id="g5650-2-2-8"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-4" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-3" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1" + width="210.17955" + height="35.209244" + x="207.76691" + y="112.69559" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + id="g5650" + transform="translate(229.41793,93.569228)"> + <path + inkscape:connector-curvature="0" + id="path5570" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273" + width="104.5895" + height="36.392323" + x="-224.02068" + y="29.41218" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7" + width="104.5895" + height="36.392323" + x="-224.02068" + y="90.691978" + rx="15" /> + <rect + style="fill:#ffc48c;fill-opacity:1;fill-rule:nonzero;stroke:#d79c64;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-2" + width="104.5895" + height="36.392323" + x="-224.02068" + y="151.97169" + rx="15" /> + <rect + style="fill:#ff9f80;fill-opacity:1;fill-rule:nonzero;stroke:#d77758;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-22" + width="104.5895" + height="36.392323" + x="-224.02068" + y="213.25146" + rx="15" /> + <rect + style="fill:#f56991;fill-opacity:1;fill-rule:nonzero;stroke:#cd4169;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-8" + width="104.5895" + height="36.392323" + x="-224.02068" + y="274.53128" + rx="15" /> + <use + x="0" + y="0" + xlink:href="#rect5273-22" + id="use5355" + transform="translate(484.58261,-183.7816)" + width="744.09448" + height="1052.3622" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="-58.692513" + y="114.39204" + id="text5371"><tspan + sodipodi:role="line" + id="tspan5373" + x="-58.692513" + y="114.39204" + style="font-size:16px;line-height:1.25;font-family:sans-serif">some text</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="-58.692513" + y="53.112247" + id="text5371-2"><tspan + sodipodi:role="line" + id="tspan5373-6" + x="-58.692513" + y="53.112247" + style="font-size:16px;line-height:1.25;font-family:sans-serif">some text</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="-58.692513" + y="236.95154" + id="text5371-4"><tspan + sodipodi:role="line" + id="tspan5373-9" + x="-58.692513" + y="236.95154" + style="font-size:16px;line-height:1.25;font-family:sans-serif">some text</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="313.14185" + y="50.482433" + id="text5371-4-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + x="313.14185" + y="50.482433" + id="tspan17171" + style="font-size:16px;line-height:1.25;font-family:sans-serif">conneg</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="312.52466" + y="134.49161" + id="text5371-2-95" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-80" + x="312.52466" + y="134.49161" + style="font-size:16px;line-height:1.25;font-family:sans-serif">resource_exists</tspan></text> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-2" + width="210.17955" + height="35.209244" + x="-489.75586" + y="33.4944" + rx="15" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="205.83722" + y="175.92931" + id="text5371-2-391" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63" + x="205.83722" + y="175.92931" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <g + transform="matrix(0,-1,1,0,-586.85324,629.53436)" + id="g5650-2"> + <path + inkscape:connector-curvature="0" + id="path5570-2" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="401.26678" + y="176.39024" + id="text5371-4-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-0" + x="401.26678" + y="176.39024" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <g + transform="translate(517.41793,-144.94975)" + id="g5650-2-2"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:2.44279909;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5367" + width="207.05719" + height="171.55719" + x="-373.52859" + y="458.58362" + rx="11.072577" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="-544.69421" + y="-354.17184" + id="text5371-2-3-0-7" + transform="rotate(-90)" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7-3-9" + x="-544.69421" + y="-354.17184" + style="font-size:16px;line-height:1.25;font-family:sans-serif">middlewares</tspan></text> + <g + transform="matrix(0,-1,1,0,-508.93096,565.23553)" + id="g5650-2-0-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="496.12921" + y="255.81152" + id="text5371-4-4-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6" + x="496.12921" + y="255.81152" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <g + transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,501.47379,-62.310424)" + id="g5650-9-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-7-6" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-09-5" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(-0.08419269,-0.81571201,-1.0857893,-0.07785618,667.56845,424.75412)" + id="g5650-2-0-4-3-8-9-2" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + id="g6634"> + <path + inkscape:connector-curvature="0" + id="path20172-9-8-9-3-7" + d="m 18.652036,463.77088 c 0,0 65.81835,-170.39134 345.869384,-106.32083" + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(-0.44664484,-0.38224114,-0.38224114,0.44664484,110.28192,145.11277)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6-1-5-3-0" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <g + transform="matrix(0,-1,1,0,-443.10758,753.30201)" + id="g5650-2-0-4-3-8-9-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:1.98598707;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 530.36552,568.78955 c 0,0 -275.73145,-235.65993 -602.761737,-30.40772" + id="path20172-9-8-9-3-1" + inkscape:connector-curvature="0" /> + <path + transform="matrix(0.29887498,0.50623478,-0.50623478,0.29887498,210.13685,523.56774)" + inkscape:transform-center-y="-0.81224338" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6-1-1" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="5.134315" /> + </g> + <use + x="0" + y="0" + xlink:href="#rect5273-22" + id="use5355-0" + transform="translate(343.36129,-20.897068)" + width="744.09448" + height="1052.3622" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="171.92052" + y="216.5154" + id="text5371-4-0-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + x="171.92052" + y="216.5154" + id="tspan17171-6" + style="font-size:16px;line-height:1.25;font-family:sans-serif">cond</tspan></text> + <g + transform="matrix(0,-1,-1,0,983.2611,313.28465)" + id="g5650-2-0-4-3-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8-9" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28-4" + width="210.17955" + height="35.209244" + x="354.54559" + y="192.94588" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="459.47131" + y="216.51535" + id="text5371-2-32-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-27-8" + x="459.47131" + y="216.51535" + style="font-size:16px;line-height:1.25;font-family:sans-serif">has if-match?</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="609.12769" + y="296.02957" + id="text5371-2-391-5" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63-7" + x="609.12769" + y="296.02957" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <g + transform="translate(517.41793,13.785058)" + id="g5650-0-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-5-7" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-1-3" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28-7" + width="210.17955" + height="35.209244" + x="354.54559" + y="351.97443" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="459.47131" + y="374.91498" + id="text5371-2-32-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-27-1" + x="459.47131" + y="374.91498" + style="font-size:16px;line-height:1.25;font-family:sans-serif">method is POST/PATCH?</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="479.69171" + y="414.84009" + id="text5371-2-8-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-4" + x="479.69171" + y="414.84009" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <g + transform="translate(517.41793,490.80719)" + id="g5650-0-6-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-5-7-76" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-1-3-7" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0.34202014,-0.93969262,-0.93969262,-0.34202014,1086.6042,1290.1092)" + id="g5650-2-0-4-0-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 152.42141,615.5283 c 0,0 -73.650807,-184.33554 -245.781275,54.61093" + id="path20172-9-3-4" + inkscape:connector-curvature="0" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,178.4823,610.19901)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-0-2" + style="opacity:0.80000000000000004;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <g + transform="translate(517.41793,570.7504)" + id="g5650-2-2-2-7-5"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-62-7-7" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-9-5-8" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9" + width="210.17955" + height="35.209244" + x="354.54559" + y="908.57428" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + transform="matrix(0,1,-1,0,694.44282,904.44724)" + id="g5650-2-2-6-6"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-6-3" + d="m -57.78256,339.02801 0,65.70583" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-1-1" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9-59" + width="210.17955" + height="35.209244" + x="354.54559" + y="829.06006" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="459.47131" + y="852.62952" + id="text5371-2-74-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2" + x="459.47131" + y="852.62952" + style="font-size:16px;line-height:1.25;font-family:sans-serif">method is POST?</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1" + width="218.52127" + height="34.993004" + x="350.37473" + y="272.56824" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="459.97131" + y="294.47879" + id="text5371-43" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3" + x="459.97131" + y="294.47879" + style="font-size:16px;line-height:1.25;font-family:sans-serif">412 precondition failed</tspan></text> + <g + transform="translate(2.6196148,3.2328831)" + id="g5650-2-2-6"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-6" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-1" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,1,-1,0,694.2803,507.19416)" + id="g5650-0-6-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-5-7-7" + d="m -57.78256,340.48769 0,63.05283" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-1-3-1" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(517.41793,93.25206)" + id="g5650-2-2-2"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-62" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-9" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28-7-6" + width="210.17955" + height="35.209244" + x="354.54559" + y="431.48868" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="459.63538" + y="453.2847" + id="text5371-2-32-8-5" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-27-1-2" + x="459.63538" + y="453.2847" + style="font-size:16px;line-height:1.25;font-family:sans-serif">previously_existed</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-5-5" + width="218.52127" + height="34.993004" + x="62.374733" + y="590.76849" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + transform="translate(229.41793,173.2314)" + id="g5650-2-2-2-7"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-62-7" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-9-5" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="171.97131" + y="614.22986" + id="text5371-43-2-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-9-74" + x="171.97131" + y="614.22986" + style="font-size:16px;line-height:1.25;font-family:sans-serif">404 not found</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="296.84631" + y="433.29703" + id="text5371-2-8-9-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-4-8" + x="296.84631" + y="433.29703" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <g + transform="translate(516.00372,173.10383)" + id="g5650-2-2-17-8"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-0-3" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-45-2" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,-1,0,983.3517,631.45158)" + id="g5650-2-0-4-3-8-0-3-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8-9-31-8-9" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6-3-6-5" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="500.12921" + y="574.2605" + id="text5371-4-4-9-3-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-2-8" + x="500.12921" + y="574.2605" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true*</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="607.7135" + y="610.86951" + id="text5371-2-391-5-5-1-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63-7-9-9-5" + x="607.7135" + y="610.86951" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-5-9-29" + width="218.52127" + height="34.993004" + x="350.37473" + y="590.76849" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="459.26428" + y="612.67908" + id="text5371-43-2-9-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-9-7-5" + x="459.26428" + y="612.67908" + style="font-size:16px;line-height:1.25;font-family:sans-serif">301 moved permanently</tspan></text> + <g + transform="translate(517.41793,332.05687)" + id="g5650-2-2-65-2"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-5-9" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-5-9" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,-1,0,982.4019,789.6002)" + id="g5650-2-0-4-3-8-0-3-7-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8-9-31-8-1-6" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6-3-6-3-2" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9-1-4" + width="210.17955" + height="35.209244" + x="354.54559" + y="670.03149" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="459.14709" + y="691.82751" + id="text5371-2-74-0-7-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2-8-9" + x="459.14709" + y="691.82751" + style="font-size:16px;line-height:1.25;font-family:sans-serif">moved_temporarily</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="500.12921" + y="733.21747" + id="text5371-4-4-9-3-2-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-2-6-6" + x="500.12921" + y="733.21747" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true*</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="607.7135" + y="769.89801" + id="text5371-2-391-5-5-1-0-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63-7-9-9-2-8" + x="607.7135" + y="769.89801" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-5-9-2-1" + width="218.52127" + height="34.993004" + x="350.37473" + y="749.65387" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="459.26428" + y="771.56445" + id="text5371-43-2-9-7-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-9-7-8-9" + x="459.26428" + y="771.56445" + style="font-size:16px;line-height:1.25;font-family:sans-serif">307 moved temporarily</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-5-9-2-4-1" + width="218.52127" + height="34.993004" + x="495.25732" + y="1220.3925" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="604.32263" + y="1242.303" + id="text5371-43-2-9-7-3-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-9-7-8-7-5" + x="604.32263" + y="1242.303" + style="font-size:16px;line-height:1.25;font-family:sans-serif">400 bad request</tspan></text> + <g + transform="matrix(-0.34202014,-0.93969262,0.93969262,-0.34202014,-311.11659,1246.6148)" + id="g5650-2-0-4-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 251.64748,501.65559 c 0,0 -132.95279,-198.6035 -335.041098,15.43198" + id="path20172-9-3" + inkscape:connector-curvature="0" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,190.22636,455.7026)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-0" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="120.08566" + y="891.92566" + id="text5371-2-8-9-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-4-5" + x="120.08566" + y="891.92566" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <g + transform="matrix(0,-1,-1,0,699.22962,550.33236)" + id="g5650-2-0-4-5" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-1" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-5" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9-1-3" + width="210.17955" + height="35.209244" + x="66.545593" + y="511.00293" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="167.39459" + y="532.79895" + id="text5371-2-74-0-7-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2-8-94" + x="167.39459" + y="532.79895" + style="font-size:16px;line-height:1.25;font-family:sans-serif">allow_missing_post</tspan></text> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9-5" + width="210.17955" + height="35.209244" + x="66.545593" + y="431.80698" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="175.2144" + y="455.37643" + id="text5371-2-74-0-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2-6" + x="175.2144" + y="455.37643" + style="font-size:16px;line-height:1.25;font-family:sans-serif">method is POST?</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="459.35022" + y="930.3703" + id="text5371-2-74-0-7-1-5" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2-8-94-5" + x="459.35022" + y="930.3703" + style="font-size:16px;line-height:1.25;font-family:sans-serif">allow_missing_post</tspan></text> + <g + transform="translate(229.41793,490.95885)" + id="g5650-0-6-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-5-7-2" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-1-3-14" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9-19" + width="210.17955" + height="35.209244" + x="66.545593" + y="829.06006" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="166.63885" + y="852.62952" + id="text5371-2-74-0-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2-7" + x="166.63885" + y="852.62952" + style="font-size:16px;line-height:1.25;font-family:sans-serif">method is PUT?</tspan></text> + <g + transform="translate(229.41793,571.07045)" + id="g5650-2-2-65-9"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-5-1" + d="m -57.78256,343.20394 0,61.59661" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-5-3" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(-0.34202014,-0.93969262,-0.93969262,0.34202014,702.18987,886.11239)" + id="g5650-2-0-4-05" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2.19573760000000018;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 96.51476,423.00572 c 0,0 -72.55269,-41.6703 -192.585744,26.04761" + id="path20172-9-9" + inkscape:connector-curvature="0" /> + <path + transform="matrix(0.20642765,0.55044303,-0.55044303,0.20642765,176.90073,487.11794)" + inkscape:transform-center-y="2.5699832" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-6" + style="opacity:0.80000000000000004;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="6.2547481" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9-1-8" + width="210.17955" + height="35.209244" + x="66.545593" + y="908.57428" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="166.24431" + y="930.3703" + id="text5371-2-74-0-7-15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2-8-2" + x="166.24431" + y="930.3703" + style="font-size:16px;line-height:1.25;font-family:sans-serif">is_conflict</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="136.52316" + y="971.55994" + id="text5371-4-4-9-3-2-08" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-2-6-0" + x="136.52316" + y="971.55994" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-5-9-2-7" + width="218.52127" + height="34.993004" + x="62.374733" + y="988.43671" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="171.44006" + y="1011.8981" + id="text5371-43-2-9-7-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-9-7-8-0" + x="171.44006" + y="1011.8981" + style="font-size:16px;line-height:1.25;font-family:sans-serif">409 conflict</tspan></text> + <g + transform="translate(370.63925,803.79161)" + id="g5650-93-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-3-0" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-4-9" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9-1-40" + width="210.17955" + height="35.209244" + x="207.76691" + y="1142.3002" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="313.14185" + y="1164.0962" + id="text5371-2-74-0-7-41" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2-8-3" + x="313.14185" + y="1164.0962" + style="font-size:16px;line-height:1.25;font-family:sans-serif">content_types_accepted</tspan></text> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-4-9" + width="210.17955" + height="35.209244" + x="207.76691" + y="1220.5249" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="313.21997" + y="1242.2975" + id="text5371-2-3-0-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7-3-1" + x="313.21997" + y="1242.2975" + style="font-size:16px;line-height:1.25;font-family:sans-serif">AcceptCallback</tspan></text> + <g + transform="translate(233.45629,961.91953)" + id="g5650-6-4-8-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78-5-5-2" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9-6-6-6" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-345.93614,1498.2457)" + id="g5650-2-0-4-8-9-6-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 169.94368,422.8286 c 0,0 -94.23585,-64.78987 -206.003937,-8.35999" + id="path20172-9-5-2-6-6" + inkscape:connector-curvature="0" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-2-8-7-6" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9-19-2" + width="210.17955" + height="35.209244" + x="70.583946" + y="1300.3734" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="175.50966" + y="1323.8022" + id="text5371-2-74-0-1-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2-7-4" + x="175.50966" + y="1323.8022" + style="font-size:16px;line-height:1.25;font-family:sans-serif">new resource?</tspan></text> + <g + transform="translate(517.41793,962.60627)" + id="g5650-6-4-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78-5-5" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9-6-6" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,-1,0,985.5699,1417.4167)" + id="g5650-2-0-4-8-9-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-5-2-6" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-2-8-7" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9-19-2-1" + width="210.17955" + height="35.209244" + x="354.54559" + y="1300.3734" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="459.47131" + y="1323.8022" + id="text5371-2-74-0-1-3-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2-7-4-8" + x="459.47131" + y="1323.8022" + style="font-size:16px;line-height:1.25;font-family:sans-serif">new resource?</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-8-7" + width="218.52127" + height="34.993004" + x="350.37473" + y="1380.1163" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="459.776" + y="1403.5779" + id="text5371-43-3-2" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-1-9" + x="459.776" + y="1403.5779" + style="font-size:16px;line-height:1.25;font-family:sans-serif">201 created</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-8-7-4" + width="218.52127" + height="34.993004" + x="350.37473" + y="1459.7511" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="459.03381" + y="1483.2128" + id="text5371-43-3-2-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-1-9-2" + x="459.03381" + y="1483.2128" + style="font-size:16px;line-height:1.25;font-family:sans-serif">303 see other</tspan></text> + <g + transform="matrix(0,1,1,0,-67.245042,1455.155)" + id="g5650-2-2-6-6-7-9-1"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-6-3-8-5-9" + d="m -57.78256,339.02801 0,65.70583" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-1-1-7-6-3" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(233.45629,1121.5376)" + id="g5650-6-4-8-7-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78-5-5-2-8" + d="m -57.78256,294.4515 0,109.76214" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9-6-6-6-7" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9-19-2-2" + width="210.17955" + height="35.209244" + x="70.583946" + y="1379.7678" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="175.50966" + y="1401.7865" + id="text5371-2-74-0-1-3-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2-7-4-9" + x="175.50966" + y="1401.7865" + style="font-size:16px;line-height:1.25;font-family:sans-serif">has resp location?</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-8-7-4-7" + width="218.52127" + height="34.993004" + x="62.374733" + y="1619.0205" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + transform="translate(233.45629,1201.4108)" + id="g5650-6-4-8-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78-5-5-3" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9-6-6-3" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,1,1,0,-63.162935,1614.665)" + id="g5650-2-2-6-6-7-9"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-6-3-8-5" + d="m -57.78256,339.02801 0,65.70583" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-1-1-7-6" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9-19-2-2-4" + width="210.17955" + height="35.209244" + x="70.583946" + y="1539.2778" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="175.50966" + y="1561.2965" + id="text5371-2-74-0-1-3-7-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2-7-4-9-5" + x="175.50966" + y="1561.2965" + style="font-size:16px;line-height:1.25;font-family:sans-serif">has resp body?</tspan></text> + <g + transform="translate(517.41793,1201.395)" + id="g5650-6-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-78-5" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9-6" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,-1,0,987.64405,1658.4266)" + id="g5650-2-0-4-8-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-5-2" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-2-8" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-87-8" + width="210.17955" + height="35.209244" + x="354.54559" + y="1539.2778" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="459.30334" + y="1561.0739" + id="text5371-2-9-6" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-8-6" + x="459.30334" + y="1561.0739" + style="font-size:16px;line-height:1.25;font-family:sans-serif">multiple_choices</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="479.75421" + y="1602.6646" + id="text5371-2-8-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-7" + x="479.75421" + y="1602.6646" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-1-0" + width="218.52127" + height="34.993004" + x="350.37473" + y="1698.6555" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="459.42053" + y="1720.566" + id="text5371-43-5-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-62-9" + x="459.42053" + y="1720.566" + style="font-size:16px;line-height:1.25;font-family:sans-serif">300 multiple choices</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-8-3" + width="218.52127" + height="34.993004" + x="350.37473" + y="1619.0208" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="458.88538" + y="1642.3412" + id="text5371-43-3-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-1-3" + x="458.88538" + y="1642.3412" + style="font-size:16px;line-height:1.25;font-family:sans-serif">200 OK</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="171.24475" + y="1642.3412" + id="text5371-43-3-2-6-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-1-9-2-0" + x="171.24475" + y="1642.3412" + style="font-size:16px;line-height:1.25;font-family:sans-serif">204 no content</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="479.69171" + y="891.92566" + id="text5371-2-8-9-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-4-1" + x="479.69171" + y="891.92566" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <g + id="g5650-4-8" + transform="matrix(0.5,0.8660254,-0.8660254,0.5,204.7918,279.30499)"> + <path + inkscape:connector-curvature="0" + id="path5570-8-7" + d="m -58.01975,316.62647 0,86.23385" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,72.919441,161.77521)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-3-4" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="496.12921" + y="494.3544" + id="text5371-4-4-9-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-8" + x="496.12921" + y="494.3544" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8-9-1-3-4-8" + width="210.17955" + height="35.209244" + x="354.54559" + y="511.00293" + rx="15" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none" + x="459.14709" + y="532.79895" + id="text5371-2-74-0-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-18-2-9" + x="459.14709" + y="532.79895" + style="font-size:16px;line-height:1.25;font-family:sans-serif">moved_permanently</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:2.73499846;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1-8-7-9" + width="218.52127" + height="34.993004" + x="350.37473" + y="988.43671" + rx="12.372616" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none" + x="459.67053" + y="1010.2067" + id="text5371-43-3-2-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-3-1-9-5" + x="459.67053" + y="1010.2067" + style="font-size:16px;line-height:1.25;font-family:sans-serif">410 gone</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="260.04547" + y="494.97446" + id="text5371-4-4-9-1-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-8-2" + x="260.04547" + y="494.97446" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="120.08566" + y="494.51349" + id="text5371-2-8-9-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-4-55" + x="120.08566" + y="494.51349" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="133.92941" + y="574.40112" + id="text5371-4-4-9-1-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-8-0" + x="133.92941" + y="574.40112" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="315.87756" + y="828.86047" + id="text5371-4-4-9-1-1-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-8-0-1" + x="315.87756" + y="828.86047" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="498.78546" + y="972.02087" + id="text5371-4-4-9-1-1-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-8-0-2" + x="498.78546" + y="972.02087" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="458.9295" + y="1217.7582" + id="text5371-4-4-9-1-1-9-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-8-0-1-2" + x="458.9295" + y="1217.7582" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <g + transform="matrix(0,1,1,0,77.85132,1295.6715)" + id="g5650-2-2-6-6-7"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1-6-3-8" + d="m -57.78256,339.02801 0,65.70583" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-5-1-1-7" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="207.75119" + y="1283.5576" + id="text5371-2-391-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63-4" + x="207.75119" + y="1283.5576" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <g + transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,501.47379,1045.323)" + id="g5650-9-9-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-7-6-1" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-09-5-4" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#6d8e41;fill-opacity:1;stroke:none" + x="419.81369" + y="1283.0615" + id="text5371-2-391-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + x="419.81369" + y="1283.0615" + id="tspan5794" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true, URI*</tspan></text> + <g + transform="matrix(-0.70710678,0.70710678,0.70710678,0.70710678,124.04665,1045.323)" + id="g5650-9-9-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + inkscape:connector-curvature="0" + id="path5570-7-6-8" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-09-5-45" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="479.69171" + y="1363.2994" + id="text5371-2-8-4-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-7-5" + x="479.69171" + y="1363.2994" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="626.74475" + y="1403.5779" + id="text5371-4-4-9-1-1-9-1-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-8-0-1-2-0" + x="626.74475" + y="1403.5779" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="624.0885" + y="1642.0209" + id="text5371-4-4-9-1-1-9-1-0" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-8-0-1-2-3" + x="624.0885" + y="1642.0209" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="317.91525" + y="1538.8624" + id="text5371-4-4-9-1-1-9-1-2" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-8-0-1-2-1" + x="317.91525" + y="1538.8624" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="190.83659" + y="1602.2036" + id="text5371-2-8-4-3-9" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-7-5-9" + x="190.83659" + y="1602.2036" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="190.83659" + y="1363.1792" + id="text5371-2-8-4-3-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-7-5-0" + x="190.83659" + y="1363.1792" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="7.9966321" + y="1443.395" + id="text5371-4-4-9-1-1-9-1-4-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-8-0-1-2-0-6" + x="7.9966321" + y="1443.395" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="317.86548" + y="1379.0562" + id="text5371-4-4-9-1-1-9-1-2-2" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-8-0-1-2-1-5" + x="317.86548" + y="1379.0562" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="190.83659" + y="1482.6313" + id="text5371-2-8-4-3-8-7" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-7-5-0-8" + x="190.83659" + y="1482.6313" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="85.095001" + y="891.92566" + id="text5371-4-4-9-1-4-2" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-2-6-8-2-9" + x="85.095001" + y="891.92566" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="232.21094" + y="971.55994" + id="text5371-2-391-5-5-1-0-7-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-63-7-9-9-2-8-8" + x="232.21094" + y="971.55994" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <g + transform="matrix(0,-1,1,0,-359.02432,626.75367)" + id="g5650-2-0-4-3-8-9-4" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <g + id="g6614"> + <g + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + id="g5650-2-0-4-3-8-9" + transform="matrix(0,-1,-1,0,347.00351,567.35686)"> + <path + inkscape:transform-center-x="-3.1059024" + sodipodi:type="star" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="path5576-12-1-7-58-6-1-4" + sodipodi:sides="3" + sodipodi:cx="-222.73865" + sodipodi:cy="415.25897" + sodipodi:r1="14.849242" + sodipodi:r2="7.4246211" + sodipodi:arg1="1.5707963" + sodipodi:arg2="2.6179939" + inkscape:flatsided="true" + inkscape:rounded="0" + inkscape:randomized="0" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:transform-center-y="6.2755376" + transform="matrix(0.10770811,0.57792634,-0.57792634,0.10770811,224.52461,390.64831)" /> + </g> + <path + transform="translate(0,-1.5472441e-4)" + inkscape:connector-curvature="0" + id="path6438" + d="M 72.831997,543.06854 C 17.500892,616.78442 35.178561,698.8088 35.178561,698.8088" + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="536.26642" + y="972.02087" + id="text5371-2-8-9-1-5" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-4-1-4" + x="536.26642" + y="972.02087" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + <g + transform="matrix(0,-1,-1,0,347.71062,566.6496)" + id="g5650-2-0-4-3-8-9-2-8" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"> + <path + style="fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m 146.3711,152.21525 c 0,0 -65.760927,60.81119 -8.48528,132.93608" + id="path20172-9-8-9-3-7-4" + inkscape:connector-curvature="0" + transform="matrix(0,1,-1,0,248.85545,276.69312)" /> + <path + transform="matrix(0.38224114,0.44664484,-0.44664484,0.38224114,233.48523,355.54168)" + inkscape:transform-center-y="-1.0388082" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1-7-58-6-1-5-3" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" + inkscape:transform-center-x="4.5299474" /> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none" + x="322.92551" + y="375.54388" + id="text5371-4-6-1" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-9-0-8" + x="322.92551" + y="375.54388" + style="font-size:16px;line-height:1.25;font-family:sans-serif">false</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none" + x="66.001251" + y="574.40112" + id="text5371-2-8-9-0-3" + inkscape:export-filename="/home/essen/ninenines/cowboy/guide/rest_options.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-3-4-55-3" + x="66.001251" + y="574.40112" + style="font-size:16px;line-height:1.25;font-family:sans-serif">true</tspan></text> + </g> +</svg> diff --git a/docs/en/cowboy/2.2/guide/rest_start.png b/docs/en/cowboy/2.2/guide/rest_start.png Binary files differnew file mode 100644 index 00000000..1f1e312e --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_start.png diff --git a/docs/en/cowboy/2.2/guide/rest_start.svg b/docs/en/cowboy/2.2/guide/rest_start.svg new file mode 100644 index 00000000..076c6195 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/rest_start.svg @@ -0,0 +1,1356 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="744.09448819" + height="1052.3622047" + id="svg2" + version="1.1" + inkscape:version="0.48.4 r9939" + sodipodi:docname="rest_start.svg" + inkscape:export-filename="/home/essen/Dropbox/Public/drawing.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs4"> + <linearGradient + id="linearGradient5265"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5267" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.58823532;" + offset="1" + id="stop5269" /> + </linearGradient> + <linearGradient + id="linearGradient5251"> + <stop + style="stop-color:#69d2e7;stop-opacity:0.78431374;" + offset="0" + id="stop5253" /> + <stop + id="stop5263" + offset="0.5" + style="stop-color:#69d2e7;stop-opacity:1;" /> + <stop + style="stop-color:#69d2e7;stop-opacity:0.39215687;" + offset="1" + id="stop5255" /> + </linearGradient> + <linearGradient + id="linearGradient5233" + osb:paint="solid"> + <stop + style="stop-color:#69d2e7;stop-opacity:1;" + offset="0" + id="stop5235" /> + </linearGradient> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="1" + inkscape:pageshadow="2" + inkscape:zoom="1.0000001" + inkscape:cx="171.11305" + inkscape:cy="549.52821" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="2560" + inkscape:window-height="1402" + inkscape:window-x="0" + inkscape:window-y="38" + inkscape:window-maximized="1" + inkscape:snap-global="true" + showguides="true"> + <inkscape:grid + type="xygrid" + id="grid5357" + empspacing="5" + visible="true" + enabled="true" + snapvisiblegridlinesonly="true" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <path + inkscape:export-ydpi="89.926643" + inkscape:export-xdpi="89.926643" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:connector-curvature="0" + id="use5777" + d="m -360.31658,371.70113 203.00246,0.045" + style="fill:none;stroke:#6d8e41;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1.99999999, 3.99999998;stroke-dashoffset:0" /> + <g + transform="translate(205.92143,-296.03137)" + id="g5650-7"> + <path + inkscape:connector-curvature="0" + id="path5570-9" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-0" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(205.92143,-212.00698)" + id="g5650-9"> + <path + inkscape:connector-curvature="0" + id="path5570-7" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-09" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(205.92143,-129.04326)" + id="g5650-0"> + <path + inkscape:connector-curvature="0" + id="path5570-5" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-1" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(205.92143,-44.866334)" + id="g5650-94"> + <path + inkscape:connector-curvature="0" + id="path5570-71" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-5" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(205.92143,38.329623)" + id="g5650-93"> + <path + inkscape:connector-curvature="0" + id="path5570-3" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-4" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(205.92143,122.59665)" + id="g5650-3"> + <path + inkscape:connector-curvature="0" + id="path5570-93" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-04" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(205.92143,206.62103)" + id="g5650-6"> + <path + inkscape:connector-curvature="0" + id="path5570-78" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-9" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(205.92143,289.59516)" + id="g5650-34"> + <path + inkscape:connector-curvature="0" + id="path5570-30" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-3" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(205.92143,373.37691)" + id="g5650-5"> + <path + inkscape:connector-curvature="0" + id="path5570-90" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-6" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="translate(205.92143,457.4117)" + id="g5650-1"> + <path + inkscape:connector-curvature="0" + id="path5570-33" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-2" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-25.673146,80.832304)" + id="g5650-2-0"> + <path + inkscape:connector-curvature="0" + id="path5570-2-5" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-1" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-25.673146,164.49956)" + id="g5650-2-6"> + <path + inkscape:connector-curvature="0" + id="path5570-2-1" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-6" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-25.673146,248.1668)" + id="g5650-2-4"> + <path + inkscape:connector-curvature="0" + id="path5570-2-0" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-7" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-25.673146,331.8341)" + id="g5650-2-04"> + <path + inkscape:connector-curvature="0" + id="path5570-2-9" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-0" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-25.673146,415.50138)" + id="g5650-2-8"> + <path + inkscape:connector-curvature="0" + id="path5570-2-50" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-2" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-25.673146,499.16862)" + id="g5650-2-1"> + <path + inkscape:connector-curvature="0" + id="path5570-2-2" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-9" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-25.673146,582.83589)" + id="g5650-2-3"> + <path + inkscape:connector-curvature="0" + id="path5570-2-10" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-60" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-25.673146,666.50315)" + id="g5650-2-44"> + <path + inkscape:connector-curvature="0" + id="path5570-2-11" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-73" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <g + transform="matrix(0,-1,1,0,-25.673146,750.17041)" + id="g5650-2-12"> + <path + inkscape:connector-curvature="0" + id="path5570-2-6" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12-04" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-28" + width="210.17955" + height="35.209244" + x="43.049091" + y="204.67757" + rx="15" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-5" + width="210.17955" + height="35.209244" + x="43.049091" + y="288.40311" + rx="15" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-8" + width="210.17955" + height="35.209244" + x="43.049091" + y="372.01199" + rx="15" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-4" + width="210.17955" + height="35.209244" + x="43.049091" + y="455.67929" + rx="15" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-87" + width="210.17955" + height="35.209244" + x="43.049091" + y="539.34656" + rx="15" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-41" + width="210.17955" + height="35.209244" + x="43.049091" + y="623.01385" + rx="15" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-7" + width="210.17955" + height="35.209244" + x="43.049091" + y="706.68115" + rx="15" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-20" + width="210.17955" + height="35.209244" + x="43.049091" + y="790.34839" + rx="15" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-3" + width="210.17955" + height="35.209244" + x="43.049091" + y="874.01562" + rx="15" /> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1" + width="210.17955" + height="35.209244" + x="43.049091" + y="121.0042" + rx="15" /> + <g + id="g5650" + transform="translate(0,-0.47597102)"> + <path + inkscape:connector-curvature="0" + id="path5570" + d="m -57.78256,351.41962 0,52.3259" + style="opacity:0.8;fill:none;stroke:#6d8e41;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576" + style="opacity:0.8;fill:#6d8e41;fill-opacity:1;fill-rule:nonzero;stroke:#6d8e41;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273" + width="104.5895" + height="36.392323" + x="-224.02068" + y="29.41218" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7" + width="104.5895" + height="36.392323" + x="-224.02068" + y="90.691978" + rx="15" /> + <rect + style="fill:#ffc48c;fill-opacity:1;fill-rule:nonzero;stroke:#d79c64;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-2" + width="104.5895" + height="36.392323" + x="-224.02068" + y="151.97169" + rx="15" /> + <rect + style="fill:#ff9f80;fill-opacity:1;fill-rule:nonzero;stroke:#d77758;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-22" + width="104.5895" + height="36.392323" + x="-224.02068" + y="213.25146" + rx="15" /> + <rect + style="fill:#f56991;fill-opacity:1;fill-rule:nonzero;stroke:#cd4169;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-8" + width="104.5895" + height="36.392323" + x="-224.02068" + y="274.53128" + rx="15" /> + <use + x="0" + y="0" + xlink:href="#rect5273-22" + id="use5355" + transform="translate(319.86479,-176.50006)" + width="744.09448" + height="1052.3622" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="114.39204" + id="text5371" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373" + x="-58.692513" + y="114.39204">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="53.112247" + id="text5371-2" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6" + x="-58.692513" + y="53.112247">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="148.18575" + y="310.19913" + id="text5371-2-3" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7" + x="148.18575" + y="310.19913">uri_too_long</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="147.60762" + y="477.47531" + id="text5371-2-3-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7-3" + x="147.60762" + y="477.47531">malformed_request</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-58.692513" + y="236.95154" + id="text5371-4" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-9" + x="-58.692513" + y="236.95154">some text</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="147.00391" + y="60.912468" + id="text5371-4-0" + sodipodi:linespacing="125%" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + x="147.00391" + y="60.912468" + id="tspan17171">init</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="148.11153" + y="561.14258" + id="text5371-2-9" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-8" + x="148.11153" + y="561.14258">is_authorized</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="148.64278" + y="646.58331" + id="text5371-2-7" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-2" + x="148.64278" + y="646.58331">forbidden</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="148.29512" + y="728.47717" + id="text5371-2-73" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-5" + x="148.29512" + y="728.47717">valid_content_headers</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="147.83809" + y="812.14441" + id="text5371-2-5" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-1" + x="147.83809" + y="812.14441">valid_entity_length</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="148.58809" + y="895.81165" + id="text5371-2-1" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-71" + x="148.58809" + y="895.81165">...</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="148.13106" + y="142.80627" + id="text5371-2-95" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-80" + x="148.13106" + y="142.80627">service_available</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="147.80684" + y="226.4736" + id="text5371-2-32" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-27" + x="147.80684" + y="226.4736">known_methods</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="148.05293" + y="393.80801" + id="text5371-2-74" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-18" + x="148.05293" + y="393.80801">allowed_methods</tspan></text> + <rect + style="fill:#d1f2a5;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-1-2" + width="210.17955" + height="35.209244" + x="-489.75586" + y="33.4944" + rx="15" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="164.26562" + y="185.95248" + id="text5371-2-391" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-63" + x="164.26562" + y="185.95248">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="164.26562" + y="269.61978" + id="text5371-2-954" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-808" + x="164.26562" + y="269.61978">known*</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="164.26562" + y="353.28702" + id="text5371-2-4" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-11" + x="164.26562" + y="353.28702">false</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="164.26562" + y="436.95425" + id="text5371-2-92" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-4" + x="164.26562" + y="436.95425">allowed*</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="164.26562" + y="520.62152" + id="text5371-2-739" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-0" + x="164.26562" + y="520.62152">false</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="164.26562" + y="604.28876" + id="text5371-2-8" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-3" + x="164.26562" + y="604.28876">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="164.26562" + y="687.95599" + id="text5371-2-0" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-01" + x="164.26562" + y="687.95599">false</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="164.26562" + y="771.62329" + id="text5371-2-2" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-33" + x="164.26562" + y="771.62329">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="164.26562" + y="855.29053" + id="text5371-2-21" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-6-9" + x="164.26562" + y="855.29053">true</tspan></text> + <g + transform="matrix(0,-1,1,0,-513.31414,353.05561)" + id="g5650-2"> + <path + inkscape:connector-curvature="0" + id="path5570-2" + d="m -57.78256,275.13761 0,129.13992" + style="opacity:0.8;fill:none;stroke:#9b3b1c;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + transform="matrix(0.58787746,0,0,0.58787746,73.160466,163.35774)" + inkscape:transform-center-y="2.1823437" + d="m -222.73865,430.10821 -12.85982,-22.27386 25.71964,0 z" + inkscape:randomized="0" + inkscape:rounded="0" + inkscape:flatsided="true" + sodipodi:arg2="2.6179939" + sodipodi:arg1="1.5707963" + sodipodi:r2="7.4246211" + sodipodi:r1="14.849242" + sodipodi:cy="415.25897" + sodipodi:cx="-222.73865" + sodipodi:sides="3" + id="path5576-12" + style="opacity:0.8;fill:#9b3b1c;fill-opacity:1;fill-rule:nonzero;stroke:#9b3b1c;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + sodipodi:type="star" /> + </g> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="315.26172" + y="123.86062" + id="text5371-4-6" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-9-0" + x="315.26172" + y="123.86062">false</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="315.26172" + y="207.30568" + id="text5371-4-7" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-9-6" + x="315.26172" + y="207.30568">unknown*</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="315.26172" + y="290.75076" + id="text5371-4-2" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-9-01" + x="315.26172" + y="290.75076">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="315.26172" + y="374.19577" + id="text5371-4-3" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-9-62" + x="315.26172" + y="374.19577">unallowed*</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="315.26172" + y="457.64084" + id="text5371-4-4" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-9-2" + x="315.26172" + y="457.64084">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="315.26172" + y="541.08588" + id="text5371-4-5" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-9-09" + x="315.26172" + y="541.08588">false*</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="315.26172" + y="624.53094" + id="text5371-4-61" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-9-69" + x="315.26172" + y="624.53094">true</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="315.26172" + y="707.97595" + id="text5371-4-58" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-9-5" + x="315.26172" + y="707.97595">false</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#9b3b1c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="315.26172" + y="791.42102" + id="text5371-4-54" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-9-012" + x="315.26172" + y="791.42102">false</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3" + width="264.92532" + height="34.728001" + x="392.03732" + y="121.24477" + rx="15" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="524.53516" + y="143.02283" + id="text5371-6" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + x="524.53516" + y="143.02283" + id="tspan18994">503 service unavailable</tspan></text> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-9" + width="264.92532" + height="34.728001" + x="392.03732" + y="204.93674" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-6" + width="264.92532" + height="34.728001" + x="392.03732" + y="288.62869" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-1" + width="264.92532" + height="34.728001" + x="392.03732" + y="372.32065" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-90" + width="264.92532" + height="34.728001" + x="392.03732" + y="456.01254" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-2" + width="264.92532" + height="34.728001" + x="392.03732" + y="539.70447" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-3" + width="264.92532" + height="34.728001" + x="392.03732" + y="623.39642" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-39" + width="264.92532" + height="34.728001" + x="392.03732" + y="707.08838" + rx="15" /> + <rect + style="fill:#effab4;fill-opacity:1;fill-rule:nonzero;stroke:#c7d28c;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5273-7-3-5" + width="264.92532" + height="34.728001" + x="392.03732" + y="790.78027" + rx="15" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="524.26172" + y="227.80464" + id="text5371-7" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-69" + x="524.26172" + y="227.80464">501 not implemented</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="524.26172" + y="311.49661" + id="text5371-9" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-5" + x="524.26172" + y="311.49661">414 request URI too long</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="524.26172" + y="395.18857" + id="text5371-43" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-3" + x="524.26172" + y="395.18857">405 method not allowed</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="524.26172" + y="478.88046" + id="text5371-3" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-67" + x="524.26172" + y="478.88046">400 bad request</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="524.26172" + y="562.57239" + id="text5371-1" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-53" + x="524.26172" + y="562.57239">401 unauthorized</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="524.26172" + y="646.26434" + id="text5371-27" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-64" + x="524.26172" + y="646.26434">403 forbidden</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="524.26172" + y="729.9563" + id="text5371-21" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-58" + x="524.26172" + y="729.9563">501 not implemented</tspan></text> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#77823c;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="524.26172" + y="813.64819" + id="text5371-5" + sodipodi:linespacing="125%"><tspan + sodipodi:role="line" + id="tspan5373-60" + x="524.26172" + y="813.64819">413 request entity too large</tspan></text> + <rect + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#a9ca7d;stroke-width:2.44279909;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" + id="rect5367" + width="207.05719" + height="171.55719" + x="-373.52859" + y="458.58362" + rx="11.072577" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643" /> + <text + xml:space="preserve" + style="font-size:16px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#6d8e41;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans" + x="-544.69421" + y="-354.17184" + id="text5371-2-3-0-7" + sodipodi:linespacing="125%" + transform="matrix(0,-1,1,0,0,0)" + inkscape:export-filename="/home/essen/extend/cowboy/guide/http_req_resp.png" + inkscape:export-xdpi="89.926643" + inkscape:export-ydpi="89.926643"><tspan + sodipodi:role="line" + id="tspan5373-6-7-3-9" + x="-544.69421" + y="-354.17184">middlewares</tspan></text> + </g> +</svg> diff --git a/docs/en/cowboy/2.2/guide/routing.asciidoc b/docs/en/cowboy/2.2/guide/routing.asciidoc new file mode 100644 index 00000000..47ef3c57 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/routing.asciidoc @@ -0,0 +1,222 @@ +[[routing]] +== Routing + +Cowboy does nothing by default. + +To make Cowboy useful, you need to map URIs to Erlang modules that will +handle the requests. This is called routing. + +When Cowboy receives a request, it tries to match the requested host and +path to the configured routes. When there's a match, the route's +associated handler is executed. + +Routes need to be compiled before they can be used by Cowboy. +The result of the compilation is the dispatch rules. + +=== Syntax + +The general structure for the routes is defined as follow. + +[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. + +[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. + +[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 its initial state. + +[source,erlang] +Path1 = {PathMatch, Handler, InitialState}. +Path2 = {PathMatch, Constraints, Handler, InitialState}. + +Continue reading to learn more about the match syntax and the optional +constraints. + +=== Match syntax + +The match syntax is used to associate host names and paths with their +respective handlers. + +The match syntax is the same for host and path with a few subtleties. +Indeed, the segments separator is different, and the host is matched +starting from the last segment going to the first. All examples will +feature both host and path match rules and explain the differences +when encountered. + +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()`. + +[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. + +[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. + +[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 +values bindings. + +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. + +[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 +segment value where they were defined. For example, the URL +`http://test.example.org/hats/wild_cowboy_legendary/prices` will +result in having the value `test` bound to the name `subdomain` +and the value `wild_cowboy_legendary` bound to the name `name`. +They can later be retrieved using `cowboy_req:binding/{2,3}`. The +binding name must be given as an atom. + +There is a special binding name you can use to mimic the underscore +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. + +[source,erlang] +HostMatch = "ninenines.:_". + +Similarly, it is possible to have optional segments. Anything +between brackets is optional. + +[source,erlang] +PathMatch = "/hats/[page/:number]". +HostMatch = "[www.]ninenines.eu". + +You can also have imbricated optional segments. + +[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 +of paths anything after the previously matched segments. It is +a special case of optional segments, in that it can have +zero, one or many segments. 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. + +[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. + +[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. + +[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. + +[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. + +[source,erlang] +PathMatch = '_'. +HostMatch = '_'. + +The second is the special host match `"*"` which will match the +wildcard path, generally used alongside the `OPTIONS` method. + +[source,erlang] +HostMatch = "*". + +=== Constraints + +After the matching has completed, the resulting bindings can be tested +against a set of constraints. Constraints are only tested when the +binding is defined. They run in the order you defined them. The match +will succeed only if they all succeed. If the match fails, then Cowboy +tries the next route in the list. + +The format used for constraints is the same as match functions in +`cowboy_req`: they are provided as a list of fields which may have +one or more constraints. While the router accepts the same format, +it will skip fields with no constraints and will also ignore default +values, if any. + +Read more about xref:constraints[constraints]. + +=== Compilation + +The routes must be compiled before Cowboy can use them. The compilation +step normalizes the routes to simplify the code and speed up the +execution, but the routes are still looked up one by one in the end. +Faster compilation strategies could be to compile the routes directly +to Erlang code, but would require heavier dependencies. + +To compile routes, just call the appropriate function: + +[source,erlang] +---- +Dispatch = cowboy_router:compile([ + %% {HostMatch, list({PathMatch, Handler, InitialState})} + {'_', [{'_', my_handler, #{}}]} +]), +%% Name, NbAcceptors, TransOpts, ProtoOpts +cowboy:start_clear(my_http_listener, + [{port, 8080}], + #{env => #{dispatch => Dispatch}} +). +---- + +=== 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: + +[source,erlang] +Dispatch = cowboy_router:compile(Routes), +cowboy:set_env(my_http_listener, dispatch, Dispatch). + +Note that you need to compile the routes again before updating. diff --git a/docs/en/cowboy/2.2/guide/routing/index.html b/docs/en/cowboy/2.2/guide/routing/index.html new file mode 100644 index 00000000..1e1aad39 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/routing/index.html @@ -0,0 +1,420 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Routing</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Routing</span></h1> + +<div class="paragraph"><p>Cowboy does nothing by default.</p></div> +<div class="paragraph"><p>To make Cowboy useful, you need to map URIs to Erlang modules that will +handle the requests. This is called routing.</p></div> +<div class="paragraph"><p>When Cowboy receives a request, it tries to match the requested host and +path to the configured routes. When there’s a match, the route’s +associated handler is executed.</p></div> +<div class="paragraph"><p>Routes need to be compiled before they can be used by Cowboy. +The result of the compilation is the dispatch rules.</p></div> +<div class="sect1"> +<h2 id="_syntax">Syntax</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The general structure for the routes is defined as follow.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Routes</span> <span style="color: #990000">=</span> [<span style="color: #009900">Host1</span>, <span style="color: #009900">Host2</span>, <span style="color: #990000">...</span> <span style="color: #009900">HostN</span>]<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Each host contains matching rules for the host along with optional +constraints, and a list of routes for the path component.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Host1</span> <span style="color: #990000">=</span> {<span style="color: #009900">HostMatch</span>, <span style="color: #009900">PathsList</span>}<span style="color: #990000">.</span> +<span style="color: #009900">Host2</span> <span style="color: #990000">=</span> {<span style="color: #009900">HostMatch</span>, <span style="color: #009900">Constraints</span>, <span style="color: #009900">PathsList</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>The list of routes for the path component is defined similar to the +list of hosts.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">PathsList</span> <span style="color: #990000">=</span> [<span style="color: #009900">Path1</span>, <span style="color: #009900">Path2</span>, <span style="color: #990000">...</span> <span style="color: #009900">PathN</span>]<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Finally, each path contains matching rules for the path along with +optional constraints, and gives us the handler module to be used +along with its initial state.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Path1</span> <span style="color: #990000">=</span> {<span style="color: #009900">PathMatch</span>, <span style="color: #009900">Handler</span>, <span style="color: #009900">InitialState</span>}<span style="color: #990000">.</span> +<span style="color: #009900">Path2</span> <span style="color: #990000">=</span> {<span style="color: #009900">PathMatch</span>, <span style="color: #009900">Constraints</span>, <span style="color: #009900">Handler</span>, <span style="color: #009900">InitialState</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Continue reading to learn more about the match syntax and the optional +constraints.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_match_syntax">Match syntax</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The match syntax is used to associate host names and paths with their +respective handlers.</p></div> +<div class="paragraph"><p>The match syntax is the same for host and path with a few subtleties. +Indeed, the segments separator is different, and the host is matched +starting from the last segment going to the first. All examples will +feature both host and path match rules and explain the differences +when encountered.</p></div> +<div class="paragraph"><p>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 <code>string()</code> or a <code>binary()</code>.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">PathMatch1</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"/"</span><span style="color: #990000">.</span> +<span style="color: #009900">PathMatch2</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"/path/to/resource"</span><span style="color: #990000">.</span> + +<span style="color: #009900">HostMatch1</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"cowboy.example.org"</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>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.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">PathMatch2</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"/path/to/resource"</span><span style="color: #990000">.</span> +<span style="color: #009900">PathMatch3</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"/path/to/resource/"</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Hosts with and without a trailing dot are equivalent for routing. +Similarly, hosts with and without a leading dot are also equivalent.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">HostMatch1</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"cowboy.example.org"</span><span style="color: #990000">.</span> +<span style="color: #009900">HostMatch2</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"cowboy.example.org."</span><span style="color: #990000">.</span> +<span style="color: #009900">HostMatch3</span> <span style="color: #990000">=</span> <span style="color: #FF0000">".cowboy.example.org"</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>It is possible to extract segments of the host and path and to store +the values in the <code>Req</code> object for later use. We call these kind of +values bindings.</p></div> +<div class="paragraph"><p>The syntax for bindings is very simple. A segment that begins with +the <code>:</code> 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.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">PathMatch</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"/hats/:name/prices"</span><span style="color: #990000">.</span> +<span style="color: #009900">HostMatch</span> <span style="color: #990000">=</span> <span style="color: #FF0000">":subdomain.example.org"</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>If these two end up matching when routing, you will end up with two +bindings defined, <code>subdomain</code> and <code>name</code>, each containing the +segment value where they were defined. For example, the URL +<code>http://test.example.org/hats/wild_cowboy_legendary/prices</code> will +result in having the value <code>test</code> bound to the name <code>subdomain</code> +and the value <code>wild_cowboy_legendary</code> bound to the name <code>name</code>. +They can later be retrieved using <code>cowboy_req:binding/{2,3}</code>. The +binding name must be given as an atom.</p></div> +<div class="paragraph"><p>There is a special binding name you can use to mimic the underscore +variable in Erlang. Any match against the <code>_</code> binding will succeed +but the data will be discarded. This is especially useful for +matching against many domain names in one go.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">HostMatch</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"ninenines.:_"</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Similarly, it is possible to have optional segments. Anything +between brackets is optional.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">PathMatch</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"/hats/[page/:number]"</span><span style="color: #990000">.</span> +<span style="color: #009900">HostMatch</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"[www.]ninenines.eu"</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>You can also have imbricated optional segments.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">PathMatch</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"/hats/[page/[:number]]"</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>You can retrieve the rest of the host or path using <code>[...]</code>. +In the case of hosts it will match anything before, in the case +of paths anything after the previously matched segments. It is +a special case of optional segments, in that it can have +zero, one or many segments. You can then find the segments using +<code>cowboy_req:host_info/1</code> and <code>cowboy_req:path_info/1</code> respectively. +They will be represented as a list of segments.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">PathMatch</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"/hats/[...]"</span><span style="color: #990000">.</span> +<span style="color: #009900">HostMatch</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"[...]ninenines.eu"</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>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.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">PathMatch</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"/hats/:name/:name"</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>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.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">PathMatch</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"/hats/:name/[:name]"</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>If a binding is defined in both the host and path, then they must +also share the same value.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">PathMatch</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"/:user/[...]"</span><span style="color: #990000">.</span> +<span style="color: #009900">HostMatch</span> <span style="color: #990000">=</span> <span style="color: #FF0000">":user.github.com"</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Finally, there are two special match values that can be used. The +first is the atom <code>'_'</code> which will match any host or path.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">PathMatch</span> <span style="color: #990000">=</span> <span style="color: #FF6600">'_'</span><span style="color: #990000">.</span> +<span style="color: #009900">HostMatch</span> <span style="color: #990000">=</span> <span style="color: #FF6600">'_'</span><span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>The second is the special host match <code>"*"</code> which will match the +wildcard path, generally used alongside the <code>OPTIONS</code> method.</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">HostMatch</span> <span style="color: #990000">=</span> <span style="color: #FF0000">"*"</span><span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_constraints">Constraints</h2> +<div class="sectionbody"> +<div class="paragraph"><p>After the matching has completed, the resulting bindings can be tested +against a set of constraints. Constraints are only tested when the +binding is defined. They run in the order you defined them. The match +will succeed only if they all succeed. If the match fails, then Cowboy +tries the next route in the list.</p></div> +<div class="paragraph"><p>The format used for constraints is the same as match functions in +<code>cowboy_req</code>: they are provided as a list of fields which may have +one or more constraints. While the router accepts the same format, +it will skip fields with no constraints and will also ignore default +values, if any.</p></div> +<div class="paragraph"><p>Read more about <a href="../constraints">constraints</a>.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_compilation">Compilation</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The routes must be compiled before Cowboy can use them. The compilation +step normalizes the routes to simplify the code and speed up the +execution, but the routes are still looked up one by one in the end. +Faster compilation strategies could be to compile the routes directly +to Erlang code, but would require heavier dependencies.</p></div> +<div class="paragraph"><p>To compile routes, just call the appropriate function:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Dispatch</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_router:compile</span></span>([ + <span style="font-style: italic"><span style="color: #9A1900">%% {HostMatch, list({PathMatch, Handler, InitialState})}</span></span> + {<span style="color: #FF6600">'_'</span>, [{<span style="color: #FF6600">'_'</span>, <span style="color: #FF6600">my_handler</span>, #{}}]} +]), +<span style="font-style: italic"><span style="color: #9A1900">%% Name, NbAcceptors, TransOpts, ProtoOpts</span></span> +<span style="font-weight: bold"><span style="color: #000000">cowboy:start_clear</span></span>(<span style="color: #FF6600">my_http_listener</span>, + [{<span style="color: #FF6600">port</span>, <span style="color: #993399">8080</span>}], + #{<span style="color: #0000FF">env</span> <span style="color: #990000">=></span> #{<span style="color: #0000FF">dispatch</span> <span style="color: #990000">=></span> <span style="color: #009900">Dispatch</span>}} +)<span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_live_update">Live update</h2> +<div class="sectionbody"> +<div class="paragraph"><p>You can use the <code>cowboy:set_env/3</code> function for updating the dispatch +list used by routing. This will apply to all new connections accepted +by the listener:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="color: #009900">Dispatch</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_router:compile</span></span>(<span style="color: #009900">Routes</span>), +<span style="font-weight: bold"><span style="color: #000000">cowboy:set_env</span></span>(<span style="color: #FF6600">my_http_listener</span>, <span style="color: #FF6600">dispatch</span>, <span style="color: #009900">Dispatch</span>)<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Note that you need to compile the routes again before updating.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/listeners/"> + Listeners + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/constraints/"> + Constraints + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/specs.asciidoc b/docs/en/cowboy/2.2/guide/specs.asciidoc new file mode 100644 index 00000000..ec101fbd --- /dev/null +++ b/docs/en/cowboy/2.2/guide/specs.asciidoc @@ -0,0 +1,189 @@ +[appendix] +== HTTP and other specifications + +This chapter intends to list all the specification documents +for or related to HTTP. + +=== HTTP + +==== IANA Registries + +* https://www.iana.org/assignments/http-methods/http-methods.xhtml[HTTP Method Registry] +* https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml[HTTP Status Code Registry] +* https://www.iana.org/assignments/message-headers/message-headers.xhtml[Message Headers] +* https://www.iana.org/assignments/http-parameters/http-parameters.xhtml[HTTP Parameters] +* https://www.iana.org/assignments/http-alt-svc-parameters/http-alt-svc-parameters.xhtml[HTTP Alt-Svc Parameter Registry] +* https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml[HTTP Authentication Scheme Registry] +* https://www.iana.org/assignments/http-cache-directives/http-cache-directives.xhtml[HTTP Cache Directive Registry] +* https://www.iana.org/assignments/http-dig-alg/http-dig-alg.xhtml[HTTP Digest Algorithm Values] +* https://www.iana.org/assignments/hoba-device-identifiers/hoba-device-identifiers.xhtml[HTTP Origin-Bound Authentication Device Identifier Types] +* https://www.iana.org/assignments/http-upgrade-tokens/http-upgrade-tokens.xhtml[HTTP Upgrade Token Registry] +* https://www.iana.org/assignments/http-warn-codes/http-warn-codes.xhtml[HTTP Warn Codes] +* https://www.iana.org/assignments/http2-parameters/http2-parameters.xhtml[HTTP/2 Parameters] +* https://www.ietf.org/assignments/websocket/websocket.xml[WebSocket Protocol Registries] + +==== Current + +* http://www.w3.org/TR/cors/[CORS]: Cross-Origin Resource Sharing +* http://www.w3.org/TR/CSP2/[CSP2]: Content Security Policy Level 2 +* http://www.w3.org/TR/tracking-dnt/[DNT]: Tracking Preference Expression (DNT) +* http://www.w3.org/TR/eventsource/[eventsource]: Server-Sent Events +* https://www.w3.org/TR/html4/interact/forms.html#h-17.13.4[Form content types]: Form content types +* https://www.w3.org/TR/preload/[Preload]: Preload +* http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm[REST]: Fielding's Dissertation +* https://tools.ietf.org/html/rfc1945[RFC 1945]: HTTP/1.0 +* https://tools.ietf.org/html/rfc1951[RFC 1951]: DEFLATE Compressed Data Format Specification version 1.3 +* https://tools.ietf.org/html/rfc1952[RFC 1952]: GZIP file format specification version 4.3 +* https://tools.ietf.org/html/rfc2046#section-5.1[RFC 2046]: Multipart media type (in MIME Part Two: Media Types) +* https://tools.ietf.org/html/rfc2295[RFC 2295]: Transparent Content Negotiation in HTTP +* https://tools.ietf.org/html/rfc2296[RFC 2296]: HTTP Remote Variant Selection Algorithm: RVSA/1.0 +* https://tools.ietf.org/html/rfc2817[RFC 2817]: Upgrading to TLS Within HTTP/1.1 +* https://tools.ietf.org/html/rfc2818[RFC 2818]: HTTP Over TLS +* https://tools.ietf.org/html/rfc3230[RFC 3230]: Instance Digests in HTTP +* https://tools.ietf.org/html/rfc4559[RFC 4559]: SPNEGO-based Kerberos and NTLM HTTP Authentication in Microsoft Windows +* https://tools.ietf.org/html/rfc5789[RFC 5789]: PATCH Method for HTTP +* https://tools.ietf.org/html/rfc5843[RFC 5843]: Additional Hash Algorithms for HTTP Instance Digests +* https://tools.ietf.org/html/rfc5861[RFC 5861]: HTTP Cache-Control Extensions for Stale Content +* https://tools.ietf.org/html/rfc5988[RFC 5988]: Web Linking +* https://tools.ietf.org/html/rfc6265[RFC 6265]: HTTP State Management Mechanism +* https://tools.ietf.org/html/rfc6266[RFC 6266]: Use of the Content-Disposition Header Field +* https://tools.ietf.org/html/rfc6454[RFC 6454]: The Web Origin Concept +* https://tools.ietf.org/html/rfc6455[RFC 6455]: The WebSocket Protocol +* https://tools.ietf.org/html/rfc6585[RFC 6585]: Additional HTTP Status Codes +* https://tools.ietf.org/html/rfc6750[RFC 6750]: The OAuth 2.0 Authorization Framework: Bearer Token Usage +* https://tools.ietf.org/html/rfc6797[RFC 6797]: HTTP Strict Transport Security (HSTS) +* https://tools.ietf.org/html/rfc6903[RFC 6903]: Additional Link Relation Types +* https://tools.ietf.org/html/rfc7034[RFC 7034]: HTTP Header Field X-Frame-Options +* https://tools.ietf.org/html/rfc7089[RFC 7089]: Time-Based Access to Resource States: Memento +* https://tools.ietf.org/html/rfc7230[RFC 7230]: HTTP/1.1 Message Syntax and Routing +* https://tools.ietf.org/html/rfc7231[RFC 7231]: HTTP/1.1 Semantics and Content +* https://tools.ietf.org/html/rfc7232[RFC 7232]: HTTP/1.1 Conditional Requests +* https://tools.ietf.org/html/rfc7233[RFC 7233]: HTTP/1.1 Range Requests +* https://tools.ietf.org/html/rfc7234[RFC 7234]: HTTP/1.1 Caching +* https://tools.ietf.org/html/rfc7235[RFC 7235]: HTTP/1.1 Authentication +* https://tools.ietf.org/html/rfc7239[RFC 7239]: Forwarded HTTP Extension +* https://tools.ietf.org/html/rfc7240[RFC 7240]: Prefer Header for HTTP +* https://tools.ietf.org/html/rfc7469[RFC 7469]: Public Key Pinning Extension for HTTP +* https://tools.ietf.org/html/rfc7486[RFC 7486]: HTTP Origin-Bound Authentication (HOBA) +* https://tools.ietf.org/html/rfc7538[RFC 7538]: HTTP Status Code 308 (Permanent Redirect) +* https://tools.ietf.org/html/rfc7540[RFC 7540]: Hypertext Transfer Protocol Version 2 (HTTP/2) +* https://tools.ietf.org/html/rfc7541[RFC 7541]: HPACK: Header Compression for HTTP/2 +* https://tools.ietf.org/html/rfc7578[RFC 7578]: Returning Values from Forms: multipart/form-data +* https://tools.ietf.org/html/rfc7615[RFC 7615]: HTTP Authentication-Info and Proxy-Authentication-Info Response Header Fields +* https://tools.ietf.org/html/rfc7616[RFC 7616]: HTTP Digest Access Authentication +* https://tools.ietf.org/html/rfc7617[RFC 7617]: The 'Basic' HTTP Authentication Scheme +* https://tools.ietf.org/html/rfc7639[RFC 7639]: The ALPN HTTP Header Field +* https://tools.ietf.org/html/rfc7692[RFC 7692]: Compression Extensions for WebSocket +* https://tools.ietf.org/html/rfc7694[RFC 7694]: HTTP Client-Initiated Content-Encoding +* https://tools.ietf.org/html/rfc7725[RFC 7725]: An HTTP Status Code to Report Legal Obstacles +* https://tools.ietf.org/html/rfc7804[RFC 7804]: Salted Challenge Response HTTP Authentication Mechanism +* https://tools.ietf.org/html/rfc7838[RFC 7838]: HTTP Alternative Services +* https://tools.ietf.org/html/rfc7932[RFC 7932]: Brotli Compressed Data Format +* https://tools.ietf.org/html/rfc7936[RFC 7936]: Clarifying Registry Procedures for the WebSocket Subprotocol Name Registry +* https://tools.ietf.org/html/rfc8053[RFC 8053]: HTTP Authentication Extensions for Interactive Clients +* https://tools.ietf.org/html/rfc8164[RFC 8164]: Opportunistic Security for HTTP/2 +* https://tools.ietf.org/html/rfc8187[RFC 8187]: Indicating Character Encoding and Language for HTTP Header Field Parameters +* https://tools.ietf.org/html/rfc8188[RFC 8188]: Encrypted Content-Encoding for HTTP +* https://tools.ietf.org/html/rfc8246[RFC 8246]: HTTP Immutable Responses +* https://www.w3.org/TR/webmention/[Webmention]: Webmention + +==== Upcoming + +* https://www.w3.org/TR/csp-cookies/[Content Security Policy: Cookie Controls] +* https://www.w3.org/TR/csp-embedded-enforcement/[Content Security Policy: Embedded Enforcement] +* https://www.w3.org/TR/CSP3/[Content Security Policy Level 3] +* https://www.w3.org/TR/csp-pinning/[Content Security Policy Pinning] +* http://www.w3.org/TR/referrer-policy/[Referrer Policy] +* http://www.w3.org/TR/UISecurity/[User Interface Security Directives for Content Security Policy] + +==== Informative + +* http://www.w3.org/TR/webarch/[Architecture of the World Wide Web] +* https://tools.ietf.org/html/rfc2936[RFC 2936]: HTTP MIME Type Handler Detection +* https://tools.ietf.org/html/rfc2964[RFC 2964]: Use of HTTP State Management +* https://tools.ietf.org/html/rfc3143[RFC 3143]: Known HTTP Proxy/Caching Problems +* https://tools.ietf.org/html/rfc6202[RFC 6202]: Known Issues and Best Practices for the Use of Long Polling and Streaming in Bidirectional HTTP +* https://tools.ietf.org/html/rfc6838[RFC 6838]: Media Type Specifications and Registration Procedures +* https://tools.ietf.org/html/rfc7478[RFC 7478]: Web Real-Time Communication Use Cases and Requirements + +==== Related + +* http://www.w3.org/TR/app-uri/[app: URL Scheme] +* http://www.w3.org/TR/beacon/[Beacon] +* http://www.w3.org/TR/FileAPI/[File API] +* https://tools.ietf.org/html/rfc8030[Generic Event Delivery Using HTTP Push] +* http://www.w3.org/TR/capability-urls/[Good Practices for Capability URLs] +* https://html.spec.whatwg.org/multipage/[HTML Living Standard] +* https://developers.whatwg.org/[HTML Living Standard for Web developers] +* http://www.w3.org/TR/html401/[HTML4.01] +* http://www.w3.org/TR/html5/[HTML5] +* http://www.w3.org/TR/html51/[HTML5.1] +* https://www.w3.org/TR/html52/[HTML5.2] +* http://www.w3.org/TR/media-frags/[Media Fragments URI 1.0] +* https://tools.ietf.org/html/rfc6690[RFC 6690]: Constrained RESTful Environments (CoRE) Link Format +* https://tools.ietf.org/html/rfc7807[RFC 7807]: Problem Details for HTTP APIs +* https://tools.ietf.org/html/rfc6906[RFC 6906]: The 'profile' Link Relation Type +* http://www.w3.org/TR/SRI/[Subresource Integrity] +* http://www.w3.org/TR/tracking-compliance/[Tracking Compliance and Scope] +* http://www.w3.org/TR/media-frags-reqs/[Use cases and requirements for Media Fragments] +* http://www.w3.org/TR/webrtc/[WebRTC 1.0: Real-time Communication Between Browsers] +* http://www.w3.org/TR/websockets/[Websocket API] +* http://www.w3.org/TR/XMLHttpRequest/[XMLHttpRequest Level 1] +* https://xhr.spec.whatwg.org/[XMLHttpRequest Living Standard] + +==== Seemingly obsolete + +* https://tools.ietf.org/html/rfc2227[RFC 2227]: Simple Hit-Metering and Usage-Limiting for HTTP +* https://tools.ietf.org/html/rfc2310[RFC 2310]: The Safe Response Header Field +* https://tools.ietf.org/html/rfc2324[RFC 2324]: Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0) +* https://tools.ietf.org/html/rfc2660[RFC 2660]: The Secure HyperText Transfer Protocol +* https://tools.ietf.org/html/rfc2774[RFC 2774]: An HTTP Extension Framework +* https://tools.ietf.org/html/rfc2965[RFC 2965]: HTTP State Management Mechanism (Cookie2) +* https://tools.ietf.org/html/rfc3229[RFC 3229]: Delta encoding in HTTP +* https://tools.ietf.org/html/rfc7168[RFC 7168]: The Hyper Text Coffee Pot Control Protocol for Tea Efflux Appliances (HTCPCP-TEA) +* http://dev.chromium.org/spdy/spdy-protocol[SPDY]: SPDY Protocol +* https://tools.ietf.org/html/draft-tyoshino-hybi-websocket-perframe-deflate-06[x-webkit-deflate-frame]: Deprecated Websocket compression + +=== URL + +* https://tools.ietf.org/html/rfc3986[RFC 3986]: URI Generic Syntax +* https://tools.ietf.org/html/rfc6570[RFC 6570]: URI Template +* https://tools.ietf.org/html/rfc6874[RFC 6874]: Representing IPv6 Zone Identifiers in Address Literals and URIs +* https://tools.ietf.org/html/rfc7320[RFC 7320]: URI Design and Ownership +* http://www.w3.org/TR/url-1/[URL] +* https://url.spec.whatwg.org/[URL Living Standard] + +=== WebDAV + +* https://tools.ietf.org/html/rfc3253[RFC 3253]: Versioning Extensions to WebDAV +* https://tools.ietf.org/html/rfc3648[RFC 3648]: WebDAV Ordered Collections Protocol +* https://tools.ietf.org/html/rfc3744[RFC 3744]: WebDAV Access Control Protocol +* https://tools.ietf.org/html/rfc4316[RFC 4316]: Datatypes for WebDAV Properties +* https://tools.ietf.org/html/rfc4331[RFC 4331]: Quota and Size Properties for DAV Collections +* https://tools.ietf.org/html/rfc4437[RFC 4437]: WebDAV Redirect Reference Resources +* https://tools.ietf.org/html/rfc4709[RFC 4709]: Mounting WebDAV Servers +* https://tools.ietf.org/html/rfc4791[RFC 4791]: Calendaring Extensions to WebDAV (CalDAV) +* https://tools.ietf.org/html/rfc4918[RFC 4918]: HTTP Extensions for WebDAV +* https://tools.ietf.org/html/rfc5323[RFC 5323]: WebDAV SEARCH +* https://tools.ietf.org/html/rfc5397[RFC 5397]: WebDAV Current Principal Extension +* https://tools.ietf.org/html/rfc5689[RFC 5689]: Extended MKCOL for WebDAV +* https://tools.ietf.org/html/rfc5842[RFC 5842]: Binding Extensions to WebDAV +* https://tools.ietf.org/html/rfc5995[RFC 5995]: Using POST to Add Members to WebDAV Collections +* https://tools.ietf.org/html/rfc6352[RFC 6352]: CardDAV: vCard Extensions to WebDAV +* https://tools.ietf.org/html/rfc6578[RFC 6578]: Collection Synchronization for WebDAV +* https://tools.ietf.org/html/rfc6638[RFC 6638]: Scheduling Extensions to CalDAV +* https://tools.ietf.org/html/rfc6764[RFC 6764]: Locating Services for Calendaring Extensions to WebDAV (CalDAV) and vCard Extensions to WebDAV (CardDAV) +* https://tools.ietf.org/html/rfc7809[RFC 7809]: Calendaring Extensions to WebDAV (CalDAV): Time Zones by Reference +* https://tools.ietf.org/html/rfc7953[RFC 7953]: Calendar Availability +* https://tools.ietf.org/html/rfc8144[RFC 8144]: Use of the Prefer Header Field in WebDAV + +=== CoAP + +* https://tools.ietf.org/html/rfc7252[RFC 7252]: The Constrained Application Protocol (CoAP) +* https://tools.ietf.org/html/rfc7390[RFC 7390]: Group Communication for CoAP +* https://tools.ietf.org/html/rfc7641[RFC 7641]: Observing Resources in CoAP +* https://tools.ietf.org/html/rfc7650[RFC 7650]: A CoAP Usage for REsource LOcation And Discovery (RELOAD) +* https://tools.ietf.org/html/rfc7959[RFC 7959]: Block-Wise Transfers in CoAP +* https://tools.ietf.org/html/rfc7967[RFC 7967]: CoAP Option for No Server Response +* https://tools.ietf.org/html/rfc8075[RFC 8075]: Guidelines for Mapping Implementations: HTTP to CoAP +* https://tools.ietf.org/html/rfc8132[RFC 8132]: PATCH and FETCH Methods for CoAP diff --git a/docs/en/cowboy/2.2/guide/specs/index.html b/docs/en/cowboy/2.2/guide/specs/index.html new file mode 100644 index 00000000..cbfa8382 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/specs/index.html @@ -0,0 +1,994 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: HTTP and other specifications</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>HTTP and other specifications</span></h1> + +<div class="paragraph"><p>This chapter intends to list all the specification documents +for or related to HTTP.</p></div> +<div class="sect1"> +<h2 id="_http">HTTP</h2> +<div class="sectionbody"> +<div class="sect3"> +<h4 id="_iana_registries">IANA Registries</h4> +<div class="ulist"><ul> +<li> +<p> +<a href="https://www.iana.org/assignments/http-methods/http-methods.xhtml">HTTP Method Registry</a> +</p> +</li> +<li> +<p> +<a href="https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml">HTTP Status Code Registry</a> +</p> +</li> +<li> +<p> +<a href="https://www.iana.org/assignments/message-headers/message-headers.xhtml">Message Headers</a> +</p> +</li> +<li> +<p> +<a href="https://www.iana.org/assignments/http-parameters/http-parameters.xhtml">HTTP Parameters</a> +</p> +</li> +<li> +<p> +<a href="https://www.iana.org/assignments/http-alt-svc-parameters/http-alt-svc-parameters.xhtml">HTTP Alt-Svc Parameter Registry</a> +</p> +</li> +<li> +<p> +<a href="https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml">HTTP Authentication Scheme Registry</a> +</p> +</li> +<li> +<p> +<a href="https://www.iana.org/assignments/http-cache-directives/http-cache-directives.xhtml">HTTP Cache Directive Registry</a> +</p> +</li> +<li> +<p> +<a href="https://www.iana.org/assignments/http-dig-alg/http-dig-alg.xhtml">HTTP Digest Algorithm Values</a> +</p> +</li> +<li> +<p> +<a href="https://www.iana.org/assignments/hoba-device-identifiers/hoba-device-identifiers.xhtml">HTTP Origin-Bound Authentication Device Identifier Types</a> +</p> +</li> +<li> +<p> +<a href="https://www.iana.org/assignments/http-upgrade-tokens/http-upgrade-tokens.xhtml">HTTP Upgrade Token Registry</a> +</p> +</li> +<li> +<p> +<a href="https://www.iana.org/assignments/http-warn-codes/http-warn-codes.xhtml">HTTP Warn Codes</a> +</p> +</li> +<li> +<p> +<a href="https://www.iana.org/assignments/http2-parameters/http2-parameters.xhtml">HTTP/2 Parameters</a> +</p> +</li> +<li> +<p> +<a href="https://www.ietf.org/assignments/websocket/websocket.xml">WebSocket Protocol Registries</a> +</p> +</li> +</ul></div> +</div> +<div class="sect3"> +<h4 id="_current">Current</h4> +<div class="ulist"><ul> +<li> +<p> +<a href="http://www.w3.org/TR/cors/">CORS</a>: Cross-Origin Resource Sharing +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/CSP2/">CSP2</a>: Content Security Policy Level 2 +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/tracking-dnt/">DNT</a>: Tracking Preference Expression (DNT) +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/eventsource/">eventsource</a>: Server-Sent Events +</p> +</li> +<li> +<p> +<a href="https://www.w3.org/TR/html4/interact/forms.html#h-17.13.4">Form content types</a>: Form content types +</p> +</li> +<li> +<p> +<a href="https://www.w3.org/TR/preload/">Preload</a>: Preload +</p> +</li> +<li> +<p> +<a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm">REST</a>: Fielding’s Dissertation +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc1945">RFC 1945</a>: HTTP/1.0 +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc1951">RFC 1951</a>: DEFLATE Compressed Data Format Specification version 1.3 +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc1952">RFC 1952</a>: GZIP file format specification version 4.3 +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc2046#section-5.1">RFC 2046</a>: Multipart media type (in MIME Part Two: Media Types) +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc2295">RFC 2295</a>: Transparent Content Negotiation in HTTP +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc2296">RFC 2296</a>: HTTP Remote Variant Selection Algorithm: RVSA/1.0 +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc2817">RFC 2817</a>: Upgrading to TLS Within HTTP/1.1 +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc2818">RFC 2818</a>: HTTP Over TLS +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc3230">RFC 3230</a>: Instance Digests in HTTP +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc4559">RFC 4559</a>: SPNEGO-based Kerberos and NTLM HTTP Authentication in Microsoft Windows +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc5789">RFC 5789</a>: PATCH Method for HTTP +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc5843">RFC 5843</a>: Additional Hash Algorithms for HTTP Instance Digests +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc5861">RFC 5861</a>: HTTP Cache-Control Extensions for Stale Content +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc5988">RFC 5988</a>: Web Linking +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6265">RFC 6265</a>: HTTP State Management Mechanism +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6266">RFC 6266</a>: Use of the Content-Disposition Header Field +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6454">RFC 6454</a>: The Web Origin Concept +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6455">RFC 6455</a>: The WebSocket Protocol +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6585">RFC 6585</a>: Additional HTTP Status Codes +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6750">RFC 6750</a>: The OAuth 2.0 Authorization Framework: Bearer Token Usage +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6797">RFC 6797</a>: HTTP Strict Transport Security (HSTS) +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6903">RFC 6903</a>: Additional Link Relation Types +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7034">RFC 7034</a>: HTTP Header Field X-Frame-Options +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7089">RFC 7089</a>: Time-Based Access to Resource States: Memento +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7230">RFC 7230</a>: HTTP/1.1 Message Syntax and Routing +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7231">RFC 7231</a>: HTTP/1.1 Semantics and Content +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7232">RFC 7232</a>: HTTP/1.1 Conditional Requests +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7233">RFC 7233</a>: HTTP/1.1 Range Requests +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7234">RFC 7234</a>: HTTP/1.1 Caching +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7235">RFC 7235</a>: HTTP/1.1 Authentication +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7239">RFC 7239</a>: Forwarded HTTP Extension +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7240">RFC 7240</a>: Prefer Header for HTTP +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7469">RFC 7469</a>: Public Key Pinning Extension for HTTP +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7486">RFC 7486</a>: HTTP Origin-Bound Authentication (HOBA) +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7538">RFC 7538</a>: HTTP Status Code 308 (Permanent Redirect) +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7540">RFC 7540</a>: Hypertext Transfer Protocol Version 2 (HTTP/2) +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7541">RFC 7541</a>: HPACK: Header Compression for HTTP/2 +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7578">RFC 7578</a>: Returning Values from Forms: multipart/form-data +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7615">RFC 7615</a>: HTTP Authentication-Info and Proxy-Authentication-Info Response Header Fields +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7616">RFC 7616</a>: HTTP Digest Access Authentication +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7617">RFC 7617</a>: The <em>Basic</em> HTTP Authentication Scheme +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7639">RFC 7639</a>: The ALPN HTTP Header Field +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7692">RFC 7692</a>: Compression Extensions for WebSocket +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7694">RFC 7694</a>: HTTP Client-Initiated Content-Encoding +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7725">RFC 7725</a>: An HTTP Status Code to Report Legal Obstacles +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7804">RFC 7804</a>: Salted Challenge Response HTTP Authentication Mechanism +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7838">RFC 7838</a>: HTTP Alternative Services +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7932">RFC 7932</a>: Brotli Compressed Data Format +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7936">RFC 7936</a>: Clarifying Registry Procedures for the WebSocket Subprotocol Name Registry +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc8053">RFC 8053</a>: HTTP Authentication Extensions for Interactive Clients +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc8164">RFC 8164</a>: Opportunistic Security for HTTP/2 +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc8187">RFC 8187</a>: Indicating Character Encoding and Language for HTTP Header Field Parameters +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc8188">RFC 8188</a>: Encrypted Content-Encoding for HTTP +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc8246">RFC 8246</a>: HTTP Immutable Responses +</p> +</li> +<li> +<p> +<a href="https://www.w3.org/TR/webmention/">Webmention</a>: Webmention +</p> +</li> +</ul></div> +</div> +<div class="sect3"> +<h4 id="_upcoming">Upcoming</h4> +<div class="ulist"><ul> +<li> +<p> +<a href="https://www.w3.org/TR/csp-cookies/">Content Security Policy: Cookie Controls</a> +</p> +</li> +<li> +<p> +<a href="https://www.w3.org/TR/csp-embedded-enforcement/">Content Security Policy: Embedded Enforcement</a> +</p> +</li> +<li> +<p> +<a href="https://www.w3.org/TR/CSP3/">Content Security Policy Level 3</a> +</p> +</li> +<li> +<p> +<a href="https://www.w3.org/TR/csp-pinning/">Content Security Policy Pinning</a> +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/referrer-policy/">Referrer Policy</a> +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/UISecurity/">User Interface Security Directives for Content Security Policy</a> +</p> +</li> +</ul></div> +</div> +<div class="sect3"> +<h4 id="_informative">Informative</h4> +<div class="ulist"><ul> +<li> +<p> +<a href="http://www.w3.org/TR/webarch/">Architecture of the World Wide Web</a> +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc2936">RFC 2936</a>: HTTP MIME Type Handler Detection +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc2964">RFC 2964</a>: Use of HTTP State Management +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc3143">RFC 3143</a>: Known HTTP Proxy/Caching Problems +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6202">RFC 6202</a>: Known Issues and Best Practices for the Use of Long Polling and Streaming in Bidirectional HTTP +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6838">RFC 6838</a>: Media Type Specifications and Registration Procedures +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7478">RFC 7478</a>: Web Real-Time Communication Use Cases and Requirements +</p> +</li> +</ul></div> +</div> +<div class="sect3"> +<h4 id="_related">Related</h4> +<div class="ulist"><ul> +<li> +<p> +<a href="http://www.w3.org/TR/app-uri/">app: URL Scheme</a> +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/beacon/">Beacon</a> +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/FileAPI/">File API</a> +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc8030">Generic Event Delivery Using HTTP Push</a> +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/capability-urls/">Good Practices for Capability URLs</a> +</p> +</li> +<li> +<p> +<a href="https://html.spec.whatwg.org/multipage/">HTML Living Standard</a> +</p> +</li> +<li> +<p> +<a href="https://developers.whatwg.org/">HTML Living Standard for Web developers</a> +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/html401/">HTML4.01</a> +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/html5/">HTML5</a> +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/html51/">HTML5.1</a> +</p> +</li> +<li> +<p> +<a href="https://www.w3.org/TR/html52/">HTML5.2</a> +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/media-frags/">Media Fragments URI 1.0</a> +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6690">RFC 6690</a>: Constrained RESTful Environments (CoRE) Link Format +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7807">RFC 7807</a>: Problem Details for HTTP APIs +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6906">RFC 6906</a>: The <em>profile</em> Link Relation Type +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/SRI/">Subresource Integrity</a> +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/tracking-compliance/">Tracking Compliance and Scope</a> +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/media-frags-reqs/">Use cases and requirements for Media Fragments</a> +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/webrtc/">WebRTC 1.0: Real-time Communication Between Browsers</a> +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/websockets/">Websocket API</a> +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/XMLHttpRequest/">XMLHttpRequest Level 1</a> +</p> +</li> +<li> +<p> +<a href="https://xhr.spec.whatwg.org/">XMLHttpRequest Living Standard</a> +</p> +</li> +</ul></div> +</div> +<div class="sect3"> +<h4 id="_seemingly_obsolete">Seemingly obsolete</h4> +<div class="ulist"><ul> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc2227">RFC 2227</a>: Simple Hit-Metering and Usage-Limiting for HTTP +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc2310">RFC 2310</a>: The Safe Response Header Field +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc2324">RFC 2324</a>: Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0) +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc2660">RFC 2660</a>: The Secure HyperText Transfer Protocol +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc2774">RFC 2774</a>: An HTTP Extension Framework +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc2965">RFC 2965</a>: HTTP State Management Mechanism (Cookie2) +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc3229">RFC 3229</a>: Delta encoding in HTTP +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7168">RFC 7168</a>: The Hyper Text Coffee Pot Control Protocol for Tea Efflux Appliances (HTCPCP-TEA) +</p> +</li> +<li> +<p> +<a href="http://dev.chromium.org/spdy/spdy-protocol">SPDY</a>: SPDY Protocol +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/draft-tyoshino-hybi-websocket-perframe-deflate-06">x-webkit-deflate-frame</a>: Deprecated Websocket compression +</p> +</li> +</ul></div> +</div> +</div> +</div> +<div class="sect1"> +<h2 id="_url">URL</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc3986">RFC 3986</a>: URI Generic Syntax +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6570">RFC 6570</a>: URI Template +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6874">RFC 6874</a>: Representing IPv6 Zone Identifiers in Address Literals and URIs +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7320">RFC 7320</a>: URI Design and Ownership +</p> +</li> +<li> +<p> +<a href="http://www.w3.org/TR/url-1/">URL</a> +</p> +</li> +<li> +<p> +<a href="https://url.spec.whatwg.org/">URL Living Standard</a> +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_webdav">WebDAV</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc3253">RFC 3253</a>: Versioning Extensions to WebDAV +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc3648">RFC 3648</a>: WebDAV Ordered Collections Protocol +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc3744">RFC 3744</a>: WebDAV Access Control Protocol +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc4316">RFC 4316</a>: Datatypes for WebDAV Properties +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc4331">RFC 4331</a>: Quota and Size Properties for DAV Collections +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc4437">RFC 4437</a>: WebDAV Redirect Reference Resources +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc4709">RFC 4709</a>: Mounting WebDAV Servers +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc4791">RFC 4791</a>: Calendaring Extensions to WebDAV (CalDAV) +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc4918">RFC 4918</a>: HTTP Extensions for WebDAV +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc5323">RFC 5323</a>: WebDAV SEARCH +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc5397">RFC 5397</a>: WebDAV Current Principal Extension +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc5689">RFC 5689</a>: Extended MKCOL for WebDAV +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc5842">RFC 5842</a>: Binding Extensions to WebDAV +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc5995">RFC 5995</a>: Using POST to Add Members to WebDAV Collections +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6352">RFC 6352</a>: CardDAV: vCard Extensions to WebDAV +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6578">RFC 6578</a>: Collection Synchronization for WebDAV +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6638">RFC 6638</a>: Scheduling Extensions to CalDAV +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc6764">RFC 6764</a>: Locating Services for Calendaring Extensions to WebDAV (CalDAV) and vCard Extensions to WebDAV (CardDAV) +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7809">RFC 7809</a>: Calendaring Extensions to WebDAV (CalDAV): Time Zones by Reference +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7953">RFC 7953</a>: Calendar Availability +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc8144">RFC 8144</a>: Use of the Prefer Header Field in WebDAV +</p> +</li> +</ul></div> +</div> +</div> +<div class="sect1"> +<h2 id="_coap">CoAP</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7252">RFC 7252</a>: The Constrained Application Protocol (CoAP) +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7390">RFC 7390</a>: Group Communication for CoAP +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7641">RFC 7641</a>: Observing Resources in CoAP +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7650">RFC 7650</a>: A CoAP Usage for REsource LOcation And Discovery (RELOAD) +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7959">RFC 7959</a>: Block-Wise Transfers in CoAP +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc7967">RFC 7967</a>: CoAP Option for No Server Response +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc8075">RFC 8075</a>: Guidelines for Mapping Implementations: HTTP to CoAP +</p> +</li> +<li> +<p> +<a href="https://tools.ietf.org/html/rfc8132">RFC 8132</a>: PATCH and FETCH Methods for CoAP +</p> +</li> +</ul></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/migrating_from_1.0/"> + Migrating from Cowboy 1.0 to 2.0 + </a> + + + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/static_files.asciidoc b/docs/en/cowboy/2.2/guide/static_files.asciidoc new file mode 100644 index 00000000..9d9b8cc2 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/static_files.asciidoc @@ -0,0 +1,163 @@ +[[static_files]] +== Static files + +Cowboy comes with a ready to use handler for serving static +files. It is provided as a convenience for serving files +during development. + +For systems in production, consider using one of the many +Content Distribution Network (CDN) available on the market, +as they are the best solution for serving files. + +The static handler can serve either one file or all files +from a given directory. The etag generation and mime types +can be configured. + +=== 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 +the `/` path, for example. The path configured is relative +to the given application's private directory. + +The following rule will serve the file 'static/index.html' +from the application `my_app`'s priv directory whenever the +path `/` is accessed: + +[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: + +[source,erlang] +{"/", cowboy_static, {file, "/var/www/index.html"}} + +=== 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 +use the `path_info` information to resolve the file location, +which means that your route must end with a `[...]` pattern +for it to work. All files are served, including the ones that +may be found in subfolders. + +You can specify the directory relative to an application's +private directory. + +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/`: + +[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: + +[source,erlang] +{"/assets/[...]", cowboy_static, {dir, "/var/www/assets"}} + +=== Customize the mimetype detection + +By default, Cowboy will attempt to recognize the mimetype +of your static files by looking at the extension. + +You can override the function that figures out the mimetype +of the static files. It can be useful when Cowboy is missing +a mimetype you need to handle, or when you want to reduce +the list to make lookups faster. You can also give a +hard-coded mimetype that will be used unconditionally. + +Cowboy comes with two functions built-in. The default +function only handles common file types used when building +Web applications. The other function is an extensive list +of hundreds of mimetypes that should cover almost any need +you may have. You can of course create your own function. + +To use the default function, you should not have to configure +anything, as it is the default. If you insist, though, the +following will do the job: + +[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 +types have this optional field. + +To use the function that will detect almost any mimetype, +the following configuration will do: + +[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: + +[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 +is recommended to return the mimetype in tuple form, although +a binary string is also allowed (but will require extra +processing). If the function can't figure out the mimetype, +then it should return `{<<"application">>, <<"octet-stream">>, []}`. + +When the static handler fails to find the extension, +it will send the file as `application/octet-stream`. +A browser receiving such file will attempt to download it +directly to disk. + +Finally, the mimetype can be hard-coded for all files. +This is especially useful in combination with the `file` +and `priv_file` options as it avoids needless computation: + +[source,erlang] +---- +{"/", cowboy_static, {priv_file, my_app, "static/index.html", + [{mimetypes, {<<"text">>, <<"html">>, []}}]}} +---- + +=== Generate an etag + +By default, the static handler will generate an etag header +value based on the size and modified time. This solution +can not be applied to all systems though. It would perform +rather poorly over a cluster of nodes, for example, as the +file metadata will vary from server to server, giving a +different etag on each server. + +You can however change the way the etag is calculated: + +[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 +time. In a distributed setup, you would typically use the +file path to retrieve an etag value that is identical across +all your servers. + +You can also completely disable etag handling: + +[source,erlang] +---- +{"/assets/[...]", cowboy_static, {priv_dir, my_app, "static/assets", + [{etag, false}]}} +---- diff --git a/docs/en/cowboy/2.2/guide/static_files/index.html b/docs/en/cowboy/2.2/guide/static_files/index.html new file mode 100644 index 00000000..e1c48e16 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/static_files/index.html @@ -0,0 +1,332 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Static files</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Static files</span></h1> + +<div class="paragraph"><p>Cowboy comes with a ready to use handler for serving static +files. It is provided as a convenience for serving files +during development.</p></div> +<div class="paragraph"><p>For systems in production, consider using one of the many +Content Distribution Network (CDN) available on the market, +as they are the best solution for serving files.</p></div> +<div class="paragraph"><p>The static handler can serve either one file or all files +from a given directory. The etag generation and mime types +can be configured.</p></div> +<div class="sect1"> +<h2 id="_serve_one_file">Serve one file</h2> +<div class="sectionbody"> +<div class="paragraph"><p>You can use the static handler to serve one specific file +from an application’s private directory. This is particularly +useful to serve an <em>index.html</em> file when the client requests +the <code>/</code> path, for example. The path configured is relative +to the given application’s private directory.</p></div> +<div class="paragraph"><p>The following rule will serve the file <em>static/index.html</em> +from the application <code>my_app</code>'s priv directory whenever the +path <code>/</code> is accessed:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF0000">"/"</span>, <span style="color: #FF6600">cowboy_static</span>, {<span style="color: #FF6600">priv_file</span>, <span style="color: #FF6600">my_app</span>, <span style="color: #FF0000">"static/index.html"</span>}}</tt></pre></div></div> +<div class="paragraph"><p>You can also specify the absolute path to a file, or the +path to the file relative to the current directory:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF0000">"/"</span>, <span style="color: #FF6600">cowboy_static</span>, {<span style="color: #FF6600">file</span>, <span style="color: #FF0000">"/var/www/index.html"</span>}}</tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_serve_all_files_from_a_directory">Serve all files from a directory</h2> +<div class="sectionbody"> +<div class="paragraph"><p>You can also use the static handler to serve all files that +can be found in the configured directory. The handler will +use the <code>path_info</code> information to resolve the file location, +which means that your route must end with a <code>[...]</code> pattern +for it to work. All files are served, including the ones that +may be found in subfolders.</p></div> +<div class="paragraph"><p>You can specify the directory relative to an application’s +private directory.</p></div> +<div class="paragraph"><p>The following rule will serve any file found in the application +<code>my_app</code>'s priv directory inside the <code>static/assets</code> folder +whenever the requested path begins with <code>/assets/</code>:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF0000">"/assets/[...]"</span>, <span style="color: #FF6600">cowboy_static</span>, {<span style="color: #FF6600">priv_dir</span>, <span style="color: #FF6600">my_app</span>, <span style="color: #FF0000">"static/assets"</span>}}</tt></pre></div></div> +<div class="paragraph"><p>You can also specify the absolute path to the directory or +set it relative to the current directory:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF0000">"/assets/[...]"</span>, <span style="color: #FF6600">cowboy_static</span>, {<span style="color: #FF6600">dir</span>, <span style="color: #FF0000">"/var/www/assets"</span>}}</tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_customize_the_mimetype_detection">Customize the mimetype detection</h2> +<div class="sectionbody"> +<div class="paragraph"><p>By default, Cowboy will attempt to recognize the mimetype +of your static files by looking at the extension.</p></div> +<div class="paragraph"><p>You can override the function that figures out the mimetype +of the static files. It can be useful when Cowboy is missing +a mimetype you need to handle, or when you want to reduce +the list to make lookups faster. You can also give a +hard-coded mimetype that will be used unconditionally.</p></div> +<div class="paragraph"><p>Cowboy comes with two functions built-in. The default +function only handles common file types used when building +Web applications. The other function is an extensive list +of hundreds of mimetypes that should cover almost any need +you may have. You can of course create your own function.</p></div> +<div class="paragraph"><p>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:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF0000">"/assets/[...]"</span>, <span style="color: #FF6600">cowboy_static</span>, {<span style="color: #FF6600">priv_dir</span>, <span style="color: #FF6600">my_app</span>, <span style="color: #FF0000">"static/assets"</span>, + [{<span style="color: #FF6600">mimetypes</span>, <span style="color: #FF6600">cow_mimetypes</span>, <span style="color: #FF6600">web</span>}]}}</tt></pre></div></div> +<div class="paragraph"><p>As you can see, there is an optional field that may contain +a list of less used options, like mimetypes or etag. All option +types have this optional field.</p></div> +<div class="paragraph"><p>To use the function that will detect almost any mimetype, +the following configuration will do:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF0000">"/assets/[...]"</span>, <span style="color: #FF6600">cowboy_static</span>, {<span style="color: #FF6600">priv_dir</span>, <span style="color: #FF6600">my_app</span>, <span style="color: #FF0000">"static/assets"</span>, + [{<span style="color: #FF6600">mimetypes</span>, <span style="color: #FF6600">cow_mimetypes</span>, <span style="color: #FF6600">all</span>}]}}</tt></pre></div></div> +<div class="paragraph"><p>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:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF0000">"/assets/[...]"</span>, <span style="color: #FF6600">cowboy_static</span>, {<span style="color: #FF6600">priv_dir</span>, <span style="color: #FF6600">my_app</span>, <span style="color: #FF0000">"static/assets"</span>, + [{<span style="color: #FF6600">mimetypes</span>, <span style="color: #009900">Module</span>, <span style="color: #009900">Function</span>}]}}</tt></pre></div></div> +<div class="paragraph"><p>The function that performs the mimetype detection receives +a single argument that is the path to the file on disk. It +is recommended to return the mimetype in tuple form, although +a binary string is also allowed (but will require extra +processing). If the function can’t figure out the mimetype, +then it should return <code>{<<"application">>, <<"octet-stream">>, []}</code>.</p></div> +<div class="paragraph"><p>When the static handler fails to find the extension, +it will send the file as <code>application/octet-stream</code>. +A browser receiving such file will attempt to download it +directly to disk.</p></div> +<div class="paragraph"><p>Finally, the mimetype can be hard-coded for all files. +This is especially useful in combination with the <code>file</code> +and <code>priv_file</code> options as it avoids needless computation:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF0000">"/"</span>, <span style="color: #FF6600">cowboy_static</span>, {<span style="color: #FF6600">priv_file</span>, <span style="color: #FF6600">my_app</span>, <span style="color: #FF0000">"static/index.html"</span>, + [{<span style="color: #FF6600">mimetypes</span>, {<span style="color: #990000"><<</span><span style="color: #FF0000">"text"</span><span style="color: #990000">>></span>, <span style="color: #990000"><<</span><span style="color: #FF0000">"html"</span><span style="color: #990000">>></span>, []}}]}}</tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_generate_an_etag">Generate an etag</h2> +<div class="sectionbody"> +<div class="paragraph"><p>By default, the static handler will generate an etag header +value based on the size and modified time. This solution +can not be applied to all systems though. It would perform +rather poorly over a cluster of nodes, for example, as the +file metadata will vary from server to server, giving a +different etag on each server.</p></div> +<div class="paragraph"><p>You can however change the way the etag is calculated:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF0000">"/assets/[...]"</span>, <span style="color: #FF6600">cowboy_static</span>, {<span style="color: #FF6600">priv_dir</span>, <span style="color: #FF6600">my_app</span>, <span style="color: #FF0000">"static/assets"</span>, + [{<span style="color: #FF6600">etag</span>, <span style="color: #009900">Module</span>, <span style="color: #009900">Function</span>}]}}</tt></pre></div></div> +<div class="paragraph"><p>This function will receive three arguments: the path to the +file on disk, the size of the file and the last modification +time. In a distributed setup, you would typically use the +file path to retrieve an etag value that is identical across +all your servers.</p></div> +<div class="paragraph"><p>You can also completely disable etag handling:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt>{<span style="color: #FF0000">"/assets/[...]"</span>, <span style="color: #FF6600">cowboy_static</span>, {<span style="color: #FF6600">priv_dir</span>, <span style="color: #FF6600">my_app</span>, <span style="color: #FF0000">"static/assets"</span>, + [{<span style="color: #FF6600">etag</span>, <span style="color: #000080">false</span>}]}}</tt></pre></div></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/loop_handlers/"> + Loop handlers + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/req/"> + The Req object + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/streams.asciidoc b/docs/en/cowboy/2.2/guide/streams.asciidoc new file mode 100644 index 00000000..841a9712 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/streams.asciidoc @@ -0,0 +1,65 @@ +[[streams]] +== Streams + +A stream is the set of messages that form an HTTP +request/response pair. + +The term stream comes from HTTP/2. In Cowboy, it is +also used when talking about HTTP/1.1 or HTTP/1.0. +It should not be confused with streaming the request +or response body. + +All versions of HTTP allow clients to initiate +streams. HTTP/2 is the only one also allowing servers, +through its server push feature. Both client and +server-initiated streams go through the same process +in Cowboy. + +=== Stream handlers + +Stream handlers must implement five different callbacks. +Four of them are directly related; one is special. + +All callbacks receives the stream ID as first argument. + +Most of them can return a list of commands to be executed +by Cowboy. When callbacks are chained, it is possible to +intercept and modify these commands. This can be useful +for modifying responses for example. + +The `init/3` callback is invoked when a new request +comes in. It receives the Req object and the protocol options +for this listener. + +The `data/4` callback is invoked when data from the request +body is received. It receives both this data and a flag +indicating whether more is to be expected. + +The `info/3` callback is invoked when an Erlang message is +received for this stream. They will typically be messages +sent by the request process. + +Finally the `terminate/3` callback is invoked with the +terminate reason for the stream. The return value is ignored. +Note that as with all terminate callbacks in Erlang, there +is no strong guarantee that it will be called. + +The special callback `early_error/5` is called when an error +occurs before the request headers were fully received and +Cowboy is sending a response. It receives the partial Req +object, the error reason, the protocol options and the response +Cowboy will send. This response must be returned, possibly +modified. + +=== Built-in handlers + +Cowboy comes with two handlers. + +`cowboy_stream_h` is the default stream handler. +It is the core of much of the functionality of Cowboy. +All chains of stream handlers should call it last. + +`cowboy_compress_h` will automatically compress +responses when possible. It is not enabled by default. +It is a good example for writing your own handlers +that will modify responses. diff --git a/docs/en/cowboy/2.2/guide/streams/index.html b/docs/en/cowboy/2.2/guide/streams/index.html new file mode 100644 index 00000000..cd44a899 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/streams/index.html @@ -0,0 +1,220 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Streams</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Streams</span></h1> + +<div class="paragraph"><p>A stream is the set of messages that form an HTTP +request/response pair.</p></div> +<div class="paragraph"><p>The term stream comes from HTTP/2. In Cowboy, it is +also used when talking about HTTP/1.1 or HTTP/1.0. +It should not be confused with streaming the request +or response body.</p></div> +<div class="paragraph"><p>All versions of HTTP allow clients to initiate +streams. HTTP/2 is the only one also allowing servers, +through its server push feature. Both client and +server-initiated streams go through the same process +in Cowboy.</p></div> +<div class="sect1"> +<h2 id="_stream_handlers">Stream handlers</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Stream handlers must implement five different callbacks. +Four of them are directly related; one is special.</p></div> +<div class="paragraph"><p>All callbacks receives the stream ID as first argument.</p></div> +<div class="paragraph"><p>Most of them can return a list of commands to be executed +by Cowboy. When callbacks are chained, it is possible to +intercept and modify these commands. This can be useful +for modifying responses for example.</p></div> +<div class="paragraph"><p>The <code>init/3</code> callback is invoked when a new request +comes in. It receives the Req object and the protocol options +for this listener.</p></div> +<div class="paragraph"><p>The <code>data/4</code> callback is invoked when data from the request +body is received. It receives both this data and a flag +indicating whether more is to be expected.</p></div> +<div class="paragraph"><p>The <code>info/3</code> callback is invoked when an Erlang message is +received for this stream. They will typically be messages +sent by the request process.</p></div> +<div class="paragraph"><p>Finally the <code>terminate/3</code> callback is invoked with the +terminate reason for the stream. The return value is ignored. +Note that as with all terminate callbacks in Erlang, there +is no strong guarantee that it will be called.</p></div> +<div class="paragraph"><p>The special callback <code>early_error/5</code> is called when an error +occurs before the request headers were fully received and +Cowboy is sending a response. It receives the partial Req +object, the error reason, the protocol options and the response +Cowboy will send. This response must be returned, possibly +modified.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_built_in_handlers">Built-in handlers</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy comes with two handlers.</p></div> +<div class="paragraph"><p><code>cowboy_stream_h</code> is the default stream handler. +It is the core of much of the functionality of Cowboy. +All chains of stream handlers should call it last.</p></div> +<div class="paragraph"><p><code>cowboy_compress_h</code> will automatically compress +responses when possible. It is not enabled by default. +It is a good example for writing your own handlers +that will modify responses.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/ws_handlers/"> + Websocket handlers + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/middlewares/"> + Middlewares + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/ws_handlers.asciidoc b/docs/en/cowboy/2.2/guide/ws_handlers.asciidoc new file mode 100644 index 00000000..a79d7e29 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/ws_handlers.asciidoc @@ -0,0 +1,269 @@ +[[ws_handlers]] +== Websocket handlers + +Websocket handlers provide an interface for upgrading HTTP/1.1 +connections to Websocket and sending or receiving frames on +the Websocket connection. + +As Websocket connections are established through the HTTP/1.1 +upgrade mechanism, Websocket handlers need to be able to first +receive the HTTP request for the upgrade, before switching to +Websocket and taking over the connection. They can then receive +or send Websocket frames, handle incoming Erlang messages or +close the connection. + +=== Upgrade + +The `init/2` callback is called when the request is received. +To establish a Websocket connection, you must switch to the +`cowboy_websocket` module: + +[source,erlang] +---- +init(Req, State) -> + {cowboy_websocket, Req, State}. +---- + +Cowboy will perform the Websocket handshake immediately. Note +that the handshake will fail if the client did not request an +upgrade to Websocket. + +The Req object becomes unavailable after this function returns. +Any information required for proper execution of the Websocket +handler must be saved in the state. + +=== Subprotocol + +The client may provide a list of Websocket subprotocols it +supports in the sec-websocket-protocol header. The server *must* +select one of them and send it back to the client or the +handshake will fail. + +For example, a client could understand both STOMP and MQTT over +Websocket, and provide the header: + +---- +sec-websocket-protocol: v12.stomp, mqtt +---- + +If the server only understands MQTT it can return: + +---- +sec-websocket-protocol: mqtt +---- + +This selection must be done in `init/2`. An example usage could +be: + +[source,erlang] +---- +init(Req0, State) -> + case cowboy_req:parse_header(<<"sec-websocket-protocol">>, Req0) of + undefined -> + {cowboy_websocket, Req0, State}; + Subprotocols -> + case lists:keymember(<<"mqtt">>, 1, Subprotocols) of + true -> + Req = cowboy_req:set_resp_header(<<"sec-websocket-protocol">>, + <<"mqtt">>, Req0), + {cowboy_websocket, Req, State}; + false -> + Req = cowboy_req:reply(400, Req0), + {ok, Req, State} + end + end. +---- + +=== Post-upgrade initialization + +Cowboy has separate processes for handling the connection +and requests. Because Websocket takes over the connection, +the Websocket protocol handling occurs in a different +process than the request handling. + +This is reflected in the different callbacks Websocket +handlers have. The `init/2` callback is called from the +temporary request process and the `websocket_` callbacks +from the connection process. + +This means that some initialization cannot be done from +`init/2`. Anything that would require the current pid, +or be tied to the current pid, will not work as intended. +The optional `websocket_init/1` can be used instead: + +[source,erlang] +---- +websocket_init(State) -> + erlang:start_timer(1000, self(), <<"Hello!">>), + {ok, State}. +---- + +All Websocket callbacks share the same return values. This +means that we can send frames to the client right after +the upgrade: + +[source,erlang] +---- +websocket_init(State) -> + {reply, {text, <<"Hello!">>}, State}. +---- + +=== Receiving frames + +Cowboy will call `websocket_handle/2` whenever a text, binary, +ping or pong frame arrives from the client. + +The handler can handle or ignore the frames. It can also +send frames back to the client or stop the connection. + +The following snippet echoes back any text frame received and +ignores all others: + +[source,erlang] +---- +websocket_handle(Frame = {text, _}, State) -> + {reply, Frame, State}; +websocket_handle(_Frame, State) -> + {ok, State}. +---- + +Note that ping and pong frames require no action from the +handler as Cowboy will automatically reply to ping frames. +They are provided for informative purposes only. + +=== Receiving Erlang messages + +Cowboy will call `websocket_info/2` whenever an Erlang message +arrives. + +The handler can handle or ignore the messages. It can also +send frames to the client or stop the connection. + +The following snippet forwards log messages to the client +and ignores all others: + +[source,erlang] +---- +websocket_info({log, Text}, State) -> + {reply, {text, Text}, State}; +websocket_info(_Info, State) -> + {ok, State}. +---- + +=== Sending frames + +// @todo This will be deprecated and eventually replaced with a +// {Commands, State} interface that allows providing more +// functionality easily. + +All `websocket_` callbacks share return values. They may +send zero, one or many frames to the client. + +To send nothing, just return an ok tuple: + +[source,erlang] +---- +websocket_info(_Info, State) -> + {ok, State}. +---- + +To send one frame, return a reply tuple with the frame to send: + +[source,erlang] +---- +websocket_info(_Info, State) -> + {reply, {text, <<"Hello!">>}, State}. +---- + +You can send frames of any type: text, binary, ping, pong +or close frames. + +To send many frames at once, return a reply tuple with the +list of frames to send: + +[source,erlang] +---- +websocket_info(_Info, State) -> + {reply, [ + {text, "Hello"}, + {text, <<"world!">>}, + {binary, <<0:8000>>} + ], State}. +---- + +They are sent in the given order. + +=== Keeping the connection alive + +Cowboy will automatically respond to ping frames sent by +the client. They are still forwarded to the handler for +informative purposes, but no further action is required. + +Cowboy does not send ping frames itself. The handler can +do it if required. A better solution in most cases is to +let the client handle pings. Doing it from the handler +would imply having an additional timer per connection and +this can be a considerable cost for servers that need to +handle large numbers of connections. + +Cowboy can be configured to close idle connections +automatically. It is highly recommended to configure +a timeout here, to avoid having processes linger longer +than needed. + +The `init/2` callback can set the timeout to be used +for the connection. For example, this would make Cowboy +close connections idle for more than 30 seconds: + +[source,erlang] +---- +init(Req, State) -> + {cowboy_websocket, Req, State, #{ + idle_timeout => 30000}}. +---- + +This value cannot be changed once it is set. It defaults to +`60000`. + +=== Saving memory + +The Websocket connection process can be set to hibernate +after the callback returns. + +Simply add an `hibernate` field to the ok or reply tuples: + +[source,erlang] +---- +websocket_init(State) -> + {ok, State, hibernate}. + +websocket_handle(_Frame, State) -> + {ok, State, hibernate}. + +websocket_info(_Info, State) -> + {reply, {text, <<"Hello!">>}, State, hibernate}. +---- + +It is highly recommended to write your handlers with +hibernate enabled, as this allows to greatly reduce the +memory usage. Do note however that an increase in the +CPU usage or latency can be observed instead, in particular +for the more busy connections. + +=== Closing the connection + +The connection can be closed at any time, either by telling +Cowboy to stop it or by sending a close frame. + +To tell Cowboy to close the connection, use a stop tuple: + +[source,erlang] +---- +websocket_info(_Info, State) -> + {stop, State}. +---- + +Sending a `close` frame will immediately initiate the closing +of the Websocket connection. Note that when sending a list of +frames that include a close frame, any frame found after the +close frame will not be sent. diff --git a/docs/en/cowboy/2.2/guide/ws_handlers/index.html b/docs/en/cowboy/2.2/guide/ws_handlers/index.html new file mode 100644 index 00000000..28f16a6a --- /dev/null +++ b/docs/en/cowboy/2.2/guide/ws_handlers/index.html @@ -0,0 +1,430 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: Websocket handlers</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>Websocket handlers</span></h1> + +<div class="paragraph"><p>Websocket handlers provide an interface for upgrading HTTP/1.1 +connections to Websocket and sending or receiving frames on +the Websocket connection.</p></div> +<div class="paragraph"><p>As Websocket connections are established through the HTTP/1.1 +upgrade mechanism, Websocket handlers need to be able to first +receive the HTTP request for the upgrade, before switching to +Websocket and taking over the connection. They can then receive +or send Websocket frames, handle incoming Erlang messages or +close the connection.</p></div> +<div class="sect1"> +<h2 id="_upgrade">Upgrade</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The <code>init/2</code> callback is called when the request is received. +To establish a Websocket connection, you must switch to the +<code>cowboy_websocket</code> module:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">cowboy_websocket</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Cowboy will perform the Websocket handshake immediately. Note +that the handshake will fail if the client did not request an +upgrade to Websocket.</p></div> +<div class="paragraph"><p>The Req object becomes unavailable after this function returns. +Any information required for proper execution of the Websocket +handler must be saved in the state.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_subprotocol">Subprotocol</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The client may provide a list of Websocket subprotocols it +supports in the sec-websocket-protocol header. The server <strong>must</strong> +select one of them and send it back to the client or the +handshake will fail.</p></div> +<div class="paragraph"><p>For example, a client could understand both STOMP and MQTT over +Websocket, and provide the header:</p></div> +<div class="listingblock"> +<div class="content"> +<pre><code>sec-websocket-protocol: v12.stomp, mqtt</code></pre> +</div></div> +<div class="paragraph"><p>If the server only understands MQTT it can return:</p></div> +<div class="listingblock"> +<div class="content"> +<pre><code>sec-websocket-protocol: mqtt</code></pre> +</div></div> +<div class="paragraph"><p>This selection must be done in <code>init/2</code>. An example usage could +be:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req0</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #0000FF">case</span></span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:parse_header</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"sec-websocket-protocol"</span><span style="color: #990000">>></span>, <span style="color: #009900">Req0</span>) <span style="font-weight: bold"><span style="color: #0000FF">of</span></span> + <span style="color: #000080">undefined</span> <span style="color: #990000">-></span> + {<span style="color: #FF6600">cowboy_websocket</span>, <span style="color: #009900">Req0</span>, <span style="color: #009900">State</span>}; + <span style="color: #009900">Subprotocols</span> <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #0000FF">case</span></span> <span style="font-weight: bold"><span style="color: #000000">lists:keymember</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"mqtt"</span><span style="color: #990000">>></span>, <span style="color: #993399">1</span>, <span style="color: #009900">Subprotocols</span>) <span style="font-weight: bold"><span style="color: #0000FF">of</span></span> + <span style="color: #000080">true</span> <span style="color: #990000">-></span> + <span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:set_resp_header</span></span>(<span style="color: #990000"><<</span><span style="color: #FF0000">"sec-websocket-protocol"</span><span style="color: #990000">>></span>, + <span style="color: #990000"><<</span><span style="color: #FF0000">"mqtt"</span><span style="color: #990000">>></span>, <span style="color: #009900">Req0</span>), + {<span style="color: #FF6600">cowboy_websocket</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}; + <span style="color: #000080">false</span> <span style="color: #990000">-></span> + <span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:reply</span></span>(<span style="color: #993399">400</span>, <span style="color: #009900">Req0</span>), + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>} + <span style="font-weight: bold"><span style="color: #0000FF">end</span></span> + <span style="font-weight: bold"><span style="color: #0000FF">end</span></span><span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_post_upgrade_initialization">Post-upgrade initialization</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy has separate processes for handling the connection +and requests. Because Websocket takes over the connection, +the Websocket protocol handling occurs in a different +process than the request handling.</p></div> +<div class="paragraph"><p>This is reflected in the different callbacks Websocket +handlers have. The <code>init/2</code> callback is called from the +temporary request process and the <code>websocket_</code> callbacks +from the connection process.</p></div> +<div class="paragraph"><p>This means that some initialization cannot be done from +<code>init/2</code>. Anything that would require the current pid, +or be tied to the current pid, will not work as intended. +The optional <code>websocket_init/1</code> can be used instead:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_init</span></span>(<span style="color: #009900">State</span>) <span style="color: #990000">-></span> + <span style="font-weight: bold"><span style="color: #000000">erlang:start_timer</span></span>(<span style="color: #993399">1000</span>, <span style="font-weight: bold"><span style="color: #000080">self</span></span>(), <span style="color: #990000"><<</span><span style="color: #FF0000">"Hello!"</span><span style="color: #990000">>></span>), + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>All Websocket callbacks share the same return values. This +means that we can send frames to the client right after +the upgrade:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_init</span></span>(<span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">reply</span>, {<span style="color: #FF6600">text</span>, <span style="color: #990000"><<</span><span style="color: #FF0000">"Hello!"</span><span style="color: #990000">>></span>}, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_receiving_frames">Receiving frames</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy will call <code>websocket_handle/2</code> whenever a text, binary, +ping or pong frame arrives from the client.</p></div> +<div class="paragraph"><p>The handler can handle or ignore the frames. It can also +send frames back to the client or stop the connection.</p></div> +<div class="paragraph"><p>The following snippet echoes back any text frame received and +ignores all others:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_handle</span></span>(<span style="color: #009900">Frame</span> <span style="color: #990000">=</span> {<span style="color: #FF6600">text</span>, <span style="color: #990000">_</span>}, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">reply</span>, <span style="color: #009900">Frame</span>, <span style="color: #009900">State</span>}; +<span style="font-weight: bold"><span style="color: #000000">websocket_handle</span></span>(<span style="color: #009900">_Frame</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Note that ping and pong frames require no action from the +handler as Cowboy will automatically reply to ping frames. +They are provided for informative purposes only.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_receiving_erlang_messages">Receiving Erlang messages</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy will call <code>websocket_info/2</code> whenever an Erlang message +arrives.</p></div> +<div class="paragraph"><p>The handler can handle or ignore the messages. It can also +send frames to the client or stop the connection.</p></div> +<div class="paragraph"><p>The following snippet forwards log messages to the client +and ignores all others:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_info</span></span>({<span style="font-weight: bold"><span style="color: #000080">log</span></span>, <span style="color: #009900">Text</span>}, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">reply</span>, {<span style="color: #FF6600">text</span>, <span style="color: #009900">Text</span>}, <span style="color: #009900">State</span>}; +<span style="font-weight: bold"><span style="color: #000000">websocket_info</span></span>(<span style="color: #009900">_Info</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +</div> +</div> +<div class="sect1"> +<h2 id="_sending_frames">Sending frames</h2> +<div class="sectionbody"> +<div class="paragraph"><p>All <code>websocket_</code> callbacks share return values. They may +send zero, one or many frames to the client.</p></div> +<div class="paragraph"><p>To send nothing, just return an ok tuple:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_info</span></span>(<span style="color: #009900">_Info</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>To send one frame, return a reply tuple with the frame to send:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_info</span></span>(<span style="color: #009900">_Info</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">reply</span>, {<span style="color: #FF6600">text</span>, <span style="color: #990000"><<</span><span style="color: #FF0000">"Hello!"</span><span style="color: #990000">>></span>}, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>You can send frames of any type: text, binary, ping, pong +or close frames.</p></div> +<div class="paragraph"><p>To send many frames at once, return a reply tuple with the +list of frames to send:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_info</span></span>(<span style="color: #009900">_Info</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">reply</span>, [ + {<span style="color: #FF6600">text</span>, <span style="color: #FF0000">"Hello"</span>}, + {<span style="color: #FF6600">text</span>, <span style="color: #990000"><<</span><span style="color: #FF0000">"world!"</span><span style="color: #990000">>></span>}, + {<span style="font-weight: bold"><span style="color: #000080">binary</span></span>, <span style="color: #990000"><<</span><span style="color: #993399">0</span><span style="color: #990000">:</span><span style="color: #993399">8000</span><span style="color: #990000">>></span>} + ], <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>They are sent in the given order.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_keeping_the_connection_alive">Keeping the connection alive</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy will automatically respond to ping frames sent by +the client. They are still forwarded to the handler for +informative purposes, but no further action is required.</p></div> +<div class="paragraph"><p>Cowboy does not send ping frames itself. The handler can +do it if required. A better solution in most cases is to +let the client handle pings. Doing it from the handler +would imply having an additional timer per connection and +this can be a considerable cost for servers that need to +handle large numbers of connections.</p></div> +<div class="paragraph"><p>Cowboy can be configured to close idle connections +automatically. It is highly recommended to configure +a timeout here, to avoid having processes linger longer +than needed.</p></div> +<div class="paragraph"><p>The <code>init/2</code> callback can set the timeout to be used +for the connection. For example, this would make Cowboy +close connections idle for more than 30 seconds:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">cowboy_websocket</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>, #{ + <span style="color: #0000FF">idle_timeout</span> <span style="color: #990000">=></span> <span style="color: #993399">30000</span>}}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>This value cannot be changed once it is set. It defaults to +<code>60000</code>.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_saving_memory">Saving memory</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The Websocket connection process can be set to hibernate +after the callback returns.</p></div> +<div class="paragraph"><p>Simply add an <code>hibernate</code> field to the ok or reply tuples:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_init</span></span>(<span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">State</span>, <span style="color: #FF6600">hibernate</span>}<span style="color: #990000">.</span> + +<span style="font-weight: bold"><span style="color: #000000">websocket_handle</span></span>(<span style="color: #009900">_Frame</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">ok</span>, <span style="color: #009900">State</span>, <span style="color: #FF6600">hibernate</span>}<span style="color: #990000">.</span> + +<span style="font-weight: bold"><span style="color: #000000">websocket_info</span></span>(<span style="color: #009900">_Info</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">reply</span>, {<span style="color: #FF6600">text</span>, <span style="color: #990000"><<</span><span style="color: #FF0000">"Hello!"</span><span style="color: #990000">>></span>}, <span style="color: #009900">State</span>, <span style="color: #FF6600">hibernate</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>It is highly recommended to write your handlers with +hibernate enabled, as this allows to greatly reduce the +memory usage. Do note however that an increase in the +CPU usage or latency can be observed instead, in particular +for the more busy connections.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_closing_the_connection">Closing the connection</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The connection can be closed at any time, either by telling +Cowboy to stop it or by sending a close frame.</p></div> +<div class="paragraph"><p>To tell Cowboy to close the connection, use a stop tuple:</p></div> +<div class="listingblock"> +<div class="content"><!-- Generator: GNU source-highlight 3.1.8 +by Lorenzo Bettini +http://www.lorenzobettini.it +http://www.gnu.org/software/src-highlite --> +<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_info</span></span>(<span style="color: #009900">_Info</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-></span> + {<span style="color: #FF6600">stop</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div> +<div class="paragraph"><p>Sending a <code>close</code> frame will immediately initiate the closing +of the Websocket connection. Note that when sending a list of +frames that include a close frame, any frame found after the +close frame will not be sent.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/ws_protocol/"> + The Websocket protocol + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/streams/"> + Streams + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + diff --git a/docs/en/cowboy/2.2/guide/ws_protocol.asciidoc b/docs/en/cowboy/2.2/guide/ws_protocol.asciidoc new file mode 100644 index 00000000..8fa0673d --- /dev/null +++ b/docs/en/cowboy/2.2/guide/ws_protocol.asciidoc @@ -0,0 +1,69 @@ +[[ws_protocol]] +== The Websocket protocol + +This chapter explains what Websocket is and why it is +a vital component of soft realtime Web applications. + +=== Description + +Websocket is an extension to HTTP that emulates plain TCP +connections between the client, typically a Web browser, +and the server. It uses the HTTP Upgrade mechanism to +establish the connection. + +Websocket connections are fully asynchronous, unlike +HTTP/1.1 (synchronous) and HTTP/2 (asynchronous, but the +server can only initiate streams in response to requests). +With Websocket, the client and the server can both send +frames at any time without any restriction. It is closer +to TCP than any of the HTTP protocols. + +Websocket is an IETF standard. Cowboy supports the standard +and all drafts that were previously implemented by browsers, +excluding the initial flawed draft sometimes known as +"version 0". + +=== Websocket vs HTTP/2 + +For a few years Websocket was the only way to have a +bidirectional asynchronous connection with the server. +This changed when HTTP/2 was introduced. While HTTP/2 +requires the client to first perform a request before +the server can push data, this is only a minor restriction +as the client can do so just as it connects. + +Websocket was designed as a kind-of-TCP channel to a +server. It only defines the framing and connection +management and lets the developer implement a protocol +on top of it. For example you could implement IRC over +Websocket and use a Javascript IRC client to speak to +the server. + +HTTP/2 on the other hand is just an improvement over +the HTTP/1.1 connection and request/response mechanism. +It has the same semantics as HTTP/1.1. + +If all you need is to access an HTTP API, then HTTP/2 +should be your first choice. On the other hand, if what +you need is a different protocol, then you can use +Websocket to implement it. + +=== Implementation + +Cowboy implements Websocket as a protocol upgrade. Once the +upgrade is performed from the `init/2` callback, Cowboy +switches to Websocket. Please consult the next chapter for +more information on initiating and handling Websocket +connections. + +The implementation of Websocket in Cowboy is validated using +the Autobahn test suite, which is an extensive suite of tests +covering all aspects of the protocol. Cowboy passes the +suite with 100% success, including all optional tests. + +Cowboy's Websocket implementation also includes the +permessage-deflate and x-webkit-deflate-frame compression +extensions. + +Cowboy will automatically use compression when the +`compress` option is returned from the `init/2` function. diff --git a/docs/en/cowboy/2.2/guide/ws_protocol/index.html b/docs/en/cowboy/2.2/guide/ws_protocol/index.html new file mode 100644 index 00000000..328eaa74 --- /dev/null +++ b/docs/en/cowboy/2.2/guide/ws_protocol/index.html @@ -0,0 +1,229 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara"> + + <meta name="generator" content="Hugo 0.30.2" /> + + <title>Nine Nines: The Websocket protocol</title> + + <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'> + <link href="/css/99s.css?r=1" rel="stylesheet"> + + <link rel="shortcut icon" href="/img/ico/favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png"> + <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png"> + <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png"> + + +</head> + + +<body class=""> + <header id="page-head"> + <div id="topbar" class="container"> + <div class="row"> + <div class="span2"> + <h1 id="logo"><a href="/" title="99s">99s</a></h1> + </div> + <div class="span10"> + + <div id="side-header"> + <nav> + <ul> + <li><a title="Hear my thoughts" href="/articles">Articles</a></li> + <li><a title="Watch my talks" href="/talks">Talks</a></li> + <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li> + <li><a title="Request my services" href="/services">Consulting & Training</a></li> + </ul> + </nav> + <ul id="social"> + <li> + <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a> + </li> + <li> + <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a> + </li> + <li> + <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a> + </li> + </ul> + </div> + </div> + </div> + </div> + + +</header> + +<div id="contents" class="two_col"> +<div class="container"> +<div class="row"> +<div id="docs" class="span9 maincol"> + +<h1 class="lined-header"><span>The Websocket protocol</span></h1> + +<div class="paragraph"><p>This chapter explains what Websocket is and why it is +a vital component of soft realtime Web applications.</p></div> +<div class="sect1"> +<h2 id="_description">Description</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Websocket is an extension to HTTP that emulates plain TCP +connections between the client, typically a Web browser, +and the server. It uses the HTTP Upgrade mechanism to +establish the connection.</p></div> +<div class="paragraph"><p>Websocket connections are fully asynchronous, unlike +HTTP/1.1 (synchronous) and HTTP/2 (asynchronous, but the +server can only initiate streams in response to requests). +With Websocket, the client and the server can both send +frames at any time without any restriction. It is closer +to TCP than any of the HTTP protocols.</p></div> +<div class="paragraph"><p>Websocket is an IETF standard. Cowboy supports the standard +and all drafts that were previously implemented by browsers, +excluding the initial flawed draft sometimes known as +"version 0".</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_websocket_vs_http_2">Websocket vs HTTP/2</h2> +<div class="sectionbody"> +<div class="paragraph"><p>For a few years Websocket was the only way to have a +bidirectional asynchronous connection with the server. +This changed when HTTP/2 was introduced. While HTTP/2 +requires the client to first perform a request before +the server can push data, this is only a minor restriction +as the client can do so just as it connects.</p></div> +<div class="paragraph"><p>Websocket was designed as a kind-of-TCP channel to a +server. It only defines the framing and connection +management and lets the developer implement a protocol +on top of it. For example you could implement IRC over +Websocket and use a Javascript IRC client to speak to +the server.</p></div> +<div class="paragraph"><p>HTTP/2 on the other hand is just an improvement over +the HTTP/1.1 connection and request/response mechanism. +It has the same semantics as HTTP/1.1.</p></div> +<div class="paragraph"><p>If all you need is to access an HTTP API, then HTTP/2 +should be your first choice. On the other hand, if what +you need is a different protocol, then you can use +Websocket to implement it.</p></div> +</div> +</div> +<div class="sect1"> +<h2 id="_implementation">Implementation</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Cowboy implements Websocket as a protocol upgrade. Once the +upgrade is performed from the <code>init/2</code> callback, Cowboy +switches to Websocket. Please consult the next chapter for +more information on initiating and handling Websocket +connections.</p></div> +<div class="paragraph"><p>The implementation of Websocket in Cowboy is validated using +the Autobahn test suite, which is an extensive suite of tests +covering all aspects of the protocol. Cowboy passes the +suite with 100% success, including all optional tests.</p></div> +<div class="paragraph"><p>Cowboy’s Websocket implementation also includes the +permessage-deflate and x-webkit-deflate-frame compression +extensions.</p></div> +<div class="paragraph"><p>Cowboy will automatically use compression when the +<code>compress</code> option is returned from the <code>init/2</code> function.</p></div> +</div> +</div> + + + + + + + + + + + <nav style="margin:1em 0"> + + <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/resource_design/"> + Designing a resource handler + </a> + + + + <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/ws_handlers/"> + Websocket handlers + </a> + + </nav> + + + + +</div> + +<div class="span3 sidecol"> + + +<h3> + Cowboy + 2.2 + + User Guide +</h3> + +<ul> + + <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li> + + + <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li> + + +</ul> + +<h4 id="docs-nav">Navigation</h4> + +<h4>Version select</h4> +<ul> + + + + <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li> + + <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li> + + <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li> + + <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li> + +</ul> + +</div> +</div> +</div> +</div> + + <footer> + <div class="container"> + <div class="row"> + <div class="span6"> + <p id="scroll-top"><a href="#">↑ Scroll to top</a></p> + <nav> + <ul> + <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li> + </ul> + </nav> + </div> + <div class="span6 credits"> + <p><img src="/img/footer_logo.png"></p> + <p>Copyright © Loïc Hoguin 2012-2016</p> + </div> + </div> + </div> + </footer> + + + <script src="/js/custom.js"></script> + </body> +</html> + + |