/tests/control/DirectorTest.php
PHP | 611 lines | 440 code | 120 blank | 51 comment | 7 complexity | 1de82612d7c60b3eb03ed584665c9fc7 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT, CC-BY-3.0, GPL-2.0, AGPL-1.0, LGPL-2.1
- <?php
- use SilverStripe\ORM\DataModel;
- /**
- * @package framework
- * @subpackage tests
- *
- * @todo test Director::alternateBaseFolder()
- */
- class DirectorTest extends SapphireTest {
- protected static $originalRequestURI;
- protected $originalProtocolHeaders = array();
- protected $originalGet = array();
- protected $originalSession = array();
- public function setUp() {
- parent::setUp();
- // Hold the original request URI once so it doesn't get overwritten
- if(!self::$originalRequestURI) {
- self::$originalRequestURI = $_SERVER['REQUEST_URI'];
- }
- $_SERVER['REQUEST_URI'] = 'http://www.mysite.com';
- $this->originalGet = $_GET;
- $this->originalSession = $_SESSION;
- $_SESSION = array();
- Config::inst()->update('Director', 'rules', array(
- 'DirectorTestRule/$Action/$ID/$OtherID' => 'DirectorTestRequest_Controller',
- 'en-nz/$Action/$ID/$OtherID' => array(
- 'Controller' => 'DirectorTestRequest_Controller',
- 'Locale' => 'en_NZ'
- )
- ));
- $headers = array(
- 'HTTP_X_FORWARDED_PROTOCOL', 'HTTPS', 'SSL'
- );
- foreach($headers as $header) {
- if(isset($_SERVER[$header])) {
- $this->originalProtocolHeaders[$header] = $_SERVER[$header];
- }
- }
- }
- public function tearDown() {
- // TODO Remove director rule, currently API doesnt allow this
- $_GET = $this->originalGet;
- $_SESSION = $this->originalSession;
- // Reinstate the original REQUEST_URI after it was modified by some tests
- $_SERVER['REQUEST_URI'] = self::$originalRequestURI;
- if($this->originalProtocolHeaders) {
- foreach($this->originalProtocolHeaders as $header => $value) {
- $_SERVER[$header] = $value;
- }
- }
- parent::tearDown();
- }
- public function testFileExists() {
- $tempFileName = 'DirectorTest_testFileExists.tmp';
- $tempFilePath = TEMP_FOLDER . '/' . $tempFileName;
- // create temp file
- file_put_contents($tempFilePath, '');
- $this->assertTrue(
- Director::fileExists($tempFilePath),
- 'File exist check with absolute path'
- );
- $this->assertTrue(
- Director::fileExists($tempFilePath . '?queryparams=1&foo[bar]=bar'),
- 'File exist check with query params ignored'
- );
- unlink($tempFilePath);
- }
- public function testAbsoluteURL() {
- $rootURL = Director::protocolAndHost();
- $_SERVER['REQUEST_URI'] = "$rootURL/mysite/sub-page/";
- Config::inst()->update('Director', 'alternate_base_url', '/mysite/');
- //test empty / local urls
- foreach(array('', './', '.') as $url) {
- $this->assertEquals("$rootURL/mysite/", Director::absoluteURL($url, Director::BASE));
- $this->assertEquals("$rootURL/", Director::absoluteURL($url, Director::ROOT));
- $this->assertEquals("$rootURL/mysite/sub-page/", Director::absoluteURL($url, Director::REQUEST));
- }
- // Test site root url
- $this->assertEquals("$rootURL/", Director::absoluteURL('/'));
- // Test Director::BASE
- $this->assertEquals($rootURL, Director::absoluteURL($rootURL, Director::BASE));
- $this->assertEquals('http://www.mytest.com', Director::absoluteURL('http://www.mytest.com', Director::BASE));
- $this->assertEquals("$rootURL/test", Director::absoluteURL("$rootURL/test", Director::BASE));
- $this->assertEquals("$rootURL/root", Director::absoluteURL("/root", Director::BASE));
- $this->assertEquals("$rootURL/root/url", Director::absoluteURL("/root/url", Director::BASE));
- // Test Director::ROOT
- $this->assertEquals($rootURL, Director::absoluteURL($rootURL, Director::ROOT));
- $this->assertEquals('http://www.mytest.com', Director::absoluteURL('http://www.mytest.com', Director::ROOT));
- $this->assertEquals("$rootURL/test", Director::absoluteURL("$rootURL/test", Director::ROOT));
- $this->assertEquals("$rootURL/root", Director::absoluteURL("/root", Director::ROOT));
- $this->assertEquals("$rootURL/root/url", Director::absoluteURL("/root/url", Director::ROOT));
- // Test Director::REQUEST
- $this->assertEquals($rootURL, Director::absoluteURL($rootURL, Director::REQUEST));
- $this->assertEquals('http://www.mytest.com', Director::absoluteURL('http://www.mytest.com', Director::REQUEST));
- $this->assertEquals("$rootURL/test", Director::absoluteURL("$rootURL/test", Director::REQUEST));
- $this->assertEquals("$rootURL/root", Director::absoluteURL("/root", Director::REQUEST));
- $this->assertEquals("$rootURL/root/url", Director::absoluteURL("/root/url", Director::REQUEST));
- // Test evaluating relative urls relative to base (default)
- $this->assertEquals("$rootURL/mysite/test", Director::absoluteURL("test"));
- $this->assertEquals("$rootURL/mysite/test/url", Director::absoluteURL("test/url"));
- $this->assertEquals("$rootURL/mysite/test", Director::absoluteURL("test", Director::BASE));
- $this->assertEquals("$rootURL/mysite/test/url", Director::absoluteURL("test/url", Director::BASE));
- // Test evaluting relative urls relative to root
- $this->assertEquals("$rootURL/test", Director::absoluteURL("test", Director::ROOT));
- $this->assertEquals("$rootURL/test/url", Director::absoluteURL("test/url", Director::ROOT));
- // Test relative to requested page
- $this->assertEquals("$rootURL/mysite/sub-page/test", Director::absoluteURL("test", Director::REQUEST));
- $this->assertEquals("$rootURL/mysite/sub-page/test/url", Director::absoluteURL("test/url", Director::REQUEST));
- // Test that javascript links are not left intact
- $this->assertStringStartsNotWith('javascript', Director::absoluteURL('javascript:alert("attack")'));
- $this->assertStringStartsNotWith('alert', Director::absoluteURL('javascript:alert("attack")'));
- $this->assertStringStartsNotWith('javascript', Director::absoluteURL('alert("attack")'));
- $this->assertStringStartsNotWith('alert', Director::absoluteURL('alert("attack")'));
- }
- public function testAlternativeBaseURL() {
- // Get original protocol and hostname
- $rootURL = Director::protocolAndHost();
- // relative base URLs - you should end them in a /
- Config::inst()->update('Director', 'alternate_base_url', '/relativebase/');
- $_SERVER['REQUEST_URI'] = "$rootURL/relativebase/sub-page/";
- $this->assertEquals('/relativebase/', Director::baseURL());
- $this->assertEquals($rootURL . '/relativebase/', Director::absoluteBaseURL());
- $this->assertEquals(
- $rootURL . '/relativebase/subfolder/test',
- Director::absoluteURL('subfolder/test')
- );
- // absolute base URLs - you should end them in a /
- Config::inst()->update('Director', 'alternate_base_url', 'http://www.example.org/');
- $_SERVER['REQUEST_URI'] = "http://www.example.org/sub-page/";
- $this->assertEquals('http://www.example.org/', Director::baseURL());
- $this->assertEquals('http://www.example.org/', Director::absoluteBaseURL());
- $this->assertEquals('http://www.example.org/sub-page/', Director::absoluteURL('', Director::REQUEST));
- $this->assertEquals('http://www.example.org/', Director::absoluteURL('', Director::BASE));
- $this->assertEquals('http://www.example.org/', Director::absoluteURL('', Director::ROOT));
- $this->assertEquals(
- 'http://www.example.org/sub-page/subfolder/test',
- Director::absoluteURL('subfolder/test', Director::REQUEST)
- );
- $this->assertEquals(
- 'http://www.example.org/subfolder/test',
- Director::absoluteURL('subfolder/test', Director::ROOT)
- );
- $this->assertEquals(
- 'http://www.example.org/subfolder/test',
- Director::absoluteURL('subfolder/test', Director::BASE)
- );
- // Setting it to false restores functionality
- Config::inst()->update('Director', 'alternate_base_url', false);
- $_SERVER['REQUEST_URI'] = $rootURL;
- $this->assertEquals(BASE_URL.'/', Director::baseURL());
- $this->assertEquals($rootURL.BASE_URL.'/', Director::absoluteBaseURL(BASE_URL));
- $this->assertEquals(
- $rootURL.BASE_URL . '/subfolder/test',
- Director::absoluteURL('subfolder/test')
- );
- }
- /**
- * Tests that {@link Director::is_absolute()} works under different environment types
- */
- public function testIsAbsolute() {
- $expected = array (
- 'C:/something' => true,
- 'd:\\' => true,
- 'e/' => false,
- 's:/directory' => true,
- '/var/www' => true,
- '\\Something' => true,
- 'something/c:' => false,
- 'folder' => false,
- 'a/c:/' => false
- );
- foreach($expected as $path => $result) {
- $this->assertEquals(Director::is_absolute($path), $result, "Test result for $path");
- }
- }
- public function testIsAbsoluteUrl() {
- $this->assertTrue(Director::is_absolute_url('http://test.com/testpage'));
- $this->assertTrue(Director::is_absolute_url('ftp://test.com'));
- $this->assertFalse(Director::is_absolute_url('test.com/testpage'));
- $this->assertFalse(Director::is_absolute_url('/relative'));
- $this->assertFalse(Director::is_absolute_url('relative'));
- $this->assertFalse(Director::is_absolute_url("/relative/?url=http://foo.com"));
- $this->assertFalse(Director::is_absolute_url("/relative/#http://foo.com"));
- $this->assertTrue(Director::is_absolute_url("https://test.com/?url=http://foo.com"));
- $this->assertTrue(Director::is_absolute_url("trickparseurl:http://test.com"));
- $this->assertTrue(Director::is_absolute_url('//test.com'));
- $this->assertTrue(Director::is_absolute_url('/////test.com'));
- $this->assertTrue(Director::is_absolute_url(' ///test.com'));
- $this->assertTrue(Director::is_absolute_url('http:test.com'));
- $this->assertTrue(Director::is_absolute_url('//http://test.com'));
- }
- public function testIsRelativeUrl() {
- $siteUrl = Director::absoluteBaseURL();
- $this->assertFalse(Director::is_relative_url('http://test.com'));
- $this->assertFalse(Director::is_relative_url('https://test.com'));
- $this->assertFalse(Director::is_relative_url(' https://test.com/testpage '));
- $this->assertTrue(Director::is_relative_url('test.com/testpage'));
- $this->assertFalse(Director::is_relative_url('ftp://test.com'));
- $this->assertTrue(Director::is_relative_url('/relative'));
- $this->assertTrue(Director::is_relative_url('relative'));
- $this->assertTrue(Director::is_relative_url('/relative/?url=http://test.com'));
- $this->assertTrue(Director::is_relative_url('/relative/#=http://test.com'));
- }
- public function testMakeRelative() {
- $siteUrl = Director::absoluteBaseURL();
- $siteUrlNoProtocol = preg_replace('/https?:\/\//', '', $siteUrl);
- $this->assertEquals(Director::makeRelative("$siteUrl"), '');
- $this->assertEquals(Director::makeRelative("https://$siteUrlNoProtocol"), '');
- $this->assertEquals(Director::makeRelative("http://$siteUrlNoProtocol"), '');
- $this->assertEquals(Director::makeRelative(" $siteUrl/testpage "), 'testpage');
- $this->assertEquals(Director::makeRelative("$siteUrlNoProtocol/testpage"), 'testpage');
- $this->assertEquals(Director::makeRelative('ftp://test.com'), 'ftp://test.com');
- $this->assertEquals(Director::makeRelative('http://test.com'), 'http://test.com');
- $this->assertEquals(Director::makeRelative('relative'), 'relative');
- $this->assertEquals(Director::makeRelative("$siteUrl/?url=http://test.com"), '?url=http://test.com');
- $this->assertEquals("test", Director::makeRelative("https://".$siteUrlNoProtocol."/test"));
- $this->assertEquals("test", Director::makeRelative("http://".$siteUrlNoProtocol."/test"));
- }
- /**
- * Mostly tested by {@link testIsRelativeUrl()},
- * just adding the host name matching aspect here.
- */
- public function testIsSiteUrl() {
- $this->assertFalse(Director::is_site_url("http://test.com"));
- $this->assertTrue(Director::is_site_url(Director::absoluteBaseURL()));
- $this->assertFalse(Director::is_site_url("http://test.com?url=" . Director::absoluteBaseURL()));
- $this->assertFalse(Director::is_site_url("http://test.com?url=" . urlencode(Director::absoluteBaseURL())));
- $this->assertFalse(Director::is_site_url("//test.com?url=" . Director::absoluteBaseURL()));
- }
- /**
- * Tests isDev, isTest, isLive set from querystring
- */
- public function testQueryIsEnvironment() {
- // Reset
- unset($_SESSION['isDev']);
- unset($_SESSION['isLive']);
- unset($_GET['isTest']);
- unset($_GET['isDev']);
- $_SESSION = $_SESSION ?: array();
- // Test isDev=1
- $_GET['isDev'] = '1';
- $this->assertTrue(Director::isDev());
- $this->assertFalse(Director::isTest());
- $this->assertFalse(Director::isLive());
- // Test persistence
- unset($_GET['isDev']);
- $this->assertTrue(Director::isDev());
- $this->assertFalse(Director::isTest());
- $this->assertFalse(Director::isLive());
- // Test change to isTest
- $_GET['isTest'] = '1';
- $this->assertFalse(Director::isDev());
- $this->assertTrue(Director::isTest());
- $this->assertFalse(Director::isLive());
- // Test persistence
- unset($_GET['isTest']);
- $this->assertFalse(Director::isDev());
- $this->assertTrue(Director::isTest());
- $this->assertFalse(Director::isLive());
- }
- public function testResetGlobalsAfterTestRequest() {
- $_GET = array('somekey' => 'getvalue');
- $_POST = array('somekey' => 'postvalue');
- $_COOKIE = array('somekey' => 'cookievalue');
- $cookies = Injector::inst()->createWithArgs(
- 'Cookie_Backend',
- array(array('somekey' => 'sometestcookievalue'))
- );
- $getresponse = Director::test('errorpage?somekey=sometestgetvalue', array('somekey' => 'sometestpostvalue'),
- null, null, null, null, $cookies);
- $this->assertEquals('getvalue', $_GET['somekey'],
- '$_GET reset to original value after Director::test()');
- $this->assertEquals('postvalue', $_POST['somekey'],
- '$_POST reset to original value after Director::test()');
- $this->assertEquals('cookievalue', $_COOKIE['somekey'],
- '$_COOKIE reset to original value after Director::test()');
- }
- public function testTestRequestCarriesGlobals() {
- $fixture = array('somekey' => 'sometestvalue');
- foreach(array('get', 'post') as $method) {
- foreach(array('return%sValue', 'returnRequestValue', 'returnCookieValue') as $testfunction) {
- $url = 'DirectorTestRequest_Controller/' . sprintf($testfunction, ucfirst($method))
- . '?' . http_build_query($fixture);
- $getresponse = Director::test(
- $url,
- $fixture,
- null,
- strtoupper($method),
- null,
- null,
- Injector::inst()->createWithArgs('Cookie_Backend', array($fixture))
- );
- $this->assertInstanceOf('SS_HTTPResponse', $getresponse, 'Director::test() returns SS_HTTPResponse');
- $this->assertEquals($fixture['somekey'], $getresponse->getBody(), 'Director::test() ' . $testfunction);
- }
- }
- }
- /**
- * Tests that additional parameters specified in the routing table are
- * saved in the request
- */
- public function testRouteParams() {
- Director::test('en-nz/myaction/myid/myotherid', null, null, null, null, null, null, $request);
- $this->assertEquals(
- array(
- 'Controller' => 'DirectorTestRequest_Controller',
- 'Action' => 'myaction',
- 'ID' => 'myid',
- 'OtherID' => 'myotherid',
- 'Locale' => 'en_NZ'
- ),
- $request->params()
- );
- }
- public function testForceSSLProtectsEntireSite() {
- $_SERVER['REQUEST_URI'] = Director::baseURL() . 'admin';
- $output = Director::forceSSL();
- $this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
- $_SERVER['REQUEST_URI'] = Director::baseURL() . 'some-url';
- $output = Director::forceSSL();
- $this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
- }
- public function testForceSSLOnTopLevelPagePattern() {
- $_SERVER['REQUEST_URI'] = Director::baseURL() . 'admin';
- $output = Director::forceSSL(array('/^admin/'));
- $this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
- }
- public function testForceSSLOnSubPagesPattern() {
- $_SERVER['REQUEST_URI'] = Director::baseURL() . Config::inst()->get('SilverStripe\\Security\\Security', 'login_url');
- $output = Director::forceSSL(array('/^Security/'));
- $this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
- }
- public function testForceSSLWithPatternDoesNotMatchOtherPages() {
- $_SERVER['REQUEST_URI'] = Director::baseURL() . 'normal-page';
- $output = Director::forceSSL(array('/^admin/'));
- $this->assertFalse($output);
- $_SERVER['REQUEST_URI'] = Director::baseURL() . 'just-another-page/sub-url';
- $output = Director::forceSSL(array('/^admin/', '/^Security/'));
- $this->assertFalse($output);
- }
- public function testForceSSLAlternateDomain() {
- Config::inst()->update('Director', 'alternate_base_url', '/');
- $_SERVER['REQUEST_URI'] = Director::baseURL() . 'admin';
- $output = Director::forceSSL(array('/^admin/'), 'secure.mysite.com');
- $this->assertEquals($output, 'https://secure.mysite.com/admin');
- }
- /**
- * @covers Director::extract_request_headers()
- */
- public function testExtractRequestHeaders() {
- $request = array(
- 'REDIRECT_STATUS' => '200',
- 'HTTP_HOST' => 'host',
- 'HTTP_USER_AGENT' => 'User Agent',
- 'HTTP_ACCEPT' => 'text/html',
- 'HTTP_ACCEPT_LANGUAGE' => 'en-us',
- 'HTTP_COOKIE' => 'MyCookie=1',
- 'SERVER_PROTOCOL' => 'HTTP/1.1',
- 'REQUEST_METHOD' => 'GET',
- 'REQUEST_URI' => '/',
- 'SCRIPT_NAME' => FRAMEWORK_DIR . '/main.php',
- 'CONTENT_TYPE' => 'text/xml',
- 'CONTENT_LENGTH' => 10
- );
- $headers = array(
- 'Host' => 'host',
- 'User-Agent' => 'User Agent',
- 'Accept' => 'text/html',
- 'Accept-Language' => 'en-us',
- 'Cookie' => 'MyCookie=1',
- 'Content-Type' => 'text/xml',
- 'Content-Length' => '10'
- );
- $this->assertEquals($headers, Director::extract_request_headers($request));
- }
- public function testUnmatchedRequestReturns404() {
- $this->assertEquals(404, Director::test('no-route')->getStatusCode());
- }
- public function testIsHttps() {
- if(!TRUSTED_PROXY) {
- $this->markTestSkipped('Test cannot be run without trusted proxy');
- }
- // nothing available
- $headers = array(
- 'HTTP_X_FORWARDED_PROTOCOL', 'HTTPS', 'SSL'
- );
- $origServer = $_SERVER;
- foreach($headers as $header) {
- if(isset($_SERVER[$header])) {
- unset($_SERVER['HTTP_X_FORWARDED_PROTOCOL']);
- }
- }
- $this->assertFalse(Director::is_https());
- $_SERVER['HTTP_X_FORWARDED_PROTOCOL'] = 'https';
- $this->assertTrue(Director::is_https());
- $_SERVER['HTTP_X_FORWARDED_PROTOCOL'] = 'http';
- $this->assertFalse(Director::is_https());
- $_SERVER['HTTP_X_FORWARDED_PROTOCOL'] = 'ftp';
- $this->assertFalse(Director::is_https());
- $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https';
- $this->assertTrue(Director::is_https());
- $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'http';
- $this->assertFalse(Director::is_https());
- $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'ftp';
- $this->assertFalse(Director::is_https());
- $_SERVER['HTTP_FRONT_END_HTTPS'] = 'On';
- $this->assertTrue(Director::is_https());
- $_SERVER['HTTP_FRONT_END_HTTPS'] = 'Off';
- $this->assertFalse(Director::is_https());
- // https via HTTPS
- $_SERVER['HTTPS'] = 'true';
- $this->assertTrue(Director::is_https());
- $_SERVER['HTTPS'] = '1';
- $this->assertTrue(Director::is_https());
- $_SERVER['HTTPS'] = 'off';
- $this->assertFalse(Director::is_https());
- // https via SSL
- $_SERVER['SSL'] = '';
- $this->assertTrue(Director::is_https());
- $_SERVER = $origServer;
- }
- public function testTestIgnoresHashes() {
- //test that hashes are ignored
- $url = "DirectorTestRequest_Controller/returnGetValue?somekey=key";
- $hash = "#test";
- $response = Director::test($url . $hash, null, null, null, null, null, null, $request);
- $this->assertFalse($response->isError());
- $this->assertEquals('key', $response->getBody());
- $this->assertEquals($request->getURL(true), $url);
- //test encoded hashes are accepted
- $url = "DirectorTestRequest_Controller/returnGetValue?somekey=test%23key";
- $response = Director::test($url, null, null, null, null, null, null, $request);
- $this->assertFalse($response->isError());
- $this->assertEquals('test#key', $response->getBody());
- $this->assertEquals($request->getURL(true), $url);
- }
- public function testRequestFilterInDirectorTest() {
- $filter = new TestRequestFilter;
- $processor = new RequestProcessor(array($filter));
- Injector::inst()->registerService($processor, 'RequestProcessor');
- $response = Director::test('some-dummy-url');
- $this->assertEquals(1, $filter->preCalls);
- $this->assertEquals(1, $filter->postCalls);
- $filter->failPost = true;
- $this->setExpectedException('SS_HTTPResponse_Exception');
- $response = Director::test('some-dummy-url');
- $this->assertEquals(2, $filter->preCalls);
- $this->assertEquals(2, $filter->postCalls);
- $filter->failPre = true;
- $response = Director::test('some-dummy-url');
- $this->assertEquals(3, $filter->preCalls);
- // preCall 'false' will trigger an exception and prevent post call execution
- $this->assertEquals(2, $filter->postCalls);
- }
- }
- class TestRequestFilter implements RequestFilter, TestOnly {
- public $preCalls = 0;
- public $postCalls = 0;
- public $failPre = false;
- public $failPost = false;
- public function preRequest(\SS_HTTPRequest $request, \Session $session, DataModel $model) {
- ++$this->preCalls;
- if ($this->failPre) {
- return false;
- }
- }
- public function postRequest(\SS_HTTPRequest $request, \SS_HTTPResponse $response, DataModel $model) {
- ++$this->postCalls;
- if ($this->failPost) {
- return false;
- }
- }
- public function reset() {
- $this->preCalls = 0;
- $this->postCalls = 0;
- }
- }
- class DirectorTestRequest_Controller extends Controller implements TestOnly {
- private static $allowed_actions = array(
- 'returnGetValue',
- 'returnPostValue',
- 'returnRequestValue',
- 'returnCookieValue',
- );
- public function returnGetValue($request) { return $_GET['somekey']; }
- public function returnPostValue($request) { return $_POST['somekey']; }
- public function returnRequestValue($request) { return $_REQUEST['somekey']; }
- public function returnCookieValue($request) { return $_COOKIE['somekey']; }
- }