Completed
Push — director-middleware ( cc340c...f3cb14 )
by Sam
08:20
created

DirectorTest::testAlternativeBaseURL()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 56
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 41
nc 1
nop 0
dl 0
loc 56
rs 9.7251
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace SilverStripe\Control\Tests;
3
4
use SilverStripe\Control\Cookie_Backend;
5
use SilverStripe\Control\Director;
6
use SilverStripe\Control\HTTPRequest;
7
use SilverStripe\Control\HTTPRequestBuilder;
8
use SilverStripe\Control\HTTPResponse;
9
use SilverStripe\Control\HTTPResponse_Exception;
10
use SilverStripe\Control\RequestProcessor;
11
use SilverStripe\Control\Tests\DirectorTest\TestController;
12
use SilverStripe\Core\Injector\Injector;
13
use SilverStripe\Core\Kernel;
14
use SilverStripe\Dev\SapphireTest;
15
use SilverStripe\Core\Config\Config;
16
17
/**
18
 * @todo test Director::alternateBaseFolder()
19
 */
20
class DirectorTest extends SapphireTest
21
{
22
    protected static $extra_controllers = [
23
        TestController::class,
24
    ];
25
26
    protected function setUp()
27
    {
28
        parent::setUp();
29
        Director::config()->set('alternate_base_url', 'http://www.mysite.com/');
30
        $this->expectedRedirect = null;
31
    }
32
33
    protected function getExtraRoutes()
34
    {
35
        $rules = parent::getExtraRoutes();
36
37
        $rules['DirectorTestRule/$Action/$ID/$OtherID'] = TestController::class;
38
        $rules['en-nz/$Action/$ID/$OtherID'] = [
39
            'Controller' => TestController::class,
40
            'Locale' => 'en_NZ',
41
        ];
42
        return $rules;
43
    }
44
45
    protected function setUpRoutes()
46
    {
47
        // Don't merge with any existing rules
48
        Director::config()->set('rules', $this->getExtraRoutes());
49
    }
50
51
    public function testFileExists()
52
    {
53
        $tempFileName = 'DirectorTest_testFileExists.tmp';
54
        $tempFilePath = TEMP_FOLDER . '/' . $tempFileName;
55
56
        // create temp file
57
        file_put_contents($tempFilePath, '');
58
59
        $this->assertTrue(
60
            Director::fileExists($tempFilePath),
61
            'File exist check with absolute path'
62
        );
63
64
        $this->assertTrue(
65
            Director::fileExists($tempFilePath . '?queryparams=1&foo[bar]=bar'),
66
            'File exist check with query params ignored'
67
        );
68
69
        unlink($tempFilePath);
70
    }
71
72
    public function testAbsoluteURL()
73
    {
74
        Director::config()->set('alternate_base_url', 'http://www.mysite.com/mysite/');
75
        $_SERVER['REQUEST_URI'] = "http://www.mysite.com/mysite/sub-page/";
76
77
        //test empty / local urls
78
        foreach (array('', './', '.') as $url) {
79
            $this->assertEquals("http://www.mysite.com/mysite/", Director::absoluteURL($url, Director::BASE));
80
            $this->assertEquals("http://www.mysite.com/", Director::absoluteURL($url, Director::ROOT));
81
            $this->assertEquals("http://www.mysite.com/mysite/sub-page/", Director::absoluteURL($url, Director::REQUEST));
82
        }
83
84
        // Test site root url
85
        $this->assertEquals("http://www.mysite.com/", Director::absoluteURL('/'));
86
87
        // Test Director::BASE
88
        $this->assertEquals('http://www.mysite.com/', Director::absoluteURL('http://www.mysite.com/', Director::BASE));
89
        $this->assertEquals('http://www.mytest.com', Director::absoluteURL('http://www.mytest.com', Director::BASE));
90
        $this->assertEquals("http://www.mysite.com/test", Director::absoluteURL("http://www.mysite.com/test", Director::BASE));
91
        $this->assertEquals("http://www.mysite.com/root", Director::absoluteURL("/root", Director::BASE));
92
        $this->assertEquals("http://www.mysite.com/root/url", Director::absoluteURL("/root/url", Director::BASE));
93
94
        // Test Director::ROOT
95
        $this->assertEquals('http://www.mysite.com/', Director::absoluteURL('http://www.mysite.com/', Director::ROOT));
96
        $this->assertEquals('http://www.mytest.com', Director::absoluteURL('http://www.mytest.com', Director::ROOT));
97
        $this->assertEquals("http://www.mysite.com/test", Director::absoluteURL("http://www.mysite.com/test", Director::ROOT));
98
        $this->assertEquals("http://www.mysite.com/root", Director::absoluteURL("/root", Director::ROOT));
99
        $this->assertEquals("http://www.mysite.com/root/url", Director::absoluteURL("/root/url", Director::ROOT));
100
101
        // Test Director::REQUEST
102
        $this->assertEquals('http://www.mysite.com/', Director::absoluteURL('http://www.mysite.com/', Director::REQUEST));
103
        $this->assertEquals('http://www.mytest.com', Director::absoluteURL('http://www.mytest.com', Director::REQUEST));
104
        $this->assertEquals("http://www.mysite.com/test", Director::absoluteURL("http://www.mysite.com/test", Director::REQUEST));
105
        $this->assertEquals("http://www.mysite.com/root", Director::absoluteURL("/root", Director::REQUEST));
106
        $this->assertEquals("http://www.mysite.com/root/url", Director::absoluteURL("/root/url", Director::REQUEST));
107
108
        // Test evaluating relative urls relative to base (default)
109
        $this->assertEquals("http://www.mysite.com/mysite/test", Director::absoluteURL("test"));
110
        $this->assertEquals("http://www.mysite.com/mysite/test/url", Director::absoluteURL("test/url"));
111
        $this->assertEquals("http://www.mysite.com/mysite/test", Director::absoluteURL("test", Director::BASE));
112
        $this->assertEquals("http://www.mysite.com/mysite/test/url", Director::absoluteURL("test/url", Director::BASE));
113
114
        // Test evaluting relative urls relative to root
115
        $this->assertEquals("http://www.mysite.com/test", Director::absoluteURL("test", Director::ROOT));
116
        $this->assertEquals("http://www.mysite.com/test/url", Director::absoluteURL("test/url", Director::ROOT));
117
118
        // Test relative to requested page
119
        $this->assertEquals("http://www.mysite.com/mysite/sub-page/test", Director::absoluteURL("test", Director::REQUEST));
120
        $this->assertEquals("http://www.mysite.com/mysite/sub-page/test/url", Director::absoluteURL("test/url", Director::REQUEST));
121
122
        // Test that javascript links are not left intact
123
        $this->assertStringStartsNotWith('javascript', Director::absoluteURL('javascript:alert("attack")'));
124
        $this->assertStringStartsNotWith('alert', Director::absoluteURL('javascript:alert("attack")'));
125
        $this->assertStringStartsNotWith('javascript', Director::absoluteURL('alert("attack")'));
126
        $this->assertStringStartsNotWith('alert', Director::absoluteURL('alert("attack")'));
127
    }
128
129
    public function testAlternativeBaseURL()
130
    {
131
        // relative base URLs - you should end them in a /
132
        Director::config()->set('alternate_base_url', '/relativebase/');
133
        $_SERVER['HTTP_HOST'] = 'www.somesite.com';
134
        $_SERVER['REQUEST_URI'] = "/relativebase/sub-page/";
135
136
        $this->assertEquals('/relativebase/', Director::baseURL());
137
        $this->assertEquals('http://www.somesite.com/relativebase/', Director::absoluteBaseURL());
138
        $this->assertEquals(
139
            'http://www.somesite.com/relativebase/subfolder/test',
140
            Director::absoluteURL('subfolder/test')
141
        );
142
143
        // absolute base URLS with subdirectory - You should end them in a /
144
        Director::config()->set('alternate_base_url', 'http://www.example.org/relativebase/');
145
        $_SERVER['REQUEST_URI'] = "http://www.example.org/relativebase/sub-page/";
146
        $this->assertEquals('/relativebase/', Director::baseURL()); // Non-absolute url
147
        $this->assertEquals('http://www.example.org/relativebase/', Director::absoluteBaseURL());
148
        $this->assertEquals('http://www.example.org/relativebase/sub-page/', Director::absoluteURL('', Director::REQUEST));
149
        $this->assertEquals('http://www.example.org/relativebase/', Director::absoluteURL('', Director::BASE));
150
        $this->assertEquals('http://www.example.org/', Director::absoluteURL('', Director::ROOT));
151
        $this->assertEquals(
152
            'http://www.example.org/relativebase/sub-page/subfolder/test',
153
            Director::absoluteURL('subfolder/test', Director::REQUEST)
154
        );
155
        $this->assertEquals(
156
            'http://www.example.org/subfolder/test',
157
            Director::absoluteURL('subfolder/test', Director::ROOT)
158
        );
159
        $this->assertEquals(
160
            'http://www.example.org/relativebase/subfolder/test',
161
            Director::absoluteURL('subfolder/test', Director::BASE)
162
        );
163
164
        // absolute base URLs - you should end them in a /
165
        Director::config()->set('alternate_base_url', 'http://www.example.org/');
166
        $_SERVER['REQUEST_URI'] = "http://www.example.org/sub-page/";
167
        $this->assertEquals('/', Director::baseURL()); // Non-absolute url
168
        $this->assertEquals('http://www.example.org/', Director::absoluteBaseURL());
169
        $this->assertEquals('http://www.example.org/sub-page/', Director::absoluteURL('', Director::REQUEST));
170
        $this->assertEquals('http://www.example.org/', Director::absoluteURL('', Director::BASE));
171
        $this->assertEquals('http://www.example.org/', Director::absoluteURL('', Director::ROOT));
172
        $this->assertEquals(
173
            'http://www.example.org/sub-page/subfolder/test',
174
            Director::absoluteURL('subfolder/test', Director::REQUEST)
175
        );
176
        $this->assertEquals(
177
            'http://www.example.org/subfolder/test',
178
            Director::absoluteURL('subfolder/test', Director::ROOT)
179
        );
180
        $this->assertEquals(
181
            'http://www.example.org/subfolder/test',
182
            Director::absoluteURL('subfolder/test', Director::BASE)
183
        );
184
    }
185
186
    /**
187
     * Tests that {@link Director::is_absolute()} works under different environment types
188
     */
189
    public function testIsAbsolute()
190
    {
191
        $expected = array (
192
            'C:/something' => true,
193
            'd:\\'         => true,
194
            'e/'           => false,
195
            's:/directory' => true,
196
            '/var/www'     => true,
197
            '\\Something'  => true,
198
            'something/c:' => false,
199
            'folder'       => false,
200
            'a/c:/'        => false
201
        );
202
203
        foreach ($expected as $path => $result) {
204
            $this->assertEquals(Director::is_absolute($path), $result, "Test result for $path");
205
        }
206
    }
207
208
    public function testIsAbsoluteUrl()
209
    {
210
        $this->assertTrue(Director::is_absolute_url('http://test.com/testpage'));
211
        $this->assertTrue(Director::is_absolute_url('ftp://test.com'));
212
        $this->assertFalse(Director::is_absolute_url('test.com/testpage'));
213
        $this->assertFalse(Director::is_absolute_url('/relative'));
214
        $this->assertFalse(Director::is_absolute_url('relative'));
215
        $this->assertFalse(Director::is_absolute_url("/relative/?url=http://foo.com"));
216
        $this->assertFalse(Director::is_absolute_url("/relative/#http://foo.com"));
217
        $this->assertTrue(Director::is_absolute_url("https://test.com/?url=http://foo.com"));
218
        $this->assertTrue(Director::is_absolute_url("trickparseurl:http://test.com"));
219
        $this->assertTrue(Director::is_absolute_url('//test.com'));
220
        $this->assertTrue(Director::is_absolute_url('/////test.com'));
221
        $this->assertTrue(Director::is_absolute_url('  ///test.com'));
222
        $this->assertTrue(Director::is_absolute_url('http:test.com'));
223
        $this->assertTrue(Director::is_absolute_url('//http://test.com'));
224
    }
225
226
    public function testIsRelativeUrl()
227
    {
228
        $this->assertFalse(Director::is_relative_url('http://test.com'));
229
        $this->assertFalse(Director::is_relative_url('https://test.com'));
230
        $this->assertFalse(Director::is_relative_url('   https://test.com/testpage   '));
231
        $this->assertTrue(Director::is_relative_url('test.com/testpage'));
232
        $this->assertFalse(Director::is_relative_url('ftp://test.com'));
233
        $this->assertTrue(Director::is_relative_url('/relative'));
234
        $this->assertTrue(Director::is_relative_url('relative'));
235
        $this->assertTrue(Director::is_relative_url('/relative/?url=http://test.com'));
236
        $this->assertTrue(Director::is_relative_url('/relative/#=http://test.com'));
237
    }
238
239
    public function testMakeRelative()
240
    {
241
        $siteUrl = Director::absoluteBaseURL();
242
        $siteUrlNoProtocol = preg_replace('/https?:\/\//', '', $siteUrl);
243
244
        $this->assertEquals(Director::makeRelative("$siteUrl"), '');
245
        $this->assertEquals(Director::makeRelative("https://$siteUrlNoProtocol"), '');
246
        $this->assertEquals(Director::makeRelative("http://$siteUrlNoProtocol"), '');
247
248
        $this->assertEquals(Director::makeRelative("   $siteUrl/testpage   "), 'testpage');
249
        $this->assertEquals(Director::makeRelative("$siteUrlNoProtocol/testpage"), 'testpage');
250
251
        $this->assertEquals(Director::makeRelative('ftp://test.com'), 'ftp://test.com');
252
        $this->assertEquals(Director::makeRelative('http://test.com'), 'http://test.com');
253
254
        $this->assertEquals(Director::makeRelative('relative'), 'relative');
255
        $this->assertEquals(Director::makeRelative("$siteUrl/?url=http://test.com"), '?url=http://test.com');
256
257
        $this->assertEquals("test", Director::makeRelative("https://".$siteUrlNoProtocol."/test"));
258
        $this->assertEquals("test", Director::makeRelative("http://".$siteUrlNoProtocol."/test"));
259
    }
260
261
    /**
262
     * Mostly tested by {@link testIsRelativeUrl()},
263
     * just adding the host name matching aspect here.
264
     */
265
    public function testIsSiteUrl()
266
    {
267
        $this->assertFalse(Director::is_site_url("http://test.com"));
268
        $this->assertTrue(Director::is_site_url(Director::absoluteBaseURL()));
0 ignored issues
show
Security Bug introduced by
It seems like \SilverStripe\Control\Director::absoluteBaseURL() targeting SilverStripe\Control\Director::absoluteBaseURL() can also be of type false; however, SilverStripe\Control\Director::is_site_url() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
269
        $this->assertFalse(Director::is_site_url("http://test.com?url=" . Director::absoluteBaseURL()));
270
        $this->assertFalse(Director::is_site_url("http://test.com?url=" . urlencode(Director::absoluteBaseURL())));
271
        $this->assertFalse(Director::is_site_url("//test.com?url=" . Director::absoluteBaseURL()));
272
    }
273
274
    /**
275
     * Tests isDev, isTest, isLive set from querystring
276
     */
277
    public function testQueryIsEnvironment()
278
    {
279
        if (!isset($_SESSION)) {
280
            $_SESSION = [];
281
        }
282
        // Reset
283
        unset($_SESSION['isDev']);
284
        unset($_SESSION['isLive']);
285
        unset($_GET['isTest']);
286
        unset($_GET['isDev']);
287
288
        /** @var Kernel $kernel */
289
        $kernel = Injector::inst()->get(Kernel::class);
290
        $kernel->setEnvironment(null);
291
292
        // Test isDev=1
293
        $_GET['isDev'] = '1';
294
        $this->assertTrue(Director::isDev());
295
        $this->assertFalse(Director::isTest());
296
        $this->assertFalse(Director::isLive());
297
298
        // Test persistence
299
        unset($_GET['isDev']);
300
        $this->assertTrue(Director::isDev());
301
        $this->assertFalse(Director::isTest());
302
        $this->assertFalse(Director::isLive());
303
304
        // Test change to isTest
305
        $_GET['isTest'] = '1';
306
        $this->assertFalse(Director::isDev());
307
        $this->assertTrue(Director::isTest());
308
        $this->assertFalse(Director::isLive());
309
310
        // Test persistence
311
        unset($_GET['isTest']);
312
        $this->assertFalse(Director::isDev());
313
        $this->assertTrue(Director::isTest());
314
        $this->assertFalse(Director::isLive());
315
    }
316
317
    public function testResetGlobalsAfterTestRequest()
318
    {
319
        $_GET = array('somekey' => 'getvalue');
320
        $_POST = array('somekey' => 'postvalue');
321
        $_COOKIE = array('somekey' => 'cookievalue');
322
323
        $cookies = Injector::inst()->createWithArgs(
324
            Cookie_Backend::class,
325
            array(array('somekey' => 'sometestcookievalue'))
326
        );
327
328
        Director::test(
329
            'errorpage?somekey=sometestgetvalue',
330
            array('somekey' => 'sometestpostvalue'),
331
            null,
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array|object<SilverStripe\Control\Session>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
332
            null,
333
            null,
334
            null,
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
335
            $cookies
336
        );
337
338
        $this->assertEquals(
339
            'getvalue',
340
            $_GET['somekey'],
341
            '$_GET reset to original value after Director::test()'
342
        );
343
        $this->assertEquals(
344
            'postvalue',
345
            $_POST['somekey'],
346
            '$_POST reset to original value after Director::test()'
347
        );
348
        $this->assertEquals(
349
            'cookievalue',
350
            $_COOKIE['somekey'],
351
            '$_COOKIE reset to original value after Director::test()'
352
        );
353
    }
354
355
    public function providerTestTestRequestCarriesGlobals()
356
    {
357
        $tests = [];
358
        $fixture = [ 'somekey' => 'sometestvalue' ];
359
        foreach (array('get', 'post') as $method) {
360
            foreach (array('return%sValue', 'returnRequestValue', 'returnCookieValue') as $testfunction) {
361
                $url = 'TestController/' . sprintf($testfunction, ucfirst($method))
362
                    . '?' . http_build_query($fixture);
363
                $tests[] = [$url, $fixture, $method];
364
            }
365
        }
366
        return $tests;
367
    }
368
369
    /**
370
     * @dataProvider providerTestTestRequestCarriesGlobals
371
     * @param $url
372
     * @param $fixture
373
     * @param $method
374
     */
375
    public function testTestRequestCarriesGlobals($url, $fixture, $method)
376
    {
377
        $getresponse = Director::test(
378
            $url,
379
            $fixture,
380
            null,
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array|object<SilverStripe\Control\Session>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
381
            strtoupper($method),
382
            null,
383
            null,
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
384
            Injector::inst()->createWithArgs(Cookie_Backend::class, array($fixture))
385
        );
386
387
        $this->assertInstanceOf(HTTPResponse::class, $getresponse, 'Director::test() returns HTTPResponse');
388
        $this->assertEquals($fixture['somekey'], $getresponse->getBody(), "Director::test({$url}, {$method})");
389
    }
390
391
    /**
392
     * Tests that additional parameters specified in the routing table are
393
     * saved in the request
394
     */
395
    public function testRouteParams()
396
    {
397
        /** @var HTTPRequest $request */
398
        Director::test('en-nz/myaction/myid/myotherid', null, null, null, null, null, null, $request);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
null is of type null, but the function expects a array|object<SilverStripe\Control\Session>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
null is of type null, but the function expects a array|object<SilverStripe\Control\Cookie_Backend>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
399
400
        $this->assertEquals(
401
            array(
402
                'Controller' => TestController::class,
403
                'Action' => 'myaction',
404
                'ID' => 'myid',
405
                'OtherID' => 'myotherid',
406
                'Locale' => 'en_NZ'
407
            ),
408
            $request->params()
409
        );
410
    }
411
412
    public function testForceSSLProtectsEntireSite()
413
    {
414
        $this->expectExceptionRedirect('https://www.mysite.com/some-url');
415
        Director::mockRequest(function () {
416
            Director::forceSSL();
417
        }, '/some-url');
418
    }
419
420
    public function testForceSSLOnTopLevelPagePattern()
421
    {
422
        // Expect admin to trigger redirect
423
        $this->expectExceptionRedirect('https://www.mysite.com/admin');
424
        Director::mockRequest(function () {
425
            Director::forceSSL(array('/^admin/'));
426
        }, '/admin');
427
    }
428
429
    public function testForceSSLOnSubPagesPattern()
430
    {
431
        // Expect to redirect to security login page
432
        $this->expectExceptionRedirect('https://www.mysite.com/Security/login');
433
        Director::mockRequest(function () {
434
            Director::forceSSL(array('/^Security/'));
435
        }, '/Security/login');
436
    }
437
438
    public function testForceSSLWithPatternDoesNotMatchOtherPages()
439
    {
440
        // Not on same url should not trigger redirect
441
        Director::mockRequest(function () {
442
            $this->assertFalse(Director::forceSSL(array('/^admin/')));
443
        }, Director::baseURL() . 'normal-page');
444
445
        // nested url should not triger redirect either
446
        Director::mockRequest(function () {
447
            $this->assertFalse(Director::forceSSL(array('/^admin/', '/^Security/')));
448
        }, Director::baseURL() . 'just-another-page/sub-url');
449
    }
450
451
    public function testForceSSLAlternateDomain()
452
    {
453
        // Ensure that forceSSL throws the appropriate exception
454
        $this->expectExceptionRedirect('https://secure.mysite.com/admin');
455
        Director::mockRequest(function (HTTPRequest $request) {
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
456
            return Director::forceSSL(array('/^admin/'), 'secure.mysite.com');
457
        }, Director::baseURL() . 'admin');
458
    }
459
460
    /**
461
     * Set url to redirect to
462
     *
463
     * @var string
464
     */
465
    protected $expectedRedirect = null;
466
467
    /**
468
     * Expects this test to throw a HTTPResponse_Exception with the given redirect
469
     *
470
     * @param string $url
471
     */
472
    protected function expectExceptionRedirect($url)
473
    {
474
        $this->expectedRedirect = $url;
475
    }
476
477
    protected function runTest()
478
    {
479
        try {
480
            $result = parent::runTest();
481
            if ($this->expectedRedirect) {
482
                $this->fail("Expected to redirect to {$this->expectedRedirect} but no redirect found");
483
            }
484
            return $result;
485
        } catch (HTTPResponse_Exception $exception) {
486
            // Check URL
487
            if ($this->expectedRedirect) {
488
                $url = $exception->getResponse()->getHeader('Location');
489
                $this->assertEquals($this->expectedRedirect, $url, "Expected to redirect to {$this->expectedRedirect}");
490
                return null;
491
            } else {
492
                throw $exception;
493
            }
494
        }
495
    }
496
497
    /**
498
     * @covers \SilverStripe\Control\Director::extract_request_headers()
499
     */
500
    public function testExtractRequestHeaders()
501
    {
502
        $request = array(
503
            'REDIRECT_STATUS'      => '200',
504
            'HTTP_HOST'            => 'host',
505
            'HTTP_USER_AGENT'      => 'User Agent',
506
            'HTTP_ACCEPT'          => 'text/html',
507
            'HTTP_ACCEPT_LANGUAGE' => 'en-us',
508
            'HTTP_COOKIE'          => 'MyCookie=1',
509
            'SERVER_PROTOCOL'      => 'HTTP/1.1',
510
            'REQUEST_METHOD'       => 'GET',
511
            'REQUEST_URI'          => '/',
512
            'SCRIPT_NAME'          => FRAMEWORK_DIR . '/main.php',
513
            'CONTENT_TYPE'         => 'text/xml',
514
            'CONTENT_LENGTH'       => 10
515
        );
516
517
        $headers = array(
518
            'Host'            => 'host',
519
            'User-Agent'      => 'User Agent',
520
            'Accept'          => 'text/html',
521
            'Accept-Language' => 'en-us',
522
            'Cookie'          => 'MyCookie=1',
523
            'Content-Type'    => 'text/xml',
524
            'Content-Length'  => '10'
525
        );
526
527
        $this->assertEquals($headers, HTTPRequestBuilder::extractRequestHeaders($request));
528
    }
529
530
    public function testUnmatchedRequestReturns404()
531
    {
532
        // Remove non-tested rules
533
        $this->assertEquals(404, Director::test('no-route')->getStatusCode());
534
    }
535
536
    public function testIsHttps()
537
    {
538
        if (!TRUSTED_PROXY) {
539
            $this->markTestSkipped('Test cannot be run without trusted proxy');
540
        }
541
        // nothing available
542
        $headers = array(
543
            'HTTP_X_FORWARDED_PROTOCOL', 'HTTPS', 'SSL'
544
        );
545
546
        $origServer = $_SERVER;
547
548
        foreach ($headers as $header) {
549
            if (isset($_SERVER[$header])) {
550
                unset($_SERVER['HTTP_X_FORWARDED_PROTOCOL']);
551
            }
552
        }
553
554
        $this->assertFalse(Director::is_https());
555
556
        $_SERVER['HTTP_X_FORWARDED_PROTOCOL'] = 'https';
557
        $this->assertTrue(Director::is_https());
558
559
        $_SERVER['HTTP_X_FORWARDED_PROTOCOL'] = 'http';
560
        $this->assertFalse(Director::is_https());
561
562
        $_SERVER['HTTP_X_FORWARDED_PROTOCOL'] = 'ftp';
563
        $this->assertFalse(Director::is_https());
564
565
        $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https';
566
        $this->assertTrue(Director::is_https());
567
568
        $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'http';
569
        $this->assertFalse(Director::is_https());
570
571
        $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'ftp';
572
        $this->assertFalse(Director::is_https());
573
574
        $_SERVER['HTTP_FRONT_END_HTTPS'] = 'On';
575
        $this->assertTrue(Director::is_https());
576
577
        $_SERVER['HTTP_FRONT_END_HTTPS'] = 'Off';
578
        $this->assertFalse(Director::is_https());
579
580
        // https via HTTPS
581
        $_SERVER['HTTPS'] = 'true';
582
        $this->assertTrue(Director::is_https());
583
584
        $_SERVER['HTTPS'] = '1';
585
        $this->assertTrue(Director::is_https());
586
587
        $_SERVER['HTTPS'] = 'off';
588
        $this->assertFalse(Director::is_https());
589
590
        // https via SSL
591
        $_SERVER['SSL'] = '';
592
        $this->assertTrue(Director::is_https());
593
594
        $_SERVER = $origServer;
595
    }
596
597
    public function testTestIgnoresHashes()
598
    {
599
        //test that hashes are ignored
600
        $url = "TestController/returnGetValue?somekey=key";
601
        $hash = "#test";
602
        /** @var HTTPRequest $request */
603
        $response = Director::test($url . $hash, null, null, null, null, null, null, $request);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
null is of type null, but the function expects a array|object<SilverStripe\Control\Session>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
null is of type null, but the function expects a array|object<SilverStripe\Control\Cookie_Backend>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
604
        $this->assertFalse($response->isError());
605
        $this->assertEquals('key', $response->getBody());
606
        $this->assertEquals($request->getURL(true), $url);
607
608
        //test encoded hashes are accepted
609
        $url = "TestController/returnGetValue?somekey=test%23key";
610
        $response = Director::test($url, null, null, null, null, null, null, $request);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
null is of type null, but the function expects a array|object<SilverStripe\Control\Session>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
null is of type null, but the function expects a array|object<SilverStripe\Control\Cookie_Backend>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
611
        $this->assertFalse($response->isError());
612
        $this->assertEquals('test#key', $response->getBody());
613
        $this->assertEquals($request->getURL(true), $url);
614
    }
615
616
    public function testRequestFilterInDirectorTest()
617
    {
618
        $filter = new DirectorTest\TestRequestFilter;
619
620
        $processor = new RequestProcessor(array($filter));
621
622
        Injector::inst()->registerService($processor, RequestProcessor::class);
623
        $response = Director::test('some-dummy-url');
624
        $this->assertEquals(404, $response->getStatusCode());
625
626
        $this->assertEquals(1, $filter->preCalls);
627
        $this->assertEquals(1, $filter->postCalls);
628
629
        $filter->failPost = true;
630
631
        $response = Director::test('some-dummy-url');
632
        $this->assertEquals(500, $response->getStatusCode());
633
        $this->assertEquals(_t(Director::class.'.REQUEST_ABORTED', 'Request aborted'), $response->getBody());
634
635
        $this->assertEquals(2, $filter->preCalls);
636
        $this->assertEquals(2, $filter->postCalls);
637
638
        $filter->failPre = true;
639
640
        $response = Director::test('some-dummy-url');
641
        $this->assertEquals(400, $response->getStatusCode());
642
        $this->assertEquals(_t(Director::class.'.INVALID_REQUEST', 'Invalid request'), $response->getBody());
643
644
        $this->assertEquals(3, $filter->preCalls);
645
646
        // preCall 'true' will trigger an exception and prevent post call execution
647
        $this->assertEquals(2, $filter->postCalls);
648
    }
649
650
    public function testGlobalMiddleware()
651
    {
652
        $middleware = new DirectorTest\TestMiddleware;
653
654
        Injector::inst()->registerService($middleware, 'Middleware1');
655
        Config::modify()->set(Director::class, 'middlewares', [ 'Middleware1' ]);
656
657
        $response = Director::test('some-dummy-url');
658
        $this->assertEquals(404, $response->getStatusCode());
659
660
        // Both triggered
661
        $this->assertEquals(1, $middleware->preCalls);
662
        $this->assertEquals(1, $middleware->postCalls);
663
664
        $middleware->failPost = true;
665
666
        $response = Director::test('some-dummy-url');
667
        $this->assertEquals(500, $response->getStatusCode());
668
669
        // Both triggered
670
        $this->assertEquals(2, $middleware->preCalls);
671
        $this->assertEquals(2, $middleware->postCalls);
672
673
        $middleware->failPre = true;
674
675
        $response = Director::test('some-dummy-url');
676
        $this->assertEquals(400, $response->getStatusCode());
677
678
        // Pre triggered, post not
679
        $this->assertEquals(3, $middleware->preCalls);
680
        $this->assertEquals(2, $middleware->postCalls);
681
    }
682
683
    public function testRouteSpecificMiddleware()
684
    {
685
        $middleware = new DirectorTest\TestMiddleware;
686
        $specificMiddleware = new DirectorTest\TestMiddleware;
687
688
        Injector::inst()->registerService($middleware, 'Middleware1');
689
        Injector::inst()->registerService($specificMiddleware, 'Middleware2');
690
691
        // Global middleware
692
        Config::modify()->set(Director::class, 'middlewares', [ 'Middleware1' ]);
693
694
        // URL rules, one of which has a specific middleware
695
        Config::modify()->set(
696
            Director::class,
697
            'rules',
698
            [
699
                'url-one' => TestController::class,
700
                'url-two' => [
701
                    'Controller' => TestController::class,
702
                    'Middlewares' => [ 'Middleware2' ]
703
                ]
704
            ]
705
        );
706
707
        // URL without a route-specific middleware
708
        $response = Director::test('url-one');
0 ignored issues
show
Unused Code introduced by
$response is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
709
710
        // Only the global middleware triggered
711
        $this->assertEquals(1, $middleware->preCalls);
712
        $this->assertEquals(0, $specificMiddleware->postCalls);
713
714
        $response = Director::test('url-two');
0 ignored issues
show
Unused Code introduced by
$response is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
715
716
        // Both triggered on the url with the specific middleware applied
717
        $this->assertEquals(2, $middleware->preCalls);
718
        $this->assertEquals(1, $specificMiddleware->postCalls);
719
720
    }
721
}
722