Example #1
0
    def test_renderPrivileges(self):
        """
        Verify that a directory listing includes children which you
        don't have access to.
        """
        request = SimpleRequest(self.site, "GET", "/")

        def setEmptyACL(resource):
            resource.setAccessControlList(davxml.ACL()) # Empty ACL = no access
            return resource

        def renderRoot(_):
            d = request.locateResource("/")
            d.addCallback(lambda r: r.render(request))

            return d

        def assertListing(response):
            data = []
            d = readStream(response.stream, lambda s: data.append(str(s)))
            d.addCallback(lambda _: self.failIf(
                'dir2/' not in "".join(data),
                "'dir2' expected in listing: %r" % (data,)
            ))
            return d

        d = request.locateResource("/dir2")
        d.addCallback(setEmptyACL)
        d.addCallback(renderRoot)
        d.addCallback(assertListing)

        return d
Example #2
0
        def work():
            for method in ("GET", "REPORT"):
                if method == "GET":
                    ok = responsecode.OK
                elif method == "REPORT":
                    ok = responsecode.MULTI_STATUS
                else:
                    raise AssertionError("We shouldn't be here.  (method = %r)" % (method,))

                for name, code in (
                    ("none"       , responsecode.FORBIDDEN),
                    ("read"       , ok),
                    ("read-write" , ok),
                    ("unlock"     , responsecode.FORBIDDEN),
                    ("all"        , ok),
                ):
                    path = os.path.join(self.docroot, name)

                    request = SimpleRequest(self.site, method, "/" + name)
                    if method == "REPORT":
                        request.stream = MemoryStream(element.PrincipalPropertySearch().toxml())

                    _add_auth_header(request)

                    def test(response, code=code, path=path):
                        if response.code != code:
                            return self.oops(request, response, code, method, name)

                    yield (request, test)
Example #3
0
    def test_Quota_Bad_Adjustment(self):
        """
        Quota adjustment too much
        """
        dst_uri = "/dst"

        def checkPUTResult(response):
            response = IResponse(response)

            if response.code != responsecode.CREATED:
                self.fail("Incorrect response code for PUT (%s != %s)"
                          % (response.code, responsecode.CREATED))

            def doBadAdjustment(_ignore):
                def checkAdjustmentResult(_ignore):
                    return self.checkQuota(100)

                d = self.site.resource.quotaSizeAdjust(None, -200)
                d.addCallback(checkAdjustmentResult)
                return d

            d = self.checkQuota(100)
            d.addCallback(doBadAdjustment)
            return d

        request = SimpleRequest(self.site, "PUT", dst_uri)
        request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb"))
        return self.send(request, checkPUTResult)
Example #4
0
        def work():
            for code in (
                responsecode.CREATED,
                responsecode.PRECONDITION_FAILED,
                responsecode.NO_CONTENT,
                responsecode.PRECONDITION_FAILED,
                responsecode.NO_CONTENT,
                responsecode.CREATED,
            ):
                def checkResult(response, code=code):
                    response = IResponse(response)

                    if response.code != code:
                        self.fail("Incorrect response code for PUT (%s != %s)"
                                  % (response.code, code))

                def onError(f):
                    f.trap(HTTPError)
                    return checkResult(f.value.response)

                request = SimpleRequest(self.site, "PUT", dst_uri)
                request.stream = FileStream(file(__file__, "rb"))
    
                if code == responsecode.CREATED:
                    if os.path.isfile(dst_path):
                        os.remove(dst_path)
                    request.headers.setHeader("if-none-match", ("*",))
                elif code == responsecode.PRECONDITION_FAILED:
                    request.headers.setHeader("if-none-match", ("*",))
    
                yield (request, (checkResult, onError))
Example #5
0
    def _simple_PROPPATCH(self, patch, prop, expected_code, what):
        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 check_xml(doc):
            response = doc.root_element.childOfType(davxml.Response)
            propstat = response.childOfType(davxml.PropertyStatus)

            self.failUnless(
                response.childOfType(davxml.HRef) == "/",
                "Incorrect response URI: %s != /" % (response.childOfType(davxml.HRef),)
            )

            self.failIf(
                propstat.childOfType(davxml.PropertyContainer).childOfType(prop) is None,
                "Not a %s in PROPPATCH property status: %s" % (prop.sname(), propstat.toxml())
            )

            self.failUnless(
                propstat.childOfType(davxml.Status).code == expected_code,
                "Incorrect status code for PROPPATCH %s: %s != %s"
                % (what, propstat.childOfType(davxml.Status).code, expected_code)
            )

        request = SimpleRequest(self.site, "PROPPATCH", "/")
        request.stream = MemoryStream(patch.toxml())
        return self.send(request, check_result)
    def test_free_busy_set_same(self):
        """
        Test that calendar-free-busy-set has the correct value and can be reset to the same.
        """

        request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/")
        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
        self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet, request)))
        prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request))
        self.assertEqual(prop.children[0], davxml.HRef("/calendars/__uids__/user01/calendar/"))

        newfbset = set()
        newfbset.add("/calendars/users/user01/calendar/")
        newset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in newfbset])

        yield inbox.writeProperty(newset, request)
        yield request._newStoreTransaction.commit()

        request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/")
        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
        prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request))
        self.assertEqual(prop.children[0], davxml.HRef("/calendars/__uids__/user01/calendar/"))
        yield request._newStoreTransaction.commit()
        calendar = yield request.locateResource("/calendars/__uids__/user01/calendar/")
        self.assertTrue(calendar._newStoreObject.isUsedForFreeBusy())
    def _checkPrivileges(self, resource, url, principal, privilege, allowed):
        request = SimpleRequest(self.site, "GET", "/")

        def gotResource(resource):
            d = resource.checkPrivileges(
                request, (privilege,), principal=davxml.Principal(principal)
            )
            if allowed:
                def onError(f):
                    f.trap(AccessDeniedError)
                    # print(resource.readDeadProperty(davxml.ACL))
                    self.fail(
                        "%s should have %s privilege on %r"
                        % (principal.sname(), privilege.sname(), resource)
                    )
                d.addErrback(onError)
            else:
                def expectAccessDenied(f):
                    f.trap(AccessDeniedError)

                def onSuccess(_):
                    # print(resource.readDeadProperty(davxml.ACL))
                    self.fail(
                        "%s should not have %s privilege on %r"
                        % (principal.sname(), privilege.sname(), resource)
                    )
                d.addCallbacks(onSuccess, expectAccessDenied)
            return d

        d = request.locateResource(url)
        d.addCallback(gotResource)
        return d
