Issue #2217371 by Wim Leers: Expose cache tags to reverse proxies: X-Drupal-Cache-Tags header (by just slightly changing an existing header).
parent
4a1ff2d485
commit
0b6e47e23d
|
@ -18,6 +18,7 @@ use Symfony\Component\Yaml\Exception\ParseException;
|
|||
use Drupal\Component\PhpStorage\PhpStorageFactory;
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Datetime\DrupalDateTime;
|
||||
use Drupal\Core\EventSubscriber\HtmlViewSubscriber;
|
||||
use Drupal\Core\Routing\GeneratorNotInitializedException;
|
||||
use Drupal\Core\Template\Attribute;
|
||||
use Drupal\Core\Render\Element;
|
||||
|
@ -3169,7 +3170,7 @@ function drupal_page_set_cache(Response $response, Request $request) {
|
|||
// because by the time it is read, the configuration might change.
|
||||
'page_compressed' => $page_compressed,
|
||||
),
|
||||
'tags' => array('content' => TRUE) + drupal_cache_tags_page_get($response),
|
||||
'tags' => HtmlViewSubscriber::convertHeaderToCacheTags($response->headers->get('X-Drupal-Cache-Tags')),
|
||||
'expire' => Cache::PERMANENT,
|
||||
'created' => REQUEST_TIME,
|
||||
);
|
||||
|
@ -4417,23 +4418,6 @@ function drupal_render_collect_cache_tags($element, $tags = array()) {
|
|||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache tags that were stored during drupal_render_page().
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Response $response
|
||||
* The response object.
|
||||
* @return array
|
||||
* An array of cache tags.
|
||||
*
|
||||
* @see \Drupal\Core\EventSubscriber\HtmlViewSubscriber::onHtmlPage()
|
||||
*/
|
||||
function drupal_cache_tags_page_get(Response $response) {
|
||||
if (($tags = $response->headers->get('cache_tags')) && $tags = unserialize($tags)) {
|
||||
return $tags;
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the cache ID for a renderable element.
|
||||
*
|
||||
|
|
|
@ -77,7 +77,7 @@ class HtmlViewSubscriber implements EventSubscriberInterface {
|
|||
// recommended.
|
||||
$response = new Response((string) $this->pageRenderer->render($page), $page->getStatusCode());
|
||||
if ($tags = $page->getCacheTags()) {
|
||||
$response->headers->set('cache_tags', serialize($tags));
|
||||
$response->headers->set('X-Drupal-Cache-Tags', static::convertCacheTagsToHeader($tags));
|
||||
}
|
||||
if ($keys = $page->getCacheKeys()) {
|
||||
$response->headers->set('cache_keys', serialize($keys));
|
||||
|
@ -105,4 +105,60 @@ class HtmlViewSubscriber implements EventSubscriberInterface {
|
|||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a cache tags array into a X-Drupal-Cache-Tags header value.
|
||||
*
|
||||
* @param array $tags
|
||||
* Associative array of cache tags to flatten.
|
||||
*
|
||||
* @return string
|
||||
* A space-separated list of flattened cache tag identifiers.
|
||||
*/
|
||||
public static function convertCacheTagsToHeader(array $tags) {
|
||||
$flat_tags = array();
|
||||
foreach ($tags as $namespace => $values) {
|
||||
if (is_array($values)) {
|
||||
foreach ($values as $value) {
|
||||
$flat_tags[] = "$namespace:$value";
|
||||
}
|
||||
}
|
||||
else {
|
||||
$flat_tags[] = "$namespace:$values";
|
||||
}
|
||||
}
|
||||
return implode(' ', $flat_tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a X-Drupal-Cache-Tags header value into a cache tags array.
|
||||
*
|
||||
* @param string $tags_header
|
||||
* A space-separated list of flattened cache tag identifiers.
|
||||
*
|
||||
* @return array
|
||||
* Associative array of cache tags to flatten.
|
||||
*/
|
||||
public static function convertHeaderToCacheTags($tags_header) {
|
||||
if (!is_string($tags_header) || strlen(trim($tags_header)) == 0) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$flat_tags = explode(' ', trim($tags_header));
|
||||
$tags = array();
|
||||
foreach ($flat_tags as $flat_tag) {
|
||||
list($namespace, $value) = explode(':', $flat_tag);
|
||||
if (!isset($tags[$namespace])) {
|
||||
$tags[$namespace] = $value;
|
||||
}
|
||||
// Multiple values in this namespace.
|
||||
else {
|
||||
if (!is_array($tags[$namespace])) {
|
||||
$tags[$namespace] = array($tags[$namespace]);
|
||||
}
|
||||
$tags[$namespace][] = $value;
|
||||
}
|
||||
}
|
||||
return $tags;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -55,7 +55,11 @@ class DefaultHtmlFragmentRenderer implements HtmlFragmentRendererInterface {
|
|||
$page->setBodyBottom(drupal_render($page_array['page_bottom']));
|
||||
$page->setContent(drupal_render($page_array));
|
||||
// Collect cache tags for all the content in all the regions on the page.
|
||||
$page->setCacheTags($page_array['#cache']['tags']);
|
||||
$tags = $page_array['#cache']['tags'];
|
||||
// Enforce the generic "content" cache tag on all pages.
|
||||
// @todo Remove the "content" cache tag. @see https://drupal.org/node/2124957
|
||||
$tags['content'] = TRUE;
|
||||
$page->setCacheTags($tags);
|
||||
$page->setStatusCode($status_code);
|
||||
|
||||
return $page;
|
||||
|
|
|
@ -65,7 +65,8 @@ class PageCacheTest extends WebTestBase {
|
|||
$cid_parts = array(url($path, array('absolute' => TRUE)), 'html');
|
||||
$cid = sha1(implode(':', $cid_parts));
|
||||
$cache_entry = \Drupal::cache('page')->get($cid);
|
||||
$this->assertIdentical($cache_entry->tags, array('content:1', 'system_test_cache_tags_page:1', 'pre_render:1'));
|
||||
sort($cache_entry->tags);
|
||||
$this->assertIdentical($cache_entry->tags, array('content:1', 'pre_render:1', 'system_test_cache_tags_page:1'));
|
||||
|
||||
Cache::invalidateTags($tags);
|
||||
$this->drupalGet($path);
|
||||
|
|
|
@ -132,14 +132,22 @@ class PageCacheTagsIntegrationTest extends WebTestBase {
|
|||
* The expected cache tags for the page cache entry of the given $path.
|
||||
*/
|
||||
protected function verifyPageCacheTags($path, $expected_tags) {
|
||||
sort($expected_tags);
|
||||
$this->drupalGet($path);
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
|
||||
$actual_tags = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Tags'));
|
||||
sort($actual_tags);
|
||||
$this->assertIdentical($actual_tags, $expected_tags);
|
||||
$this->drupalGet($path);
|
||||
$actual_tags = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Tags'));
|
||||
sort($actual_tags);
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
|
||||
$this->assertIdentical($actual_tags, $expected_tags);
|
||||
$cid_parts = array(url($path, array('absolute' => TRUE)), 'html');
|
||||
$cid = sha1(implode(':', $cid_parts));
|
||||
$cache_entry = \Drupal::cache('page')->get($cid);
|
||||
$this->assertIdentical($cache_entry->tags, $expected_tags);
|
||||
sort($cache_entry->tags);
|
||||
$this->assertEqual($cache_entry->tags, $expected_tags);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,6 +49,8 @@ abstract class PageCacheTagsTestBase extends WebTestBase {
|
|||
$cid_parts = array(url($path, array('absolute' => TRUE)), 'html');
|
||||
$cid = sha1(implode(':', $cid_parts));
|
||||
$cache_entry = \Drupal::cache('page')->get($cid);
|
||||
sort($cache_entry->tags);
|
||||
sort($tags);
|
||||
$this->assertIdentical($cache_entry->tags, $tags);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue