3 namespace Drupal\page_cache\Tests;
5 use Drupal\Component\Datetime\DateTimePlus;
6 use Drupal\Core\Site\Settings;
8 use Drupal\entity_test\Entity\EntityTest;
9 use Drupal\simpletest\WebTestBase;
10 use Drupal\Core\Cache\Cache;
11 use Drupal\user\RoleInterface;
14 * Enables the page cache and tests it with various HTTP requests.
18 class PageCacheTest extends WebTestBase {
20 protected $dumpHeaders = TRUE;
27 public static $modules = ['test_page_test', 'system_test', 'entity_test'];
32 protected function setUp() {
35 $this->config('system.site')
36 ->set('name', 'Drupal')
37 ->set('page.front', '/test-page')
42 * Test that cache tags are properly persisted.
44 * Since tag based invalidation works, we know that our tag properly
47 public function testPageCacheTags() {
48 $config = $this->config('system.performance');
49 $config->set('cache.page.max_age', 300);
52 $path = 'system-test/cache_tags_page';
53 $tags = ['system_test_cache_tags_page'];
54 $this->drupalGet($path);
55 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
57 // Verify a cache hit, but also the presence of the correct cache tags.
58 $this->drupalGet($path);
59 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
60 $cid_parts = [\Drupal::url('system_test.cache_tags_page', [], ['absolute' => TRUE]), 'html'];
61 $cid = implode(':', $cid_parts);
62 $cache_entry = \Drupal::cache('render')->get($cid);
63 sort($cache_entry->tags);
65 'config:user.role.anonymous',
69 'system_test_cache_tags_page',
71 $this->assertIdentical($cache_entry->tags, $expected_tags);
73 Cache::invalidateTags($tags);
74 $this->drupalGet($path);
75 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
79 * Test that the page cache doesn't depend on cacheability headers.
81 public function testPageCacheTagsIndependentFromCacheabilityHeaders() {
82 $this->setHttpResponseDebugCacheabilityHeaders(FALSE);
84 $path = 'system-test/cache_tags_page';
85 $tags = ['system_test_cache_tags_page'];
86 $this->drupalGet($path);
87 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
89 // Verify a cache hit, but also the presence of the correct cache tags.
90 $this->drupalGet($path);
91 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
92 $cid_parts = [\Drupal::url('system_test.cache_tags_page', [], ['absolute' => TRUE]), 'html'];
93 $cid = implode(':', $cid_parts);
94 $cache_entry = \Drupal::cache('render')->get($cid);
95 sort($cache_entry->tags);
97 'config:user.role.anonymous',
101 'system_test_cache_tags_page',
103 $this->assertIdentical($cache_entry->tags, $expected_tags);
105 Cache::invalidateTags($tags);
106 $this->drupalGet($path);
107 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
111 * Tests support for different cache items with different request formats
112 * specified via a query parameter.
114 public function testQueryParameterFormatRequests() {
115 $config = $this->config('system.performance');
116 $config->set('cache.page.max_age', 300);
119 $accept_header_cache_url = Url::fromRoute('system_test.page_cache_accept_header');
120 $accept_header_cache_url_with_json = Url::fromRoute('system_test.page_cache_accept_header', ['_format' => 'json']);
122 $this->drupalGet($accept_header_cache_url);
123 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'HTML page was not yet cached.');
124 $this->drupalGet($accept_header_cache_url);
125 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'HTML page was cached.');
126 $this->assertRaw('<p>oh hai this is html.</p>', 'The correct HTML response was returned.');
128 $this->drupalGet($accept_header_cache_url_with_json);
129 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Json response was not yet cached.');
130 $this->drupalGet($accept_header_cache_url_with_json);
131 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Json response was cached.');
132 $this->assertRaw('{"content":"oh hai this is json"}', 'The correct Json response was returned.');
134 // Enable REST support for nodes and hal+json.
135 \Drupal::service('module_installer')->install(['node', 'rest', 'hal', 'basic_auth']);
136 $this->drupalCreateContentType(['type' => 'article']);
137 $node = $this->drupalCreateNode(['type' => 'article']);
138 $node_uri = $node->urlInfo();
139 $node_url_with_hal_json_format = $node->urlInfo('canonical')->setRouteParameter('_format', 'hal_json');
141 $this->drupalGet($node_uri);
142 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
143 $this->assertEqual($this->drupalGetHeader('Content-Type'), 'text/html; charset=UTF-8');
144 $this->drupalGet($node_uri);
145 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
146 $this->assertEqual($this->drupalGetHeader('Content-Type'), 'text/html; charset=UTF-8');
148 // Now request a HAL page, we expect that the first request is a cache miss
149 // and it serves HTML.
150 $this->drupalGet($node_url_with_hal_json_format);
151 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
152 $this->assertEqual($this->drupalGetHeader('Content-Type'), 'application/hal+json');
153 $this->drupalGet($node_url_with_hal_json_format);
154 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
155 $this->assertEqual($this->drupalGetHeader('Content-Type'), 'application/hal+json');
157 // Clear the page cache. After that request a HAL request, followed by an
158 // ordinary HTML one.
159 \Drupal::cache('render')->deleteAll();
160 $this->drupalGet($node_url_with_hal_json_format);
161 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
162 $this->assertEqual($this->drupalGetHeader('Content-Type'), 'application/hal+json');
163 $this->drupalGet($node_url_with_hal_json_format);
164 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
165 $this->assertEqual($this->drupalGetHeader('Content-Type'), 'application/hal+json');
167 $this->drupalGet($node_uri);
168 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
169 $this->assertEqual($this->drupalGetHeader('Content-Type'), 'text/html; charset=UTF-8');
170 $this->drupalGet($node_uri);
171 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
172 $this->assertEqual($this->drupalGetHeader('Content-Type'), 'text/html; charset=UTF-8');
176 * Tests support of requests with If-Modified-Since and If-None-Match headers.
178 public function testConditionalRequests() {
179 $config = $this->config('system.performance');
180 $config->set('cache.page.max_age', 300);
184 $this->drupalGet('');
185 // Verify the page is not printed twice when the cache is cold.
186 $this->assertNoPattern('#<html.*<html#');
188 $this->drupalHead('');
189 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
190 $etag = $this->drupalGetHeader('ETag');
191 $last_modified = $this->drupalGetHeader('Last-Modified');
193 $this->drupalGet('', [], ['If-Modified-Since: ' . $last_modified, 'If-None-Match: ' . $etag]);
194 $this->assertResponse(304, 'Conditional request returned 304 Not Modified.');
196 $this->drupalGet('', [], ['If-Modified-Since: ' . gmdate(DATE_RFC822, strtotime($last_modified)), 'If-None-Match: ' . $etag]);
197 $this->assertResponse(304, 'Conditional request with obsolete If-Modified-Since date returned 304 Not Modified.');
199 $this->drupalGet('', [], ['If-Modified-Since: ' . gmdate(DATE_RFC850, strtotime($last_modified)), 'If-None-Match: ' . $etag]);
200 $this->assertResponse(304, 'Conditional request with obsolete If-Modified-Since date returned 304 Not Modified.');
202 $this->drupalGet('', [], ['If-Modified-Since: ' . $last_modified]);
203 // Verify the page is not printed twice when the cache is warm.
204 $this->assertNoPattern('#<html.*<html#');
205 $this->assertResponse(200, 'Conditional request without If-None-Match returned 200 OK.');
206 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
208 $this->drupalGet('', [], ['If-Modified-Since: ' . gmdate(DateTimePlus::RFC7231, strtotime($last_modified) + 1), 'If-None-Match: ' . $etag]);
209 $this->assertResponse(200, 'Conditional request with new a If-Modified-Since date newer than Last-Modified returned 200 OK.');
210 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
212 $user = $this->drupalCreateUser();
213 $this->drupalLogin($user);
214 $this->drupalGet('', [], ['If-Modified-Since: ' . $last_modified, 'If-None-Match: ' . $etag]);
215 $this->assertResponse(200, 'Conditional request returned 200 OK for authenticated user.');
216 $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Absence of Page was not cached.');
220 * Tests cache headers.
222 public function testPageCache() {
223 $config = $this->config('system.performance');
224 $config->set('cache.page.max_age', 300);
225 $config->set('response.gzip', 1);
229 $this->drupalGet('system-test/set-header', ['query' => ['name' => 'Foo', 'value' => 'bar']]);
230 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
231 $this->assertEqual(strtolower($this->drupalGetHeader('Vary')), 'cookie,accept-encoding', 'Vary header was sent.');
232 // Symfony's Response logic determines a specific order for the subvalues
233 // of the Cache-Control header, even if they are explicitly passed in to
234 // the response header bag in a different order.
235 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'max-age=300, public', 'Cache-Control header was sent.');
236 $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
237 $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.');
240 $this->drupalGet('system-test/set-header', ['query' => ['name' => 'Foo', 'value' => 'bar']]);
241 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
242 $this->assertEqual(strtolower($this->drupalGetHeader('Vary')), 'cookie,accept-encoding', 'Vary: Cookie header was sent.');
243 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'max-age=300, public', 'Cache-Control header was sent.');
244 $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
245 $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.');
247 // Check replacing default headers.
248 $this->drupalGet('system-test/set-header', ['query' => ['name' => 'Expires', 'value' => 'Fri, 19 Nov 2008 05:00:00 GMT']]);
249 $this->assertEqual($this->drupalGetHeader('Expires'), 'Fri, 19 Nov 2008 05:00:00 GMT', 'Default header was replaced.');
250 $this->drupalGet('system-test/set-header', ['query' => ['name' => 'Vary', 'value' => 'User-Agent']]);
251 $this->assertEqual(strtolower($this->drupalGetHeader('Vary')), 'user-agent,accept-encoding', 'Default header was replaced.');
253 // Check that authenticated users bypass the cache.
254 $user = $this->drupalCreateUser();
255 $this->drupalLogin($user);
256 $this->drupalGet('system-test/set-header', ['query' => ['name' => 'Foo', 'value' => 'bar']]);
257 $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Caching was bypassed.');
258 $this->assertTrue(strpos(strtolower($this->drupalGetHeader('Vary')), 'cookie') === FALSE, 'Vary: Cookie header was not sent.');
259 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'must-revalidate, no-cache, private', 'Cache-Control header was sent.');
260 $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
261 $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.');
263 // Until bubbling of max-age up to the response is supported, verify that
264 // a custom #cache max-age set on an element does not affect page max-age.
265 $this->drupalLogout();
266 $this->drupalGet('system-test/cache_maxage_page');
267 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'max-age=300, public');
271 * Tests the automatic presence of the anonymous role's cache tag.
273 * The 'user.permissions' cache context ensures that if the permissions for a
274 * role are modified, users are not served stale render cache content. But,
275 * when entire responses are cached in reverse proxies, the value for the
276 * cache context is never calculated, causing the stale response to not be
277 * invalidated. Therefore, when varying by permissions and the current user is
278 * the anonymous user, the cache tag for the 'anonymous' role must be added.
280 * This test verifies that, and it verifies that it does not happen for other
283 public function testPageCacheAnonymousRolePermissions() {
284 $config = $this->config('system.performance');
285 $config->set('cache.page.max_age', 300);
288 $content_url = Url::fromRoute('system_test.permission_dependent_content');
289 $route_access_url = Url::fromRoute('system_test.permission_dependent_route_access');
291 // 1. anonymous user, without permission.
292 $this->drupalGet($content_url);
293 $this->assertText('Permission to pet llamas: no!');
294 $this->assertCacheContext('user.permissions');
295 $this->assertCacheTag('config:user.role.anonymous');
296 $this->drupalGet($route_access_url);
297 $this->assertCacheContext('user.permissions');
298 $this->assertCacheTag('config:user.role.anonymous');
300 // 2. anonymous user, with permission.
301 user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, ['pet llamas']);
302 $this->drupalGet($content_url);
303 $this->assertText('Permission to pet llamas: yes!');
304 $this->assertCacheContext('user.permissions');
305 $this->assertCacheTag('config:user.role.anonymous');
306 $this->drupalGet($route_access_url);
307 $this->assertCacheContext('user.permissions');
308 $this->assertCacheTag('config:user.role.anonymous');
310 // 3. authenticated user, without permission.
311 $auth_user = $this->drupalCreateUser();
312 $this->drupalLogin($auth_user);
313 $this->drupalGet($content_url);
314 $this->assertText('Permission to pet llamas: no!');
315 $this->assertCacheContext('user.permissions');
316 $this->assertNoCacheTag('config:user.role.authenticated');
317 $this->drupalGet($route_access_url);
318 $this->assertCacheContext('user.permissions');
319 $this->assertNoCacheTag('config:user.role.authenticated');
321 // 4. authenticated user, with permission.
322 user_role_grant_permissions(RoleInterface::AUTHENTICATED_ID, ['pet llamas']);
323 $this->drupalGet($content_url);
324 $this->assertText('Permission to pet llamas: yes!');
325 $this->assertCacheContext('user.permissions');
326 $this->assertNoCacheTag('config:user.role.authenticated');
327 $this->drupalGet($route_access_url);
328 $this->assertCacheContext('user.permissions');
329 $this->assertNoCacheTag('config:user.role.authenticated');
333 * Tests the 4xx-response cache tag is added and invalidated.
335 public function testPageCacheAnonymous403404() {
336 $admin_url = Url::fromRoute('system.admin');
337 $invalid_url = 'foo/does_not_exist';
342 $cache_ttl_4xx = Settings::get('cache_ttl_4xx', 3600);
343 foreach ($tests as $code => $content_url) {
344 // Anonymous user, without permissions.
345 $this->drupalGet($content_url);
346 $this->assertResponse($code);
347 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
348 $this->assertCacheTag('4xx-response');
349 $this->drupalGet($content_url);
350 $this->assertResponse($code);
351 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
353 'name' => $this->randomMachineName(),
355 'field_test_text' => [
357 'value' => $this->randomString(),
358 'format' => 'plain_text',
362 $entity = EntityTest::create($entity_values);
364 // Saving an entity clears 4xx cache tag.
365 $this->drupalGet($content_url);
366 $this->assertResponse($code);
367 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
368 $this->drupalGet($content_url);
369 $this->assertResponse($code);
370 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT');
371 // Rebuilding the router should invalidate the 4xx cache tag.
372 $this->container->get('router.builder')->rebuild();
373 $this->drupalGet($content_url);
374 $this->assertResponse($code);
375 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
377 // Ensure the 'expire' field on the cache entry uses cache_ttl_4xx.
378 $cache_item = \Drupal::service('cache.render')->get($this->getUrl() . ':html');
379 $difference = $cache_item->expire - (int) $cache_item->created;
380 // Given that a second might have passed we cannot be sure that
381 // $difference will exactly equal the default cache_ttl_4xx setting.
382 // Account for any timing difference or rounding errors by ensuring the
383 // value is within 10 seconds.
385 $difference > $cache_ttl_4xx - 10 &&
386 $difference < $cache_ttl_4xx + 10,
387 "The cache entry expiry time uses the cache_ttl_4xx setting. Expire: {$cache_item->expire} Created: {$cache_item->created}"
391 // Disable 403 and 404 caching.
392 $settings['settings']['cache_ttl_4xx'] = (object) [
396 $this->writeSettings($settings);
397 \Drupal::service('cache.render')->deleteAll();
399 foreach ($tests as $code => $content_url) {
400 // Getting the 404 page twice should still result in a cache miss.
401 $this->drupalGet($content_url);
402 $this->drupalGet($content_url);
403 $this->assertResponse($code);
404 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
409 * Tests the omit_vary_cookie setting.
411 public function testPageCacheWithoutVaryCookie() {
412 $config = $this->config('system.performance');
413 $config->set('cache.page.max_age', 300);
416 $settings['settings']['omit_vary_cookie'] = (object) [
420 $this->writeSettings($settings);
423 $this->drupalGet('');
424 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
425 $this->assertTrue(strpos($this->drupalGetHeader('Vary'), 'Cookie') === FALSE, 'Vary: Cookie header was not sent.');
426 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'max-age=300, public', 'Cache-Control header was sent.');
429 $this->drupalGet('');
430 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
431 $this->assertTrue(strpos($this->drupalGetHeader('Vary'), 'Cookie') === FALSE, 'Vary: Cookie header was not sent.');
432 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'max-age=300, public', 'Cache-Control header was sent.');
436 * Test the setting of forms to be immutable.
438 public function testFormImmutability() {
439 // Install the module that provides the test form.
440 $this->container->get('module_installer')
441 ->install(['page_cache_form_test']);
442 // Uninstall the page_cache module to verify that form is immutable
443 // regardless of the internal page cache module.
444 $this->container->get('module_installer')->uninstall(['page_cache']);
445 \Drupal::service('router.builder')->rebuild();
447 $this->drupalGet('page_cache_form_test_immutability');
449 $this->assertText("Immutable: TRUE", "Form is immutable.");
451 // The immutable flag is set unconditionally by system_form_alter(), set
452 // a flag to tell page_cache_form_test_module_implements_alter() to disable
453 // that implementation.
454 \Drupal::state()->set('page_cache_bypass_form_immutability', TRUE);
455 \Drupal::moduleHandler()->resetImplementations();
456 Cache::invalidateTags(['rendered']);
458 $this->drupalGet('page_cache_form_test_immutability');
460 $this->assertText("Immutable: FALSE", "Form is not immutable,");
464 * Tests cacheability of a CacheableResponse.
466 * Tests the difference between having a controller return a plain Symfony
467 * Response object versus returning a Response object that implements the
468 * CacheableResponseInterface.
470 public function testCacheableResponseResponses() {
471 $config = $this->config('system.performance');
472 $config->set('cache.page.max_age', 300);
475 // GET a URL, which would be marked as a cache miss if it were cacheable.
476 $this->drupalGet('/system-test/respond-reponse');
477 $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Drupal page cache header not found.');
478 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'must-revalidate, no-cache, private', 'Cache-Control header was sent');
480 // GET it again, verify it's still not cached.
481 $this->drupalGet('/system-test/respond-reponse');
482 $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Drupal page cache header not found.');
483 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'must-revalidate, no-cache, private', 'Cache-Control header was sent');
485 // GET a URL, which would be marked as a cache miss if it were cacheable.
486 $this->drupalGet('/system-test/respond-public-response');
487 $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Drupal page cache header not found.');
488 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'max-age=60, public', 'Cache-Control header was sent');
490 // GET it again, verify it's still not cached.
491 $this->drupalGet('/system-test/respond-public-response');
492 $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Drupal page cache header not found.');
493 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'max-age=60, public', 'Cache-Control header was sent');
495 // GET a URL, which should be marked as a cache miss.
496 $this->drupalGet('/system-test/respond-cacheable-reponse');
497 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
498 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'max-age=300, public', 'Cache-Control header was sent.');
500 // GET it again, it should now be a cache hit.
501 $this->drupalGet('/system-test/respond-cacheable-reponse');
502 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
503 $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'max-age=300, public', 'Cache-Control header was sent.');
505 // Uninstall page cache. This should flush all caches so the next call to a
506 // previously cached page should be a miss now.
507 $this->container->get('module_installer')
508 ->uninstall(['page_cache']);
510 // GET a URL that was cached by Page Cache before, it should not be now.
511 $this->drupalGet('/respond-cacheable-reponse');
512 $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Drupal page cache header not found.');
516 * Tests that HEAD requests are treated the same as GET requests.
518 public function testHead() {
520 $url_a = $this->buildUrl('system-test/set-header', ['query' => ['name' => 'Foo', 'value' => 'bar']]);
521 $response_body = $this->curlExec([CURLOPT_HTTPGET => TRUE, CURLOPT_URL => $url_a, CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_NOBODY => FALSE]);
522 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
523 $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.');
524 $this->assertEqual('The following header was set: <em class="placeholder">Foo</em>: <em class="placeholder">bar</em>', $response_body);
525 $response_body = $this->curlExec([CURLOPT_HTTPGET => FALSE, CURLOPT_URL => $url_a, CURLOPT_CUSTOMREQUEST => 'HEAD', CURLOPT_NOBODY => FALSE]);
526 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
527 $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.');
528 $this->assertEqual('', $response_body);
531 $url_b = $this->buildUrl('system-test/set-header', ['query' => ['name' => 'Foo', 'value' => 'baz']]);
532 $response_body = $this->curlExec([CURLOPT_HTTPGET => FALSE, CURLOPT_URL => $url_b, CURLOPT_CUSTOMREQUEST => 'HEAD', CURLOPT_NOBODY => FALSE]);
533 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
534 $this->assertEqual($this->drupalGetHeader('Foo'), 'baz', 'Custom header was sent.');
535 $this->assertEqual('', $response_body);
536 $response_body = $this->curlExec([CURLOPT_HTTPGET => TRUE, CURLOPT_URL => $url_b, CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_NOBODY => FALSE]);
537 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
538 $this->assertEqual($this->drupalGetHeader('Foo'), 'baz', 'Custom header was sent.');
539 $this->assertEqual('The following header was set: <em class="placeholder">Foo</em>: <em class="placeholder">baz</em>', $response_body);
543 * Test that URLs are cached in a not normalized form.
545 public function testNoUrlNormalization() {
547 // Use absolute URLs to avoid any processing.
548 $url = Url::fromRoute('<front>')->setAbsolute()->toString();
550 // In each test, the first array value is raw URL, the second one is the
551 // possible normalized URL.
567 foreach ($tests as list($url_raw, $url_normalized)) {
569 // Initialize cache on raw URL.
570 $this->drupalGet($url_raw);
571 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
572 // Ensure cache was set.
573 $this->drupalGet($url_raw);
574 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', "Cache was set for {$url_raw} URL.");
576 // Check if the normalized URL is not cached.
577 $this->drupalGet($url_normalized);
578 $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', "Cache is missing for {$url_normalized} URL.");