Example #8
0
    def test_Quota_DELETE(self):
        """
        Quota change on DELETE
        """
        dst_uri = "/dst"

        def checkPUTResult(response):
            response = IResponse(response)

            if response.code != responsecode.CREATED:
                self.fail("Incorrect response code for PUT (%s != %s)"
                          % (response.code, responsecode.CREATED))

            def doDelete(_ignore):
                def checkDELETEResult(response):
                    response = IResponse(response)

                    if response.code != responsecode.NO_CONTENT:
                        self.fail("Incorrect response code for PUT (%s != %s)"
                                  % (response.code, responsecode.NO_CONTENT))

                    return self.checkQuota(0)

                request = SimpleRequest(self.site, "DELETE", dst_uri)
                return self.send(request, checkDELETEResult)

            d = self.checkQuota(100)
            d.addCallback(doDelete)
            return d

        request = SimpleRequest(self.site, "PUT", dst_uri)
        request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb"))
        return self.send(request, checkPUTResult)
Example #9
0
        def work():
            for which in (davxml.AllProperties(), davxml.PropertyName()):
                query = davxml.PropertyFind(which)

                request = SimpleRequest(self.site, "PROPFIND", "/")
                request.headers.setHeader("depth", "0")
                request.stream = MemoryStream(query.toxml())

                yield (request, check_result(which))
    def test_REPORT_no_body(self):
        """
        REPORT request with no body
        """
        def do_test(response):
            response = IResponse(response)

            if response.code != responsecode.BAD_REQUEST:
                self.fail("Unexpected response code for REPORT with no body: %s"
                          % (response.code,))

        request = SimpleRequest(self.site, "REPORT", "/")
        request.stream = MemoryStream("")

        return self.send(request, do_test)
Example #11
0
    def test_receive_ping(self):
        """
        Cross-pod request works with the "ping" action.
        """

        request = SimpleRequest(self.site,
                                "POST",
                                "/conduit",
                                headers=http_headers.Headers(
                                    rawHeaders={
                                        "Content-Type": ("application/json", ),
                                        self.thisServer.secretHeader()[0]:
                                        self.thisServer.secretHeader()[1],
                                    }),
                                content="""
{
    "action":"ping"
}
""".replace("\n", "\r\n"))

        response = (yield self.send(request))
        self.assertEqual(response.code, responsecode.OK)
        data = (yield allDataFromStream(response.stream))
        j = json.loads(data)
        self.assertTrue("result" in j)
        self.assertEqual(j["result"], "ok")
Example #12
0
    def test_REPORT_no_body(self):
        """
        REPORT request with no body
        """
        def do_test(response):
            response = IResponse(response)

            if response.code != responsecode.BAD_REQUEST:
                self.fail(
                    "Unexpected response code for REPORT with no body: %s" %
                    (response.code, ))

        request = SimpleRequest(self.site, "REPORT", "/")
        request.stream = MemoryStream("")

        return self.send(request, do_test)
Example #13
0
    def test_receive_fake_conduit(self):
        """
        Cross-pod request works when conduit does support the action.
        """

        store = self.storeUnderTest()
        self.patch(store, "conduit", self.FakeConduit(store))

        request = SimpleRequest(self.site,
                                "POST",
                                "/conduit",
                                headers=http_headers.Headers(
                                    rawHeaders={
                                        "Content-Type": ("application/json", ),
                                        self.thisServer.secretHeader()[0]:
                                        self.thisServer.secretHeader()[1],
                                    }),
                                content="""
{
    "action":"fake",
    "echo":"bravo"
}
""".replace("\n", "\r\n"))

        response = (yield self.send(request))
        self.assertEqual(response.code, responsecode.OK)
        data = (yield allDataFromStream(response.stream))
        j = json.loads(data)
        self.assertTrue("result" in j)
        self.assertEqual(j["result"], "ok")
        self.assertTrue("value" in j)
        self.assertEqual(j["value"], {"back2u": "bravo", "more": "bits"})
Example #14
0
    def test_receive_fake_conduit_no_action(self):
        """
        Cross-pod request fails when conduit does not support the action.
        """

        store = self.storeUnderTest()
        self.patch(store, "conduit", self.FakeConduit(store))

        request = SimpleRequest(self.site,
                                "POST",
                                "/conduit",
                                headers=http_headers.Headers(
                                    rawHeaders={
                                        "Content-Type": ("application/json", ),
                                        self.thisServer.secretHeader()[0]:
                                        self.thisServer.secretHeader()[1],
                                    }),
                                content="""
{
    "action":"bogus",
    "echo":"bravo"
}
""".replace("\n", "\r\n"))

        response = (yield self.send(request))
        self.assertEqual(response.code, responsecode.BAD_REQUEST)
Example #15
0
    def test_free_busy_set_invalid_url(self):
        """
        Test that calendar-free-busy-set will generate an error if an invalid value is used.
        """

        request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/")
        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
        self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet, request)))
        oldfbset = set(("/calendar",))

        newfbset = set()
        newfbset.update(oldfbset)
        newfbset.add("/calendar-broken")
        newset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in newfbset])

        yield self.failUnlessFailure(inbox.writeProperty(newset, request), HTTPError)
