diff options
Diffstat (limited to '3rdparty/Sabre/DAV/Server.php')
-rw-r--r--[-rwxr-xr-x] | 3rdparty/Sabre/DAV/Server.php | 175 |
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)); } |