def calendar_query(self, calendar_uri, query, got_xml, data, no_init): if not no_init: response = yield self.send(SimpleStoreRequest(self, "MKCALENDAR", calendar_uri, authid="wsanchez")) response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code,)) if data: for filename, icaldata in data.iteritems(): request = SimpleStoreRequest(self, "PUT", joinURL(calendar_uri, filename + ".ics"), authid="wsanchez") request.stream = MemoryStream(icaldata) yield self.send(request) else: # Add holiday events to calendar for child in FilePath(self.holidays_dir).children(): if os.path.splitext(child.basename())[1] != ".ics": continue request = SimpleStoreRequest(self, "PUT", joinURL(calendar_uri, child.basename()), authid="wsanchez") request.stream = MemoryStream(child.getContent()) yield self.send(request) request = SimpleStoreRequest(self, "REPORT", calendar_uri, authid="wsanchez") request.stream = MemoryStream(query.toxml()) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("REPORT failed: %s" % (response.code,)) returnValue( (yield davXMLFromStream(response.stream).addCallback(got_xml)) )
def http_ACL(self, request): """ Respond to a ACL request. (RFC 3744, section 8.1) """ if not self.fp.exists(): log.err("File not found: %s" % (self.fp.path,)) yield responsecode.NOT_FOUND return # # Check authentication and access controls # x = waitForDeferred(self.authorize(request, (davxml.WriteACL(),))) yield x x.getResult() # # Read request body # doc = waitForDeferred(davXMLFromStream(request.stream)) yield doc try: doc = doc.getResult() except ValueError, e: log.err("Error while handling ACL body: %s" % (e,)) raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
def propfind_cb(response): response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response to PROPFIND: %s" % (response.code,)) def got_xml(doc): if not isinstance(doc.root_element, davxml.MultiStatus): self.fail("PROPFIND response XML root element is not multistatus: %r" % (doc.root_element,)) response = doc.root_element.childOfType(davxml.Response) href = response.childOfType(davxml.HRef) self.failUnless(str(href) == inbox_uri) for propstat in response.childrenOfType(davxml.PropertyStatus): status = propstat.childOfType(davxml.Status) if status.code != responsecode.OK: self.fail("Unable to read requested properties (%s): %r" % (status, propstat.childOfType(davxml.PropertyContainer).toxml())) container = propstat.childOfType(davxml.PropertyContainer) # # Check CalDAV:calendar-free-busy-set # free_busy_set = container.childOfType(caldavxml.CalendarFreeBusySet) if not free_busy_set: self.fail("Expected CalDAV:calendar-free-busy-set element; but got none.") if not free_busy_set.children: self.fail("Expected non-empty CalDAV:calendar-free-busy-set element.") return davXMLFromStream(response.stream).addCallback(got_xml)
def http_PROPFIND(self, request): """ Respond to a PROPFIND request. (RFC 2518, section 8.1) """ if not self.exists(): log.err("File not found: %s" % (self,)) raise HTTPError(responsecode.NOT_FOUND) # # Check authentication and access controls # x = waitForDeferred(self.authorize(request, (davxml.Read(),))) yield x x.getResult() # # Read request body # try: doc = waitForDeferred(davXMLFromStream(request.stream)) yield doc doc = doc.getResult() except ValueError, e: log.err("Error while handling PROPFIND body: %s" % (e,)) raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
def http_PROPFIND(self, request): """ Respond to a PROPFIND request. (RFC 2518, section 8.1) """ if not self.exists(): # Return 403 if parent does not allow Bind parentURL = parentForURL(request.uri) parent = (yield request.locateResource(parentURL)) yield parent.authorize(request, (davxml.Bind(),)) log.error("Resource not found: %s" % (self,)) raise HTTPError(responsecode.NOT_FOUND) # # Check authentication and access controls # yield self.authorize(request, (davxml.Read(),)) # # Read request body # try: doc = (yield davXMLFromStream(request.stream)) except ValueError, e: log.error("Error while handling PROPFIND body: %s" % (e,)) raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
def do_test(response): response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("REPORT failed: %s" % (response.code,)) return davXMLFromStream(response.stream).addCallback(got_xml)
def check_result(response): response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response code for PROPPATCH (%s != %s)" % (response.code, responsecode.MULTI_STATUS)) return davXMLFromStream(response.stream).addCallback(check_xml)
def calendar_query(self, query, got_xml): request = SimpleStoreRequest(self, "REPORT", "/calendars/users/wsanchez/calendar/", authid="wsanchez") request.stream = MemoryStream(query.toxml()) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("REPORT failed: %s" % (response.code,)) returnValue( (yield davXMLFromStream(response.stream).addCallback(got_xml)) )
def check_result(response): response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response code for PROPFIND (%s != %s)" % (response.code, responsecode.MULTI_STATUS)) content_type = response.headers.getHeader("content-type") if content_type not in (http_headers.MimeType("text", "xml"), http_headers.MimeType("application", "xml")): self.fail("Incorrect content-type for PROPFIND response (%r not in %r)" % (content_type, (http_headers.MimeType("text", "xml"), http_headers.MimeType("application", "xml")))) return davXMLFromStream(response.stream).addCallback(check_xml)
def http_REPORT(self, request): """ Respond to a REPORT request. (RFC 3253, section 3.6) """ if not self.exists(): log.err("Resource not found: %s" % (self,)) raise HTTPError(responsecode.NOT_FOUND) # # Read request body # try: doc = (yield davXMLFromStream(request.stream)) except ValueError, e: log.err("Error while handling REPORT body: %s" % (e,)) raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
def addressbook_query(self, addressbook_uri, query, got_xml, data, no_init): if not no_init: ''' FIXME: clear address book, possibly by removing mkcol = """<?xml version="1.0" encoding="utf-8" ?> <D:mkcol xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:carddav"> <D:set> <D:prop> <D:resourcetype><D:collection/><C:addressbook/></D:resourcetype> </D:prop> </D:set> </D:mkcol> """ response = yield self.send(SimpleStoreRequest(self, "MKCOL", addressbook_uri, content=mkcol, authid="wsanchez")) response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCOL failed: %s" % (response.code,)) ''' if data: for filename, icaldata in data.iteritems(): request = SimpleStoreRequest(self, "PUT", joinURL(addressbook_uri, filename + ".vcf"), authid="wsanchez") request.stream = MemoryStream(icaldata) yield self.send(request) else: # Add vcards to addressbook for child in FilePath(self.vcards_dir).children(): if os.path.splitext(child.basename())[1] != ".vcf": continue request = SimpleStoreRequest(self, "PUT", joinURL(addressbook_uri, child.basename()), authid="wsanchez") request.stream = MemoryStream(child.getContent()) yield self.send(request) request = SimpleStoreRequest(self, "REPORT", addressbook_uri, authid="wsanchez") request.stream = MemoryStream(query.toxml()) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("REPORT failed: %s" % (response.code,)) returnValue( (yield davXMLFromStream(response.stream).addCallback(got_xml)) )
def propfind_cb(response): response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response to PROPFIND: %s" % (response.code,)) def got_xml(doc): if not isinstance(doc.root_element, davxml.MultiStatus): self.fail("PROPFIND response XML root element is not multistatus: %r" % (doc.root_element,)) response = doc.root_element.childOfType(davxml.Response) href = response.childOfType(davxml.HRef) self.failUnless(str(href) == calendar_uri) container = response.childOfType(davxml.PropertyStatus).childOfType(davxml.PropertyContainer) # # Check CalDAV:supported-calendar-component-set # supported_components = container.childOfType(caldavxml.SupportedCalendarComponentSet) if supported_components: self.fail("CalDAV:supported-calendar-component-set element was returned; but should be hidden.") # # Check CalDAV:supported-calendar-data # supported_calendar = container.childOfType(caldavxml.SupportedCalendarData) if supported_calendar: self.fail("CalDAV:supported-calendar-data elementwas returned; but should be hidden.") # # Check DAV:supported-report-set # supported_reports = container.childOfType(davxml.SupportedReportSet) if supported_reports: self.fail("DAV:supported-report-set element was returned; but should be hidden..") return davXMLFromStream(response.stream).addCallback(got_xml)
def http_PROPPATCH(self, request): """ Respond to a PROPPATCH request. (RFC 2518, section 8.2) """ if not self.exists(): log.error("File not found: %s" % (self,)) raise HTTPError(responsecode.NOT_FOUND) x = waitForDeferred(self.authorize(request, (davxml.WriteProperties(),))) yield x x.getResult() # # Read request body # try: doc = waitForDeferred(davXMLFromStream(request.stream)) yield doc doc = doc.getResult() except ValueError, e: log.error("Error while handling PROPPATCH body: %s" % (e,)) raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
def http_MKCALENDAR(self, request): """ Respond to a MKCALENDAR request. (CalDAV-access-09, section 5.3.1) """ # # Check authentication and access controls # parent = (yield request.locateResource(parentForURL(request.uri))) yield parent.authorize(request, (davxml.Bind(),)) if self.exists(): log.error("Attempt to create collection where resource exists: %s" % (self,)) raise HTTPError(ErrorResponse( responsecode.FORBIDDEN, (davxml.dav_namespace, "resource-must-be-null"), "Resource already exists", )) if not parent.isCollection(): log.error("Attempt to create collection with non-collection parent: %s" % (self,)) raise HTTPError(ErrorResponse( responsecode.CONFLICT, (caldavxml.caldav_namespace, "calendar-collection-location-ok"), "Cannot create calendar inside another calendar", )) # # Read request body # try: doc = (yield davXMLFromStream(request.stream)) yield self.createCalendar(request) except ValueError, e: log.error("Error while handling MKCALENDAR: %s" % (e,)) raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
def calendar_query(self, calendar_uri, query, got_xml): response = yield self.send(SimpleRequest(self.site, "MKCALENDAR", calendar_uri)) response = IResponse(response) if response.code != responsecode.CREATED: self.fail("MKCALENDAR failed: %s" % (response.code,)) # Add holiday events to calendar yield addEventsDir(self, FilePath(self.holidays_dir), calendar_uri) request = SimpleRequest(self.site, "REPORT", calendar_uri) request.stream = MemoryStream(query.toxml()) response = yield self.send(request) response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("REPORT failed: %s" % (response.code,)) returnValue( (yield davXMLFromStream(response.stream).addCallback(got_xml)) )
def oops(self, request, response, code, method, name): def gotResponseData(doc): if doc is None: doc_xml = None else: doc_xml = doc.toxml() def fail(acl): self.fail("Incorrect status code %s (!= %s) for %s of resource %s with %s ACL: %s\nACL: %s" % (response.code, code, method, request.uri, name, doc_xml, acl.toxml())) def getACL(resource): return resource.accessControlList(request) d = request.locateResource(request.uri) d.addCallback(getACL) d.addCallback(fail) return d d = davXMLFromStream(response.stream) d.addCallback(gotResponseData) return d
def propfind_cb(response): response = IResponse(response) if response.code != responsecode.MULTI_STATUS: self.fail("Incorrect response to PROPFIND: %s" % (response.code,)) def got_xml(doc): if not isinstance(doc.root_element, davxml.MultiStatus): self.fail("PROPFIND response XML root element is not multistatus: %r" % (doc.root_element,)) response = doc.root_element.childOfType(davxml.Response) href = response.childOfType(davxml.HRef) self.failUnless(str(href) == calendar_uri) for propstat in response.childrenOfType(davxml.PropertyStatus): status = propstat.childOfType(davxml.Status) if status.code != responsecode.OK: self.fail("Unable to read requested properties (%s): %r" % (status, propstat.childOfType(davxml.PropertyContainer).toxml())) container = propstat.childOfType(davxml.PropertyContainer) # # Check CalDAV:supported-calendar-component-set # supported_components = container.childOfType(caldavxml.SupportedCalendarComponentSet) if not supported_components: self.fail("Expected CalDAV:supported-calendar-component-set element; but got none.") supported = set(("VEVENT",)) for component in supported_components.children: if component.type in supported: supported.remove(component.type) if supported: self.fail("Expected supported calendar component types: %s" % (tuple(supported),)) # # Check CalDAV:supported-calendar-data # supported_calendar = container.childOfType(caldavxml.SupportedCalendarData) if not supported_calendar: self.fail("Expected CalDAV:supported-calendar-data element; but got none.") for calendar in supported_calendar.children: if calendar.content_type != "text/calendar": self.fail("Expected a text/calendar calendar-data type restriction") if calendar.version != "2.0": self.fail("Expected a version 2.0 calendar-data restriction") # # Check DAV:supported-report-set # supported_reports = container.childOfType(davxml.SupportedReportSet) if not supported_reports: self.fail("Expected DAV:supported-report-set element; but got none.") cal_query = False cal_multiget = False cal_freebusy = False for supported in supported_reports.childrenOfType(davxml.SupportedReport): report = supported.childOfType(davxml.Report) if report.childOfType(caldavxml.CalendarQuery) is not None: cal_query = True if report.childOfType(caldavxml.CalendarMultiGet) is not None: cal_multiget = True if report.childOfType(caldavxml.FreeBusyQuery) is not None: cal_freebusy = True if not cal_query: self.fail("Expected CalDAV:CalendarQuery element; but got none.") if not cal_multiget: self.fail("Expected CalDAV:CalendarMultiGet element; but got none.") if not cal_freebusy: self.fail("Expected CalDAV:FreeBusyQuery element; but got none.") return davXMLFromStream(response.stream).addCallback(got_xml)
def http_MKCOL(self, request): # # Check authentication and access controls # parent = (yield request.locateResource(parentForURL(request.uri))) yield parent.authorize(request, (davxml.Bind(),)) if self.exists(): log.err("Attempt to create collection where resource exists: %s" % (self,)) raise HTTPError(ErrorResponse( responsecode.FORBIDDEN, (davxml.dav_namespace, "resource-must-be-null")) ) if not parent.isCollection(): log.err("Attempt to create collection with non-collection parent: %s" % (self,)) raise HTTPError(ErrorResponse( responsecode.CONFLICT, (davxml.dav_namespace, "collection-location-ok")) ) # # Don't allow DAV collections in a calendar or address book collection # if config.EnableCalDAV: parent = (yield self._checkParents(request, isPseudoCalendarCollectionResource)) if parent is not None: raise HTTPError(StatusResponse( responsecode.FORBIDDEN, "Cannot create collection within calendar collection %s" % (parent,) )) if config.EnableCardDAV: parent = (yield self._checkParents(request, isAddressBookCollectionResource)) if parent is not None: raise HTTPError(StatusResponse( responsecode.FORBIDDEN, "Cannot create collection within address book collection %s" % (parent,) )) # # Read request body # try: doc = (yield davXMLFromStream(request.stream)) except ValueError, e: log.err("Error while handling MKCOL: %s" % (e,)) # TODO: twext.web2.dav 'MKCOL' tests demand this particular response # code, but should we really be looking at the XML content or the # content-type header? It seems to me like this ought to be considered # a BAD_REQUEST if it claims to be XML but isn't, but an # UNSUPPORTED_MEDIA_TYPE if it claims to be something else. -glyph raise HTTPError( StatusResponse(responsecode.UNSUPPORTED_MEDIA_TYPE, str(e)) )