Example #16
0
 def test_lacksPrivileges(self):
     request = SimpleRequest(self.site, "GET", "/protected")
     request.headers.setHeader(
         "authorization", ("basic", "baduser:badpass".encode("base64")))
     d = self.assertFailure(self.checkSecurity(request), HTTPError)
     d.addCallback(self.assertErrorResponse, responsecode.FORBIDDEN)
     return d
Example #17
0
    def test_dav_header_full_caldav(self):
        """
        DAV header advertises CalDAV
        """
        def do_test(response):
            response = IResponse(response)

            dav = response.headers.getHeader("dav")
            if not dav:
                self.fail("no DAV header: %s" % (response.headers, ))
            self.assertIn("1", dav, "no DAV level 1 header")
            self.assertIn("access-control", dav,
                          "no DAV access-control header")
            self.assertIn("calendar-access", dav,
                          "no DAV calendar-access header")
            self.assertIn("calendar-schedule", dav,
                          "no DAV calendar-schedule header")
            self.assertIn("calendar-auto-schedule", dav,
                          "no DAV calendar-auto-schedule header")
            self.assertIn("calendar-availability", dav,
                          "no DAV calendar-availability header")

        config.Scheduling.CalDAV.OldDraftCompatibility = True
        request = SimpleRequest(self.site, "OPTIONS", "/")

        return self.send(request, do_test)
 def test_Header_Our_Server_Allowed(self):
     proxy = ReverseProxyResource("pool")
     proxy.allowMultiHop = True
     request = SimpleRequest(proxy, "GET", "/")
     request.headers.addRawHeader("x-forwarded-server", config.ServerHostName)
     response = yield proxy.renderHTTP(request)
     self.assertIsInstance(response, ClientRequest)
Example #19
0
        def work():
            src_path = os.path.join(self.docroot, "read")
            uri = "/" + os.path.basename(src_path)

            for method in ("COPY", "MOVE"):
                for name, code in (
                    ("nobind" , responsecode.FORBIDDEN),
                    ("bind"   , responsecode.CREATED),
                    ("unbind" , responsecode.CREATED),
                ):
                    dst_parent_path = os.path.join(self.docroot, name)
                    dst_path = os.path.join(dst_parent_path, "dst")

                    request = SimpleRequest(self.site, method, uri)
                    request.headers.setHeader("destination", "/" + name + "/dst")
                    _add_auth_header(request)

                    def test(response, code=code, dst_path=dst_path):
                        if os.path.isfile(dst_path):
                            os.remove(dst_path)

                        if response.code != code:
                            return self.oops(request, response, code, method, name)

                    yield (request, test)
                    self.restore()
Example #20
0
    def test_PUT_no_parent(self):
        """
        PUT with no parent
        """
        dst_uri = "/put/no/parent"

        def checkResult(response):
            response = IResponse(response)

            if response.code != responsecode.CONFLICT:
                self.fail("Incorrect response code for PUT with no parent (%s != %s)"
                          % (response.code, responsecode.CONFLICT))

        request = SimpleRequest(self.site, "PUT", dst_uri)
        request.stream = FileStream(file(__file__, "rb"))

        return self.send(request, checkResult)
    def test_findChildrenWithPrivileges(self):
        """
        This test revokes read privileges for the C{"/file2"} and C{"/dir2/"}
        resource to verify that we can not find them giving our unauthenticated
        privileges.
        """
        
        expected_children = [
            "/file1",
            "/dir1/",
        ]

        request = SimpleRequest(self.site, "GET", "/")
        resource = waitForDeferred(request.locateResource("/"))
        yield resource
        resource = resource.getResult()

        def checkChildren(resource, uri):
            self.assertEquals(uri, resource.uri)

            if uri not in expected_children:
                unexpected_children.append(uri)
            else:
                found_children.append(uri)

        found_children = []
        unexpected_children = []

        privileges = waitForDeferred(resource.currentPrivileges(request))
        yield privileges
        privileges = privileges.getResult()

        fc = resource.findChildren("1", request, checkChildren, privileges)
        completed = waitForDeferred(fc)
        yield completed
        completed.getResult()

        self.assertEquals(
            unexpected_children, [],
            "Found unexpected children: %r" % (unexpected_children,)
        )

        expected_children.sort()
        found_children.sort()

        self.assertEquals(expected_children, found_children)
 def test_Header_Other_Servers(self):
     proxy = ReverseProxyResource("pool")
     request = SimpleRequest(proxy, "GET", "/")
     request.headers.setHeader("x-forwarded-server", (
         "foobar.example.com",
         "bar.example.com",
     ))
     self.assertIsInstance(proxy.renderHTTP(request), ClientRequest)
Example #23
0
 def test_locateChild(self):
     resource = LeafResource()
     child, segments = (resource.locateChild(
         SimpleRequest(Site(resource), "GET", "/"),
         ("", "foo"),
     ))
     self.assertEquals(child, resource)
     self.assertEquals(segments, StopTraversal)
Example #24
0
    def test_isOwnerYes_noStoreObject(self):
        """
        L{CalDAVResource.isOwner} returns C{True} for authenticated requests
        with a principal that matches the resource's owner.
        """
        site = None
        request = SimpleRequest(site, "GET", "/not/a/real/url/")
        request.authzUser = request.authnUser = StubPrincipal("/yes-i-am-the-owner/")
        parent = CalDAVResource()
        parent.owner = lambda igreq: HRef("/yes-i-am-the-owner/")
        rsrc = CalDAVResource()
        rsrc._newStoreObject = None

        request._rememberResource(parent, "/not/a/real/")
        request._rememberResource(rsrc, "/not/a/real/url/")

        self.assertEquals((yield rsrc.isOwner(request)), True)
