I'm seeing some interesting Chrome behaviour, and I need a hand deciphering what's going on and possibly how to work around it effectively.
Here's the scenario:
User views a list of resources (e.g. TODO items)
User modifies a few of them
User navigates away from my Ember application and then returns via the back button
User sees previous state of resources
When making the initial request for the resources, I'm seeing something like this coming from the browser:
Request
Request Method:GET
Request URL:https://api.server/some_resource?ids%5B%5D=7495&ids%5B%5D=6420&ids%5B%5D=6787...
Status Code:200 OK
Accept:application/json, text/javascript, */*; q=0.01
Accept-Encoding:gzip,deflate
Accept-Language:en-US,en;q=0.8
If-None-Match:"(some md5)"
Referer:https://api.server
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2121.3 Safari/537.36
X-Requested-With:XMLHttpRequest
Response
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Referer,Accept,Content-Type,Authorization
Access-Control-Allow-Methods:GET, POST, PUT, OPTIONS
Cache-Control:max-age=0, private, must-revalidate
Connection:keep-alive
Content-Encoding:gzip
Content-Type:application/json; charset=utf-8
Date:Tue, 12 Aug 2014 14:53:06 GMT
ETag:"(some md5 not matching If-None-Match)"
Server:nginx
Status:200 OK
Strict-Transport-Security:max-age=31536000
Transfer-Encoding:chunked
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-Request-Id:64b7607a-20a8-46f1-906e-0568bffffd15
And the subsequent request when returning to view the resources:
Request
Request Method:GET
Request URL:https://api.server/some_resource?ids%5B%5D=7495&ids%5B%5D=6420&ids%5B%5D=6787...
Status Code:200 OK (from cache)
Accept:application/json, text/javascript, */*; q=0.01
Referer:https://api.server
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2121.3 Safari/537.36
X-Requested-With:XMLHttpRequest
Response
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Referer,Accept,Content-Type,Authorization
Access-Control-Allow-Methods:GET, POST, PUT, OPTIONS
Cache-Control:max-age=0, private, must-revalidate
Content-Encoding:gzip
Content-Type:application/json; charset=utf-8
Date:Tue, 12 Aug 2014 14:53:06 GMT
ETag:"(same md5 as above for initial request)"
Server:nginx
Status:200 OK
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-Request-Id:64b7607a-20a8-46f1-906e-0568bffffd15
X-Runtime:0.160730
Notice on the subsequent request that Chrome is reporting the status as "200 OK (from cache)", which seems to be why I'm seeing this happen.
My homework on this problem has turned up a seemingly related question on SO, which in turn links to You Do Not Understand Browser History. OK, so Chrome isn't validating the etag when the back button is used. How do I work around this? Disabling caching of requests really sucks, and it seems like there should be a more elegant solution.
Related
I am working on a JavaScript application, where I want to read data from an XML file and post them into a HTML file.
My code is producing the following error:
Request URL:http://myServer/dirs/dir/scripts/xml_data.xml
Request Method:POST
Status Code:405 Method Not Allowed
Request Headersview source
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:en,en-US;q=0.8,da;q=0.6
Connection:keep-alive
Content-Length:13
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Host:myServer
Origin:http://myServer
Referer:http://myServer/dirs/dir/inWork.html
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36
X-Requested-With:XMLHttpRequest
Form Dataview sourceview URL encoded
node:xnode-24
Response Headersview source
Allow:GET, HEAD, OPTIONS, TRACE
Cache-Control:private
Content-Length:5309
Content-Type:text/html; charset=utf-8
Date:Thu, 12 Feb 2015 21:06:08 GMT
Server:Microsoft-IIS/8.0
X-Powered-By:ASP.NET
Based on this posting I created a new 'Handler Mapping' and I also adjusted the 'Handler Mapping' for 'StaticFile' to allow the methods: GET,HEAD,POST,DEBUG,PUT,DELETE.
The IIS server was restarted but still the error message appears and the only methods allowed are: GET, HEAD, OPTIONS, TRACE.
So, there is some configuration file or 'Handler Mapping' overriding my settings, or I simply did not consider.
Any suggestions on how to tell the IIS to accept my settings for this XMLHttpRequest?
I have an AngularJS WebAPI application.
As far as I can understand the OPTIONS request is constructed automatically by the browser.
POST http://localhost:3048/Token HTTP/1.1
Host: localhost:3048
Connection: keep-alive
Content-Length: 78
Accept: application/json, text/plain, */*
Origin: http://localhost:2757
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://localhost:2757/Auth/login
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
grant_type=password&username=xxx%40live.com&password=xxx
Response:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 971
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/8.0
Access-Control-Allow-Origin: *
Set-Cookie: .AspNet.Cookies=CpvxrR1gPFNs0vP8GAmcUt0EiKuEzLS1stLl-70O93wsipJkLUZuNdwC8tZc5M0o1ifoCjvnRXKjEBk3nLRbFlbldJLydW2BWonr5JmBjRjXZyKtcc29ggAVhZlc2E-3gGDlyoZLAa5Et8zrAokl8vsSoXmHnsjrxZw0VecB_Ry98Ln84UuKdeHlwSBnfaKKJfsN-u3Rsm6MoEfBO5aAFEekhVBWytrYDx5ks-iVok3TjJgaPc5ex53kp7qrtH3izbjT7HtnrsYYtcfPtmsxbCXBkX4ssCBthIl-NsN2wObyoEqHMpFEf1E9sB86PJhTCySEJoeUJ5u3juTnPlQnHsk1UTcO0tDb39g-_BD-I4FWS5GMwxLNtmut3Ynjir0GndwqsvpEsLls1Y4Pq7UuVCTn7DMO4seb64Sy8oEYkKZYk9tU4tsJuGD2CAIhdSc-lAmTAA78J5NOx23klkiuSe_SSiiZo5uRpas_1CFHjhi1c8ItEMpgeTsvgTkxafq5EOIWKPRxEHbCE8Dv106k5GlKK5BaH6z7ESg5BHPBvY8; path=/; HttpOnly
X-SourceFiles: =?UTF-8?B?QzpcR1xhYmlsaXRlc3Qtc2VydmVyXFdlYlJvbGVcVG9rZW4=?=
X-Powered-By: ASP.NET
Date: Tue, 13 Jan 2015 04:54:55 GMT
{"access_token":"TkJ2trqT ....
Now logged in
I log out which is nothing more than removing the token and log in again. Something happens that is different. Before it did not send the OPTIONS but now it does. Is there something resulting from a previous request/response that would influence the browser to act different the second time I log in?
OPTIONS http://localhost:3048/Token HTTP/1.1
Host: localhost:3048
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:2757
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Access-Control-Request-Headers: accept, authorization, content-type
Accept: */*
Referer: http://localhost:2757/Auth/login
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Response:
HTTP/1.1 400 Bad Request
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 34
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/8.0
X-SourceFiles: =?UTF-8?B?QzpcR1xhYmlsaXRlc3Qtc2VydmVyXFdlYlJvbGVcVG9rZW4=?=
X-Powered-By: ASP.NET
Date: Tue, 13 Jan 2015 04:56:32 GMT
{"error":"unsupported_grant_type"}
If I do a browser reset and reload of the page then it goes back to like before where it does not send OPTIONS the first time and I am able to log in.
Probably I need to change something on the server so it handles options.
BUT why does my browser (Chrome) not send OPTIONS the first time?
Whether the Chrome (or any other browser) sends an OPTIONS request is exactly specified by the CORS specfication:
When the cross-origin request algorithm is invoked, these steps must be followed:
...
2. If the following conditions are true, follow the simple cross-origin request algorithm:
The request method is a simple method and the force preflight flag is unset.
Each of the author request headers is a simple header or author request headers is empty.
3. Otherwise, follow the cross-origin request with preflight algorithm.
Note: Cross-origin requests using a method that is simple with author request headers that are not simple will have a preflight request to ensure that the resource can handle those headers. (Similarly to requests using a method that is not a simple method.)
Your OPTIONS request contains the following request header:
Access-Control-Request-Headers: accept, authorization, content-type
This means that your Angular app has inserted the non-simple Authorization request header, probably as a part of an authentication scheme. Non-simple "author request headers" trigger the OPTIONS request, as you can see in the above quote.
To allow the request to succeed, your server should handle OPTIONS request and respond with:
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Headers: authorization
To learn more about CORS, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS.
When you first login you most likely set the Authorization HTTP header somewhere in your login procedure. On the other side, you forgot to remove this header when the user logs out.
When you try to login again, the Authorization HTTP header is still present. This triggers the browser to perform a preflight request (see explanation of Rob W: https://stackoverflow.com/a/27924344/548020. Considering that you try to login with a grant type password it does not make sense to send an Authorization header, as this implies that you are already authorized (= logged in). Your are basically asking your backend to log you in and at the same time telling your backend that you are already authorized (= logged in).
This can be fixed by simple removing the Authorization HTTP header when the user logs out.
You can also clean your Headers when you login, before sending your POST request:
delete $http.defaults.headers.common['Authorization'];
My app needs to access a resources as in the Request URL however I can see in the Chrome network console that the request is GET (Cancelled)
Request URL:http://localhost:6001/_api/
Request Headers CAUTION: Provisional headers are shown.
Accept:application/json, text/javascript, */*; q=0.01
Cache-Control:max-age=0
Origin:http://127.0.0.1:6001
Referer:http://127.0.0.1:6001/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/33.0.1750.152 Chrome/33.0.1750.152 Safari/537.36
Is there anything wrong in the request? If I access the Request URL and paste it in the browser, the JSON string is returned properly. What could be the reason?
Update:
Prior to the request above here there is a request for this:
Request URL:http://localhost:6001/_api/_session
Request Method:OPTIONS
Status Code:200 OK
Request Headersview source
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept
Access-Control-Request-Method:DELETE
Cache-Control:max-age=0
Connection:keep-alive
Host:localhost:6001
Origin:http://127.0.0.1:6001
Referer:http://127.0.0.1:6001/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/33.0.1750.152 Chrome/33.0.1750.152 Safari/537.36
Response Headersview source
access-control-allow-headers:Authorization, Content-Type, If-None-Match
access-control-allow-methods:GET, HEAD, POST, PUT, DELETE, OPTIONS
access-control-allow-origin:*
access-control-expose-headers:WWW-Authenticate, Server-Authorization
access-control-max-age:86400
cache-control:no-cache
Connection:keep-alive
content-encoding:gzip
content-type:application/json; charset=utf-8
Date:Sun, 06 Apr 2014 04:26:37 GMT
Transfer-Encoding:chunked
vary:accept-encoding
But the status was: A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'http://127.0.0.1:6001' is therefore not allowed access.
You are mixing 127.0.0.1 and localhost which could make it look like xss. Use one or the other but not both.
We have an SPA that draws more javascript modules from a separate backend server, assisted by Require.js. By nature of the XHR loading procedure, pre-flight OPTIONS requests are made to the backend server and the Access-Control-Allow-Origin response is perfectly valid. The process of login and initial module loading work just fine, as expected.
XHR finished loading: "http://backend.cloudapp.net/api/modules/resourceA".
XHR finished loading: "http://backend.cloudapp.net/api/modules/resourceB".
Funny thing is, certain subsequent actions that call for more modules would unexpectedly raise a CORS error in Chrome.
XMLHttpRequest cannot load
http://backend.cloudapp.net/api/modules/resourceC. Origin
https://frontend.cloudapp.net is not allowed by
Access-Control-Allow-Origin.
Which does not make sense, since the previous modules loaded just fine. Even the actual OPTIONS preflight came back proper for resourceC. Some other places in the UI have their modules loading fine too. And Firefox does not appear to suffer from this problem. Has anybody experienced similar CORS errors?
Request/response headers for successful (expected) module
Request URL:http://backend.cloudapp.net/api/modules/resourceA
Request Method:OPTIONS
Status Code:200 OK
Request Headers
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-GB,en-US;q=0.8,en;q=0.6
Access-Control-Request-Headers:accept, origin, content-type
Access-Control-Request-Method:GET
Host:backend.cloudapp.net
Origin:https://frontend.cloudapp.net
Proxy-Connection:keep-alive
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36
Response Headers
Access-Control-Allow-Headers:accept, origin, content-type
Access-Control-Allow-Methods:GET
Access-Control-Allow-Origin:https://frontend.cloudapp.net
Cache-Control:no-cache
Connection:Keep-Alive
Content-Length:0
Date:Wed, 19 Jun 2013 07:12:42 GMT
Expires:-1
Pragma:no-cache
Proxy-Connection:Keep-Alive
Server:Microsoft-IIS/7.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
Request URL:http://backend.cloudapp.net/api/modules/resourceA
Request Method:GET
Status Code:200 OK
Request Headers
Accept:application/json
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-GB,en-US;q=0.8,en;q=0.6
Content-Type:application/json
Host:backend.cloudapp.net
Origin:https://frontend.cloudapp.net
Proxy-Connection:keep-alive
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36
Response Headers
Access-Control-Allow-Origin:https://frontend.cloudapp.net
Cache-Control:no-cache
Connection:Keep-Alive
Content-Length:5048
Content-Type:application/json; charset=utf-8
Date:Wed, 19 Jun 2013 07:12:42 GMT
Expires:-1
Pragma:no-cache
Proxy-Connection:Keep-Alive
Server:Microsoft-IIS/7.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
Request/response headers for unsuccessful module
Request URL:http://backend.cloudapp.net/api/modules/resourceC
Request Method:OPTIONS
Status Code:200 OK
Request Headers
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-GB,en-US;q=0.8,en;q=0.6
Access-Control-Request-Headers:accept, origin, content-type
Access-Control-Request-Method:GET
Host:backend.cloudapp.net
Origin:https://frontend.cloudapp.net
Proxy-Connection:keep-alive
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36
Response Headers
Access-Control-Allow-Headers:accept, origin, content-type
Access-Control-Allow-Methods:GET
Access-Control-Allow-Origin:https://frontend.cloudapp.net
Cache-Control:no-cache
Connection:Keep-Alive
Content-Length:0
Date:Wed, 19 Jun 2013 07:12:59 GMT
Expires:-1
Pragma:no-cache
Proxy-Connection:Keep-Alive
Server:Microsoft-IIS/7.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
Request URL:http://backend.cloudapp.net/api/modules/resourceC
Request Headers
Accept:application/json
Content-Type:application/json
Origin:https://frontend.cloudapp.net
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36
(And browser blocks further action)
Given that Chrome has gone through so many version updates, in addition to us deploying some module resources in a different package manner now in different AWS infrastructure, we no longer experience this problem now.
Inspired from my answer here
It might be worth investigating if any of the failing XHRs are sending any peculiar unicode character. In our case, one of our user's name contained a unicode character and our HTTP proxy wasn't handling it properly thereby leading to a CORS error.
All of a sudden, chrome (v 23.0) began rendering .txt files used to debug curl http requests. There is javascript and html in these files that used to be displayed as text. Now, some of the javascript is causing a redirect. Safari and Firefox are still working as before.
I'm concluding that this is a setting, but did not find any thing related in Chrome settings.
Any ideas where to change a setting like this.
Edit: HTTP Headers:
Request URL:https://mysite.com/debug/checkin_cron/checkin_cron_bu_913.txt
Request Method:GET
Status Code:200 OK
Request Headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Cookie:
Host:mysite.com
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11
Response Headers
Accept-Ranges:bytes
Connection:Keep-Alive
Content-Length:47520
Content-Type:text/plain
Date:Fri, 14 Dec 2012 23:09:00 GMT
Keep-Alive:timeout=3, max=100
Last-Modified:Fri, 14 Dec 2012 22:28:31 GMT
Server:Apache