summaryrefslogtreecommitdiffstats
path: root/3rdparty/Sabre/DAV/Server.php
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/Sabre/DAV/Server.php')
-rw-r--r--[-rwxr-xr-x]3rdparty/Sabre/DAV/Server.php175
1 files changed, 152 insertions, 23 deletions
diff --git a/3rdparty/Sabre/DAV/Server.php b/3rdparty/Sabre/DAV/Server.php
index 0dfac8b0c71..cf6f87e68ab 100755..100644
--- a/3rdparty/Sabre/DAV/Server.php
+++ b/3rdparty/Sabre/DAV/Server.php
@@ -12,7 +12,7 @@
class Sabre_DAV_Server {
/**
- * Inifinity is used for some request supporting the HTTP Depth header and indicates that the operation should traverse the entire tree
+ * Infinity is used for some request supporting the HTTP Depth header and indicates that the operation should traverse the entire tree
*/
const DEPTH_INFINITY = -1;
@@ -102,7 +102,6 @@ class Sabre_DAV_Server {
'{DAV:}getetag',
'{DAV:}getlastmodified',
'{DAV:}lockdiscovery',
- '{DAV:}resourcetype',
'{DAV:}supportedlock',
// RFC4331
@@ -162,7 +161,7 @@ class Sabre_DAV_Server {
* If an array is passed, we automatically create a root node, and use
* the nodes in the array as top-level children.
*
- * @param Sabre_DAV_Tree|Sabre_DAV_INode|null $treeOrNode The tree object
+ * @param Sabre_DAV_Tree|Sabre_DAV_INode|array|null $treeOrNode The tree object
*/
public function __construct($treeOrNode = null) {
@@ -207,6 +206,10 @@ class Sabre_DAV_Server {
} catch (Exception $e) {
+ try {
+ $this->broadcastEvent('exception', array($e));
+ } catch (Exception $ignore) {
+ }
$DOM = new DOMDocument('1.0','utf-8');
$DOM->formatOutput = true;
@@ -214,17 +217,23 @@ class Sabre_DAV_Server {
$error->setAttribute('xmlns:s',self::NS_SABREDAV);
$DOM->appendChild($error);
- $error->appendChild($DOM->createElement('s:exception',get_class($e)));
- $error->appendChild($DOM->createElement('s:message',$e->getMessage()));
+ $h = function($v) {
+
+ return htmlspecialchars($v, ENT_NOQUOTES, 'UTF-8');
+
+ };
+
+ $error->appendChild($DOM->createElement('s:exception',$h(get_class($e))));
+ $error->appendChild($DOM->createElement('s:message',$h($e->getMessage())));
if ($this->debugExceptions) {
- $error->appendChild($DOM->createElement('s:file',$e->getFile()));
- $error->appendChild($DOM->createElement('s:line',$e->getLine()));
- $error->appendChild($DOM->createElement('s:code',$e->getCode()));
- $error->appendChild($DOM->createElement('s:stacktrace',$e->getTraceAsString()));
+ $error->appendChild($DOM->createElement('s:file',$h($e->getFile())));
+ $error->appendChild($DOM->createElement('s:line',$h($e->getLine())));
+ $error->appendChild($DOM->createElement('s:code',$h($e->getCode())));
+ $error->appendChild($DOM->createElement('s:stacktrace',$h($e->getTraceAsString())));
}
if (self::$exposeVersion) {
- $error->appendChild($DOM->createElement('s:sabredav-version',Sabre_DAV_Version::VERSION));
+ $error->appendChild($DOM->createElement('s:sabredav-version',$h(Sabre_DAV_Version::VERSION)));
}
if($e instanceof Sabre_DAV_Exception) {
@@ -508,7 +517,7 @@ class Sabre_DAV_Server {
if (!$this->checkPreconditions(true)) return false;
- if (!($node instanceof Sabre_DAV_IFile)) throw new Sabre_DAV_Exception_NotImplemented('GET is only implemented on File objects');
+ if (!$node instanceof Sabre_DAV_IFile) throw new Sabre_DAV_Exception_NotImplemented('GET is only implemented on File objects');
$body = $node->get();
// Converting string into stream, if needed.
@@ -696,6 +705,7 @@ class Sabre_DAV_Server {
// This is a multi-status response
$this->httpResponse->sendStatus(207);
$this->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
+ $this->httpResponse->setHeader('Vary','Brief,Prefer');
// Normally this header is only needed for OPTIONS responses, however..
// iCal seems to also depend on these being set for PROPFIND. Since
@@ -704,7 +714,10 @@ class Sabre_DAV_Server {
foreach($this->plugins as $plugin) $features = array_merge($features,$plugin->getFeatures());
$this->httpResponse->setHeader('DAV',implode(', ',$features));
- $data = $this->generateMultiStatus($newProperties);
+ $prefer = $this->getHTTPPrefer();
+ $minimal = $prefer['return-minimal'];
+
+ $data = $this->generateMultiStatus($newProperties, $minimal);
$this->httpResponse->sendBody($data);
}
@@ -724,6 +737,30 @@ class Sabre_DAV_Server {
$result = $this->updateProperties($uri, $newProperties);
+ $prefer = $this->getHTTPPrefer();
+ $this->httpResponse->setHeader('Vary','Brief,Prefer');
+
+ if ($prefer['return-minimal']) {
+
+ // If return-minimal is specified, we only have to check if the
+ // request was succesful, and don't need to return the
+ // multi-status.
+ $ok = true;
+ foreach($result as $code=>$prop) {
+ if ((int)$code > 299) {
+ $ok = false;
+ }
+ }
+
+ if ($ok) {
+
+ $this->httpResponse->sendStatus(204);
+ return;
+
+ }
+
+ }
+
$this->httpResponse->sendStatus(207);
$this->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
@@ -927,7 +964,7 @@ class Sabre_DAV_Server {
* This method moves one uri to a different uri. A lot of the actual request processing is done in getCopyMoveInfo
*
* @param string $uri
- * @return void
+ * @return bool
*/
protected function httpMove($uri) {
@@ -1009,7 +1046,7 @@ class Sabre_DAV_Server {
if ($this->broadcastEvent('report',array($reportName,$dom, $uri))) {
// If broadcastEvent returned true, it means the report was not supported
- throw new Sabre_DAV_Exception_ReportNotImplemented();
+ throw new Sabre_DAV_Exception_ReportNotSupported();
}
@@ -1158,6 +1195,85 @@ class Sabre_DAV_Server {
}
+ /**
+ * Returns the HTTP Prefer header information.
+ *
+ * The prefer header is defined in:
+ * http://tools.ietf.org/html/draft-snell-http-prefer-14
+ *
+ * This method will return an array with options.
+ *
+ * Currently, the following options may be returned:
+ * array(
+ * 'return-asynch' => true,
+ * 'return-minimal' => true,
+ * 'return-representation' => true,
+ * 'wait' => 30,
+ * 'strict' => true,
+ * 'lenient' => true,
+ * )
+ *
+ * This method also supports the Brief header, and will also return
+ * 'return-minimal' if the brief header was set to 't'.
+ *
+ * For the boolean options, false will be returned if the headers are not
+ * specified. For the integer options it will be 'null'.
+ *
+ * @return array
+ */
+ public function getHTTPPrefer() {
+
+ $result = array(
+ 'return-asynch' => false,
+ 'return-minimal' => false,
+ 'return-representation' => false,
+ 'wait' => null,
+ 'strict' => false,
+ 'lenient' => false,
+ );
+
+ if ($prefer = $this->httpRequest->getHeader('Prefer')) {
+
+ $parameters = array_map('trim',
+ explode(',', $prefer)
+ );
+
+ foreach($parameters as $parameter) {
+
+ // Right now our regex only supports the tokens actually
+ // specified in the draft. We may need to expand this if new
+ // tokens get registered.
+ if(!preg_match('/^(?P<token>[a-z0-9-]+)(?:=(?P<value>[0-9]+))?$/', $parameter, $matches)) {
+ continue;
+ }
+
+ switch($matches['token']) {
+
+ case 'return-asynch' :
+ case 'return-minimal' :
+ case 'return-representation' :
+ case 'strict' :
+ case 'lenient' :
+ $result[$matches['token']] = true;
+ break;
+ case 'wait' :
+ $result[$matches['token']] = $matches['value'];
+ break;
+
+ }
+
+ }
+
+ }
+
+ if ($this->httpRequest->getHeader('Brief')=='t') {
+ $result['return-minimal'] = true;
+ }
+
+ return $result;
+
+ }
+
/**
* Returns information about Copy and Move requests
@@ -1433,15 +1549,18 @@ class Sabre_DAV_Server {
}
- $this->broadcastEvent('afterGetProperties',array(trim($myPath,'/'),&$newProperties));
+ $this->broadcastEvent('afterGetProperties',array(trim($myPath,'/'),&$newProperties, $node));
$newProperties['href'] = trim($myPath,'/');
// Its is a WebDAV recommendation to add a trailing slash to collectionnames.
- // Apple's iCal also requires a trailing slash for principals (rfc 3744).
- // Therefore we add a trailing / for any non-file. This might need adjustments
- // if we find there are other edge cases.
- if ($myPath!='' && isset($newProperties[200]['{DAV:}resourcetype']) && count($newProperties[200]['{DAV:}resourcetype']->getValue())>0) $newProperties['href'] .='/';
+ // Apple's iCal also requires a trailing slash for principals (rfc 3744), though this is non-standard.
+ if ($myPath!='' && isset($newProperties[200]['{DAV:}resourcetype'])) {
+ $rt = $newProperties[200]['{DAV:}resourcetype'];
+ if ($rt->is('{DAV:}collection') || $rt->is('{DAV:}principal')) {
+ $newProperties['href'] .='/';
+ }
+ }
// If the resourcetype property was manually added to the requested property list,
// we will remove it again.
@@ -1476,11 +1595,14 @@ class Sabre_DAV_Server {
if (!$this->broadcastEvent('beforeBind',array($uri))) return false;
$parent = $this->tree->getNodeForPath($dir);
+ if (!$parent instanceof Sabre_DAV_ICollection) {
+ throw new Sabre_DAV_Exception_Conflict('Files can only be created as children of collections');
+ }
if (!$this->broadcastEvent('beforeCreateFile',array($uri, &$data, $parent))) return false;
$etag = $parent->createFile($name,$data);
- $this->tree->markDirty($dir);
+ $this->tree->markDirty($dir . '/' . $name);
$this->broadcastEvent('afterBind',array($uri));
$this->broadcastEvent('afterCreateFile',array($uri, $parent));
@@ -1901,12 +2023,15 @@ class Sabre_DAV_Server {
/**
- * Generates a WebDAV propfind response body based on a list of nodes
+ * Generates a WebDAV propfind response body based on a list of nodes.
+ *
+ * If 'strip404s' is set to true, all 404 responses will be removed.
*
* @param array $fileProperties The list with nodes
+ * @param bool strip404s
* @return string
*/
- public function generateMultiStatus(array $fileProperties) {
+ public function generateMultiStatus(array $fileProperties, $strip404s = false) {
$dom = new DOMDocument('1.0','utf-8');
//$dom->formatOutput = true;
@@ -1925,6 +2050,10 @@ class Sabre_DAV_Server {
$href = $entry['href'];
unset($entry['href']);
+ if ($strip404s && isset($entry[404])) {
+ unset($entry[404]);
+ }
+
$response = new Sabre_DAV_Property_Response($href,$entry);
$response->serialize($this,$multiStatus);
@@ -1995,7 +2124,7 @@ class Sabre_DAV_Server {
if (!$body) return array();
$dom = Sabre_DAV_XMLUtil::loadDOMDocument($body);
- $elem = $dom->getElementsByTagNameNS('urn:DAV','propfind')->item(0);
+ $elem = $dom->getElementsByTagNameNS('DAV:','propfind')->item(0);
return array_keys(Sabre_DAV_XMLUtil::parseProperties($elem));
}