Commit 39803eb1 authored by effulgentsia's avatar effulgentsia

Issue #2827797 by Wim Leers, dawehner, effulgentsia, tedbow:...

Issue #2827797 by Wim Leers, dawehner, effulgentsia, tedbow: ResourceResponse(Subscriber) + Dynamic Page Cache: making authenticated ResourceResponses significantly faster
parent 61541281
......@@ -196,8 +196,9 @@ protected function flattenResponse(ResourceResponseInterface $response) {
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
// Run shortly before \Drupal\Core\EventSubscriber\FinishResponseSubscriber.
$events[KernelEvents::RESPONSE][] = ['onResponse', 5];
// Run before \Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber
// (priority 100), so that Dynamic Page Cache can cache flattened responses.
$events[KernelEvents::RESPONSE][] = ['onResponse', 128];
return $events;
}
......
......@@ -4,11 +4,13 @@
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableResponseInterface;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Url;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\rest\ResourceResponseInterface;
use Drupal\Tests\rest\Functional\ResourceTestBase;
use GuzzleHttp\RequestOptions;
use Psr\Http\Message\ResponseInterface;
......@@ -386,6 +388,18 @@ public function testGet() {
// 200 for well-formed HEAD request.
$response = $this->request('HEAD', $url, $request_options);
$this->assertResourceResponse(200, '', $response);
// @todo Entity resources with URLs that begin with '/admin/' are marked as
// administrative (see https://www.drupal.org/node/2874938), which
// excludes them from Dynamic Page Cache (see
// https://www.drupal.org/node/2877528). When either of those issues is
// fixed, remove the if-test and the 'else' block.
if (strpos($this->entity->getEntityType()->getLinkTemplate('canonical'), '/admin/') !== 0) {
$this->assertTrue($response->hasHeader('X-Drupal-Dynamic-Cache'));
$this->assertSame(['MISS'], $response->getHeader('X-Drupal-Dynamic-Cache'));
}
else {
$this->assertFalse($response->hasHeader('X-Drupal-Dynamic-Cache'));
}
if (!$this->account) {
$this->assertSame(['MISS'], $response->getHeader('X-Drupal-Cache'));
}
......@@ -395,13 +409,44 @@ public function testGet() {
$head_headers = $response->getHeaders();
// 200 for well-formed GET request. Page Cache hit because of HEAD request.
// Same for Dynamic Page Cache hit.
$response = $this->request('GET', $url, $request_options);
$this->assertResourceResponse(200, FALSE, $response);
if (!static::$auth) {
$this->assertSame(['HIT'], $response->getHeader('X-Drupal-Cache'));
// @todo Entity resources with URLs that begin with '/admin/' are marked as
// administrative (see https://www.drupal.org/node/2874938), which
// excludes them from Dynamic Page Cache (see
// https://www.drupal.org/node/2877528). When either of those issues is
// fixed, remove the if-test and the 'else' block.
if (strpos($this->entity->getEntityType()->getLinkTemplate('canonical'), '/admin/') !== 0) {
$this->assertTrue($response->hasHeader('X-Drupal-Dynamic-Cache'));
if (!static::$auth) {
$this->assertSame(['HIT'], $response->getHeader('X-Drupal-Cache'));
$this->assertSame(['MISS'], $response->getHeader('X-Drupal-Dynamic-Cache'));
}
else {
$this->assertFalse($response->hasHeader('X-Drupal-Cache'));
$this->assertSame(['HIT'], $response->getHeader('X-Drupal-Dynamic-Cache'));
// Assert that Dynamic Page Cache did not store a ResourceResponse object,
// which needs serialization after every cache hit. Instead, it should
// contain a flattened response. Otherwise performance suffers.
// @see \Drupal\rest\EventSubscriber\ResourceResponseSubscriber::flattenResponse()
$cache_items = $this->container->get('database')
->query("SELECT cid, data FROM {cache_dynamic_page_cache} WHERE cid LIKE :pattern", [
':pattern' => '%[route]=rest.%',
])
->fetchAllAssoc('cid');
foreach ($cache_items as $cid => $cache_item) {
$cached_data = unserialize($cache_item->data);
if (!isset($cached_data['#cache_redirect'])) {
$cached_response = $cached_data['#response'];
$this->assertNotInstanceOf(ResourceResponseInterface::class, $cached_response);
$this->assertInstanceOf(CacheableResponseInterface::class, $cached_response);
}
}
}
}
else {
$this->assertFalse($response->hasHeader('X-Drupal-Cache'));
$this->assertFalse($response->hasHeader('X-Drupal-Dynamic-Cache'));
}
$cache_tags_header_value = $response->getHeader('X-Drupal-Cache-Tags')[0];
$this->assertEquals($this->getExpectedCacheTags(), empty($cache_tags_header_value) ? [] : explode(' ', $cache_tags_header_value));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment