Search code examples
google-chromexmlhttprequestcorspreflight

How to prevent Chrome to redirecting AJAX requests to HTTPS?


My AngularJS application is doing many AJAX requests to our services (powered by Jetty). For some reason the following error occurs for SOME users only and goes away when asked to clear the browser cache. This only happens on Google Chrome.

I'm on www.domain.com trying to request api.domain.com.

XMLHttpRequest cannot load http://api.domain.com/my-service. The request was redirected to 'https://api.domain.com/my-service', which is disallowed for cross-origin requests that require preflight. /my-current-page

Note that Chrome is trying to redirect the service from HTTP to HTTPS. My website can be accessed over HTTP or HTTPS

Here is the chrome://net-internals/#events output:

1523417: URL_REQUEST
http://api.domain.com/my-service
Start Time: 2014-08-15 14:17:39.809

t=5984 [st= 0] +REQUEST_ALIVE  [dt=26]
t=5984 [st= 0]   +URL_REQUEST_DELEGATE  [dt=0]
t=5984 [st= 0]      DELEGATE_INFO  [dt=0]
                    --> delegate_info = "extension AdBlock"
t=5984 [st= 0]      DELEGATE_INFO  [dt=0]
                    --> delegate_info = "extension AdBlock"
t=5984 [st= 0]   -URL_REQUEST_DELEGATE
t=5984 [st= 0]   +URL_REQUEST_START_JOB  [dt=26]
                  --> load_flags = 143540480 (DO_NOT_SAVE_COOKIES | DO_NOT_SEND_AUTH_DATA | DO_NOT_SEND_COOKIES | ENABLE_LOAD_TIMING | MAYBE_USER_GESTURE | REPORT_RAW_HEADERS | VERIFY_EV_CERT)
                  --> method = "OPTIONS"
                  --> priority = "LOW"
                  --> url = "http://api.domain.com/my-service"
t=5984 [st= 0]      URL_REQUEST_REDIRECT_JOB
                    --> reason = "HSTS"
t=5985 [st= 1]     +URL_REQUEST_DELEGATE  [dt=25]
t=5985 [st= 1]        DELEGATE_INFO  [dt=25]
                      --> delegate_info = "AsyncResourceHandler"
t=6010 [st=26]     -URL_REQUEST_DELEGATE
t=6010 [st=26]      CANCELLED
t=6010 [st=26]   -URL_REQUEST_START_JOB
                  --> net_error = -3 (ERR_ABORTED)
t=6010 [st=26]    URL_REQUEST_DELEGATE  [dt=0]
t=6010 [st=26] -REQUEST_ALIVE

Any idea why Chrome would force a redirect like that? I can't see anything wrong in the network tab, there is nothing coming back for that request.

More info:

Here is the Response Headers on a working Chrome browser.

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:X-Requested-With, authorization, content-type, X-CSRF-Token
Access-Control-Allow-Methods:GET, POST, HEAD, PUT, OPTIONS
Access-Control-Allow-Origin:http://api.domain.com
Content-Length:0
Server:Jetty(8.y.z-SNAPSHOT)

Solution

  • This could be caused by an extension such as HTTPS everywhere or by Strict Transport Security (HSTS).

    These factors are outside your control, to resolve it you need to modify the server-side API endpoint to serve CORS response headers, e.g.:

    Access-Control-Allow-Origin: http://api.domain.com
    

    ... or just enforce https side-wide. Then you don't need to worry about http/https origin violations. As a bonus, https has recently become one of the positive factors for your site's ranking on Google.


    The log in the question clearly shows that HSTS is the culprit. Chrome's HSTS implementation does not properly work with cross-origin requests at the moment (crbug.com/387198). The only way for website owners to work around this bug is to enforce side-wide https, and access the API over https.

    f you want to reproduce the bug, visit chrome://net-internals/#hsts and add the domain to the HSTS list via the first input box ("Add domain"). Then, after having reproduced the bug, remove the domain from the HSTS list via the second input box ("Delete domain"). This method is also a way for users to work around the bug. After all, if the domain is removed from the HSTS list, then there's no HSTS redirect any more.

    What is HSTS?
    HSTS is activated after the server sends a Strict-Transport-Security header in any of its https responses. After receiving this header once, the browser will force that all resources on the web page are requested over https. For more info, see http://chromium.org/sts and http://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security.

    Since this bug occurs only for some of your users, it is most likely that that it is caused by a browser extension or some page on the API domain that responds with the STS header.