HttpCache does not consider ESI resources in HEAD requests
This commit is contained in:
parent
3b42d8859e
commit
4dd0e53171
|
@ -633,14 +633,6 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
|
||||||
*/
|
*/
|
||||||
private function restoreResponseBody(Request $request, Response $response)
|
private function restoreResponseBody(Request $request, Response $response)
|
||||||
{
|
{
|
||||||
if ($request->isMethod('HEAD') || 304 === $response->getStatusCode()) {
|
|
||||||
$response->setContent(null);
|
|
||||||
$response->headers->remove('X-Body-Eval');
|
|
||||||
$response->headers->remove('X-Body-File');
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($response->headers->has('X-Body-Eval')) {
|
if ($response->headers->has('X-Body-Eval')) {
|
||||||
ob_start();
|
ob_start();
|
||||||
|
|
||||||
|
@ -656,7 +648,11 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
|
||||||
$response->headers->set('Content-Length', strlen($response->getContent()));
|
$response->headers->set('Content-Length', strlen($response->getContent()));
|
||||||
}
|
}
|
||||||
} elseif ($response->headers->has('X-Body-File')) {
|
} elseif ($response->headers->has('X-Body-File')) {
|
||||||
$response->setContent(file_get_contents($response->headers->get('X-Body-File')));
|
// Response does not include possibly dynamic content (ESI, SSI), so we need
|
||||||
|
// not handle the content for HEAD requests
|
||||||
|
if (!$request->isMethod('HEAD')) {
|
||||||
|
$response->setContent(file_get_contents($response->headers->get('X-Body-File')));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1133,7 +1133,7 @@ class HttpCacheTest extends HttpCacheTestCase
|
||||||
array(
|
array(
|
||||||
'status' => 200,
|
'status' => 200,
|
||||||
'body' => 'Hello World!',
|
'body' => 'Hello World!',
|
||||||
'headers' => array('Cache-Control' => 's-maxage=300'),
|
'headers' => array('Cache-Control' => 's-maxage=200'),
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'status' => 200,
|
'status' => 200,
|
||||||
|
@ -1147,8 +1147,33 @@ class HttpCacheTest extends HttpCacheTestCase
|
||||||
$this->request('GET', '/', array(), array(), true);
|
$this->request('GET', '/', array(), array(), true);
|
||||||
$this->assertEquals('Hello World! My name is Bobby.', $this->response->getContent());
|
$this->assertEquals('Hello World! My name is Bobby.', $this->response->getContent());
|
||||||
|
|
||||||
// check for 100 or 99 as the test can be executed after a second change
|
$this->assertEquals(100, $this->response->getTtl());
|
||||||
$this->assertTrue(in_array($this->response->getTtl(), array(99, 100)));
|
}
|
||||||
|
|
||||||
|
public function testEsiCacheSendsTheLowestTtlForHeadRequests()
|
||||||
|
{
|
||||||
|
$responses = array(
|
||||||
|
array(
|
||||||
|
'status' => 200,
|
||||||
|
'body' => 'I am a long-lived master response, but I embed a short-lived resource: <esi:include src="/foo" />',
|
||||||
|
'headers' => array(
|
||||||
|
'Cache-Control' => 's-maxage=300',
|
||||||
|
'Surrogate-Control' => 'content="ESI/1.0"',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'status' => 200,
|
||||||
|
'body' => 'I am a short-lived resource',
|
||||||
|
'headers' => array('Cache-Control' => 's-maxage=100'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setNextResponses($responses);
|
||||||
|
|
||||||
|
$this->request('HEAD', '/', array(), array(), true);
|
||||||
|
|
||||||
|
$this->assertEmpty($this->response->getContent());
|
||||||
|
$this->assertEquals(100, $this->response->getTtl());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testEsiCacheForceValidation()
|
public function testEsiCacheForceValidation()
|
||||||
|
@ -1184,6 +1209,37 @@ class HttpCacheTest extends HttpCacheTestCase
|
||||||
$this->assertTrue($this->response->headers->hasCacheControlDirective('no-cache'));
|
$this->assertTrue($this->response->headers->hasCacheControlDirective('no-cache'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testEsiCacheForceValidationForHeadRequests()
|
||||||
|
{
|
||||||
|
$responses = array(
|
||||||
|
array(
|
||||||
|
'status' => 200,
|
||||||
|
'body' => 'I am the master response and use expiration caching, but I embed another resource: <esi:include src="/foo" />',
|
||||||
|
'headers' => array(
|
||||||
|
'Cache-Control' => 's-maxage=300',
|
||||||
|
'Surrogate-Control' => 'content="ESI/1.0"',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'status' => 200,
|
||||||
|
'body' => 'I am the embedded resource and use validation caching',
|
||||||
|
'headers' => array('ETag' => 'foobar'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setNextResponses($responses);
|
||||||
|
|
||||||
|
$this->request('HEAD', '/', array(), array(), true);
|
||||||
|
|
||||||
|
// The response has been assembled from expiration and validation based resources
|
||||||
|
// This can neither be cached nor revalidated, so it should be private/no cache
|
||||||
|
$this->assertEmpty($this->response->getContent());
|
||||||
|
$this->assertNull($this->response->getTtl());
|
||||||
|
$this->assertTrue($this->response->mustRevalidate());
|
||||||
|
$this->assertTrue($this->response->headers->hasCacheControlDirective('private'));
|
||||||
|
$this->assertTrue($this->response->headers->hasCacheControlDirective('no-cache'));
|
||||||
|
}
|
||||||
|
|
||||||
public function testEsiRecalculateContentLengthHeader()
|
public function testEsiRecalculateContentLengthHeader()
|
||||||
{
|
{
|
||||||
$responses = array(
|
$responses = array(
|
||||||
|
@ -1192,7 +1248,6 @@ class HttpCacheTest extends HttpCacheTestCase
|
||||||
'body' => '<esi:include src="/foo" />',
|
'body' => '<esi:include src="/foo" />',
|
||||||
'headers' => array(
|
'headers' => array(
|
||||||
'Content-Length' => 26,
|
'Content-Length' => 26,
|
||||||
'Cache-Control' => 's-maxage=300',
|
|
||||||
'Surrogate-Control' => 'content="ESI/1.0"',
|
'Surrogate-Control' => 'content="ESI/1.0"',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1210,6 +1265,37 @@ class HttpCacheTest extends HttpCacheTestCase
|
||||||
$this->assertEquals(12, $this->response->headers->get('Content-Length'));
|
$this->assertEquals(12, $this->response->headers->get('Content-Length'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testEsiRecalculateContentLengthHeaderForHeadRequest()
|
||||||
|
{
|
||||||
|
$responses = array(
|
||||||
|
array(
|
||||||
|
'status' => 200,
|
||||||
|
'body' => '<esi:include src="/foo" />',
|
||||||
|
'headers' => array(
|
||||||
|
'Content-Length' => 26,
|
||||||
|
'Surrogate-Control' => 'content="ESI/1.0"',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'status' => 200,
|
||||||
|
'body' => 'Hello World!',
|
||||||
|
'headers' => array(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setNextResponses($responses);
|
||||||
|
|
||||||
|
$this->request('HEAD', '/', array(), array(), true);
|
||||||
|
|
||||||
|
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
|
||||||
|
// "The Content-Length entity-header field indicates the size of the entity-body,
|
||||||
|
// in decimal number of OCTETs, sent to the recipient or, in the case of the HEAD
|
||||||
|
// method, the size of the entity-body that would have been sent had the request
|
||||||
|
// been a GET."
|
||||||
|
$this->assertEmpty($this->response->getContent());
|
||||||
|
$this->assertEquals(12, $this->response->headers->get('Content-Length'));
|
||||||
|
}
|
||||||
|
|
||||||
public function testClientIpIsAlwaysLocalhostForForwardedRequests()
|
public function testClientIpIsAlwaysLocalhostForForwardedRequests()
|
||||||
{
|
{
|
||||||
$this->setNextResponse();
|
$this->setNextResponse();
|
||||||
|
@ -1301,6 +1387,35 @@ class HttpCacheTest extends HttpCacheTestCase
|
||||||
$this->assertNull($this->response->getLastModified());
|
$this->assertNull($this->response->getLastModified());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testEsiCacheRemoveValidationHeadersIfEmbeddedResponsesAndHeadRequest()
|
||||||
|
{
|
||||||
|
$time = \DateTime::createFromFormat('U', time());
|
||||||
|
|
||||||
|
$responses = array(
|
||||||
|
array(
|
||||||
|
'status' => 200,
|
||||||
|
'body' => '<esi:include src="/hey" />',
|
||||||
|
'headers' => array(
|
||||||
|
'Surrogate-Control' => 'content="ESI/1.0"',
|
||||||
|
'ETag' => 'hey',
|
||||||
|
'Last-Modified' => $time->format(DATE_RFC2822),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'status' => 200,
|
||||||
|
'body' => 'Hey!',
|
||||||
|
'headers' => array(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setNextResponses($responses);
|
||||||
|
|
||||||
|
$this->request('HEAD', '/', array(), array(), true);
|
||||||
|
$this->assertEmpty($this->response->getContent());
|
||||||
|
$this->assertNull($this->response->getETag());
|
||||||
|
$this->assertNull($this->response->getLastModified());
|
||||||
|
}
|
||||||
|
|
||||||
public function testDoesNotCacheOptionsRequest()
|
public function testDoesNotCacheOptionsRequest()
|
||||||
{
|
{
|
||||||
$this->setNextResponse(200, array('Cache-Control' => 'public, s-maxage=60'), 'get');
|
$this->setNextResponse(200, array('Cache-Control' => 'public, s-maxage=60'), 'get');
|
||||||
|
|
Reference in New Issue