Completed
Push — master ( db7984...ab328d )
by Thomas
38:41 queued 22:29
created

PreviewPlugin::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Thomas Müller <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2017, ownCloud GmbH
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
namespace OCA\DAV\Files;
23
24
use OCA\DAV\Connector\Sabre\Exception\FileLocked;
25
use OCP\AppFramework\Utility\ITimeFactory;
26
use OCP\Encryption\Exceptions\GenericEncryptionException;
27
use OCP\Files\ForbiddenException;
28
use OCP\Files\IPreviewNode;
29
use OCP\Files\StorageNotAvailableException;
30
use OCP\IPreview;
31
use OCP\Lock\LockedException;
32
use Sabre\DAV\Exception\Forbidden;
33
use Sabre\DAV\Exception\NotFound;
34
use Sabre\DAV\Exception\ServiceUnavailable;
35
use Sabre\DAV\Server;
36
use Sabre\DAV\ServerPlugin;
37
use Sabre\HTTP\RequestInterface;
38
use Sabre\HTTP\ResponseInterface;
39
40
class PreviewPlugin extends ServerPlugin {
41
42
	/** @var Server */
43
	protected $server;
44
	/** @var ITimeFactory */
45
	private $timeFactory;
46
	/** @var IPreview */
47
	private $previewManager;
48
49
	/**
50
	 * PreviewPlugin constructor.
51
	 *
52
	 * @param ITimeFactory $timeFactory
53
	 * @param IPreview $previewManager
54
	 */
55
	public function __construct(ITimeFactory $timeFactory, IPreview $previewManager) {
56
		$this->timeFactory = $timeFactory;
57
		$this->previewManager = $previewManager;
58
	}
59
60
	/**
61
	 * Initializes the plugin and registers event handlers
62
	 *
63
	 * @param Server $server
64
	 * @return void
65
	 */
66
	public function initialize(Server $server) {
67
		$this->server = $server;
68
		$this->server->on('method:GET', [$this, 'httpGet'], 90);
69
	}
70
71
	/**
72
	 * Intercepts GET requests on node urls ending with ?preview.
73
	 * The node has to implement IPreviewNode
74
	 *
75
	 * @param RequestInterface $request
76
	 * @param ResponseInterface $response
77
	 * @return bool
78
	 * @throws NotFound
79
	 * @throws \Sabre\DAVACL\Exception\NeedPrivileges
80
	 * @throws \Sabre\DAV\Exception\NotAuthenticated
81
	 * @throws Forbidden
82
	 * @throws FileLocked
83
	 * @throws ServiceUnavailable
84
	 */
85
	public function httpGet(RequestInterface $request, ResponseInterface $response) {
86
		$queryParams = $request->getQueryParameters();
87
		if (!\array_key_exists('preview', $queryParams)) {
88
			return true;
89
		}
90
91
		$path = $request->getPath();
92
		$node = $this->server->tree->getNodeForPath($path);
93
94
		if (!$node instanceof IFileNode) {
95
			return false;
96
		}
97
		$fileNode = $node->getNode();
98
		if (!$fileNode instanceof IPreviewNode) {
99
			return false;
100
		}
101
102
		// Checking ACL, if available.
103
		if ($aclPlugin = $this->server->getPlugin('acl')) {
104
			/** @var \Sabre\DAVACL\Plugin $aclPlugin */
105
			$aclPlugin->checkPrivileges($path, '{DAV:}read');
106
		}
107
108
		try {
109
			if (!$this->previewManager->isAvailable($fileNode)) {
0 ignored issues
show
Documentation introduced by
$fileNode is of type object<OCP\Files\IPreviewNode>, but the function expects a object<OCP\Files\FileInfo>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
110
				// no preview available or preview disabled
111
				throw new NotFound();
112
			}
113
			if ($image = $fileNode->getThumbnail($queryParams)) {
114
				if ($image === null || !$image->valid()) {
115
					throw new NotFound();
116
				}
117
				$type = $image->mimeType();
118
				if (!\in_array($type, ['image/png', 'image/jpeg', 'image/gif'])) {
119
					$type = 'application/octet-stream';
120
				}
121
122
				// Enable output buffering
123
				\ob_start();
124
				// Capture the output
125
				$image->show();
126
				$imageData = \ob_get_contents();
127
				// Clear the output buffer
128
				\ob_end_clean();
129
130
				$response->setHeader('Content-Type', $type);
131
				$response->setHeader('Content-Disposition', 'attachment');
132
				// cache 24h
133
				$response->setHeader('Cache-Control', 'max-age=86400, must-revalidate');
134
				$response->setHeader('Expires', \gmdate("D, d M Y H:i:s", $this->timeFactory->getTime() + 86400) . " GMT");
135
136
				$response->setStatus(200);
137
				$response->setBody($imageData);
138
139
				// Returning false to break the event chain
140
				return false;
141
			}
142
		} catch (GenericEncryptionException $e) {
143
			// returning 403 because some apps stops syncing if 503 is returned.
144
			throw new Forbidden('Encryption not ready: ' . $e->getMessage());
145
		} catch (StorageNotAvailableException $e) {
146
			throw new ServiceUnavailable('Failed to open file: ' . $e->getMessage());
147
		} catch (ForbiddenException $ex) {
148
			throw new Forbidden($ex->getMessage(), $ex->getRetry());
149
		} catch (LockedException $e) {
150
			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
151
		}
152
		// TODO: add forceIcon handling .... if still needed
153
		throw new NotFound();
154
	}
155
}
156