From cf240b6c0f8435568d1fc71234462ec68bb00e7a Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Sat, 7 Feb 2026 09:50:48 -0600 Subject: [PATCH] webdav: permit redirects on PROPFIND for metadata The WebDAV implementation already permits redirects on PROPFIND for listing paths in the `listAll` method but does not permit this for metadata in `readMetaDataForPath`. This results in a strange experience for endpoints that heavily use redirects - ``` rclone lsl endpoint: ``` functions and lists `hello_world.txt` in its output but ``` rclone lsl endpoint:hello_world.txt ``` Fails with a HTTP 307. The git history for this setting indicates this was done to avoid an issue where redirects cause a verb change to GET in the Go HTTP client; it does not appear to be problematic with HTTP 307. To fix, a new `CheckRedirect` function is added in the `rest` library to force the client to use the same verb across redirects, forcing this for the PROPFIND case. --- backend/webdav/webdav.go | 2 +- lib/rest/rest.go | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/backend/webdav/webdav.go b/backend/webdav/webdav.go index 09746f2b6..ccf48e957 100644 --- a/backend/webdav/webdav.go +++ b/backend/webdav/webdav.go @@ -348,7 +348,7 @@ func (f *Fs) readMetaDataForPath(ctx context.Context, path string, depth string) ExtraHeaders: map[string]string{ "Depth": depth, }, - NoRedirect: true, + CheckRedirect: rest.PreserveMethodRedirectFn, } if f.hasOCMD5 || f.hasOCSHA1 { opts.Body = bytes.NewBuffer(owncloudProps) diff --git a/lib/rest/rest.go b/lib/rest/rest.go index f8771f106..3a36a0343 100644 --- a/lib/rest/rest.go +++ b/lib/rest/rest.go @@ -215,6 +215,22 @@ func ClientWithNoRedirects(c *http.Client) *http.Client { return &clientCopy } +// PreserveMethodRedirectFn is a CheckRedirect function that +// preserves the original HTTP method on redirects. +// +// By default Go's http.Client changes the method to GET on 301, 302, +// and 303 redirects. This function overrides that behaviour so the +// original method (e.g. PROPFIND being preserved across a 307) is kept. +func PreserveMethodRedirectFn(req *http.Request, via []*http.Request) error { + if len(via) >= 10 { + return errors.New("stopped after 10 redirects") + } + if len(via) > 0 { + req.Method = via[0].Method + } + return nil +} + // Do calls the internal http.Client.Do method func (api *Client) Do(req *http.Request) (*http.Response, error) { return api.c.Do(req)