Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why browser do not follow redirects using XMLHTTPRequest and CORS?

I am writing a web application for some service using RESTful API. The API is available at https://api.example and app at https://app.example. Simple GET requests using CORS are working just fine in Chrome and Firefox. Some method accept data via POST and return 303 code with new uri in Location header.

Preflight OPTIONS request is fine:

Request Method:OPTIONS
Status Code:200 OK

Request Headers

Accept:*/*
Accept-Charset:UTF-8,*;q=0.5
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,ru;q=0.6
Access-Control-Request-Headers:origin, authorization, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
DNT:1
Host:api.example
Origin:https://app.example
Referer:https://app.example/app/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.32 (KHTML, like Gecko) Chrome/27.0.1425.0 Safari/537.32 SUSE/27.0.1425.0

Response Headers

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Authorization, Content-Type
Access-Control-Allow-Methods:GET,POST,PUT,DELETE,HEAD,OPTIONS
Access-Control-Allow-Origin:https://app.example
Access-Control-Expose-Headers:*
Access-Control-Max-Age:3628800
Connection:keep-alive
Content-Length:0
Date:Sun, 05 May 2013 15:22:50 GMT
Server:nginx/1.2.5

Then the actual request just stop after receiving 303:

Request URL:https://api.example
Request Method:POST
Status Code:HTTP/1.1 303 See Other

Response headers:

Server:nginx/1.2.5
Location:https://api.example/some_url
Date:Sun, 05 May 2013 15:27:49 GMT
Content-Type:application/json
Content-Length:0
Connection:keep-alive
Access-Control-Max-Age:3628800
Access-Control-Expose-Headers:*
Access-Control-Allow-Origin:https://app.example
Access-Control-Allow-Methods:GET,POST,PUT,DELETE,HEAD,OPTIONS
Access-Control-Allow-Headers:Authorization, Content-Type
Access-Control-Allow-Credentials:true

By RFC user agent should follow redirects, but Chrome and FF seems doesn't behave as expected. Is it a browsers' bug or I am doing something wrong?

update: If I start chromium with --disable-web-security everything works fine.

like image 256
galadog Avatar asked May 05 '13 15:05

galadog


People also ask

Does XMLHttpRequest follow redirect?

XMLHttpRequest will automatically follow the redirect. What data are you trying to retrieve? Be careful you may need CORS for both the redirect and the page it is redirected to (with redirects, like POST's, it might not work at all, see the linked answer in the other comments).

Does CORS apply to redirect?

Simple CORS requests will follow redirects. Preflight requests will not follow redirects. If the redirect is to the same server as the original request, the Origin header will stay the same. Otherwise, the Origin header will be set to null .

How do I fix redirect is not allowed for a preflight request?

Check the URL in the Location response header in the response to the OPTIONS request. Change your code to make the request to that other URL directly instead.


2 Answers

I've been wrestling with this, too. It appears that 3xx redirects for preflighted CORS requests are forbidden by the spec.

http://www.w3.org/TR/cors/

From the spec:

(Step 1. and 2. detail the preflighting process. And the we come to step...)

...3. 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.

And then if we scroll on down to http://www.w3.org/TR/cors/#cache-and-network-error-steps:

Whenever the network error steps are applied, terminate the algorithm that invoked this set of steps and set the cross-origin request status to network error.

Note: This has no effect on setting of user credentials. I.e. if the block cookies flag is unset, cookies will be set by the response.

Whenever the cache and network error steps are applied, follow these steps:

Remove the entries in the preflight result cache where origin field value is a case-sensitive match for source origin and url field value is a case-sensitive match for request URL.

Apply the network error steps acting as if the algorithm that invoked the cache and network error steps invoked the network error steps instead.

(Emphasis taken from the doc.)

3xx redirects are, however, permitted for simple CORS requests.

like image 171
nothankyou Avatar answered Oct 19 '22 06:10

nothankyou


If its the chromium bug here is the possible errors on your code given by chromium suport:

  1. If a same-origin request causes a redirect to a different origin,
    do not enforce access control checks for the redirect response
    itself, because the request which resulted in the redirect was
    same-origin.

  2. If a same-origin request causes a redirect to a different origin,
    use the original request's URL as the origin for the new request do not use a unique security origin.

  3. Track whether the client (i.e., XMLHttpRequest) actually requested
    that credentials be sent in the first place. When a same-origin request redirects to a different origin, the original request will send cookies whether requested or not, because it is same-origin. The new cross-origin request should not send cookies unless they were requested, so that the access control checks on the response will succeed if the server granted "Access-Control-Allow-Origin=*".

like image 31
João Beirão Avatar answered Oct 19 '22 05:10

João Beirão