function testSerialize() { $dt = new DateTime('2010-03-14 16:35', new DateTimeZone('UTC')); $lastMod = new Sabre_DAV_Property_GetLastModified($dt); $doc = new DOMDocument(); $root = $doc->createElement('d:getlastmodified'); $root->setAttribute('xmlns:d', 'DAV:'); $doc->appendChild($root); $objectTree = new Sabre_DAV_ObjectTree(new Sabre_DAV_SimpleDirectory('rootdir')); $server = new Sabre_DAV_Server($objectTree); $lastMod->serialize($server, $root); $xml = $doc->saveXML(); $this->assertEquals('<?xml version="1.0"?> <d:getlastmodified xmlns:d="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/" b:dt="dateTime.rfc1123">' . Sabre_HTTP_Util::toHTTPDate($dt) . '</d:getlastmodified> ', $xml); $ok = false; try { Sabre_DAV_Property_GetLastModified::unserialize(Sabre_DAV_XMLUtil::loadDOMDocument($xml)->firstChild); } catch (Sabre_DAV_Exception $e) { $ok = true; } if (!$ok) { $this->markTestFailed('Unserialize should not be supported'); } }
function parse($xml) { $xml = implode("\n", $xml); $dom = Sabre_DAV_XMLUtil::loadDOMDocument($xml); $q = new Sabre_CardDAV_AddressBookQueryParser($dom); $q->parse(); return $q; }
/** * @depends testConstruct */ function testUnserialize() { $xml = '<?xml version="1.0"?> <d:anything xmlns:d="DAV:"><d:collection/><d:principal/></d:anything> '; $dom = Sabre_DAV_XMLUtil::loadDOMDocument($xml); $resourceType = Sabre_DAV_Property_ResourceType::unserialize($dom->firstChild); $this->assertEquals(array('{DAV:}collection', '{DAV:}principal'), $resourceType->getValue()); }
/** * @depends testSimple */ function testUnserializer() { $xml = '<?xml version="1.0"?> <d:root xmlns:d="DAV:" xmlns:cal="' . Sabre_CalDAV_Plugin::NS_CALDAV . '">' . '<cal:comp name="VEVENT"/>' . '<cal:comp name="VJOURNAL"/>' . '</d:root>'; $dom = Sabre_DAV_XMLUtil::loadDOMDocument($xml); $property = Sabre_CalDAV_Property_SupportedCalendarComponentSet::unserialize($dom->firstChild); $this->assertTrue($property instanceof Sabre_CalDAV_Property_SupportedCalendarComponentSet); $this->assertEquals(array('VEVENT', 'VJOURNAL'), $property->getValue()); }
/** * @expectedException Sabre_DAV_Exception */ function testUnserializeNoStatus() { $xml = '<?xml version="1.0"?> <d:root xmlns:d="DAV:" xmlns:cal="' . Sabre_CalDAV_Plugin::NS_CALDAV . '" xmlns:cs="' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '"> <cs:user> <d:href>mailto:user1@example.org</d:href> <!-- <cs:invite-accepted/> --> <cs:access> <cs:read-write/> </cs:access> </cs:user> </d:root>'; $doc2 = Sabre_DAV_XMLUtil::loadDOMDocument($xml); $outputProperty = Sabre_CalDAV_Property_Invite::unserialize($doc2->firstChild); }
/** * This event is triggered when the server didn't know how to handle a * certain request. * * We intercept this to handle POST requests on calendars. * * @param string $method * @param string $uri * @return null|bool */ public function unknownMethod($method, $uri) { if ($method !== 'POST') { return; } // Only handling xml $contentType = $this->server->httpRequest->getHeader('Content-Type'); if (strpos($contentType, 'application/xml') === false && strpos($contentType, 'text/xml') === false) { return; } // Making sure the node exists try { $node = $this->server->tree->getNodeForPath($uri); } catch (Sabre_DAV_Exception_NotFound $e) { return; } $requestBody = $this->server->httpRequest->getBody(true); // If this request handler could not deal with this POST request, it // will return 'null' and other plugins get a chance to handle the // request. // // However, we already requested the full body. This is a problem, // because a body can only be read once. This is why we preemptively // re-populated the request body with the existing data. $this->server->httpRequest->setBody($requestBody); $dom = Sabre_DAV_XMLUtil::loadDOMDocument($requestBody); $documentType = Sabre_DAV_XMLUtil::toClarkNotation($dom->firstChild); switch ($documentType) { // Dealing with the 'share' document, which modified invitees on a // calendar. case '{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}share': // We can only deal with IShareableCalendar objects if (!$node instanceof Sabre_CalDAV_IShareableCalendar) { return; } // Getting ACL info $acl = $this->server->getPlugin('acl'); // If there's no ACL support, we allow everything if ($acl) { $acl->checkPrivileges($uri, '{DAV:}write'); } $mutations = $this->parseShareRequest($dom); $node->updateShares($mutations[0], $mutations[1]); $this->server->httpResponse->sendStatus(200); // Adding this because sending a response body may cause issues, // and I wanted some type of indicator the response was handled. $this->server->httpResponse->setHeader('X-Sabre-Status', 'everything-went-well'); // Breaking the event chain return false; // The invite-reply document is sent when the user replies to an // invitation of a calendar share. // The invite-reply document is sent when the user replies to an // invitation of a calendar share. case '{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}invite-reply': // This only works on the calendar-home-root node. if (!$node instanceof Sabre_CalDAV_UserCalendars) { return; } // Getting ACL info $acl = $this->server->getPlugin('acl'); // If there's no ACL support, we allow everything if ($acl) { $acl->checkPrivileges($uri, '{DAV:}write'); } $message = $this->parseInviteReplyRequest($dom); $url = $node->shareReply($message['href'], $message['status'], $message['calendarUri'], $message['inReplyTo'], $message['summary']); $this->server->httpResponse->sendStatus(200); // Adding this because sending a response body may cause issues, // and I wanted some type of indicator the response was handled. $this->server->httpResponse->setHeader('X-Sabre-Status', 'everything-went-well'); if ($url) { $dom = new DOMDocument('1.0', 'UTF-8'); $dom->formatOutput = true; $root = $dom->createElement('cs:shared-as'); foreach ($this->server->xmlNamespaces as $namespace => $prefix) { $root->setAttribute('xmlns:' . $prefix, $namespace); } $dom->appendChild($root); $href = new Sabre_DAV_Property_Href($url); $href->serialize($this->server, $root); $this->server->httpResponse->setHeader('Content-Type', 'application/xml'); $this->server->httpResponse->sendBody($dom->saveXML()); } // Breaking the event chain return false; case '{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}publish-calendar': // We can only deal with IShareableCalendar objects if (!$node instanceof Sabre_CalDAV_IShareableCalendar) { return; } // Getting ACL info $acl = $this->server->getPlugin('acl'); // If there's no ACL support, we allow everything if ($acl) { $acl->checkPrivileges($uri, '{DAV:}write'); } $node->setPublishStatus(true); // iCloud sends back the 202, so we will too. $this->server->httpResponse->sendStatus(202); // Adding this because sending a response body may cause issues, // and I wanted some type of indicator the response was handled. $this->server->httpResponse->setHeader('X-Sabre-Status', 'everything-went-well'); // Breaking the event chain return false; case '{' . Sabre_CalDAV_Plugin::NS_CALENDARSERVER . '}unpublish-calendar': // We can only deal with IShareableCalendar objects if (!$node instanceof Sabre_CalDAV_IShareableCalendar) { return; } // Getting ACL info $acl = $this->server->getPlugin('acl'); // If there's no ACL support, we allow everything if ($acl) { $acl->checkPrivileges($uri, '{DAV:}write'); } $node->setPublishStatus(false); $this->server->httpResponse->sendStatus(200); // Adding this because sending a response body may cause issues, // and I wanted some type of indicator the response was handled. $this->server->httpResponse->setHeader('X-Sabre-Status', 'everything-went-well'); // Breaking the event chain return false; } }
/** * This method parses the PROPFIND request and returns its information * * This will either be a list of properties, or an empty array; in which case * an {DAV:}allprop was requested. * * @param string $body * @return array */ public function parsePropFindRequest($body) { // If the propfind body was empty, it means IE is requesting 'all' properties if (!$body) { return array(); } $dom = Sabre_DAV_XMLUtil::loadDOMDocument($body); $elem = $dom->getElementsByTagNameNS('urn:DAV', 'propfind')->item(0); return array_keys(Sabre_DAV_XMLUtil::parseProperties($elem)); }
function testParsePropertiesMapHref() { $xml = '<?xml version="1.0"?> <root xmlns="DAV:"> <prop> <displayname>Calendars</displayname> </prop> <prop> <someprop><href>http://sabredav.org/</href></someprop> </prop> </root>'; $dom = Sabre_DAV_XMLUtil::loadDOMDocument($xml); $properties = Sabre_DAV_XMLUtil::parseProperties($dom->firstChild, array('{DAV:}someprop' => 'Sabre_DAV_Property_Href')); $this->assertEquals(array('{DAV:}displayname' => 'Calendars', '{DAV:}someprop' => new Sabre_DAV_Property_Href('http://sabredav.org/', false)), $properties); }
/** * This function handles the MKCALENDAR HTTP method, which creates * a new calendar. * * @param string $uri * @return void */ public function httpMkCalendar($uri) { // Due to unforgivable bugs in iCal, we're completely disabling MKCALENDAR support // for clients matching iCal in the user agent //$ua = $this->server->httpRequest->getHeader('User-Agent'); //if (strpos($ua,'iCal/')!==false) { // throw new Sabre_DAV_Exception_Forbidden('iCal has major bugs in it\'s RFC3744 support. Therefore we are left with no other choice but disabling this feature.'); //} $body = $this->server->httpRequest->getBody(true); $properties = array(); if ($body) { $dom = Sabre_DAV_XMLUtil::loadDOMDocument($body); foreach ($dom->firstChild->childNodes as $child) { if (Sabre_DAV_XMLUtil::toClarkNotation($child) !== '{DAV:}set') { continue; } foreach (Sabre_DAV_XMLUtil::parseProperties($child, $this->server->propertyMap) as $k => $prop) { $properties[$k] = $prop; } } } $resourceType = array('{DAV:}collection', '{urn:ietf:params:xml:ns:caldav}calendar'); $this->server->createCollection($uri, $resourceType, $properties); $this->server->httpResponse->sendStatus(201); $this->server->httpResponse->setHeader('Content-Length', 0); }
/** * This method is responsible for handling the 'ACL' event. * * @param string $uri * @return void */ public function httpACL($uri) { $body = $this->server->httpRequest->getBody(true); $dom = Sabre_DAV_XMLUtil::loadDOMDocument($body); $newAcl = Sabre_DAVACL_Property_Acl::unserialize($dom->firstChild)->getPrivileges(); // Normalizing urls foreach ($newAcl as $k => $newAce) { $newAcl[$k]['principal'] = $this->server->calculateUri($newAce['principal']); } $node = $this->server->tree->getNodeForPath($uri); if (!$node instanceof Sabre_DAVACL_IACL) { throw new Sabre_DAV_Exception_MethodNotAllowed('This node does not support the ACL method'); } $oldAcl = $this->getACL($node); $supportedPrivileges = $this->getFlatPrivilegeSet(); /* Checking if protected principals from the existing principal set are not overwritten. */ foreach ($oldAcl as $k => $oldAce) { if (!isset($oldAce['protected']) || !$oldAce['protected']) { continue; } $found = false; foreach ($newAcl as $newAce) { if ($newAce['privilege'] === $oldAce['privilege'] && $newAce['principal'] === $oldAce['principal'] && $newAce['protected']) { $found = true; } } if (!$found) { throw new Sabre_DAVACL_Exception_AceConflict('This resource contained a protected {DAV:}ace, but this privilege did not occur in the ACL request'); } } foreach ($newAcl as $k => $newAce) { // Do we recognize the privilege if (!isset($supportedPrivileges[$newAce['privilege']])) { throw new Sabre_DAVACL_Exception_NotSupportedPrivilege('The privilege you specified (' . $newAce['privilege'] . ') is not recognized by this server'); } if ($supportedPrivileges[$newAce['privilege']]['abstract']) { throw new Sabre_DAVACL_Exception_NoAbstract('The privilege you specified (' . $newAce['privilege'] . ') is an abstract privilege'); } // Looking up the principal try { $principal = $this->server->tree->getNodeForPath($newAce['principal']); } catch (Sabre_DAV_Exception_FileNotFound $e) { throw new Sabre_DAVACL_Exception_NotRecognizedPrincipal('The specified principal (' . $newAce['principal'] . ') does not exist'); } if (!$principal instanceof Sabre_DAVACL_IPrincipal) { throw new Sabre_DAVACL_Exception_NotRecognizedPrincipal('The specified uri (' . $newAce['principal'] . ') is not a principal'); } } $node->setACL($newAcl); }
/** * @expectedException Sabre_DAV_Exception_BadRequest */ function testUnserializeMissingPriv() { $source = '<?xml version="1.0"?> <d:root xmlns:d="DAV:"> <d:ace> <d:grant> <d:privilege /> </d:grant> <d:principal><d:href>/principals/evert</d:href></d:principal> </d:ace> </d:root> '; $dom = Sabre_DAV_XMLUtil::loadDOMDocument($source); Sabre_DAVACL_Property_Acl::unserialize($dom->firstChild); }
/** * @depends testParamFilter */ function testUndefinedNegation() { $xml = <<<XML <?xml version="1.0"?> <C:filter xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <C:comp-filter name="VCALENDAR"> <C:comp-filter name="VTODO"> <C:prop-filter name="COMPLETED"> <C:is-not-defined /> </C:prop-filter> <C:prop-filter name="STATUS"> <C:text-match negate-condition="yes">CANCELLED</C:text-match> </C:prop-filter> </C:comp-filter> </C:comp-filter> </C:filter> XML; $dom = Sabre_DAV_XMLUtil::loadDOMDocument($xml); $expected = array('/c:iCalendar/c:vcalendar' => array(), '/c:iCalendar/c:vcalendar/c:vtodo' => array(), '/c:iCalendar/c:vcalendar/c:vtodo/c:completed' => array('is-not-defined' => true), '/c:iCalendar/c:vcalendar/c:vtodo/c:status' => array('text-match' => array('collation' => 'i;ascii-casemap', 'negate-condition' => true, 'value' => 'CANCELLED'))); $result = Sabre_CalDAV_XMLUtil::parseCalendarQueryFilters($dom->firstChild); $this->assertEquals($expected, $result); }
/** * @expectedException Sabre_DAV_Exception_BadRequest */ function testUnserializeUnknown() { $xml = '<?xml version="1.0"?> <d:principal xmlns:d="DAV:">' . ' <d:foo />' . '</d:principal>'; $dom = Sabre_DAV_XMLUtil::loadDOMDocument($xml); Sabre_DAVACL_Property_Principal::unserialize($dom->firstChild); }
/** * @expectedException Sabre_DAV_Exception */ function testFreeBusyReportNoACLPlugin() { $this->server = new Sabre_DAV_Server(); $this->plugin = new Sabre_CalDAV_Plugin(); $this->server->addPlugin($this->plugin); $reportXML = <<<XML <?xml version="1.0"?> <c:free-busy-query xmlns:c="urn:ietf:params:xml:ns:caldav"> <c:time-range start="20111001T000000Z" end="20111101T000000Z" /> </c:free-busy-query> XML; $dom = Sabre_DAV_XMLUtil::loadDOMDocument($reportXML); $this->plugin->report('{urn:ietf:params:xml:ns:caldav}free-busy-query', $dom); }
/** * @expectedException Sabre_DAV_Exception_BadRequest */ function testExpandBadTimes() { $xml = array('<d:prop>', ' <c:calendar-data>', ' <c:expand start="20120101T000000Z" end="19980101T000000Z"/>', ' </c:calendar-data>', '</d:prop>', '<c:filter>', ' <c:comp-filter name="VCALENDAR" />', '</c:filter>'); $xml = '<?xml version="1.0"?> <c:calendar-query xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:"> ' . implode("\n", $xml) . ' </c:calendar-query>'; $dom = Sabre_DAV_XMLUtil::loadDOMDocument($xml); $q = new Sabre_CalDAV_CalendarQueryParser($dom); $q->parse(); }