diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php index 56a5270..4b90923 100644 --- a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php +++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php @@ -109,7 +109,8 @@ public function post(EntityInterface $entity = NULL) { $this->logger->notice('Created entity %type with ID %id.', array('%type' => $entity->getEntityTypeId(), '%id' => $entity->id())); // 201 Created responses return the newly created entity in the response - // body. + // body. These responses are not cacheable, so we add no cacheability + // metadata here. $url = $entity->urlInfo('canonical', ['absolute' => TRUE])->toString(TRUE); $response = new NonCacheableResourceResponse($entity, 201, ['Location' => $url->getGeneratedUrl()]); return $response; diff --git a/core/modules/rest/src/Tests/PageCacheTest.php b/core/modules/rest/src/Tests/PageCacheTest.php index 1958fdc..c31af80 100644 --- a/core/modules/rest/src/Tests/PageCacheTest.php +++ b/core/modules/rest/src/Tests/PageCacheTest.php @@ -21,9 +21,14 @@ class PageCacheTest extends RESTTestBase { */ public function testConfigChangePageCache() { $this->enableService('entity:entity_test', 'GET'); - // Allow anonymous users to issue GET requests. - $permissions = $this->entityPermissions('entity_test', 'view'); - $permissions[] = 'restful get entity:entity_test'; + // Allow anonymous users to issue GET, DELETE and PATCH requests. + $permissions = [ + 'view test entity', + 'administer entity_test content', + 'restful get entity:entity_test', + 'restful patch entity:entity_test', + 'restful delete entity:entity_test', + ]; user_role_grant_permissions('anonymous', $permissions); // Create an entity programmatically. @@ -55,6 +60,47 @@ public function testConfigChangePageCache() { $this->assertCacheTag('config:rest.settings'); $this->assertCacheTag('entity_test:1'); $this->assertCacheTag('entity_test_access:field_test_text'); + + // Log in for deleting / updating entity. + $account = $this->drupalCreateUser($permissions); + $this->drupalLogin($account); + + // Test that updating an entity is not cacheable. + $this->enableService('entity:entity_test', 'PATCH'); + + // Create a second stub entity for overwriting a field. + $patch_values['field_test_text'] = [0 => [ + 'value' => 'patched value', + 'format' => 'plain_text', + ]]; + $patch_entity = $this->container->get('entity_type.manager') + ->getStorage('entity_test') + ->create($patch_values); + // We don't want to overwrite the UUID. + $patch_entity->set('uuid', NULL); + $serialized = $this->container->get('serializer') + ->serialize($patch_entity, $this->defaultFormat); + + // Update the entity over the REST API. + $this->httpRequest($entity->urlInfo(), 'PATCH', $serialized, $this->defaultMimeType); + $this->assertResponse(204); + $headers = $this->headers; + foreach ($headers as $header) { + if (strpos($header, 'x-drupal-cache') !== FALSE) { + $this->fail('Patch request is cached.'); + } + } + + // Test that the response from a delete request is not cacheable. + $this->enableService('entity:entity_test', 'DELETE'); + $this->httpRequest($entity->urlInfo(), 'DELETE'); + $this->assertResponse(204); + $headers = $this->headers; + foreach ($headers as $header) { + if (strpos($header, 'x-drupal-cache') !== FALSE) { + $this->fail('Patch request is cached.'); + } + } } } diff --git a/core/modules/rest/tests/src/Kernel/RequestHandlerTest.php b/core/modules/rest/tests/src/Kernel/RequestHandlerTest.php index a571967..4657490 100644 --- a/core/modules/rest/tests/src/Kernel/RequestHandlerTest.php +++ b/core/modules/rest/tests/src/Kernel/RequestHandlerTest.php @@ -7,6 +7,7 @@ namespace Drupal\Tests\rest\Kernel; +use Drupal\Core\Cache\CacheableResponseInterface; use Drupal\Core\Routing\RouteMatch; use Drupal\KernelTests\KernelTestBase; use Drupal\rest\NonCacheableResourceResponse; @@ -72,9 +73,9 @@ public function testBaseHandler() { $handler_response = $this->requestHandler->handle($route_match, $request); $this->assertEquals($response, $handler_response); // Only GET request must be cacheable. - $this->assertInstanceOf('Drupal\Core\Cache\CacheableResponseInterface', $handler_response); + $this->assertInstanceOf(CacheableResponseInterface::class, $handler_response); - // We will call the PATCH method this time.Response will return a + // We will call the PATCH method this time. Response will return a // NonCacheableResourceResponse. $request->setMethod('PATCH'); $response = new NonCacheableResourceResponse([]); @@ -84,7 +85,7 @@ public function testBaseHandler() { $handler_response = $this->requestHandler->handle($route_match, $request); $this->assertEquals($response, $handler_response); // PATCH request is non-cacheable. - $this->assertNotInstanceOf('Drupal\Core\Cache\CacheableResponseInterface', $handler_response); + $this->assertNotInstanceOf(CacheableResponseInterface::class, $handler_response); }