30
votes

From what I've read about CORS, I understand it should work as follows:

  1. Script on a client side tries to fetch a resource from a server with different origin.
  2. Browser intercepts this request and first makes preflight OPTIONS request to the same URL.
  3. If response to this preflight request contains appropriate headers (e.g. Access-Control-Allow-Origin: *), browser understands it's allowed to send main request and does it.
  4. Response is returned to the client script.

I've set up a test for it like this:

  • server in Go accepting both - GET and OPTIONS requests (checked using CURL) - and setting Access-Control-* headers in response
  • simple HTML page (served by another server on another port) with the following script in it ($ stands for jQuery):

    $.ajax({
      type: "GET",
      crossDomain: true,
      url: "http://local.site.com/endpoint,
      success: function (data) {
        alert(data);
      },
      error: function (request, error) {
        alert(error);
      }
    });
    

When I call this method, however, I see only one GET and no preflight OPTIONS request in the Network tab in both - Chrome 49 and Firefox 33.

Here are details of my GET request from Chrome:

Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8,ru;q=0.6
Connection:keep-alive
Host:local.adform.com
Origin:http://localhost:7500
Referer:http://localhost:7500/test-page.html
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36

and corresponding response:

Access-Control-Allow-Headers:Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization
Access-Control-Allow-Methods:POST, GET, OPTIONS, PUT, DELETE
Access-Control-Allow-Origin:*
Content-Length:2
Content-Type:text/plain; charset=utf-8
Date:Wed, 03 Aug 2016 10:53:19 GMT

Any thoughts on why my browser(s) don't send preflight request?

1
preflight is not always done, less likely (if at all?) with a GET - see documentation for when preflight is requiredJaromanda X
See this for more info on when a browser issues a preflight request.robertklep
@JaromandaX: Thanks for remark. If preflight request is not always required, what is the (conventional) way to overcome "same-origin" policy? The scenario is: we create a script that will be incorporated into 3rd party websites and will send us our cookies? As far as I understand, without preflight request browser won't send cookies to our servers, right?ffriend
see the next section in the doc I linked - request with credentialsJaromanda X
I would recommend reading the whole page - it's informativeJaromanda X

1 Answers

16
votes

As pointed out by commentators, with GET browser doesn't always send preflight OPTIONS request. If preflight is indeed needed, one way to make browser to send it is to set custom header (e.g. "X-PINGOVER: pingpong" or whatever). Note, that server should also allow this request header by adding it to "Access-Control-Allow-Headers" response header.


My underlying goal was to pass cookies with domain a.com to servers of a.com, but from a page of another site(s) b.com (common use case for this is tracking your users on 3rd party websites). It turns out to send cookies alongside the request a bit more work is involved.

On the client side (i.e. in JavaScript) one needs to enable cross domain request and allow passing credentials. E.g. the following request with jQuery worked for me:

$.ajax({
  type: "GET",
  url: "http://example.com",
  xhrFields: {
    withCredentials: true           // allow passing cookies
  },
  crossDomain: true,                // force corss-domain request                
  success: function (data) { ... },
  error: function (request, error) { ... }
});

On the server side one needs to set 2 response headers:

  • Access-Control-Allow-Credentials: true
  • Access-Control-Allow-Origin: <requester origin>

where <requester origin> is protocol + host + port of a website that performed a call. Note, that generic * may not work in many browsers, so it makes sense for server to parse Referer header of request and respond with specific allowed origin.