summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreffulgentsia2017-05-11 16:36:37 (GMT)
committereffulgentsia2017-05-11 16:36:37 (GMT)
commit39803eb1f613df2b7007f43dfb166b911f3eaa47 (patch)
tree4856be79d19eff622e57bb6cc505566cc375cfe7
parent61541281129fcec40fcc9a72f2486de92a180159 (diff)
Issue #2827797 by Wim Leers, dawehner, effulgentsia, tedbow: ResourceResponse(Subscriber) + Dynamic Page Cache: making authenticated ResourceResponses significantly faster
-rw-r--r--core/modules/rest/src/EventSubscriber/ResourceResponseSubscriber.php5
-rw-r--r--core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php51
2 files changed, 51 insertions, 5 deletions
diff --git a/core/modules/rest/src/EventSubscriber/ResourceResponseSubscriber.php b/core/modules/rest/src/EventSubscriber/ResourceResponseSubscriber.php
index 86935ea..df77281 100644
--- a/core/modules/rest/src/EventSubscriber/ResourceResponseSubscriber.php
+++ b/core/modules/rest/src/EventSubscriber/ResourceResponseSubscriber.php
@@ -196,8 +196,9 @@ class ResourceResponseSubscriber implements EventSubscriberInterface {
* {@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;
}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
index a55ae92..5bcf5fe 100644
--- a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
+++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
@@ -4,11 +4,13 @@ namespace Drupal\Tests\rest\Functional\EntityResource;
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 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
// 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 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
$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));