Exemplo n.º 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
Exemplo n.º 2
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)
Exemplo n.º 3
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)
Exemplo n.º 4
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)
Exemplo n.º 5
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:
            if cr: cr.close()
            raise
        except NotImplementedError, e:
            if cr: cr.close()
            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')
Exemplo n.º 6
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:
            if cr: cr.close()
            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
            cr.close()
            raise DAV_Error(400, 'No locks for this resource')

        res = self._try_function(node_fn, (cr, token), "unlock %s" % uri, cr=cr)
        cr.commit()
        cr.close()
        return res
Exemplo n.º 7
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:
            if cr: cr.close()
            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:
                cr.close()
                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()
                cr.close()
                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
            cr.close()
            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()
            cr.close()
            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:
            cr.close()
            raise

        cr.close()
        return created, data, token