Completed
Push — master ( d60977...1e7efd )
by Robin
02:37
created

SearchPlugin   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 95
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 13

Importance

Changes 0
Metric Value
wmc 15
lcom 1
cbo 13
dl 0
loc 95
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A initialize() 0 9 1
A propFindHandler() 0 5 2
A getHTTPMethods() 0 8 2
A optionHandler() 0 5 2
C searchHandler() 0 33 7
1
<?php
2
/**
3
 * @copyright Copyright (c) 2017 Robin Appelman <[email protected]>
4
 *
5
 * @license GNU AGPL version 3 or any later version
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Affero General Public License as
9
 * published by the Free Software Foundation, either version 3 of the
10
 * License, or (at your option) any later version.
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
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 *
20
 */
21
22
namespace SearchDAV\DAV;
23
24
use Sabre\DAV\Exception\BadRequest;
25
use Sabre\DAV\Exception\Forbidden;
26
use Sabre\DAV\INode;
27
use Sabre\DAV\Node;
28
use Sabre\DAV\PropFind;
29
use Sabre\DAV\Server;
30
use Sabre\DAV\ServerPlugin;
31
use Sabre\DAV\Xml\Element\Response;
32
use Sabre\DAV\Xml\Response\MultiStatus;
33
use Sabre\HTTP\RequestInterface;
34
use Sabre\HTTP\ResponseInterface;
35
use Sabre\Xml\ParseException;
36
use Sabre\Xml\Writer;
37
use SearchDAV\Backend\ISearchBackend;
38
use SearchDAV\Backend\SearchPropertyDefinition;
39
use SearchDAV\Backend\SearchResult;
40
use SearchDAV\XML\BasicSearch;
41
use SearchDAV\XML\BasicSearchSchema;
42
use SearchDAV\XML\PropDesc;
43
use SearchDAV\XML\QueryDiscoverResponse;
44
use SearchDAV\XML\Scope;
45
use SearchDAV\XML\SupportedQueryGrammar;
46
47
class SearchPlugin extends ServerPlugin {
48
	/** @var Server */
49
	private $server;
50
51
	/** @var ISearchBackend */
52
	private $searchBackend;
53
54
	/** @var QueryParser */
55
	private $queryParser;
56
57
	/** @var PathHelper */
58
	private $pathHelper;
59
60
	/** @var SearchHandler */
61
	private $search;
62
63
	/** @var DiscoverHandler */
64
	private $discover;
65
66
	public function __construct(ISearchBackend $searchBackend) {
67
		$this->searchBackend = $searchBackend;
68
		$this->queryParser = new QueryParser();
69
	}
70
71
	public function initialize(Server $server) {
72
		$this->server = $server;
73
		$this->pathHelper = new PathHelper($server);
74
		$this->search = new SearchHandler($this->searchBackend, $this->pathHelper, $server);
75
		$this->discover = new DiscoverHandler($this->searchBackend, $this->pathHelper, $this->queryParser);
76
		$server->on('method:SEARCH', [$this, 'searchHandler']);
77
		$server->on('afterMethod:OPTIONS', [$this, 'optionHandler']);
78
		$server->on('propFind', [$this, 'propFindHandler']);
79
	}
80
81
	public function propFindHandler(PropFind $propFind, INode $node) {
0 ignored issues
show
Unused Code introduced by
The parameter $node is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
82
		if ($propFind->getPath() === $this->searchBackend->getArbiterPath()) {
83
			$propFind->handle('{DAV:}supported-query-grammar-set', new SupportedQueryGrammar());
84
		}
85
	}
86
87
	/**
88
	 * SEARCH is allowed for users files
89
	 *
90
	 * @param string $uri
91
	 * @return array
92
	 */
93
	public function getHTTPMethods($uri) {
94
		$path = $this->pathHelper->getPathFromUri($uri);
95
		if ($this->searchBackend->getArbiterPath() === $path) {
96
			return ['SEARCH'];
97
		} else {
98
			return [];
99
		}
100
	}
101
102
	public function optionHandler(RequestInterface $request, ResponseInterface $response) {
103
		if ($request->getPath() === $this->searchBackend->getArbiterPath()) {
104
			$response->addHeader('DASL', '<DAV:basicsearch>');
105
		}
106
	}
107
108
	public function searchHandler(RequestInterface $request, ResponseInterface $response) {
109
		$contentType = $request->getHeader('Content-Type');
110
111
		// Currently we only support xml search queries
112
		if ((strpos($contentType, 'text/xml') === false) && (strpos($contentType, 'application/xml') === false)) {
113
			return true;
114
		}
115
116
		if ($request->getPath() !== $this->searchBackend->getArbiterPath()) {
117
			return true;
118
		}
119
120
		try {
121
			$xml = $this->queryParser->parse(
122
				$request->getBody(),
123
				$request->getUrl(),
124
				$documentType
125
			);
126
		} catch (ParseException $e) {
127
			$response->setStatus(400);
128
			$response->setBody('Parse error: ' . $e->getMessage());
129
			return false;
130
		}
131
132
		switch ($documentType) {
133
			case '{DAV:}searchrequest':
134
				return $this->search->handleSearchRequest($xml, $response);
135
			case '{DAV:}query-schema-discovery':
136
				return $this->discover->handelDiscoverRequest($xml, $request, $response);
137
			default:
138
				throw new BadRequest('Unexpected document type: ' . $documentType . ' for this Content-Type');
139
		}
140
	}
141
}
142