Passed
Push — master ( 00c2c4...dd81fa )
by Daniel
06:52
created

PicoAssetResponse::setContentSecurityPolicy()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 9
ccs 0
cts 5
cp 0
rs 10
cc 2
nc 2
nop 1
crap 6
1
<?php
2
/**
3
 * CMS Pico - Create websites using Pico CMS for Nextcloud.
4
 *
5
 * @copyright Copyright (c) 2019, Daniel Rudolf (<[email protected]>)
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License as
11
 * published by the Free Software Foundation, either version 3 of the
12
 * License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
declare(strict_types=1);
24
25
namespace OCA\CMSPico\Http;
26
27
use OCA\CMSPico\Model\PicoAsset;
28
use OCP\AppFramework\Http\DownloadResponse;
29
use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
30
31
class PicoAssetResponse extends DownloadResponse
32
{
33
	/** @var PicoAsset */
34
	private $asset;
35
36
	/** @var array<string,int> */
37
	private $cacheFor = [
38
		'application/font-sfnt' => 2592000,
39
		'application/font-woff' => 2592000,
40
		'application/javascript' => 604800,
41
		'application/json' => 604800,
42
		'application/vnd.ms-fontobject' => 2592000,
43
		'image/bmp' => 2592000,
44
		'image/gif' => 2592000,
45
		'image/jpeg' => 2592000,
46
		'image/png' => 2592000,
47
		'image/svg+xml' => 2592000,
48
		'image/tiff' => 2592000,
49
		'image/vnd.microsoft.icon' => 2592000,
50
		'image/webp' => 2592000,
51
		'image/x-icon' => 2592000,
52
		'text/css' => 604800,
53
	];
54
55
	/**
56
	 * PicoAssetResponse constructor.
57
	 *
58
	 * @param PicoAsset $asset
59
	 * @param bool      $enableCache
60
	 * @param bool      $enableSecureMimeType
61
	 */
62 3
	public function __construct(PicoAsset $asset, bool $enableCache = true, bool $enableSecureMimeType = true)
63
	{
64 3
		$this->asset = $asset;
65
66 3
		parent::setContentSecurityPolicy(new PicoContentSecurityPolicy());
67
68 3
		$mimeType = $asset->getMimeType();
69 3
		$contentType = $enableSecureMimeType ? $asset->getSecureMimeType() : $mimeType;
70
71 3
		parent::__construct($asset->getName(), $contentType);
72
73 3
		$this->setETag($asset->getEtag());
74 3
		$this->setLastModified($asset->getLastModified());
75
76 3
		if ($enableCache && isset($this->cacheFor[$mimeType])) {
77
			$this->cacheFor($this->cacheFor[$mimeType], $asset->isPublicAsset());
78
		} else {
79 3
			$this->cacheFor(0);
80
		}
81 3
	}
82
83
	/**
84
	 * @param EmptyContentSecurityPolicy $csp
85
	 *
86
	 * @return $this
87
	 */
88
	public function setContentSecurityPolicy(EmptyContentSecurityPolicy $csp): self
89
	{
90
		if (!($csp instanceof PicoContentSecurityPolicy)) {
91
			// Pico really needs its own CSP...
92
			return $this;
93
		}
94
95
		parent::setContentSecurityPolicy($csp);
96
		return $this;
97
	}
98
99
	/**
100
	 * @param int  $cacheSeconds
101
	 * @param bool $public
102
	 *
103
	 * @return $this
104
	 */
105 3
	public function cacheFor(int $cacheSeconds, bool $public = false, bool $immutable = false): self
106
	{
107 3
		if ($cacheSeconds > 0) {
108
			$pragma = $public ? 'public' : 'private';
109
			$maxAge = 'max-age=' . $cacheSeconds;
110
111
			$this->addHeader('Cache-Control', $pragma . ',' . $maxAge . ($immutable ? ', immutable' : ''));
112
			$this->addHeader('Pragma', $pragma);
113
114
			try {
115
				$expires = new \DateTime();
116
				$expires->add(new \DateInterval('PT' . $cacheSeconds . 'S'));
117
				$this->addHeader('Expires', $expires->format(\DateTime::RFC2822));
118
			} catch (\Exception $e) {
119
				// ignore DateTime and DateInterval exceptions
120
			}
121
		} else {
122 3
			$this->addHeader('Cache-Control', 'no-cache, must-revalidate');
123 3
			$this->addHeader('Pragma', 'no-cache');
124 3
			$this->addHeader('Expires', null);
125
		}
126
127 3
		return $this;
128
	}
129
130
	/**
131
	 * @return $this
132
	 */
133
	public function noCache(): self
134
	{
135
		$this->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
136
		$this->addHeader('Pragma', 'no-cache');
137
		$this->addHeader('Expires', null);
138
139
		return $this;
140
	}
141
142
	/**
143
	 * @return string
144
	 */
145 1
	public function render(): string
146
	{
147 1
		return $this->asset->getContent();
148
	}
149
}
150