X-Git-Url: http://www.aleph1.co.uk/gitweb/?a=blobdiff_plain;ds=sidebyside;f=vendor%2Fsymfony%2Fhttp-foundation%2FRequest.php;fp=vendor%2Fsymfony%2Fhttp-foundation%2FRequest.php;h=164fb4e0e333a2ccd0750088f9237859f6a4c86a;hb=af6d1fb995500ae68849458ee10d66abbdcfb252;hp=4fbad5ee6c801762bfadb535a031d1ee960c3c66;hpb=680c79a86e3ed402f263faeac92e89fb6d9edcc0;p=yaffs-website diff --git a/vendor/symfony/http-foundation/Request.php b/vendor/symfony/http-foundation/Request.php index 4fbad5ee6..164fb4e0e 100644 --- a/vendor/symfony/http-foundation/Request.php +++ b/vendor/symfony/http-foundation/Request.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpFoundation; use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException; +use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException; use Symfony\Component\HttpFoundation\Session\SessionInterface; /** @@ -29,11 +30,22 @@ use Symfony\Component\HttpFoundation\Session\SessionInterface; */ class Request { - const HEADER_FORWARDED = 'forwarded'; - const HEADER_CLIENT_IP = 'client_ip'; - const HEADER_CLIENT_HOST = 'client_host'; - const HEADER_CLIENT_PROTO = 'client_proto'; - const HEADER_CLIENT_PORT = 'client_port'; + const HEADER_FORWARDED = 0b00001; // When using RFC 7239 + const HEADER_X_FORWARDED_FOR = 0b00010; + const HEADER_X_FORWARDED_HOST = 0b00100; + const HEADER_X_FORWARDED_PROTO = 0b01000; + const HEADER_X_FORWARDED_PORT = 0b10000; + const HEADER_X_FORWARDED_ALL = 0b11110; // All "X-Forwarded-*" headers + const HEADER_X_FORWARDED_AWS_ELB = 0b11010; // AWS ELB doesn't send X-Forwarded-Host + + /** @deprecated since version 3.3, to be removed in 4.0 */ + const HEADER_CLIENT_IP = self::HEADER_X_FORWARDED_FOR; + /** @deprecated since version 3.3, to be removed in 4.0 */ + const HEADER_CLIENT_HOST = self::HEADER_X_FORWARDED_HOST; + /** @deprecated since version 3.3, to be removed in 4.0 */ + const HEADER_CLIENT_PROTO = self::HEADER_X_FORWARDED_PROTO; + /** @deprecated since version 3.3, to be removed in 4.0 */ + const HEADER_CLIENT_PORT = self::HEADER_X_FORWARDED_PORT; const METHOD_HEAD = 'HEAD'; const METHOD_GET = 'GET'; @@ -69,6 +81,8 @@ class Request * * The other headers are non-standard, but widely used * by popular reverse proxies (like Apache mod_proxy or Amazon EC2). + * + * @deprecated since version 3.3, to be removed in 4.0 */ protected static $trustedHeaders = array( self::HEADER_FORWARDED => 'FORWARDED', @@ -130,7 +144,7 @@ class Request public $headers; /** - * @var string + * @var string|resource|false|null */ protected $content; @@ -206,25 +220,35 @@ class Request protected static $requestFactory; + private $isHostValid = true; private $isForwardedValid = true; + private static $trustedHeaderSet = -1; + + /** @deprecated since version 3.3, to be removed in 4.0 */ + private static $trustedHeaderNames = array( + self::HEADER_FORWARDED => 'FORWARDED', + self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR', + self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST', + self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO', + self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT', + ); + private static $forwardedParams = array( - self::HEADER_CLIENT_IP => 'for', - self::HEADER_CLIENT_HOST => 'host', - self::HEADER_CLIENT_PROTO => 'proto', - self::HEADER_CLIENT_PORT => 'host', + self::HEADER_X_FORWARDED_FOR => 'for', + self::HEADER_X_FORWARDED_HOST => 'host', + self::HEADER_X_FORWARDED_PROTO => 'proto', + self::HEADER_X_FORWARDED_PORT => 'host', ); /** - * Constructor. - * - * @param array $query The GET parameters - * @param array $request The POST parameters - * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) - * @param array $cookies The COOKIE parameters - * @param array $files The FILES parameters - * @param array $server The SERVER parameters - * @param string|resource $content The raw body data + * @param array $query The GET parameters + * @param array $request The POST parameters + * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) + * @param array $cookies The COOKIE parameters + * @param array $files The FILES parameters + * @param array $server The SERVER parameters + * @param string|resource|null $content The raw body data */ public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null) { @@ -236,13 +260,13 @@ class Request * * This method also re-initializes all properties. * - * @param array $query The GET parameters - * @param array $request The POST parameters - * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) - * @param array $cookies The COOKIE parameters - * @param array $files The FILES parameters - * @param array $server The SERVER parameters - * @param string|resource $content The raw body data + * @param array $query The GET parameters + * @param array $request The POST parameters + * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) + * @param array $cookies The COOKIE parameters + * @param array $files The FILES parameters + * @param array $server The SERVER parameters + * @param string|resource|null $content The raw body data */ public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null) { @@ -305,13 +329,13 @@ class Request * The information contained in the URI always take precedence * over the other information (server and parameters). * - * @param string $uri The URI - * @param string $method The HTTP method - * @param array $parameters The query (GET) or request (POST) parameters - * @param array $cookies The request cookies ($_COOKIE) - * @param array $files The request files ($_FILES) - * @param array $server The server parameters ($_SERVER) - * @param string $content The raw body data + * @param string $uri The URI + * @param string $method The HTTP method + * @param array $parameters The query (GET) or request (POST) parameters + * @param array $cookies The request cookies ($_COOKIE) + * @param array $files The request files ($_FILES) + * @param array $server The server parameters ($_SERVER) + * @param string|resource|null $content The raw body data * * @return static */ @@ -436,22 +460,22 @@ class Request public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null) { $dup = clone $this; - if ($query !== null) { + if (null !== $query) { $dup->query = new ParameterBag($query); } - if ($request !== null) { + if (null !== $request) { $dup->request = new ParameterBag($request); } - if ($attributes !== null) { + if (null !== $attributes) { $dup->attributes = new ParameterBag($attributes); } - if ($cookies !== null) { + if (null !== $cookies) { $dup->cookies = new ParameterBag($cookies); } - if ($files !== null) { + if (null !== $files) { $dup->files = new FileBag($files); } - if ($server !== null) { + if (null !== $server) { $dup->server = new ServerBag($server); $dup->headers = new HeaderBag($dup->server->getHeaders()); } @@ -507,9 +531,21 @@ class Request return trigger_error($e, E_USER_ERROR); } + $cookieHeader = ''; + $cookies = array(); + + foreach ($this->cookies as $k => $v) { + $cookies[] = $k.'='.$v; + } + + if (!empty($cookies)) { + $cookieHeader = 'Cookie: '.implode('; ', $cookies)."\r\n"; + } + return sprintf('%s %s %s', $this->getMethod(), $this->getRequestUri(), $this->server->get('SERVER_PROTOCOL'))."\r\n". - $this->headers."\r\n". + $this->headers. + $cookieHeader."\r\n". $content; } @@ -521,7 +557,7 @@ class Request */ public function overrideGlobals() { - $this->server->set('QUERY_STRING', static::normalizeQueryString(http_build_query($this->query->all(), null, '&'))); + $this->server->set('QUERY_STRING', static::normalizeQueryString(http_build_query($this->query->all(), '', '&'))); $_GET = $this->query->all(); $_POST = $this->request->all(); @@ -553,11 +589,26 @@ class Request * * You should only list the reverse proxies that you manage directly. * - * @param array $proxies A list of trusted proxies + * @param array $proxies A list of trusted proxies + * @param int $trustedHeaderSet A bit field of Request::HEADER_*, to set which headers to trust from your proxies + * + * @throws \InvalidArgumentException When $trustedHeaderSet is invalid */ - public static function setTrustedProxies(array $proxies) + public static function setTrustedProxies(array $proxies/*, int $trustedHeaderSet*/) { self::$trustedProxies = $proxies; + + if (2 > func_num_args()) { + @trigger_error(sprintf('The %s() method expects a bit field of Request::HEADER_* as second argument since Symfony 3.3. Defining it will be required in 4.0. ', __METHOD__), E_USER_DEPRECATED); + + return; + } + $trustedHeaderSet = (int) func_get_arg(1); + + foreach (self::$trustedHeaderNames as $header => $name) { + self::$trustedHeaders[$header] = $header & $trustedHeaderSet ? $name : null; + } + self::$trustedHeaderSet = $trustedHeaderSet; } /** @@ -570,6 +621,16 @@ class Request return self::$trustedProxies; } + /** + * Gets the set of trusted headers from trusted proxies. + * + * @return int A bit field of Request::HEADER_* that defines which headers are trusted from your proxies + */ + public static function getTrustedHeaderSet() + { + return self::$trustedHeaderSet; + } + /** * Sets a list of trusted host patterns. * @@ -613,14 +674,35 @@ class Request * @param string $value The header name * * @throws \InvalidArgumentException + * + * @deprecated since version 3.3, to be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead. */ public static function setTrustedHeaderName($key, $value) { - if (!array_key_exists($key, self::$trustedHeaders)) { + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.', __METHOD__), E_USER_DEPRECATED); + + if ('forwarded' === $key) { + $key = self::HEADER_FORWARDED; + } elseif ('client_ip' === $key) { + $key = self::HEADER_CLIENT_IP; + } elseif ('client_host' === $key) { + $key = self::HEADER_CLIENT_HOST; + } elseif ('client_proto' === $key) { + $key = self::HEADER_CLIENT_PROTO; + } elseif ('client_port' === $key) { + $key = self::HEADER_CLIENT_PORT; + } elseif (!array_key_exists($key, self::$trustedHeaders)) { throw new \InvalidArgumentException(sprintf('Unable to set the trusted header name for key "%s".', $key)); } self::$trustedHeaders[$key] = $value; + + if (null !== $value) { + self::$trustedHeaderNames[$key] = $value; + self::$trustedHeaderSet |= $key; + } else { + self::$trustedHeaderSet &= ~$key; + } } /** @@ -631,9 +713,15 @@ class Request * @return string The header name * * @throws \InvalidArgumentException + * + * @deprecated since version 3.3, to be removed in 4.0. Use the Request::getTrustedHeaderSet() method instead. */ public static function getTrustedHeaderName($key) { + if (2 > func_num_args() || func_get_arg(1)) { + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the Request::getTrustedHeaderSet() method instead.', __METHOD__), E_USER_DEPRECATED); + } + if (!array_key_exists($key, self::$trustedHeaders)) { throw new \InvalidArgumentException(sprintf('Unable to get the trusted header name for key "%s".', $key)); } @@ -719,8 +807,8 @@ class Request * * Order of precedence: PATH (routing placeholders or custom attributes), GET, BODY * - * @param string $key the key - * @param mixed $default the default value if the parameter key does not exist + * @param string $key The key + * @param mixed $default The default value if the parameter key does not exist * * @return mixed */ @@ -821,8 +909,8 @@ class Request * adding the IP address where it received the request from. * * If your reverse proxy uses a different header name than "X-Forwarded-For", - * ("Client-Ip" for instance), configure it via "setTrustedHeaderName()" with - * the "client-ip" key. + * ("Client-Ip" for instance), configure it via the $trustedHeaderSet + * argument of the Request::setTrustedProxies() method instead. * * @return string|null The client IP address * @@ -928,7 +1016,8 @@ class Request * The "X-Forwarded-Port" header must contain the client port. * * If your reverse proxy uses a different header name than "X-Forwarded-Port", - * configure it via "setTrustedHeaderName()" with the "client-port" key. + * configure it via via the $trustedHeaderSet argument of the + * Request::setTrustedProxies() method instead. * * @return int|string can be a string if fetched from the server bag */ @@ -942,7 +1031,7 @@ class Request return $this->server->get('SERVER_PORT'); } - if ($host[0] === '[') { + if ('[' === $host[0]) { $pos = strpos($host, ':', strrpos($host, ']')); } else { $pos = strrpos($host, ':'); @@ -1004,7 +1093,7 @@ class Request $scheme = $this->getScheme(); $port = $this->getPort(); - if (('http' == $scheme && $port == 80) || ('https' == $scheme && $port == 443)) { + if (('http' == $scheme && 80 == $port) || ('https' == $scheme && 443 == $port)) { return $this->getHost(); } @@ -1145,8 +1234,8 @@ class Request * The "X-Forwarded-Proto" header must contain the protocol: "https" or "http". * * If your reverse proxy uses a different header name than "X-Forwarded-Proto" - * ("SSL_HTTPS" for instance), configure it via "setTrustedHeaderName()" with - * the "client-proto" key. + * ("SSL_HTTPS" for instance), configure it via the $trustedHeaderSet + * argument of the Request::setTrustedProxies() method instead. * * @return bool */ @@ -1170,11 +1259,12 @@ class Request * The "X-Forwarded-Host" header must contain the client host name. * * If your reverse proxy uses a different header name than "X-Forwarded-Host", - * configure it via "setTrustedHeaderName()" with the "client-host" key. + * configure it via the $trustedHeaderSet argument of the + * Request::setTrustedProxies() method instead. * * @return string * - * @throws \UnexpectedValueException when the host name is invalid + * @throws SuspiciousOperationException when the host name is invalid or not trusted */ public function getHost() { @@ -1194,7 +1284,12 @@ class Request // check that it does not contain forbidden characters (see RFC 952 and RFC 2181) // use preg_replace() instead of preg_match() to prevent DoS attacks with long host names if ($host && '' !== preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $host)) { - throw new \UnexpectedValueException(sprintf('Invalid Host "%s"', $host)); + if (!$this->isHostValid) { + return ''; + } + $this->isHostValid = false; + + throw new SuspiciousOperationException(sprintf('Invalid Host "%s".', $host)); } if (count(self::$trustedHostPatterns) > 0) { @@ -1212,7 +1307,12 @@ class Request } } - throw new \UnexpectedValueException(sprintf('Untrusted Host "%s"', $host)); + if (!$this->isHostValid) { + return ''; + } + $this->isHostValid = false; + + throw new SuspiciousOperationException(sprintf('Untrusted Host "%s".', $host)); } return $host; @@ -1460,7 +1560,7 @@ class Request if (!func_num_args() || func_get_arg(0)) { // This deprecation should be turned into a BadMethodCallException in 4.0 (without adding the argument in the signature) // then setting $andCacheable to false should be deprecated in 4.1 - @trigger_error('Checking only for cacheable HTTP methods with Symfony\Component\HttpFoundation\Request::isMethodSafe() is deprecated since version 3.2 and will throw an exception in 4.0. Disable checking only for cacheable methods by calling the method with `false` as first argument or use the Request::isMethodCacheable() instead.', E_USER_DEPRECATED); + @trigger_error('Checking only for cacheable HTTP methods with Symfony\Component\HttpFoundation\Request::isMethodSafe() is deprecated since Symfony 3.2 and will throw an exception in 4.0. Disable checking only for cacheable methods by calling the method with `false` as first argument or use the Request::isMethodCacheable() instead.', E_USER_DEPRECATED); return in_array($this->getMethod(), array('GET', 'HEAD')); } @@ -1490,6 +1590,30 @@ class Request return in_array($this->getMethod(), array('GET', 'HEAD')); } + /** + * Returns the protocol version. + * + * If the application is behind a proxy, the protocol version used in the + * requests between the client and the proxy and between the proxy and the + * server might be different. This returns the former (from the "Via" header) + * if the proxy is trusted (see "setTrustedProxies()"), otherwise it returns + * the latter (from the "SERVER_PROTOCOL" server parameter). + * + * @return string + */ + public function getProtocolVersion() + { + if ($this->isFromTrustedProxy()) { + preg_match('~^(HTTP/)?([1-9]\.[0-9]) ~', $this->headers->get('Via'), $matches); + + if ($matches) { + return 'HTTP/'.$matches[2]; + } + } + + return $this->server->get('SERVER_PROTOCOL'); + } + /** * Returns the request body content. * @@ -1618,7 +1742,7 @@ class Request } } else { for ($i = 0, $max = count($codes); $i < $max; ++$i) { - if ($i === 0) { + if (0 === $i) { $lang = strtolower($codes[0]); } else { $lang .= '_'.strtoupper($codes[$i]); @@ -1713,7 +1837,7 @@ class Request // IIS with ISAPI_Rewrite $requestUri = $this->headers->get('X_REWRITE_URL'); $this->headers->remove('X_REWRITE_URL'); - } elseif ($this->server->get('IIS_WasUrlRewritten') == '1' && $this->server->get('UNENCODED_URL') != '') { + } elseif ('1' == $this->server->get('IIS_WasUrlRewritten') && '' != $this->server->get('UNENCODED_URL')) { // IIS7 with URL Rewrite: make sure we get the unencoded URL (double slash problem) $requestUri = $this->server->get('UNENCODED_URL'); $this->server->remove('UNENCODED_URL'); @@ -1722,7 +1846,7 @@ class Request $requestUri = $this->server->get('REQUEST_URI'); // HTTP proxy reqs setup request URI with scheme and host [and port] + the URL path, only use URL path $schemeAndHttpHost = $this->getSchemeAndHttpHost(); - if (strpos($requestUri, $schemeAndHttpHost) === 0) { + if (0 === strpos($requestUri, $schemeAndHttpHost)) { $requestUri = substr($requestUri, strlen($schemeAndHttpHost)); } } elseif ($this->server->has('ORIG_PATH_INFO')) { @@ -1774,7 +1898,7 @@ class Request // Does the baseUrl have anything in common with the request_uri? $requestUri = $this->getRequestUri(); - if ($requestUri !== '' && $requestUri[0] !== '/') { + if ('' !== $requestUri && '/' !== $requestUri[0]) { $requestUri = '/'.$requestUri; } @@ -1802,7 +1926,7 @@ class Request // If using mod_rewrite or ISAPI_Rewrite strip the script filename // out of baseUrl. $pos !== 0 makes sure it is not matching a value // from PATH_INFO or QUERY_STRING - if (strlen($requestUri) >= strlen($baseUrl) && (false !== $pos = strpos($requestUri, $baseUrl)) && $pos !== 0) { + if (strlen($requestUri) >= strlen($baseUrl) && (false !== $pos = strpos($requestUri, $baseUrl)) && 0 !== $pos) { $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl)); } @@ -1816,12 +1940,12 @@ class Request */ protected function prepareBasePath() { - $filename = basename($this->server->get('SCRIPT_FILENAME')); $baseUrl = $this->getBaseUrl(); if (empty($baseUrl)) { return ''; } + $filename = basename($this->server->get('SCRIPT_FILENAME')); if (basename($baseUrl) === $filename) { $basePath = dirname($baseUrl); } else { @@ -1842,8 +1966,6 @@ class Request */ protected function preparePathInfo() { - $baseUrl = $this->getBaseUrl(); - if (null === ($requestUri = $this->getRequestUri())) { return '/'; } @@ -1852,16 +1974,18 @@ class Request if (false !== $pos = strpos($requestUri, '?')) { $requestUri = substr($requestUri, 0, $pos); } - if ($requestUri !== '' && $requestUri[0] !== '/') { + if ('' !== $requestUri && '/' !== $requestUri[0]) { $requestUri = '/'.$requestUri; } + if (null === ($baseUrl = $this->getBaseUrl())) { + return $requestUri; + } + $pathInfo = substr($requestUri, strlen($baseUrl)); - if (null !== $baseUrl && (false === $pathInfo || '' === $pathInfo)) { + if (false === $pathInfo || '' === $pathInfo) { // If substr() returns false then PATH_INFO is set to an empty string return '/'; - } elseif (null === $baseUrl) { - return $requestUri; } return (string) $pathInfo; @@ -1878,6 +2002,7 @@ class Request 'js' => array('application/javascript', 'application/x-javascript', 'text/javascript'), 'css' => array('text/css'), 'json' => array('application/json', 'application/x-json'), + 'jsonld' => array('application/ld+json'), 'xml' => array('text/xml', 'application/xml', 'application/x-xml'), 'rdf' => array('application/rdf+xml'), 'atom' => array('application/atom+xml'),