26 $this->assertInstanceOf(
'Symfony\Component\HttpFoundation\Response', $response);
27 $this->assertEquals(301, $response->getStatusCode());
28 $this->assertEquals(
'bar', $response->headers->get(
'foo'));
34 $response = explode(
"\r\n", $response);
35 $this->assertEquals(
'HTTP/1.0 200 OK', $response[0]);
36 $this->assertEquals(
'Cache-Control: no-cache, private', $response[1]);
42 $responseClone = clone $response;
43 $this->assertEquals($response, $responseClone);
49 $headers = $response->sendHeaders();
50 $this->assertObjectHasAttribute(
'headers', $headers);
51 $this->assertObjectHasAttribute(
'content', $headers);
52 $this->assertObjectHasAttribute(
'version', $headers);
53 $this->assertObjectHasAttribute(
'statusCode', $headers);
54 $this->assertObjectHasAttribute(
'statusText', $headers);
55 $this->assertObjectHasAttribute(
'charset', $headers);
61 $responseSend = $response->send();
62 $this->assertObjectHasAttribute(
'headers', $responseSend);
63 $this->assertObjectHasAttribute(
'content', $responseSend);
64 $this->assertObjectHasAttribute(
'version', $responseSend);
65 $this->assertObjectHasAttribute(
'statusCode', $responseSend);
66 $this->assertObjectHasAttribute(
'statusText', $responseSend);
67 $this->assertObjectHasAttribute(
'charset', $responseSend);
73 $charsetOrigin =
'UTF-8';
74 $response->setCharset($charsetOrigin);
75 $charset = $response->getCharset();
76 $this->assertEquals($charsetOrigin, $charset);
82 $this->assertFalse($response->isCacheable());
88 $this->assertFalse($response->isCacheable());
94 $response->headers->set(
'cache-control',
'private');
95 $this->assertFalse($response->isCacheable());
101 $response->setTtl(10);
102 $this->assertTrue($response->isCacheable());
108 $this->assertFalse($response->mustRevalidate());
114 $response->headers->set(
'cache-control',
'must-revalidate');
116 $this->assertTrue($response->mustRevalidate());
122 $response->headers->set(
'cache-control',
'proxy-revalidate');
124 $this->assertTrue($response->mustRevalidate());
130 $modified = $response->setNotModified();
131 $this->assertObjectHasAttribute(
'headers', $modified);
132 $this->assertObjectHasAttribute(
'content', $modified);
133 $this->assertObjectHasAttribute(
'version', $modified);
134 $this->assertObjectHasAttribute(
'statusCode', $modified);
135 $this->assertObjectHasAttribute(
'statusText', $modified);
136 $this->assertObjectHasAttribute(
'charset', $modified);
137 $this->assertEquals(304, $modified->getStatusCode());
143 $this->assertTrue($response->isSuccessful());
149 $modified = $response->isNotModified(
new Request());
150 $this->assertFalse($modified);
158 $this->assertFalse($response->isNotModified($request));
163 $before =
'Sun, 25 Aug 2013 18:32:31 GMT';
164 $modified =
'Sun, 25 Aug 2013 18:33:31 GMT';
165 $after =
'Sun, 25 Aug 2013 19:33:31 GMT';
168 $request->headers->set(
'If-Modified-Since', $modified);
172 $response->headers->set(
'Last-Modified', $modified);
173 $this->assertTrue($response->isNotModified($request));
175 $response->headers->set(
'Last-Modified', $before);
176 $this->assertTrue($response->isNotModified($request));
178 $response->headers->set(
'Last-Modified', $after);
179 $this->assertFalse($response->isNotModified($request));
181 $response->headers->set(
'Last-Modified',
'');
182 $this->assertFalse($response->isNotModified($request));
187 $etagOne =
'randomly_generated_etag';
188 $etagTwo =
'randomly_generated_etag_2';
191 $request->headers->set(
'if_none_match', sprintf(
'%s, %s, %s', $etagOne, $etagTwo,
'etagThree'));
195 $response->headers->set(
'ETag', $etagOne);
196 $this->assertTrue($response->isNotModified($request));
198 $response->headers->set(
'ETag', $etagTwo);
199 $this->assertTrue($response->isNotModified($request));
201 $response->headers->set(
'ETag',
'');
202 $this->assertFalse($response->isNotModified($request));
207 $before =
'Sun, 25 Aug 2013 18:32:31 GMT';
208 $modified =
'Sun, 25 Aug 2013 18:33:31 GMT';
209 $after =
'Sun, 25 Aug 2013 19:33:31 GMT';
210 $etag =
'randomly_generated_etag';
213 $request->headers->set(
'if_none_match', sprintf(
'%s, %s', $etag,
'etagThree'));
214 $request->headers->set(
'If-Modified-Since', $modified);
218 $response->headers->set(
'ETag', $etag);
219 $response->headers->set(
'Last-Modified', $after);
220 $this->assertFalse($response->isNotModified($request));
222 $response->headers->set(
'ETag',
'non-existent-etag');
223 $response->headers->set(
'Last-Modified', $before);
224 $this->assertFalse($response->isNotModified($request));
226 $response->headers->set(
'ETag', $etag);
227 $response->headers->set(
'Last-Modified', $modified);
228 $this->assertTrue($response->isNotModified($request));
233 $modified =
'Sun, 25 Aug 2013 18:33:31 GMT';
234 $etag =
'randomly_generated_etag';
237 $request->headers->set(
'if_none_match', sprintf(
'%s, %s', $etag,
'etagThree'));
238 $request->headers->set(
'If-Modified-Since', $modified);
242 $response->headers->set(
'ETag', $etag);
243 $this->assertTrue($response->isNotModified($request));
245 $response->headers->set(
'ETag',
'non-existent-etag');
246 $this->assertFalse($response->isNotModified($request));
252 $this->assertTrue($response->isValidateable(),
'->isValidateable() returns true if Last-Modified is present');
254 $response =
new Response(
'', 200, array(
'ETag' =>
'"12345"'));
255 $this->assertTrue($response->isValidateable(),
'->isValidateable() returns true if ETag is present');
258 $this->assertFalse($response->isValidateable(),
'->isValidateable() returns false when no validator is present');
264 $response =
new Response(
'', 200, array(
'Date' => $oneHourAgo->format(DATE_RFC2822)));
265 $date = $response->getDate();
266 $this->assertEquals($oneHourAgo->getTimestamp(), $date->getTimestamp(),
'->getDate() returns the Date header if present');
269 $date = $response->getDate();
270 $this->assertEquals(time(), $date->getTimestamp(),
'->getDate() returns the current Date if no Date header present');
274 $response->headers->set(
'Date', $now->format(DATE_RFC2822));
275 $date = $response->getDate();
276 $this->assertEquals($now->getTimestamp(), $date->getTimestamp(),
'->getDate() returns the date when the header has been modified');
280 $response->headers->remove(
'Date');
281 $date = $response->getDate();
282 $this->assertEquals($now->getTimestamp(), $date->getTimestamp(),
'->getDate() returns the current Date when the header has previously been removed');
288 $response->headers->set(
'Cache-Control',
's-maxage=600, max-age=0');
289 $this->assertEquals(600, $response->getMaxAge(),
'->getMaxAge() uses s-maxage cache control directive when present');
292 $response->headers->set(
'Cache-Control',
'max-age=600');
293 $this->assertEquals(600, $response->getMaxAge(),
'->getMaxAge() falls back to max-age when no s-maxage directive present');
296 $response->headers->set(
'Cache-Control',
'must-revalidate');
298 $this->assertEquals(3600, $response->getMaxAge(),
'->getMaxAge() falls back to Expires when no max-age or s-maxage directive present');
301 $response->headers->set(
'Cache-Control',
'must-revalidate');
302 $response->headers->set(
'Expires', -1);
303 $this->assertEquals(
'Sat, 01 Jan 00 00:00:00 +0000', $response->getExpires()->format(DATE_RFC822));
306 $this->assertNull($response->getMaxAge(),
'->getMaxAge() returns null if no freshness information available');
312 $response->setSharedMaxAge(20);
314 $cacheControl = $response->headers->get(
'Cache-Control');
315 $this->assertEquals(
'public, s-maxage=20', $cacheControl);
321 $response->headers->set(
'Cache-Control',
'max-age=100');
322 $response->setPrivate();
323 $this->assertEquals(100, $response->headers->getCacheControlDirective(
'max-age'),
'->isPrivate() adds the private Cache-Control directive when set to true');
324 $this->assertTrue($response->headers->getCacheControlDirective(
'private'),
'->isPrivate() adds the private Cache-Control directive when set to true');
327 $response->headers->set(
'Cache-Control',
'public, max-age=100');
328 $response->setPrivate();
329 $this->assertEquals(100, $response->headers->getCacheControlDirective(
'max-age'),
'->isPrivate() adds the private Cache-Control directive when set to true');
330 $this->assertTrue($response->headers->getCacheControlDirective(
'private'),
'->isPrivate() adds the private Cache-Control directive when set to true');
331 $this->assertFalse($response->headers->hasCacheControlDirective(
'public'),
'->isPrivate() removes the public Cache-Control directive');
337 $response->headers->set(
'Cache-Control',
'max-age=100');
339 $this->assertEquals(100, $response->headers->get(
'Age'),
'->expire() sets the Age to max-age when present');
342 $response->headers->set(
'Cache-Control',
'max-age=100, s-maxage=500');
344 $this->assertEquals(500, $response->headers->get(
'Age'),
'->expire() sets the Age to s-maxage when both max-age and s-maxage are present');
347 $response->headers->set(
'Cache-Control',
'max-age=5, s-maxage=500');
348 $response->headers->set(
'Age',
'1000');
350 $this->assertEquals(1000, $response->headers->get(
'Age'),
'->expire() does nothing when the response is already stale/expired');
354 $this->assertFalse($response->headers->has(
'Age'),
'->expire() does nothing when the response does not include freshness information');
357 $response->headers->set(
'Expires', -1);
359 $this->assertNull($response->headers->get(
'Age'),
'->expire() does not set the Age when the response is expired');
365 $this->assertNull($response->getTtl(),
'->getTtl() returns null when no Expires or Cache-Control headers are present');
369 $this->assertEquals(3600, $response->getTtl(),
'->getTtl() uses the Expires header when no max-age is present');
373 $this->assertLessThan(0, $response->getTtl(),
'->getTtl() returns negative values when Expires is in past');
376 $response->headers->set(
'Expires', $response->getDate()->format(DATE_RFC2822));
377 $response->headers->set(
'Age', 0);
378 $this->assertSame(0, $response->getTtl(),
'->getTtl() correctly handles zero');
381 $response->headers->set(
'Cache-Control',
'max-age=60');
382 $this->assertEquals(60, $response->getTtl(),
'->getTtl() uses Cache-Control max-age when present');
388 $response->setClientTtl(10);
390 $this->assertEquals($response->getMaxAge(), $response->getAge() + 10);
397 $this->assertEquals(
'1.0', $response->getProtocolVersion());
399 $response->setProtocolVersion(
'1.1');
401 $this->assertEquals(
'1.1', $response->getProtocolVersion());
407 $this->assertEquals(array(), $response->getVary(),
'->getVary() returns an empty array if no Vary header is present');
410 $response->headers->set(
'Vary',
'Accept-Language');
411 $this->assertEquals(array(
'Accept-Language'), $response->getVary(),
'->getVary() parses a single header name value');
414 $response->headers->set(
'Vary',
'Accept-Language User-Agent X-Foo');
415 $this->assertEquals(array(
'Accept-Language',
'User-Agent',
'X-Foo'), $response->getVary(),
'->getVary() parses multiple header name values separated by spaces');
418 $response->headers->set(
'Vary',
'Accept-Language,User-Agent, X-Foo');
419 $this->assertEquals(array(
'Accept-Language',
'User-Agent',
'X-Foo'), $response->getVary(),
'->getVary() parses multiple header name values separated by commas');
421 $vary = array(
'Accept-Language',
'User-Agent',
'X-foo');
424 $response->headers->set(
'Vary', $vary);
425 $this->assertEquals($vary, $response->getVary(),
'->getVary() parses multiple header name values in arrays');
428 $response->headers->set(
'Vary',
'Accept-Language, User-Agent, X-foo');
429 $this->assertEquals($vary, $response->getVary(),
'->getVary() parses multiple header name values in arrays');
435 $response->setVary(
'Accept-Language');
436 $this->assertEquals(array(
'Accept-Language'), $response->getVary());
438 $response->setVary(
'Accept-Language, User-Agent');
439 $this->assertEquals(array(
'Accept-Language',
'User-Agent'), $response->getVary(),
'->setVary() replace the vary header by default');
441 $response->setVary(
'X-Foo',
false);
442 $this->assertEquals(array(
'Accept-Language',
'User-Agent',
'X-Foo'), $response->getVary(),
'->setVary() doesn\'t wipe out earlier Vary headers if replace is set to false');
447 $headerMock = $this->getMockBuilder(
'Symfony\Component\HttpFoundation\ResponseHeaderBag')->setMethods(array(
'set'))->getMock();
448 $headerMock->expects($this->at(0))
450 ->with(
'Content-Type',
'text/html');
451 $headerMock->expects($this->at(1))
453 ->with(
'Content-Type',
'text/html; charset=UTF-8');
456 $response->headers = $headerMock;
458 $response->prepare(
new Request());
464 $response->headers->set(
'Content-Type',
'text/css');
467 $response->prepare(
new Request());
469 $this->assertEquals(
'text/css; charset=UTF-8', $response->headers->get(
'Content-Type'));
475 $response->headers->set(
'Content-Type',
'text/plain');
477 $response->prepare(
new Request());
479 $this->assertEquals(
'text/plain; charset=UTF-8', $response->headers->get(
'content-type'));
486 $response->prepare(
new Request());
488 $this->assertEquals(
'text/html; charset=UTF-8', $response->headers->get(
'content-type'));
495 $request->setRequestFormat(
'json');
497 $response->prepare($request);
499 $this->assertEquals(
'application/json', $response->headers->get(
'content-type'));
508 $response->headers->set(
'Content-Length', $length);
509 $response->prepare($request);
511 $this->assertEquals(
'', $response->getContent());
512 $this->assertEquals($length, $response->headers->get(
'Content-Length'),
'Content-Length should be as if it was GET; see RFC2616 14.13');
520 $response->setContent(
'content');
521 $response->setStatusCode(101);
522 $response->prepare($request);
523 $this->assertEquals(
'', $response->getContent());
524 $this->assertFalse($response->headers->has(
'Content-Type'));
525 $this->assertFalse($response->headers->has(
'Content-Type'));
527 $response->setContent(
'content');
528 $response->setStatusCode(304);
529 $response->prepare($request);
530 $this->assertEquals(
'', $response->getContent());
531 $this->assertFalse($response->headers->has(
'Content-Type'));
532 $this->assertFalse($response->headers->has(
'Content-Length'));
540 $response->headers->set(
'Content-Length', 12345);
541 $response->prepare($request);
542 $this->assertEquals(12345, $response->headers->get(
'Content-Length'));
544 $response->headers->set(
'Transfer-Encoding',
'chunked');
545 $response->prepare($request);
546 $this->assertFalse($response->headers->has(
'Content-Length'));
552 $request->server->set(
'SERVER_PROTOCOL',
'HTTP/1.0');
555 $response->prepare($request);
556 $this->assertEquals(
'no-cache', $response->headers->get(
'pragma'));
557 $this->assertEquals(
'-1', $response->headers->get(
'expires'));
559 $request->server->set(
'SERVER_PROTOCOL',
'HTTP/1.1');
561 $response->prepare($request);
562 $this->assertFalse($response->headers->has(
'pragma'));
563 $this->assertFalse($response->headers->has(
'expires'));
571 $response->setCache(array(
'wrong option' =>
'value'));
572 $this->fail(
'->setCache() throws an InvalidArgumentException if an option is not supported');
573 }
catch (\Exception $e) {
574 $this->assertInstanceOf(
'InvalidArgumentException', $e,
'->setCache() throws an InvalidArgumentException if an option is not supported');
575 $this->assertContains(
'"wrong option"', $e->getMessage());
578 $options = array(
'etag' =>
'"whatever"');
579 $response->setCache($options);
580 $this->assertEquals($response->getEtag(),
'"whatever"');
583 $options = array(
'last_modified' => $now);
584 $response->setCache($options);
585 $this->assertEquals($response->getLastModified()->getTimestamp(), $now->getTimestamp());
587 $options = array(
'max_age' => 100);
588 $response->setCache($options);
589 $this->assertEquals($response->getMaxAge(), 100);
591 $options = array(
's_maxage' => 200);
592 $response->setCache($options);
593 $this->assertEquals($response->getMaxAge(), 200);
595 $this->assertTrue($response->headers->hasCacheControlDirective(
'public'));
596 $this->assertFalse($response->headers->hasCacheControlDirective(
'private'));
598 $response->setCache(array(
'public' =>
true));
599 $this->assertTrue($response->headers->hasCacheControlDirective(
'public'));
600 $this->assertFalse($response->headers->hasCacheControlDirective(
'private'));
602 $response->setCache(array(
'public' =>
false));
603 $this->assertFalse($response->headers->hasCacheControlDirective(
'public'));
604 $this->assertTrue($response->headers->hasCacheControlDirective(
'private'));
606 $response->setCache(array(
'private' =>
true));
607 $this->assertFalse($response->headers->hasCacheControlDirective(
'public'));
608 $this->assertTrue($response->headers->hasCacheControlDirective(
'private'));
610 $response->setCache(array(
'private' =>
false));
611 $this->assertTrue($response->headers->hasCacheControlDirective(
'public'));
612 $this->assertFalse($response->headers->hasCacheControlDirective(
'private'));
617 $response =
new Response(
'test response rendering', 200);
620 $response->sendContent();
621 $string = ob_get_clean();
622 $this->assertContains(
'test response rendering', $string);
628 $response->setPublic();
630 $this->assertTrue($response->headers->hasCacheControlDirective(
'public'));
631 $this->assertFalse($response->headers->hasCacheControlDirective(
'private'));
637 $response->setExpires(
null);
639 $this->assertNull($response->getExpires(),
'->setExpires() remove the header when passed null');
642 $response->setExpires($now);
644 $this->assertEquals($response->getExpires()->getTimestamp(), $now->getTimestamp());
651 $this->assertNotNull($response->getLastModified());
653 $response->setLastModified(
null);
654 $this->assertNull($response->getLastModified());
662 $response->setStatusCode(99);
664 }
catch (\InvalidArgumentException $e) {
665 $this->assertTrue($response->isInvalid());
669 $response->setStatusCode(650);
671 }
catch (\InvalidArgumentException $e) {
672 $this->assertTrue($response->isInvalid());
676 $this->assertFalse($response->isInvalid());
686 $response->setStatusCode($code, $text);
688 $statusText = new \ReflectionProperty($response,
'statusText');
689 $statusText->setAccessible(
true);
691 $this->assertEquals($expectedText, $statusText->getValue($response));
697 array(
'200',
null,
'OK'),
698 array(
'200',
false,
''),
699 array(
'200',
'foo',
'foo'),
700 array(
'199',
null,
'unknown status'),
701 array(
'199',
false,
''),
702 array(
'199',
'foo',
'foo'),
709 $this->assertTrue($response->isInformational());
712 $this->assertFalse($response->isInformational());
717 foreach (array(301, 302, 303, 307) as $code) {
718 $response =
new Response(
'', $code);
719 $this->assertTrue($response->isRedirection());
720 $this->assertTrue($response->isRedirect());
724 $this->assertTrue($response->isRedirection());
725 $this->assertFalse($response->isRedirect());
728 $this->assertFalse($response->isRedirection());
729 $this->assertFalse($response->isRedirect());
732 $this->assertFalse($response->isRedirection());
733 $this->assertFalse($response->isRedirect());
735 $response =
new Response(
'', 301, array(
'Location' =>
'/good-uri'));
736 $this->assertFalse($response->isRedirect(
'/bad-uri'));
737 $this->assertTrue($response->isRedirect(
'/good-uri'));
743 $this->assertTrue($response->isNotFound());
746 $this->assertFalse($response->isNotFound());
751 foreach (array(204, 304) as $code) {
752 $response =
new Response(
'', $code);
753 $this->assertTrue($response->isEmpty());
757 $this->assertFalse($response->isEmpty());
763 $this->assertTrue($response->isForbidden());
766 $this->assertFalse($response->isForbidden());
772 $this->assertTrue($response->isOk());
775 $this->assertFalse($response->isOk());
781 $this->assertTrue($response->isClientError());
782 $this->assertFalse($response->isServerError());
785 $this->assertFalse($response->isClientError());
786 $this->assertTrue($response->isServerError());
792 $this->assertFalse($response->hasVary());
794 $response->setVary(
'User-Agent');
795 $this->assertTrue($response->hasVary());
800 $response =
new Response(
'', 200, array(
'ETag' =>
'"12345"'));
801 $response->setEtag();
803 $this->assertNull($response->headers->get(
'Etag'),
'->setEtag() removes Etags when call with null');
812 $response->setContent($content);
813 $this->assertEquals((
string) $content, $response->getContent());
823 $response->setContent($content);
831 'setProtocolVersion' =>
'1.0',
832 'setCharset' =>
'UTF-8',
834 'setPrivate' =>
null,
838 'setSharedMaxAge' => 1,
843 foreach ($setters as $setter => $arg) {
844 $this->assertEquals($response, $response->{$setter}($arg));
851 $this->getMockBuilder(Response::class)->getMock();
855 $this->addToAssertionCount(1);
862 'string' => array(
'Foo'),
870 'obj' => array(
new \stdClass()),
871 'array' => array(array()),
872 'bool' => array(
true,
'1'),
878 return $this->createDateTimeNow()->sub(
new \DateInterval(
'PT1H'));
883 return $this->createDateTimeNow()->add(
new \DateInterval(
'PT1H'));
888 $date = new \DateTime();
890 return $date->setTimestamp(time());
907 if (!in_array(
'https', stream_get_wrappers(),
true)) {
908 $this->markTestSkipped(
'The "https" wrapper is not available');
911 $ianaHttpStatusCodes = new \DOMDocument();
913 libxml_set_streams_context(stream_context_create(array(
920 $ianaHttpStatusCodes->load(
'https://www.iana.org/assignments/http-status-codes/http-status-codes.xml');
921 if (!$ianaHttpStatusCodes->relaxNGValidate(__DIR__.
'/schema/http-status-codes.rng')) {
922 self::fail(
'Invalid IANA\'s HTTP status code list.');
925 $ianaCodesReasonPhrases = array();
927 $xpath = new \DomXPath($ianaHttpStatusCodes);
928 $xpath->registerNamespace(
'ns',
'http://www.iana.org/assignments');
930 $records = $xpath->query(
'//ns:record');
931 foreach ($records as $record) {
932 $value = $xpath->query(
'.//ns:value', $record)->item(0)->nodeValue;
933 $description = $xpath->query(
'.//ns:description', $record)->item(0)->nodeValue;
935 if (in_array($description, array(
'Unassigned',
'(Unused)'),
true)) {
939 if (preg_match(
'/^([0-9]+)\s*\-\s*([0-9]+)$/', $value, $matches)) {
940 for ($value = $matches[1]; $value <= $matches[2]; ++$value) {
941 $ianaCodesReasonPhrases[] = array($value, $description);
944 $ianaCodesReasonPhrases[] = array($value, $description);
948 return $ianaCodesReasonPhrases;