I have the following situation:
User makes request to PAGE A that displays a form (server stores cache of this page)
User submits the form to CONTROLLER that is used for form submit
CONTROLLER finds an error in user submitted data, sets a cookie ERRORS detailing such, and redirects the user back to PAGE A
PAGE A shows the original content plus the ERRORS (server stores cache of this page)
PAGE A deletes ERRORS cookie
This works, but only if I don't use cache on my system for PAGE A.
Problem is that, after deleting the cookie, browser makes a request to my server without the cookie and gets a 304 Not Modified error and, as a result, the browser still shows the page with the error, instead of without (from the original request). Server stores cache properly (for page that has an error as well as an error-free page).
Basically the server has two cached pages now: PAGE A and PAGE A WITH ERRORS.
Browser, whose last known page was PAGE A WITH ERRORS asks for server a page with conditions of PAGE A, instead of PAGE A WITH ERRORS, since cookie does not exist anymore. But it thinks that the 304 response is about the PAGE A WITH ERRORS, instead of PAGE A. I even checked the data sent by the browser, it knows that it got PAGE A WITH ERRORS with the ERRORS cookie, yet accepts 304 not modified when making requests without that cookie. It does not validate its own cache against the conditions it was created under.
Doesn't browser validate its cache with the cookies it has set?
And is there a workaround for it without setting some GET variables for each request? Another alternative is to tell servers to never cache pages that have such an ERRORS state set, but that would be a hack.
Apparently the solution was to include this as a response header:
Vary: Cookie
This will take cookies into account in caching engines.
EDIT:
There is a problem though: Chrome, Internet Explorer and Firefox work as expected, but Safari and Opera both ignore 'Vary' header when storing and validating cache.
client-side sessions (a.k.a cookies) are probably not sufficient for this scenario...
would suggest server-side sessions instead. Even if Vary headers might work - with $_SESSION you'll be on the save side.
Cache-control: public is probably not what you want. Public essentially says that you're working with static, globally accessible data. It doesn't change per user. It's caching globally because you're claiming that the data is global.
As soon as you start changing per user, caches are having their assumptions violated. 'private' is more akin to what you want.
That will mean that you get less of the good middle-man caching, however. You might be able to hit some middle ground with re-validation, or with appropriate use of Vary headers.
Related
I solved my problem but I don't know why it works. I was hoping someone could shed some light?
I have a WordPress site. If a new user visits the site, they see a generic element on the homepage. When they visit an internal page, a cookie is created. When the user visits the homepage again, they see a customized element based on the cookie.
The problem I was having was that when the user returned to the homepage from an internal page, even though the new cookie was set with the right value, the $COOKIE superglobal was not reset until a refresh was performed. You could naviagte to as many different pages as you'd like, but still the superglobal was not reset until a literal refresh was performed. This was using both setcookie() and the setting the super global directly.
This was fixed by adding session_start() to the header. I thought session_start() affected the SESSION super global. Why did this solution also affect the COOKIE superglobal?
Why did this solution also affect the COOKIE superglobal?
Most likely it didn't, not directly - but by sending different headers regarding caching, it influenced how your browser was instructed to check for changes when displaying the same URL again, whereas before you simply got a stale copy presented from the cache.
it just seemed odd to me that cookies would be cached as well
Well not the cookie itself got "cached" - but the document in which you made any output depending on the cookie was. You still saw the first version of the page you loaded - the PHP code behind this was not executed again, because the browser did not actually request the URL from the server again.
But when the server sent a response header indicating that this page should not be cached (or that the client you check with the server before displaying the resource again) the first time it was loaded - it caused the browser to make a new request when you returned to the page.
The application I'm working with accepts three different types of login. Automatically if the client connects from certain IP-adresses, or a POST request, either from a normal browser rendered form, or towards a JSON reading API-endpoint.
All three options boil down to calling the same functions for registering the user as logged in, and generating a session.
Despite the code paths being the same as far as I can determine, two of these consistently work, while one consistently fails to add a 'Set-Cookie' header to the response, even though the application logic generates a sessionid that gets sent in the reponse body.
Never having needed to dig into how session authentication works to this level of detail, I realise I don't understand. where the 'Set-Cookie' header, should come from. Should application logic always build the header manually? Will PHP do it automatically once session_start() is called? Does Apache do it based on other parts of the header?
I sort of ruled out 1 by failing to find anything with grep -ri "set.cookie" * in the codebase I'm working with.
session_start sends a session cache limiter and a session cookie (or sets a $_GET key with your PHPSESSID).
This function is where the Set-Cookie paramater is sent from. Apache will then pass it back to the browser when it sends the page back.
You need to remember however that storing the cookie is actually up to the browser. By and large they will be set without issue, but certain conditions will stop this from happening, such as the security settings in Internet Explorer or the user rejecting cookies entirely.
Further reading:
http://www.php.net/manual/en/function.session-start.php
http://www.php.net/manual/en/function.session-get-cookie-params.php
http://www.php.net/manual/en/function.session-status.php
I have been working on a login system in php. The thing works pretty well but I have 1 funny Behavior I cant get rid of. Basically if I perform many quick refreshes (hitting f5 like crazy) I get logged out.
This is because the system relies on the server refreshing a cookie in the browser every time a request is issued. I have the feeling that when refreshing very quickly, the request N+1 is issued before the cookie returned by the request N has been saved in the browser. This leads to a misalignment of the info in the provided cookie and the info expected by the server.
In fact if I hit f5 regularly, say once a second, the authenticated state is maintained and everything works fine.
Any1 has ever had a similar problem? As far as u know, is the process saving cookies executed in a different thread in the browser? That would explain my problem I guess.
gracias hombres
It's probably not a problem of saving the cookie, but a problem of aborting the request.
browser sends request to server
server handles request, prepares new cookie, invalidates old cookie
you hit F5
browser aborts request, issues new request with old cookie
server sends response including new coo--
server receives new request with old, invalid cookie
And yeah, that happens. To avoid this causing problems you might want to allow the last two cookies to be reused, but that requires some manual session juggling.
I have a partly inherited web application in PHP and after poking around with Fiddler I have a little more data than before. The problem I'm trying to solve is unwanted logouts on IE6/8 but not FF/Chrome. If a user clicks between different pages, the login data cookies vanish.
The behavior is different in FF vs. IE, and the reported information is different in almost exactly the same way between Fiddler(/IE) and Live HTTP Headers(/FF).
In Firefox the cookies appear to be treated like the PHP specifies: they are created when the user logs in and checks "Remember me", and they are only deleted if the user visits the logout page, and they have a two week expiration date. Live HTTP Headers report nothing different: the cookies are never reported as being changed or deleted when the user clicks between pages.
But with IE, they disappear when the user clicks between different pages, and Fiddler reports,
Cookies / Login
Set-Cookie: *******=deleted; expires=Sun, 29-Jun-2008 21:07:46 GMT; path=; domain=.********.com
Set-Cookie: *******=deleted; expires=Sun, 29-Jun-2008 21:07:46 GMT; path=; domain=.********.com
('deleted' is literally quoted from Fiddler's output. I do not have any place in my code where either value is set to a magic string of 'deleted'.)
Not only do IE and Firefox have different interpretations of how the site is saying but Fiddler and HTTP Live Headers report correspondingly different versions of what the site does.
Is there something special about IE and 'deleted'? This may sound strange, but does IE want cookies to be re-enabled with each page view or something like that?
And how can I appease IE to bless the cookies in question as not deleted by the server unless the user requests it by visiting the logout URL?
What I eventually found was as follows: Firefox and IE were behaving differently because they were treating caching differently when a missing document was within the 14 day Expires: headers that had been set.
Firefox was apparently checking once for missing data, and then not requesting it again.
IE, on the other hand, kept on checking for an item a stylesheet gave the wrong path for, got 404 pages, and the custom 404 page did a boilerplate invitation to log in that triggered the user being logged out (perhaps not the best boilerplate). I guess the stylesheet was cached, but IE kept on asking for items that were missing.
So it was caching differences plus indirect inclusion plus 404 page behavior.
I still don't know what "deleted" came from. (Does PHP supply the word "deleted" if you set a cookie string to an empty value?)
IE won't set a cookie if the host has an underscore in it, but that's not the problem here.
Fiddler doesn't "invent" anything-- if it says that it got a HTTP header setting the cookie to the value "deleted", that means that the server literally sent that.
You might want to take a look at whether or not you have any errant requests going out on the wire that are causing the server to delete the cookies. For instance, in another thread, someone noted that an IMG tag with a source of "" (empty string) would cause IE to send a request for the root of the site, and their homepage deleted the login cookies if visited.
IE6/7/8 currently have a limit of 50 cookies per host, but that's not what you're hitting here either.
Does the URL of the page in question have an underscore in it? I recall IE having problems with cookies from domainnames which don't follow the domain name specification (RFC 1035 check section 2.3.1).
Also there are (where?) some limitation in IE regarding to cookie size and number of cookies per domain. In IE6 I believe the limitation was maximum size of all cookies per domain 4095 bytes and 20 cookies per domain.
The problem might also arise if you use header based redirection where IE could loose track of the cookie.
Btw. the date you provided in the two Set-Cookie directives are they from an old log or does the server really set a cookie with a expire date in the past (which is the usual way to say.. "hey browser delete this cookie as it already expired days ago")
I have a login setup on a site that stores login information in PHP's $_SESSION, and additionally sets a two-week cookie with login information if a checkbox is checked. The user is considered logged in if valid login information is either submitted by POST or either cookie is true.
The behavior on FF3/Chrome is as intended, at least with the "Remember me" checkbox checked: log in anywhere and everywhere on the site you are treated as being logged in.
However, someone working with IE6 said that she logged on one place, clicked around on links to other sections of the site, and was asked to log in again. I ran into some trouble with my (Multiple IE) IE6, but I reproduced similar behavior on IE8, including setting Advanced Privacy Settings->Always allow session cookies, and otherwise set cookie permissions to be as tolerant as I could. The behavior was identical: log in one place in a way that should set both _SESSION and the two-week cookie, click on links to another pages, and the page presents you with a login screen because it doesn't recognize you as logged in. PHP is 5.2.8 on a Gentoo server.
Any suggestions or resources to getting recognized cookies?
--
[Added after checking on traffic with Fiddler:]
Thank you; I have downloaded Fiddler 2.
Fiddler is reporting Set-Cookie: [name]=deleted... on the logouts in question. I'm presently puzzled as to why. The included file that checks and displays a login screen only has one area where it can delete the relevant cookies, inside a conditional if $_GET['logout'] is set. I didn't see that happening, and when I put an error_log() statement inside the conditional before the statements to delete cookies, no additional messages appear to be being logged.
Couple of suggestions
Try using Fiddler or similar to examine the HTTP requests and responses to see the cookies being sent and transmitted. This provide more insight into what is going wrong
Try having your app output a P3P header, e.g. header('P3P: CP="CAO PSA OUR"');
One thing that's kinda subtle that may jump out and bite you is that IE doesn't allow domain names with underscores (ie: developer_1_test.example.com) while other browsers let you get away with this. You're not v.likely to do this in production but it's an easy oversight to make in a development environment where you're setting up a bunch of vhosts for different developers/code branches/etc.
You'll need to be more specific. Find out exactly how you can replicate this behaviour on both browsers, and you've found your bug. For instance, there might be one or two pages where you're failing to call session_start().
It's important to remember that, if your particular $_SESSION variable is not being seen, and causing a redirect to your login, it's most probably part of your system that is broken.
The first thing I check when this happens is that the domain parameter for the setcookie() function is set properly.
I've seen instances where the cookie domain is set to 'example.com' but the site is being accessed via 'www.example.com'.
For example if you logged into the page at example.com, then clicked a link that took you to a page on www.example.com, you would no longer be logged in.
The workaround is to either make sure all your internal linking is consistent or that you set your cookie with '.example.com' which will enable the cookie for all subdomains.
What I eventually found was as follows: Firefox and IE were behaving differently because they were treating caching differently when a missing document was within the 14 day Expires: headers that had been set.
Firefox was apparently checking once for missing data, and then not requesting it again.
IE, on the other hand, kept on checking for an item a stylesheet gave the wrong path for, got 404 pages, and the custom 404 page did a boilerplate invitation to log in that triggered the user being logged out (perhaps not the best boilerplate). I guess the stylesheet was cached, but IE kept on asking for items that were missing.
So it was caching differences plus indirect inclusion plus 404 page behavior.