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 MKCOL(self, REQUEST, RESPONSE): """Create a new collection resource.""" self.dav__init(REQUEST, RESPONSE) if REQUEST.get('BODY', ''): raise UnsupportedMediaType, 'Unknown request body.' name=self.__name__ parent = self.__parent__ if hasattr(aq_base(parent), name): raise MethodNotAllowed, 'The name %s is in use.' % name if not isDavCollection(parent): raise Forbidden, 'Cannot create collection at this location.' ifhdr = REQUEST.get_header('If', '') if (IWriteLock.providedBy(parent) or WriteLockInterface.isImplementedBy(parent)) and \ parent.wl_isLocked(): if ifhdr: parent.dav__simpleifhandler(REQUEST, RESPONSE, col=1) else: raise Locked elif ifhdr: # There was an If header, but the parent is not locked raise PreconditionFailed # Add hook for webdav/FTP MKCOL (Collector #2254) (needed for CMF) # parent.manage_addFolder(name) mkcol_handler = getattr(parent,'MKCOL_handler' ,parent.manage_addFolder) mkcol_handler(name) RESPONSE.setStatus(201) RESPONSE.setBody('') return RESPONSE
def PROPPATCH(self, REQUEST, RESPONSE): """Set and/or remove properties defined on the resource.""" self.dav__init(REQUEST, RESPONSE) if not hasattr(aq_base(self), 'propertysheets'): raise 'Method Not Allowed', ( 'Method not supported for this resource.') # Lock checking ifhdr = REQUEST.get_header('If', '') if Lockable.wl_isLocked(self): if ifhdr: self.dav__simpleifhandler(REQUEST, RESPONSE, 'PROPPATCH') else: raise 'Locked', 'Resource is locked.' cmd=davcmds.PropPatch(REQUEST) result=cmd.apply(self) RESPONSE.setStatus(207) RESPONSE.setHeader('Content-Type', 'text/xml; charset="utf-8"') RESPONSE.setBody(result) return RESPONSE
def MKCOL(self, REQUEST, RESPONSE): """Create a new collection resource.""" self.dav__init(REQUEST, RESPONSE) if REQUEST.get('BODY', ''): raise UnsupportedMediaType, 'Unknown request body.' name = self.__name__ parent = self.__parent__ if hasattr(aq_base(parent), name): raise MethodNotAllowed, 'The name %s is in use.' % name if not isDavCollection(parent): raise Forbidden, 'Cannot create collection at this location.' ifhdr = REQUEST.get_header('If', '') if (IWriteLock.providedBy(parent) or WriteLockInterface.isImplementedBy(parent)) and \ parent.wl_isLocked(): if ifhdr: parent.dav__simpleifhandler(REQUEST, RESPONSE, col=1) else: raise Locked elif ifhdr: # There was an If header, but the parent is not locked raise PreconditionFailed # Add hook for webdav/FTP MKCOL (Collector #2254) (needed for CMF) # parent.manage_addFolder(name) mkcol_handler = getattr(parent, 'MKCOL_handler', parent.manage_addFolder) mkcol_handler(name) RESPONSE.setStatus(201) RESPONSE.setBody('') return RESPONSE
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()
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
def COPY(self, REQUEST, RESPONSE): """Create a duplicate of the source resource whose state and behavior match that of the source resource as closely as possible. Though we may later try to make a copy appear seamless across namespaces (e.g. from Zope to Apache), COPY is currently only supported within the Zope namespace.""" self.dav__init(REQUEST, RESPONSE) if not hasattr(aq_base(self), 'cb_isCopyable') or \ not self.cb_isCopyable(): raise 'Method Not Allowed', 'This object may not be copied.' depth=REQUEST.get_header('Depth', 'infinity') if not depth in ('0', 'infinity'): raise 'Bad Request', 'Invalid Depth header.' dest=REQUEST.get_header('Destination', '') while dest and dest[-1]=='/': dest=dest[:-1] if not dest: raise 'Bad Request', 'Invalid Destination header.' try: path = REQUEST.physicalPathFromURL(dest) except ValueError: raise 'Bad Request', 'Invalid Destination header' name = path.pop() parent_path = '/'.join(path) oflag=REQUEST.get_header('Overwrite', 'F').upper() if not oflag in ('T', 'F'): raise 'Bad Request', 'Invalid Overwrite header.' try: parent=self.restrictedTraverse(path) except ValueError: raise 'Conflict', 'Attempt to copy to an unknown namespace.' except 'Not Found': raise 'Conflict', 'Object ancestors must already exist.' except: t, v, tb=sys.exc_info() raise t, v if hasattr(parent, '__null_resource__'): raise 'Conflict', 'Object ancestors must already exist.' existing=hasattr(aq_base(parent), name) if existing and oflag=='F': raise 'Precondition Failed', 'Destination resource exists.' 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. The If header on a copy only cares about the # lock on the destination, so we need to check out the destinations # lock status. 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, 'COPY', refresh=1) if not itrue: raise 'Preconditon Failed' else: raise 'Locked', 'Destination is locked.' elif WriteLockInterface.isImplementedBy(parent) and \ parent.wl_isLocked(): if ifhdr: parent.dav__simpleifhandler(REQUEST, RESPONSE, 'COPY', refresh=1) else: raise 'Locked', 'Destination is locked.' ob=self._getCopy(parent) ob.manage_afterClone(ob) # We remove any locks from the copied object because webdav clients # don't track the lock status and the lock token for copied resources ob.wl_clearLocks() ob._setId(name) if depth=='0' and isDavCollection(ob): for id in ob.objectIds(): ob._delObject(id) 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