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
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)
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)
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)
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')
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
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