def test_url_15(url0, url0b, url1):
    # 4b) join method, with URL as input parameter
    url2 = URL.objectify(url1)
    url6 = url1.join(URL.objectify(url2))
    assert url6 == url1

    url6b = url6.join(url0)
    url6c = url6.join(url0b)

    url6d = url6.join(None)
    for url6alt in (url6b, url6c, url6d):
        assert url6 == url6alt
Esempio n. 2
0
    async def ainit(self):
        """Method called after construction in order to asynchronously init the object.

        no args, only asynchronous.
        """
        # backwards compatibility.
        if self._url is not None:
            self.url = self.client.url.join(URL.objectify(self._url))
        else:
            self.url = self.client.url
            await asyncio.sleep(1)
            cup = await self.get_properties([dav.CurrentUserPrincipal()])
            self.url = self.client.url.join(
                URL.objectify(cup['{DAV:}current-user-principal']))
        return self
Esempio n. 3
0
    def __init__(self,
                 client=None,
                 url=None,
                 parent=None,
                 name=None,
                 id=None,
                 **extra):
        """
        Default constructor.

        Parameters:
         * client: A DAVClient instance
         * url: The url for this object.  May be a full URL or a relative URL.
         * parent: The parent object - used when creating objects
         * name: A displayname
         * id: The resource id (UID for an Event)
        """

        if client is None and parent is not None:
            client = parent.client
        self.client = client
        self.parent = parent
        self.name = name
        self.id = id
        self.extra_init_options = extra
        # url may be a path relative to the caldav root
        if client and url:
            self.url = client.url.join(url)
        else:
            self.url = URL.objectify(url)
def test_url_16(url1, url3):
    url7 = url1.join(URL.objectify(url3))
    assert url7 == "http://*****:*****@www.example.com:8080/bar"
    assert url7.username == 'foo'
    assert url7.is_auth() is True
    # 7) unauth() strips username/password
    assert url7.unauth() == 'http://www.example.com:8080/bar'
Esempio n. 5
0
 def _calendar_home_setter(self, url):
     # TODO: Handle when url is None ?
     if isinstance(url, CalendarSet):
         self._calendar_home_set = url
         return url
     sanitized_url = URL.objectify(url)
     if (sanitized_url.hostname
             and sanitized_url.hostname != self.client.url.hostname):
         # icloud (and others?) having a load balanced system,
         # where each principal resides on one named host
         self.client.url = sanitized_url
     self._calendar_home_set = CalendarSet(
         self.client, self.client.url.join(sanitized_url))
     return self._calendar_home_set
Esempio n. 6
0
    async def save(self):
        """
        The save method for a calendar is only used to create it, for now.
        We know we have to create it when we don't have a url.

        Returns:
         * self
        """
        if self.url is None:
            await self._create(name=self.name,
                               id=self.id,
                               **self.extra_init_options)
            if not self.url.endswith('/'):
                self.url = URL.objectify(str(self.url) + '/')
        return self
Esempio n. 7
0
    async def object_by_uid(self, uid, comp_filter=None):
        """
        Get one event from the calendar.

        Parameters:
         * uid: the event uid

        Returns:
         * Event() or None
        """
        data = cdav.CalendarData()
        prop = dav.Prop() + data

        query = cdav.TextMatch(uid)
        query = cdav.PropFilter("UID") + query
        if comp_filter:
            query = comp_filter + query
        vcalendar = cdav.CompFilter("VCALENDAR") + query
        filter = cdav.Filter() + vcalendar

        root = cdav.CalendarQuery() + [prop, filter]

        response = await self._query(root, 1, 'report')

        if response.status == 404:
            raise error.NotFoundError(errmsg(response))
        elif response.status == 400:
            raise error.ReportError(errmsg(response))

        items_found = response.tree.findall(".//" + dav.Response.tag)
        for r in items_found:
            href = unquote(r.find(".//" + dav.Href.tag).text)
            data = unquote(r.find(".//" + cdav.CalendarData.tag).text)
            # Ref Lucas Verney, we've actually done a substring search, if the
            # uid given in the query is short (i.e. just "0") we're likely to
            # get false positives back from the server.
            #
            # Long uids are folded, so splice the lines together here before
            # attempting a match.
            item_uid = re.search(r'\nUID:((.|\n[ \t])*)\n', data)
            if (not item_uid
                    or re.sub(r'\n[ \t]', '', item_uid.group(1)) != uid):
                continue
            return self._calendar_comp_class_by_data(data)(
                self.client, url=URL.objectify(href), data=data, parent=self)
        raise error.NotFoundError(errmsg(response))