Example #25
0
    def test_checkPrivileges(self):
        """
        DAVResource.checkPrivileges()
        """
        ds = []

        authAllResource = AuthAllResource()
        requested_access = (davxml.All(),)

        site = Site(authAllResource)

        def expectError(failure):
            failure.trap(AccessDeniedError)
            errors = failure.value.errors

            self.failUnless(len(errors) == 1)

            subpath, denials = errors[0]

            self.failUnless(subpath is None)
            self.failUnless(
                tuple(denials) == requested_access,
                "%r != %r" % (tuple(denials), requested_access)
            )

        def expectOK(result):
            self.failUnlessEquals(result, None)

        def _checkPrivileges(resource):
            d = resource.checkPrivileges(request, requested_access)
            return d

        # No auth; should deny
        request = SimpleRequest(site, "GET", "/")
        d = request.locateResource("/").addCallback(_checkPrivileges).addErrback(expectError)
        ds.append(d)

        # Has auth; should allow
        request = SimpleRequest(site, "GET", "/")
        request.authzUser = request.authnUser = self.rootresource.principalForUser("gooduser")
        d = request.locateResource("/")
        d.addCallback(_checkPrivileges)
        d.addCallback(expectOK)
        ds.append(d)

        return DeferredList(ds)
Example #26
0
    def test_PUT_no_parent(self):
        """
        PUT with no parent
        """
        dst_uri = "/put/no/parent"

        def checkResult(response):
            response = IResponse(response)

            if response.code != responsecode.CONFLICT:
                self.fail("Incorrect response code for PUT with no parent (%s != %s)"
                          % (response.code, responsecode.CONFLICT))

        request = SimpleRequest(self.site, "PUT", dst_uri)
        request.stream = FileStream(file(__file__, "rb"))

        return self.send(request, checkResult)
Example #27
0
    def test_free_busy_set_same(self):
        """
        Test that calendar-free-busy-set has the correct value and can be reset to the same.
        """

        request = SimpleRequest(self.site, "GET",
                                "/calendars/users/user01/inbox/")
        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
        self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet,
                                                 request)))
        prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet,
                                         request))
        self.assertEqual(prop.children[0],
                         davxml.HRef("/calendars/__uids__/user01/calendar/"))

        newfbset = set()
        newfbset.add("/calendars/users/user01/calendar/")
        newset = caldavxml.CalendarFreeBusySet(
            *[davxml.HRef(url) for url in newfbset])

        yield inbox.writeProperty(newset, request)
        yield request._newStoreTransaction.commit()

        request = SimpleRequest(self.site, "GET",
                                "/calendars/users/user01/inbox/")
        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
        prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet,
                                         request))
        self.assertEqual(prop.children[0],
                         davxml.HRef("/calendars/__uids__/user01/calendar/"))
        yield request._newStoreTransaction.commit()
        calendar = yield request.locateResource(
            "/calendars/__uids__/user01/calendar/")
        self.assertTrue(calendar._newStoreObject.isUsedForFreeBusy())
    def test_findChildrenWithPrivileges(self):
        """
        This test revokes read privileges for the C{"/file2"} and C{"/dir2/"}
        resource to verify that we can not find them giving our unauthenticated
        privileges.
        """

        expected_children = [
            "/file1",
            "/dir1/",
        ]

        request = SimpleRequest(self.site, "GET", "/")
        resource = waitForDeferred(request.locateResource("/"))
        yield resource
        resource = resource.getResult()

        def checkChildren(resource, uri):
            self.assertEquals(uri, resource.uri)

            if uri not in expected_children:
                unexpected_children.append(uri)
            else:
                found_children.append(uri)

        found_children = []
        unexpected_children = []

        privileges = waitForDeferred(resource.currentPrivileges(request))
        yield privileges
        privileges = privileges.getResult()

        fc = resource.findChildren("1", request, checkChildren, privileges)
        completed = waitForDeferred(fc)
        yield completed
        completed.getResult()

        self.assertEquals(
            unexpected_children, [],
            "Found unexpected children: %r" % (unexpected_children, ))

        expected_children.sort()
        found_children.sort()

        self.assertEquals(expected_children, found_children)
Example #29
0
 def test_Header_Our_Server_Moxied(self):
     proxy = ReverseProxyResource("pool")
     request = SimpleRequest(proxy, "GET", "/")
     request.headers.setHeader("x-forwarded-server", (
         "foobar.example.com",
         "bar.example.com",
         config.ServerHostName,
     ))
     yield self.assertFailure(proxy.renderHTTP(request), HTTPError)
Example #30
0
    def test_Quota_PUT(self):
        """
        Quota change on PUT
        """
        dst_uri = "/dst"

        def checkResult(response):
            response = IResponse(response)

            if response.code != responsecode.CREATED:
                self.fail("Incorrect response code for PUT (%s != %s)"
                          % (response.code, responsecode.CREATED))

            return self.checkQuota(100)

        request = SimpleRequest(self.site, "PUT", dst_uri)
        request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb"))
        return self.send(request, checkResult)
 def test_failsWithDifferentMethod(self):
     """
     Test that the response fails if made for a different request method
     than it is being issued for.
     """
     d = self._createAndDecodeChallenge(req=SimpleRequest(None, 'POST', '/'))
     def _test(creds):
         self.failIf(creds.checkPassword('password'))
     return d.addCallback(_test)
Example #32
0
    def test_okLink(self):
        resource = CalendarHomeResource(self.site.resource, "home", object(), StubHome())
        self.site.resource.putChild("home", resource)
        link = LinkResource(resource, "/home/outbox/")
        resource.putChild("link", link)

        request = SimpleRequest(self.site, "GET", "/home/link/")
        linked_to, _ignore = (yield resource.locateChild(request, ["link", ]))
        self.assertTrue(linked_to is resource.getChild("outbox"))
