4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\HttpKernel\Tests\HttpCache;
14 use Symfony\Component\HttpKernel\HttpCache\HttpCache;
15 use Symfony\Component\HttpFoundation\Request;
16 use Symfony\Component\HttpFoundation\Response;
17 use Symfony\Component\HttpKernel\HttpKernelInterface;
20 * @group time-sensitive
22 class HttpCacheTest extends HttpCacheTestCase
24 public function testTerminateDelegatesTerminationOnlyForTerminableInterface()
26 $storeMock = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\HttpCache\\StoreInterface')
27 ->disableOriginalConstructor()
30 // does not implement TerminableInterface
31 $kernel = new TestKernel();
32 $httpCache = new HttpCache($kernel, $storeMock);
33 $httpCache->terminate(Request::create('/'), new Response());
35 $this->assertFalse($kernel->terminateCalled, 'terminate() is never called if the kernel class does not implement TerminableInterface');
37 // implements TerminableInterface
38 $kernelMock = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\Kernel')
39 ->disableOriginalConstructor()
40 ->setMethods(array('terminate', 'registerBundles', 'registerContainerConfiguration'))
43 $kernelMock->expects($this->once())
44 ->method('terminate');
46 $kernel = new HttpCache($kernelMock, $storeMock);
47 $kernel->terminate(Request::create('/'), new Response());
50 public function testPassesOnNonGetHeadRequests()
52 $this->setNextResponse(200);
53 $this->request('POST', '/');
54 $this->assertHttpKernelIsCalled();
55 $this->assertResponseOk();
56 $this->assertTraceContains('pass');
57 $this->assertFalse($this->response->headers->has('Age'));
60 public function testInvalidatesOnPostPutDeleteRequests()
62 foreach (array('post', 'put', 'delete') as $method) {
63 $this->setNextResponse(200);
64 $this->request($method, '/');
66 $this->assertHttpKernelIsCalled();
67 $this->assertResponseOk();
68 $this->assertTraceContains('invalidate');
69 $this->assertTraceContains('pass');
73 public function testDoesNotCacheWithAuthorizationRequestHeaderAndNonPublicResponse()
75 $this->setNextResponse(200, array('ETag' => '"Foo"'));
76 $this->request('GET', '/', array('HTTP_AUTHORIZATION' => 'basic foobarbaz'));
78 $this->assertHttpKernelIsCalled();
79 $this->assertResponseOk();
80 $this->assertEquals('private', $this->response->headers->get('Cache-Control'));
82 $this->assertTraceContains('miss');
83 $this->assertTraceNotContains('store');
84 $this->assertFalse($this->response->headers->has('Age'));
87 public function testDoesCacheWithAuthorizationRequestHeaderAndPublicResponse()
89 $this->setNextResponse(200, array('Cache-Control' => 'public', 'ETag' => '"Foo"'));
90 $this->request('GET', '/', array('HTTP_AUTHORIZATION' => 'basic foobarbaz'));
92 $this->assertHttpKernelIsCalled();
93 $this->assertResponseOk();
94 $this->assertTraceContains('miss');
95 $this->assertTraceContains('store');
96 $this->assertTrue($this->response->headers->has('Age'));
97 $this->assertEquals('public', $this->response->headers->get('Cache-Control'));
100 public function testDoesNotCacheWithCookieHeaderAndNonPublicResponse()
102 $this->setNextResponse(200, array('ETag' => '"Foo"'));
103 $this->request('GET', '/', array(), array('foo' => 'bar'));
105 $this->assertHttpKernelIsCalled();
106 $this->assertResponseOk();
107 $this->assertEquals('private', $this->response->headers->get('Cache-Control'));
108 $this->assertTraceContains('miss');
109 $this->assertTraceNotContains('store');
110 $this->assertFalse($this->response->headers->has('Age'));
113 public function testDoesNotCacheRequestsWithACookieHeader()
115 $this->setNextResponse(200);
116 $this->request('GET', '/', array(), array('foo' => 'bar'));
118 $this->assertHttpKernelIsCalled();
119 $this->assertResponseOk();
120 $this->assertEquals('private', $this->response->headers->get('Cache-Control'));
121 $this->assertTraceContains('miss');
122 $this->assertTraceNotContains('store');
123 $this->assertFalse($this->response->headers->has('Age'));
126 public function testRespondsWith304WhenIfModifiedSinceMatchesLastModified()
128 $time = \DateTime::createFromFormat('U', time());
130 $this->setNextResponse(200, array('Cache-Control' => 'public', 'Last-Modified' => $time->format(DATE_RFC2822), 'Content-Type' => 'text/plain'), 'Hello World');
131 $this->request('GET', '/', array('HTTP_IF_MODIFIED_SINCE' => $time->format(DATE_RFC2822)));
133 $this->assertHttpKernelIsCalled();
134 $this->assertEquals(304, $this->response->getStatusCode());
135 $this->assertEquals('', $this->response->headers->get('Content-Type'));
136 $this->assertEmpty($this->response->getContent());
137 $this->assertTraceContains('miss');
138 $this->assertTraceContains('store');
141 public function testRespondsWith304WhenIfNoneMatchMatchesETag()
143 $this->setNextResponse(200, array('Cache-Control' => 'public', 'ETag' => '12345', 'Content-Type' => 'text/plain'), 'Hello World');
144 $this->request('GET', '/', array('HTTP_IF_NONE_MATCH' => '12345'));
146 $this->assertHttpKernelIsCalled();
147 $this->assertEquals(304, $this->response->getStatusCode());
148 $this->assertEquals('', $this->response->headers->get('Content-Type'));
149 $this->assertTrue($this->response->headers->has('ETag'));
150 $this->assertEmpty($this->response->getContent());
151 $this->assertTraceContains('miss');
152 $this->assertTraceContains('store');
155 public function testRespondsWith304OnlyIfIfNoneMatchAndIfModifiedSinceBothMatch()
157 $time = \DateTime::createFromFormat('U', time());
159 $this->setNextResponse(200, array(), '', function ($request, $response) use ($time) {
160 $response->setStatusCode(200);
161 $response->headers->set('ETag', '12345');
162 $response->headers->set('Last-Modified', $time->format(DATE_RFC2822));
163 $response->headers->set('Content-Type', 'text/plain');
164 $response->setContent('Hello World');
168 $t = \DateTime::createFromFormat('U', time() - 3600);
169 $this->request('GET', '/', array('HTTP_IF_NONE_MATCH' => '12345', 'HTTP_IF_MODIFIED_SINCE' => $t->format(DATE_RFC2822)));
170 $this->assertHttpKernelIsCalled();
171 $this->assertEquals(200, $this->response->getStatusCode());
173 // only Last-Modified matches
174 $this->request('GET', '/', array('HTTP_IF_NONE_MATCH' => '1234', 'HTTP_IF_MODIFIED_SINCE' => $time->format(DATE_RFC2822)));
175 $this->assertHttpKernelIsCalled();
176 $this->assertEquals(200, $this->response->getStatusCode());
179 $this->request('GET', '/', array('HTTP_IF_NONE_MATCH' => '12345', 'HTTP_IF_MODIFIED_SINCE' => $time->format(DATE_RFC2822)));
180 $this->assertHttpKernelIsCalled();
181 $this->assertEquals(304, $this->response->getStatusCode());
184 public function testIncrementsMaxAgeWhenNoDateIsSpecifiedEventWhenUsingETag()
186 $this->setNextResponse(
190 'Cache-Control' => 'public, s-maxage=60',
194 $this->request('GET', '/');
195 $this->assertHttpKernelIsCalled();
196 $this->assertEquals(200, $this->response->getStatusCode());
197 $this->assertTraceContains('miss');
198 $this->assertTraceContains('store');
202 $this->request('GET', '/');
203 $this->assertHttpKernelIsNotCalled();
204 $this->assertEquals(200, $this->response->getStatusCode());
205 $this->assertTraceContains('fresh');
206 $this->assertEquals(2, $this->response->headers->get('Age'));
209 public function testValidatesPrivateResponsesCachedOnTheClient()
211 $this->setNextResponse(200, array(), '', function ($request, $response) {
212 $etags = preg_split('/\s*,\s*/', $request->headers->get('IF_NONE_MATCH'));
213 if ($request->cookies->has('authenticated')) {
214 $response->headers->set('Cache-Control', 'private, no-store');
215 $response->setETag('"private tag"');
216 if (in_array('"private tag"', $etags)) {
217 $response->setStatusCode(304);
219 $response->setStatusCode(200);
220 $response->headers->set('Content-Type', 'text/plain');
221 $response->setContent('private data');
224 $response->headers->set('Cache-Control', 'public');
225 $response->setETag('"public tag"');
226 if (in_array('"public tag"', $etags)) {
227 $response->setStatusCode(304);
229 $response->setStatusCode(200);
230 $response->headers->set('Content-Type', 'text/plain');
231 $response->setContent('public data');
236 $this->request('GET', '/');
237 $this->assertHttpKernelIsCalled();
238 $this->assertEquals(200, $this->response->getStatusCode());
239 $this->assertEquals('"public tag"', $this->response->headers->get('ETag'));
240 $this->assertEquals('public data', $this->response->getContent());
241 $this->assertTraceContains('miss');
242 $this->assertTraceContains('store');
244 $this->request('GET', '/', array(), array('authenticated' => ''));
245 $this->assertHttpKernelIsCalled();
246 $this->assertEquals(200, $this->response->getStatusCode());
247 $this->assertEquals('"private tag"', $this->response->headers->get('ETag'));
248 $this->assertEquals('private data', $this->response->getContent());
249 $this->assertTraceContains('stale');
250 $this->assertTraceContains('invalid');
251 $this->assertTraceNotContains('store');
254 public function testStoresResponsesWhenNoCacheRequestDirectivePresent()
256 $time = \DateTime::createFromFormat('U', time() + 5);
258 $this->setNextResponse(200, array('Cache-Control' => 'public', 'Expires' => $time->format(DATE_RFC2822)));
259 $this->request('GET', '/', array('HTTP_CACHE_CONTROL' => 'no-cache'));
261 $this->assertHttpKernelIsCalled();
262 $this->assertTraceContains('store');
263 $this->assertTrue($this->response->headers->has('Age'));
266 public function testReloadsResponsesWhenCacheHitsButNoCacheRequestDirectivePresentWhenAllowReloadIsSetTrue()
270 $this->setNextResponse(200, array('Cache-Control' => 'public, max-age=10000'), '', function ($request, $response) use (&$count) {
272 $response->setContent(1 == $count ? 'Hello World' : 'Goodbye World');
275 $this->request('GET', '/');
276 $this->assertEquals(200, $this->response->getStatusCode());
277 $this->assertEquals('Hello World', $this->response->getContent());
278 $this->assertTraceContains('store');
280 $this->request('GET', '/');
281 $this->assertEquals(200, $this->response->getStatusCode());
282 $this->assertEquals('Hello World', $this->response->getContent());
283 $this->assertTraceContains('fresh');
285 $this->cacheConfig['allow_reload'] = true;
286 $this->request('GET', '/', array('HTTP_CACHE_CONTROL' => 'no-cache'));
287 $this->assertEquals(200, $this->response->getStatusCode());
288 $this->assertEquals('Goodbye World', $this->response->getContent());
289 $this->assertTraceContains('reload');
290 $this->assertTraceContains('store');
293 public function testDoesNotReloadResponsesWhenAllowReloadIsSetFalseDefault()
297 $this->setNextResponse(200, array('Cache-Control' => 'public, max-age=10000'), '', function ($request, $response) use (&$count) {
299 $response->setContent(1 == $count ? 'Hello World' : 'Goodbye World');
302 $this->request('GET', '/');
303 $this->assertEquals(200, $this->response->getStatusCode());
304 $this->assertEquals('Hello World', $this->response->getContent());
305 $this->assertTraceContains('store');
307 $this->request('GET', '/');
308 $this->assertEquals(200, $this->response->getStatusCode());
309 $this->assertEquals('Hello World', $this->response->getContent());
310 $this->assertTraceContains('fresh');
312 $this->cacheConfig['allow_reload'] = false;
313 $this->request('GET', '/', array('HTTP_CACHE_CONTROL' => 'no-cache'));
314 $this->assertEquals(200, $this->response->getStatusCode());
315 $this->assertEquals('Hello World', $this->response->getContent());
316 $this->assertTraceNotContains('reload');
318 $this->request('GET', '/', array('HTTP_CACHE_CONTROL' => 'no-cache'));
319 $this->assertEquals(200, $this->response->getStatusCode());
320 $this->assertEquals('Hello World', $this->response->getContent());
321 $this->assertTraceNotContains('reload');
324 public function testRevalidatesFreshCacheEntryWhenMaxAgeRequestDirectiveIsExceededWhenAllowRevalidateOptionIsSetTrue()
328 $this->setNextResponse(200, array(), '', function ($request, $response) use (&$count) {
330 $response->headers->set('Cache-Control', 'public, max-age=10000');
331 $response->setETag($count);
332 $response->setContent(1 == $count ? 'Hello World' : 'Goodbye World');
335 $this->request('GET', '/');
336 $this->assertEquals(200, $this->response->getStatusCode());
337 $this->assertEquals('Hello World', $this->response->getContent());
338 $this->assertTraceContains('store');
340 $this->request('GET', '/');
341 $this->assertEquals(200, $this->response->getStatusCode());
342 $this->assertEquals('Hello World', $this->response->getContent());
343 $this->assertTraceContains('fresh');
345 $this->cacheConfig['allow_revalidate'] = true;
346 $this->request('GET', '/', array('HTTP_CACHE_CONTROL' => 'max-age=0'));
347 $this->assertEquals(200, $this->response->getStatusCode());
348 $this->assertEquals('Goodbye World', $this->response->getContent());
349 $this->assertTraceContains('stale');
350 $this->assertTraceContains('invalid');
351 $this->assertTraceContains('store');
354 public function testDoesNotRevalidateFreshCacheEntryWhenEnableRevalidateOptionIsSetFalseDefault()
358 $this->setNextResponse(200, array(), '', function ($request, $response) use (&$count) {
360 $response->headers->set('Cache-Control', 'public, max-age=10000');
361 $response->setETag($count);
362 $response->setContent(1 == $count ? 'Hello World' : 'Goodbye World');
365 $this->request('GET', '/');
366 $this->assertEquals(200, $this->response->getStatusCode());
367 $this->assertEquals('Hello World', $this->response->getContent());
368 $this->assertTraceContains('store');
370 $this->request('GET', '/');
371 $this->assertEquals(200, $this->response->getStatusCode());
372 $this->assertEquals('Hello World', $this->response->getContent());
373 $this->assertTraceContains('fresh');
375 $this->cacheConfig['allow_revalidate'] = false;
376 $this->request('GET', '/', array('HTTP_CACHE_CONTROL' => 'max-age=0'));
377 $this->assertEquals(200, $this->response->getStatusCode());
378 $this->assertEquals('Hello World', $this->response->getContent());
379 $this->assertTraceNotContains('stale');
380 $this->assertTraceNotContains('invalid');
381 $this->assertTraceContains('fresh');
383 $this->request('GET', '/', array('HTTP_CACHE_CONTROL' => 'max-age=0'));
384 $this->assertEquals(200, $this->response->getStatusCode());
385 $this->assertEquals('Hello World', $this->response->getContent());
386 $this->assertTraceNotContains('stale');
387 $this->assertTraceNotContains('invalid');
388 $this->assertTraceContains('fresh');
391 public function testFetchesResponseFromBackendWhenCacheMisses()
393 $time = \DateTime::createFromFormat('U', time() + 5);
394 $this->setNextResponse(200, array('Cache-Control' => 'public', 'Expires' => $time->format(DATE_RFC2822)));
396 $this->request('GET', '/');
397 $this->assertEquals(200, $this->response->getStatusCode());
398 $this->assertTraceContains('miss');
399 $this->assertTrue($this->response->headers->has('Age'));
402 public function testDoesNotCacheSomeStatusCodeResponses()
404 foreach (array_merge(range(201, 202), range(204, 206), range(303, 305), range(400, 403), range(405, 409), range(411, 417), range(500, 505)) as $code) {
405 $time = \DateTime::createFromFormat('U', time() + 5);
406 $this->setNextResponse($code, array('Expires' => $time->format(DATE_RFC2822)));
408 $this->request('GET', '/');
409 $this->assertEquals($code, $this->response->getStatusCode());
410 $this->assertTraceNotContains('store');
411 $this->assertFalse($this->response->headers->has('Age'));
415 public function testDoesNotCacheResponsesWithExplicitNoStoreDirective()
417 $time = \DateTime::createFromFormat('U', time() + 5);
418 $this->setNextResponse(200, array('Expires' => $time->format(DATE_RFC2822), 'Cache-Control' => 'no-store'));
420 $this->request('GET', '/');
421 $this->assertTraceNotContains('store');
422 $this->assertFalse($this->response->headers->has('Age'));
425 public function testDoesNotCacheResponsesWithoutFreshnessInformationOrAValidator()
427 $this->setNextResponse();
429 $this->request('GET', '/');
430 $this->assertEquals(200, $this->response->getStatusCode());
431 $this->assertTraceNotContains('store');
434 public function testCachesResponsesWithExplicitNoCacheDirective()
436 $time = \DateTime::createFromFormat('U', time() + 5);
437 $this->setNextResponse(200, array('Expires' => $time->format(DATE_RFC2822), 'Cache-Control' => 'public, no-cache'));
439 $this->request('GET', '/');
440 $this->assertTraceContains('store');
441 $this->assertTrue($this->response->headers->has('Age'));
444 public function testCachesResponsesWithAnExpirationHeader()
446 $time = \DateTime::createFromFormat('U', time() + 5);
447 $this->setNextResponse(200, array('Cache-Control' => 'public', 'Expires' => $time->format(DATE_RFC2822)));
449 $this->request('GET', '/');
450 $this->assertEquals(200, $this->response->getStatusCode());
451 $this->assertEquals('Hello World', $this->response->getContent());
452 $this->assertNotNull($this->response->headers->get('Date'));
453 $this->assertNotNull($this->response->headers->get('X-Content-Digest'));
454 $this->assertTraceContains('miss');
455 $this->assertTraceContains('store');
457 $values = $this->getMetaStorageValues();
458 $this->assertCount(1, $values);
461 public function testCachesResponsesWithAMaxAgeDirective()
463 $this->setNextResponse(200, array('Cache-Control' => 'public, max-age=5'));
465 $this->request('GET', '/');
466 $this->assertEquals(200, $this->response->getStatusCode());
467 $this->assertEquals('Hello World', $this->response->getContent());
468 $this->assertNotNull($this->response->headers->get('Date'));
469 $this->assertNotNull($this->response->headers->get('X-Content-Digest'));
470 $this->assertTraceContains('miss');
471 $this->assertTraceContains('store');
473 $values = $this->getMetaStorageValues();
474 $this->assertCount(1, $values);
477 public function testCachesResponsesWithASMaxAgeDirective()
479 $this->setNextResponse(200, array('Cache-Control' => 's-maxage=5'));
481 $this->request('GET', '/');
482 $this->assertEquals(200, $this->response->getStatusCode());
483 $this->assertEquals('Hello World', $this->response->getContent());
484 $this->assertNotNull($this->response->headers->get('Date'));
485 $this->assertNotNull($this->response->headers->get('X-Content-Digest'));
486 $this->assertTraceContains('miss');
487 $this->assertTraceContains('store');
489 $values = $this->getMetaStorageValues();
490 $this->assertCount(1, $values);
493 public function testCachesResponsesWithALastModifiedValidatorButNoFreshnessInformation()
495 $time = \DateTime::createFromFormat('U', time());
496 $this->setNextResponse(200, array('Cache-Control' => 'public', 'Last-Modified' => $time->format(DATE_RFC2822)));
498 $this->request('GET', '/');
499 $this->assertEquals(200, $this->response->getStatusCode());
500 $this->assertEquals('Hello World', $this->response->getContent());
501 $this->assertTraceContains('miss');
502 $this->assertTraceContains('store');
505 public function testCachesResponsesWithAnETagValidatorButNoFreshnessInformation()
507 $this->setNextResponse(200, array('Cache-Control' => 'public', 'ETag' => '"123456"'));
509 $this->request('GET', '/');
510 $this->assertEquals(200, $this->response->getStatusCode());
511 $this->assertEquals('Hello World', $this->response->getContent());
512 $this->assertTraceContains('miss');
513 $this->assertTraceContains('store');
516 public function testHitsCachedResponsesWithExpiresHeader()
518 $time1 = \DateTime::createFromFormat('U', time() - 5);
519 $time2 = \DateTime::createFromFormat('U', time() + 5);
520 $this->setNextResponse(200, array('Cache-Control' => 'public', 'Date' => $time1->format(DATE_RFC2822), 'Expires' => $time2->format(DATE_RFC2822)));
522 $this->request('GET', '/');
523 $this->assertHttpKernelIsCalled();
524 $this->assertEquals(200, $this->response->getStatusCode());
525 $this->assertNotNull($this->response->headers->get('Date'));
526 $this->assertTraceContains('miss');
527 $this->assertTraceContains('store');
528 $this->assertEquals('Hello World', $this->response->getContent());
530 $this->request('GET', '/');
531 $this->assertHttpKernelIsNotCalled();
532 $this->assertEquals(200, $this->response->getStatusCode());
533 $this->assertTrue(strtotime($this->responses[0]->headers->get('Date')) - strtotime($this->response->headers->get('Date')) < 2);
534 $this->assertTrue($this->response->headers->get('Age') > 0);
535 $this->assertNotNull($this->response->headers->get('X-Content-Digest'));
536 $this->assertTraceContains('fresh');
537 $this->assertTraceNotContains('store');
538 $this->assertEquals('Hello World', $this->response->getContent());
541 public function testHitsCachedResponseWithMaxAgeDirective()
543 $time = \DateTime::createFromFormat('U', time() - 5);
544 $this->setNextResponse(200, array('Date' => $time->format(DATE_RFC2822), 'Cache-Control' => 'public, max-age=10'));
546 $this->request('GET', '/');
547 $this->assertHttpKernelIsCalled();
548 $this->assertEquals(200, $this->response->getStatusCode());
549 $this->assertNotNull($this->response->headers->get('Date'));
550 $this->assertTraceContains('miss');
551 $this->assertTraceContains('store');
552 $this->assertEquals('Hello World', $this->response->getContent());
554 $this->request('GET', '/');
555 $this->assertHttpKernelIsNotCalled();
556 $this->assertEquals(200, $this->response->getStatusCode());
557 $this->assertTrue(strtotime($this->responses[0]->headers->get('Date')) - strtotime($this->response->headers->get('Date')) < 2);
558 $this->assertTrue($this->response->headers->get('Age') > 0);
559 $this->assertNotNull($this->response->headers->get('X-Content-Digest'));
560 $this->assertTraceContains('fresh');
561 $this->assertTraceNotContains('store');
562 $this->assertEquals('Hello World', $this->response->getContent());
565 public function testHitsCachedResponseWithSMaxAgeDirective()
567 $time = \DateTime::createFromFormat('U', time() - 5);
568 $this->setNextResponse(200, array('Date' => $time->format(DATE_RFC2822), 'Cache-Control' => 's-maxage=10, max-age=0'));
570 $this->request('GET', '/');
571 $this->assertHttpKernelIsCalled();
572 $this->assertEquals(200, $this->response->getStatusCode());
573 $this->assertNotNull($this->response->headers->get('Date'));
574 $this->assertTraceContains('miss');
575 $this->assertTraceContains('store');
576 $this->assertEquals('Hello World', $this->response->getContent());
578 $this->request('GET', '/');
579 $this->assertHttpKernelIsNotCalled();
580 $this->assertEquals(200, $this->response->getStatusCode());
581 $this->assertTrue(strtotime($this->responses[0]->headers->get('Date')) - strtotime($this->response->headers->get('Date')) < 2);
582 $this->assertTrue($this->response->headers->get('Age') > 0);
583 $this->assertNotNull($this->response->headers->get('X-Content-Digest'));
584 $this->assertTraceContains('fresh');
585 $this->assertTraceNotContains('store');
586 $this->assertEquals('Hello World', $this->response->getContent());
589 public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformation()
591 $this->setNextResponse();
593 $this->cacheConfig['default_ttl'] = 10;
594 $this->request('GET', '/');
595 $this->assertHttpKernelIsCalled();
596 $this->assertTraceContains('miss');
597 $this->assertTraceContains('store');
598 $this->assertEquals('Hello World', $this->response->getContent());
599 $this->assertRegExp('/s-maxage=10/', $this->response->headers->get('Cache-Control'));
601 $this->cacheConfig['default_ttl'] = 10;
602 $this->request('GET', '/');
603 $this->assertHttpKernelIsNotCalled();
604 $this->assertEquals(200, $this->response->getStatusCode());
605 $this->assertTraceContains('fresh');
606 $this->assertTraceNotContains('store');
607 $this->assertEquals('Hello World', $this->response->getContent());
608 $this->assertRegExp('/s-maxage=10/', $this->response->headers->get('Cache-Control'));
611 public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAfterTtlWasExpired()
613 $this->setNextResponse();
615 $this->cacheConfig['default_ttl'] = 2;
616 $this->request('GET', '/');
617 $this->assertHttpKernelIsCalled();
618 $this->assertTraceContains('miss');
619 $this->assertTraceContains('store');
620 $this->assertEquals('Hello World', $this->response->getContent());
621 $this->assertRegExp('/s-maxage=2/', $this->response->headers->get('Cache-Control'));
623 $this->request('GET', '/');
624 $this->assertHttpKernelIsNotCalled();
625 $this->assertEquals(200, $this->response->getStatusCode());
626 $this->assertTraceContains('fresh');
627 $this->assertTraceNotContains('store');
628 $this->assertEquals('Hello World', $this->response->getContent());
629 $this->assertRegExp('/s-maxage=2/', $this->response->headers->get('Cache-Control'));
632 $values = $this->getMetaStorageValues();
633 $this->assertCount(1, $values);
634 $tmp = unserialize($values[0]);
635 $time = \DateTime::createFromFormat('U', time() - 5);
636 $tmp[0][1]['date'] = $time->format(DATE_RFC2822);
637 $r = new \ReflectionObject($this->store);
638 $m = $r->getMethod('save');
639 $m->setAccessible(true);
640 $m->invoke($this->store, 'md'.hash('sha256', 'http://localhost/'), serialize($tmp));
642 $this->request('GET', '/');
643 $this->assertHttpKernelIsCalled();
644 $this->assertEquals(200, $this->response->getStatusCode());
645 $this->assertTraceContains('stale');
646 $this->assertTraceContains('invalid');
647 $this->assertTraceContains('store');
648 $this->assertEquals('Hello World', $this->response->getContent());
649 $this->assertRegExp('/s-maxage=2/', $this->response->headers->get('Cache-Control'));
651 $this->setNextResponse();
653 $this->request('GET', '/');
654 $this->assertHttpKernelIsNotCalled();
655 $this->assertEquals(200, $this->response->getStatusCode());
656 $this->assertTraceContains('fresh');
657 $this->assertTraceNotContains('store');
658 $this->assertEquals('Hello World', $this->response->getContent());
659 $this->assertRegExp('/s-maxage=2/', $this->response->headers->get('Cache-Control'));
662 public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAfterTtlWasExpiredWithStatus304()
664 $this->setNextResponse();
666 $this->cacheConfig['default_ttl'] = 2;
667 $this->request('GET', '/');
668 $this->assertHttpKernelIsCalled();
669 $this->assertTraceContains('miss');
670 $this->assertTraceContains('store');
671 $this->assertEquals('Hello World', $this->response->getContent());
672 $this->assertRegExp('/s-maxage=2/', $this->response->headers->get('Cache-Control'));
674 $this->request('GET', '/');
675 $this->assertHttpKernelIsNotCalled();
676 $this->assertEquals(200, $this->response->getStatusCode());
677 $this->assertTraceContains('fresh');
678 $this->assertTraceNotContains('store');
679 $this->assertEquals('Hello World', $this->response->getContent());
682 $values = $this->getMetaStorageValues();
683 $this->assertCount(1, $values);
684 $tmp = unserialize($values[0]);
685 $time = \DateTime::createFromFormat('U', time() - 5);
686 $tmp[0][1]['date'] = $time->format(DATE_RFC2822);
687 $r = new \ReflectionObject($this->store);
688 $m = $r->getMethod('save');
689 $m->setAccessible(true);
690 $m->invoke($this->store, 'md'.hash('sha256', 'http://localhost/'), serialize($tmp));
692 $this->request('GET', '/');
693 $this->assertHttpKernelIsCalled();
694 $this->assertEquals(200, $this->response->getStatusCode());
695 $this->assertTraceContains('stale');
696 $this->assertTraceContains('valid');
697 $this->assertTraceContains('store');
698 $this->assertTraceNotContains('miss');
699 $this->assertEquals('Hello World', $this->response->getContent());
700 $this->assertRegExp('/s-maxage=2/', $this->response->headers->get('Cache-Control'));
702 $this->request('GET', '/');
703 $this->assertHttpKernelIsNotCalled();
704 $this->assertEquals(200, $this->response->getStatusCode());
705 $this->assertTraceContains('fresh');
706 $this->assertTraceNotContains('store');
707 $this->assertEquals('Hello World', $this->response->getContent());
708 $this->assertRegExp('/s-maxage=2/', $this->response->headers->get('Cache-Control'));
711 public function testDoesNotAssignDefaultTtlWhenResponseHasMustRevalidateDirective()
713 $this->setNextResponse(200, array('Cache-Control' => 'must-revalidate'));
715 $this->cacheConfig['default_ttl'] = 10;
716 $this->request('GET', '/');
717 $this->assertHttpKernelIsCalled();
718 $this->assertEquals(200, $this->response->getStatusCode());
719 $this->assertTraceContains('miss');
720 $this->assertTraceNotContains('store');
721 $this->assertNotRegExp('/s-maxage/', $this->response->headers->get('Cache-Control'));
722 $this->assertEquals('Hello World', $this->response->getContent());
725 public function testFetchesFullResponseWhenCacheStaleAndNoValidatorsPresent()
727 $time = \DateTime::createFromFormat('U', time() + 5);
728 $this->setNextResponse(200, array('Cache-Control' => 'public', 'Expires' => $time->format(DATE_RFC2822)));
730 // build initial request
731 $this->request('GET', '/');
732 $this->assertHttpKernelIsCalled();
733 $this->assertEquals(200, $this->response->getStatusCode());
734 $this->assertNotNull($this->response->headers->get('Date'));
735 $this->assertNotNull($this->response->headers->get('X-Content-Digest'));
736 $this->assertNotNull($this->response->headers->get('Age'));
737 $this->assertTraceContains('miss');
738 $this->assertTraceContains('store');
739 $this->assertEquals('Hello World', $this->response->getContent());
741 // go in and play around with the cached metadata directly ...
742 $values = $this->getMetaStorageValues();
743 $this->assertCount(1, $values);
744 $tmp = unserialize($values[0]);
745 $time = \DateTime::createFromFormat('U', time());
746 $tmp[0][1]['expires'] = $time->format(DATE_RFC2822);
747 $r = new \ReflectionObject($this->store);
748 $m = $r->getMethod('save');
749 $m->setAccessible(true);
750 $m->invoke($this->store, 'md'.hash('sha256', 'http://localhost/'), serialize($tmp));
752 // build subsequent request; should be found but miss due to freshness
753 $this->request('GET', '/');
754 $this->assertHttpKernelIsCalled();
755 $this->assertEquals(200, $this->response->getStatusCode());
756 $this->assertTrue($this->response->headers->get('Age') <= 1);
757 $this->assertNotNull($this->response->headers->get('X-Content-Digest'));
758 $this->assertTraceContains('stale');
759 $this->assertTraceNotContains('fresh');
760 $this->assertTraceNotContains('miss');
761 $this->assertTraceContains('store');
762 $this->assertEquals('Hello World', $this->response->getContent());
765 public function testValidatesCachedResponsesWithLastModifiedAndNoFreshnessInformation()
767 $time = \DateTime::createFromFormat('U', time());
768 $this->setNextResponse(200, array(), 'Hello World', function ($request, $response) use ($time) {
769 $response->headers->set('Cache-Control', 'public');
770 $response->headers->set('Last-Modified', $time->format(DATE_RFC2822));
771 if ($time->format(DATE_RFC2822) == $request->headers->get('IF_MODIFIED_SINCE')) {
772 $response->setStatusCode(304);
773 $response->setContent('');
777 // build initial request
778 $this->request('GET', '/');
779 $this->assertHttpKernelIsCalled();
780 $this->assertEquals(200, $this->response->getStatusCode());
781 $this->assertNotNull($this->response->headers->get('Last-Modified'));
782 $this->assertNotNull($this->response->headers->get('X-Content-Digest'));
783 $this->assertEquals('Hello World', $this->response->getContent());
784 $this->assertTraceContains('miss');
785 $this->assertTraceContains('store');
786 $this->assertTraceNotContains('stale');
788 // build subsequent request; should be found but miss due to freshness
789 $this->request('GET', '/');
790 $this->assertHttpKernelIsCalled();
791 $this->assertEquals(200, $this->response->getStatusCode());
792 $this->assertNotNull($this->response->headers->get('Last-Modified'));
793 $this->assertNotNull($this->response->headers->get('X-Content-Digest'));
794 $this->assertTrue($this->response->headers->get('Age') <= 1);
795 $this->assertEquals('Hello World', $this->response->getContent());
796 $this->assertTraceContains('stale');
797 $this->assertTraceContains('valid');
798 $this->assertTraceContains('store');
799 $this->assertTraceNotContains('miss');
802 public function testValidatesCachedResponsesUseSameHttpMethod()
806 $this->setNextResponse(200, array(), 'Hello World', function ($request, $response) use ($test) {
807 $test->assertSame('OPTIONS', $request->getMethod());
810 // build initial request
811 $this->request('OPTIONS', '/');
813 // build subsequent request
814 $this->request('OPTIONS', '/');
817 public function testValidatesCachedResponsesWithETagAndNoFreshnessInformation()
819 $this->setNextResponse(200, array(), 'Hello World', function ($request, $response) {
820 $response->headers->set('Cache-Control', 'public');
821 $response->headers->set('ETag', '"12345"');
822 if ($response->getETag() == $request->headers->get('IF_NONE_MATCH')) {
823 $response->setStatusCode(304);
824 $response->setContent('');
828 // build initial request
829 $this->request('GET', '/');
830 $this->assertHttpKernelIsCalled();
831 $this->assertEquals(200, $this->response->getStatusCode());
832 $this->assertNotNull($this->response->headers->get('ETag'));
833 $this->assertNotNull($this->response->headers->get('X-Content-Digest'));
834 $this->assertEquals('Hello World', $this->response->getContent());
835 $this->assertTraceContains('miss');
836 $this->assertTraceContains('store');
838 // build subsequent request; should be found but miss due to freshness
839 $this->request('GET', '/');
840 $this->assertHttpKernelIsCalled();
841 $this->assertEquals(200, $this->response->getStatusCode());
842 $this->assertNotNull($this->response->headers->get('ETag'));
843 $this->assertNotNull($this->response->headers->get('X-Content-Digest'));
844 $this->assertTrue($this->response->headers->get('Age') <= 1);
845 $this->assertEquals('Hello World', $this->response->getContent());
846 $this->assertTraceContains('stale');
847 $this->assertTraceContains('valid');
848 $this->assertTraceContains('store');
849 $this->assertTraceNotContains('miss');
852 public function testServesResponseWhileFreshAndRevalidatesWithLastModifiedInformation()
854 $time = \DateTime::createFromFormat('U', time());
856 $this->setNextResponse(200, array(), 'Hello World', function (Request $request, Response $response) use ($time) {
857 $response->setSharedMaxAge(10);
858 $response->headers->set('Last-Modified', $time->format(DATE_RFC2822));
862 $this->request('GET', '/');
864 // next request before s-maxage has expired: Serve from cache
865 // without hitting the backend
866 $this->request('GET', '/');
867 $this->assertHttpKernelIsNotCalled();
868 $this->assertEquals(200, $this->response->getStatusCode());
869 $this->assertEquals('Hello World', $this->response->getContent());
870 $this->assertTraceContains('fresh');
872 sleep(15); // expire the cache
876 $this->setNextResponse(304, array(), '', function (Request $request, Response $response) use ($time, $that) {
877 $that->assertEquals($time->format(DATE_RFC2822), $request->headers->get('IF_MODIFIED_SINCE'));
880 $this->request('GET', '/');
881 $this->assertHttpKernelIsCalled();
882 $this->assertEquals(200, $this->response->getStatusCode());
883 $this->assertEquals('Hello World', $this->response->getContent());
884 $this->assertTraceContains('stale');
885 $this->assertTraceContains('valid');
888 public function testReplacesCachedResponsesWhenValidationResultsInNon304Response()
890 $time = \DateTime::createFromFormat('U', time());
892 $this->setNextResponse(200, array(), 'Hello World', function ($request, $response) use ($time, &$count) {
893 $response->headers->set('Last-Modified', $time->format(DATE_RFC2822));
894 $response->headers->set('Cache-Control', 'public');
897 $response->setContent('first response');
900 $response->setContent('second response');
903 $response->setContent('');
904 $response->setStatusCode(304);
909 // first request should fetch from backend and store in cache
910 $this->request('GET', '/');
911 $this->assertEquals(200, $this->response->getStatusCode());
912 $this->assertEquals('first response', $this->response->getContent());
914 // second request is validated, is invalid, and replaces cached entry
915 $this->request('GET', '/');
916 $this->assertEquals(200, $this->response->getStatusCode());
917 $this->assertEquals('second response', $this->response->getContent());
919 // third response is validated, valid, and returns cached entry
920 $this->request('GET', '/');
921 $this->assertEquals(200, $this->response->getStatusCode());
922 $this->assertEquals('second response', $this->response->getContent());
924 $this->assertEquals(3, $count);
927 public function testPassesHeadRequestsThroughDirectlyOnPass()
930 $this->setNextResponse(200, array(), 'Hello World', function ($request, $response) use ($that) {
931 $response->setContent('');
932 $response->setStatusCode(200);
933 $that->assertEquals('HEAD', $request->getMethod());
936 $this->request('HEAD', '/', array('HTTP_EXPECT' => 'something ...'));
937 $this->assertHttpKernelIsCalled();
938 $this->assertEquals('', $this->response->getContent());
941 public function testUsesCacheToRespondToHeadRequestsWhenFresh()
944 $this->setNextResponse(200, array(), 'Hello World', function ($request, $response) use ($that) {
945 $response->headers->set('Cache-Control', 'public, max-age=10');
946 $response->setContent('Hello World');
947 $response->setStatusCode(200);
948 $that->assertNotEquals('HEAD', $request->getMethod());
951 $this->request('GET', '/');
952 $this->assertHttpKernelIsCalled();
953 $this->assertEquals('Hello World', $this->response->getContent());
955 $this->request('HEAD', '/');
956 $this->assertHttpKernelIsNotCalled();
957 $this->assertEquals(200, $this->response->getStatusCode());
958 $this->assertEquals('', $this->response->getContent());
959 $this->assertEquals(strlen('Hello World'), $this->response->headers->get('Content-Length'));
962 public function testSendsNoContentWhenFresh()
964 $time = \DateTime::createFromFormat('U', time());
966 $this->setNextResponse(200, array(), 'Hello World', function ($request, $response) use ($that, $time) {
967 $response->headers->set('Cache-Control', 'public, max-age=10');
968 $response->headers->set('Last-Modified', $time->format(DATE_RFC2822));
971 $this->request('GET', '/');
972 $this->assertHttpKernelIsCalled();
973 $this->assertEquals('Hello World', $this->response->getContent());
975 $this->request('GET', '/', array('HTTP_IF_MODIFIED_SINCE' => $time->format(DATE_RFC2822)));
976 $this->assertHttpKernelIsNotCalled();
977 $this->assertEquals(304, $this->response->getStatusCode());
978 $this->assertEquals('', $this->response->getContent());
981 public function testInvalidatesCachedResponsesOnPost()
983 $this->setNextResponse(200, array(), 'Hello World', function ($request, $response) {
984 if ('GET' == $request->getMethod()) {
985 $response->setStatusCode(200);
986 $response->headers->set('Cache-Control', 'public, max-age=500');
987 $response->setContent('Hello World');
988 } elseif ('POST' == $request->getMethod()) {
989 $response->setStatusCode(303);
990 $response->headers->set('Location', '/');
991 $response->headers->remove('Cache-Control');
992 $response->setContent('');
996 // build initial request to enter into the cache
997 $this->request('GET', '/');
998 $this->assertHttpKernelIsCalled();
999 $this->assertEquals(200, $this->response->getStatusCode());
1000 $this->assertEquals('Hello World', $this->response->getContent());
1001 $this->assertTraceContains('miss');
1002 $this->assertTraceContains('store');
1004 // make sure it is valid
1005 $this->request('GET', '/');
1006 $this->assertHttpKernelIsNotCalled();
1007 $this->assertEquals(200, $this->response->getStatusCode());
1008 $this->assertEquals('Hello World', $this->response->getContent());
1009 $this->assertTraceContains('fresh');
1011 // now POST to same URL
1012 $this->request('POST', '/helloworld');
1013 $this->assertHttpKernelIsCalled();
1014 $this->assertEquals('/', $this->response->headers->get('Location'));
1015 $this->assertTraceContains('invalidate');
1016 $this->assertTraceContains('pass');
1017 $this->assertEquals('', $this->response->getContent());
1019 // now make sure it was actually invalidated
1020 $this->request('GET', '/');
1021 $this->assertHttpKernelIsCalled();
1022 $this->assertEquals(200, $this->response->getStatusCode());
1023 $this->assertEquals('Hello World', $this->response->getContent());
1024 $this->assertTraceContains('stale');
1025 $this->assertTraceContains('invalid');
1026 $this->assertTraceContains('store');
1029 public function testServesFromCacheWhenHeadersMatch()
1032 $this->setNextResponse(200, array('Cache-Control' => 'max-age=10000'), '', function ($request, $response) use (&$count) {
1033 $response->headers->set('Vary', 'Accept User-Agent Foo');
1034 $response->headers->set('Cache-Control', 'public, max-age=10');
1035 $response->headers->set('X-Response-Count', ++$count);
1036 $response->setContent($request->headers->get('USER_AGENT'));
1039 $this->request('GET', '/', array('HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/1.0'));
1040 $this->assertEquals(200, $this->response->getStatusCode());
1041 $this->assertEquals('Bob/1.0', $this->response->getContent());
1042 $this->assertTraceContains('miss');
1043 $this->assertTraceContains('store');
1045 $this->request('GET', '/', array('HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/1.0'));
1046 $this->assertEquals(200, $this->response->getStatusCode());
1047 $this->assertEquals('Bob/1.0', $this->response->getContent());
1048 $this->assertTraceContains('fresh');
1049 $this->assertTraceNotContains('store');
1050 $this->assertNotNull($this->response->headers->get('X-Content-Digest'));
1053 public function testStoresMultipleResponsesWhenHeadersDiffer()
1056 $this->setNextResponse(200, array('Cache-Control' => 'max-age=10000'), '', function ($request, $response) use (&$count) {
1057 $response->headers->set('Vary', 'Accept User-Agent Foo');
1058 $response->headers->set('Cache-Control', 'public, max-age=10');
1059 $response->headers->set('X-Response-Count', ++$count);
1060 $response->setContent($request->headers->get('USER_AGENT'));
1063 $this->request('GET', '/', array('HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/1.0'));
1064 $this->assertEquals(200, $this->response->getStatusCode());
1065 $this->assertEquals('Bob/1.0', $this->response->getContent());
1066 $this->assertEquals(1, $this->response->headers->get('X-Response-Count'));
1068 $this->request('GET', '/', array('HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/2.0'));
1069 $this->assertEquals(200, $this->response->getStatusCode());
1070 $this->assertTraceContains('miss');
1071 $this->assertTraceContains('store');
1072 $this->assertEquals('Bob/2.0', $this->response->getContent());
1073 $this->assertEquals(2, $this->response->headers->get('X-Response-Count'));
1075 $this->request('GET', '/', array('HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/1.0'));
1076 $this->assertTraceContains('fresh');
1077 $this->assertEquals('Bob/1.0', $this->response->getContent());
1078 $this->assertEquals(1, $this->response->headers->get('X-Response-Count'));
1080 $this->request('GET', '/', array('HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/2.0'));
1081 $this->assertTraceContains('fresh');
1082 $this->assertEquals('Bob/2.0', $this->response->getContent());
1083 $this->assertEquals(2, $this->response->headers->get('X-Response-Count'));
1085 $this->request('GET', '/', array('HTTP_USER_AGENT' => 'Bob/2.0'));
1086 $this->assertTraceContains('miss');
1087 $this->assertEquals('Bob/2.0', $this->response->getContent());
1088 $this->assertEquals(3, $this->response->headers->get('X-Response-Count'));
1091 public function testShouldCatchExceptions()
1093 $this->catchExceptions();
1095 $this->setNextResponse();
1096 $this->request('GET', '/');
1098 $this->assertExceptionsAreCaught();
1101 public function testShouldCatchExceptionsWhenReloadingAndNoCacheRequest()
1103 $this->catchExceptions();
1105 $this->setNextResponse();
1106 $this->cacheConfig['allow_reload'] = true;
1107 $this->request('GET', '/', array(), array(), false, array('Pragma' => 'no-cache'));
1109 $this->assertExceptionsAreCaught();
1112 public function testShouldNotCatchExceptions()
1114 $this->catchExceptions(false);
1116 $this->setNextResponse();
1117 $this->request('GET', '/');
1119 $this->assertExceptionsAreNotCaught();
1122 public function testEsiCacheSendsTheLowestTtl()
1127 'body' => '<esi:include src="/foo" /> <esi:include src="/bar" />',
1129 'Cache-Control' => 's-maxage=300',
1130 'Surrogate-Control' => 'content="ESI/1.0"',
1135 'body' => 'Hello World!',
1136 'headers' => array('Cache-Control' => 's-maxage=300'),
1140 'body' => 'My name is Bobby.',
1141 'headers' => array('Cache-Control' => 's-maxage=100'),
1145 $this->setNextResponses($responses);
1147 $this->request('GET', '/', array(), array(), true);
1148 $this->assertEquals('Hello World! My name is Bobby.', $this->response->getContent());
1150 // check for 100 or 99 as the test can be executed after a second change
1151 $this->assertTrue(in_array($this->response->getTtl(), array(99, 100)));
1154 public function testEsiCacheForceValidation()
1159 'body' => '<esi:include src="/foo" /> <esi:include src="/bar" />',
1161 'Cache-Control' => 's-maxage=300',
1162 'Surrogate-Control' => 'content="ESI/1.0"',
1167 'body' => 'Hello World!',
1168 'headers' => array('ETag' => 'foobar'),
1172 'body' => 'My name is Bobby.',
1173 'headers' => array('Cache-Control' => 's-maxage=100'),
1177 $this->setNextResponses($responses);
1179 $this->request('GET', '/', array(), array(), true);
1180 $this->assertEquals('Hello World! My name is Bobby.', $this->response->getContent());
1181 $this->assertNull($this->response->getTtl());
1182 $this->assertTrue($this->response->mustRevalidate());
1183 $this->assertTrue($this->response->headers->hasCacheControlDirective('private'));
1184 $this->assertTrue($this->response->headers->hasCacheControlDirective('no-cache'));
1187 public function testEsiRecalculateContentLengthHeader()
1192 'body' => '<esi:include src="/foo" />',
1194 'Content-Length' => 26,
1195 'Cache-Control' => 's-maxage=300',
1196 'Surrogate-Control' => 'content="ESI/1.0"',
1201 'body' => 'Hello World!',
1202 'headers' => array(),
1206 $this->setNextResponses($responses);
1208 $this->request('GET', '/', array(), array(), true);
1209 $this->assertEquals('Hello World!', $this->response->getContent());
1210 $this->assertEquals(12, $this->response->headers->get('Content-Length'));
1213 public function testClientIpIsAlwaysLocalhostForForwardedRequests()
1215 $this->setNextResponse();
1216 $this->request('GET', '/', array('REMOTE_ADDR' => '10.0.0.1'));
1218 $this->assertEquals('127.0.0.1', $this->kernel->getBackendRequest()->server->get('REMOTE_ADDR'));
1222 * @dataProvider getTrustedProxyData
1224 public function testHttpCacheIsSetAsATrustedProxy(array $existing, array $expected)
1226 Request::setTrustedProxies($existing);
1228 $this->setNextResponse();
1229 $this->request('GET', '/', array('REMOTE_ADDR' => '10.0.0.1'));
1231 $this->assertEquals($expected, Request::getTrustedProxies());
1234 public function getTrustedProxyData()
1237 array(array(), array('127.0.0.1')),
1238 array(array('10.0.0.2'), array('10.0.0.2', '127.0.0.1')),
1239 array(array('10.0.0.2', '127.0.0.1'), array('10.0.0.2', '127.0.0.1')),
1244 * @dataProvider getXForwardedForData
1246 public function testXForwarderForHeaderForForwardedRequests($xForwardedFor, $expected)
1248 $this->setNextResponse();
1249 $server = array('REMOTE_ADDR' => '10.0.0.1');
1250 if (false !== $xForwardedFor) {
1251 $server['HTTP_X_FORWARDED_FOR'] = $xForwardedFor;
1253 $this->request('GET', '/', $server);
1255 $this->assertEquals($expected, $this->kernel->getBackendRequest()->headers->get('X-Forwarded-For'));
1258 public function getXForwardedForData()
1261 array(false, '10.0.0.1'),
1262 array('10.0.0.2', '10.0.0.2, 10.0.0.1'),
1263 array('10.0.0.2, 10.0.0.3', '10.0.0.2, 10.0.0.3, 10.0.0.1'),
1267 public function testXForwarderForHeaderForPassRequests()
1269 $this->setNextResponse();
1270 $server = array('REMOTE_ADDR' => '10.0.0.1');
1271 $this->request('POST', '/', $server);
1273 $this->assertEquals('10.0.0.1', $this->kernel->getBackendRequest()->headers->get('X-Forwarded-For'));
1276 public function testEsiCacheRemoveValidationHeadersIfEmbeddedResponses()
1278 $time = \DateTime::createFromFormat('U', time());
1283 'body' => '<esi:include src="/hey" />',
1285 'Surrogate-Control' => 'content="ESI/1.0"',
1287 'Last-Modified' => $time->format(DATE_RFC2822),
1293 'headers' => array(),
1297 $this->setNextResponses($responses);
1299 $this->request('GET', '/', array(), array(), true);
1300 $this->assertNull($this->response->getETag());
1301 $this->assertNull($this->response->getLastModified());
1304 public function testDoesNotCacheOptionsRequest()
1306 $this->setNextResponse(200, array('Cache-Control' => 'public, s-maxage=60'), 'get');
1307 $this->request('GET', '/');
1308 $this->assertHttpKernelIsCalled();
1310 $this->setNextResponse(200, array('Cache-Control' => 'public, s-maxage=60'), 'options');
1311 $this->request('OPTIONS', '/');
1312 $this->assertHttpKernelIsCalled();
1314 $this->request('GET', '/');
1315 $this->assertHttpKernelIsNotCalled();
1316 $this->assertSame('get', $this->response->getContent());
1320 class TestKernel implements HttpKernelInterface
1322 public $terminateCalled = false;
1324 public function terminate(Request $request, Response $response)
1326 $this->terminateCalled = true;
1329 public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true)