Completed
Push — master ( 76ba1c...91e148 )
by Thomas
23:00 queued 09:19
created

ChunkingPlugin   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 76
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
dl 0
loc 76
rs 10
c 0
b 0
f 0
wmc 8
lcom 1
cbo 7

4 Methods

Rating   Name   Duplication   Size   Complexity  
A initialize() 0 4 1
A beforeMove() 0 10 2
A performMove() 0 20 2
A verifySize() 0 10 3
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
23
namespace OCA\DAV\Upload;
24
25
26
use OCA\DAV\Connector\Sabre\File;
27
use Sabre\DAV\Exception\BadRequest;
28
use Sabre\DAV\Server;
29
use Sabre\DAV\ServerPlugin;
30
31
class ChunkingPlugin extends ServerPlugin {
32
33
	/** @var Server */
34
	private $server;
35
	/** @var FutureFile */
36
	private $sourceNode;
37
38
	/**
39
	 * @inheritdoc
40
	 */
41
	function initialize(Server $server) {
42
		$server->on('beforeMove', [$this, 'beforeMove']);
43
		$this->server = $server;
44
	}
45
46
	/**
47
	 * @param string $sourcePath source path
48
	 * @param string $destination destination path
49
	 */
50
	function beforeMove($sourcePath, $destination) {
51
		$this->sourceNode = $this->server->tree->getNodeForPath($sourcePath);
52
		if (!$this->sourceNode instanceof FutureFile) {
53
			// skip handling as the source is not a chunked FutureFile
54
			return;
55
		}
56
57
		$this->verifySize();
58
		return $this->performMove($sourcePath, $destination);
59
	}
60
61
	/**
62
	 * Move handler for future file.
63
	 *
64
	 * This overrides the default move behavior to prevent Sabre
65
	 * to delete the target file before moving. Because deleting would
66
	 * lose the file id and metadata.
67
	 *
68
	 * @param string $path source path
69
	 * @param string $destination destination path
70
	 * @return bool|void false to stop handling, void to skip this handler
71
	 */
72
	public function performMove($path, $destination) {
73
		if (!$this->server->tree->nodeExists($destination)) {
74
			// skip and let the default handler do its work
75
			return;
76
		}
77
78
		// do a move manually, skipping Sabre's default "delete" for existing nodes
79
		$this->server->tree->move($path, $destination);
80
81
		// trigger all default events (copied from CorePlugin::move)
82
		$this->server->emit('afterMove', [$path, $destination]);
83
		$this->server->emit('afterUnbind', [$path]);
84
		$this->server->emit('afterBind', [$destination]);
85
86
		$response = $this->server->httpResponse;
87
		$response->setHeader('Content-Length', '0');
88
		$response->setStatus(204);
89
90
		return false;
91
	}
92
93
	/**
94
	 * @throws BadRequest
95
	 */
96
	private function verifySize() {
97
		$expectedSize = $this->server->httpRequest->getHeader('OC-Total-Length');
98
		if ($expectedSize === null) {
99
			return;
100
		}
101
		$actualSize = $this->sourceNode->getSize();
102
		if ((int)$expectedSize !== $actualSize) {
103
			throw new BadRequest("Chunks on server do not sum up to $expectedSize but to $actualSize");
104
		}
105
	}
106
}
107