Example #33
0
        def work():
            dst_uri = "/dst"

            for name in os.listdir(self.docroot):
                if name == "dst":
                    continue

                path = os.path.join(self.docroot, name)

                # Can't really PUT something you can't read
                if not os.path.isfile(path): continue
    
                def do_test(response): checkResult(response, path)
    
                request = SimpleRequest(self.site, "PUT", dst_uri)
                request.stream = FileStream(file(path, "rb"))
    
                yield (request, do_test)
Example #34
0
    def test_renderHTTP(self):
        """
        Test that if the renderHTTP method is ever called we authenticate
        the request and delegate rendering to the wrapper.
        """
        self.protectedResource.responseText = "I hope you can see me."
        self.protectedResource.addSlash = True

        root = wrapper.HTTPAuthResource(self.protectedResource,
                                        [self.credFactory],
                                        self.portal,
                                        interfaces=(IHTTPUser, ))

        request = SimpleRequest(None, "GET", "/")
        request.prepath = ['']

        def _gotSecondResponse(response):
            self.assertEquals(response.code, 200)
            self.assertEquals(str(response.stream.read()),
                              "I hope you can see me.")

        def _gotResponse(exception):
            response = exception.response

            self.assertEquals(response.code, 401)
            self.failUnless(response.headers.hasHeader('WWW-Authenticate'))
            self.assertEquals(response.headers.getHeader('WWW-Authenticate'),
                              [('basic', {
                                  'realm': "test realm"
                              })])

            credentials = base64.encodestring('username:password')

            request.headers.setHeader('authorization', ['basic', credentials])

            d = root.renderHTTP(request)
            d.addCallback(_gotSecondResponse)

        d = self.assertFailure(root.renderHTTP(request), http.HTTPError)

        d.addCallback(_gotResponse)

        return d
    def test_REPORT_unknown(self):
        """
        Unknown/bogus report type
        """
        def do_test(response):
            response = IResponse(response)

            if response.code != responsecode.FORBIDDEN:
                self.fail("Unexpected response code for unknown REPORT: %s"
                          % (response.code,))
        class GoofyReport (davxml.WebDAVUnknownElement):
            namespace = "GOOFY:"
            name      = "goofy-report"
            def __init__(self): super(GoofyReport, self).__init__()

        request = SimpleRequest(self.site, "REPORT", "/")
        request.stream = MemoryStream(GoofyReport().toxml())

        return self.send(request, do_test)
Example #36
0
    def test_renderHTTP(self):
        """
        Test that if the renderHTTP method is ever called we authenticate
        the request and delegate rendering to the wrapper.
        """
        self.protectedResource.responseText = "I hope you can see me."
        self.protectedResource.addSlash = True

        root = wrapper.HTTPAuthResource(self.protectedResource,
                                        [self.credFactory],
                                        self.portal,
                                        interfaces=(IHTTPUser,))

        request = SimpleRequest(None, "GET", "/")
        request.prepath = ['']

        def _gotSecondResponse(response):
            self.assertEquals(response.code, 200)
            self.assertEquals(str(response.stream.read()),
                              "I hope you can see me.")

        def _gotResponse(exception):
            response = exception.response

            self.assertEquals(response.code, 401)
            self.failUnless(response.headers.hasHeader('WWW-Authenticate'))
            self.assertEquals(response.headers.getHeader('WWW-Authenticate'),
                              [('basic', {'realm': "test realm"})])

            credentials = base64.encodestring('username:password')

            request.headers.setHeader('authorization',
                                      ['basic', credentials])

            d = root.renderHTTP(request)
            d.addCallback(_gotSecondResponse)

        d = self.assertFailure(root.renderHTTP(request),
                               http.HTTPError)

        d.addCallback(_gotResponse)

        return d
Example #37
0
    def test_free_busy_set_invalid_url(self):
        """
        Test that calendar-free-busy-set will generate an error if an invalid value is used.
        """

        request = SimpleRequest(self.site, "GET",
                                "/calendars/users/user01/inbox/")
        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
        self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet,
                                                 request)))
        oldfbset = set(("/calendar", ))

        newfbset = set()
        newfbset.update(oldfbset)
        newfbset.add("/calendar-broken")
        newset = caldavxml.CalendarFreeBusySet(
            *[davxml.HRef(url) for url in newfbset])

        self.failUnlessFailure(inbox.writeProperty(newset, request), HTTPError)
Example #38
0
        def work():
            dst_uri = "/dst"

            for name in os.listdir(self.docroot):
                if name == "dst":
                    continue

                path = os.path.join(self.docroot, name)

                # Can't really PUT something you can't read
                if not os.path.isfile(path): continue

                def do_test(response):
                    checkResult(response, path)

                request = SimpleRequest(self.site, "PUT", dst_uri)
                request.stream = FileStream(file(path, "rb"))

                yield (request, do_test)
 def test_authorize(self):
     """
     Authorizing a known user with the correct password will not raise an
     exception, indicating that the user is properly authorized given their
     credentials.
     """
     request = SimpleRequest(self.site, "GET", "/protected")
     request.headers.setHeader(
         "authorization", ("basic", "gooduser:goodpass".encode("base64")))
     return self.checkSecurity(request)
Example #40
0
 def test_isOwnerUnauthenticated(self):
     """
     L{CalDAVResource.isOwner} returns C{False} for unauthenticated requests.
     """
     site = None
     request = SimpleRequest(site, "GET", "/not/a/real/url/")
     request.authzUser = request.authnUser = None
     rsrc = CalDAVResource()
     rsrc.owner = lambda igreq: HRef("/somebody/")
     self.assertEquals((yield rsrc.isOwner(request)), False)
    def test_findChildrenCallbackRaises(self):
        """
        Verify that when the user callback raises an exception
        the completion deferred returned by findChildren errbacks

        TODO: Verify that the user callback doesn't get called subsequently
        """
        def raiseOnChild(resource, uri):
            raise Exception("Oh no!")

        def findChildren(resource):
            return self.assertFailure(
                resource.findChildren("infinity", request, raiseOnChild),
                Exception)

        request = SimpleRequest(self.site, "GET", "/")
        d = request.locateResource("/").addCallback(findChildren)

        return d
