annotate vendor/symfony/http-foundation/ResponseHeaderBag.php @ 2:92f882872392

Trusted hosts, + remove migration modules
author Chris Cannam
date Tue, 05 Dec 2017 09:26:43 +0000
parents 4c8ae668cc8c
children 1fec387a4317
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\HttpFoundation;
Chris@0 13
Chris@0 14 /**
Chris@0 15 * ResponseHeaderBag is a container for Response HTTP headers.
Chris@0 16 *
Chris@0 17 * @author Fabien Potencier <fabien@symfony.com>
Chris@0 18 */
Chris@0 19 class ResponseHeaderBag extends HeaderBag
Chris@0 20 {
Chris@0 21 const COOKIES_FLAT = 'flat';
Chris@0 22 const COOKIES_ARRAY = 'array';
Chris@0 23
Chris@0 24 const DISPOSITION_ATTACHMENT = 'attachment';
Chris@0 25 const DISPOSITION_INLINE = 'inline';
Chris@0 26
Chris@0 27 /**
Chris@0 28 * @var array
Chris@0 29 */
Chris@0 30 protected $computedCacheControl = array();
Chris@0 31
Chris@0 32 /**
Chris@0 33 * @var array
Chris@0 34 */
Chris@0 35 protected $cookies = array();
Chris@0 36
Chris@0 37 /**
Chris@0 38 * @var array
Chris@0 39 */
Chris@0 40 protected $headerNames = array();
Chris@0 41
Chris@0 42 /**
Chris@0 43 * Constructor.
Chris@0 44 *
Chris@0 45 * @param array $headers An array of HTTP headers
Chris@0 46 */
Chris@0 47 public function __construct(array $headers = array())
Chris@0 48 {
Chris@0 49 parent::__construct($headers);
Chris@0 50
Chris@0 51 if (!isset($this->headers['cache-control'])) {
Chris@0 52 $this->set('Cache-Control', '');
Chris@0 53 }
Chris@0 54 }
Chris@0 55
Chris@0 56 /**
Chris@0 57 * {@inheritdoc}
Chris@0 58 */
Chris@0 59 public function __toString()
Chris@0 60 {
Chris@0 61 $cookies = '';
Chris@0 62 foreach ($this->getCookies() as $cookie) {
Chris@0 63 $cookies .= 'Set-Cookie: '.$cookie."\r\n";
Chris@0 64 }
Chris@0 65
Chris@0 66 ksort($this->headerNames);
Chris@0 67
Chris@0 68 return parent::__toString().$cookies;
Chris@0 69 }
Chris@0 70
Chris@0 71 /**
Chris@0 72 * Returns the headers, with original capitalizations.
Chris@0 73 *
Chris@0 74 * @return array An array of headers
Chris@0 75 */
Chris@0 76 public function allPreserveCase()
Chris@0 77 {
Chris@0 78 return array_combine($this->headerNames, $this->headers);
Chris@0 79 }
Chris@0 80
Chris@0 81 /**
Chris@0 82 * {@inheritdoc}
Chris@0 83 */
Chris@0 84 public function replace(array $headers = array())
Chris@0 85 {
Chris@0 86 $this->headerNames = array();
Chris@0 87
Chris@0 88 parent::replace($headers);
Chris@0 89
Chris@0 90 if (!isset($this->headers['cache-control'])) {
Chris@0 91 $this->set('Cache-Control', '');
Chris@0 92 }
Chris@0 93 }
Chris@0 94
Chris@0 95 /**
Chris@0 96 * {@inheritdoc}
Chris@0 97 */
Chris@0 98 public function set($key, $values, $replace = true)
Chris@0 99 {
Chris@0 100 parent::set($key, $values, $replace);
Chris@0 101
Chris@0 102 $uniqueKey = str_replace('_', '-', strtolower($key));
Chris@0 103 $this->headerNames[$uniqueKey] = $key;
Chris@0 104
Chris@0 105 // ensure the cache-control header has sensible defaults
Chris@0 106 if (in_array($uniqueKey, array('cache-control', 'etag', 'last-modified', 'expires'))) {
Chris@0 107 $computed = $this->computeCacheControlValue();
Chris@0 108 $this->headers['cache-control'] = array($computed);
Chris@0 109 $this->headerNames['cache-control'] = 'Cache-Control';
Chris@0 110 $this->computedCacheControl = $this->parseCacheControl($computed);
Chris@0 111 }
Chris@0 112 }
Chris@0 113
Chris@0 114 /**
Chris@0 115 * {@inheritdoc}
Chris@0 116 */
Chris@0 117 public function remove($key)
Chris@0 118 {
Chris@0 119 parent::remove($key);
Chris@0 120
Chris@0 121 $uniqueKey = str_replace('_', '-', strtolower($key));
Chris@0 122 unset($this->headerNames[$uniqueKey]);
Chris@0 123
Chris@0 124 if ('cache-control' === $uniqueKey) {
Chris@0 125 $this->computedCacheControl = array();
Chris@0 126 }
Chris@0 127 }
Chris@0 128
Chris@0 129 /**
Chris@0 130 * {@inheritdoc}
Chris@0 131 */
Chris@0 132 public function hasCacheControlDirective($key)
Chris@0 133 {
Chris@0 134 return array_key_exists($key, $this->computedCacheControl);
Chris@0 135 }
Chris@0 136
Chris@0 137 /**
Chris@0 138 * {@inheritdoc}
Chris@0 139 */
Chris@0 140 public function getCacheControlDirective($key)
Chris@0 141 {
Chris@0 142 return array_key_exists($key, $this->computedCacheControl) ? $this->computedCacheControl[$key] : null;
Chris@0 143 }
Chris@0 144
Chris@0 145 /**
Chris@0 146 * Sets a cookie.
Chris@0 147 *
Chris@0 148 * @param Cookie $cookie
Chris@0 149 */
Chris@0 150 public function setCookie(Cookie $cookie)
Chris@0 151 {
Chris@0 152 $this->cookies[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie;
Chris@0 153 }
Chris@0 154
Chris@0 155 /**
Chris@0 156 * Removes a cookie from the array, but does not unset it in the browser.
Chris@0 157 *
Chris@0 158 * @param string $name
Chris@0 159 * @param string $path
Chris@0 160 * @param string $domain
Chris@0 161 */
Chris@0 162 public function removeCookie($name, $path = '/', $domain = null)
Chris@0 163 {
Chris@0 164 if (null === $path) {
Chris@0 165 $path = '/';
Chris@0 166 }
Chris@0 167
Chris@0 168 unset($this->cookies[$domain][$path][$name]);
Chris@0 169
Chris@0 170 if (empty($this->cookies[$domain][$path])) {
Chris@0 171 unset($this->cookies[$domain][$path]);
Chris@0 172
Chris@0 173 if (empty($this->cookies[$domain])) {
Chris@0 174 unset($this->cookies[$domain]);
Chris@0 175 }
Chris@0 176 }
Chris@0 177 }
Chris@0 178
Chris@0 179 /**
Chris@0 180 * Returns an array with all cookies.
Chris@0 181 *
Chris@0 182 * @param string $format
Chris@0 183 *
Chris@0 184 * @return array
Chris@0 185 *
Chris@0 186 * @throws \InvalidArgumentException When the $format is invalid
Chris@0 187 */
Chris@0 188 public function getCookies($format = self::COOKIES_FLAT)
Chris@0 189 {
Chris@0 190 if (!in_array($format, array(self::COOKIES_FLAT, self::COOKIES_ARRAY))) {
Chris@0 191 throw new \InvalidArgumentException(sprintf('Format "%s" invalid (%s).', $format, implode(', ', array(self::COOKIES_FLAT, self::COOKIES_ARRAY))));
Chris@0 192 }
Chris@0 193
Chris@0 194 if (self::COOKIES_ARRAY === $format) {
Chris@0 195 return $this->cookies;
Chris@0 196 }
Chris@0 197
Chris@0 198 $flattenedCookies = array();
Chris@0 199 foreach ($this->cookies as $path) {
Chris@0 200 foreach ($path as $cookies) {
Chris@0 201 foreach ($cookies as $cookie) {
Chris@0 202 $flattenedCookies[] = $cookie;
Chris@0 203 }
Chris@0 204 }
Chris@0 205 }
Chris@0 206
Chris@0 207 return $flattenedCookies;
Chris@0 208 }
Chris@0 209
Chris@0 210 /**
Chris@0 211 * Clears a cookie in the browser.
Chris@0 212 *
Chris@0 213 * @param string $name
Chris@0 214 * @param string $path
Chris@0 215 * @param string $domain
Chris@0 216 * @param bool $secure
Chris@0 217 * @param bool $httpOnly
Chris@0 218 */
Chris@0 219 public function clearCookie($name, $path = '/', $domain = null, $secure = false, $httpOnly = true)
Chris@0 220 {
Chris@0 221 $this->setCookie(new Cookie($name, null, 1, $path, $domain, $secure, $httpOnly));
Chris@0 222 }
Chris@0 223
Chris@0 224 /**
Chris@0 225 * Generates a HTTP Content-Disposition field-value.
Chris@0 226 *
Chris@0 227 * @param string $disposition One of "inline" or "attachment"
Chris@0 228 * @param string $filename A unicode string
Chris@0 229 * @param string $filenameFallback A string containing only ASCII characters that
Chris@0 230 * is semantically equivalent to $filename. If the filename is already ASCII,
Chris@0 231 * it can be omitted, or just copied from $filename
Chris@0 232 *
Chris@0 233 * @return string A string suitable for use as a Content-Disposition field-value
Chris@0 234 *
Chris@0 235 * @throws \InvalidArgumentException
Chris@0 236 *
Chris@0 237 * @see RFC 6266
Chris@0 238 */
Chris@0 239 public function makeDisposition($disposition, $filename, $filenameFallback = '')
Chris@0 240 {
Chris@0 241 if (!in_array($disposition, array(self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE))) {
Chris@0 242 throw new \InvalidArgumentException(sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE));
Chris@0 243 }
Chris@0 244
Chris@0 245 if ('' == $filenameFallback) {
Chris@0 246 $filenameFallback = $filename;
Chris@0 247 }
Chris@0 248
Chris@0 249 // filenameFallback is not ASCII.
Chris@0 250 if (!preg_match('/^[\x20-\x7e]*$/', $filenameFallback)) {
Chris@0 251 throw new \InvalidArgumentException('The filename fallback must only contain ASCII characters.');
Chris@0 252 }
Chris@0 253
Chris@0 254 // percent characters aren't safe in fallback.
Chris@0 255 if (false !== strpos($filenameFallback, '%')) {
Chris@0 256 throw new \InvalidArgumentException('The filename fallback cannot contain the "%" character.');
Chris@0 257 }
Chris@0 258
Chris@0 259 // path separators aren't allowed in either.
Chris@0 260 if (false !== strpos($filename, '/') || false !== strpos($filename, '\\') || false !== strpos($filenameFallback, '/') || false !== strpos($filenameFallback, '\\')) {
Chris@0 261 throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.');
Chris@0 262 }
Chris@0 263
Chris@0 264 $output = sprintf('%s; filename="%s"', $disposition, str_replace('"', '\\"', $filenameFallback));
Chris@0 265
Chris@0 266 if ($filename !== $filenameFallback) {
Chris@0 267 $output .= sprintf("; filename*=utf-8''%s", rawurlencode($filename));
Chris@0 268 }
Chris@0 269
Chris@0 270 return $output;
Chris@0 271 }
Chris@0 272
Chris@0 273 /**
Chris@0 274 * Returns the calculated value of the cache-control header.
Chris@0 275 *
Chris@0 276 * This considers several other headers and calculates or modifies the
Chris@0 277 * cache-control header to a sensible, conservative value.
Chris@0 278 *
Chris@0 279 * @return string
Chris@0 280 */
Chris@0 281 protected function computeCacheControlValue()
Chris@0 282 {
Chris@0 283 if (!$this->cacheControl && !$this->has('ETag') && !$this->has('Last-Modified') && !$this->has('Expires')) {
Chris@0 284 return 'no-cache, private';
Chris@0 285 }
Chris@0 286
Chris@0 287 if (!$this->cacheControl) {
Chris@0 288 // conservative by default
Chris@0 289 return 'private, must-revalidate';
Chris@0 290 }
Chris@0 291
Chris@0 292 $header = $this->getCacheControlHeader();
Chris@0 293 if (isset($this->cacheControl['public']) || isset($this->cacheControl['private'])) {
Chris@0 294 return $header;
Chris@0 295 }
Chris@0 296
Chris@0 297 // public if s-maxage is defined, private otherwise
Chris@0 298 if (!isset($this->cacheControl['s-maxage'])) {
Chris@0 299 return $header.', private';
Chris@0 300 }
Chris@0 301
Chris@0 302 return $header;
Chris@0 303 }
Chris@0 304 }