""" WebDAV 文件管理路由 使用 WsgiDAV 开源库提供完整的 WebDAV 协议支持 为 projects/{resource_type}/ 目录提供 WebDAV 协议支持 支持的资源类型: robot, docs """ from pathlib import Path from urllib.parse import urlparse, urlunparse from wsgidav.wsgidav_app import WsgiDAVApp from wsgidav.fs_dav_provider import FilesystemProvider from utils.settings import WEBDAV_USERNAME, WEBDAV_PASSWORD PROJECTS_BASE_DIR = Path("projects") ALLOWED_RESOURCE_TYPES = {"robot", "docs"} # 确保基础目录存在 for resource_type in ALLOWED_RESOURCE_TYPES: (PROJECTS_BASE_DIR / resource_type).mkdir(parents=True, exist_ok=True) # 构建 provider_mapping:每个资源类型映射到对应目录 provider_mapping = {} for resource_type in ALLOWED_RESOURCE_TYPES: abs_path = str((PROJECTS_BASE_DIR / resource_type).resolve()) provider_mapping[f"/{resource_type}"] = FilesystemProvider(abs_path) config = { "mount_path": "/webdav", "provider_mapping": provider_mapping, "http_authenticator": { "domain_controller": "wsgidav.dc.simple_dc.SimpleDomainController", "accept_basic": True, "accept_digest": False, "default_to_digest": False, }, "simple_dc": { "user_mapping": { "*": { WEBDAV_USERNAME: { "password": WEBDAV_PASSWORD, }, }, }, }, "verbose": 1, "lock_storage": True, "property_manager": True, "dir_browser": { "enable": True, "icon": True, "response_trailer": "", }, "hotfixes": { "re_encode_path_info": True, }, } _wsgidav_app = WsgiDAVApp(config) def wsgidav_app(environ, start_response): """WSGI 中间件:处理反向代理场景下 Destination 头的 scheme/host 不匹配问题。 当服务运行在 HTTPS 反向代理后面时,客户端发送的 Destination 头包含外部 URL (如 https://example.com/webdav/docs/new-name),但 WsgiDAV 内部看到的是 HTTP。 这个中间件将 Destination 头重写为与内部请求一致的 scheme 和 host。 """ # 从 X-Forwarded 头获取外部信息,并确保 wsgi.url_scheme 正确 forwarded_proto = environ.get("HTTP_X_FORWARDED_PROTO") if forwarded_proto: environ["wsgi.url_scheme"] = forwarded_proto # 重写 Destination 头:将外部 scheme/host 替换为内部实际值 destination = environ.get("HTTP_DESTINATION") if destination: parsed = urlparse(destination) # 用内部实际的 scheme 和 host 替换 internal_scheme = environ.get("wsgi.url_scheme", "http") internal_host = environ.get("HTTP_HOST", environ.get("SERVER_NAME", "localhost")) rewritten = urlunparse(( internal_scheme, internal_host, parsed.path, parsed.params, parsed.query, parsed.fragment, )) environ["HTTP_DESTINATION"] = rewritten return _wsgidav_app(environ, start_response)