diff --git a/core/lib/Drupal/Core/Cache/Context/HeadersCacheContext.php b/core/lib/Drupal/Core/Cache/Context/HeadersCacheContext.php index 0a9ac0a86e7..71db8e64c78 100644 --- a/core/lib/Drupal/Core/Cache/Context/HeadersCacheContext.php +++ b/core/lib/Drupal/Core/Cache/Context/HeadersCacheContext.php @@ -25,11 +25,28 @@ class HeadersCacheContext extends RequestStackCacheContextBase implements Calcul */ public function getContext($header = NULL) { if ($header === NULL) { - return $this->requestStack->getCurrentRequest()->headers->all(); + $headers = $this->requestStack->getCurrentRequest()->headers->all(); + // Order headers by name to have less cache variations. + ksort($headers); + $result = ''; + foreach ($headers as $name => $value) { + if ($result) { + $result .= '&'; + } + // Sort values to minimize cache variations. + sort($value); + $result .= $name . '=' . implode(',', $value); + } + return $result; } - else { - return $this->requestStack->getCurrentRequest()->headers->get($header); + elseif ($this->requestStack->getCurrentRequest()->headers->has($header)) { + $value = $this->requestStack->getCurrentRequest()->headers->get($header); + if ($value !== '') { + return $value; + } + return '?valueless?'; } + return ''; } /** diff --git a/core/tests/Drupal/Tests/Core/Cache/Context/HeadersCacheContextTest.php b/core/tests/Drupal/Tests/Core/Cache/Context/HeadersCacheContextTest.php new file mode 100644 index 00000000000..8f69e21740c --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Cache/Context/HeadersCacheContextTest.php @@ -0,0 +1,54 @@ +headers->replace($headers); + $request_stack->push($request); + $cache_context = new HeadersCacheContext($request_stack); + $this->assertSame($cache_context->getContext($header_name), $context); + } + + /** + * Provides a list of headers and expected cache contexts. + */ + public function providerTestGetContext() { + return [ + [[], NULL, ''], + [[], 'foo', ''], + // Non-empty headers. + [['llama' => 'rocks', 'alpaca' => '', 'panda' => 'drools', 'z' => '0'], NULL, 'alpaca=&llama=rocks&panda=drools&z=0'], + [['llama' => 'rocks', 'alpaca' => '', 'panda' => 'drools', 'z' => '0'], 'llama', 'rocks'], + [['llama' => 'rocks', 'alpaca' => '', 'panda' => 'drools', 'z' => '0'], 'alpaca', '?valueless?'], + [['llama' => 'rocks', 'alpaca' => '', 'panda' => 'drools', 'z' => '0'], 'panda', 'drools'], + [['llama' => 'rocks', 'alpaca' => '', 'panda' => 'drools', 'z' => '0'], 'z', '0'], + [['llama' => 'rocks', 'alpaca' => '', 'panda' => 'drools', 'z' => '0'], 'chicken', ''], + // Header value could be an array. + [['z' => ['0', '1']], NULL, 'z=0,1'], + // Values are sorted to minimize cache variations. + [['z' => ['1', '0'], 'a' => []], NULL, 'a=&z=0,1'], + [['a' => [], 'z' => ['1', '0']], NULL, 'a=&z=0,1'], + ]; + } + +}