mirror of
https://github.com/almet/notmyidea.git
synced 2025-04-28 19:42:37 +02:00
379 lines
No EOL
26 KiB
HTML
379 lines
No EOL
26 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
|
|
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
|
|
|
|
<title>Implementing CORS in Cornice - Alexis - Carnets en ligne</title>
|
|
|
|
<meta charset="utf-8" />
|
|
<link href="https://blog.notmyidea.org/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="Alexis - Carnets en ligne Full Atom Feed" />
|
|
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/poole.css"/>
|
|
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/syntax.css"/>
|
|
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/lanyon.css"/>
|
|
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=PT+Serif:400,400italic,700%7CPT+Sans:400">
|
|
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/styles.css"/>
|
|
|
|
|
|
|
|
<style>
|
|
|
|
h1 {
|
|
font-family: "Avant Garde", Avantgarde, "Century Gothic", CenturyGothic, "AppleGothic", sans-serif;
|
|
padding: 80px 50px;
|
|
text-align: center;
|
|
text-transform: uppercase;
|
|
text-rendering: optimizeLegibility;
|
|
color: #202020;
|
|
letter-spacing: .1em;
|
|
text-shadow:
|
|
-1px -1px 1px #111,
|
|
2px 2px 1px #eaeaea;
|
|
}
|
|
|
|
#main {
|
|
text-align: justify;
|
|
text-justify: inter-word;
|
|
}
|
|
#main h1 {
|
|
padding: 10px;
|
|
}
|
|
|
|
.post-headline {
|
|
padding: 15px;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<!-- Target for toggling the sidebar `.sidebar-checkbox` is for regular
|
|
styles, `#sidebar-checkbox` for behavior. -->
|
|
<input type="checkbox" class="sidebar-checkbox" id="sidebar-checkbox">
|
|
<!-- Toggleable sidebar -->
|
|
<div class="sidebar" id="sidebar">
|
|
<div class="sidebar-item">
|
|
<div class="profile">
|
|
<img src="https://blog.notmyidea.org/theme/img/profile.png"/>
|
|
</div>
|
|
</div>
|
|
|
|
<nav class="sidebar-nav">
|
|
<a class="sidebar-nav-item" href="/">Articles</a>
|
|
|
|
<a class="sidebar-nav-item" href="https://www.vieuxsinge.com">Brasserie du Vieux Singe</a>
|
|
<a class="sidebar-nav-item" href="http://blog.notmyidea.org/pages/about.html">A propos</a>
|
|
<a class="sidebar-nav-item" href="https://twitter.com/ametaireau">Messages courts</a>
|
|
<a class="sidebar-nav-item" href="https://github.com/almet">Code</a>
|
|
</nav>
|
|
</div> <div class="wrap">
|
|
<div class="masthead">
|
|
<div class="container">
|
|
<h3 class="masthead-title">
|
|
<a href="https://blog.notmyidea.org/" title="Home">Alexis - Carnets en ligne</a>
|
|
</h3>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="container content">
|
|
<div id="main" class="posts">
|
|
<h1 class="post-title">Implementing CORS in Cornice</h1>
|
|
<span class="post-date">04 février 2013, dans <a class="no-color" href="category/technologie.html">Technologie</a></span>
|
|
<img id="illustration" src="" />
|
|
|
|
<div class="post article">
|
|
<h1>🌟</h1>
|
|
|
|
<div class="note">
|
|
|
|
<div class="admonition-title">
|
|
|
|
Note
|
|
|
|
</div>
|
|
|
|
I'm cross-posting [on the mozilla services
|
|
weblog](https://blog.mozilla.org/services/). Since this is the first
|
|
time we're doing that, I though it could be useful to point you there.
|
|
Check it out and expect more technical articles there in the future.
|
|
|
|
</div>
|
|
|
|
<p>For security reasons, it's not possible to do cross-domain requests. In
|
|
other words, if you have a page served from the domain lolnet.org, it
|
|
will not be possible for it to get data from notmyidea.org.</p>
|
|
<p>Well, it's possible, using tricks and techniques like
|
|
<a href="http://en.wikipedia.org/wiki/JSONP">JSONP</a>, but that doesn't work all
|
|
the time (see <a href="#how-this-is-different-from-jsonp">the section below</a>). I
|
|
remember myself doing some simple proxies on my domain server to be able
|
|
to query other's API.</p>
|
|
<p>Thankfully, there is a nicer way to do this, namely, "Cross Origin
|
|
Resource-Sharing", or <a href="http://www.w3.org/TR/cors/">CORS</a>.</p>
|
|
<h2 id="you-want-an-icecream-go-ask-your-dad-first">You want an icecream? Go ask your dad first.</h2>
|
|
<p>If you want to use CORS, you need the API you're querying to support it;
|
|
on the server side.</p>
|
|
<p>The HTTP server need to answer to the OPTIONS verb, and with the
|
|
appropriate response headers.</p>
|
|
<p>OPTIONS is sent as what the authors of the spec call a "preflight
|
|
request"; just before doing a request to the API, the <em>User-Agent</em> (the
|
|
browser most of the time) asks the permission to the resource, with an
|
|
OPTIONS call.</p>
|
|
<p>The server answers, and tell what is available and what isn't:</p>
|
|
<p><img alt="The CORS flow (from the HTML5 CORS tutorial)" src="images/cors_flow.png"></p>
|
|
<ul>
|
|
<li>
|
|
<p>1a. The User-Agent, rather than doing the call directly, asks the
|
|
server, the API, the permission to do the request. It does so with
|
|
the following headers:</p>
|
|
<ul>
|
|
<li><strong>Access-Control-Request-Headers</strong>, contains the headers the
|
|
User-Agent want to access.</li>
|
|
<li><strong>Access-Control-Request-Method</strong> contains the method the
|
|
User-Agent want to access.</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<p>1b. The API answers what is authorized:</p>
|
|
<ul>
|
|
<li><strong>Access-Control-Allow-Origin</strong> the origin that's accepted. Can
|
|
be * or the domain name.</li>
|
|
<li><strong>Access-Control-Allow-Methods</strong> a <em>list</em> of allowed methods.
|
|
This can be cached. Note than the request asks permission for
|
|
one method and the server should return a list of accepted
|
|
methods.</li>
|
|
<li><strong>Access-Allow-Headers</strong> a list of allowed headers, for all of
|
|
the methods, since this can be cached as well.</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<ol>
|
|
<li>The User-Agent can do the "normal" request.</li>
|
|
</ol>
|
|
</li>
|
|
</ul>
|
|
<p>So, if you want to access the /icecream resource, and do a PUT there,
|
|
you'll have the following flow:</p>
|
|
<div class="highlight"><pre><span></span><span class="o">></span> <span class="k">OPTIONS</span> <span class="o">/</span><span class="n">icecream</span>
|
|
<span class="o">></span> <span class="k">Access</span><span class="o">-</span><span class="n">Control</span><span class="o">-</span><span class="n">Request</span><span class="o">-</span><span class="n">Methods</span> <span class="o">=</span> <span class="n">PUT</span>
|
|
<span class="o">></span> <span class="n">Origin</span><span class="p">:</span> <span class="n">notmyidea</span><span class="p">.</span><span class="n">org</span>
|
|
<span class="o"><</span> <span class="k">Access</span><span class="o">-</span><span class="n">Control</span><span class="o">-</span><span class="n">Allow</span><span class="o">-</span><span class="n">Origin</span> <span class="o">=</span> <span class="n">notmyidea</span><span class="p">.</span><span class="n">org</span>
|
|
<span class="o"><</span> <span class="k">Access</span><span class="o">-</span><span class="n">Control</span><span class="o">-</span><span class="n">Allow</span><span class="o">-</span><span class="n">Methods</span> <span class="o">=</span> <span class="n">PUT</span><span class="p">,</span><span class="k">GET</span><span class="p">,</span><span class="k">DELETE</span>
|
|
<span class="mi">200</span> <span class="n">OK</span>
|
|
</pre></div>
|
|
|
|
|
|
<p>You can see that we have an Origin Header in the request, as well as a
|
|
Access-Control-Request-Methods. We're here asking if we have the right,
|
|
as notmyidea.org, to do a PUT request on /icecream.</p>
|
|
<p>And the server tells us that we can do that, as well as GET and DELETE.</p>
|
|
<p>I'll not cover all the details of the CORS specification here, but bear
|
|
in mind than with CORS, you can control what are the authorized methods,
|
|
headers, origins, and if the client is allowed to send authentication
|
|
information or not.</p>
|
|
<h2 id="a-word-about-security">A word about security</h2>
|
|
<p>CORS is not an answer for every cross-domain call you want to do,
|
|
because you need to control the service you want to call. For instance,
|
|
if you want to build a feed reader and access the feeds on different
|
|
domains, you can be pretty much sure that the servers will not implement
|
|
CORS, so you'll need to write a proxy yourself, to provide this.</p>
|
|
<p>Secondly, if misunderstood, CORS can be insecure, and cause problems.
|
|
Because the rules apply when a client wants to do a request to a server,
|
|
you need to be extra careful about who you're authorizing.</p>
|
|
<p>An incorrectly secured CORS server can be accessed by a malicious client
|
|
very easily, bypassing network security. For instance, if you host a
|
|
server on an intranet that is only available from behind a VPN but
|
|
accepts every cross-origin call. A bad guy can inject javascript into
|
|
the browser of a user who has access to your protected server and make
|
|
calls to your service, which is probably not what you want.</p>
|
|
<h2 id="how-this-is-different-from-jsonp">How this is different from JSONP?</h2>
|
|
<p>You may know the <a href="http://en.wikipedia.org/wiki/JSONP">JSONP</a> protocol.
|
|
JSONP allows cross origin, but for a particular use case, and does have
|
|
some drawbacks (for instance, it's not possible to do DELETEs or PUTs
|
|
with JSONP).</p>
|
|
<p>JSONP exploits the fact that it is possible to get information from
|
|
another domain when you are asking for javascript code, using the
|
|
\<script> element.</p>
|
|
<blockquote>
|
|
<p>Exploiting the open policy for \<script> elements, some pages use
|
|
them to retrieve JavaScript code that operates on dynamically
|
|
generated JSON-formatted data from other origins. This usage pattern
|
|
is known as JSONP. Requests for JSONP retrieve not JSON, but arbitrary
|
|
JavaScript code. They are evaluated by the JavaScript interpreter, not
|
|
parsed by a JSON parser.</p>
|
|
</blockquote>
|
|
<h2 id="using-cors-in-cornice">Using CORS in Cornice</h2>
|
|
<p>Okay, things are hopefully clearer about CORS, let's see how we
|
|
implemented it on the server-side.</p>
|
|
<p>Cornice is a toolkit that lets you define resources in python and takes
|
|
care of the heavy lifting for you, so I wanted it to take care of the
|
|
CORS support as well.</p>
|
|
<p>In Cornice, you define a service like this:</p>
|
|
<p>``` sourceCode python
|
|
from cornice import Service</p>
|
|
<p>foobar = Service(name="foobar", path="/foobar")</p>
|
|
<h1 id="and-then-you-do-something-with-it">and then you do something with it</h1>
|
|
<p>@foobar.get()
|
|
def get_foobar(request):
|
|
# do something with the request.</p>
|
|
<div class="highlight"><pre><span></span><span class="k">To</span><span class="w"> </span><span class="k">add</span><span class="w"> </span><span class="n">CORS</span><span class="w"> </span><span class="n">support</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">resource</span><span class="p">,</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">can</span><span class="w"> </span><span class="k">go</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">way</span><span class="p">,</span><span class="w"> </span><span class="k">with</span><span class="w"> </span><span class="n">the</span><span class="w"></span>
|
|
<span class="n">cors</span><span class="err">\</span><span class="n">_origins</span><span class="w"> </span><span class="k">parameter</span><span class="err">:</span><span class="w"></span>
|
|
|
|
<span class="err">```</span><span class="w"> </span><span class="n">sourceCode</span><span class="w"> </span><span class="n">python</span><span class="w"></span>
|
|
<span class="n">foobar</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Service</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'foobar'</span><span class="p">,</span><span class="w"> </span><span class="k">path</span><span class="o">=</span><span class="s1">'/foobar'</span><span class="p">,</span><span class="w"> </span><span class="n">cors_origins</span><span class="o">=</span><span class="p">(</span><span class="s1">'*'</span><span class="p">,))</span><span class="w"></span>
|
|
</pre></div>
|
|
|
|
|
|
<p>Ta-da! You have enabled CORS for your service. <strong>Be aware that you're
|
|
authorizing anyone to query your server, that may not be what you
|
|
want.</strong></p>
|
|
<p>Of course, you can specify a list of origins you trust, and you don't
|
|
need to stick with *, which means "authorize everyone".</p>
|
|
<h3 id="headers">Headers</h3>
|
|
<p>You can define the headers you want to expose for the service:</p>
|
|
<p>``` sourceCode python
|
|
foobar = Service(name='foobar', path='/foobar', cors_origins=('*',))</p>
|
|
<p>@foobar.get(cors_headers=('X-My-Header', 'Content-Type'))
|
|
def get_foobars_please(request):
|
|
return "some foobar for you"</p>
|
|
<div class="highlight"><pre><span></span><span class="nv">I</span><span class="s1">'</span><span class="s">ve done some testing and it wasn</span><span class="s1">'</span><span class="nv">t</span> <span class="nv">working</span> <span class="nv">on</span> <span class="nv">Chrome</span> <span class="nv">because</span> <span class="nv">I</span> <span class="nv">wasn</span><span class="s1">'</span><span class="s">t</span>
|
|
<span class="nv">handling</span> <span class="nv">the</span> <span class="nv">headers</span> <span class="nv">the</span> <span class="nv">right</span> <span class="nv">way</span> <span class="ss">(</span><span class="nv">The</span> <span class="nv">missing</span> <span class="nv">one</span> <span class="nv">was</span> <span class="nv">Content</span><span class="o">-</span><span class="nv">Type</span>,
|
|
<span class="nv">that</span> <span class="nv">Chrome</span> <span class="nv">was</span> <span class="nv">asking</span> <span class="k">for</span><span class="ss">)</span>. <span class="nv">With</span> <span class="nv">my</span> <span class="nv">first</span> <span class="nv">version</span> <span class="nv">of</span> <span class="nv">the</span>
|
|
<span class="nv">implementation</span>, <span class="nv">I</span> <span class="nv">needed</span> <span class="nv">the</span> <span class="nv">service</span> <span class="nv">implementers</span> <span class="nv">to</span> <span class="nv">explicitely</span> <span class="nv">list</span>
|
|
<span class="nv">all</span> <span class="nv">the</span> <span class="nv">headers</span> <span class="nv">that</span> <span class="nv">should</span> <span class="nv">be</span> <span class="nv">exposed</span>. <span class="k">While</span> <span class="nv">this</span> <span class="nv">improves</span> <span class="nv">security</span>, <span class="nv">it</span>
|
|
<span class="nv">can</span> <span class="nv">be</span> <span class="nv">frustrating</span> <span class="k">while</span> <span class="nv">developing</span>.
|
|
|
|
<span class="nv">So</span> <span class="nv">I</span> <span class="nv">introduced</span> <span class="nv">an</span> <span class="nv">expose</span>\<span class="nv">_all</span>\<span class="nv">_headers</span> <span class="nv">flag</span>, <span class="nv">which</span> <span class="nv">is</span> <span class="nv">set</span> <span class="nv">to</span> <span class="nv">True</span> <span class="nv">by</span>
|
|
<span class="nv">default</span>, <span class="k">if</span> <span class="nv">the</span> <span class="nv">service</span> <span class="nv">supports</span> <span class="nv">CORS</span>.
|
|
|
|
### <span class="nv">Cookies</span> <span class="o">/</span> <span class="nv">Credentials</span>
|
|
|
|
<span class="nv">By</span> <span class="nv">default</span>, <span class="nv">the</span> <span class="nv">requests</span> <span class="nv">you</span> <span class="k">do</span> <span class="nv">to</span> <span class="nv">your</span> <span class="nv">API</span> <span class="nv">endpoint</span> <span class="nv">don</span><span class="s1">'</span><span class="s">t include the</span>
|
|
<span class="nv">credential</span> <span class="nv">information</span> <span class="k">for</span> <span class="nv">security</span> <span class="nv">reasons</span>. <span class="k">If</span> <span class="nv">you</span> <span class="nv">really</span> <span class="nv">want</span> <span class="nv">to</span> <span class="k">do</span>
|
|
<span class="nv">that</span>, <span class="nv">you</span> <span class="nv">need</span> <span class="nv">to</span> <span class="nv">enable</span> <span class="nv">it</span> <span class="nv">using</span> <span class="nv">the</span> <span class="nv">cors</span>\<span class="nv">_credentials</span> <span class="nv">parameter</span>. <span class="nv">You</span>
|
|
<span class="nv">can</span> <span class="nv">activate</span> <span class="nv">this</span> <span class="nv">one</span> <span class="nv">on</span> <span class="nv">a</span> <span class="nv">per</span><span class="o">-</span><span class="nv">service</span> <span class="nv">basis</span> <span class="nv">or</span> <span class="nv">on</span> <span class="nv">a</span> <span class="nv">per</span><span class="o">-</span><span class="nv">method</span> <span class="nv">basis</span>.
|
|
|
|
### <span class="nv">Caching</span>
|
|
|
|
<span class="nv">When</span> <span class="nv">you</span> <span class="k">do</span> <span class="nv">a</span> <span class="nv">preflight</span> <span class="nv">request</span>, <span class="nv">the</span> <span class="nv">information</span> <span class="nv">returned</span> <span class="nv">by</span> <span class="nv">the</span> <span class="nv">server</span>
|
|
<span class="nv">can</span> <span class="nv">be</span> <span class="nv">cached</span> <span class="nv">by</span> <span class="nv">the</span> <span class="nv">User</span><span class="o">-</span><span class="nv">Agent</span> <span class="nv">so</span> <span class="nv">that</span> <span class="nv">it</span><span class="s1">'</span><span class="s">s not redone before each</span>
|
|
<span class="nv">actual</span> <span class="nv">call</span>.
|
|
|
|
<span class="nv">The</span> <span class="nv">caching</span> <span class="nv">period</span> <span class="nv">is</span> <span class="nv">defined</span> <span class="nv">by</span> <span class="nv">the</span> <span class="nv">server</span>, <span class="nv">using</span> <span class="nv">the</span>
|
|
<span class="nv">Access</span><span class="o">-</span><span class="nv">Control</span><span class="o">-</span><span class="nv">Max</span><span class="o">-</span><span class="nv">Age</span> <span class="nv">header</span>. <span class="nv">You</span> <span class="nv">can</span> <span class="nv">configure</span> <span class="nv">this</span> <span class="nv">timing</span> <span class="nv">using</span> <span class="nv">the</span>
|
|
<span class="nv">cors</span>\<span class="nv">_max</span>\<span class="nv">_age</span> <span class="nv">parameter</span>.
|
|
|
|
### <span class="nv">Simplifying</span> <span class="nv">the</span> <span class="nv">API</span>
|
|
|
|
<span class="nv">We</span> <span class="nv">have</span> <span class="nv">cors</span>\<span class="nv">_headers</span>, <span class="nv">cors</span>\<span class="nv">_enabled</span>, <span class="nv">cors</span>\<span class="nv">_origins</span>, <span class="nv">cors</span>\<span class="nv">_credentials</span>,
|
|
<span class="nv">cors</span>\<span class="nv">_max</span>\<span class="nv">_age</span>, <span class="nv">cors</span>\<span class="nv">_expose</span>\<span class="nv">_all</span>\<span class="nv">_headers</span> … <span class="nv">a</span> <span class="nv">fair</span> <span class="nv">number</span> <span class="nv">of</span>
|
|
<span class="nv">parameters</span>. <span class="k">If</span> <span class="nv">you</span> <span class="nv">want</span> <span class="nv">to</span> <span class="nv">have</span> <span class="nv">a</span> <span class="nv">specific</span> <span class="nv">CORS</span><span class="o">-</span><span class="nv">policy</span> <span class="k">for</span> <span class="nv">your</span>
|
|
<span class="nv">services</span>, <span class="nv">that</span> <span class="nv">can</span> <span class="nv">be</span> <span class="nv">a</span> <span class="nv">bit</span> <span class="nv">tedious</span> <span class="nv">to</span> <span class="nv">pass</span> <span class="nv">these</span> <span class="nv">to</span> <span class="nv">your</span> <span class="nv">services</span> <span class="nv">all</span>
|
|
<span class="nv">the</span> <span class="nv">time</span>.
|
|
|
|
<span class="nv">I</span> <span class="nv">introduced</span> <span class="nv">another</span> <span class="nv">way</span> <span class="nv">to</span> <span class="nv">pass</span> <span class="nv">the</span> <span class="nv">CORS</span> <span class="nv">policy</span>, <span class="nv">so</span> <span class="nv">you</span> <span class="nv">can</span> <span class="k">do</span>
|
|
<span class="nv">something</span> <span class="nv">like</span> <span class="nv">that</span>:
|
|
|
|
``` <span class="nv">sourceCode</span> <span class="nv">python</span>
|
|
<span class="nv">policy</span> <span class="o">=</span> <span class="nv">dict</span><span class="ss">(</span><span class="nv">enabled</span><span class="o">=</span><span class="nv">False</span>,
|
|
<span class="nv">headers</span><span class="o">=</span><span class="ss">(</span><span class="s1">'</span><span class="s">X-My-Header</span><span class="s1">'</span>, <span class="s1">'</span><span class="s">Content-Type</span><span class="s1">'</span><span class="ss">)</span>,
|
|
<span class="nv">origins</span><span class="o">=</span><span class="ss">(</span><span class="s1">'</span><span class="s">*.notmyidea.org</span><span class="s1">'</span><span class="ss">)</span>,
|
|
<span class="nv">credentials</span><span class="o">=</span><span class="nv">True</span>,
|
|
<span class="nv">max_age</span><span class="o">=</span><span class="mi">42</span><span class="ss">)</span>
|
|
|
|
<span class="nv">foobar</span> <span class="o">=</span> <span class="nv">Service</span><span class="ss">(</span><span class="nv">name</span><span class="o">=</span><span class="s1">'</span><span class="s">foobar</span><span class="s1">'</span>, <span class="nv">path</span><span class="o">=</span><span class="s1">'</span><span class="s">/foobar</span><span class="s1">'</span>, <span class="nv">cors_policy</span><span class="o">=</span><span class="nv">policy</span><span class="ss">)</span>
|
|
</pre></div>
|
|
|
|
|
|
<h2 id="comparison-with-other-implementations">Comparison with other implementations</h2>
|
|
<p>I was curious to have a look at other implementations of CORS, in django
|
|
for instance, and I found <a href="https://gist.github.com/426829.js">a gist about
|
|
it</a>.</p>
|
|
<p>Basically, this adds a middleware that adds the "rights" headers to the
|
|
answer, depending on the request.</p>
|
|
<p>While this approach works, it's not implementing the specification
|
|
completely. You need to add support for all the resources at once.</p>
|
|
<p>We can think about a nice way to implement this specifying a definition
|
|
of what's supposed to be exposed via CORS and what shouldn't directly in
|
|
your settings. In my opinion, CORS support should be handled at the
|
|
service definition level, except for the list of authorized hosts.
|
|
Otherwise, you don't know exactly what's going on when you look at the
|
|
definition of the service.</p>
|
|
<h2 id="resources">Resources</h2>
|
|
<p>There are a number of good resources that can be useful to you if you
|
|
want to either understand how CORS works, or if you want to implement it
|
|
yourself.</p>
|
|
<ul>
|
|
<li><a href="http://enable-cors.org/">http://enable-cors.org/</a> is useful to get started when you don't
|
|
know anything about CORS.</li>
|
|
<li>There is a W3C wiki page containing information that may be useful
|
|
about clients, common pitfalls etc:
|
|
<a href="http://www.w3.org/wiki/CORS_Enabled">http://www.w3.org/wiki/CORS_Enabled</a></li>
|
|
<li><em>HTML5 rocks</em> has a tutorial explaining how to implement CORS, with
|
|
<a href="http://www.html5rocks.com/en/tutorials/cors/#toc-adding-cors-support-to-the-server">a nice section about the
|
|
server-side</a>.</li>
|
|
<li>Be sure to have a look at the <a href="http://caniuse.com/#search=cors">clients support-matrix for this
|
|
feature</a>.</li>
|
|
<li>About security, <a href="https://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity">check out this
|
|
page</a></li>
|
|
<li>If you want to have a look at the implementation code, check <a href="https://github.com/mozilla-services/cornice/pull/98/files">on
|
|
github</a></li>
|
|
</ul>
|
|
<p>Of course, the W3C specification is the best resource to rely on. This
|
|
specification isn't hard to read, so you may want to go through it.
|
|
Especially the <a href="http://www.w3.org/TR/cors/#resource-processing-model">"resource processing model"
|
|
section</a></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<label for="sidebar-checkbox" class="sidebar-toggle"></label>
|
|
|
|
<script>
|
|
(function(document) {
|
|
var i = 0;
|
|
// snip empty header rows since markdown can't
|
|
var rows = document.querySelectorAll('tr');
|
|
for(i=0; i<rows.length; i++) {
|
|
var ths = rows[i].querySelectorAll('th');
|
|
var rowlen = rows[i].children.length;
|
|
if (ths.length > 0 && ths.length === rowlen) {
|
|
rows[i].remove();
|
|
}
|
|
}
|
|
})(document);
|
|
</script>
|
|
|
|
<script>
|
|
/* Lanyon & Poole are Copyright (c) 2014 Mark Otto. Adapted to Pelican 20141223 and extended a bit by @thomaswilley */
|
|
(function(document) {
|
|
var toggle = document.querySelector('.sidebar-toggle');
|
|
var sidebar = document.querySelector('#sidebar');
|
|
var checkbox = document.querySelector('#sidebar-checkbox');
|
|
document.addEventListener('click', function(e) {
|
|
var target = e.target;
|
|
if(!checkbox.checked ||
|
|
sidebar.contains(target) ||
|
|
(target === checkbox || target === toggle)) return;
|
|
checkbox.checked = false;
|
|
}, false);
|
|
})(document);
|
|
</script>
|
|
<!-- Piwik -->
|
|
<script type="text/javascript">
|
|
var _paq = _paq || [];
|
|
_paq.push(['trackPageView']);
|
|
_paq.push(['enableLinkTracking']);
|
|
(function() {
|
|
var u="//tracker.notmyidea.org/";
|
|
_paq.push(['setTrackerUrl', u+'piwik.php']);
|
|
_paq.push(['setSiteId', 3]);
|
|
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
|
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
|
|
})();
|
|
</script>
|
|
<noscript><p><img src="//tracker.notmyidea.org/piwik.php?idsite=3" style="border:0;" alt="" /></p></noscript>
|
|
<!-- End Piwik Code -->
|
|
</div>
|
|
</body>
|
|
</html> |