Example #42
0
    def test_checkPreconditions_none(self):
        """
        RenderMixin.checkPreconditions()
        checkPreconditions() returns None
        """
        resource = TestResource()
        request = SimpleRequest(Site(resource), "SWEETHOOKUPS", "/")

        # Check that checkPreconditions without a raise doesn't barf
        self.assertEquals((yield resource.renderHTTP(request)),
                          responsecode.NO_CONTENT)
Example #43
0
 def test_isOwnerYes(self):
     """
     L{CalDAVResource.isOwner} returns C{True} for authenticated requests
     with a principal that matches the resource's owner.
     """
     site = None
     request = SimpleRequest(site, "GET", "/not/a/real/url/")
     request.authzUser = request.authnUser = StubPrincipal("/yes-i-am-the-owner/")
     rsrc = CalDAVResource()
     rsrc.owner = lambda igreq: HRef("/yes-i-am-the-owner/")
     self.assertEquals((yield rsrc.isOwner(request)), True)
Example #44
0
    def test_badLink(self):
        resource = CalendarHomeResource(self.site.resource, "home", object(), StubHome())
        self.site.resource.putChild("home", resource)
        link = LinkResource(resource, "/home/outbox/abc")
        resource.putChild("link", link)

        request = SimpleRequest(self.site, "GET", "/home/link/")
        try:
            yield resource.locateChild(request, ["link", ])
        except HTTPError, e:
            self.assertEqual(e.response.code, responsecode.NOT_FOUND)
Example #45
0
    def test_receive_reject_local_originator(self):
        """
        Make calendar
        """

        request = SimpleRequest(
            self.site,
            "POST",
            "/ischedule",
            headers=http_headers.Headers(
                rawHeaders={
                    "Originator": ("mailto:[email protected]", ),
                    "Recipient": ("mailto:[email protected]", ),
                    "Content-Type": ("text/calendar", )
                }),
            content="""BEGIN:VCALENDAR
CALSCALE:GREGORIAN
PRODID:-//Example Inc.//Example Calendar//EN
VERSION:2.0
METHOD:REQUEST
BEGIN:VEVENT
DTSTAMP:20051222T205953Z
CREATED:20060101T150000Z
DTSTART:20060101T100000Z
DURATION:PT1H
SUMMARY:event 1
UID:deadlocked
ORGANIZER:mailto:[email protected]
ATTENDEE;PARTSTAT=ACCEPTED:mailto:[email protected]
ATTENDEE;RSVP=TRUE;PARTSTAT=NEEDS-ACTION:mailto:[email protected]
END:VEVENT
END:VCALENDAR
""".replace("\n", "\r\n"))

        response = (yield self.send(request))
        self.assertEqual(response.code, responsecode.FORBIDDEN)

        calendar = (yield self.calendarUnderTest(name="calendar_1",
                                                 home="user01"))
        count = (yield calendar.listCalendarObjects())
        self.assertEqual(len(count), 0)

        inbox = (yield self.calendarUnderTest(name="inbox", home="user01"))
        count = (yield inbox.listCalendarObjects())
        self.assertEqual(len(count), 0)

        calendar = (yield self.calendarUnderTest(name="calendar_1",
                                                 home="user02"))
        count = (yield calendar.listCalendarObjects())
        self.assertEqual(len(count), 0)

        inbox = (yield self.calendarUnderTest(name="inbox", home="user02"))
        count = (yield inbox.listCalendarObjects())
        self.assertEqual(len(count), 0)
Example #46
0
    def _test_level(self, level):
        def doTest(response):
            response = IResponse(response)

            dav = response.headers.getHeader("dav")
            if not dav: self.fail("no DAV header: %s" % (response.headers, ))
            self.assertIn(level, dav, "no DAV level %s header" % (level, ))

            return response

        return self.send(SimpleRequest(self.site, "OPTIONS", "/"), doTest)
Example #47
0
    def test_Quota_PUT(self):
        """
        Quota change on PUT
        """
        dst_uri = "/dst"

        self.site.resource.setQuotaRoot(None, 90)

        def checkResult(response):
            response = IResponse(response)

            if response.code != responsecode.INSUFFICIENT_STORAGE_SPACE:
                self.fail("Incorrect response code for PUT (%s != %s)"
                          % (response.code, responsecode.INSUFFICIENT_STORAGE_SPACE))

            return self.checkQuota(0)

        request = SimpleRequest(self.site, "PUT", dst_uri)
        request.stream = FileStream(file(os.path.join(os.path.dirname(__file__), "data", "quota_100.txt"), "rb"))
        return self.send(request, checkResult)
