Browse Source

HTTP headers checks refactored to use PSR-7 abstraction

tags/3.0.0-alpha1
Klimov Paul 7 years ago
parent
commit
722022f744
  1. 15
      framework/filters/Cors.php
  2. 9
      framework/filters/HttpCache.php
  3. 6
      framework/validators/FileValidator.php
  4. 2
      framework/web/ErrorHandler.php
  5. 60
      framework/web/Request.php
  6. 6
      framework/web/Response.php
  7. 1
      framework/web/Session.php
  8. 15
      tests/framework/filters/HttpCacheTest.php

15
framework/filters/Cors.php

@ -135,8 +135,7 @@ class Cors extends ActionFilter
$headers = [];
$requestHeaders = array_keys($this->cors);
foreach ($requestHeaders as $headerField) {
$serverField = $this->headerizeToPhp($headerField);
$headerData = isset($_SERVER[$serverField]) ? $_SERVER[$serverField] : null;
$headerData = $this->request->getHeaderLine($headerField);
if ($headerData !== null) {
$headers[$headerField] = $headerData;
}
@ -233,16 +232,4 @@ class Cors extends ActionFilter
}, $headers);
return implode(', ', $headers);
}
/**
* Convert any string (including php headers with HTTP prefix) to header format like :
* * X-Pingother -> HTTP_X_PINGOTHER
* * X PINGOTHER -> HTTP_X_PINGOTHER
* @param string $string string to convert
* @return string the result in "php $_SERVER header" format
*/
protected function headerizeToPhp($string)
{
return 'HTTP_' . strtoupper(str_replace([' ', '-'], ['_', '_'], $string));
}
}

9
framework/filters/HttpCache.php

