Issue #3074710 by bucefal91, sokru, Wim Leers, larowlan: Losing cacheability while normalizing EntityAccessDeniedHttpException for an inaccessible include
							parent
							
								
									6aec5a3f88
								
							
						
					
					
						commit
						0e29b534a4
					
				| 
						 | 
				
			
			@ -49,7 +49,9 @@ class HttpExceptionNormalizer extends NormalizerBase {
 | 
			
		|||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function normalize($object, $format = NULL, array $context = []) {
 | 
			
		||||
    return new HttpExceptionNormalizerValue(new CacheableMetadata(), static::rasterizeValueRecursive($this->buildErrorObjects($object)));
 | 
			
		||||
    $cacheability = new CacheableMetadata();
 | 
			
		||||
    $cacheability->addCacheableDependency($object);
 | 
			
		||||
    return new HttpExceptionNormalizerValue($cacheability, static::rasterizeValueRecursive($this->buildErrorObjects($object)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1131,4 +1131,60 @@ class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
 | 
			
		|||
    $this->assertSame($doc['data']['attributes']['data'], Json::decode((string) $response->getBody())['data']['attributes']['data']);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Ensure EntityAccessDeniedHttpException cacheability is taken into account.
 | 
			
		||||
   */
 | 
			
		||||
  public function testLeakCacheMetadataInOmitted() {
 | 
			
		||||
    $term = Term::create([
 | 
			
		||||
      'name' => 'Llama term',
 | 
			
		||||
      'vid' => 'tags',
 | 
			
		||||
    ]);
 | 
			
		||||
    $term->setUnpublished();
 | 
			
		||||
    $term->save();
 | 
			
		||||
 | 
			
		||||
    $node = Node::create([
 | 
			
		||||
      'type' => 'article',
 | 
			
		||||
      'title' => 'Llama node',
 | 
			
		||||
      'field_tags' => ['target_id' => $term->id()],
 | 
			
		||||
    ]);
 | 
			
		||||
    $node->save();
 | 
			
		||||
 | 
			
		||||
    $user = $this->drupalCreateUser([
 | 
			
		||||
      'access content',
 | 
			
		||||
    ]);
 | 
			
		||||
    $request_options = [
 | 
			
		||||
      RequestOptions::AUTH => [
 | 
			
		||||
        $user->getAccountName(),
 | 
			
		||||
        $user->pass_raw,
 | 
			
		||||
      ],
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    // Request with unpublished term. At this point it would include the term
 | 
			
		||||
    // into "omitted" part of the response. The point here is that we
 | 
			
		||||
    // purposefully warm up the cache where it is excluded from response and
 | 
			
		||||
    // on the next run we will assure merely publishing term is enough to make
 | 
			
		||||
    // it visible, i.e. that the 1st response was invalidated in Drupal cache.
 | 
			
		||||
    $url = Url::fromUri('internal:/jsonapi/' . $node->getEntityTypeId() . '/' . $node->bundle(), [
 | 
			
		||||
      'query' => ['include' => 'field_tags'],
 | 
			
		||||
    ]);
 | 
			
		||||
    $response = $this->request('GET', $url, $request_options);
 | 
			
		||||
    $this->assertSame(200, $response->getStatusCode());
 | 
			
		||||
 | 
			
		||||
    $response = Json::decode((string) $response->getBody());
 | 
			
		||||
    $this->assertArrayNotHasKey('included', $response, 'JSON API response does not contain "included" taxonomy term as the latter is not published, i.e not accessible.');
 | 
			
		||||
 | 
			
		||||
    $omitted = $response['meta']['omitted']['links'];
 | 
			
		||||
    unset($omitted['help']);
 | 
			
		||||
    $omitted = reset($omitted);
 | 
			
		||||
    $expected_url = Url::fromUri('internal:/jsonapi/' . $term->getEntityTypeId() . '/' . $term->bundle() . '/' . $term->uuid());
 | 
			
		||||
    $expected_url->setAbsolute();
 | 
			
		||||
    $this->assertSame($expected_url->toString(), $omitted['href'], 'Entity that is excluded due to access constraints is correctly reported in the "Omitted" section of the JSON API response.');
 | 
			
		||||
 | 
			
		||||
    $term->setPublished();
 | 
			
		||||
    $term->save();
 | 
			
		||||
    $response = $this->request('GET', $url, $request_options);
 | 
			
		||||
    $this->assertSame(200, $response->getStatusCode());
 | 
			
		||||
    $this->assertEquals($term->uuid(), Json::decode((string) $response->getBody())['included'][0]['id'], 'JSON API response contains "included" taxonomy term as it became published, i.e accessible.');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue