[TASK] Adapt FAL dumpFile to use PSR-7 response objects
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Http / AbstractApplication.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Core\Http;
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 Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
20 use Psr\Http\Server\RequestHandlerInterface;
21 use TYPO3\CMS\Core\Core\ApplicationInterface;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23
24 /**
25 * @internal
26 */
27 abstract class AbstractApplication implements ApplicationInterface
28 {
29 /**
30 * @var string
31 */
32 protected $requestHandler = '';
33
34 /**
35 * @var string
36 */
37 protected $middlewareStack = '';
38
39 /**
40 * @param RequestHandlerInterface $requestHandler
41 * @return MiddlewareDispatcher
42 */
43 protected function createMiddlewareDispatcher(RequestHandlerInterface $requestHandler): MiddlewareDispatcher
44 {
45 $resolver = new MiddlewareStackResolver(
46 GeneralUtility::makeInstance(\TYPO3\CMS\Core\Package\PackageManager::class),
47 GeneralUtility::makeInstance(\TYPO3\CMS\Core\Service\DependencyOrderingService::class),
48 GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\CacheManager::class)->getCache('cache_core')
49 );
50 $middlewares = $resolver->resolve($this->middlewareStack);
51
52 return new MiddlewareDispatcher($requestHandler, $middlewares);
53 }
54
55 /**
56 * Outputs content
57 *
58 * @param ResponseInterface $response
59 */
60 protected function sendResponse(ResponseInterface $response)
61 {
62 if ($response instanceof NullResponse) {
63 return;
64 }
65
66 // @todo This requires some merge strategy or header callback handling
67 if (!headers_sent()) {
68 // If the response code was not changed by legacy code (still is 200)
69 // then allow the PSR-7 response object to explicitly set it.
70 // Otherwise let legacy code take precedence.
71 // This code path can be deprecated once we expose the response object to third party code
72 if (http_response_code() === 200) {
73 header('HTTP/' . $response->getProtocolVersion() . ' ' . $response->getStatusCode() . ' ' . $response->getReasonPhrase());
74 }
75
76 foreach ($response->getHeaders() as $name => $values) {
77 header($name . ': ' . implode(', ', $values));
78 }
79 }
80 $body = $response->getBody();
81 if ($body instanceof SelfEmittableStreamInterface) {
82 // Optimization for streams that use php functions like readfile() as fastpath for serving files.
83 $body->emit();
84 } else {
85 echo $body->__toString();
86 }
87 }
88
89 /**
90 * @param ServerRequestInterface $request
91 * @return ResponseInterface
92 */
93 protected function handle(ServerRequestInterface $request): ResponseInterface
94 {
95 $requestHandler = GeneralUtility::makeInstance($this->requestHandler);
96 $dispatcher = $this->createMiddlewareDispatcher($requestHandler);
97
98 return $dispatcher->handle($request);
99 }
100
101 /**
102 * Set up the application and shut it down afterwards
103 *
104 * @param callable $execute
105 */
106 final public function run(callable $execute = null)
107 {
108 try {
109 $response = $this->handle(
110 \TYPO3\CMS\Core\Http\ServerRequestFactory::fromGlobals()
111 );
112 if ($execute !== null) {
113 call_user_func($execute);
114 }
115 } catch (ImmediateResponseException $exception) {
116 $response = $exception->getResponse();
117 }
118
119 $this->sendResponse($response);
120 }
121 }