ILIAS  trunk Revision v13.0_alpha-62-g3b72d83f2e5
BaseDelivery.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
26use Psr\Http\Message\ResponseInterface;
28
32abstract class BaseDelivery
33{
34 protected const MIME_TYPE_MAP = __DIR__ . '/../../../FileUpload/src/mime_type_map.php';
35
36 protected array $mime_type_map;
37
38 public function __construct(
39 protected GlobalHttpState $http,
40 protected ResponseBuilder $response_builder,
41 protected ResponseBuilder $fallback_response_builder,
42 protected IsolationConfig $isolation = new IsolationConfig(false, null, null),
43 ) {
44 if (is_readable(self::MIME_TYPE_MAP)) {
45 $map = include self::MIME_TYPE_MAP;
46 }
47 $this->mime_type_map = $map ?? [];
48 }
49
55 protected function isRequestHostAllowed(): bool
56 {
57 if (!$this->isolation->isActivated()) {
58 return true;
59 }
60
61 $expected = $this->isolation->getContentHost();
62 if ($expected === null) {
63 return true;
64 }
65
66 return strcasecmp($this->http->request()->getUri()->getHost(), $expected) === 0;
67 }
68
75 protected function isRequestOnContentHost(): bool
76 {
77 if (!$this->isolation->isActivated()) {
78 return false;
79 }
80
81 $content_host = $this->isolation->getContentHost();
82 if ($content_host === null) {
83 return false;
84 }
85
86 return strcasecmp($this->http->request()->getUri()->getHost(), $content_host) === 0;
87 }
88
94 protected function notFound(ResponseInterface $r): never
95 {
96 $this->http->saveResponse($r->withStatus(404));
97 $this->http->sendResponse();
98 $this->http->close();
99 }
100
101 protected function saveAndClose(
102 ResponseInterface $r,
103 ?string $path_to_delete = null
104 ): never {
105 if ($path_to_delete !== null && file_exists($path_to_delete)) {
106 // close() ends the request, the file can only be deleted by a shutdown function,
107 // see https://mantis.ilias.de/view.php?id=48312
108 ignore_user_abort(true);
109 set_time_limit(0);
110 register_shutdown_function(static function () use ($path_to_delete): void {
111 if (file_exists($path_to_delete)) {
112 unlink($path_to_delete);
113 }
114 });
115 }
116
117 $this->http->saveResponse($r);
118 $this->http->sendResponse();
119 $this->http->close();
120 }
121
122 protected function setGeneralHeaders(
123 ResponseInterface $r,
124 string $uri,
125 string $mime_type,
126 string $file_name,
127 Disposition $disposition = Disposition::INLINE,
128 bool $isolated = true
129 ): ResponseInterface {
130 $r = $r->withHeader('X-ILIAS-FileDelivery-Method', $this->response_builder->getName());
131 $r = $r->withHeader(ResponseHeader::CONTENT_TYPE, $mime_type);
132 $r = $r->withHeader(
134 (new ContentDispositionHeader())->build($disposition->value, $file_name)
135 );
136 $r = $r->withHeader(ResponseHeader::CACHE_CONTROL, 'max-age=31536000, immutable, private');
137 $r = $r->withHeader(
139 date("D, j M Y H:i:s", strtotime('+5 days')) . " GMT"
140 );
141
142 // files delivered on the ILIAS domain are same-origin, the cross-origin headers do not apply
143 return $isolated ? $this->applyIsolationHeaders($r) : $r;
144 }
145
153 protected function applyIsolationHeaders(ResponseInterface $r): ResponseInterface
154 {
155 if (!$this->isolation->isActivated()) {
156 return $r;
157 }
158
159 $r = $r->withHeader(ResponseHeader::X_CONTENT_TYPE_OPTIONS, 'nosniff');
160 $r = $r->withHeader('Cross-Origin-Resource-Policy', 'cross-origin');
161 $r = $r->withHeader('Referrer-Policy', 'no-referrer');
162
163 if (($ilias_domain = $this->isolation->getIliasDomain()) !== null) {
164 $r = $r->withHeader(ResponseHeader::ACCESS_CONTROL_ALLOW_ORIGIN, $ilias_domain);
165 $r = $r->withAddedHeader('Vary', 'Origin');
166 }
167
168 return $r;
169 }
170}
saveAndClose(ResponseInterface $r, ?string $path_to_delete=null)
setGeneralHeaders(ResponseInterface $r, string $uri, string $mime_type, string $file_name, Disposition $disposition=Disposition::INLINE, bool $isolated=true)
applyIsolationHeaders(ResponseInterface $r)
When isolation is active, harden delivery responses:
isRequestHostAllowed()
When user content isolation is active, only requests targeting the configured content domain may be s...
notFound(ResponseInterface $r)
Send an empty 404 response and terminate.
__construct(protected GlobalHttpState $http, protected ResponseBuilder $response_builder, protected ResponseBuilder $fallback_response_builder, protected IsolationConfig $isolation=new IsolationConfig(false, null, null),)
Builds the Content-Disposition header value per RFC 6266 / RFC 5987.
Read-only configuration of the IRSS User Content Isolation feature.
Interface GlobalHttpState.
Interface ResponseHeader.
static http()
Fetches the global http state from ILIAS.
if(!file_exists('../ilias.ini.php'))