mirror of
https://github.com/rclone/rclone.git
synced 2025-10-06 05:47:10 +02:00
lib/rest: add URLPathEscapeAll to URL escape as many chars as possible
This commit is contained in:
@@ -3,6 +3,7 @@ package rest
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// URLJoin joins a URL and a path returning a new URL
|
||||
@@ -24,3 +25,24 @@ func URLPathEscape(in string) string {
|
||||
u.Path = in
|
||||
return u.String()
|
||||
}
|
||||
|
||||
// URLPathEscapeAll escapes URL path the in string using URL escaping rules
|
||||
//
|
||||
// It escapes every character except [A-Za-z0-9] and /
|
||||
func URLPathEscapeAll(in string) string {
|
||||
var b strings.Builder
|
||||
b.Grow(len(in) * 3) // worst case: every byte escaped
|
||||
const hex = "0123456789ABCDEF"
|
||||
for i := range len(in) {
|
||||
c := in[i]
|
||||
if (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') || c == '/' {
|
||||
b.WriteByte(c)
|
||||
} else {
|
||||
b.WriteByte('%')
|
||||
b.WriteByte(hex[c>>4])
|
||||
b.WriteByte(hex[c&0x0F])
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
@@ -59,3 +59,27 @@ func TestURLPathEscape(t *testing.T) {
|
||||
assert.Equal(t, test.want, got, fmt.Sprintf("Test %d path = %q", i, test.path))
|
||||
}
|
||||
}
|
||||
|
||||
func TestURLPathEscapeAll(t *testing.T) {
|
||||
tests := []struct {
|
||||
in string
|
||||
want string
|
||||
}{
|
||||
{"", ""},
|
||||
{"/hello.txt", "/hello%2Etxt"},
|
||||
{"With Space", "With%20Space"},
|
||||
{"With Colon:", "With%20Colon%3A"},
|
||||
{"With Percent%", "With%20Percent%25"},
|
||||
{"abc/XYZ123", "abc/XYZ123"},
|
||||
{"hello world", "hello%20world"},
|
||||
{"$test", "%24test"},
|
||||
{"ümlaut", "%C3%BCmlaut"},
|
||||
{"", ""},
|
||||
{" /?", "%20/%3F"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
got := URLPathEscapeAll(test.in)
|
||||
assert.Equal(t, test.want, got)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user