diff --git a/routes/webdav.py b/routes/webdav.py index a1a655e..c89745d 100644 --- a/routes/webdav.py +++ b/routes/webdav.py @@ -6,6 +6,7 @@ WebDAV 文件管理路由 """ from pathlib import Path +from urllib.parse import urlparse, urlunparse from wsgidav.wsgidav_app import WsgiDAVApp from wsgidav.fs_dav_provider import FilesystemProvider @@ -56,4 +57,36 @@ config = { }, } -wsgidav_app = WsgiDAVApp(config) +_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)