Exemple #1
0
 def mkcol(self, uri):
     """ create a new collection
         see par. 9.3 of rfc4918
     """
     self.parent.log_message('MKCOL: %s' % uri)
     cr, uid, pool, dbname, uri2 = self.get_cr(uri)
     if not uri2[-1]:
         if cr: cr.close()
         raise DAV_Error(409, "Cannot create nameless collection.")
     if not dbname:
         if cr: cr.close()
         raise DAV_Error, 409
     node = self.uri2object(cr, uid, pool, uri2[:-1])
     if not node:
         cr.close()
         raise DAV_Error(409, "Parent path %s does not exist" % uri2[:-1])
     nc = node.child(cr, uri2[-1])
     if nc:
         cr.close()
         raise DAV_Error(405, "Path already exists.")
     self._try_function(node.create_child_collection, (cr, uri2[-1]),
                        "create col %s" % uri2[-1],
                        cr=cr)
     cr.commit()
     cr.close()
     return True
Exemple #2
0
    def lock(self, uri, lock_data):
        """ Lock (may create) resource.
            Data is a dict, may contain:
                depth, token, refresh, lockscope, locktype, owner
        """
        cr, uid, pool, dbname, uri2 = self.get_cr(uri)
        created = False
        if not dbname:
            raise DAV_Error, 409

        try:
            node = self.uri2object(cr, uid, pool, uri2[:])
        except Exception:
            node = False

        objname = misc.ustr(uri2[-1])

        if not node:
            dir_node = self.uri2object(cr, uid, pool, uri2[:-1])
            if not dir_node:
                raise DAV_NotFound('Parent folder not found.')

            # We create a new node (file) but with empty data=None,
            # as in RFC4918 p. 9.10.4
            node = self._try_function(dir_node.create_child,
                                      (cr, objname, None),
                                      "create %s" % objname,
                                      cr=cr)
            if not node:
                cr.commit()
                raise DAV_Error(400, "Failed to create resource.")

            created = True

        try:
            node_fn = node.dav_lock
        except AttributeError:
            # perhaps the node doesn't support locks
            raise DAV_Error(400, 'No locks for this resource.')

        # Obtain the lock on the node
        lres, pid, token = self._try_function(node_fn, (cr, lock_data),
                                              "lock %s" % objname,
                                              cr=cr)

        if not lres:
            cr.commit()
            raise DAV_Error(423, "Resource already locked.")

        assert isinstance(lres, list), 'lres: %s' % repr(lres)

        try:
            data = mk_lock_response(self, uri, lres)
            cr.commit()
        except Exception:
            raise

        return created, data, token
Exemple #3
0
    def do_LOCK(self):
        """ Attempt to place a lock on the given resource.
        """

        dc = self.IFACE_CLASS
        lock_data = {}

        self.log_message('LOCKing resource %s' % self.headers)

        body = None
        if self.headers.has_key('Content-Length'):
            l = self.headers['Content-Length']
            body = self.rfile.read(atoi(l))

        depth = self.headers.get('Depth', 'infinity')

        uri = urlparse.urljoin(self.get_baseuri(dc), self.path)
        uri = urllib.unquote(uri)
        self.log_message('do_LOCK: uri = %s' % uri)

        ifheader = self.headers.get('If')

        if ifheader:
            ldif = IfParser(ifheader)
            if isinstance(ldif, list):
                if len(ldif) !=1 or (not isinstance(ldif[0], TagList)) \
                        or len(ldif[0].list) != 1:
                    raise DAV_Error(400, "Cannot accept multiple tokens.")
                ldif = ldif[0].list[0]
                if ldif[0] == '<' and ldif[-1] == '>':
                    ldif = ldif[1:-1]

            lock_data['token'] = ldif

        if not body:
            lock_data['refresh'] = True
        else:
            lock_data['refresh'] = False
            lock_data.update(self._lock_unlock_parse(body))

        if lock_data['refresh'] and not lock_data.get('token', False):
            raise DAV_Error(400, 'Lock refresh must specify token.')

        lock_data['depth'] = depth

        try:
            created, data, lock_token = dc.lock(uri, lock_data)
        except DAV_Error, (ec, dd):
            return self.send_status(ec, dd)
