better-argo-tunnels/webdav/app.py

86 lines
2.5 KiB
Python

"""Minimal WebDAV server. Serves /data for uploads. Auth at reverse tunnel; app allows anonymous."""
import os
import sys
import traceback
from wsgidav.fs_dav_provider import FilesystemProvider
from wsgidav.wsgidav_app import WsgiDAVApp
from wsgidav.dir_browser import WsgiDavDirBrowser
from wsgidav.error_printer import ErrorPrinter
from wsgidav.request_resolver import RequestResolver
from wsgidav.http_authenticator import HTTPAuthenticator
from wsgidav.mw.cors import Cors
from cheroot.wsgi import Server as WSGIServer
ROOT = "/data"
PORT = 80
def ensure_data_dir_writable() -> None:
os.makedirs(ROOT, exist_ok=True)
probe = os.path.join(ROOT, ".write_probe")
try:
with open(probe, "w") as f:
f.write("")
os.remove(probe)
except OSError as e:
print(f"FATAL: cannot write to {ROOT}: {e}", file=sys.stderr)
sys.exit(1)
def catch_all(app):
"""Catch uncaught exceptions so one bad request doesn't kill the server."""
def wrapper(environ, start_response):
try:
return app(environ, start_response)
except Exception:
traceback.print_exc()
start_response("500 Internal Server Error", [("Content-Type", "text/plain")])
return [b"Internal Server Error"]
return wrapper
ensure_data_dir_writable()
config = {
"host": "0.0.0.0",
"port": PORT,
# Mount at /dav so root / is not special-cased (Finder PROPFIND needs real XML)
"provider_mapping": {"/dav": FilesystemProvider(ROOT, readonly=False)},
"middleware_stack": [
Cors,
ErrorPrinter,
HTTPAuthenticator,
WsgiDavDirBrowser,
RequestResolver,
],
"http_authenticator": {
"domain_controller": None,
"accept_basic": True,
"accept_digest": True,
"default_to_digest": False,
},
"simple_dc": {
"user_mapping": {"*": True},
},
"hotfixes": {
"emulate_win32_lastmod": True,
"treat_root_options_as_asterisk": True,
},
"add_header_MS_Author_Via": True,
"property_manager": True, # Required for PROPFIND to return XML (Finder mount)
"verbose": 3,
}
app = WsgiDAVApp(config)
app = catch_all(app)
if __name__ == "__main__":
server = WSGIServer((config["host"], config["port"]), app)
# Avoid Finder/hung clients holding connections forever
if hasattr(server, "connection_limit"):
server.connection_limit = 20
if hasattr(server, "timeout"):
server.timeout = 30
server.start()