Cookie created on server not stored on client - http

Given this server response:
HTTP/1.1 200 OK
Date: Fri, 23 Mar 2018 12:17:57 GMT
Access-Control-Allow-Origin: http://localhost:8888
Vary: Origin
Access-Control-Allow-Credentials: true
Set-Cookie: key=value;Version=1
Content-Type: application/json
Content-Length: 276
I thought this cookie (key=value) would be stored on client side and I would be able to view it from Chrome DevTools. However I don't see any cookie there. And the cookie is not included on the further requests made after the requested shown above. So I guess it's not stored.
To store the cookies is not the default behavior of the browser?
I've tried setting the cookie property httpOnly to true with the same results.
How can force the browser to store the cookie without using JS and including it on further requests without any JS interaction?

Related

Cookie is not being passed onto the next request call

Issue:
Cookie set between server.com and CLIENT is not being passed to a CNAME server: abc.server.com.
User's Flow:
CLIENT sends GET request for page data # request URL dev.server.com/myapi for a website that runs on https://abc.mywebsite.com
dev.server.com responds with:
Set-Cookie: MYCOOKIE=asdfasdf1; expires=Tue, 04 May 2021 06:59:32 GMT; domain=.server.com; path=/; SameSite = None; secure; httponly
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://mywebsite.com
Referrer-Policy: strict-origin
On the CLIENT's browser: client makes a POST to a CNAME my-cname-host.server.com
Why isn't the cookie being passed onto this last POST request? It seems domain= is set properly to include the CNAME.

Safari Caching GET request even with disabled cache

I have set all headers that I know of to disable caching (even disabling ETAG) on my server, yet Safari still occasionally (about 50% times) caches my requests.
Workflow
I am implementing oauth 1, so:
Browser makes GET /api/user request
Server returns 405
Browser redirects to 3rd party website to authenticate
Browser is redirected to api/callback which stores some info into cookie.
Browser is redirected back to original route.
Browser makes GET /api/user request which should be successful, however it gets 405 served from disk cache instead.
Request summary from Safari Network Inspector
Summary
URL: http://localhost:3000/api/user
Status: 405 Method Not Allowed
Source: Disk Cache
Request
No request, served from the disk cache.
Response
Transfer-Encoding: Identity
Content-Type: application/json; charset=utf-8
Pragma: no-cache
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0
Vary: Cookie, Accept-Encoding
Date: Wed, 23 Jan 2019 11:34:23 GMT
Content-Encoding: gzip
Expires: Thu, 01 Dec 1994 16:00:00 GMT
Connection: close
x-powered-by: Express
Conclusion
I have no idea what's wrong and I will greatly appreciate any help. My
Safari version is 12.0.2. I wasn't able to replicate this issue with Chrome.
Use Vary: *. This magically solved my problem.
This answer helped me: https://stackoverflow.com/a/2068353/1364158
Alternatively, you can really force browser to load a new version of request by including some meaningless random query arg in your url, e.g. /api/user?ts=18284

Universal Analytics Measurement Protocol respond 200 OK, but no events appers

I am sending events from Winform application to Universal Analytics via Measurement protocol and I use fiddler to inspect the request and response. Everything seems to be OK, but no events appears in Universal Analytics.
My app request:
POST http://www.google-analytics.com/collect HTTP/1.1
Host: www.google-analytics.com
Content-Length: 112
Expect: 100-continue
v=1
&tid=UA-44974825-1
&cid=1aba0888-732f-4690-9a91-d906c94a4a23
&t=exception
&exd=NullReferenceException
&exf=1
Server response:
HTTP/1.1 200 OK
Pragma: no-cache
Expires: Mon, 07 Aug 1995 23:30:00 GMT
Cache-Control: private, no-cache, no-cache=Set-Cookie, proxy-revalidate
Access-Control-Allow-Origin: *
Last-Modified: Sun, 17 May 1998 03:00:00 GMT
X-Content-Type-Options: nosniff
Content-Type: image/gif
Date: Fri, 18 Oct 2013 13:54:39 GMT
Server: Golfe2
Content-Length: 35
Alternate-Protocol: 80:quic
GIF89a�����������,�������D�;
Your request is missing the app name parameter, &an, which is required for sending data to app profiles in Google Analytics via the Measurement Protocol.
The requirements for sending app data to Google Analytics via the Measurement Protocol are documented here:
https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide#apptracking
The GA endpoint will always return 200, even if the request is missing required parameters.
I discovered another reason why no data is being collected: I hadn't upgraded my property to Universal Analytics, yet! Doh!
The root problem here is that you are not formatting your request properly. You need to format your POST body like any other application/x-www-form-urlencoded encoded POST body, all on one line:
v=1&tid=UA-44974825-1&cid=1aba0888-732f-4690-9a91-d906c94a4a23&t=exception&exd=NullReferenceException&exf=1
For anyone who lands here looking for solution to something similar, check this tool: Hit builder to validate the payload data.
I was facing the same issue this tool helped.
(Not sure if this debug tool was available then when this question was posted)

