def HEAD(self, REQUEST, RESPONSE): """Retrieve resource information without a response body.""" self.dav__init(REQUEST, RESPONSE) content_type=None if hasattr(self, 'content_type'): content_type=absattr(self.content_type) if content_type is None: url=urlfix(REQUEST['URL'], 'HEAD') name=unquote(filter(None, url.split( '/')[-1])) content_type, encoding=mimetypes.guess_type(name) if content_type is None: if hasattr(self, 'default_content_type'): content_type=absattr(self.default_content_type) if content_type is None: content_type = 'application/octet-stream' RESPONSE.setHeader('Content-Type', content_type.lower()) if hasattr(aq_base(self), 'get_size'): RESPONSE.setHeader('Content-Length', absattr(self.get_size)) if hasattr(self, '_p_mtime'): mtime=rfc1123_date(self._p_mtime) RESPONSE.setHeader('Last-Modified', mtime) if hasattr(aq_base(self), 'http__etag'): etag = self.http__etag(readonly=1) if etag: RESPONSE.setHeader('Etag', etag) RESPONSE.setStatus(200) return RESPONSE
def apply(self, obj, token, url=None, result=None, top=1): if result is None: result = StringIO() url = urlfix(url, 'UNLOCK') url = urlbase(url) iscol = isDavCollection(obj) if iscol and url[-1] != '/': url = url + '/' errmsg = None islockable = IWriteLock.providedBy(obj) or \ WriteLockInterface.isImplementedBy(obj) if islockable and obj.wl_hasLock(token): method = getattr(obj, 'wl_delLock') vld = getSecurityManager().validate(None,obj,'wl_delLock',method) if vld: obj.wl_delLock(token) else: errmsg = "403 Forbidden" elif not islockable: # Only set an error message if the command is being applied # to a top level object. Otherwise, we're descending a tree # which may contain many objects that don't implement locking, # so we just want to avoid them if top: errmsg = "405 Method Not Allowed" if errmsg: if top and (not iscol): # We don't need to raise multistatus errors if errmsg[:3] == '403': raise Forbidden else: raise PreconditionFailed elif not result.getvalue(): # We haven't had any errors yet, so our result is empty # and we need to set up the XML header result.write('<?xml version="1.0" encoding="utf-8" ?>\n' \ '<d:multistatus xmlns:d="DAV:">\n') result.write('<d:response>\n <d:href>%s</d:href>\n' % url) result.write(' <d:status>HTTP/1.1 %s</d:status>\n' % errmsg) result.write('</d:response>\n') if iscol: for ob in obj.objectValues(): if hasattr(ob, '__dav_resource__') and \ (IWriteLock.providedBy(ob) or WriteLockInterface.isImplementedBy(ob)): uri = urljoin(url, absattr(ob.getId())) self.apply(ob, token, uri, result, top=0) if not top: return result if result.getvalue(): # One or more subitems probably failed, so close the multistatus # element and clear out all succesful unlocks result.write('</d:multistatus>') transaction.abort() return result.getvalue()
def apply(self, obj, token, user, url=None, result=None, top=1): if result is None: result = StringIO() url = urlfix(url, 'DELETE') url = urlbase(url) iscol = isDavCollection(obj) errmsg = None parent = aq_parent(obj) islockable = IWriteLock.providedBy(obj) or \ WriteLockInterface.isImplementedBy(obj) if parent and (not user.has_permission('Delete objects', parent)): # User doesn't have permission to delete this object errmsg = "403 Forbidden" elif islockable and obj.wl_isLocked(): if token and obj.wl_hasLock(token): # Object is locked, and the token matches (no error) errmsg = "" else: errmsg = "423 Locked" if errmsg: if top and (not iscol): err = errmsg[4:] raise err elif not result.getvalue(): # We haven't had any errors yet, so our result is empty # and we need to set up the XML header result.write('<?xml version="1.0" encoding="utf-8" ?>\n' \ '<d:multistatus xmlns:d="DAV:">\n') result.write('<d:response>\n <d:href>%s</d:href>\n' % url) result.write(' <d:status>HTTP/1.1 %s</d:status>\n' % errmsg) result.write('</d:response>\n') if iscol: for ob in obj.objectValues(): dflag = hasattr(ob,'_p_changed') and (ob._p_changed == None) if hasattr(ob, '__dav_resource__'): uri = urljoin(url, absattr(ob.getId())) self.apply(ob, token, user, uri, result, top=0) if dflag: ob._p_deactivate() if not top: return result if result.getvalue(): # One or more subitems can't be delted, so close the multistatus # element result.write('</d:multistatus>\n') return result.getvalue()
def apply(self, obj, url=None, depth=0, result=None, top=1): if result is None: result=StringIO() depth=self.depth url=urlfix(self.request['URL'], 'PROPFIND') url=urlbase(url) result.write('<?xml version="1.0" encoding="utf-8"?>\n' \ '<d:multistatus xmlns:d="DAV:">\n') iscol=isDavCollection(obj) if iscol and url[-1] != '/': url=url+'/' result.write('<d:response>\n<d:href>%s</d:href>\n' % safe_quote(url)) if hasattr(aq_base(obj), 'propertysheets'): propsets=obj.propertysheets.values() obsheets=obj.propertysheets else: davprops=DAVProps(obj) propsets=(davprops,) obsheets={'DAV:': davprops} if self.allprop: stats=[] for ps in propsets: if hasattr(aq_base(ps), 'dav__allprop'): stats.append(ps.dav__allprop()) stats=''.join(stats) or '<d:status>200 OK</d:status>\n' result.write(stats) elif self.propname: stats=[] for ps in propsets: if hasattr(aq_base(ps), 'dav__propnames'): stats.append(ps.dav__propnames()) stats=''.join(stats) or '<d:status>200 OK</d:status>\n' result.write(stats) elif self.propnames: rdict={} for name, ns in self.propnames: ps=obsheets.get(ns, None) if ps is not None and hasattr(aq_base(ps), 'dav__propstat'): stat=ps.dav__propstat(name, rdict) else: prop='<n:%s xmlns:n="%s"/>' % (name, ns) code='404 Not Found' if not rdict.has_key(code): rdict[code]=[prop] else: rdict[code].append(prop) keys=rdict.keys() keys.sort() for key in keys: result.write('<d:propstat>\n' \ ' <d:prop>\n' \ ) map(result.write, rdict[key]) result.write(' </d:prop>\n' \ ' <d:status>HTTP/1.1 %s</d:status>\n' \ '</d:propstat>\n' % key ) else: raise 'Bad Request', 'Invalid request' result.write('</d:response>\n') if depth in ('1', 'infinity') and iscol: for ob in obj.objectValues(): if hasattr(ob,"meta_type"): if ob.meta_type=="Broken Because Product is Gone": continue dflag=hasattr(ob, '_p_changed') and (ob._p_changed == None) if hasattr(ob, '__locknull_resource__'): # Do nothing, a null resource shouldn't show up to DAV if dflag: ob._p_deactivate() elif hasattr(ob, '__dav_resource__'): uri=os.path.join(url, absattr(ob.id)) depth=depth=='infinity' and depth or 0 self.apply(ob, uri, depth, result, top=0) if dflag: ob._p_deactivate() if not top: return result result.write('</d:multistatus>') return result.getvalue()
if top and ((depth in (0, '0')) or (not iscol)): # We don't need to raise multistatus errors raise errmsg[4:] elif not result.getvalue(): # We haven't had any errors yet, so our result is empty # and we need to set up the XML header result.write('<?xml version="1.0" encoding="utf-8" ?>\n' \ '<d:multistatus xmlns:d="DAV:">\n') result.write('<d:response>\n <d:href>%s</d:href>\n' % url) result.write(' <d:status>HTTP/1.1 %s</d:status>\n' % errmsg) result.write('</d:response>\n') if depth == 'infinity' and iscol: for ob in obj.objectValues(): if hasattr(obj, '__dav_resource__'): uri = os.path.join(url, absattr(ob.id)) self.apply(ob, creator, depth, token, result, uri, top=0) if not top: return token, result if result.getvalue(): # One or more subitems probably failed, so close the multistatus # element and clear out all succesful locks result.write('</d:multistatus>') get_transaction().abort() # This *SHOULD* clear all succesful locks return token, result.getvalue() class Unlock: """ Model an Unlock request """ def apply(self, obj, token, url=None, result=None, top=1):
def apply(self, obj, creator=None, depth='infinity', token=None, result=None, url=None, top=1): """ Apply, built for recursion (so that we may lock subitems of a collection if requested """ if result is None: result = StringIO() url = urlfix(self.request['URL'], 'LOCK') url = urlbase(url) iscol = isDavCollection(obj) if iscol and url[-1] != '/': url = url + '/' errmsg = None lock = None try: lock = LockItem(creator, self.owner, depth, self.timeout, self.type, self.scope, token) if token is None: token = lock.getLockToken() except ValueError: errmsg = "412 Precondition Failed" except: errmsg = "403 Forbidden" try: if not (IWriteLock.providedBy(obj) or WriteLockInterface.isImplementedBy(obj)): if top: # This is the top level object in the apply, so we # do want an error errmsg = "405 Method Not Allowed" else: # We're in an infinity request and a subobject does # not support locking, so we'll just pass pass elif obj.wl_isLocked(): errmsg = "423 Locked" else: method = getattr(obj, 'wl_setLock') vld = getSecurityManager().validate(None, obj, 'wl_setLock', method) if vld and token and (lock is not None): obj.wl_setLock(token, lock) else: errmsg = "403 Forbidden" except: errmsg = "403 Forbidden" if errmsg: if top and ((depth in (0, '0')) or (not iscol)): # We don't need to raise multistatus errors raise errmsg[4:] elif not result.getvalue(): # We haven't had any errors yet, so our result is empty # and we need to set up the XML header result.write('<?xml version="1.0" encoding="utf-8" ?>\n' \ '<d:multistatus xmlns:d="DAV:">\n') result.write('<d:response>\n <d:href>%s</d:href>\n' % url) result.write(' <d:status>HTTP/1.1 %s</d:status>\n' % errmsg) result.write('</d:response>\n') if depth == 'infinity' and iscol: for ob in obj.objectValues(): if hasattr(obj, '__dav_resource__'): uri = urljoin(url, absattr(ob.getId())) self.apply(ob, creator, depth, token, result, uri, top=0) if not top: return token, result if result.getvalue(): # One or more subitems probably failed, so close the multistatus # element and clear out all succesful locks result.write('</d:multistatus>') transaction.abort() # This *SHOULD* clear all succesful locks return token, result.getvalue()
def MOVE(self, REQUEST, RESPONSE): """Move a resource to a new location. Though we may later try to make a move appear seamless across namespaces (e.g. from Zope to Apache), MOVE is currently only supported within the Zope namespace.""" self.dav__init(REQUEST, RESPONSE) self.dav__validate(self, 'DELETE', REQUEST) if not hasattr(aq_base(self), 'cb_isMoveable') or \ not self.cb_isMoveable(): raise 'Method Not Allowed', 'This object may not be moved.' dest=REQUEST.get_header('Destination', '') try: path = REQUEST.physicalPathFromURL(dest) except ValueError: raise 'Bad Request', 'No destination given' flag=REQUEST.get_header('Overwrite', 'F') flag=flag.upper() name = path.pop() parent_path = '/'.join(path) try: parent = self.restrictedTraverse(path) except ValueError: raise 'Conflict', 'Attempt to move to an unknown namespace.' except 'Not Found': raise 'Conflict', 'The resource %s must exist.' % parent_path except: t, v, tb=sys.exc_info() raise t, v if hasattr(parent, '__null_resource__'): raise 'Conflict', 'The resource %s must exist.' % parent_path existing=hasattr(aq_base(parent), name) if existing and flag=='F': raise 'Precondition Failed', 'Resource %s exists.' % dest try: parent._checkId(name, allow_dup=1) except: raise 'Forbidden', sys.exc_info()[1] try: parent._verifyObjectPaste(self) except Unauthorized: raise except: raise 'Forbidden', sys.exc_info()[1] # Now check locks. Since we're affecting the resource that we're # moving as well as the destination, we have to check both. ifhdr = REQUEST.get_header('If', '') if existing: # The destination itself exists, so we need to check its locks destob = aq_base(parent)._getOb(name) if WriteLockInterface.isImplementedBy(destob) and \ destob.wl_isLocked(): if ifhdr: itrue = destob.dav__simpleifhandler( REQUEST, RESPONSE, 'MOVE', url=dest, refresh=1) if not itrue: raise 'Precondition Failed' else: raise 'Locked', 'Destination is locked.' elif WriteLockInterface.isImplementedBy(parent) and \ parent.wl_isLocked(): # There's no existing object in the destination folder, so # we need to check the folders locks since we're changing its # member list if ifhdr: itrue = parent.dav__simpleifhandler(REQUEST, RESPONSE, 'MOVE', col=1, url=dest, refresh=1) if not itrue: raise 'Precondition Failed', 'Condition failed.' else: raise 'Locked', 'Destination is locked.' if Lockable.wl_isLocked(self): # Lastly, we check ourselves if ifhdr: itrue = self.dav__simpleifhandler(REQUEST, RESPONSE, 'MOVE', refresh=1) if not itrue: raise 'Precondition Failed', 'Condition failed.' else: raise 'Precondition Failed', 'Source is locked and no '\ 'condition was passed in.' ob=aq_base(self._getCopy(parent)) self.aq_parent._delObject(absattr(self.id)) ob._setId(name) if existing: object=getattr(parent, name) self.dav__validate(object, 'DELETE', REQUEST) parent._delObject(name) parent._setObject(name, ob) RESPONSE.setStatus(existing and 204 or 201) if not existing: RESPONSE.setHeader('Location', dest) RESPONSE.setBody('') return RESPONSE