Example #48
0
        def work():
            dst_path = os.path.join(self.docroot, "copy_dst")
            dst_uri = "/" + os.path.basename(dst_path)

            for src, status in (
                ("nobind", responsecode.FORBIDDEN),
                ("bind", responsecode.FORBIDDEN),
                ("unbind", responsecode.CREATED),
            ):
                src_path = os.path.join(self.docroot, "src_" + src)
                src_uri = "/" + os.path.basename(src_path)
                if not os.path.isdir(src_path):
                    os.mkdir(src_path)
                src_resource = self.resource_class(src_path)
                src_resource.setAccessControlList({
                    "nobind": self.grant(),
                    "bind"  : self.grant(element.Bind()),
                    "unbind": self.grant(element.Bind(), element.Unbind())
                }[src])
                for name, acl in (
                    ("none"       , self.grant()),
                    ("read"       , self.grant(element.Read())),
                    ("read-write" , self.grant(element.Read(), element.Write())),
                    ("unlock"     , self.grant(element.Unlock())),
                    ("all"        , self.grant(element.All())),
                ):
                    filename = os.path.join(src_path, name)
                    if not os.path.isfile(filename):
                        file(filename, "w").close()
                    self.resource_class(filename).setAccessControlList(acl)

                for method in ("COPY", "MOVE"):
                    for name, code in (
                        ("none", {"COPY": responsecode.FORBIDDEN, "MOVE": status}[method]),
                        ("read", {"COPY": responsecode.CREATED, "MOVE": status}[method]),
                        ("read-write" , {"COPY": responsecode.CREATED, "MOVE": status}[method]),
                        ("unlock", {"COPY": responsecode.FORBIDDEN, "MOVE": status}[method]),
                        ("all", {"COPY": responsecode.CREATED, "MOVE": status}[method]),
                    ):
                        path = os.path.join(src_path, name)
                        uri = src_uri + "/" + name

                        request = SimpleRequest(self.site, method, uri)
                        request.headers.setHeader("destination", dst_uri)
                        _add_auth_header(request)

                        def test(response, code=code, path=path):
                            if os.path.isfile(dst_path):
                                os.remove(dst_path)

                            if response.code != code:
                                return self.oops(request, response, code, method, name)

                        yield (request, test)
Example #49
0
        def work():
            for name, code in (
                ("none"       , responsecode.FORBIDDEN),
                ("read"       , responsecode.FORBIDDEN),
                ("read-write" , responsecode.MULTI_STATUS),
                ("unlock"     , responsecode.FORBIDDEN),
                ("all"        , responsecode.MULTI_STATUS),
            ):
                path = os.path.join(self.docroot, name)

                request = SimpleRequest(self.site, "PROPPATCH", "/" + name)
                request.stream = MemoryStream(
                    element.WebDAVDocument(element.PropertyUpdate()).toxml()
                )
                _add_auth_header(request)

                def test(response, code=code, path=path):
                    if response.code != code:
                        return self.oops(request, response, code, "PROPPATCH", name)

                yield (request, test)
    def test_findChildrenCallbackRaises(self):
        """
        Verify that when the user callback raises an exception
        the completion deferred returned by findChildren errbacks

        TODO: Verify that the user callback doesn't get called subsequently
        """

        def raiseOnChild(resource, uri):
            raise Exception("Oh no!")

        def findChildren(resource):
            return self.assertFailure(
                resource.findChildren("infinity", request, raiseOnChild),
                Exception
            )
        
        request = SimpleRequest(self.site, "GET", "/")
        d = request.locateResource("/").addCallback(findChildren)

        return d
Example #51
0
    def test_free_busy_set_tasks(self):
        """
        Test that calendar-free-busy-set ignores tasks calendar.
        """

        request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/")
        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
        self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet, request)))
        prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request))
        self.assertEqual(
            set([str(child) for child in prop.children]),
            set((
                "/calendars/__uids__/user01/calendar/",
            ))
        )
        newfbset = set()
        newfbset.add("/calendars/users/user01/tasks/")
        newset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in newfbset])

        yield inbox.writeProperty(newset, request)
        yield request._newStoreTransaction.commit()

        request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/")
        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
        prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request))
        self.assertEqual(len(prop.children), 0)
        yield request._newStoreTransaction.commit()
        calendar = yield request.locateResource("/calendars/__uids__/user01/tasks/")
        self.assertFalse(calendar._newStoreObject.isUsedForFreeBusy())
        calendar = yield request.locateResource("/calendars/__uids__/user01/calendar/")
        self.assertFalse(calendar._newStoreObject.isUsedForFreeBusy())
Example #52
0
    def free_busy_query(self, calendar_uri, query, got_calendar):

        request = SimpleRequest(self.site, "MKCALENDAR", calendar_uri)
        response = yield self.send(request)
        response = IResponse(response)

        if response.code != responsecode.CREATED:
            self.fail("MKCALENDAR failed: %s" % (response.code,))

        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.OK:
            self.fail("REPORT failed: %s" % (response.code,))

        result = yield Component.fromIStream(response.stream).addCallback(
            got_calendar
        )
        returnValue(result)
    def test_MKCOL_invalid_body(self):
        """
        MKCOL request with invalid request body
        (Any body at all is invalid in our implementation; there is no
        such thing as a valid body.)
        """
        path, uri = self.mkdtemp("collection")

        rmdir(path)

        def check_result(response):
            response = IResponse(response)

            if response.code != responsecode.UNSUPPORTED_MEDIA_TYPE:
                self.fail("MKCOL response %s != %s" % (response.code, responsecode.UNSUPPORTED_MEDIA_TYPE))

            if os.path.isdir(path):
                self.fail("MKCOL incorrectly created directory %s" % (path,))

        request = SimpleRequest(self.site, "MKCOL", uri)
        request.stream = MemoryStream("This is not a valid MKCOL request body.")

        return self.send(request, check_result)
Example #54
0
    def test_free_busy_set_different(self):
        """
        Test that calendar-free-busy-set has the correct value and can be reset to the same.
        """

        txn = self.transactionUnderTest()
        home = (yield txn.calendarHomeWithUID("user01", create=True))
        yield home.createCalendarWithName("calendar_new")
        yield self.commit()

        request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/")
        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
        self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet, request)))
        prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request))
        self.assertEqual(
            set([str(child) for child in prop.children]),
            set((
                "/calendars/__uids__/user01/calendar/",
                "/calendars/__uids__/user01/calendar_new/",
            ))
        )
        calendar = yield request.locateResource("/calendars/__uids__/user01/calendar_new/")
        self.assertTrue(calendar._newStoreObject.isUsedForFreeBusy())
        calendar = yield request.locateResource("/calendars/__uids__/user01/calendar/")
        self.assertTrue(calendar._newStoreObject.isUsedForFreeBusy())

        newfbset = set()
        newfbset.add("/calendars/users/user01/calendar_new/")
        newset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in newfbset])

        yield inbox.writeProperty(newset, request)
        yield request._newStoreTransaction.commit()

        request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/")
        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
        prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request))
        self.assertEqual(prop.children[0], davxml.HRef("/calendars/__uids__/user01/calendar_new/"))
        yield request._newStoreTransaction.commit()
        calendar = yield request.locateResource("/calendars/__uids__/user01/calendar_new/")
        self.assertTrue(calendar._newStoreObject.isUsedForFreeBusy())
        calendar = yield request.locateResource("/calendars/__uids__/user01/calendar/")
        self.assertFalse(calendar._newStoreObject.isUsedForFreeBusy())
