Beef up IncomingRequest & Negotiate unit testing

This commit is contained in:
Master Yoda 2018-07-21 00:36:06 -07:00
parent d88520b20a
commit 364847cec7
No known key found for this signature in database
GPG Key ID: CED549230775AD5B
6 changed files with 363 additions and 68 deletions

View File

@ -1,4 +1,6 @@
<?php namespace CodeIgniter\HTTP;
<?php
namespace CodeIgniter\HTTP;
/**
* CodeIgniter
@ -80,7 +82,7 @@ class IncomingRequest extends Request
protected $enableCSRF = false;
/**
* A \CodeIgniter\HTTPLite\URI instance.
* A \CodeIgniter\HTTP\URI instance.
*
* @var URI
*/
@ -98,7 +100,7 @@ class IncomingRequest extends Request
*
* @var \CodeIgniter\HTTP\Negotiate
*/
protected $negotiate;
protected $negotiator;
/**
* The default Locale this request
@ -242,6 +244,8 @@ class IncomingRequest extends Request
// If the intl extension is loaded, make sure
// that we set the locale for it... if not, though,
// don't worry about it.
// this should not block code coverage thru unit testing
// @codeCoverageIgnoreStart
try
{
if (class_exists('\Locale', false))
@ -250,8 +254,9 @@ class IncomingRequest extends Request
}
} catch (\Exception $e)
{
}
// @codeCoverageIgnoreEnd
return $this;
}
@ -294,12 +299,10 @@ class IncomingRequest extends Request
if ( ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off')
{
return true;
}
elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
} elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
{
return true;
}
elseif ( ! empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off')
} elseif ( ! empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off')
{
return true;
}
@ -533,7 +536,6 @@ class IncomingRequest extends Request
return $this->files->all(); // return all files
}
//--------------------------------------------------------------------
/**
@ -584,13 +586,14 @@ class IncomingRequest extends Request
$this->uri->setHost(parse_url($baseURL, PHP_URL_HOST));
$this->uri->setPort(parse_url($baseURL, PHP_URL_PORT));
$this->uri->resolveRelativeURI(parse_url($baseURL, PHP_URL_PATH));
}
else
} else
{
if(! is_cli())
// @codeCoverageIgnoreStart
if ( ! is_cli())
{
throw FrameworkException::forEmptyBaseURL();
}
// @codeCoverageIgnoreEnd
}
}
@ -604,7 +607,7 @@ class IncomingRequest extends Request
*
* @return string
*/
public function detectPath($protocol)
public function detectPath($protocol = '')
{
if (empty($protocol))
{
@ -642,25 +645,21 @@ class IncomingRequest extends Request
*/
public function negotiate(string $type, array $supported, bool $strictMatch = false)
{
if (is_null($this->negotiate))
if (is_null($this->negotiator))
{
$this->negotiate = Services::negotiator($this, true);
$this->negotiator = Services::negotiator($this, true);
}
switch (strtolower($type))
{
case 'media':
return $this->negotiate->media($supported, $strictMatch);
break;
return $this->negotiator->media($supported, $strictMatch);
case 'charset':
return $this->negotiate->charset($supported);
break;
return $this->negotiator->charset($supported);
case 'encoding':
return $this->negotiate->encoding($supported);
break;
return $this->negotiator->encoding($supported);
case 'language':
return $this->negotiate->language($supported);
break;
return $this->negotiator->language($supported);
}
throw HTTPException::forInvalidNegotiationType($type);
@ -689,25 +688,24 @@ class IncomingRequest extends Request
if (isset($_SERVER['SCRIPT_NAME'][0]))
{
// strip the script name from the beginning of the URI
if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0)
{
$uri = (string) substr($uri, strlen($_SERVER['SCRIPT_NAME']));
}
elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
{
$uri = (string) substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
}
} elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
// if the script is nested, strip the parent folder & script from the URI
if (strpos($uri, $_SERVER['SCRIPT_NAME']) > 0)
$uri = (string) substr($uri, strpos($uri, $_SERVER['SCRIPT_NAME']) + strlen($_SERVER['SCRIPT_NAME']));
}
// This section ensures that even on servers that require the URI to be in the query string (Nginx) a correct
// This section ensures that even on servers that require the URI to contain the query string (Nginx) a correct
// URI is found, and also fixes the QUERY_STRING getServer var and $_GET array.
if (trim($uri, '/') === '' && strncmp($query, '/', 1) === 0)
{
$query = explode('?', $query, 2);
$uri = $query[0];
$_SERVER['QUERY_STRING'] = $query[1] ?? '';
}
else
} else
{
$_SERVER['QUERY_STRING'] = $query;
}
@ -738,8 +736,7 @@ class IncomingRequest extends Request
if (trim($uri, '/') === '')
{
return '';
}
elseif (strncmp($uri, '/', 1) === 0)
} elseif (strncmp($uri, '/', 1) === 0)
{
$uri = explode('?', $uri, 2);
$_SERVER['QUERY_STRING'] = $uri[1] ?? '';

View File

@ -213,7 +213,7 @@ class Negotiate
// If no acceptable values exist, return the
// first that we support.
if (empty($acceptable))
if (count($acceptable) === 0)
{
return $supported[0];
}

View File

@ -4,10 +4,10 @@ use CodeIgniter\HTTP\IncomingRequest;
class MockIncomingRequest extends IncomingRequest
{
public function populateHeaders()
{
// Don't do anything... force the tester to manually set the headers they want.
}
// public function populateHeaders()
// {
// // Don't do anything... force the tester to manually set the headers they want.
// }
public function detectURI($protocol, $baseURL)
{

View File

@ -0,0 +1,143 @@
<?php
namespace CodeIgniter\HTTP;
use Config\App;
use CodeIgniter\HTTP\Files\UploadedFile;
/**
* @backupGlobals enabled
*/
class IncomingRequestDetectingTest extends \CIUnitTestCase
{
/**
* @var \CodeIgniter\HTTP\IncomingRequest
*/
protected $request;
public function setUp()
{
parent::setUp();
$_POST = $_GET = $_SERVER = $_REQUEST = $_ENV = $_COOKIE = $_SESSION = [];
$origin = 'http://www.example.com/index.php/woot?code=good#pos';
$this->request = new IncomingRequest(new App(), new URI($origin), null, new UserAgent());
}
//--------------------------------------------------------------------
public function testPathDefault()
{
$this->request->uri = '/index.php/woot?code=good#pos';
$_SERVER['REQUEST_URI'] = '/index.php/woot';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$expected = 'woot';
$this->assertEquals($expected, $this->request->detectPath());
}
public function testPathRequestURI()
{
$this->request->uri = '/index.php/woot?code=good#pos';
$_SERVER['REQUEST_URI'] = '/index.php/woot';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$expected = 'woot';
$this->assertEquals($expected, $this->request->detectPath('REQUEST_URI'));
}
public function testPathRequestURINested()
{
$this->request->uri = '/ci/index.php/woot?code=good#pos';
$_SERVER['REQUEST_URI'] = '/index.php/woot';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$expected = 'woot';
$this->assertEquals($expected, $this->request->detectPath('REQUEST_URI'));
}
public function testPathRequestURISubfolder()
{
$this->request->uri = '/ci/index.php/popcorn/woot?code=good#pos';
$_SERVER['REQUEST_URI'] = '/ci/index.php/popcorn/woot';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$expected = 'popcorn/woot';
$this->assertEquals($expected, $this->request->detectPath('REQUEST_URI'));
}
public function testPathRequestURINginx()
{
$this->request->uri = '/ci/index.php/woot?code=good#pos';
$_SERVER['REQUEST_URI'] = '/index.php/woot?code=good';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$expected = 'woot';
$this->assertEquals($expected, $this->request->detectPath('REQUEST_URI'));
}
public function testPathRequestURINginxRedirecting()
{
$this->request->uri = '/?/ci/index.php/woot';
$_SERVER['REQUEST_URI'] = '/?/ci/woot';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$expected = 'ci/woot';
$this->assertEquals($expected, $this->request->detectPath('REQUEST_URI'));
}
public function testPathRequestURISuppressed()
{
$this->request->uri = '/woot?code=good#pos';
$_SERVER['REQUEST_URI'] = '/woot';
$_SERVER['SCRIPT_NAME'] = '/';
$expected = 'woot';
$this->assertEquals($expected, $this->request->detectPath('REQUEST_URI'));
}
//--------------------------------------------------------------------
public function testPathQueryString()
{
$this->request->uri = '/?/ci/index.php/woot';
$_SERVER['REQUEST_URI'] = '/?/ci/woot';
$_SERVER['QUERY_STRING'] = '/ci/woot';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$expected = 'ci/woot';
$this->assertEquals($expected, $this->request->detectPath('QUERY_STRING'));
}
public function testPathQueryStringEmpty()
{
$this->request->uri = '/?/ci/index.php/woot';
$_SERVER['REQUEST_URI'] = '/?/ci/woot';
$_SERVER['QUERY_STRING'] = '';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$expected = '';
$this->assertEquals($expected, $this->request->detectPath('QUERY_STRING'));
}
//--------------------------------------------------------------------
public function testPathPathInfo()
{
$this->request->uri = '/index.php/woot?code=good#pos';
$this->request->setGlobal('server', [
'PATH_INFO' => null,
]);
$_SERVER['REQUEST_URI'] = '/index.php/woot';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$expected = 'woot';
$this->assertEquals($expected, $this->request->detectPath('PATH_INFO'));
}
public function testPathPathInfoGlobal()
{
$this->request->uri = '/index.php/woot?code=good#pos';
$this->request->uri = '/index.php/woot?code=good#pos';
$this->request->setGlobal('server', [
'PATH_INFO' => 'silliness',
]);
$_SERVER['REQUEST_URI'] = '/index.php/woot';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$expected = 'silliness';
$this->assertEquals($expected, $this->request->detectPath('PATH_INFO'));
}
}

View File

@ -1,12 +1,16 @@
<?php namespace CodeIgniter\HTTP;
<?php
namespace CodeIgniter\HTTP;
use Config\App;
use CodeIgniter\HTTP\Files\UploadedFile;
/**
* @backupGlobals enabled
*/
class IncomingRequestTest extends \CIUnitTestCase
{
/**
* @var \CodeIgniter\HTTP\IncomingRequest
*/
@ -31,8 +35,6 @@ class IncomingRequestTest extends \CIUnitTestCase
$this->assertNull($this->request->getVar('TESTY'));
}
//--------------------------------------------------------------------
public function testCanGrabGetVars()
{
$_GET['TEST'] = 5;
@ -41,8 +43,6 @@ class IncomingRequestTest extends \CIUnitTestCase
$this->assertNull($this->request->getGEt('TESTY'));
}
//--------------------------------------------------------------------
public function testCanGrabPostVars()
{
$_POST['TEST'] = 5;
@ -51,8 +51,6 @@ class IncomingRequestTest extends \CIUnitTestCase
$this->assertNull($this->request->getPost('TESTY'));
}
//--------------------------------------------------------------------
public function testCanGrabPostBeforeGet()
{
$_POST['TEST'] = 5;
@ -64,20 +62,29 @@ class IncomingRequestTest extends \CIUnitTestCase
//--------------------------------------------------------------------
/**
* @group single
*/
public function testCanGetOldInput()
{
$_SESSION['_ci_old_input'] = [
'get' => ['one' => 'two'],
'post' => ['name' => 'foo']
];
public function testCanGetOldInput()
{
$_SESSION['_ci_old_input'] = [
'get' => ['one' => 'two'],
'post' => ['name' => 'foo']
];
$this->assertEquals('foo', $this->request->getOldInput('name'));
$this->assertEquals('two', $this->request->getOldInput('one'));
}
$this->assertEquals('foo', $this->request->getOldInput('name'));
$this->assertEquals('two', $this->request->getOldInput('one'));
}
public function testCanGetOldInputDotted()
{
$_SESSION['_ci_old_input'] = [
'get' => ['apple' => ['name' => 'two']],
'post' => ['banana' => ['name' => 'foo']],
];
$this->assertEquals('foo', $this->request->getOldInput('banana.name'));
$this->assertEquals('two', $this->request->getOldInput('apple.name'));
}
//--------------------------------------------------------------------
public function testCanGrabServerVars()
{
@ -89,8 +96,6 @@ class IncomingRequestTest extends \CIUnitTestCase
$this->assertNull($this->request->getServer('TESTY'));
}
//--------------------------------------------------------------------
public function testCanGrabEnvVars()
{
$server = $this->getPrivateProperty($this->request, 'globals');
@ -101,8 +106,6 @@ class IncomingRequestTest extends \CIUnitTestCase
$this->assertNull($this->request->getEnv('TESTY'));
}
//--------------------------------------------------------------------
public function testCanGrabCookieVars()
{
$_COOKIE['TEST'] = 5;
@ -111,7 +114,7 @@ class IncomingRequestTest extends \CIUnitTestCase
$this->assertNull($this->request->getCookie('TESTY'));
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
public function testStoresDefaultLocale()
{
@ -121,8 +124,6 @@ class IncomingRequestTest extends \CIUnitTestCase
$this->assertEquals($config->defaultLocale, $this->request->getLocale());
}
//--------------------------------------------------------------------
public function testSetLocaleSaves()
{
$config = new App();
@ -136,6 +137,19 @@ class IncomingRequestTest extends \CIUnitTestCase
$this->assertEquals('en', $request->getLocale());
}
public function testSetBadLocale()
{
$config = new App();
$config->supportedLocales = ['en', 'es'];
$config->defaultLocale = 'es';
$config->baseURL = 'http://example.com';
$request = new IncomingRequest($config, new URI(), null, new UserAgent());
$request->setLocale('xx');
$this->assertEquals('es', $request->getLocale());
}
//--------------------------------------------------------------------
public function testNegotiatesLocale()
@ -153,6 +167,44 @@ class IncomingRequestTest extends \CIUnitTestCase
$this->assertEquals('es', $request->getLocale());
}
// The negotiation tests below are not intended to exercise the HTTP\Negotiate class -
// that is up to the NegotiateTest. These are only to make sure that the requests
// flow through to the negotiator
public function testNegotiatesNot()
{
$this->request->setHeader('Accept-Charset', 'iso-8859-5, unicode-1-1;q=0.8');
$this->expectException(Exceptions\HTTPException::class);
$this->request->negotiate('something bogus', ['iso-8859-5', 'unicode-1-1']);
}
public function testNegotiatesCharset()
{
// $_SERVER['HTTP_ACCEPT_CHARSET'] = 'iso-8859-5, unicode-1-1;q=0.8';
$this->request->setHeader('Accept-Charset', 'iso-8859-5, unicode-1-1;q=0.8');
$this->assertEquals(strtolower($this->request->config->charset), $this->request->negotiate('charset', ['iso-8859', 'unicode-1-2']));
}
public function testNegotiatesMedia()
{
$this->request->setHeader('Accept', 'text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c');
$this->assertEquals('text/html', $this->request->negotiate('media', ['text/html', 'text/x-c', 'text/x-dvi', 'text/plain']));
}
public function testNegotiatesEncoding()
{
$this->request->setHeader('Accept-Encoding', 'gzip;q=1.0, identity; q=0.4, compress;q=0.5');
$this->assertEquals('gzip', $this->request->negotiate('encoding', ['gzip', 'compress']));
}
public function testNegotiatesLanguage()
{
$this->request->setHeader('Accept-Language', 'da, en-gb;q=0.8, en;q=0.7');
$this->assertEquals('en', $this->request->negotiate('language', ['en', 'da']));
}
//--------------------------------------------------------------------
public function testCanGrabGetRawJSON()
@ -172,8 +224,6 @@ class IncomingRequestTest extends \CIUnitTestCase
$this->assertEquals($expected, $request->getJSON(true));
}
//--------------------------------------------------------------------
public function testCanGrabGetRawInput()
{
$rawstring = 'username=admin001&role=administrator&usepass=0';
@ -193,4 +243,73 @@ class IncomingRequestTest extends \CIUnitTestCase
}
//--------------------------------------------------------------------
public function testIsCLI()
{
// this should be the case in unit testing
$this->assertTrue($this->request->isCLI());
}
public function testIsAJAX()
{
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'xmlhttprequest';
$this->assertTrue($this->request->isAJAX());
}
//--------------------------------------------------------------------
public function testIsSecure()
{
$_SERVER['HTTPS'] = 'on';
$this->assertTrue($this->request->isSecure());
}
public function testIsSecureFrontEnd()
{
$_SERVER['HTTP_FRONT_END_HTTPS'] = 'on';
$this->assertTrue($this->request->isSecure());
}
public function testIsSecureForwarded()
{
$_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https';
$this->assertTrue($this->request->isSecure());
}
//--------------------------------------------------------------------
public function testUserAgent()
{
$_SERVER['HTTP_USER_AGENT'] = 'Mozilla';
$config = new App();
$request = new IncomingRequest($config, new URI(), null, new UserAgent());
$this->assertEquals('Mozilla', $request->getUserAgent());
}
//--------------------------------------------------------------------
public function testFileCollectionFactory()
{
$_FILES = [
'userfile' => [
'name' => 'someFile.txt',
'type' => 'text/plain',
'size' => '124',
'tmp_name' => '/tmp/myTempFile.txt',
'error' => 0
]
];
$files = $this->request->getFiles();
$this->assertCount(1, $files);
$file = array_shift($files);
$this->assertInstanceOf(UploadedFile::class, $file);
$this->assertEquals('someFile.txt', $file->getName());
$this->assertEquals(124, $file->getSize());
}
//--------------------------------------------------------------------
}

View File

@ -1,9 +1,12 @@
<?php namespace CodeIgniter\HTTP;
<?php
namespace CodeIgniter\HTTP;
use Config\App;
class NegotiateTest extends \CIUnitTestCase
{
/**
* @var CodeIgniter\HTTP\Request
*/
@ -36,6 +39,7 @@ class NegotiateTest extends \CIUnitTestCase
public function testNegotiateMediaFindsHighestMatch()
{
$this->request->setHeader('Accept', 'text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c');
$this->negotiate->setRequest($this->request);
$this->assertEquals('text/html', $this->negotiate->media(['text/html', 'text/x-c', 'text/x-dvi', 'text/plain']));
$this->assertEquals('text/x-c', $this->negotiate->media(['text/x-c', 'text/x-dvi', 'text/plain']));
@ -50,7 +54,7 @@ class NegotiateTest extends \CIUnitTestCase
public function testParseHeaderDeterminesCorrectPrecedence()
{
$header =$this->negotiate->parseHeader('text/*, text/plain, text/plain;format=flowed, */*');
$header = $this->negotiate->parseHeader('text/*, text/plain, text/plain;format=flowed, */*');
$this->assertEquals('text/plain', $header[0]['value']);
$this->assertEquals('flowed', $header[0]['params']['format']);
@ -134,4 +138,36 @@ class NegotiateTest extends \CIUnitTestCase
}
//--------------------------------------------------------------------
public function testBestMatchEmpty()
{
$this->expectException(Exceptions\HTTPException::class);
$this->negotiate->media([]);
}
public function testBestMatchNoHeader()
{
$this->request->setHeader('Accept','');
$this->assertEquals('', $this->negotiate->media(['apple', 'banana'], true));
$this->assertEquals('apple/mac', $this->negotiate->media(['apple/mac', 'banana/yellow'], false));
}
public function testBestMatchNotAcceptable()
{
$this->request->setHeader('Accept','popcorn/cheddar');
$this->assertEquals('apple/mac', $this->negotiate->media(['apple/mac', 'banana/yellow'],false));
}
public function testBestMatchFirstSupported()
{
$this->request->setHeader('Accept','popcorn/cheddar, */*');
$this->assertEquals('apple/mac', $this->negotiate->media(['apple/mac', 'banana/yellow'],false));
}
public function testBestMatchLowQuality()
{
$this->request->setHeader('Accept','popcorn/cheddar;q=0, apple/mac, */*');
$this->assertEquals('apple/mac', $this->negotiate->media(['apple/mac', 'popcorn/cheddar'],false));
$this->assertEquals('apple/mac', $this->negotiate->media(['popcorn/cheddar','apple/mac'],false));
}
}