mirror of
https://github.com/rclone/rclone.git
synced 2026-03-26 03:12:36 -04:00
lib/rest: fix URLPathEscapeAll breaking WebDAV servers (eg nzbdav) with strict path matching
URLPathEscapeAll was only passing [A-Za-z0-9/] through unencoded, causing it to percent-encode RFC 3986 unreserved characters (-, ., _, ~). Per RFC 3986 §2.3, unreserved characters MUST NOT be percent-encoded, and a URI that unnecessarily encodes them is not equivalent to one that does not. Servers that perform strict path matching without normalising percent-encoded characters will reject the over-encoded form with a 404. Before: /files/my-report.pdf → /files/my%2Dreport%2Epdf After: /files/my-report.pdf → /files/my-report.pdf Reserved characters (spaces, semicolons, colons, etc.) continue to be encoded as before.
This commit is contained in:
committed by
Nick Craig-Wood
parent
14defb23dc
commit
f9bf6d823e
@@ -28,7 +28,9 @@ func URLPathEscape(in string) string {
|
||||
|
||||
// URLPathEscapeAll escapes URL path the in string using URL escaping rules
|
||||
//
|
||||
// It escapes every character except [A-Za-z0-9] and /
|
||||
// It escapes every character except the RFC 3986 unreserved characters
|
||||
// [A-Za-z0-9-._~] and the path separator /. Unreserved characters MUST NOT
|
||||
// be percent-encoded per RFC 3986 §2.3.
|
||||
func URLPathEscapeAll(in string) string {
|
||||
var b strings.Builder
|
||||
b.Grow(len(in) * 3) // worst case: every byte escaped
|
||||
@@ -36,7 +38,8 @@ func URLPathEscapeAll(in string) string {
|
||||
for i := range len(in) {
|
||||
c := in[i]
|
||||
if (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') || c == '/' {
|
||||
(c >= '0' && c <= '9') || c == '/' ||
|
||||
c == '-' || c == '.' || c == '_' || c == '~' {
|
||||
b.WriteByte(c)
|
||||
} else {
|
||||
b.WriteByte('%')
|
||||
|
||||
@@ -66,7 +66,10 @@ func TestURLPathEscapeAll(t *testing.T) {
|
||||
want string
|
||||
}{
|
||||
{"", ""},
|
||||
{"/hello.txt", "/hello%2Etxt"},
|
||||
// RFC 3986 unreserved characters must not be encoded
|
||||
{"/hello.txt", "/hello.txt"},
|
||||
{"file-name_v2.~bak", "file-name_v2.~bak"},
|
||||
// Reserved and other characters must be encoded
|
||||
{"With Space", "With%20Space"},
|
||||
{"With Colon:", "With%20Colon%3A"},
|
||||
{"With Percent%", "With%20Percent%25"},
|
||||
|
||||
Reference in New Issue
Block a user