WebDAV: fix 500, perms, bind path; drop broken depth middleware
ci/woodpecker/push/woodpecker Pipeline was successful
Details
ci/woodpecker/push/woodpecker Pipeline was successful
Details
- Remove limit_propfind_depth middleware (was breaking response chain)
- Entrypoint: mkdir/chmod /data, chmod -R a+rwX, umask 0000
- Compose: bind webdav data to ${HOME}/dev/piconfigurator/bin
- Add __pycache__ to .gitignore
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
5431fdbbfb
commit
00c0e073d1
|
|
@ -9,5 +9,9 @@ macmini-tunnel
|
|||
macmini-tunnel.pub
|
||||
webdav-data/
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# Server (ingress) is assumed configured for this domain and key.
|
||||
#
|
||||
# What works:
|
||||
# - WebDAV: no auth in app; uploads go to ./webdav-data. Rebuild after app changes: --build.
|
||||
# - WebDAV: no auth in app; uploads go to ~/dev/piconfigurator/bin. Rebuild after app changes: --build.
|
||||
# - Tunnel: uses ~/.ssh/ca-userkey (same key as all other tunnel clients).
|
||||
# - Auth: TUNNEL_AUTH_USER/PASS (genghis/genghis) = HTTP Basic at the tunnel; WebDAV behind it is open.
|
||||
# - network_mode: service:webdav so tunnel forwards to localhost:80 inside the webdav container.
|
||||
|
|
@ -11,8 +11,14 @@ services:
|
|||
webdav:
|
||||
build: ./webdav
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:80/')"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
volumes:
|
||||
- ./webdav-data:/data
|
||||
- ${HOME}/dev/piconfigurator/bin:/data
|
||||
|
||||
tunnel-client:
|
||||
image: git.nixc.us/colin/better-argo-tunnels:client-production-arm64
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ WORKDIR /app
|
|||
RUN pip install --no-cache-dir wsgidav cheroot
|
||||
|
||||
COPY app.py .
|
||||
RUN mkdir -p /data
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
EXPOSE 80
|
||||
CMD ["python", "-u", "app.py"]
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
|
|
|||
|
|
@ -1,25 +1,83 @@
|
|||
"""Minimal WebDAV server. Serves /data for uploads. Auth handled at reverse tunnel."""
|
||||
"""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,
|
||||
"provider_mapping": {"/": FilesystemProvider(ROOT, readonly=False)},
|
||||
"middleware_stack": [Cors, ErrorPrinter, WsgiDavDirBrowser, RequestResolver],
|
||||
"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,
|
||||
"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()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
mkdir -p /data
|
||||
chmod 1777 /data
|
||||
# Fix perms on existing content so host user can read/write
|
||||
chmod -R a+rwX /data 2>/dev/null || true
|
||||
# New files/dirs world-readable/writable so host user can manage them
|
||||
umask 0000
|
||||
exec python -u app.py
|
||||
Loading…
Reference in New Issue