func urlUnescape(s string, doPlus bool) (string, error) { // Count %, check that they're well-formed. n := 0 hasPlus := false for i := 0; i < len(s); { switch s[i] { case '%': n++ if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { s = s[i:] if len(s) > 3 { s = s[0:3] } return "", url.EscapeError(s) } i += 3 case '+': hasPlus = doPlus i++ default: i++ } } if n == 0 && !hasPlus { return s, nil } t := make([]byte, len(s)-2*n) j := 0 for i := 0; i < len(s); { switch s[i] { case '%': t[j] = unhex(s[i+1])<<4 | unhex(s[i+2]) j++ i += 3 case '+': if doPlus { t[j] = ' ' } else { t[j] = '+' } j++ i++ default: t[j] = s[i] j++ i++ } } return string(t), nil }
func pathUnescape(s string) (string, error) { // Count %, check that they're well-formed. n := 0 for i := 0; i < len(s); { switch s[i] { case '%': n++ if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { s = s[i:] if len(s) > 3 { s = s[0:3] } return "", url.EscapeError(s) } i += 3 case '+': i++ default: i++ } } if n == 0 { return s, nil } t := make([]byte, len(s)-2*n) j := 0 for i := 0; i < len(s); { switch s[i] { case '%': t[j] = unhex(s[i+1])<<4 | unhex(s[i+2]) j++ i += 3 default: t[j] = s[i] j++ i++ } } return string(t), nil }
t.Errorf("ishex(%v) == %v, expected %v", test.input, actual, test.ishex) } if actual := unhex(test.input); actual != test.unhex { t.Errorf("unhex(%v) == %v, expected %v", test.input, actual, test.unhex) } } } var UnescapeTests = []struct { input string err error output string }{ {"hello", nil, "hello"}, {"file%20one%26two", nil, "file one&two"}, {"one/two%2fthree", nil, "one/two/three"}, {"this%20is%0not%valid", url.EscapeError("%0n"), ""}, } func TestUnescape(t *testing.T) { t.Parallel() for _, test := range UnescapeTests { if actual, err := unescape(test.input); err != test.err { t.Errorf("unescape(%q) had err %v, expected %q", test.input, err, test.err) } else if actual != test.output { t.Errorf("unescape(%q) = %q, expected %q)", test.input, actual, test.output) } } }