86 lines
2.5 KiB
Python
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()
|