Example #55
0
    def test_PROPFIND_basic(self):
        """
        PROPFIND request
        """
        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 check_xml(doc):
            multistatus = doc.root_element

            if not isinstance(multistatus, davxml.MultiStatus):
                self.fail("PROPFIND response XML root element is not multistatus: %r" % (multistatus,))

            for response in multistatus.childrenOfType(davxml.PropertyStatusResponse):
                if response.childOfType(davxml.HRef) == "/":
                    for propstat in response.childrenOfType(davxml.PropertyStatus):
                        status = propstat.childOfType(davxml.Status)
                        properties = propstat.childOfType(davxml.PropertyContainer).children

                        if status.code != responsecode.OK:
                            self.fail("PROPFIND failed (status %s) to locate live properties: %s"
                                      % (status.code, properties))

                        properties_to_find = [p.qname() for p in self.liveProperties()]

                        for property in properties:
                            qname = property.qname()
                            if qname in properties_to_find:
                                properties_to_find.remove(qname)
                            else:
                                self.fail("PROPFIND found property we didn't ask for: %r" % (property,))

                        if properties_to_find:
                            self.fail("PROPFIND failed to find properties: %r" % (properties_to_find,))

                    break

            else:
                self.fail("No response for URI /")

        query = davxml.PropertyFind(davxml.PropertyContainer(*self.liveProperties()))

        request = SimpleRequest(self.site, "PROPFIND", "/")

        depth = "1"
        if depth is not None:
            request.headers.setHeader("depth", depth)

        request.stream = MemoryStream(query.toxml())

        return self.send(request, check_result)
    def test_findChildren(self):
        """
        This test asserts that we have:
        1) not found any unexpected children
        2) found all expected children

        It does this for all depths C{"0"}, C{"1"}, and C{"infintiy"}
        """
        expected_children = {
            "0": [],
            "1": [
                "/file1",
                "/file2",
                "/dir1/",
                "/dir2/",
            ],
            "infinity": [
                "/file1",
                "/file2",
                "/dir1/",
                "/dir1/subdir1/",
                "/dir2/",
                "/dir2/file1",
                "/dir2/file2",
                "/dir2/subdir1/",
                "/dir2/subdir1/file1",
                "/dir2/subdir1/file2",
            ],
        }

        request = SimpleRequest(self.site, "GET", "/")
        resource = waitForDeferred(request.locateResource("/"))
        yield resource
        resource = resource.getResult()

        def checkChildren(resource, uri):
            self.assertEquals(uri, resource.uri)

            if uri not in expected_children[depth]:
                unexpected_children.append(uri)

            else:
                found_children.append(uri)

        for depth in ["0", "1", "infinity"]:
            found_children = []
            unexpected_children = []

            fc = resource.findChildren(depth, request, checkChildren)
            completed = waitForDeferred(fc)
            yield completed
            completed.getResult()

            self.assertEquals(
                unexpected_children, [],
                "Found unexpected children: %r" % (unexpected_children,)
            )

            expected_children[depth].sort()
            found_children.sort()

            self.assertEquals(expected_children[depth], found_children)
Example #57
0
    def test_PROPPATCH_basic(self):
        """
        PROPPATCH
        """
        # FIXME:
        # Do PROPFIND to make sure it's still there
        # Test nonexistant resource
        # Test None namespace in property

        def check_patch_response(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 PROPPATCH response (%r not in %r)"
                          % (content_type, (http_headers.MimeType("text", "xml"),
                                            http_headers.MimeType("application", "xml"))))

            return davXMLFromStream(response.stream).addCallback(check_patch_xml)

        def check_patch_xml(doc):
            multistatus = doc.root_element

            if not isinstance(multistatus, davxml.MultiStatus):
                self.fail("PROPFIND response XML root element is not multistatus: %r" % (multistatus,))

            # Requested a property change one resource, so there should be exactly one response
            response = multistatus.childOfType(davxml.Response)

            # Should have a response description (its contents are arbitrary)
            response.childOfType(davxml.ResponseDescription)

            # Requested property change was on /
            self.failUnless(
                response.childOfType(davxml.HRef) == "/",
                "Incorrect response URI: %s != /" % (response.childOfType(davxml.HRef),)
            )

            # Requested one property change, so there should be exactly one property status
            propstat = response.childOfType(davxml.PropertyStatus)

            # And the contained property should be a SpiffyProperty
            self.failIf(
                propstat.childOfType(davxml.PropertyContainer).childOfType(SpiffyProperty) is None,
                "Not a SpiffyProperty in PROPPATCH property status: %s" % (propstat.toxml())
            )

            # And the status should be 200
            self.failUnless(
                propstat.childOfType(davxml.Status).code == responsecode.OK,
                "Incorrect status code for PROPPATCH of property %s: %s != %s"
                % (propstat.childOfType(davxml.PropertyContainer).toxml(),
                   propstat.childOfType(davxml.Status).code, responsecode.OK)
            )

        patch = davxml.PropertyUpdate(
            davxml.Set(
                davxml.PropertyContainer(
                    SpiffyProperty.fromString("This is a spiffy resource.")
                )
            )
        )

        request = SimpleRequest(self.site, "PROPPATCH", "/")
        request.stream = MemoryStream(patch.toxml())
        return self.send(request, check_patch_response)