@ -165,12 +165,13 @@ class HttpCache extends ActionFilter
*/
protected function validateCache($lastModified, $etag)
{
if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
// HTTP_IF_NONE_MATCH takes precedence over HTTP_IF_MODIFIED_SINCE
$request = Yii::$app->getRequest();
if ($request->hasHeader('if-none-match')) {
// 'if-none-match' takes precedence over 'if-modified-since'
// http://tools.ietf.org/html/rfc7232#section-3.3
return $etag !== null && in_array($etag, Yii::$app->request->getETags(), true);
} elseif (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
return $lastModified !== null && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $lastModified;
} elseif ($request->hasHeader('if-modified-since')) {
return $lastModified !== null && @strtotime($request->getHeaderLine('if-modified-since')) >= $lastModified;
}
return false;

6
framework/validators/FileValidator.php

@ -303,8 +303,10 @@ class FileValidator extends Validator
if ($this->maxSize !== null && $limit > 0 && $this->maxSize < $limit) {
$limit = $this->maxSize;
}
if (isset($_POST['MAX_FILE_SIZE']) && $_POST['MAX_FILE_SIZE'] > 0 && $_POST['MAX_FILE_SIZE'] < $limit) {
$limit = (int) $_POST['MAX_FILE_SIZE'];
$maxFileSize = Yii::$app->getRequest()->getBodyParam('MAX_FILE_SIZE', 0);
if ($maxFileSize > 0 && $maxFileSize < $limit) {
$limit = (int)$maxFileSize;
}
return $limit;

2
framework/web/ErrorHandler.php

@ -486,6 +486,6 @@ class ErrorHandler extends \yii\base\ErrorHandler
*/
protected function shouldRenderSimpleHtml()
{
return YII_ENV_TEST || isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
return YII_ENV_TEST || Yii::$app->getRequest()->getHeaderLine('x-requested-with') === 'XMLHttpRequest';
}
}

60
framework/web/Request.php

@ -288,8 +288,8 @@ class Request extends \yii\base\Request implements RequestInterface
if ($this->_method === null) {
if (isset($_POST[$this->methodParam])) {
$this->_method = $_POST[$this->methodParam];
} elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
$this->_method = $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'];
} elseif ($this->hasHeader('x-http-method-override')) {
$this->_method = $this->getHeaderLine('x-http-method-override');
} elseif (isset($_SERVER['REQUEST_METHOD'])) {
$this->_method = $_SERVER['REQUEST_METHOD'];
} else {
@ -446,7 +446,7 @@ class Request extends \yii\base\Request implements RequestInterface
*/
public function getIsAjax()
{
return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
return $this->getHeaderLine('x-requested-with') === 'XMLHttpRequest';
}
/**
@ -455,7 +455,7 @@ class Request extends \yii\base\Request implements RequestInterface
*/
public function getIsPjax()
{
return $this->getIsAjax() && !empty($_SERVER['HTTP_X_PJAX']);
return $this->getIsAjax() && $this->hasHeader('x-pjax');
}
/**
@ -464,8 +464,11 @@ class Request extends \yii\base\Request implements RequestInterface
*/
public function getIsFlash()
{
return isset($_SERVER['HTTP_USER_AGENT']) &&
(stripos($_SERVER['HTTP_USER_AGENT'], 'Shockwave') !== false || stripos($_SERVER['HTTP_USER_AGENT'], 'Flash') !== false);
$userAgent = $this->getUserAgent();
if ($userAgent === null) {
return false;
}
return (stripos($userAgent, 'Shockwave') !== false || stripos($userAgent, 'Flash') !== false);
}
/**
@ -697,8 +700,8 @@ class Request extends \yii\base\Request implements RequestInterface
if ($this->_hostInfo === null) {
$secure = $this->getIsSecureConnection();
$http = $secure ? 'https' : 'http';
if (isset($_SERVER['HTTP_HOST'])) {
$this->_hostInfo = $http . '://' . $_SERVER['HTTP_HOST'];
if ($this->hasHeader('Host')) {
$this->_hostInfo = $http . '://' . $this->getHeaderLine('Host');
} elseif (isset($_SERVER['SERVER_NAME'])) {
$this->_hostInfo = $http . '://' . $_SERVER['SERVER_NAME'];
$port = $secure ? $this->getSecurePort() : $this->getPort();
@ -979,8 +982,8 @@ class Request extends \yii\base\Request implements RequestInterface
*/
protected function resolveRequestUri()
{
if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // IIS
$requestUri = $_SERVER['HTTP_X_REWRITE_URL'];
if ($this->hasHeader('x-rewrite-url')) { // IIS
$requestUri = $this->getHeaderLine('x-rewrite-url');
} elseif (isset($_SERVER['REQUEST_URI'])) {
$requestUri = $_SERVER['REQUEST_URI'];
if ($requestUri !== '' && $requestUri[0] !== '/') {
@ -1014,7 +1017,7 @@ class Request extends \yii\base\Request implements RequestInterface
public function getIsSecureConnection()
{
return isset($_SERVER['HTTPS']) && (strcasecmp($_SERVER['HTTPS'], 'on') === 0 || $_SERVER['HTTPS'] == 1)
|| isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0;
|| strcasecmp($this->getHeaderLine('x-forwarded-proto'), 'https') === 0;
}
/**
@ -1041,7 +1044,10 @@ class Request extends \yii\base\Request implements RequestInterface
*/
public function getReferrer()
{
return isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
if (!$this->hasHeader('Referer')) {
return null;
}
return $this->getHeaderLine('Referer');
}
/**
@ -1070,7 +1076,10 @@ class Request extends \yii\base\Request implements RequestInterface
*/
public function getUserAgent()
{
return isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
if (!$this->hasHeader('User-Agent')) {
return null;
}
return $this->getHeaderLine('User-Agent');
}
/**
@ -1196,8 +1205,8 @@ class Request extends \yii\base\Request implements RequestInterface
public function getAcceptableContentTypes()
{
if ($this->_contentTypes === null) {
if (isset($_SERVER['HTTP_ACCEPT'])) {
$this->_contentTypes = $this->parseAcceptHeader($_SERVER['HTTP_ACCEPT']);
if ($this->hasHeader('Accept')) {
$this->_contentTypes = $this->parseAcceptHeader($this->getHeaderLine('Accept'));
} else {
$this->_contentTypes = [];
}
@ -1225,22 +1234,13 @@ class Request extends \yii\base\Request implements RequestInterface
* contained in [[getRawBody()]] or, in the case of the HEAD method, the
* media type that would have been sent had the request been a GET.
* For the MIME-types the user expects in response, see [[acceptableContentTypes]].
* @return string request content-type. Null is returned if this information is not available.
* @return string request content-type. Empty string is returned if this information is not available.
* @link https://tools.ietf.org/html/rfc2616#section-14.17
* HTTP 1.1 header field definitions
*/
public function getContentType()
{
if (isset($_SERVER['CONTENT_TYPE'])) {
return $_SERVER['CONTENT_TYPE'];
}
if (isset($_SERVER['HTTP_CONTENT_TYPE'])) {
//fix bug https://bugs.php.net/bug.php?id=66606
return $_SERVER['HTTP_CONTENT_TYPE'];
}
return null;
return $this->getHeaderLine('Content-Type');
}
private $_languages;
@ -1254,8 +1254,8 @@ class Request extends \yii\base\Request implements RequestInterface
public function getAcceptableLanguages()
{
if ($this->_languages === null) {
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$this->_languages = array_keys($this->parseAcceptHeader($_SERVER['HTTP_ACCEPT_LANGUAGE']));
if ($this->hasHeader('Accept-Language')) {
$this->_languages = array_keys($this->parseAcceptHeader($this->getHeaderLine('Accept-Language')));
} else {
$this->_languages = [];
}
@ -1403,8 +1403,8 @@ class Request extends \yii\base\Request implements RequestInterface
*/
public function getETags()
{
if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
return preg_split('/[\s,]+/', str_replace('-gzip', '', $_SERVER['HTTP_IF_NONE_MATCH']), -1, PREG_SPLIT_NO_EMPTY);
if ($this->hasHeader('if-none-match')) {
return preg_split('/[\s,]+/', str_replace('-gzip', '', $this->getHeaderLine('if-none-match')), -1, PREG_SPLIT_NO_EMPTY);
}
return [];

6
framework/web/Response.php

@ -658,10 +658,12 @@ class Response extends \yii\base\Response implements ResponseInterface
*/
protected function getHttpRange($fileSize)
{
if (!isset($_SERVER['HTTP_RANGE']) || $_SERVER['HTTP_RANGE'] === '-') {
$rangeHeader = Yii::$app->getRequest()->getHeaderLine('Range');
if (empty($rangeHeader) || $rangeHeader === '-') {
return [0, $fileSize - 1];
}
if (!preg_match('/^bytes=(\d*)-(\d*)$/', $_SERVER['HTTP_RANGE'], $matches)) {
if (!preg_match('/^bytes=(\d*)-(\d*)$/', $rangeHeader, $matches)) {
return false;
}
if ($matches[1] === '') {

1
framework/web/Session.php

@ -231,6 +231,7 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
if ($this->_hasSessionId === null) {
$name = $this->getName();
$request = Yii::$app->getRequest();
// unable to use `Request::$cookies` since CSRF protection feature exclude the session one from them
if (!empty($_COOKIE[$name]) && ini_get('session.use_cookies')) {
$this->_hasSessionId = true;
} elseif (!ini_get('session.use_only_cookies') && ini_get('session.use_trans_sid')) {

15
tests/framework/filters/HttpCacheTest.php

@ -49,27 +49,34 @@ class HttpCacheTest extends \yiiunit\TestCase
*/
public function testValidateCache()
{
$request = Yii::$app->request;
$httpCache = new HttpCache();
$method = new \ReflectionMethod($httpCache, 'validateCache');
$method->setAccessible(true);
unset($_SERVER['HTTP_IF_MODIFIED_SINCE'], $_SERVER['HTTP_IF_NONE_MATCH']);
$request->setHeaders([]);
$this->assertFalse($method->invoke($httpCache, null, null));
$this->assertFalse($method->invoke($httpCache, 0, null));
$this->assertFalse($method->invoke($httpCache, 0, '"foo"'));
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = 'Thu, 01 Jan 1970 00:00:00 GMT';
$request->setHeaders([
'if-modified-since' => ['Thu, 01 Jan 1970 00:00:00 GMT']
]);
$this->assertTrue($method->invoke($httpCache, 0, null));
$this->assertFalse($method->invoke($httpCache, 1, null));
$_SERVER['HTTP_IF_NONE_MATCH'] = '"foo"';
$request->setHeaders([
'if-none-match' => ['"foo"']
]);
$this->assertTrue($method->invoke($httpCache, 0, '"foo"'));
$this->assertFalse($method->invoke($httpCache, 0, '"foos"'));
$this->assertTrue($method->invoke($httpCache, 1, '"foo"'));
$this->assertFalse($method->invoke($httpCache, 1, '"foos"'));
$this->assertFalse($method->invoke($httpCache, null, null));
$_SERVER['HTTP_IF_NONE_MATCH'] = '*';
$request->setHeaders([
'if-none-match' => ['*']
]);
$this->assertFalse($method->invoke($httpCache, 0, '"foo"'));
$this->assertFalse($method->invoke($httpCache, 0, null));
}

Loading…
Cancel
Save