[99s-extend] Response headers
Phillips, Christopher
Christopher.Phillips at turner.com
Wed Apr 3 22:35:36 CEST 2013
Sure. Right now, Cowboy doesn't parse the headers, but you can manually
parse them in your handler. I've got them working in my implementation
pretty well, I'll try and break it down a bit here.
A good, basic overview of what the requests the browser will send, and
what your responses should look like, is here:
https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
HANDLING PRE-FLIGHTS -
Pre-flights are the OPTION requests the browser automatically sends off
when you make a CORS request using a verb other than GET, or POST with one
of three acceptable content types. They're defined well in the above link.
You can read off the requested headers the actual call wants to send in
the OPTIONS preflight with
{Headers, NewRequest } =
cowboy_req:header(<<"access-control-request-headers">>, Request)
Headers will either be the binary, or undefined. If the binary, you
either need to manually parse it and choose to allow/disallow the request
from continuing based on it, or, if you just want to allow all headers
trivially, just pipe that back into the request, a la -
Request2 =
cowboy_req:set_resp_header(<<"access-control-allow-headers">>,
binary_to_list(Headers), NewRequest)
(As a reminder, it can be undefined. You'll need to check for that
before passing it into the above. If it's undefined, you don't need to add
the access-control-allow-headers header).
As part of the pre-flight request, you also need to handle what methods
are allowed. This looks something like -
PreflightedRequest =
cowboy_req:set_resp_header(<<"access-control-allow-methods">>, <<"GET,
POST, DELETE, PUT">>, Request2)
If I wanted to allow gets, posts, deletes, and puts. You can also choose
to read off the access-control-request-method header sent from the client,
but I don't see the point; your list of allowed methods doesn't need to
change based on that (the user is requesting a POST, why does that change
whether you allow a POST or not? But I digress).
FOR ALL CALLS (both pre-flights and the actual call)
Respond with acceptable origin. If you want any domain to access this
resource (not advised, unless this is a public, readonly resource, but
good for testing), you can do -
NewRequest =
cowboy_req:set_resp_header(<<"access-control-allow-origin">>, <<"*">>,
Request)
If you want to filter out the allowed domains, it looks like -
Origin = cowboy_req:header(<<"origin">>, Request) %Get the origin that
the browser sent you
%Do logic to check Origin, and any other data that would decide
whether this request is allowed; it will only apply on a CORS request from
another browser.
%If it passes, pass Origin back as the value for the
access-control-allow-origin header.
NewRequest =
cowboy_req:set_resp_header(<<"access-control-allow-origin">>, Origin,
Request)
FOR ONLY THE ACTUAL CALL
If you want to send custom headers back to your Javascript client (or
read any standard header beyond content-type), you need to explicitly
allow them. This looks like (if I wanted to expose the 'server' header so
my client Javascript can see that it's Cowboy on the backend) -
ExposedHeaderRequest =
cowboy_req:set_resp_header(<<"access-control-expose-headers">>,
<<"server">>, Request)
That's basically it I believe. There is also a max age, and a allow
credentials header (which is really more of a require credentials);
they're pretty straightforwardly explained on that page I linked above,
but I haven't played with them personally.
Caveats I ran into were largely being aware that same domain requests do
NOT supply any of the CORS headers, not even the origin header (so you can
get undefined and have to handle those cases), as well as understanding
the ramifications of allowing cross domain requests. Also, if you want to
develop while disconnected (or if it's not easy to grab another domain),
use your hosts file to declare a fake domain pointed to 127.0.0.1, load
your page from that, explicitly define your AJAX calls to localhost. Note
too that there is a bug in Firefox at present when you try and get all the
request headers. It returns an empty list. You can get individual ones if
you know the name (I.e., getResponseHeader("server") will work,
getAllResponseHeaders() returns an empty string). This is further
compounded by jQuery building its own XHR that loads headers by calling
getAllResponseHeaders, so in Firefox, using jQuery, you can get back zero
headers. Don't know if that affects you, but it's an issue it took me a
good while to diagnose, and which we've had to bear in mind.
On 4/3/13 3:33 PM, "Lee Sylvester" <lee.sylvester at gmail.com> wrote:
>Hi list,
>
>I'd like to set up my handler to use CORS. Can anyone tell me how I can
>modify the headers for my handler to support this?
>
>Thanks loads,
>Lee
>_______________________________________________
>Extend mailing list
>Extend at lists.ninenines.eu
>http://lists.ninenines.eu:81/listinfo/extend
>
More information about the Extend
mailing list