Esempio n. 8
0
    async def _create(self, data, id=None, path=None, new=False):
        if id is None and path is not None and str(path).endswith('.ics'):
            id = re.search('(/|^)([^/]*).ics', str(path)).group(2)
        elif id is None:
            for obj_type in ('vevent', 'vtodo', 'vjournal', 'vfreebusy',
                             'vavailability'):
                obj = None
                if hasattr(self.instance, obj_type):
                    obj = getattr(self.instance, obj_type)
                elif self.instance.name.lower() == obj_type:
                    obj = self.instance
                if obj is not None:
                    id = obj.uid.value
                    break
        else:
            for obj_type in ('vevent', 'vtodo', 'vjournal', 'vfreebusy',
                             'vavailability'):
                obj = None
                if hasattr(self.instance, obj_type):
                    obj = getattr(self.instance, obj_type)
                elif self.instance.name.lower() == obj_type:
                    obj = self.instance
                if obj is not None:
                    if not hasattr(obj, 'uid'):
                        obj.add('uid')
                    obj.uid = id
                    break
        if path is None and id is not None:
            path = id + ".ics"
        if path is None and id is None:
            raise error.PutError("Nothing to do: no content")
        path = self.parent.url.join(path)
        headers = {"Content-Type": 'text/calendar; charset="utf-8"'}
        if new:
            headers["If-None-Match"] = "*"
        else:
            headers["If-Match"] = "*"
        r = await self.client.put(path, data, headers)

        if r.status == 302:
            path = [x[1] for x in r.headers if x[0] == 'location'][0]
        elif not (r.status in (204, 201)):
            raise error.PutError(errmsg(r))

        self.url = URL.objectify(path)
        self.id = id
Esempio n. 9
0
    def __init__(self, url, proxy=None, username=None, password=None,
                 auth=None, ssl_verify_cert=None):
        """
        Sets up a HTTPConnection object towards the server in the url.
        Parameters:
         * url: A fully qualified url: `scheme://user:pass@hostname:port`
         * proxy: A string defining a proxy server: `hostname:port`
         * username and password should be passed as arguments or in the URL
         * auth and ssl_verify_cert is passed to aiohttp.request.
         ** ssl_verify_cert can be None (default verify) or False or a ssl.SSLContext
        """

        log.debug("url: " + str(url))
        self.url = URL.objectify(url)

        # Prepare proxy info
        if proxy is not None:
            self.proxy = proxy
            # library expects the proxy url to have a scheme
            if re.match('^.*://', proxy) is None:
                self.proxy = self.url.scheme + '://' + proxy

            # add a port is one is not specified
            # TODO: this will break if using basic auth and embedding
            # username:password in the proxy URL
            p = self.proxy.split(":")
            if len(p) == 2:
                self.proxy += ':8080'
            log.debug("init - proxy: %s" % (self.proxy))

        # Build global headers
        self.headers = {"User-Agent": "Mozilla/5.0",
                        "Content-Type": "text/xml",
                        "Accept": "text/xml"}
        if self.url.username is not None:
            username = unquote(self.url.username)
            password = unquote(self.url.password)

        self.username = username
        self.password = password
        self.auth = auth
        # TODO: it's possible to force through a specific auth method here,
        # but no test code for this.
        self.ssl_verify_cert = ssl_verify_cert
        self.url = self.url.unauth()
        log.debug("self.url: " + str(url))
Esempio n. 10
0
    async def _query(self,
                     root=None,
                     depth=0,
                     query_method='propfind',
                     url=None,
                     expected_return_value=None):
        """
        This is an internal method for doing a query.  It's a
        result of code-refactoring work, attempting to consolidate
        similar-looking code into a common method.
        """
        # ref https://bitbucket.org/cyrilrbt/caldav/issues/46 -
        # COMPATIBILITY ISSUE. The lines below seems to solve real
        # world problems, though I believe it's the wrong place to
        # inject the missing slash.
        # TODO: find out why the slash is missing and fix
        # it properly.
        # Background: Collection URLs ends with a slash,
        # non-collection URLs does not end with a slash.  If the
        # slash is missing, Servers MAY pretend it's present (RFC
        # 4918, section 5.2, cprint(ollection resources), hence only some
        # few servers break when the slash is missing.  RFC 4918
        # specifies that collection URLs end with a slash while
        # non-collection URLs should not end with a slash.
        if url is None:
            url = self.url
            if not url.endswith('/'):
                url = URL(str(url) + '/')

        body = ""
        if root:
            body = etree.tostring(root.xmlelement(),
                                  encoding="utf-8",
                                  xml_declaration=True)
        # print("QUERY: %s, URL:%s, BODY:%s" % (query_method, url, body))
        ret = await getattr(self.client, query_method)(url, body, depth)
        if ret.status == 404:
            raise error.NotFoundError(errmsg(ret))
        if ((expected_return_value is not None
             and ret.status != expected_return_value) or ret.status >= 400):
            raise error.exception_by_method[query_method](errmsg(ret))
        return ret
