package main import ( "html" "log" "net/http" "os" "path/filepath" "time" "golang.org/x/net/webdav" ) const ( rootDir = "/data" addr = ":80" ) func main() { if err := os.MkdirAll(rootDir, 0o750); err != nil { log.Fatalf("mkdir %s: %v", rootDir, err) } abs, err := filepath.Abs(rootDir) if err != nil { log.Fatalf("abs %s: %v", rootDir, err) } var fs webdav.FileSystem = webdav.Dir(abs) if os.Getenv("WEBDAV_IMAGES_ONLY") == "1" { fs = &imageOnlyFS{FileSystem: fs} log.Print("WebDAV images-only mode: only image and SVG uploads allowed") } h := &webdav.Handler{ FileSystem: fs, LockSystem: webdav.NewMemLS(), } // Wrap so GET / returns a simple page instead of 403 for directory mux := http.NewServeMux() mux.Handle("/", &rootGETWrapper{Handler: h}) log.Printf("WebDAV listening on %s (root %s)", addr, abs) server := &http.Server{ Addr: addr, Handler: mux, ReadHeaderTimeout: 10 * time.Second, ReadTimeout: 30 * time.Second, WriteTimeout: 5 * time.Minute, IdleTimeout: 2 * time.Minute, } if err := server.ListenAndServe(); err != nil { log.Fatalf("listen: %v", err) } } // rootGETWrapper serves a minimal HTML page for GET / and passes everything else to WebDAV. type rootGETWrapper struct { *webdav.Handler } func (w *rootGETWrapper) ServeHTTP(rw http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet && (r.URL.Path == "" || r.URL.Path == "/") { rw.Header().Set("Content-Type", "text/html; charset=utf-8") rw.WriteHeader(http.StatusOK) host := html.EscapeString(r.Host) if _, err := rw.Write([]byte(`
Finder → Go → Connect to Server… (⌘K) → https://` + host + `
File Explorer → right-click This PC → Map network drive → Choose a drive letter → Folder: https://` + host + ` → Finish (use the same login when prompted).
Or: File Explorer → This PC → Computer tab → Map network drive.
`)); err != nil { log.Printf("write root response: %v", err) } return } w.Handler.ServeHTTP(rw, r) }