Exemple #4
0
def _get_caldav_schedule_outbox_URL(self, uri):
    dbname, dburi = self._get_dburi(uri)
    if not dbname:
        raise DAV_NotFound
    pool = Pool(Transaction().database.name)
    try:
        Collection = pool.get('webdav.collection')
    except KeyError:
        raise DAV_NotFound
    if not getattr(Collection, 'get_schedule_outbox_URL', None):
        raise DAV_NotFound
    try:
        res = Collection.get_schedule_outbox_URL(dburi, cache=LOCAL.cache)
    except DAV_Error as exception:
        self._log_exception(exception)
        raise
    except Exception as exception:
        self._log_exception(exception)
        raise DAV_Error(500)
    uparts = list(urllib.parse.urlsplit(uri))
    uparts[2] = urllib.parse.quote(dbname + res)
    doc = domimpl.createDocument(None, 'href', None)
    href = doc.documentElement
    href.tagName = 'D:href'
    huri = doc.createTextNode(urllib.parse.urlunsplit(uparts))
    href.appendChild(huri)
    return href
Exemple #5
0
def _get_caldav_calendar_user_address_set(self, uri):
    dbname, dburi = self._get_dburi(uri)
    if not dbname:
        raise DAV_NotFound
    pool = Pool(Transaction().database.name)
    try:
        Collection = pool.get('webdav.collection')
    except KeyError:
        raise DAV_NotFound
    if not getattr(Collection, 'get_calendar_user_address_set', None):
        raise DAV_NotFound
    try:
        res = Collection.get_calendar_user_address_set(dburi,
                                                       cache=LOCAL.cache)
    except DAV_Error as exception:
        self._log_exception(exception)
        raise
    except Exception as exception:
        self._log_exception(exception)
        raise DAV_Error(500)
    doc = domimpl.createDocument(None, 'href', None)
    href = doc.documentElement
    href.tagName = 'D:href'
    huri = doc.createTextNode('MAILTO:' + res)
    href.appendChild(huri)
    return href
Exemple #6
0
    def get_data(self, uri, rrange=None):
        self.parent.log_message('GET: %s' % uri)
        cr, uid, pool, dbname, uri2 = self.get_cr(uri)
        try:
            if not dbname:
                raise DAV_Error, 409
            node = self.uri2object(cr, uid, pool, uri2)
            if not node:
                raise DAV_NotFound2(uri2)
            # TODO: if node is a collection, for some specific set of
            # clients ( web browsers; available in node context),
            # we may return a pseydo-html page with the directory listing.
            try:
                res = node.open_data(cr, 'r')
                if rrange:
                    assert isinstance(rrange, (tuple, list))
                    start, end = map(long, rrange)
                    if not start:
                        start = 0
                    assert start >= 0
                    if end and end < start:
                        self.parent.log_error("Invalid range for data: %s-%s" %
                                              (start, end))
                        raise DAV_Error(416, "Invalid range for data.")
                    if end:
                        if end >= res.size():
                            raise DAV_Error(
                                416, "Requested data exceeds available size.")
                        length = (end + 1) - start
                    else:
                        length = res.size() - start
                    res = BoundStream2(res, offset=start, length=length)

            except TypeError, e:
                # for the collections that return this error, the DAV standard
                # says we'd better just return 200 OK with empty data
                return ''
            except IndexError, e:
                self.parent.log_error("GET IndexError: %s", str(e))
                raise DAV_NotFound2(uri2)
Exemple #7
0
    def put(self, uri, data, content_type=None):
        """ put the object into the filesystem """
        self.parent.log_message(
            'Putting %s (%d), %s' %
            (misc.ustr(uri), data and len(data) or 0, content_type))
        cr, uid, pool, dbname, uri2 = self.get_cr(uri)
        if not dbname:
            if cr: cr.close()
            raise DAV_Forbidden
        try:
            node = self.uri2object(cr, uid, pool, uri2[:])
        except Exception:
            node = False

        objname = misc.ustr(uri2[-1])

        ret = None
        if not node:
            dir_node = self.uri2object(cr, uid, pool, uri2[:-1])
            if not dir_node:
                cr.close()
                raise DAV_NotFound('Parent folder not found')

            newchild = self._try_function(dir_node.create_child,
                                          (cr, objname, data),
                                          "create %s" % objname,
                                          cr=cr)
            if not newchild:
                cr.commit()
                cr.close()
                raise DAV_Error(400, "Failed to create resource")

            uparts = urlparse.urlparse(uri)
            fileloc = '/'.join(newchild.full_path())
            if isinstance(fileloc, unicode):
                fileloc = fileloc.encode('utf-8')
            # the uri we get is a mangled one, where the davpath has been removed
            davpath = self.parent.get_davpath()

            surl = '%s://%s' % (uparts[0], uparts[1])
            uloc = urllib.quote(fileloc)
            hurl = False
            if uri != ('/' + uloc) and uri != (surl + '/' + uloc):
                hurl = '%s%s/%s/%s' % (surl, davpath, dbname, uloc)
            etag = False
            try:
                etag = str(newchild.get_etag(cr))
            except Exception, e:
                self.parent.log_error("Cannot get etag for node: %s" % e)
            ret = (str(hurl), etag)
