‪TYPO3CMS  9.5
ErrorControllerTest.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
18 use Prophecy\Argument;
19 use Psr\Http\Message\StreamInterface;
28 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
29 
33 class ‪ErrorControllerTest extends UnitTestCase
34 {
38  public function ‪tearDown()
39  {
40  GeneralUtility::purgeInstances();
41  parent::tearDown();
42  }
43 
48  {
49  $this->expectExceptionMessage('This test page was not found!');
50  $this->expectExceptionCode(1518472189);
51  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling'] = false;
52  ‪$GLOBALS['TYPO3_REQUEST'] = [];
53  $subject = new ‪ErrorController();
54  $subject->pageNotFoundAction(new ‪ServerRequest(), 'This test page was not found!');
55  }
56 
63  {
64  return [
65  '404 with default errorpage' => [
66  'handler' => true,
67  'header' => 'HTTP/1.0 404 Not Found',
68  'message' => 'Custom message',
69  'response' => [
70  'type' => HtmlResponse::class,
71  'statusCode' => 404,
72  'reasonPhrase' => 'Not Found',
73  'content' => 'Reason: Custom message',
74  'headers' => [
75  'Content-Type' => ['text/html; charset=utf-8'],
76  ],
77  ],
78  ],
79  '404 with default errorpage setting the handler to legacy value' => [
80  'handler' => '1',
81  'header' => 'HTTP/1.0 404 This is a dead end',
82  'message' => 'Come back tomorrow',
83  'response' => [
84  'type' => HtmlResponse::class,
85  'statusCode' => 404,
86  'reasonPhrase' => 'This is a dead end',
87  'content' => 'Reason: Come back tomorrow',
88  'headers' => [
89  'Content-Type' => ['text/html; charset=utf-8'],
90  ],
91  ],
92  ],
93  '404 with custom userfunction' => [
94  'handler' => 'USER_FUNCTION:' . ErrorControllerTest::class . '->mockedUserFunctionCall',
95  'header' => 'HTTP/1.0 404 Not Found',
96  'message' => 'Custom message',
97  'response' => [
98  'type' => HtmlResponse::class,
99  'statusCode' => 404,
100  'reasonPhrase' => 'Not Found',
101  'content' => 'It\'s magic, Michael: Custom message',
102  'headers' => [
103  'Content-Type' => ['text/html; charset=utf-8'],
104  ],
105  ],
106  ],
107  '404 with a readfile functionality' => [
108  'handler' => 'READFILE:typo3/sysext/frontend/Tests/Unit/Controller/Fixtures/error.txt',
109  'header' => 'HTTP/1.0 404 Not Found',
110  'message' => 'Custom message',
111  'response' => [
112  'type' => HtmlResponse::class,
113  'statusCode' => 404,
114  'reasonPhrase' => 'Not Found',
115  'content' => 'rama-lama-ding-dong',
116  'headers' => [
117  'Content-Type' => ['text/html; charset=utf-8'],
118  ],
119  ],
120  ],
121  '404 with a readfile functionality with an invalid file' => [
122  'handler' => 'READFILE:does_not_exist.php6',
123  'header' => 'HTTP/1.0 404 Not Found',
124  'message' => 'Custom message',
125  'response' => null,
126  'exceptionCode' => 1518472245,
127  ],
128  '404 with a redirect - never do that in production - it is bad for SEO. But with custom headers as well...' => [
129  'handler' => 'REDIRECT:www.typo3.org',
130  'header' => 'HTTP/1.0 404 Not Found
131 X-TYPO3-Additional-Header: Banana Stand',
132  'message' => 'Custom message',
133  'response' => [
134  'type' => RedirectResponse::class,
135  'statusCode' => 404,
136  'reasonPhrase' => 'Not Found',
137  'headers' => [
138  'location' => ['www.typo3.org'],
139  'X-TYPO3-Additional-Header' => ['Banana Stand'],
140  ],
141  ],
142  ],
143  ];
144  }
145 
151  $handler,
152  $header,
153  $message,
154  $expectedResponseDetails,
155  $expectedExceptionCode = null
156  ) {
157  if ($expectedExceptionCode !== null) {
158  $this->expectExceptionCode($expectedExceptionCode);
159  }
160  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling'] = $handler;
161  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling_statheader'] = $header;
162  // faking getIndpEnv() variables
163  $_SERVER['REQUEST_URI'] = '/unit-test/';
164  $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
165  $_SERVER['HTTP_HOST'] = 'localhost';
166  $_SERVER['SSL_SESSION_ID'] = true;
167  ‪$GLOBALS['TYPO3_REQUEST'] = [];
168 
170 
171  $subject = new ‪ErrorController();
172  $response = $subject->pageNotFoundAction(new ‪ServerRequest(), $message);
173  if (is_array($expectedResponseDetails)) {
174  $this->assertInstanceOf($expectedResponseDetails['type'], $response);
175  $this->assertEquals($expectedResponseDetails['statusCode'], $response->getStatusCode());
176  $this->assertEquals($expectedResponseDetails['reasonPhrase'], $response->getReasonPhrase());
177  if (isset($expectedResponseDetails['content'])) {
178  $this->assertContains($expectedResponseDetails['content'], $response->getBody()->getContents());
179  }
180  $this->assertEquals($expectedResponseDetails['headers'], $response->getHeaders());
181  }
182  }
183 
188  {
189  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling'] = '/404/';
190  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling_statheader'] = 'HTTP/1.0 404 Not Found
191 X-TYPO3-Additional-Header: Banana Stand';
192  // faking getIndpEnv() variables
193  $_SERVER['REQUEST_URI'] = '/unit-test/';
194  $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
195  $_SERVER['HTTP_HOST'] = 'localhost';
196  $_SERVER['SSL_SESSION_ID'] = true;
197  ‪$GLOBALS['TYPO3_REQUEST'] = [];
199  $subject = new ‪ErrorController();
200 
201  $this->‪prophesizeGetUrl();
202  $response = $subject->pageNotFoundAction(new ‪ServerRequest(), 'Custom message');
203 
204  $expectedResponseDetails = [
205  'type' => HtmlResponse::class,
206  'statusCode' => 404,
207  'reasonPhrase' => 'Not Found',
208  'headers' => [
209  'Content-Type' => ['text/html; charset=utf-8'],
210  'X-TYPO3-Additional-Header' => ['Banana Stand'],
211  ],
212  ];
213  $this->assertInstanceOf($expectedResponseDetails['type'], $response);
214  $this->assertEquals($expectedResponseDetails['statusCode'], $response->getStatusCode());
215  $this->assertEquals($expectedResponseDetails['reasonPhrase'], $response->getReasonPhrase());
216  if (isset($expectedResponseDetails['content'])) {
217  $this->assertContains($expectedResponseDetails['content'], $response->getBody()->getContents());
218  }
219  $this->assertEquals($expectedResponseDetails['headers'], $response->getHeaders());
220  }
221 
227  public function ‪accessDeniedDataProvider()
228  {
229  return [
230  '403 with default errorpage' => [
231  'handler' => true,
232  'header' => 'HTTP/1.0 403 Who are you',
233  'message' => 'Be nice, do good',
234  'response' => [
235  'type' => HtmlResponse::class,
236  'statusCode' => 403,
237  'reasonPhrase' => 'Who are you',
238  'content' => 'Reason: Be nice, do good',
239  'headers' => [
240  'Content-Type' => ['text/html; charset=utf-8'],
241  ],
242  ],
243  ],
244  ];
245  }
246 
251  public function ‪accessDeniedReturnsProperHeaders($handler, $header, $message, $expectedResponseDetails)
252  {
253  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling'] = $handler;
254  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling_accessdeniedheader'] = $header;
255  // faking getIndpEnv() variables
256  $_SERVER['REQUEST_URI'] = '/unit-test/';
257  $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
258  $_SERVER['HTTP_HOST'] = 'localhost';
259  $_SERVER['SSL_SESSION_ID'] = true;
260  ‪$GLOBALS['TYPO3_REQUEST'] = [];
261  $subject = new ‪ErrorController();
262  $response = $subject->accessDeniedAction(new ‪ServerRequest(), $message);
263  if (is_array($expectedResponseDetails)) {
264  $this->assertInstanceOf($expectedResponseDetails['type'], $response);
265  $this->assertEquals($expectedResponseDetails['statusCode'], $response->getStatusCode());
266  $this->assertEquals($expectedResponseDetails['reasonPhrase'], $response->getReasonPhrase());
267  if (isset($expectedResponseDetails['content'])) {
268  $this->assertContains($expectedResponseDetails['content'], $response->getBody()->getContents());
269  }
270  $this->assertEquals($expectedResponseDetails['headers'], $response->getHeaders());
271  }
272  }
273 
278  {
279  ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask'] = '*';
280  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_handling'] = true;
281  $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
282  $this->expectExceptionMessage('All your system are belong to us!');
283  $this->expectExceptionCode(1518472181);
284  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_handling'] = false;
285  $subject = new ‪ErrorController();
286  $subject->unavailableAction(new ‪ServerRequest(), 'All your system are belong to us!');
287  }
288 
293  {
294  ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask'] = '*';
295  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_handling'] = true;
296  $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
297 
298  $this->expectExceptionMessage('All your system are belong to us!');
299  $this->expectExceptionCode(1518472181);
300  $subject = new ‪ErrorController();
301  $subject->unavailableAction(new ‪ServerRequest(), 'All your system are belong to us!');
302  }
303 
310  {
311  return [
312  '503 with default errorpage' => [
313  'handler' => true,
314  'header' => 'HTTP/1.0 503 Service Temporarily Unavailable',
315  'message' => 'Custom message',
316  'response' => [
317  'type' => HtmlResponse::class,
318  'statusCode' => 503,
319  'reasonPhrase' => 'Service Temporarily Unavailable',
320  'content' => 'Reason: Custom message',
321  'headers' => [
322  'Content-Type' => ['text/html; charset=utf-8'],
323  ],
324  ],
325  ],
326  '503 with default errorpage setting the handler to legacy value' => [
327  'handler' => '1',
328  'header' => 'HTTP/1.0 503 This is a dead end',
329  'message' => 'Come back tomorrow',
330  'response' => [
331  'type' => HtmlResponse::class,
332  'statusCode' => 503,
333  'reasonPhrase' => 'This is a dead end',
334  'content' => 'Reason: Come back tomorrow',
335  'headers' => [
336  'Content-Type' => ['text/html; charset=utf-8'],
337  ],
338  ],
339  ],
340  '503 with custom userfunction' => [
341  'handler' => 'USER_FUNCTION:' . ErrorControllerTest::class . '->mockedUserFunctionCall',
342  'header' => 'HTTP/1.0 503 Service Temporarily Unavailable',
343  'message' => 'Custom message',
344  'response' => [
345  'type' => HtmlResponse::class,
346  'statusCode' => 503,
347  'reasonPhrase' => 'Service Temporarily Unavailable',
348  'content' => 'It\'s magic, Michael: Custom message',
349  'headers' => [
350  'Content-Type' => ['text/html; charset=utf-8'],
351  ],
352  ],
353  ],
354  '503 with a readfile functionality' => [
355  'handler' => 'READFILE:typo3/sysext/frontend/Tests/Unit/Controller/Fixtures/error.txt',
356  'header' => 'HTTP/1.0 503 Service Temporarily Unavailable',
357  'message' => 'Custom message',
358  'response' => [
359  'type' => HtmlResponse::class,
360  'statusCode' => 503,
361  'reasonPhrase' => 'Service Temporarily Unavailable',
362  'content' => 'Let it snow',
363  'headers' => [
364  'Content-Type' => ['text/html; charset=utf-8'],
365  ],
366  ],
367  ],
368  '503 with a readfile functionality with an invalid file' => [
369  'handler' => 'READFILE:does_not_exist.php6',
370  'header' => 'HTTP/1.0 503 Service Temporarily Unavailable',
371  'message' => 'Custom message',
372  'response' => null,
373  'exceptionCode' => 1518472245,
374  ],
375  '503 with a redirect - never do that in production - it is bad for SEO. But with custom headers as well...' => [
376  'handler' => 'REDIRECT:www.typo3.org',
377  'header' => 'HTTP/1.0 503 Service Temporarily Unavailable
378 X-TYPO3-Additional-Header: Banana Stand',
379  'message' => 'Custom message',
380  'response' => [
381  'type' => RedirectResponse::class,
382  'statusCode' => 503,
383  'reasonPhrase' => 'Service Temporarily Unavailable',
384  'headers' => [
385  'location' => ['www.typo3.org'],
386  'X-TYPO3-Additional-Header' => ['Banana Stand'],
387  ],
388  ],
389  ],
390  ];
391  }
392 
398  $handler,
399  $header,
400  $message,
401  $expectedResponseDetails,
402  $expectedExceptionCode = null
403  ) {
404  if ($expectedExceptionCode !== null) {
405  $this->expectExceptionCode($expectedExceptionCode);
406  }
407  ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask'] = '-1';
408  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_handling'] = $handler;
409  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_handling_statheader'] = $header;
410  // faking getIndpEnv() variables
411  $_SERVER['REQUEST_URI'] = '/unit-test/';
412  $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
413  $_SERVER['HTTP_HOST'] = 'localhost';
414  $_SERVER['SSL_SESSION_ID'] = true;
415  ‪$GLOBALS['TYPO3_REQUEST'] = [];
416  $this->‪prophesizeGetUrl();
418  $subject = new ‪ErrorController();
419  $response = $subject->unavailableAction(new ‪ServerRequest(), $message);
420  if (is_array($expectedResponseDetails)) {
421  $this->assertInstanceOf($expectedResponseDetails['type'], $response);
422  $this->assertEquals($expectedResponseDetails['statusCode'], $response->getStatusCode());
423  $this->assertEquals($expectedResponseDetails['reasonPhrase'], $response->getReasonPhrase());
424  if (isset($expectedResponseDetails['content'])) {
425  $this->assertContains($expectedResponseDetails['content'], $response->getBody()->getContents());
426  }
427  $this->assertEquals($expectedResponseDetails['headers'], $response->getHeaders());
428  }
429  }
430 
435  {
436  ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask'] = '-1';
437  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_handling'] = '/fail/';
438  ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_handling_statheader'] = 'HTTP/1.0 503 Service Temporarily Unavailable
439 X-TYPO3-Additional-Header: Banana Stand';
440  // faking getIndpEnv() variables
441  $_SERVER['REQUEST_URI'] = '/unit-test/';
442  $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
443  $_SERVER['HTTP_HOST'] = 'localhost';
444  $_SERVER['SSL_SESSION_ID'] = true;
445  ‪$GLOBALS['TYPO3_REQUEST'] = [];
447  $this->‪prophesizeGetUrl();
448  $subject = new ‪ErrorController();
449  $response = $subject->unavailableAction(new ‪ServerRequest(), 'custom message');
450 
451  $expectedResponseDetails = [
452  'type' => HtmlResponse::class,
453  'statusCode' => 503,
454  'reasonPhrase' => 'Service Temporarily Unavailable',
455  'headers' => [
456  'Content-Type' => ['text/html; charset=utf-8'],
457  'X-TYPO3-Additional-Header' => ['Banana Stand'],
458  ],
459  ];
460  $this->assertInstanceOf($expectedResponseDetails['type'], $response);
461  $this->assertEquals($expectedResponseDetails['statusCode'], $response->getStatusCode());
462  $this->assertEquals($expectedResponseDetails['reasonPhrase'], $response->getReasonPhrase());
463  if (isset($expectedResponseDetails['content'])) {
464  $this->assertContains($expectedResponseDetails['content'], $response->getBody()->getContents());
465  }
466  $this->assertEquals($expectedResponseDetails['headers'], $response->getHeaders());
467  }
468 
472  public function ‪mockedUserFunctionCall($params)
473  {
474  return '<p>It\'s magic, Michael: ' . $params['reasonText'] . '</p>';
475  }
476 
477  private function ‪prophesizeErrorPageController(): void
478  {
479  $errorPageControllerProphecy = $this->prophesize(ErrorPageController::class);
480  $errorPageControllerProphecy->errorAction(Argument::cetera())
481  ->will(
482  function (‪$args) {
483  return 'Reason: ' . ‪$args[1];
484  }
485  );
486  GeneralUtility::addInstance(ErrorPageController::class, $errorPageControllerProphecy->reveal());
487  }
488 
489  private function ‪prophesizeGetUrl(): void
490  {
491  $streamProphecy = $this->prophesize(StreamInterface::class);
492  $prefixPageResponseProphecy = $this->prophesize(Response::class);
493  $prefixPageResponseProphecy->getHeaders()->willReturn([]);
494  $prefixPageResponseProphecy->getBody()->willReturn($streamProphecy);
495  $prefixPageResponseProphecy->getStatusCode()->willReturn(200);
496  $prefixPageResponseProphecy->getHeaderLine('Content-Type')->willReturn('text/html; charset=utf-8');
497  $requestFactoryProphecy = $this->prophesize(RequestFactory::class);
498  $requestFactoryProphecy->request(Argument::cetera())->willReturn($prefixPageResponseProphecy->reveal());
499  GeneralUtility::addInstance(RequestFactory::class, $requestFactoryProphecy->reveal());
500  }
501 }
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\prophesizeGetUrl
‪prophesizeGetUrl()
Definition: ErrorControllerTest.php:489
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\tearDown
‪tearDown()
Definition: ErrorControllerTest.php:38
‪TYPO3\CMS\Core\Controller\ErrorPageController
Definition: ErrorPageController.php:31
‪$args
‪$args
Definition: checkIntegrityCsvFixtures.php:230
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\prophesizeErrorPageController
‪prophesizeErrorPageController()
Definition: ErrorControllerTest.php:477
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\pageNotFoundHandlingReturnsResponseFromPrefix
‪pageNotFoundHandlingReturnsResponseFromPrefix()
Definition: ErrorControllerTest.php:187
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\accessDeniedDataProvider
‪array accessDeniedDataProvider()
Definition: ErrorControllerTest.php:227
‪TYPO3\CMS\Frontend\Controller\ErrorController
Definition: ErrorController.php:35
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\unavailableHandlingThrowsExceptionIfNotConfigured
‪unavailableHandlingThrowsExceptionIfNotConfigured()
Definition: ErrorControllerTest.php:277
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\pageNotFoundHandlingReturnsConfiguredResponseObject
‪pageNotFoundHandlingReturnsConfiguredResponseObject( $handler, $header, $message, $expectedResponseDetails, $expectedExceptionCode=null)
Definition: ErrorControllerTest.php:150
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\pageUnavailableHandlingReturnsResponseOfPrefix
‪pageUnavailableHandlingReturnsResponseOfPrefix()
Definition: ErrorControllerTest.php:434
‪TYPO3\CMS\Core\Http\Response
Definition: Response.php:28
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\pageNotFoundHandlingThrowsExceptionIfNotConfigured
‪pageNotFoundHandlingThrowsExceptionIfNotConfigured()
Definition: ErrorControllerTest.php:47
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\accessDeniedReturnsProperHeaders
‪accessDeniedReturnsProperHeaders($handler, $header, $message, $expectedResponseDetails)
Definition: ErrorControllerTest.php:251
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\unavailableHandlingDataProvider
‪array unavailableHandlingDataProvider()
Definition: ErrorControllerTest.php:309
‪TYPO3\CMS\Frontend\Tests\Unit\Controller
Definition: ErrorControllerTest.php:3
‪TYPO3\CMS\Core\Http\ServerRequest
Definition: ServerRequest.php:35
‪TYPO3\CMS\Core\Http\RequestFactory
Definition: RequestFactory.php:27
‪TYPO3\CMS\Core\Http\RedirectResponse
Definition: RedirectResponse.php:27
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\errorPageHandlingDataProvider
‪array errorPageHandlingDataProvider()
Definition: ErrorControllerTest.php:62
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest
Definition: ErrorControllerTest.php:34
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\mockedUserFunctionCall
‪mockedUserFunctionCall($params)
Definition: ErrorControllerTest.php:472
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\unavailableHandlingDoesNotTriggerDueToDevIpMask
‪unavailableHandlingDoesNotTriggerDueToDevIpMask()
Definition: ErrorControllerTest.php:292
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Frontend\Tests\Unit\Controller\ErrorControllerTest\pageUnavailableHandlingReturnsConfiguredResponseObject
‪pageUnavailableHandlingReturnsConfiguredResponseObject( $handler, $header, $message, $expectedResponseDetails, $expectedExceptionCode=null)
Definition: ErrorControllerTest.php:397
‪TYPO3\CMS\Core\Http\HtmlResponse
Definition: HtmlResponse.php:25