mirror of
https://github.com/rclone/rclone.git
synced 2026-02-21 03:43:32 +00:00
webdav: escape reserved characters in URL path segments
Use URLPathEscapeAll instead of URLPathEscape for path encoding. URLPathEscape relies on Go's url.URL.String() which only minimally escapes paths - reserved sub-delimiter characters like semicolons and equals signs pass through unescaped. Per RFC 3986 section 3.3, these characters must be percent-encoded when used as literal values in path segments. Some WebDAV servers (notably dCache/Jetty) interpret unescaped semicolons as path parameter delimiters, which truncates filenames at the semicolon position. URLPathEscapeAll encodes everything except [A-Za-z0-9/], which is safe for all servers. Fixes #9082
This commit is contained in:
@@ -423,7 +423,7 @@ func (f *Fs) filePath(file string) string {
|
||||
if f.opt.Enc != encoder.EncodeZero {
|
||||
subPath = f.opt.Enc.FromStandardPath(subPath)
|
||||
}
|
||||
return rest.URLPathEscape(subPath)
|
||||
return rest.URLPathEscapeAll(subPath)
|
||||
}
|
||||
|
||||
// dirPath returns a directory path (f.root, dir)
|
||||
|
||||
@@ -80,3 +80,35 @@ func TestHeaders(t *testing.T) {
|
||||
_, err := f.Features().About(context.Background())
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// TestReservedCharactersInPathAreEscaped verifies that reserved characters
|
||||
// like semicolons and equals signs in file paths are percent-encoded in
|
||||
// HTTP requests to the WebDAV server (RFC 3986 compliance).
|
||||
func TestReservedCharactersInPathAreEscaped(t *testing.T) {
|
||||
var capturedPath string
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
capturedPath = r.RequestURI
|
||||
// Return a 404 so the NewObject call fails cleanly
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
})
|
||||
ts := httptest.NewServer(handler)
|
||||
defer ts.Close()
|
||||
|
||||
configfile.Install()
|
||||
m := configmap.Simple{
|
||||
"type": "webdav",
|
||||
"url": ts.URL,
|
||||
}
|
||||
|
||||
f, err := webdav.NewFs(context.Background(), remoteName, "", m)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Try to access a file with a semicolon in the name.
|
||||
// We expect the request to fail (404), but the path should be escaped.
|
||||
_, _ = f.NewObject(context.Background(), "my;test")
|
||||
|
||||
// The semicolon must be percent-encoded as %3B
|
||||
assert.Contains(t, capturedPath, "my%3Btest", "semicolons in path should be percent-encoded")
|
||||
assert.NotContains(t, capturedPath, "my;test", "raw semicolons should not appear in path")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user