Exemple #8
0
def _get_carddav_address_data(self, uri):
    dbname, dburi = self._get_dburi(uri)
    if not dbname:
        raise DAV_NotFound
    pool = Pool(Transaction().database.name)
    try:
        Collection = pool.get('webdav.collection')
    except KeyError:
        raise DAV_NotFound
    try:
        return Collection.get_address_data(dburi, cache=LOCAL.cache)
    except DAV_Error:
        raise
    except Exception:
        raise DAV_Error(500)
Exemple #9
0
 def exists(self, uri):
     dbname, dburi = self._get_dburi(uri)
     if not dbname or not dburi:
         return 1
     pool = Pool(Transaction().database.name)
     Collection = pool.get('webdav.collection')
     try:
         res = Collection.exists(dburi, cache=LOCAL.cache)
     except (DAV_Error, DAV_NotFound, DAV_Secret,
             DAV_Forbidden) as exception:
         self._log_exception(exception)
         raise
     except Exception as exception:
         self._log_exception(exception)
         raise DAV_Error(500)
     return res
Exemple #10
0
 def _get_dav_getcontenttype(self, uri):
     dbname, dburi = self._get_dburi(uri)
     if not dbname or self.is_collection(uri):
         return "text/html"
     pool = Pool(Transaction().database.name)
     Collection = pool.get('webdav.collection')
     try:
         res = Collection.get_contenttype(dburi, cache=LOCAL.cache)
     except (DAV_Error, DAV_NotFound, DAV_Secret,
             DAV_Forbidden) as exception:
         self._log_exception(exception)
         raise
     except Exception as exception:
         self._log_exception(exception)
         raise DAV_Error(500)
     return res
Exemple #11
0
def _get_caldav_post(self, uri, body, contenttype=''):
    dbname, dburi = self._get_dburi(uri)
    if not dbname:
        raise DAV_Forbidden
    pool = Pool(Transaction().database.name)
    Calendar = pool.get('calendar.calendar')
    if not getattr(Calendar, 'post', None):
        raise DAV_NotFound
    try:
        res = Calendar.post(dburi, body)
    except DAV_Error as exception:
        self._log_exception(exception)
        raise
    except Exception as exception:
        self._log_exception(exception)
        raise DAV_Error(500)
    return res
Exemple #12
0
    def get_childs(self, uri, filter=None):
        res = []
        dbname, dburi = self._get_dburi(uri)
        if not dbname:
            with Transaction().start(None, 0, close=True) as transaction:
                list_ = transaction.database.list()
            for dbname in list_:
                res.append(urllib.parse.urljoin(uri, dbname))
            return res
        pool = Pool(Transaction().database.name)
        try:
            Collection = pool.get('webdav.collection')

            scheme, netloc, path, params, query, fragment = \
                urllib.parse.urlparse(uri)

            if not isinstance(uri, str):
                scheme = scheme.decode()
                netloc = netloc.decode()
                path = path.decode()
                params = params.decode()
                query = query.decode()
                fragment = fragment.decode()

            if path[-1:] != '/':
                path = path + '/'
            for child in Collection.get_childs(dburi,
                                               filter=filter,
                                               cache=LOCAL.cache):

                path_child = (path + child)
                res.append(
                    urllib.parse.urlunparse(
                        (scheme, netloc, path_child, params, query, fragment)))
        except KeyError:
            return res
        except (DAV_Error, DAV_NotFound, DAV_Secret,
                DAV_Forbidden) as exception:
            self._log_exception(exception)
            raise
        except Exception as exception:
            self._log_exception(exception)
            raise DAV_Error(500)

        return res
