1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace SilverStripe\Control\Tests; |
4
|
|
|
|
5
|
|
|
use SilverStripe\Control\Controller; |
6
|
|
|
use SilverStripe\Control\Director; |
7
|
|
|
use SilverStripe\Control\Tests\ControllerTest\AccessBaseController; |
8
|
|
|
use SilverStripe\Control\Tests\ControllerTest\AccessSecuredController; |
9
|
|
|
use SilverStripe\Control\Tests\ControllerTest\AccessWildcardSecuredController; |
10
|
|
|
use SilverStripe\Control\Tests\ControllerTest\ContainerController; |
11
|
|
|
use SilverStripe\Control\Tests\ControllerTest\HasAction; |
12
|
|
|
use SilverStripe\Control\Tests\ControllerTest\HasAction_Unsecured; |
13
|
|
|
use SilverStripe\Control\Tests\ControllerTest\IndexSecuredController; |
14
|
|
|
use SilverStripe\Control\Tests\ControllerTest\SubController; |
15
|
|
|
use SilverStripe\Control\Tests\ControllerTest\TestController; |
16
|
|
|
use SilverStripe\Control\Tests\ControllerTest\UnsecuredController; |
17
|
|
|
use SilverStripe\Dev\FunctionalTest; |
18
|
|
|
use SilverStripe\Security\Member; |
19
|
|
|
use SilverStripe\View\SSViewer; |
20
|
|
|
|
21
|
|
|
class ControllerTest extends FunctionalTest |
22
|
|
|
{ |
23
|
|
|
|
24
|
|
|
protected static $fixture_file = 'ControllerTest.yml'; |
25
|
|
|
|
26
|
|
|
protected $autoFollowRedirection = false; |
27
|
|
|
|
28
|
|
|
protected $depSettings = null; |
29
|
|
|
|
30
|
|
|
protected static $extra_controllers = [ |
31
|
|
|
AccessBaseController::class, |
32
|
|
|
AccessSecuredController::class, |
33
|
|
|
AccessWildcardSecuredController::class, |
34
|
|
|
ContainerController::class, |
35
|
|
|
HasAction::class, |
36
|
|
|
HasAction_Unsecured::class, |
37
|
|
|
IndexSecuredController::class, |
38
|
|
|
SubController::class, |
39
|
|
|
TestController::class, |
40
|
|
|
UnsecuredController::class, |
41
|
|
|
]; |
42
|
|
|
|
43
|
|
|
protected function setUp() |
44
|
|
|
{ |
45
|
|
|
parent::setUp(); |
46
|
|
|
Director::config()->update('alternate_base_url', '/'); |
47
|
|
|
|
48
|
|
|
// Add test theme |
49
|
|
|
$themeDir = substr(__DIR__, strlen(FRAMEWORK_DIR)) . '/ControllerTest/'; |
50
|
|
|
$themes = [ |
51
|
|
|
"silverstripe/framework:{$themeDir}", |
52
|
|
|
SSViewer::DEFAULT_THEME, |
53
|
|
|
]; |
54
|
|
|
SSViewer::set_themes($themes); |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
public function testDefaultAction() |
58
|
|
|
{ |
59
|
|
|
/* For a controller with a template, the default action will simple run that template. */ |
60
|
|
|
$response = $this->get("TestController/"); |
61
|
|
|
$this->assertContains("This is the main template. Content is 'default content'", $response->getBody()); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
public function testMethodActions() |
65
|
|
|
{ |
66
|
|
|
/* The Action can refer to a method that is called on the object. If a method returns an array, then it |
67
|
|
|
* will be used to customise the template data */ |
68
|
|
|
$response = $this->get("TestController/methodaction"); |
69
|
|
|
$this->assertContains("This is the main template. Content is 'methodaction content'.", $response->getBody()); |
70
|
|
|
|
71
|
|
|
/* If the method just returns a string, then that will be used as the response */ |
72
|
|
|
$response = $this->get("TestController/stringaction"); |
73
|
|
|
$this->assertContains("stringaction was called.", $response->getBody()); |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
public function testTemplateActions() |
77
|
|
|
{ |
78
|
|
|
/* If there is no method, it can be used to point to an alternative template. */ |
79
|
|
|
$response = $this->get("TestController/templateaction"); |
80
|
|
|
$this->assertContains( |
81
|
|
|
"This is the template for templateaction. Content is 'default content'.", |
82
|
|
|
$response->getBody() |
83
|
|
|
); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
public function testUndefinedActions() |
87
|
|
|
{ |
88
|
|
|
$response = $this->get('IndexSecuredController/undefinedaction'); |
89
|
|
|
$this->assertInstanceOf('SilverStripe\\Control\\HTTPResponse', $response); |
90
|
|
|
$this->assertEquals(404, $response->getStatusCode(), 'Undefined actions return a not found response.'); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
public function testAllowedActions() |
94
|
|
|
{ |
95
|
|
|
$adminUser = $this->objFromFixture(Member::class, 'admin'); |
96
|
|
|
|
97
|
|
|
$response = $this->get("UnsecuredController/"); |
98
|
|
|
$this->assertEquals( |
99
|
|
|
200, |
100
|
|
|
$response->getStatusCode(), |
101
|
|
|
'Access granted on index action without $allowed_actions on defining controller, ' . 'when called without an action in the URL' |
102
|
|
|
); |
103
|
|
|
|
104
|
|
|
$response = $this->get("UnsecuredController/index"); |
105
|
|
|
$this->assertEquals( |
106
|
|
|
200, |
107
|
|
|
$response->getStatusCode(), |
108
|
|
|
'Access denied on index action without $allowed_actions on defining controller, ' . 'when called with an action in the URL' |
109
|
|
|
); |
110
|
|
|
|
111
|
|
|
$response = $this->get("UnsecuredController/method1"); |
112
|
|
|
$this->assertEquals( |
113
|
|
|
403, |
114
|
|
|
$response->getStatusCode(), |
115
|
|
|
'Access denied on action without $allowed_actions on defining controller, ' . 'when called without an action in the URL' |
116
|
|
|
); |
117
|
|
|
|
118
|
|
|
$response = $this->get("AccessBaseController/"); |
119
|
|
|
$this->assertEquals( |
120
|
|
|
200, |
121
|
|
|
$response->getStatusCode(), |
122
|
|
|
'Access granted on index with empty $allowed_actions on defining controller, ' . 'when called without an action in the URL' |
123
|
|
|
); |
124
|
|
|
|
125
|
|
|
$response = $this->get("AccessBaseController/index"); |
126
|
|
|
$this->assertEquals( |
127
|
|
|
200, |
128
|
|
|
$response->getStatusCode(), |
129
|
|
|
'Access granted on index with empty $allowed_actions on defining controller, ' . 'when called with an action in the URL' |
130
|
|
|
); |
131
|
|
|
|
132
|
|
|
$response = $this->get("AccessBaseController/method1"); |
133
|
|
|
$this->assertEquals( |
134
|
|
|
403, |
135
|
|
|
$response->getStatusCode(), |
136
|
|
|
'Access denied on action with empty $allowed_actions on defining controller' |
137
|
|
|
); |
138
|
|
|
|
139
|
|
|
$response = $this->get("AccessBaseController/method2"); |
140
|
|
|
$this->assertEquals( |
141
|
|
|
403, |
142
|
|
|
$response->getStatusCode(), |
143
|
|
|
'Access denied on action with empty $allowed_actions on defining controller, ' . 'even when action is allowed in subclasses (allowed_actions don\'t inherit)' |
144
|
|
|
); |
145
|
|
|
|
146
|
|
|
$response = $this->get("AccessSecuredController/"); |
147
|
|
|
$this->assertEquals( |
148
|
|
|
200, |
149
|
|
|
$response->getStatusCode(), |
150
|
|
|
'Access granted on index with non-empty $allowed_actions on defining controller, ' . 'even when index isn\'t specifically mentioned in there' |
151
|
|
|
); |
152
|
|
|
|
153
|
|
|
$response = $this->get("AccessSecuredController/method1"); |
154
|
|
|
$this->assertEquals( |
155
|
|
|
403, |
156
|
|
|
$response->getStatusCode(), |
157
|
|
|
'Access denied on action which is only defined in parent controller, ' . 'even when action is allowed in currently called class (allowed_actions don\'t inherit)' |
158
|
|
|
); |
159
|
|
|
|
160
|
|
|
$response = $this->get("AccessSecuredController/method2"); |
161
|
|
|
$this->assertEquals( |
162
|
|
|
200, |
163
|
|
|
$response->getStatusCode(), |
164
|
|
|
'Access granted on action originally defined with empty $allowed_actions on parent controller, ' . 'because it has been redefined in the subclass' |
165
|
|
|
); |
166
|
|
|
|
167
|
|
|
$response = $this->get("AccessSecuredController/templateaction"); |
168
|
|
|
$this->assertEquals( |
169
|
|
|
403, |
170
|
|
|
$response->getStatusCode(), |
171
|
|
|
'Access denied on action with $allowed_actions on defining controller, ' . 'if action is not a method but rather a template discovered by naming convention' |
172
|
|
|
); |
173
|
|
|
|
174
|
|
|
$response = $this->get("AccessSecuredController/templateaction"); |
175
|
|
|
$this->assertEquals( |
176
|
|
|
403, |
177
|
|
|
$response->getStatusCode(), |
178
|
|
|
'Access denied on action with $allowed_actions on defining controller, ' . 'if action is not a method but rather a template discovered by naming convention' |
179
|
|
|
); |
180
|
|
|
|
181
|
|
|
Member::actAs($adminUser, function () { |
182
|
|
|
$response = $this->get("AccessSecuredController/templateaction"); |
183
|
|
|
$this->assertEquals( |
184
|
|
|
200, |
185
|
|
|
$response->getStatusCode(), |
186
|
|
|
'Access granted for logged in admin on action with $allowed_actions on defining controller, ' . 'if action is not a method but rather a template discovered by naming convention' |
187
|
|
|
); |
188
|
|
|
}); |
189
|
|
|
|
190
|
|
|
$response = $this->get("AccessSecuredController/adminonly"); |
191
|
|
|
$this->assertEquals( |
192
|
|
|
403, |
193
|
|
|
$response->getStatusCode(), |
194
|
|
|
'Access denied on action with $allowed_actions on defining controller, ' . 'when restricted by unmatched permission code' |
195
|
|
|
); |
196
|
|
|
|
197
|
|
|
$response = $this->get("AccessSecuredController/aDmiNOnlY"); |
198
|
|
|
$this->assertEquals( |
199
|
|
|
403, |
200
|
|
|
$response->getStatusCode(), |
201
|
|
|
'Access denied on action with $allowed_actions on defining controller, ' . 'regardless of capitalization' |
202
|
|
|
); |
203
|
|
|
|
204
|
|
|
$response = $this->get('AccessSecuredController/protectedmethod'); |
205
|
|
|
$this->assertEquals( |
206
|
|
|
404, |
207
|
|
|
$response->getStatusCode(), |
208
|
|
|
"Access denied to protected method even if its listed in allowed_actions" |
209
|
|
|
); |
210
|
|
|
|
211
|
|
|
Member::actAs($adminUser, function () { |
212
|
|
|
$response = $this->get("AccessSecuredController/adminonly"); |
213
|
|
|
$this->assertEquals( |
214
|
|
|
200, |
215
|
|
|
$response->getStatusCode(), |
216
|
|
|
"Permission codes are respected when set in \$allowed_actions" |
217
|
|
|
); |
218
|
|
|
}); |
219
|
|
|
|
220
|
|
|
$response = $this->get('AccessBaseController/extensionmethod1'); |
221
|
|
|
$this->assertEquals( |
222
|
|
|
200, |
223
|
|
|
$response->getStatusCode(), |
224
|
|
|
"Access granted to method defined in allowed_actions on extension, " . "where method is also defined on extension" |
225
|
|
|
); |
226
|
|
|
|
227
|
|
|
$response = $this->get('AccessSecuredController/extensionmethod1'); |
228
|
|
|
$this->assertEquals( |
229
|
|
|
200, |
230
|
|
|
$response->getStatusCode(), |
231
|
|
|
"Access granted to method defined in allowed_actions on extension, " . "where method is also defined on extension, even when called in a subclass" |
232
|
|
|
); |
233
|
|
|
|
234
|
|
|
$response = $this->get('AccessBaseController/extensionmethod2'); |
235
|
|
|
$this->assertEquals( |
236
|
|
|
404, |
237
|
|
|
$response->getStatusCode(), |
238
|
|
|
"Access denied to method not defined in allowed_actions on extension, " . "where method is also defined on extension" |
239
|
|
|
); |
240
|
|
|
|
241
|
|
|
$response = $this->get('IndexSecuredController/'); |
242
|
|
|
$this->assertEquals( |
243
|
|
|
403, |
244
|
|
|
$response->getStatusCode(), |
245
|
|
|
"Access denied when index action is limited through allowed_actions, " . "and doesn't satisfy checks, and action is empty" |
246
|
|
|
); |
247
|
|
|
|
248
|
|
|
$response = $this->get('IndexSecuredController/index'); |
249
|
|
|
$this->assertEquals( |
250
|
|
|
403, |
251
|
|
|
$response->getStatusCode(), |
252
|
|
|
"Access denied when index action is limited through allowed_actions, " . "and doesn't satisfy checks" |
253
|
|
|
); |
254
|
|
|
|
255
|
|
|
Member::actAs($adminUser, function () { |
256
|
|
|
$response = $this->get('IndexSecuredController/'); |
257
|
|
|
$this->assertEquals( |
258
|
|
|
200, |
259
|
|
|
$response->getStatusCode(), |
260
|
|
|
"Access granted when index action is limited through allowed_actions, " . "and does satisfy checks" |
261
|
|
|
); |
262
|
|
|
}); |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* @expectedException \InvalidArgumentException |
267
|
|
|
* @expectedExceptionMessage Invalid allowed_action '*' |
268
|
|
|
*/ |
269
|
|
|
public function testWildcardAllowedActions() |
270
|
|
|
{ |
271
|
|
|
$this->get('AccessWildcardSecuredController'); |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
/** |
275
|
|
|
* Test Controller::join_links() |
276
|
|
|
*/ |
277
|
|
|
public function testJoinLinks() |
278
|
|
|
{ |
279
|
|
|
/* Controller::join_links() will reliably join two URL-segments together so that they will be |
280
|
|
|
* appropriately parsed by the URL parser */ |
281
|
|
|
$this->assertEquals("admin/crm/MyForm", Controller::join_links("admin/crm", "MyForm")); |
282
|
|
|
$this->assertEquals("admin/crm/MyForm", Controller::join_links("admin/crm/", "MyForm")); |
283
|
|
|
|
284
|
|
|
/* It will also handle appropriate combination of querystring variables */ |
285
|
|
|
$this->assertEquals("admin/crm/MyForm?flush=1", Controller::join_links("admin/crm/?flush=1", "MyForm")); |
286
|
|
|
$this->assertEquals("admin/crm/MyForm?flush=1", Controller::join_links("admin/crm/", "MyForm?flush=1")); |
287
|
|
|
$this->assertEquals( |
288
|
|
|
"admin/crm/MyForm?field=1&other=1", |
289
|
|
|
Controller::join_links("admin/crm/?field=1", "MyForm?other=1") |
290
|
|
|
); |
291
|
|
|
|
292
|
|
|
/* It can handle arbitrary numbers of components, and will ignore empty ones */ |
293
|
|
|
$this->assertEquals("admin/crm/MyForm/", Controller::join_links("admin/", "crm", "", "MyForm/")); |
294
|
|
|
$this->assertEquals( |
295
|
|
|
"admin/crm/MyForm/?a=1&b=2", |
296
|
|
|
Controller::join_links("admin/?a=1", "crm", "", "MyForm/?b=2") |
297
|
|
|
); |
298
|
|
|
|
299
|
|
|
/* It can also be used to attach additional get variables to a link */ |
300
|
|
|
$this->assertEquals("admin/crm?flush=1", Controller::join_links("admin/crm", "?flush=1")); |
301
|
|
|
$this->assertEquals("admin/crm?existing=1&flush=1", Controller::join_links("admin/crm?existing=1", "?flush=1")); |
302
|
|
|
$this->assertEquals( |
303
|
|
|
"admin/crm/MyForm?a=1&b=2&c=3", |
304
|
|
|
Controller::join_links("?a=1", "admin/crm", "?b=2", "MyForm?c=3") |
305
|
|
|
); |
306
|
|
|
|
307
|
|
|
// And duplicates are handled nicely |
308
|
|
|
$this->assertEquals( |
309
|
|
|
"admin/crm?foo=2&bar=3&baz=1", |
310
|
|
|
Controller::join_links("admin/crm?foo=1&bar=1&baz=1", "?foo=2&bar=3") |
311
|
|
|
); |
312
|
|
|
|
313
|
|
|
$this->assertEquals( |
314
|
|
|
'admin/action', |
315
|
|
|
Controller::join_links('admin/', '/', '/action'), |
316
|
|
|
'Test that multiple slashes are trimmed.' |
317
|
|
|
); |
318
|
|
|
|
319
|
|
|
$this->assertEquals('/admin/action', Controller::join_links('/admin', 'action')); |
320
|
|
|
|
321
|
|
|
/* One fragment identifier is handled as you would expect */ |
322
|
|
|
$this->assertEquals("my-page?arg=var#subsection", Controller::join_links("my-page#subsection", "?arg=var")); |
323
|
|
|
|
324
|
|
|
/* If there are multiple, it takes the last one */ |
325
|
|
|
$this->assertEquals( |
326
|
|
|
"my-page?arg=var#second-section", |
327
|
|
|
Controller::join_links("my-page#subsection", "?arg=var", "#second-section") |
328
|
|
|
); |
329
|
|
|
|
330
|
|
|
/* Does type-safe checks for zero value */ |
331
|
|
|
$this->assertEquals("my-page/0", Controller::join_links("my-page", 0)); |
332
|
|
|
|
333
|
|
|
// Test array args |
334
|
|
|
$this->assertEquals( |
335
|
|
|
"admin/crm/MyForm?a=1&b=2&c=3", |
336
|
|
|
Controller::join_links(["?a=1", "admin/crm", "?b=2", "MyForm?c=3"]) |
337
|
|
|
); |
338
|
|
|
} |
339
|
|
|
|
340
|
|
|
public function testLink() |
341
|
|
|
{ |
342
|
|
|
$controller = new HasAction(); |
343
|
|
|
$this->assertEquals('HasAction/', $controller->Link()); |
344
|
|
|
$this->assertEquals('HasAction/', $controller->Link(null)); |
345
|
|
|
$this->assertEquals('HasAction/', $controller->Link(false)); |
|
|
|
|
346
|
|
|
$this->assertEquals('HasAction/allowed-action/', $controller->Link('allowed-action')); |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
/** |
350
|
|
|
* @covers \SilverStripe\Control\Controller::hasAction |
351
|
|
|
*/ |
352
|
|
|
public function testHasAction() |
353
|
|
|
{ |
354
|
|
|
$controller = new HasAction(); |
355
|
|
|
$unsecuredController = new HasAction_Unsecured(); |
356
|
|
|
$securedController = new AccessSecuredController(); |
357
|
|
|
|
358
|
|
|
$this->assertFalse( |
359
|
|
|
$controller->hasAction('1'), |
360
|
|
|
'Numeric actions do not slip through.' |
361
|
|
|
); |
362
|
|
|
//$this->assertFalse( |
363
|
|
|
// $controller->hasAction('lowercase_permission'), |
364
|
|
|
// 'Lowercase permission does not slip through.' |
365
|
|
|
//); |
366
|
|
|
$this->assertFalse( |
367
|
|
|
$controller->hasAction('undefined'), |
368
|
|
|
'undefined actions do not exist' |
369
|
|
|
); |
370
|
|
|
$this->assertTrue( |
371
|
|
|
$controller->hasAction('allowed_action'), |
372
|
|
|
'allowed actions are recognised' |
373
|
|
|
); |
374
|
|
|
$this->assertTrue( |
375
|
|
|
$controller->hasAction('template_action'), |
376
|
|
|
'action-specific templates are recognised' |
377
|
|
|
); |
378
|
|
|
|
379
|
|
|
$this->assertTrue( |
380
|
|
|
$unsecuredController->hasAction('defined_action'), |
381
|
|
|
'Without an allowed_actions, any defined methods are recognised as actions' |
382
|
|
|
); |
383
|
|
|
|
384
|
|
|
$this->assertTrue( |
385
|
|
|
$securedController->hasAction('adminonly'), |
386
|
|
|
'Method is generally visible even if its denied via allowed_actions' |
387
|
|
|
); |
388
|
|
|
|
389
|
|
|
$this->assertFalse( |
390
|
|
|
$securedController->hasAction('protectedmethod'), |
391
|
|
|
'Method is not visible when protected, even if its defined in allowed_actions' |
392
|
|
|
); |
393
|
|
|
|
394
|
|
|
$this->assertTrue( |
395
|
|
|
$securedController->hasAction('extensionmethod1'), |
396
|
|
|
'Method is visible when defined on an extension and part of allowed_actions' |
397
|
|
|
); |
398
|
|
|
|
399
|
|
|
$this->assertFalse( |
400
|
|
|
$securedController->hasAction('internalextensionmethod'), |
401
|
|
|
'Method is not visible when defined on an extension, but not part of allowed_actions' |
402
|
|
|
); |
403
|
|
|
|
404
|
|
|
$this->assertFalse( |
405
|
|
|
$securedController->hasAction('protectedextensionmethod'), |
406
|
|
|
'Method is not visible when defined on an extension, part of allowed_actions, ' . 'but with protected visibility' |
407
|
|
|
); |
408
|
|
|
} |
409
|
|
|
|
410
|
|
|
public function testRedirectBackByReferer() |
411
|
|
|
{ |
412
|
|
|
$internalRelativeUrl = Controller::join_links(Director::baseURL(), '/some-url'); |
413
|
|
|
$internalAbsoluteUrl = Controller::join_links(Director::absoluteBaseURL(), '/some-url'); |
414
|
|
|
|
415
|
|
|
$response = $this->get( |
416
|
|
|
'TestController/redirectbacktest', |
417
|
|
|
null, |
418
|
|
|
array('Referer' => $internalRelativeUrl) |
419
|
|
|
); |
420
|
|
|
$this->assertEquals(302, $response->getStatusCode()); |
421
|
|
|
$this->assertEquals( |
422
|
|
|
$internalAbsoluteUrl, |
423
|
|
|
$response->getHeader('Location'), |
424
|
|
|
"Redirects on internal relative URLs" |
425
|
|
|
); |
426
|
|
|
|
427
|
|
|
$response = $this->get( |
428
|
|
|
'TestController/redirectbacktest', |
429
|
|
|
null, |
430
|
|
|
array('Referer' => $internalAbsoluteUrl) |
431
|
|
|
); |
432
|
|
|
$this->assertEquals(302, $response->getStatusCode()); |
433
|
|
|
$this->assertEquals( |
434
|
|
|
$internalAbsoluteUrl, |
435
|
|
|
$response->getHeader('Location'), |
436
|
|
|
"Redirects on internal absolute URLs" |
437
|
|
|
); |
438
|
|
|
|
439
|
|
|
$externalAbsoluteUrl = 'http://myhost.com/some-url'; |
440
|
|
|
$response = $this->get( |
441
|
|
|
'TestController/redirectbacktest', |
442
|
|
|
null, |
443
|
|
|
array('Referer' => $externalAbsoluteUrl) |
444
|
|
|
); |
445
|
|
|
$this->assertEquals( |
446
|
|
|
Director::absoluteBaseURL(), |
447
|
|
|
$response->getHeader('Location'), |
448
|
|
|
"Redirects back to home page on external url" |
449
|
|
|
); |
450
|
|
|
} |
451
|
|
|
|
452
|
|
|
public function testRedirectBackByBackUrl() |
453
|
|
|
{ |
454
|
|
|
$internalRelativeUrl = Controller::join_links(Director::baseURL(), '/some-url'); |
455
|
|
|
$internalAbsoluteUrl = Controller::join_links(Director::absoluteBaseURL(), '/some-url'); |
456
|
|
|
|
457
|
|
|
$response = $this->get('TestController/redirectbacktest?BackURL=' . urlencode($internalRelativeUrl)); |
458
|
|
|
$this->assertEquals(302, $response->getStatusCode()); |
459
|
|
|
$this->assertEquals( |
460
|
|
|
$internalAbsoluteUrl, |
461
|
|
|
$response->getHeader('Location'), |
462
|
|
|
"Redirects on internal relative URLs" |
463
|
|
|
); |
464
|
|
|
|
465
|
|
|
// BackURL is internal link |
466
|
|
|
$internalAbsoluteUrl = Director::absoluteBaseURL() . '/some-url'; |
467
|
|
|
$link = 'TestController/redirectbacktest?BackURL=' . urlencode($internalAbsoluteUrl); |
468
|
|
|
$response = $this->get($link); |
469
|
|
|
$this->assertEquals($internalAbsoluteUrl, $response->getHeader('Location')); |
470
|
|
|
$this->assertEquals( |
471
|
|
|
302, |
472
|
|
|
$response->getStatusCode(), |
473
|
|
|
"Redirects on internal absolute URLs" |
474
|
|
|
); |
475
|
|
|
|
476
|
|
|
// Note that this test is affected by the prior ->get() |
477
|
|
|
$externalAbsoluteUrl = 'http://myhost.com/some-url'; |
478
|
|
|
$response = $this->get('TestController/redirectbacktest?BackURL=' . urlencode($externalAbsoluteUrl)); |
479
|
|
|
$this->assertEquals( |
480
|
|
|
Director::absoluteURL($link), |
481
|
|
|
$response->getHeader('Location'), |
482
|
|
|
"If BackURL Is external link, fall back to last url (Referer)" |
483
|
|
|
); |
484
|
|
|
} |
485
|
|
|
|
486
|
|
|
public function testSubActions() |
487
|
|
|
{ |
488
|
|
|
// If a controller action returns another controller, ensure that the $action variable is correctly forwarded |
489
|
|
|
$response = $this->get("ContainerController/subcontroller/subaction"); |
490
|
|
|
$this->assertEquals('subaction', $response->getBody()); |
491
|
|
|
|
492
|
|
|
// Handle nested action |
493
|
|
|
$response = $this->get('ContainerController/subcontroller/substring/subvieweraction'); |
494
|
|
|
$this->assertEquals('Hope this works', $response->getBody()); |
495
|
|
|
} |
496
|
|
|
} |
497
|
|
|
|