Completed
Pull Request — master (#31851)
by Jörn Friedrich
11:50
created

Server::__construct()   D

Complexity

Conditions 14
Paths 128

Size

Total Lines 225

Duplication

Lines 8
Ratio 3.56 %

Importance

Changes 0
Metric Value
cc 14
nc 128
nop 2
dl 8
loc 225
rs 4.8266
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @author Christoph Wurst <[email protected]>
4
 * @author Georg Ehrke <[email protected]>
5
 * @author Lukas Reschke <[email protected]>
6
 * @author Roeland Jago Douma <[email protected]>
7
 * @author Thomas Citharel <[email protected]>
8
 * @author Thomas Müller <[email protected]>
9
 * @author Vincent Petry <[email protected]>
10
 *
11
 * @copyright Copyright (c) 2018, ownCloud GmbH
12
 * @license AGPL-3.0
13
 *
14
 * This code is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License, version 3,
16
 * as published by the Free Software Foundation.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License, version 3,
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
25
 *
26
 */
27
namespace OCA\DAV;
28
29
use OCA\DAV\AppInfo\PluginManager;
30
use OCA\DAV\CalDAV\Schedule\IMipPlugin;
31
use OCA\DAV\CardDAV\ImageExportPlugin;
32
use OCA\DAV\Connector\Sabre\Auth;
33
use OCA\DAV\Connector\Sabre\BlockLegacyClientPlugin;
34
use OCA\DAV\Connector\Sabre\CommentPropertiesPlugin;
35
use OCA\DAV\Connector\Sabre\CopyEtagHeaderPlugin;
36
use OCA\DAV\Connector\Sabre\CorsPlugin;
37
use OCA\DAV\Connector\Sabre\DavAclPlugin;
38
use OCA\DAV\Connector\Sabre\DummyGetResponsePlugin;
39
use OCA\DAV\Connector\Sabre\FakeLockerPlugin;
40
use OCA\DAV\Connector\Sabre\FilesPlugin;
41
use OCA\DAV\Connector\Sabre\FilesReportPlugin;
42
use OCA\DAV\Connector\Sabre\MaintenancePlugin;
43
use OCA\DAV\Connector\Sabre\QuotaPlugin;
44
use OCA\DAV\Connector\Sabre\SharesPlugin;
45
use OCA\DAV\Connector\Sabre\TagsPlugin;
46
use OCA\DAV\Connector\Sabre\ValidateRequestPlugin;
47
use OCA\DAV\DAV\FileCustomPropertiesBackend;
48
use OCA\DAV\DAV\FileCustomPropertiesPlugin;
49
use OCA\DAV\DAV\LazyOpsPlugin;
50
use OCA\DAV\DAV\MiscCustomPropertiesBackend;
51
use OCA\DAV\DAV\PublicAuth;
52
use OCA\DAV\Files\BrowserErrorPagePlugin;
53
use OCA\DAV\Files\PreviewPlugin;
54
use OCA\DAV\Files\ZsyncPlugin;
55
use OCA\DAV\JobStatus\Entity\JobStatusMapper;
56
use OCA\DAV\JobStatus\EventStreamPlugin;
57
use OCA\DAV\SystemTag\SystemTagPlugin;
58
use OCA\DAV\Upload\ChunkingPlugin;
59
use OCA\DAV\Upload\ChunkingPluginZsync;
60
use OCP\IRequest;
61
use OCP\SabrePluginEvent;
62
use Sabre\CardDAV\VCFExportPlugin;
63
use Sabre\DAV\Auth\Plugin;
64
65
class Server {
66
67
	/** @var Connector\Sabre\Server  */
68
	public $server;
69
70
	/** @var string */
71
	private $baseUri;
72
	/** @var IRequest */
73
	private $request;
74
75
	/**
76
	 * Server constructor.
77
	 *
78
	 * @param IRequest $request
79
	 * @param string $baseUri
80
	 * @throws \OCP\AppFramework\QueryException
81
	 * @throws \Sabre\DAV\Exception
82
	 */
83
	public function __construct(IRequest $request, $baseUri) {
84
		$this->request = $request;
85
		$this->baseUri = $baseUri;
86
		$logger = \OC::$server->getLogger();
87
		$dispatcher = \OC::$server->getEventDispatcher();
88
89
		$root = new RootCollection();
90
		$tree = new \OCA\DAV\Tree($root);
91
		$this->server = new \OCA\DAV\Connector\Sabre\Server($tree);
92
93
		$config = \OC::$server->getConfig();
94
		if ($config->getSystemValue('dav.enable.async', true)) {
95
			$this->server->addPlugin(new LazyOpsPlugin(
96
				\OC::$server->getUserSession(),
97
				\OC::$server->getURLGenerator(),
98
				\OC::$server->getShutdownHandler(),
99
				\OC::$server->query(JobStatusMapper::class),
100
				\OC::$server->getLogger()
101
			));
102
		}
103
104
		// Backends
105
		$authBackend = new Auth(
106
			\OC::$server->getSession(),
107
			\OC::$server->getUserSession(),
108
			\OC::$server->getRequest(),
109
			\OC::$server->getTwoFactorAuthManager(),
110
			\OC::$server->getAccountModuleManager()
111
		);
112
113
		// Set URL explicitly due to reverse-proxy situations
114
		$this->server->httpRequest->setUrl($this->request->getRequestUri());
115
		$this->server->setBaseUri($this->baseUri);
116
117
		$this->server->addPlugin(new MaintenancePlugin($config));
118
		$this->server->addPlugin(new ValidateRequestPlugin('dav'));
119
		$this->server->addPlugin(new BlockLegacyClientPlugin($config));
120
		$this->server->addPlugin(new CorsPlugin(\OC::$server->getUserSession()));
121
		$authPlugin = new Plugin();
122
		$authPlugin->addBackend(new PublicAuth());
123
		$this->server->addPlugin($authPlugin);
124
125
		// allow setup of additional auth backends
126
		$event = new SabrePluginEvent($this->server);
127
		$dispatcher->dispatch('OCA\DAV\Connector\Sabre::authInit', $event);
128
129
		// because we are throwing exceptions this plugin has to be the last one
130
		$authPlugin->addBackend($authBackend);
131
132
		// debugging
133
		if (\OC::$server->getConfig()->getSystemValue('debug', false)) {
134
			$this->server->addPlugin(new \Sabre\DAV\Browser\Plugin());
135
		} else {
136
			$this->server->addPlugin(new DummyGetResponsePlugin());
137
		}
138
139
		$this->server->addPlugin(new \OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin('webdav', $logger));
140
		$this->server->addPlugin(new \OCA\DAV\Connector\Sabre\LockPlugin());
141
		$this->server->addPlugin(new \Sabre\DAV\Sync\Plugin());
142
143
		// ACL plugin not used in files subtree, also it causes issues
144
		// with performance and locking issues because it will query
145
		// every parent node which might trigger an implicit rescan in the
146
		// case of external storages with update detection
147
		if (!$this->isRequestForSubtree(['files'])) {
148
			// acl
149
			$acl = new DavAclPlugin();
150
			$acl->principalCollectionSet = [
151
				'principals/users', 'principals/groups'
152
			];
153
			$acl->defaultUsernamePath = 'principals/users';
0 ignored issues
show
Bug introduced by
The property defaultUsernamePath does not seem to exist in OCA\DAV\Connector\Sabre\DavAclPlugin.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
154
			$this->server->addPlugin($acl);
155
		}
156
157
		// calendar plugins
158
		if ($this->isRequestForSubtree(['calendars', 'public-calendars', 'principals'])) {
159
			$mailer = \OC::$server->getMailer();
160
			$this->server->addPlugin(new \OCA\DAV\CalDAV\Plugin());
161
			$this->server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
162
			$this->server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin());
163
			$this->server->addPlugin(new IMipPlugin($mailer, $logger, $request));
164
			$this->server->addPlugin(new \Sabre\CalDAV\Subscriptions\Plugin());
165
			$this->server->addPlugin(new \Sabre\CalDAV\Notifications\Plugin());
166
			$this->server->addPlugin(new DAV\Sharing\Plugin($authBackend, \OC::$server->getRequest()));
167
			$this->server->addPlugin(new \OCA\DAV\CalDAV\Publishing\PublishPlugin(
168
				\OC::$server->getConfig(),
169
				\OC::$server->getURLGenerator()
170
			));
171
		}
172
173
		// addressbook plugins
174
		if ($this->isRequestForSubtree(['addressbooks', 'principals'])) {
175
			$this->server->addPlugin(new DAV\Sharing\Plugin($authBackend, \OC::$server->getRequest()));
176
			$this->server->addPlugin(new \OCA\DAV\CardDAV\Plugin());
177
			$this->server->addPlugin(new VCFExportPlugin());
178
			$this->server->addPlugin(new ImageExportPlugin(\OC::$server->getLogger()));
179
		}
180
181
		// system tags plugins
182
		$this->server->addPlugin(new SystemTagPlugin(
183
			\OC::$server->getSystemTagManager(),
184
			\OC::$server->getGroupManager(),
185
			\OC::$server->getUserSession()
186
		));
187
188
		$this->server->addPlugin(new CopyEtagHeaderPlugin());
189
		$this->server->addPlugin(new ChunkingPlugin());
190
		$this->server->addPlugin(new EventStreamPlugin());
191
192
		// Some WebDAV clients do require Class 2 WebDAV support (locking), since
193
		// we do not provide locking we emulate it using a fake locking plugin.
194 View Code Duplication
		if ($request->isUserAgent([
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
195
			'/WebDAVFS/',
196
			'/OneNote/',
197
			'/Microsoft Office OneNote 2013/',
198
			'/Microsoft-WebDAV-MiniRedir/',
199
		])) {
200
			$this->server->addPlugin(new FakeLockerPlugin());
201
		}
202
203
		if (BrowserErrorPagePlugin::isBrowserRequest($request)) {
204
			$this->server->addPlugin(new BrowserErrorPagePlugin());
205
		}
206
207
		$this->server->addPlugin(new PreviewPlugin(\OC::$server->getTimeFactory(), \OC::$server->getPreviewManager()));
208
		// wait with registering these until auth is handled and the filesystem is setup
209
		$this->server->on('beforeMethod', function () use ($root) {
210
			// custom properties plugin must be the last one
211
			$userSession = \OC::$server->getUserSession();
212
			$user = $userSession->getUser();
213
			if ($user !== null) {
214
				$userHomeView = new \OC\Files\View('/'.$user->getUID());
215
				$this->server->addPlugin(
216
					new ChunkingPluginZsync($userHomeView)
217
				);
218
219
				$this->server->addPlugin(
220
					new ZsyncPlugin($userHomeView)
221
				);
222
223
				$view = \OC\Files\Filesystem::getView();
224
				$this->server->addPlugin(
225
					new FilesPlugin(
226
						$this->server->tree,
227
						\OC::$server->getConfig(),
228
						$this->request,
229
						false,
230
						!\OC::$server->getConfig()->getSystemValue('debug', false)
231
					)
232
				);
233
234
				if ($this->isRequestForSubtree(['files', 'uploads'])) {
235
					//For files only
236
					$filePropertiesPlugin = new FileCustomPropertiesPlugin(
237
						new FileCustomPropertiesBackend(
238
							$this->server->tree,
239
							\OC::$server->getDatabaseConnection(),
240
							\OC::$server->getUserSession()->getUser()
0 ignored issues
show
Bug introduced by
It seems like \OC::$server->getUserSession()->getUser() can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
241
						)
242
					);
243
					$this->server->addPlugin($filePropertiesPlugin);
244
				} else {
245
					$miscPropertiesPlugin = new \Sabre\DAV\PropertyStorage\Plugin(
246
						new MiscCustomPropertiesBackend(
247
							$this->server->tree,
248
							\OC::$server->getDatabaseConnection(),
249
							\OC::$server->getUserSession()->getUser()
0 ignored issues
show
Bug introduced by
It seems like \OC::$server->getUserSession()->getUser() can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
250
						)
251
					);
252
					$this->server->addPlugin($miscPropertiesPlugin);
253
				}
254
255
				if ($view !== null) {
256
					$this->server->addPlugin(
257
						new QuotaPlugin($view));
258
				}
259
				$this->server->addPlugin(
260
					new TagsPlugin(
261
						$this->server->tree, \OC::$server->getTagManager()
262
					)
263
				);
264
				// TODO: switch to LazyUserFolder
265
				$userFolder = \OC::$server->getUserFolder();
266
				$this->server->addPlugin(new SharesPlugin(
267
					$this->server->tree,
268
					$userSession,
269
					\OC::$server->getShareManager()
270
				));
271
				$this->server->addPlugin(new CommentPropertiesPlugin(
272
					\OC::$server->getCommentsManager(),
273
					$userSession
274
				));
275
276
				if ($view !== null) {
277
					$this->server->addPlugin(new FilesReportPlugin(
278
						$this->server->tree,
279
						$view,
280
						\OC::$server->getSystemTagManager(),
281
						\OC::$server->getSystemTagObjectMapper(),
282
						\OC::$server->getTagManager(),
283
						$userSession,
284
						\OC::$server->getGroupManager(),
285
						$userFolder
0 ignored issues
show
Bug introduced by
It seems like $userFolder defined by \OC::$server->getUserFolder() on line 265 can be null; however, OCA\DAV\Connector\Sabre\...rtPlugin::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
286
					));
287
				}
288
				$this->server->addPlugin(
289
					new \OCA\DAV\Connector\Sabre\FilesSearchReportPlugin(
290
						\OC::$server->getSearch()
291
					)
292
				);
293
			}
294
295
			// register plugins from apps
296
			$pluginManager = new PluginManager(
297
				\OC::$server,
298
				\OC::$server->getAppManager()
299
			);
300
			foreach ($pluginManager->getAppPlugins() as $appPlugin) {
301
				$this->server->addPlugin($appPlugin);
302
			}
303
			foreach ($pluginManager->getAppCollections() as $appCollection) {
304
				$root->addChild($appCollection);
305
			}
306
		});
307
	}
308
309
	public function exec() {
310
		$this->server->exec();
311
	}
312
313
	/**
314
	 * @param string[] $subTrees
315
	 * @return bool
316
	 */
317
	private function isRequestForSubtree(array $subTrees) {
318
		foreach ($subTrees as $subTree) {
319
			$subTree = \trim($subTree, " /");
320
			if (\strpos($this->server->getRequestUri(), "$subTree/") === 0) {
321
				return true;
322
			}
323
		}
324
		return false;
325
	}
326
}
327