Exemple #13
0
 def _get_dav_displayname(self, uri):
     dbname, dburi = self._get_dburi(uri)
     if not dbname or not dburi:
         return uri.decode().split('/')[-1]
     pool = Pool(Transaction().database.name)
     try:
         Collection = pool.get('webdav.collection')
         res = Collection.get_displayname(dburi, cache=LOCAL.cache)
     except KeyError:
         raise DAV_NotFound
     except (DAV_Error, DAV_NotFound, DAV_Secret,
             DAV_Forbidden) as exception:
         self._log_exception(exception)
         raise
     except Exception as exception:
         self._log_exception(exception)
         raise DAV_Error(500)
     return res
Exemple #14
0
    def _try_function(self, funct, args, opname='run function', cr=None,
            default_exc=DAV_Forbidden):
        """ Try to run a function, and properly convert exceptions to DAV ones.

            @objname the name of the operation being performed
            @param cr if given, the cursor to close at exceptions
        """

        try:
            return funct(*args)
        except DAV_Error:
            raise
        except NotImplementedError, e:
            import traceback
            self.parent.log_error("Cannot %s: %s", opname, str(e))
            self.parent.log_message("Exc: %s",traceback.format_exc())
            # see par 9.3.1 of rfc
            raise DAV_Error(403, str(e) or 'Not supported at this path.')
Exemple #15
0
    def unlock(self, uri, token):
        """ Unlock a resource from that token

        @return True if unlocked, False if no lock existed, Exceptions
        """
        cr, uid, pool, dbname, uri2 = self.get_cr(uri)
        if not dbname:
            raise DAV_Error, 409

        node = self.uri2object(cr, uid, pool, uri2)
        try:
            node_fn = node.dav_unlock
        except AttributeError:
            # perhaps the node doesn't support locks
            raise DAV_Error(400, 'No locks for this resource.')

        res = self._try_function(node_fn, (cr, token), "unlock %s" % uri, cr=cr)
        cr.commit()
        return res
Exemple #16
0
def _get_caldav_calendar_data(self, uri):
    dbname, dburi = self._get_dburi(uri)
    if not dbname:
        raise DAV_NotFound
    pool = Pool(Transaction().database.name)
    try:
        Collection = pool.get('webdav.collection')
    except KeyError:
        raise DAV_NotFound
    if not getattr(Collection, 'get_calendar_data', None):
        raise DAV_NotFound
    try:
        res = Collection.get_calendar_data(dburi, cache=LOCAL.cache)
    except DAV_Error as exception:
        self._log_exception(exception)
        raise
    except Exception as exception:
        self._log_exception(exception)
        raise DAV_Error(500)
    return res
Exemple #17
0
 def put(self, uri, data, content_type=''):
     dbname, dburi = self._get_dburi(uri)
     if not dbname or not dburi:
         raise DAV_Forbidden
     pool = Pool(Transaction().database.name)
     Collection = pool.get('webdav.collection')
     try:
         res = Collection.put(dburi, data, content_type, cache=LOCAL.cache)
         Transaction().commit()
     except (DAV_Error, DAV_NotFound, DAV_Secret,
             DAV_Forbidden) as exception:
         self._log_exception(exception)
         Transaction().rollback()
     except Exception as exception:
         self._log_exception(exception)
         Transaction().rollback()
         raise DAV_Error(500)
     if res:
         uparts = list(urllib.parse.urlsplit(uri))
         uparts[2] = res.encode()
         res = urllib.parse.urlunsplit(uparts)
     return res
Exemple #18
0
        raise DAV_NotFound
    pool = Pool(Transaction().cursor.database_name)
    try:
        Collection = pool.get('webdav.collection')
    except KeyError:
        raise DAV_NotFound
    try:
        res = Collection.get_calendar_description(dburi, cache=CACHE)
    except AttributeError:
        raise DAV_NotFound
    except DAV_Error, exception:
        self._log_exception(exception)
        raise
    except Exception, exception:
        self._log_exception(exception)
        raise DAV_Error(500)
    return res

TrytonDAVInterface._get_caldav_calendar_description = \
    _get_caldav_calendar_description


def _get_caldav_calendar_data(self, uri):
    dbname, dburi = self._get_dburi(uri)
    if not dbname:
        raise DAV_NotFound
    pool = Pool(Transaction().cursor.database_name)
    try:
        Collection = pool.get('webdav.collection')
    except KeyError:
        raise DAV_NotFound
