From 18b6ac625fc37ff831a3413264bb9355ffc4f63c Mon Sep 17 00:00:00 2001 From: Hari <73809867+harivansh-afk@users.noreply.github.com> Date: Wed, 1 Apr 2026 16:42:34 -0400 Subject: [PATCH] Fix macOS Finder WebDAV mount by handling GET on directories (#12) Go's webdav.Handler returns 405 Method Not Allowed for GET on collections (directories). macOS Finder sends GET to the WebDAV root as part of its mount flow and refuses to connect when it gets 405. Add a finderCompatible wrapper that intercepts GET/HEAD on directories and returns a minimal 200 response, while passing all standard WebDAV methods through to the underlying handler unchanged. --- apps/node-agent/cmd/node-agent/app.go | 5 +- apps/node-agent/cmd/node-agent/dav_finder.go | 60 ++++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 apps/node-agent/cmd/node-agent/dav_finder.go diff --git a/apps/node-agent/cmd/node-agent/app.go b/apps/node-agent/cmd/node-agent/app.go index 0ff0d6a..4e0b9e5 100644 --- a/apps/node-agent/cmd/node-agent/app.go +++ b/apps/node-agent/cmd/node-agent/app.go @@ -155,12 +155,13 @@ func (a *app) handler() http.Handler { for _, mount := range a.exportMounts { mountPathPrefix := strings.TrimSuffix(mount.mountPath, "/") + fs := webdav.Dir(mount.exportPath) dav := &webdav.Handler{ Prefix: mountPathPrefix, - FileSystem: webdav.Dir(mount.exportPath), + FileSystem: fs, LockSystem: webdav.NewMemLS(), } - mux.Handle(mount.mountPath, a.requireDAVAuth(mount, dav)) + mux.Handle(mount.mountPath, a.requireDAVAuth(mount, finderCompatible(dav, fs, mountPathPrefix))) } return mux diff --git a/apps/node-agent/cmd/node-agent/dav_finder.go b/apps/node-agent/cmd/node-agent/dav_finder.go new file mode 100644 index 0000000..399c0c9 --- /dev/null +++ b/apps/node-agent/cmd/node-agent/dav_finder.go @@ -0,0 +1,60 @@ +package main + +import ( + "context" + "net/http" + "os" + "strings" + + "golang.org/x/net/webdav" +) + +// finderCompatible wraps a webdav.Handler to work around macOS Finder quirks. +// +// Finder sends GET requests to WebDAV collection (directory) URLs and expects +// a 200 response. The standard Go webdav.Handler returns 405 Method Not Allowed +// for GET on directories, which causes Finder to refuse the mount. +// +// This wrapper intercepts GET and HEAD requests on directories and returns a +// minimal 200 response so Finder proceeds with the WebDAV protocol. +func finderCompatible(dav *webdav.Handler, fs webdav.FileSystem, prefix string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet && r.Method != http.MethodHead { + dav.ServeHTTP(w, r) + return + } + + // Strip the prefix to get the filesystem-relative path. + fsPath := strings.TrimPrefix(r.URL.Path, prefix) + if fsPath == "" { + fsPath = "/" + } + + f, err := fs.OpenFile(context.Background(), fsPath, os.O_RDONLY, 0) + if err != nil { + // Not found or other error: let the regular handler deal with it. + dav.ServeHTTP(w, r) + return + } + defer f.Close() + + info, err := f.Stat() + if err != nil { + dav.ServeHTTP(w, r) + return + } + + if !info.IsDir() { + // Regular file: let the standard handler serve it. + dav.ServeHTTP(w, r) + return + } + + // Directory GET: return a minimal 200 so Finder is satisfied. + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.WriteHeader(http.StatusOK) + if r.Method == http.MethodGet { + _, _ = w.Write([]byte("
betterNAS WebDAV
\n")) + } + }) +}