diff --git a/src/snek/webdav.py b/src/snek/webdav.py index 3033e3a..e03e675 100755 --- a/src/snek/webdav.py +++ b/src/snek/webdav.py @@ -188,11 +188,74 @@ class WebdavApplication(aiohttp.web.Application): statvfs = os.statvfs(path) return statvfs.f_bavail * statvfs.f_frsize + + async def create_node(self, request, response_xml, full_path, depth): + requested_path = request.match_info.get("filename", "") + abs_path = pathlib.Path(full_path) + relative_path = str(full_path.relative_to(request['home'])) + + href_path = f"{relative_path}".strip("/") + #href_path = href_path.replace("./","/") + href_path = href_path.replace("//", "/") + response = etree.SubElement(response_xml, "{DAV:}response") + href = etree.SubElement(response, "{DAV:}href") + href.text = href_path + propstat = etree.SubElement(response, "{DAV:}propstat") + prop = etree.SubElement(propstat, "{DAV:}prop") + res_type = etree.SubElement(prop, "{DAV:}resourcetype") + if full_path.is_dir(): + etree.SubElement(res_type, "{DAV:}collection") + creation_date, last_modified = self.get_current_utc_time(full_path) + etree.SubElement(prop, "{DAV:}creationdate").text = creation_date + etree.SubElement(prop, "{DAV:}quota-used-bytes").text = str( + full_path.stat().st_size + if full_path.is_file() + else self.get_directory_size(full_path) + ) + etree.SubElement(prop, "{DAV:}quota-available-bytes").text = str( + self.get_disk_free_space(request['home']) + ) + etree.SubElement(prop, "{DAV:}getlastmodified").text = last_modified + etree.SubElement(prop, "{DAV:}displayname").text = full_path.name + etree.SubElement(prop, "{DAV:}lockdiscovery") + mimetype, _ = mimetypes.guess_type(full_path.name) + etree.SubElement(prop, "{DAV:}contenttype").text = mimetype + etree.SubElement(prop, "{DAV:}getcontentlength").text = str( + full_path.stat().st_size + if full_path.is_file() + else self.get_directory_size(full_path) + ) + supported_lock = etree.SubElement(prop, "{DAV:}supportedlock") + lock_entry_1 = etree.SubElement(supported_lock, "{DAV:}lockentry") + lock_scope_1 = etree.SubElement(lock_entry_1, "{DAV:}lockscope") + etree.SubElement(lock_scope_1, "{DAV:}exclusive") + lock_type_1 = etree.SubElement(lock_entry_1, "{DAV:}locktype") + etree.SubElement(lock_type_1, "{DAV:}write") + lock_entry_2 = etree.SubElement(supported_lock, "{DAV:}lockentry") + lock_scope_2 = etree.SubElement(lock_entry_2, "{DAV:}lockscope") + etree.SubElement(lock_scope_2, "{DAV:}shared") + lock_type_2 = etree.SubElement(lock_entry_2, "{DAV:}locktype") + etree.SubElement(lock_type_2, "{DAV:}write") + etree.SubElement(propstat, "{DAV:}status").text = "HTTP/1.1 200 OK" + + if abs_path.is_dir() and depth != -1: + for item in abs_path.iterdir(): + await self.create_node(request,response_xml, item, depth - 1) + + + + async def handle_propfind(self, request): if not await self.authenticate(request): return aiohttp.web.Response( status=401, headers={"WWW-Authenticate": 'Basic realm="WebDAV"'} ) + + depth = 0 + try: + depth = int(request.headers.get("Depth", "0")) + except ValueError: + pass requested_path = request.match_info.get("filename", "") abs_path = request['home'] / requested_path if not abs_path.exists(): @@ -200,54 +263,9 @@ class WebdavApplication(aiohttp.web.Application): nsmap = {"D": "DAV:"} response_xml = etree.Element("{DAV:}multistatus", nsmap=nsmap) directories = [requested_path] - if abs_path.is_dir(): - directories.extend(os.listdir(abs_path)) - for item in directories: - full_path = abs_path / item if item != requested_path else abs_path - href_path = f"/{requested_path}/{item}/" if item != requested_path else f"/{requested_path}/" - href_path = href_path.replace("//", "/") - response = etree.SubElement(response_xml, "{DAV:}response") - href = etree.SubElement(response, "{DAV:}href") - if not full_path.is_dir(): - href_path = href_path.rstrip("/") - href.text = href_path - propstat = etree.SubElement(response, "{DAV:}propstat") - prop = etree.SubElement(propstat, "{DAV:}prop") - res_type = etree.SubElement(prop, "{DAV:}resourcetype") - if full_path.is_dir(): - etree.SubElement(res_type, "{DAV:}collection") - creation_date, last_modified = self.get_current_utc_time(full_path) - etree.SubElement(prop, "{DAV:}creationdate").text = creation_date - etree.SubElement(prop, "{DAV:}quota-used-bytes").text = str( - full_path.stat().st_size - if full_path.is_file() - else self.get_directory_size(full_path) - ) - etree.SubElement(prop, "{DAV:}quota-available-bytes").text = str( - self.get_disk_free_space(request['home']) - ) - etree.SubElement(prop, "{DAV:}getlastmodified").text = last_modified - etree.SubElement(prop, "{DAV:}displayname").text = full_path.name - etree.SubElement(prop, "{DAV:}lockdiscovery") - mimetype, _ = mimetypes.guess_type(full_path.name) - etree.SubElement(prop, "{DAV:}contenttype").text = mimetype - etree.SubElement(prop, "{DAV:}getcontentlength").text = str( - full_path.stat().st_size - if full_path.is_file() - else self.get_directory_size(full_path) - ) - supported_lock = etree.SubElement(prop, "{DAV:}supportedlock") - lock_entry_1 = etree.SubElement(supported_lock, "{DAV:}lockentry") - lock_scope_1 = etree.SubElement(lock_entry_1, "{DAV:}lockscope") - etree.SubElement(lock_scope_1, "{DAV:}exclusive") - lock_type_1 = etree.SubElement(lock_entry_1, "{DAV:}locktype") - etree.SubElement(lock_type_1, "{DAV:}write") - lock_entry_2 = etree.SubElement(supported_lock, "{DAV:}lockentry") - lock_scope_2 = etree.SubElement(lock_entry_2, "{DAV:}lockscope") - etree.SubElement(lock_scope_2, "{DAV:}shared") - lock_type_2 = etree.SubElement(lock_entry_2, "{DAV:}locktype") - etree.SubElement(lock_type_2, "{DAV:}write") - etree.SubElement(propstat, "{DAV:}status").text = "HTTP/1.1 200 OK" + + await self.create_node(request, response_xml, abs_path, depth) + xml_output = etree.tostring( response_xml, encoding="utf-8", xml_declaration=True ).decode()