Skip to content

Commit

Permalink
Fixed pages with session messages should never be cached [#3108]
Browse files Browse the repository at this point in the history
  • Loading branch information
mahagr committed Dec 22, 2020
1 parent 2923658 commit d1925c8
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* Fixed port issue with `system.custom_base_url`
* Hide errors with `exif_read_data` in `ImageFile`
* Fixed unserialize in `MarkdownFormatter` and `Framework\File` classes
* Fixed pages with session messages should never be cached [#3108](https://github.com/getgrav/grav/issues/3108)

# v1.7.0-rc.20
## 12/15/2020
Expand Down
27 changes: 24 additions & 3 deletions system/src/Grav/Common/Grav.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use Grav\Framework\DI\Container;
use Grav\Framework\Psr7\Response;
use Grav\Framework\RequestHandler\RequestHandler;
use Grav\Framework\Session\Messages;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use RocketTheme\Toolbox\Event\Event;
Expand Down Expand Up @@ -252,25 +253,35 @@ public function process()
);

$default = static function () {
return new Response(404, ['Expires' => 0, 'Cache-Control' => 'no-cache, no-store, must-revalidate'], 'Not Found');
return new Response(404, ['Expires' => 0, 'Cache-Control' => 'no-store, max-age=0'], 'Not Found');
};

$collection = new RequestHandler($this->middleware, $default, $container);

$response = $collection->handle($this['request']);
$body = $response->getBody();

/** @var Messages $messages */
$messages = $this['messages'];

// Prevent caching if session messages were displayed in the page.
$noCache = $messages->isCleared();
if ($noCache) {
$response = $response->withHeader('Cache-Control', 'no-store, max-age=0');
}

// Handle ETag and If-None-Match headers.
if ($response->getHeaderLine('ETag') === '1') {
$etag = md5($body);
$response = $response->withHeader('ETag', $etag);

if ($this['request']->getHeaderLine('If-None-Match') === $etag) {
if ($noCache === false && $this['request']->getHeaderLine('If-None-Match') === $etag) {
$response = $response->withStatus(304);
$body = '';
}
}

// Echo page content.
$this->header($response);
echo $body;

Expand Down Expand Up @@ -312,17 +323,27 @@ public function close(ResponseInterface $response): void

$body = $response->getBody();

/** @var Messages $messages */
$messages = $this['messages'];

// Prevent caching if session messages were displayed in the page.
$noCache = $messages->isCleared();
if ($noCache) {
$response = $response->withHeader('Cache-Control', 'no-store, max-age=0');
}

// Handle ETag and If-None-Match headers.
if ($response->getHeaderLine('ETag') === '1') {
$etag = md5($body);
$response = $response->withHeader('ETag', $etag);

if ($request->getHeaderLine('If-None-Match') === $etag) {
if ($noCache === false && $request->getHeaderLine('If-None-Match') === $etag) {
$response = $response->withStatus(304);
$body = '';
}
}

// Echo page content.
$this->header($response);
echo $body;
exit();
Expand Down
8 changes: 4 additions & 4 deletions system/src/Grav/Common/Service/SessionServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
use Grav\Common\Session;
use Grav\Common\Uri;
use Grav\Common\Utils;
use Grav\Framework\Session\Messages;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use RocketTheme\Toolbox\Session\Message;

/**
* Class SessionServiceProvider
Expand Down Expand Up @@ -113,14 +113,14 @@ public function register(Container $container)
$debugger = $c['debugger'];
$debugger->addMessage('Inactive session: session messages may disappear', 'warming');

return new Message;
return new Messages();
}

/** @var Session $session */
$session = $c['session'];

if (!isset($session->messages)) {
$session->messages = new Message;
if (!$session->messages instanceof Messages) {
$session->messages = new Messages();
}

return $session->messages;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ protected function createJsonResponse(array $content, int $code = null, array $h
}
$headers = ($headers ?? []) + [
'Content-Type' => 'application/json',
'Cache-Control' => 'no-cache, no-store, must-revalidate'
'Cache-Control' => 'no-store, max-age=0'
];

return new Response($code, $headers, json_encode($content));
Expand Down
132 changes: 132 additions & 0 deletions system/src/Grav/Framework/Session/Messages.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php

/**
* @package Grav\Framework\Session
*
* @copyright Copyright (C) 2015 - 2020 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

namespace Grav\Framework\Session;

use Grav\Framework\Compat\Serializable;

/**
* Implements session messages.
*/
class Messages implements \Serializable
{
use Serializable;

/** @var array */
protected $messages = [];
protected $isCleared = false;

/**
* Add message to the queue.
*
* @param string $message
* @param string $scope
* @return $this
*/
public function add(string $message, string $scope = 'default'): Messages
{
$key = md5($scope . '~' . $message);
$item = ['message' => $message, 'scope' => $scope];

// don't add duplicates
if (!array_key_exists($key, $this->messages)) {
$this->messages[$key] = $item;
}

return $this;
}

/**
* Clear message queue.
*
* @param string|null $scope
* @return $this
*/
public function clear(string $scope = null): Messages
{
if ($scope === null) {
if ($this->messages !== []) {
$this->isCleared = true;
$this->messages = [];
}
} else {
foreach ($this->messages as $key => $message) {
if ($message['scope'] === $scope) {
$this->isCleared = true;
unset($this->messages[$key]);
}
}
}

return $this;
}

/**
* @return bool
*/
public function isCleared(): bool
{
return $this->isCleared;
}

/**
* Fetch all messages.
*
* @param string|null $scope
* @return array
*/
public function all(string $scope = null): array
{
if ($scope === null) {
return array_values($this->messages);
}

$messages = [];
foreach ($this->messages as $message) {
if ($message['scope'] === $scope) {
$messages[] = $message;
}
}

return $messages;
}

/**
* Fetch and clear message queue.
*
* @param string|null $scope
* @return array
*/
public function fetch(string $scope = null): array
{
$messages = $this->all($scope);
$this->clear($scope);

return $messages;
}

/**
* @return array
*/
public function __serialize(): array
{
return [
'messages' => $this->messages
];
}

/**
* @param array $data
* @return void
*/
public function __unserialize(array $data): void
{
$this->messages = $data['messages'];
}
}

0 comments on commit d1925c8

Please sign in to comment.