Exemple #19
0
    def get_data(self, uri, range=None):

        uri = uri.decode()

        dbname, dburi = self._get_dburi(uri)
        if not dbname or (self.exists(uri) and self.is_collection(uri)):
            res = ('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 '
                   'Transitional//EN">')
            res += '<html>'
            res += '<head>'
            res += ('<meta http-equiv="Content-Type" content="text/html; '
                    'charset=utf-8">')
            res += '<title>Tryton - WebDAV - %s</title>' % dbname or 'root'
            res += '</head>'
            res += '<body>'
            res += '<h2>Collection: %s</h2>' % (get_urifilename(uri) or '/')
            res += '<ul>'
            if dbname:
                scheme, netloc, path, params, query, fragment = \
                    urllib.parse.urlparse(uri)
                if path[-1:] != '/':
                    path += '/'
                res += ('<li><a href="%s">..</a></li>' %
                        urllib.parse.urlunparse((scheme, netloc, path + '..',
                                                 params, query, fragment)))
            childs = self.get_childs(uri)
            childs.sort()
            for child in childs:
                res += ('<li><a href="%s">%s</a></li>' %
                        (quote_uri(child), get_urifilename(child)))
            res += '</ul>'
            res += '<hr noshade>'
            res += ('<em>Powered by <a href="http://www.tryton.org/">'
                    'Tryton</a> version %s</em>' % __version__)
            res += '</body>'
            res += '</html>'
            return res
        pool = Pool(Transaction().database.name)
        Collection = pool.get('webdav.collection')

        try:
            res = Collection.get_data(dburi, cache=LOCAL.cache)
        except (DAV_Error, DAV_NotFound, DAV_Secret,
                DAV_Forbidden) as exception:
            self._log_exception(exception)
            raise
        except Exception as exception:
            self._log_exception(exception)
            raise DAV_Error(500)
        if range is None:
            return res
        size = len(res)
        if range[1] == '':
            range[1] = size
        else:
            range[1] = int(range[1])
        if range[1] > size:
            range[1] = size
        if range[0] == '':
            range[0] = size - range[1]
        else:
            range[0] = int(range[0])
        if range[0] > size:
            raise DAV_Requested_Range_Not_Satisfiable

        return res[range[0]:range[1]]
Exemple #20
0
class TrytonDAVInterface(iface.dav_interface):
    def __init__(self, interface, port, secure=False):
        if secure:
            protocol = 'https'
        else:
            protocol = 'http'
        self.baseuri = '%s://%s:%s/' % (protocol, interface
                                        or socket.gethostname(), port)
        self.verbose = False

    def _log_exception(self, exception):
        if isinstance(exception,
                      (NotLogged, ConcurrencyException, UserError, UserWarning,
                       DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden)):
            logger.debug('Exception %s', exception, exc_info=True)
        else:
            logger.error('Exception %s', exception, exc_info=True)

    @staticmethod
    def get_dburi(uri):
        uri = urlparse.urlsplit(uri)[2]
        if uri and uri[0] == '/':
            uri = uri[1:]
        dbname, uri = (uri.split('/', 1) + [None])[0:2]
        if dbname:
            dbname = urllib.unquote_plus(dbname)
        if uri:
            uri = urllib.unquote_plus(uri)
        return dbname, uri

    def _get_dburi(self, uri):
        return TrytonDAVInterface.get_dburi(uri)

    def get_childs(self, uri, filter=None):
        res = []
        dbname, dburi = self._get_dburi(uri)
        if not dbname:
            database = backend.get('Database')().connect()
            cursor = database.cursor()
            try:
                lists = database.list(cursor)
            except Exception:
                lists = []
            finally:
                cursor.close()
            for dbname in lists:
                res.append(urlparse.urljoin(uri, dbname))
            return res
        pool = Pool(Transaction().cursor.database_name)
        try:
            Collection = pool.get('webdav.collection')
            scheme, netloc, path, params, query, fragment = \
                urlparse.urlparse(uri)
            if path[-1:] != '/':
                path += '/'
            for child in Collection.get_childs(dburi,
                                               filter=filter,
                                               cache=CACHE):
                res.append(
                    urlparse.urlunparse(
                        (scheme, netloc, path + child.encode('utf-8'), params,
                         query, fragment)))
        except KeyError:
            return res
        except (DAV_Error, DAV_NotFound, DAV_Secret, DAV_Forbidden), exception:
            self._log_exception(exception)
            raise
        except Exception, exception:
            self._log_exception(exception)
            raise DAV_Error(500)