HTTP 302 Redirect to a CORS request is dropped by browsers

Manoj Saxena picture Manoj Saxena · Mar 7, 2015 · Viewed 18.2k times · Source

I am loading a HTML page with some javascript from site A.

Javascript sends a HTTP GET request to site B. At this point:
    - browser sends OPTIONS request to site B
    - Site B responds to OPTIONS request
    - Browser then sends original HTTP GET request to site B
    - Site B responds with HTTP 302 with location set to site C.

At this point Browser stops processing the request. I was expecting it to send the HTTP OPTIONS request to site C just like it did when it sent request to Site B. But it didn't. I observed the same behaviour on Firefox and Chrome.

I would like to understand why browsers are behaving in this manner. I understand there should be some checks or max redirects to prevent loops but not limited 2 redirect requests.

Also why the header information is NOT sent to Javascript code so that application can do something about it. It is simply dropped by browser although it teases you by showing the HTTP 302 Response from site C with Location URL in browser console.

XMLHttpRequest cannot load https://siteB/... The request was redirected to 'https://siteC/..', which is disallowed for cross-origin requests that require preflight.

Any insights to the design are sincerely appreciated.

Regards

Answer

Mathis Gardon picture Mathis Gardon · May 12, 2015

Well, I had the same problem you did, and unfortunately, this behavior is normal, according to W3C spec

This spec describes the behavior of the browser regarding CORS as a machine state, and if you jump to step 3 (doing the actual request), it clearly states :

This is the actual request. Apply the make a request steps and observe the request rules below while making the request.

If the response has an HTTP status code of 301, 302, 303, 307, or 308 Apply the cache and network error steps.

So if I understand correctly, we can't expect the browser to automatically follow the redirect in case of a CORS (supposedly, as the OPTION has granted access to another resource ? But then why not automatically send another OPTION request to this resource ?).

What's worse, as the HEADERS of the response are hidden by the browser after the automatic redirect failed for the reason above, we don't have access to the Location header to handle the subsequent call to the correct resource ourselves. So there is no way to fetch the actual resource in this case.

I consider this a bug, but I couldn't find any good post on the subject on the web.

One workaround, if possible for you, is to not do a CORS request but instead use a simple request (according to the spec again, such as a simple GET with no custom headers), that will not cause any preflight requests to be sent : in this case, the redirect works normally (automatically followed by the browser).

Otherwise, you could see if you can tune your server to not respond 302 in case of a CORS-kind of request, but instead respond with a custom HTTP code that you can identify in your client to include the redirect Location in the content of the response to let your client follow it manually.

If anybody has any valid information about why this behavior is, please give your input :-)

Hope it helps.