vendor/symfony/src/Symfony/Component/HttpFoundation/Response.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of the Symfony package.
       
     5  *
       
     6  * (c) Fabien Potencier <fabien@symfony.com>
       
     7  *
       
     8  * For the full copyright and license information, please view the LICENSE
       
     9  * file that was distributed with this source code.
       
    10  */
       
    11 
       
    12 namespace Symfony\Component\HttpFoundation;
       
    13 
       
    14 /**
       
    15  * Response represents an HTTP response.
       
    16  *
       
    17  * @author Fabien Potencier <fabien@symfony.com>
       
    18  *
       
    19  * @api
       
    20  */
       
    21 class Response
       
    22 {
       
    23     /**
       
    24      * @var \Symfony\Component\HttpFoundation\ResponseHeaderBag
       
    25      */
       
    26     public $headers;
       
    27 
       
    28     protected $content;
       
    29     protected $version;
       
    30     protected $statusCode;
       
    31     protected $statusText;
       
    32     protected $charset;
       
    33 
       
    34     static public $statusTexts = array(
       
    35         100 => 'Continue',
       
    36         101 => 'Switching Protocols',
       
    37         200 => 'OK',
       
    38         201 => 'Created',
       
    39         202 => 'Accepted',
       
    40         203 => 'Non-Authoritative Information',
       
    41         204 => 'No Content',
       
    42         205 => 'Reset Content',
       
    43         206 => 'Partial Content',
       
    44         300 => 'Multiple Choices',
       
    45         301 => 'Moved Permanently',
       
    46         302 => 'Found',
       
    47         303 => 'See Other',
       
    48         304 => 'Not Modified',
       
    49         305 => 'Use Proxy',
       
    50         307 => 'Temporary Redirect',
       
    51         400 => 'Bad Request',
       
    52         401 => 'Unauthorized',
       
    53         402 => 'Payment Required',
       
    54         403 => 'Forbidden',
       
    55         404 => 'Not Found',
       
    56         405 => 'Method Not Allowed',
       
    57         406 => 'Not Acceptable',
       
    58         407 => 'Proxy Authentication Required',
       
    59         408 => 'Request Timeout',
       
    60         409 => 'Conflict',
       
    61         410 => 'Gone',
       
    62         411 => 'Length Required',
       
    63         412 => 'Precondition Failed',
       
    64         413 => 'Request Entity Too Large',
       
    65         414 => 'Request-URI Too Long',
       
    66         415 => 'Unsupported Media Type',
       
    67         416 => 'Requested Range Not Satisfiable',
       
    68         417 => 'Expectation Failed',
       
    69         418 => 'I\'m a teapot',
       
    70         500 => 'Internal Server Error',
       
    71         501 => 'Not Implemented',
       
    72         502 => 'Bad Gateway',
       
    73         503 => 'Service Unavailable',
       
    74         504 => 'Gateway Timeout',
       
    75         505 => 'HTTP Version Not Supported',
       
    76     );
       
    77 
       
    78     /**
       
    79      * Constructor.
       
    80      *
       
    81      * @param string  $content The response content
       
    82      * @param integer $status  The response status code
       
    83      * @param array   $headers An array of response headers
       
    84      *
       
    85      * @api
       
    86      */
       
    87     public function __construct($content = '', $status = 200, $headers = array())
       
    88     {
       
    89         $this->headers = new ResponseHeaderBag($headers);
       
    90         $this->setContent($content);
       
    91         $this->setStatusCode($status);
       
    92         $this->setProtocolVersion('1.0');
       
    93         if (!$this->headers->has('Date')) {
       
    94             $this->setDate(new \DateTime(null, new \DateTimeZone('UTC')));
       
    95         }
       
    96     }
       
    97 
       
    98     /**
       
    99      * Returns the response content as it will be sent (with the headers).
       
   100      *
       
   101      * @return string The response content
       
   102      */
       
   103     public function __toString()
       
   104     {
       
   105         $this->prepare();
       
   106 
       
   107         return
       
   108             sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n".
       
   109             $this->headers."\r\n".
       
   110             $this->getContent();
       
   111     }
       
   112 
       
   113     /**
       
   114      * Clones the current Response instance.
       
   115      */
       
   116     public function __clone()
       
   117     {
       
   118         $this->headers = clone $this->headers;
       
   119     }
       
   120 
       
   121     /**
       
   122      * Prepares the Response before it is sent to the client.
       
   123      *
       
   124      * This method tweaks the Response to ensure that it is
       
   125      * compliant with RFC 2616.
       
   126      */
       
   127     public function prepare()
       
   128     {
       
   129         if ($this->isInformational() || in_array($this->statusCode, array(204, 304))) {
       
   130             $this->setContent('');
       
   131         }
       
   132 
       
   133         // Fix Content-Type
       
   134         $charset = $this->charset ?: 'UTF-8';
       
   135         if (!$this->headers->has('Content-Type')) {
       
   136             $this->headers->set('Content-Type', 'text/html; charset='.$charset);
       
   137         } elseif ('text/' === substr($this->headers->get('Content-Type'), 0, 5) && false === strpos($this->headers->get('Content-Type'), 'charset')) {
       
   138             // add the charset
       
   139             $this->headers->set('Content-Type', $this->headers->get('Content-Type').'; charset='.$charset);
       
   140         }
       
   141 
       
   142         // Fix Content-Length
       
   143         if ($this->headers->has('Transfer-Encoding')) {
       
   144             $this->headers->remove('Content-Length');
       
   145         }
       
   146     }
       
   147 
       
   148     /**
       
   149      * Sends HTTP headers.
       
   150      */
       
   151     public function sendHeaders()
       
   152     {
       
   153         // headers have already been sent by the developer
       
   154         if (headers_sent()) {
       
   155             return;
       
   156         }
       
   157 
       
   158         $this->prepare();
       
   159 
       
   160         // status
       
   161         header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText));
       
   162 
       
   163         // headers
       
   164         foreach ($this->headers->all() as $name => $values) {
       
   165             foreach ($values as $value) {
       
   166                 header($name.': '.$value, false);
       
   167             }
       
   168         }
       
   169 
       
   170         // cookies
       
   171         foreach ($this->headers->getCookies() as $cookie) {
       
   172             setcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly());
       
   173         }
       
   174     }
       
   175 
       
   176     /**
       
   177      * Sends content for the current web response.
       
   178      */
       
   179     public function sendContent()
       
   180     {
       
   181         echo $this->content;
       
   182     }
       
   183 
       
   184     /**
       
   185      * Sends HTTP headers and content.
       
   186      *
       
   187      * @api
       
   188      */
       
   189     public function send()
       
   190     {
       
   191         $this->sendHeaders();
       
   192         $this->sendContent();
       
   193 
       
   194         if (function_exists('fastcgi_finish_request')) {
       
   195             fastcgi_finish_request();
       
   196         }
       
   197     }
       
   198 
       
   199     /**
       
   200      * Sets the response content
       
   201      *
       
   202      * Valid types are strings, numbers, and objects that implement a __toString() method.
       
   203      *
       
   204      * @param mixed $content
       
   205      *
       
   206      * @api
       
   207      */
       
   208     public function setContent($content)
       
   209     {
       
   210         if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable(array($content, '__toString'))) {
       
   211             throw new \UnexpectedValueException('The Response content must be a string or object implementing __toString(), "'.gettype($content).'" given.');
       
   212         }
       
   213 
       
   214         $this->content = (string) $content;
       
   215     }
       
   216 
       
   217     /**
       
   218      * Gets the current response content
       
   219      *
       
   220      * @return string Content
       
   221      *
       
   222      * @api
       
   223      */
       
   224     public function getContent()
       
   225     {
       
   226         return $this->content;
       
   227     }
       
   228 
       
   229     /**
       
   230      * Sets the HTTP protocol version (1.0 or 1.1).
       
   231      *
       
   232      * @param string $version The HTTP protocol version
       
   233      *
       
   234      * @api
       
   235      */
       
   236     public function setProtocolVersion($version)
       
   237     {
       
   238         $this->version = $version;
       
   239     }
       
   240 
       
   241     /**
       
   242      * Gets the HTTP protocol version.
       
   243      *
       
   244      * @return string The HTTP protocol version
       
   245      *
       
   246      * @api
       
   247      */
       
   248     public function getProtocolVersion()
       
   249     {
       
   250         return $this->version;
       
   251     }
       
   252 
       
   253     /**
       
   254      * Sets response status code.
       
   255      *
       
   256      * @param integer $code HTTP status code
       
   257      * @param string  $text HTTP status text
       
   258      *
       
   259      * @throws \InvalidArgumentException When the HTTP status code is not valid
       
   260      *
       
   261      * @api
       
   262      */
       
   263     public function setStatusCode($code, $text = null)
       
   264     {
       
   265         $this->statusCode = (int) $code;
       
   266         if ($this->isInvalid()) {
       
   267             throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $code));
       
   268         }
       
   269 
       
   270         $this->statusText = false === $text ? '' : (null === $text ? self::$statusTexts[$this->statusCode] : $text);
       
   271     }
       
   272 
       
   273     /**
       
   274      * Retrieves status code for the current web response.
       
   275      *
       
   276      * @return string Status code
       
   277      *
       
   278      * @api
       
   279      */
       
   280     public function getStatusCode()
       
   281     {
       
   282         return $this->statusCode;
       
   283     }
       
   284 
       
   285     /**
       
   286      * Sets response charset.
       
   287      *
       
   288      * @param string $charset Character set
       
   289      *
       
   290      * @api
       
   291      */
       
   292     public function setCharset($charset)
       
   293     {
       
   294         $this->charset = $charset;
       
   295     }
       
   296 
       
   297     /**
       
   298      * Retrieves the response charset.
       
   299      *
       
   300      * @return string Character set
       
   301      *
       
   302      * @api
       
   303      */
       
   304     public function getCharset()
       
   305     {
       
   306         return $this->charset;
       
   307     }
       
   308 
       
   309     /**
       
   310      * Returns true if the response is worth caching under any circumstance.
       
   311      *
       
   312      * Responses marked "private" with an explicit Cache-Control directive are
       
   313      * considered uncacheable.
       
   314      *
       
   315      * Responses with neither a freshness lifetime (Expires, max-age) nor cache
       
   316      * validator (Last-Modified, ETag) are considered uncacheable.
       
   317      *
       
   318      * @return Boolean true if the response is worth caching, false otherwise
       
   319      *
       
   320      * @api
       
   321      */
       
   322     public function isCacheable()
       
   323     {
       
   324         if (!in_array($this->statusCode, array(200, 203, 300, 301, 302, 404, 410))) {
       
   325             return false;
       
   326         }
       
   327 
       
   328         if ($this->headers->hasCacheControlDirective('no-store') || $this->headers->getCacheControlDirective('private')) {
       
   329             return false;
       
   330         }
       
   331 
       
   332         return $this->isValidateable() || $this->isFresh();
       
   333     }
       
   334 
       
   335     /**
       
   336      * Returns true if the response is "fresh".
       
   337      *
       
   338      * Fresh responses may be served from cache without any interaction with the
       
   339      * origin. A response is considered fresh when it includes a Cache-Control/max-age
       
   340      * indicator or Expiration header and the calculated age is less than the freshness lifetime.
       
   341      *
       
   342      * @return Boolean true if the response is fresh, false otherwise
       
   343      *
       
   344      * @api
       
   345      */
       
   346     public function isFresh()
       
   347     {
       
   348         return $this->getTtl() > 0;
       
   349     }
       
   350 
       
   351     /**
       
   352      * Returns true if the response includes headers that can be used to validate
       
   353      * the response with the origin server using a conditional GET request.
       
   354      *
       
   355      * @return Boolean true if the response is validateable, false otherwise
       
   356      *
       
   357      * @api
       
   358      */
       
   359     public function isValidateable()
       
   360     {
       
   361         return $this->headers->has('Last-Modified') || $this->headers->has('ETag');
       
   362     }
       
   363 
       
   364     /**
       
   365      * Marks the response as "private".
       
   366      *
       
   367      * It makes the response ineligible for serving other clients.
       
   368      *
       
   369      * @api
       
   370      */
       
   371     public function setPrivate()
       
   372     {
       
   373         $this->headers->removeCacheControlDirective('public');
       
   374         $this->headers->addCacheControlDirective('private');
       
   375     }
       
   376 
       
   377     /**
       
   378      * Marks the response as "public".
       
   379      *
       
   380      * It makes the response eligible for serving other clients.
       
   381      *
       
   382      * @api
       
   383      */
       
   384     public function setPublic()
       
   385     {
       
   386         $this->headers->addCacheControlDirective('public');
       
   387         $this->headers->removeCacheControlDirective('private');
       
   388     }
       
   389 
       
   390     /**
       
   391      * Returns true if the response must be revalidated by caches.
       
   392      *
       
   393      * This method indicates that the response must not be served stale by a
       
   394      * cache in any circumstance without first revalidating with the origin.
       
   395      * When present, the TTL of the response should not be overridden to be
       
   396      * greater than the value provided by the origin.
       
   397      *
       
   398      * @return Boolean true if the response must be revalidated by a cache, false otherwise
       
   399      *
       
   400      * @api
       
   401      */
       
   402     public function mustRevalidate()
       
   403     {
       
   404         return $this->headers->hasCacheControlDirective('must-revalidate') || $this->headers->has('must-proxy-revalidate');
       
   405     }
       
   406 
       
   407     /**
       
   408      * Returns the Date header as a DateTime instance.
       
   409      *
       
   410      * @return \DateTime A \DateTime instance
       
   411      *
       
   412      * @throws \RuntimeException when the header is not parseable
       
   413      *
       
   414      * @api
       
   415      */
       
   416     public function getDate()
       
   417     {
       
   418         return $this->headers->getDate('Date');
       
   419     }
       
   420 
       
   421     /**
       
   422      * Sets the Date header.
       
   423      *
       
   424      * @param \DateTime $date A \DateTime instance
       
   425      *
       
   426      * @api
       
   427      */
       
   428     public function setDate(\DateTime $date)
       
   429     {
       
   430         $date->setTimezone(new \DateTimeZone('UTC'));
       
   431         $this->headers->set('Date', $date->format('D, d M Y H:i:s').' GMT');
       
   432     }
       
   433 
       
   434     /**
       
   435      * Returns the age of the response.
       
   436      *
       
   437      * @return integer The age of the response in seconds
       
   438      */
       
   439     public function getAge()
       
   440     {
       
   441         if ($age = $this->headers->get('Age')) {
       
   442             return $age;
       
   443         }
       
   444 
       
   445         return max(time() - $this->getDate()->format('U'), 0);
       
   446     }
       
   447 
       
   448     /**
       
   449      * Marks the response stale by setting the Age header to be equal to the maximum age of the response.
       
   450      *
       
   451      * @api
       
   452      */
       
   453     public function expire()
       
   454     {
       
   455         if ($this->isFresh()) {
       
   456             $this->headers->set('Age', $this->getMaxAge());
       
   457         }
       
   458     }
       
   459 
       
   460     /**
       
   461      * Returns the value of the Expires header as a DateTime instance.
       
   462      *
       
   463      * @return \DateTime A DateTime instance
       
   464      *
       
   465      * @api
       
   466      */
       
   467     public function getExpires()
       
   468     {
       
   469         return $this->headers->getDate('Expires');
       
   470     }
       
   471 
       
   472     /**
       
   473      * Sets the Expires HTTP header with a \DateTime instance.
       
   474      *
       
   475      * If passed a null value, it removes the header.
       
   476      *
       
   477      * @param \DateTime $date A \DateTime instance
       
   478      *
       
   479      * @api
       
   480      */
       
   481     public function setExpires(\DateTime $date = null)
       
   482     {
       
   483         if (null === $date) {
       
   484             $this->headers->remove('Expires');
       
   485         } else {
       
   486             $date = clone $date;
       
   487             $date->setTimezone(new \DateTimeZone('UTC'));
       
   488             $this->headers->set('Expires', $date->format('D, d M Y H:i:s').' GMT');
       
   489         }
       
   490     }
       
   491 
       
   492     /**
       
   493      * Sets the number of seconds after the time specified in the response's Date
       
   494      * header when the the response should no longer be considered fresh.
       
   495      *
       
   496      * First, it checks for a s-maxage directive, then a max-age directive, and then it falls
       
   497      * back on an expires header. It returns null when no maximum age can be established.
       
   498      *
       
   499      * @return integer|null Number of seconds
       
   500      *
       
   501      * @api
       
   502      */
       
   503     public function getMaxAge()
       
   504     {
       
   505         if ($age = $this->headers->getCacheControlDirective('s-maxage')) {
       
   506             return $age;
       
   507         }
       
   508 
       
   509         if ($age = $this->headers->getCacheControlDirective('max-age')) {
       
   510             return $age;
       
   511         }
       
   512 
       
   513         if (null !== $this->getExpires()) {
       
   514             return $this->getExpires()->format('U') - $this->getDate()->format('U');
       
   515         }
       
   516 
       
   517         return null;
       
   518     }
       
   519 
       
   520     /**
       
   521      * Sets the number of seconds after which the response should no longer be considered fresh.
       
   522      *
       
   523      * This methods sets the Cache-Control max-age directive.
       
   524      *
       
   525      * @param integer $value A number of seconds
       
   526      *
       
   527      * @api
       
   528      */
       
   529     public function setMaxAge($value)
       
   530     {
       
   531         $this->headers->addCacheControlDirective('max-age', $value);
       
   532     }
       
   533 
       
   534     /**
       
   535      * Sets the number of seconds after which the response should no longer be considered fresh by shared caches.
       
   536      *
       
   537      * This methods sets the Cache-Control s-maxage directive.
       
   538      *
       
   539      * @param integer $value A number of seconds
       
   540      *
       
   541      * @api
       
   542      */
       
   543     public function setSharedMaxAge($value)
       
   544     {
       
   545         $this->setPublic();
       
   546         $this->headers->addCacheControlDirective('s-maxage', $value);
       
   547     }
       
   548 
       
   549     /**
       
   550      * Returns the response's time-to-live in seconds.
       
   551      *
       
   552      * It returns null when no freshness information is present in the response.
       
   553      *
       
   554      * When the responses TTL is <= 0, the response may not be served from cache without first
       
   555      * revalidating with the origin.
       
   556      *
       
   557      * @return integer The TTL in seconds
       
   558      *
       
   559      * @api
       
   560      */
       
   561     public function getTtl()
       
   562     {
       
   563         if ($maxAge = $this->getMaxAge()) {
       
   564             return $maxAge - $this->getAge();
       
   565         }
       
   566 
       
   567         return null;
       
   568     }
       
   569 
       
   570     /**
       
   571      * Sets the response's time-to-live for shared caches.
       
   572      *
       
   573      * This method adjusts the Cache-Control/s-maxage directive.
       
   574      *
       
   575      * @param integer $seconds The number of seconds
       
   576      *
       
   577      * @api
       
   578      */
       
   579     public function setTtl($seconds)
       
   580     {
       
   581         $this->setSharedMaxAge($this->getAge() + $seconds);
       
   582     }
       
   583 
       
   584     /**
       
   585      * Sets the response's time-to-live for private/client caches.
       
   586      *
       
   587      * This method adjusts the Cache-Control/max-age directive.
       
   588      *
       
   589      * @param integer $seconds The number of seconds
       
   590      *
       
   591      * @api
       
   592      */
       
   593     public function setClientTtl($seconds)
       
   594     {
       
   595         $this->setMaxAge($this->getAge() + $seconds);
       
   596     }
       
   597 
       
   598     /**
       
   599      * Returns the Last-Modified HTTP header as a DateTime instance.
       
   600      *
       
   601      * @return \DateTime A DateTime instance
       
   602      *
       
   603      * @api
       
   604      */
       
   605     public function getLastModified()
       
   606     {
       
   607         return $this->headers->getDate('Last-Modified');
       
   608     }
       
   609 
       
   610     /**
       
   611      * Sets the Last-Modified HTTP header with a \DateTime instance.
       
   612      *
       
   613      * If passed a null value, it removes the header.
       
   614      *
       
   615      * @param \DateTime $date A \DateTime instance
       
   616      *
       
   617      * @api
       
   618      */
       
   619     public function setLastModified(\DateTime $date = null)
       
   620     {
       
   621         if (null === $date) {
       
   622             $this->headers->remove('Last-Modified');
       
   623         } else {
       
   624             $date = clone $date;
       
   625             $date->setTimezone(new \DateTimeZone('UTC'));
       
   626             $this->headers->set('Last-Modified', $date->format('D, d M Y H:i:s').' GMT');
       
   627         }
       
   628     }
       
   629 
       
   630     /**
       
   631      * Returns the literal value of ETag HTTP header.
       
   632      *
       
   633      * @return string The ETag HTTP header
       
   634      *
       
   635      * @api
       
   636      */
       
   637     public function getEtag()
       
   638     {
       
   639         return $this->headers->get('ETag');
       
   640     }
       
   641 
       
   642     /**
       
   643      * Sets the ETag value.
       
   644      *
       
   645      * @param string  $etag The ETag unique identifier
       
   646      * @param Boolean $weak Whether you want a weak ETag or not
       
   647      *
       
   648      * @api
       
   649      */
       
   650     public function setEtag($etag = null, $weak = false)
       
   651     {
       
   652         if (null === $etag) {
       
   653             $this->headers->remove('Etag');
       
   654         } else {
       
   655             if (0 !== strpos($etag, '"')) {
       
   656                 $etag = '"'.$etag.'"';
       
   657             }
       
   658 
       
   659             $this->headers->set('ETag', (true === $weak ? 'W/' : '').$etag);
       
   660         }
       
   661     }
       
   662 
       
   663     /**
       
   664      * Sets Response cache headers (validation and/or expiration).
       
   665      *
       
   666      * Available options are: etag, last_modified, max_age, s_maxage, private, and public.
       
   667      *
       
   668      * @param array $options An array of cache options
       
   669      *
       
   670      * @api
       
   671      */
       
   672     public function setCache(array $options)
       
   673     {
       
   674         if ($diff = array_diff(array_keys($options), array('etag', 'last_modified', 'max_age', 's_maxage', 'private', 'public'))) {
       
   675             throw new \InvalidArgumentException(sprintf('Response does not support the following options: "%s".', implode('", "', array_keys($diff))));
       
   676         }
       
   677 
       
   678         if (isset($options['etag'])) {
       
   679             $this->setEtag($options['etag']);
       
   680         }
       
   681 
       
   682         if (isset($options['last_modified'])) {
       
   683             $this->setLastModified($options['last_modified']);
       
   684         }
       
   685 
       
   686         if (isset($options['max_age'])) {
       
   687             $this->setMaxAge($options['max_age']);
       
   688         }
       
   689 
       
   690         if (isset($options['s_maxage'])) {
       
   691             $this->setSharedMaxAge($options['s_maxage']);
       
   692         }
       
   693 
       
   694         if (isset($options['public'])) {
       
   695             if ($options['public']) {
       
   696                 $this->setPublic();
       
   697             } else {
       
   698                 $this->setPrivate();
       
   699             }
       
   700         }
       
   701 
       
   702         if (isset($options['private'])) {
       
   703             if ($options['private']) {
       
   704                 $this->setPrivate();
       
   705             } else {
       
   706                 $this->setPublic();
       
   707             }
       
   708         }
       
   709     }
       
   710 
       
   711     /**
       
   712      * Modifies the response so that it conforms to the rules defined for a 304 status code.
       
   713      *
       
   714      * This sets the status, removes the body, and discards any headers
       
   715      * that MUST NOT be included in 304 responses.
       
   716      *
       
   717      * @see http://tools.ietf.org/html/rfc2616#section-10.3.5
       
   718      *
       
   719      * @api
       
   720      */
       
   721     public function setNotModified()
       
   722     {
       
   723         $this->setStatusCode(304);
       
   724         $this->setContent(null);
       
   725 
       
   726         // remove headers that MUST NOT be included with 304 Not Modified responses
       
   727         foreach (array('Allow', 'Content-Encoding', 'Content-Language', 'Content-Length', 'Content-MD5', 'Content-Type', 'Last-Modified') as $header) {
       
   728             $this->headers->remove($header);
       
   729         }
       
   730     }
       
   731 
       
   732     /**
       
   733      * Returns true if the response includes a Vary header.
       
   734      *
       
   735      * @return true if the response includes a Vary header, false otherwise
       
   736      *
       
   737      * @api
       
   738      */
       
   739     public function hasVary()
       
   740     {
       
   741         return (Boolean) $this->headers->get('Vary');
       
   742     }
       
   743 
       
   744     /**
       
   745      * Returns an array of header names given in the Vary header.
       
   746      *
       
   747      * @return array An array of Vary names
       
   748      *
       
   749      * @api
       
   750      */
       
   751     public function getVary()
       
   752     {
       
   753         if (!$vary = $this->headers->get('Vary')) {
       
   754             return array();
       
   755         }
       
   756 
       
   757         return is_array($vary) ? $vary : preg_split('/[\s,]+/', $vary);
       
   758     }
       
   759 
       
   760     /**
       
   761      * Sets the Vary header.
       
   762      *
       
   763      * @param string|array $headers
       
   764      * @param Boolean      $replace Whether to replace the actual value of not (true by default)
       
   765      *
       
   766      * @api
       
   767      */
       
   768     public function setVary($headers, $replace = true)
       
   769     {
       
   770         $this->headers->set('Vary', $headers, $replace);
       
   771     }
       
   772 
       
   773     /**
       
   774      * Determines if the Response validators (ETag, Last-Modified) matches
       
   775      * a conditional value specified in the Request.
       
   776      *
       
   777      * If the Response is not modified, it sets the status code to 304 and
       
   778      * remove the actual content by calling the setNotModified() method.
       
   779      *
       
   780      * @param Request $request A Request instance
       
   781      *
       
   782      * @return Boolean true if the Response validators matches the Request, false otherwise
       
   783      *
       
   784      * @api
       
   785      */
       
   786     public function isNotModified(Request $request)
       
   787     {
       
   788         $lastModified = $request->headers->get('If-Modified-Since');
       
   789         $notModified = false;
       
   790         if ($etags = $request->getEtags()) {
       
   791             $notModified = (in_array($this->getEtag(), $etags) || in_array('*', $etags)) && (!$lastModified || $this->headers->get('Last-Modified') == $lastModified);
       
   792         } elseif ($lastModified) {
       
   793             $notModified = $lastModified == $this->headers->get('Last-Modified');
       
   794         }
       
   795 
       
   796         if ($notModified) {
       
   797             $this->setNotModified();
       
   798         }
       
   799 
       
   800         return $notModified;
       
   801     }
       
   802 
       
   803     // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
       
   804     /**
       
   805      * @api
       
   806      */
       
   807     public function isInvalid()
       
   808     {
       
   809         return $this->statusCode < 100 || $this->statusCode >= 600;
       
   810     }
       
   811 
       
   812     /**
       
   813      * @api
       
   814      */
       
   815     public function isInformational()
       
   816     {
       
   817         return $this->statusCode >= 100 && $this->statusCode < 200;
       
   818     }
       
   819 
       
   820     /**
       
   821      * @api
       
   822      */
       
   823     public function isSuccessful()
       
   824     {
       
   825         return $this->statusCode >= 200 && $this->statusCode < 300;
       
   826     }
       
   827 
       
   828     /**
       
   829      * @api
       
   830      */
       
   831     public function isRedirection()
       
   832     {
       
   833         return $this->statusCode >= 300 && $this->statusCode < 400;
       
   834     }
       
   835 
       
   836     /**
       
   837      * @api
       
   838      */
       
   839     public function isClientError()
       
   840     {
       
   841         return $this->statusCode >= 400 && $this->statusCode < 500;
       
   842     }
       
   843 
       
   844     /**
       
   845      * @api
       
   846      */
       
   847     public function isServerError()
       
   848     {
       
   849         return $this->statusCode >= 500 && $this->statusCode < 600;
       
   850     }
       
   851 
       
   852     /**
       
   853      * @api
       
   854      */
       
   855     public function isOk()
       
   856     {
       
   857         return 200 === $this->statusCode;
       
   858     }
       
   859 
       
   860     /**
       
   861      * @api
       
   862      */
       
   863     public function isForbidden()
       
   864     {
       
   865         return 403 === $this->statusCode;
       
   866     }
       
   867 
       
   868     /**
       
   869      * @api
       
   870      */
       
   871     public function isNotFound()
       
   872     {
       
   873         return 404 === $this->statusCode;
       
   874     }
       
   875 
       
   876     /**
       
   877      * @api
       
   878      */
       
   879     public function isRedirect($location = null)
       
   880     {
       
   881         return in_array($this->statusCode, array(201, 301, 302, 303, 307)) && (null === $location ?: $location == $this->headers->get('Location'));
       
   882     }
       
   883 
       
   884     /**
       
   885      * @api
       
   886      */
       
   887     public function isEmpty()
       
   888     {
       
   889         return in_array($this->statusCode, array(201, 204, 304));
       
   890     }
       
   891 }