What is Cache-Control: private?

When I visit chesseng.herokuapp.com I get a response header that looks like
Cache-Control:private
Connection:keep-alive
Content-Encoding:gzip
Content-Type:text/css
Date:Tue, 16 Oct 2012 06:37:53 GMT
Last-Modified:Tue, 16 Oct 2012 03:13:38 GMT
Status:200 OK
transfer-encoding:chunked
Vary:Accept-Encoding
X-Rack-Cache:miss
and then I refresh the page and get
Cache-Control:private
Connection:keep-alive
Date:Tue, 16 Oct 2012 06:20:49 GMT
Status:304 Not Modified
X-Rack-Cache:miss
so it seems like caching is working. If that works for caching then what is the point of Expires and Cache-Control:max-age. To add to confusion, when I test the page at https://developers.google.com/speed/pagespeed/insights/ it tells me to "Leverage browser caching".
Cache-Control: private
Indicates that all or part of the response message is intended for a single user and MUST NOT be cached by a shared cache, such as a proxy server.
From RFC2616 section 14.9.1
To answer your question about why caching is working, even though the web-server didn't include the headers:
Expires: [a date]
Cache-Control: max-age=[seconds]
The server kindly asked any intermediate proxies to not cache the contents (i.e. the item should only be cached in a private cache, i.e. only on your own local machine):
Cache-Control: private
But the server forgot to include any sort of caching hints:
they forgot to include Expires (so the browser knows to use the cached copy until that date)
they forgot to include Max-Age (so the browser knows how long the cached item is good for)
they forgot to include E-Tag (so the browser can do a conditional request)
But they did include a Last-Modified date in the response:
Last-Modified: Tue, 16 Oct 2012 03:13:38 GMT
Because the browser knows the date the file was modified, it can perform a conditional request. It will ask the server for the file, but instruct the server to only send the file if it has been modified since 2012/10/16 3:13:38:
GET / HTTP/1.1
If-Modified-Since: Tue, 16 Oct 2012 03:13:38 GMT
The server receives the request, realizes that the client has the most recent version already. Rather than sending the client 200 OK, followed by the contents of the page, it instead tells you that your cached version is good:
304 Not Modified
Your browser did have to suffer the round-trip delay of sending a request to the server, and waiting for the response, but it did save having to re-download the static content.
Why Max-Age? Why Expires?
Because Last-Modified sucks.
Not everything on the server has a date associated with it. If I'm building a page on the fly, there is no date associated with it - it's now. But I'm perfectly willing to let the user cache the homepage for 15 seconds:
200 OK
Cache-Control: max-age=15
If the user hammers F5, they'll keep getting the cached version for 15 seconds. If it's a corporate proxy, then all 67,198 users hitting the same page in the same 15-second window will all get the same contents - all served from close cache. Performance win for everyone.
The virtue of adding Cache-Control: max-age is that the browser doesn't even have to perform a "conditional" request.
if you specified only Last-Modified, the browser has to perform a If-Modified-Since request, and watch for a 304 Not Modified response
if you specified max-age, the browser won't even have to suffer the network round-trip; the content will come right out of the caches.
The difference between "Cache-Control: max-age" and "Expires"
Expires is a legacy (c. 1998) equivalent of the modern Cache-Control: max-age header:
Expires: you specify a date (yuck)
max-age: you specify seconds (goodness)
And if both are specified, then the browser uses max-age:
200 OK
Cache-Control: max-age=60
Expires: 20180403T192837
Any web-site written after 1998 should not use Expires anymore, and instead use max-age.
What is ETag?
ETag is similar to Last-Modified, except that it doesn't have to be a date - it just has to be a something.
If I'm pulling a list of products out of a database, the server can send the last rowversion as an ETag, rather than a date:
200 OK
ETag: "247986"
My ETag can be the SHA1 hash of a static resource (e.g. image, js, css, font), or of the cached rendered page (i.e. this is what the Mozilla MDN wiki does; they hash the final markup):
200 OK
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
And exactly like in the case of a conditional request based on Last-Modified:
GET / HTTP/1.1
If-Modified-Since: Tue, 16 Oct 2012 03:13:38 GMT
304 Not Modified
I can perform a conditional request based on the ETag:
GET / HTTP/1.1
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
304 Not Modified
An ETag is superior to Last-Modified because it works for things besides files, or things that have a notion of date. It just is
RFC 2616, section 14.9.1:
Indicates that all or part of the response message is intended for a single user and MUST NOT be cached by a shared cache...A private (non-shared) cache MAY cache the response.
Browsers could use this information. Of course, the current "user" may mean many things: OS user, a browser user (e.g. Chrome's profiles), etc. It's not specified.
For me, a more concrete example of Cache-Control: private is that proxy servers (which typically have many users) won't cache it. It is meant for the end user, and no one else.
FYI, the RFC makes clear that this does not provide security. It is about showing the correct content, not securing content.
This usage of the word private only controls where the response may be cached, and cannot ensure the privacy of the message content.
The Expires entity-header field gives the date/time after which the response is considered stale.The Cache-control:maxage field gives the age value (in seconds) bigger than which response is consider stale.
Althought above header field give a mechanism to client to decide whether to send request to the server. In some condition, the client send a request to sever and the age value of response is bigger then the maxage value ,dose it means server needs to send the resource to client? Maybe the resource never changed.
In order to resolve this problem, HTTP1.1 gives last-modifided head. The server gives the last modified date of the response to client. When the client need this resource, it will send If-Modified-Since head field to server. If this date is before the modified date of the resouce, the server will sends the resource to client and gives 200 code.Otherwise,it will returns 304 code to client and this means client can use the resource it cached.

HTTP caching in WCF Web API seems inconsistent across browsers

I'm implementing a simple REST service with the WCF Web API and attempt to set HTTP headers in order to cache responses.
For a simple GET like this
http://localhost:49302/my/2
the response headers look like this:
Server: ASP.NET Development Server/10.0.0.0
Date: Tue, 24 Jan 2012 18:18:44 GMT
X-AspNet-Version: 4.0.30319
Content-Length: 233
Cache-Control: max-age=120
Vary: Accept
Expires: Tue, 24 Jan 2012 18:20:44 GMT
Last-Modified: Tue, 24 Jan 2012 18:18:15 GMT
Content-Type: application/xml; charset=utf-8
The intent is that the client should cache the resource for two minutes.
However, using the WCF Web API Test Client, the behavior is inconsistent across various browsers:
In Firefox (9.0.1) the request is cached, and first after two minutes is a new version of the resource displayed. This behavior is as expected.
In Chrome (16.0.912.77 m) the cache headers aren't respected at all. A new version of the resource is being fetched for every GET request. This behavior is not expected (by me, at least).
In Internet Explorer (9) the behavior is the same as in Chrome.
Why doesn't Chrome and IE respect the cache headers?
Is it a bug in the WCF Web API Test Client?
Caching is hard to get right. The fact that a browser may ignore cache directives certainly doesn't help.
According to this document IE never cached any request with a Vary header containing anything but Accept-Encoding and User-Agent
If I test this with a 15 seconds cache period and I just set the MaxAge and MustRevalidate it seems to work fine with IE9, FireFox and Chrome.
Web API HttpResponseMessage:
result = new HttpResponseMessage<Book>(book);
result.Headers.CacheControl = new CacheControlHeaderValue();
result.Headers.CacheControl.MaxAge = TimeSpan.FromSeconds(15);
result.Headers.CacheControl.MustRevalidate = true;
return result;
Response headers:
HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Wed, 25 Jan 2012 09:13:32 GMT
X-AspNet-Version: 4.0.30319
Content-Length: 98
Cache-Control: must-revalidate, max-age=15
Content-Type: application/json; charset=utf-8
Connection: Close
I am not sure the MustRevalidate is really required but it is recommended to use it. See the specs here.
Test to replace localhost with "real domain" so the WCF Test Client or Chrome/IE doesnt have any special tricks for localhost.

Resources