Passed
Push — master ( d94b1b...759e8d )
by
unknown
25:31 queued 11:11
created

ErrorController   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 141
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 21
eloc 40
dl 0
loc 141
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A accessDeniedAction() 0 10 3
A internalErrorAction() 0 10 4
A unavailableAction() 0 10 4
A isPageUnavailableHandlerConfigured() 0 3 1
A getErrorHandlerFromSite() 0 11 3
A pageNotFoundAction() 0 10 3
A handleDefaultError() 0 10 3
1
<?php
2
3
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
namespace TYPO3\CMS\Frontend\Controller;
19
20
use Psr\Http\Message\ResponseInterface;
21
use Psr\Http\Message\ServerRequestInterface;
22
use TYPO3\CMS\Core\Controller\ErrorPageController;
23
use TYPO3\CMS\Core\Error\Http\InternalServerErrorException;
24
use TYPO3\CMS\Core\Error\Http\PageNotFoundException;
25
use TYPO3\CMS\Core\Error\Http\ServiceUnavailableException;
26
use TYPO3\CMS\Core\Error\PageErrorHandler\PageErrorHandlerInterface;
27
use TYPO3\CMS\Core\Error\PageErrorHandler\PageErrorHandlerNotConfiguredException;
28
use TYPO3\CMS\Core\Http\HtmlResponse;
29
use TYPO3\CMS\Core\Http\JsonResponse;
30
use TYPO3\CMS\Core\Site\Entity\Site;
31
use TYPO3\CMS\Core\Utility\GeneralUtility;
32
33
/**
34
 * Handles error requests,
35
 * returns a response object.
36
 */
37
class ErrorController
38
{
39
    /**
40
     * Used for creating a 500 response ("Internal Server Error"), usually due some misconfiguration
41
     * but if configured, a RedirectResponse could be returned as well.
42
     *
43
     * @param ServerRequestInterface $request
44
     * @param string $message
45
     * @param array $reasons
46
     * @return ResponseInterface
47
     * @throws InternalServerErrorException
48
     */
49
    public function internalErrorAction(ServerRequestInterface $request, string $message, array $reasons = []): ResponseInterface
50
    {
51
        if (!$this->isPageUnavailableHandlerConfigured()) {
52
            throw new InternalServerErrorException($message, 1607585445);
53
        }
54
        $errorHandler = $this->getErrorHandlerFromSite($request, 500);
55
        if ($errorHandler instanceof PageErrorHandlerInterface) {
56
            return $errorHandler->handlePageError($request, $message, $reasons);
57
        }
58
        return $this->handleDefaultError($request, 500, $message ?: 'Internal Server Error');
59
    }
60
61
    /**
62
     * Used for creating a 503 response ("Service Unavailable"), to be used for maintenance mode
63
     * or when the server is overloaded, a RedirectResponse could be returned as well.
64
     *
65
     * @param ServerRequestInterface $request
66
     * @param string $message
67
     * @param array $reasons
68
     * @return ResponseInterface
69
     * @throws ServiceUnavailableException
70
     */
71
    public function unavailableAction(ServerRequestInterface $request, string $message, array $reasons = []): ResponseInterface
72
    {
73
        if (!$this->isPageUnavailableHandlerConfigured()) {
74
            throw new ServiceUnavailableException($message, 1518472181);
75
        }
76
        $errorHandler = $this->getErrorHandlerFromSite($request, 503);
77
        if ($errorHandler instanceof PageErrorHandlerInterface) {
78
            return $errorHandler->handlePageError($request, $message, $reasons);
79
        }
80
        return $this->handleDefaultError($request, 503, $message ?: 'Service Unavailable');
81
    }
82
83
    /**
84
     * Used for creating a 404 response ("Page Not Found"),
85
     * but if configured, a RedirectResponse could be returned as well.
86
     *
87
     * @param ServerRequestInterface $request
88
     * @param string $message
89
     * @param array $reasons
90
     * @return ResponseInterface
91
     * @throws PageNotFoundException
92
     */
93
    public function pageNotFoundAction(ServerRequestInterface $request, string $message, array $reasons = []): ResponseInterface
94
    {
95
        $errorHandler = $this->getErrorHandlerFromSite($request, 404);
96
        if ($errorHandler instanceof PageErrorHandlerInterface) {
97
            return $errorHandler->handlePageError($request, $message, $reasons);
98
        }
99
        try {
100
            return $this->handleDefaultError($request, 404, $message);
101
        } catch (\RuntimeException $e) {
102
            throw new PageNotFoundException($message, 1518472189);
103
        }
104
    }
105
106
    /**
107
     * Used for creating a 403 response ("Access denied"),
108
     * but if configured, a RedirectResponse could be returned as well.
109
     *
110
     * @param ServerRequestInterface $request
111
     * @param string $message
112
     * @param array $reasons
113
     * @return ResponseInterface
114
     * @throws PageNotFoundException
115
     */
116
    public function accessDeniedAction(ServerRequestInterface $request, string $message, array $reasons = []): ResponseInterface
117
    {
118
        $errorHandler = $this->getErrorHandlerFromSite($request, 403);
119
        if ($errorHandler instanceof PageErrorHandlerInterface) {
120
            return $errorHandler->handlePageError($request, $message, $reasons);
121
        }
122
        try {
123
            return $this->handleDefaultError($request, 403, $message);
124
        } catch (\RuntimeException $e) {
125
            throw new PageNotFoundException($message, 1518472195);
126
        }
127
    }
128
129
    /**
130
     * Checks whether the devIPMask matches the current visitor's IP address.
131
     * Note: the name of this method is a misnomer (legacy code),
132
     *
133
     * @return bool True if the server error handler should be used.
134
     */
135
    protected function isPageUnavailableHandlerConfigured(): bool
136
    {
137
        return !GeneralUtility::cmpIP(GeneralUtility::getIndpEnv('REMOTE_ADDR'), $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask']);
138
    }
139
140
    /**
141
     * Checks if a site is configured, and an error handler is configured for this specific status code.
142
     *
143
     * @param ServerRequestInterface $request
144
     * @param int $statusCode
145
     * @return PageErrorHandlerInterface|null
146
     */
147
    protected function getErrorHandlerFromSite(ServerRequestInterface $request, int $statusCode): ?PageErrorHandlerInterface
148
    {
149
        $site = $request->getAttribute('site');
150
        if ($site instanceof Site) {
151
            try {
152
                return $site->getErrorHandler($statusCode);
153
            } catch (PageErrorHandlerNotConfiguredException $e) {
154
                // No error handler found, so fallback back to the generic TYPO3 error handler.
155
            }
156
        }
157
        return null;
158
    }
159
160
    /**
161
     * Ensures that a response object is created as a "fallback" when no error handler is configured.
162
     *
163
     * @param ServerRequestInterface $request
164
     * @param int $statusCode
165
     * @param string $reason
166
     * @return ResponseInterface
167
     */
168
    protected function handleDefaultError(ServerRequestInterface $request, int $statusCode, string $reason = ''): ResponseInterface
169
    {
170
        if (strpos($request->getHeaderLine('Accept'), 'application/json') !== false) {
171
            return new JsonResponse(['reason' => $reason], $statusCode);
172
        }
173
        $content = GeneralUtility::makeInstance(ErrorPageController::class)->errorAction(
174
            'Page Not Found',
175
            'The page did not exist or was inaccessible.' . ($reason ? ' Reason: ' . $reason : '')
176
        );
177
        return new HtmlResponse($content, $statusCode);
178
    }
179
}
180