Esempio n. 11
0
    def calendar(self, name=None, cal_id=None):
        """
        The calendar method will return a calendar object.  It will not
        initiate any communication with the server.

        Parameters:
         * name: return the calendar with this name
         * cal_id: return the calendar with this calendar id

        Returns:
         * Calendar(...)-object
        """
        cal = Calendar(self.client,
                       name=name,
                       parent=self,
                       url=self.url.join(cal_id),
                       id=cal_id)
        # check url for consistency with Calendar.save() method
        if not cal.url.endswith('/'):
            cal.url = URL.objectify(str(cal.url) + '/')
        return cal
Esempio n. 12
0
def test_url_18(url1, url5):
    url9 = url1.join(URL.objectify(url5))
    assert url9 == "http://*****:*****@www.example.com:8080/bar"
Esempio n. 13
0
def test_url_10(url1):
    url4 = URL.objectify(urlparse(str(url1)))
    url8 = url1.join(url4)
    assert url8 == url1
Esempio n. 14
0
def test_url_8(url1):
    # 4) join method
    url2 = URL.objectify(url1)
    url6 = url1.join(url2)
    assert url6 == url1
Esempio n. 15
0
def url0b(request):
    return URL.objectify("")
Esempio n. 16
0
def test_url_2(url1):
    url4 = URL.objectify(urlparse(str(url1)))
    assert url1 == url4
Esempio n. 17
0
def test_url_19(url1):
    urlA = url1.join(URL.objectify("someuser/calendar"))
    assert urlA == "http://*****:*****@www.example.com:8080/caldav.php/someuser/calendar"
Esempio n. 18
0
def url3(request):
    return URL.objectify("/bar")
Esempio n. 19
0
def url1(request):
    return URL.objectify(LONG_URL)
Esempio n. 20
0
def test_url_22(url1):
    urlC = URL.objectify("https://www.example.com:443/foo")
    assert urlC.port == 443

    # 6) is_auth returns True if the URL contains a username.
    assert urlC.is_auth() is False
Esempio n. 21
0
def url0(request):
    return URL.objectify(None)
Esempio n. 22
0
def test_url_6(url1):
    url4 = URL.objectify(urlparse(str(url1)))
    assert str(url4) == LONG_URL
Esempio n. 23
0
def url5(request):
    return URL.objectify(urlparse("/bar"))
Esempio n. 24
0
def test_url_20(url1, url5):
    urlB = url5.join(URL.objectify(url1))
    assert urlB == url1
Esempio n. 25
0
def test_url_1(url1):
    # 1) URL.objectify should return a valid URL object almost no matter
    # what's thrown in
    url2 = URL.objectify(url1)
    assert url1 == url2
    assert url2.path == '/caldav.php/'
Esempio n. 26
0
    async def request(self, url, method="GET", body="", headers={}):
        """
        Actually sends the request
        """

        # objectify the url
        url = URL.objectify(url)

        proxy = None
        if self.proxy is not None:
            proxy = self.proxy
            log.debug("using proxy - %s", proxy)

        # ensure that url is a unicode string
        url = str(url)

        combined_headers = dict(self.headers)
        combined_headers.update(headers)
        if body is None or body == "" and "Content-Type" in combined_headers:
            del combined_headers["Content-Type"]

        log.debug(
            "sending request - method={0}, url={1}, headers={2}\nbody:\n{3}"
            .format(method, url, combined_headers, body))
        print("sending request - method={0}, url={1}, headers={2}\nbody:\n{3}"
              .format(method, url, combined_headers, body))
        auth = None
        # digest auth is not (yet) supported by aiohttp, so skip it for now
        # if self.auth is None and self.username is not None:
        #     auth = aiohttp.HTTPDigestAuth(self.username, self.password)
        # else:
        #     auth = self.auth

        # async with aiohttp.ClientSession() as client:
        # r = await client.request(
        #     method, url, data=to_wire(body),
        #     headers=combined_headers, proxy=proxy,
        #     auth=auth, ssl=self.ssl_verify_cert)
        # response = DAVResponse()
        # await response.load(r)

        # If server supports BasicAuth and not DigestAuth, let's try again:
        # if response.status == 401 and self.auth is None and auth is not None:
        if self.auth is None and self.username is not None:
            auth = aiohttp.BasicAuth(self.username, self.password)
        else:
            auth = self.auth
        # TODO: Define total timeout in config ?
        async with aiohttp.ClientSession(
                timeout=aiohttp.ClientTimeout(total=30)) as client:
            r = await client.request(
                method, url, data=to_wire(body),
                headers=combined_headers, proxy=proxy,
                auth=auth, ssl=self.ssl_verify_cert)
            response = DAVResponse()
            await response.load(r)
       
        # this is an error condition the application wants to know
        if response.status in (401, 403):  # forbidden or unauthorized
            ex = error.AuthorizationError()
            ex.url = url
            ex.reason = response.reason
            raise ex

        # let's save the auth object and remove the user/pass information
        if not self.auth and auth:
            self.auth = auth
            del self.username
            del self.password

        return response