Can't logout with the menu item Users > Logout#12504
Can't logout with the menu item Users > Logout#12504demis-palma wants to merge 7 commits intojoomla:stagingfrom
Conversation
…redirect() handle the cache-related headers
libraries/joomla/application/web.php
Outdated
| * | ||
| * @return void | ||
| * | ||
| * @since 3.6.4 |
There was a problem hiding this comment.
@since __DEPLOY_VERSION__
There was a problem hiding this comment.
I suppose that the token __DEPLOY_VERSION__ will be automatically replaced.
There was a problem hiding this comment.
Yes that's correct. It will be replaced with the correct version. (Which won't be 364)
|
you have a lot of unit tests failing here |
|
I see that there are a lot of errors, but I don't understand the cause. |
|
The tests are validating the sent headers. You're making changes that add additional headers, so the expected return no longer matches the actual return. |
| @@ -539,8 +517,12 @@ public function redirect($url, $status = 303) | |||
|
|
|||
| // All other cases use the more efficient HTTP header for redirection. | |||
| $this->header($this->responseMap[$status]); | |||
There was a problem hiding this comment.
This should be changed to setHeader too since you're changing the others below it.
There was a problem hiding this comment.
Yes, but I can't replace $this->header($this->responseMap[$status]); at the moment.
The reason is that sendHeaders() is not designed to deal with statuses as a string like responseMap[$status] are. For example 'HTTP/1.1 301 Moved Permanently'.
It is designed to hold a int code instead (see all occurrences of $app->setHeader('status', ...) everywhere)
So we should turn $responseMap into an array of int first, and I would leave this for a separate PR.
There was a problem hiding this comment.
Well, the only issue is header() will immediately send the header while setHeader() enqueues it for sending. As long as that doesn't cause problems it's fine for now, but I'd suggest commenting in the code why it's this way (even if it's just temporary).
|
yes that is correct. That way the version will be correctly set when it is On 23 October 2016 at 17:41, Demis Palma ツ notifications@github.com wrote:
Brian Teeman |
|
Ok, I used the placeholder In addition, the tests are not satisfactory yet. How to proceed? |
|
Tests OK. To me the PR is complete for the moment. |
|
I've found that 2 months later, this same patch has been proposed (and merged in 2 days) here: #13516 The reasons to keep a patch dormant for 4 months and counting, are beyond my understanding, but it's a pity that someone has to waste his time reinventing something that was already there, waiting to be merged. |
The menu item Users > Logout recently introduced highlights an old time latent problem related to the cache.
Basically, while JApplicationWeb::respond() respects the fact that the page can be cachable or not, JApplicationWeb::redirect() totally ignores that fact.
As a result, redirections can be cached causing weird bugs.
One of them, is the inability to execute the log-out a second time. That is, you can login, then logout, login again, but from here to the cache expiration you won't be able to logout furthermore.
We didn't noticed this up to now, because the "Logout button" submits a form, and a POST request is never cached. The new "Logout menu item" is a GET request instead, which on the contrary can be cached.
Cache problem are tricky to reproduce and debug, due to the different way the various cache layers work and react to different inputs, (such as a simple URL request vs a page refresh). For that reason I'll explain how to reproduce the problem step by step.
I've verified this problem with Google Chrome. In my tests, Mozilla Firefox is not affected. I haven't tested further browsers.
Since the logout button is not affected, the problem can be observed through the Logout menu item, so prepare it. New menu item > Type = Users - Logout. Save and close.
To test this, you need to activate a cache layer between the web server and the client.
While a proxy should be fine for this purpose, I've used Apache module mod_expires instead, which is a common environment in many hosting providers. It's easy con configure and from the browser's point of view, it has a predictable behaviour.
mod_expires configuration follows:
1- Ensure that Apache mod_expires is enabled.
2- Set up the cache in the .htaccess.
This sets a one hour cache to all resources, such as images, js, css. php would be affected as well, but note that Joomla, while generating its HTML output, overrides this general settings by turning off any cache through appropriate HTTP response headers (see JApplicationWeb::respond()).
Open the "Network" console in Google Chrome, and browse any page of the Joomla website.
It's headers contains all the necessary anti-cache elements:
See screenshot n.1.
So far, so good.
Now, login and logout using the "Logout menu item". The logout is successful, but note the absence of the necessary anti-cache elements. Also note the "Expires" date in the future.
See screenshot n.2.
The page can now be cached. We will have big problems soon.
Login again. Now there is no way to Logout by the "Logout menu item". By pressing the Logout menu item we get the page from the cache, and no PHP code is executed server-side.
See screenshot n.3.
The PR proposed simply uniforms the way that JApplicationWeb::respond() and JApplicationWeb::redirect() handle the cache-related headers.
See screenshot n.4.
After applying the PR, the redirect contains all the necessary anti-cache elements.