|
|
|
@ -59,12 +59,12 @@ func isHex(b byte) bool {
|
|
|
|
|
|
|
|
|
|
func unHex(b byte) byte {
|
|
|
|
|
switch {
|
|
|
|
|
case 'a' <= b || b <= 'f':
|
|
|
|
|
return b - 'a'
|
|
|
|
|
case 'A' <= b || b <= 'F':
|
|
|
|
|
return b - 'A'
|
|
|
|
|
case '0' <= b || b <= '9':
|
|
|
|
|
case '0' <= b && b <= '9':
|
|
|
|
|
return b - '0'
|
|
|
|
|
case 'a' <= b && b <= 'f':
|
|
|
|
|
return b - 'a' + 10
|
|
|
|
|
case 'A' <= b && b <= 'F':
|
|
|
|
|
return b - 'A' + 10
|
|
|
|
|
default:
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
@ -147,14 +147,14 @@ func unescapeHost(raw string) (string, *errors.Error) {
|
|
|
|
|
|
|
|
|
|
// If not a valid % encoded hex value, return with error
|
|
|
|
|
if i+2 >= len(raw) || !isHex(raw[i+1]) || !isHex(raw[i+2]) {
|
|
|
|
|
return "", errors.NewError(InvalidRequestErr).Extend("escaping host info " + raw)
|
|
|
|
|
return "", errors.NewError(InvalidRequestErr).Extend("unescaping host info " + raw)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// In the host component % encoding can only be used
|
|
|
|
|
// for non-ASCII bytes. And rfc6874 introduces %25 for
|
|
|
|
|
// escaped percent sign in IPv6 literals
|
|
|
|
|
if unHex(raw[i+1]) < 8 && raw[i:i+3] != "%25" {
|
|
|
|
|
return "", errors.NewError(InvalidRequestErr).Extend("escaping host " + raw)
|
|
|
|
|
return "", errors.NewError(InvalidRequestErr).Extend("unescaping host " + raw)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Skip iteration past the
|
|
|
|
@ -163,7 +163,7 @@ func unescapeHost(raw string) (string, *errors.Error) {
|
|
|
|
|
default:
|
|
|
|
|
// If within ASCII range, and shoud be escaped, return error
|
|
|
|
|
if raw[i] < 0x80 && shouldHostEscape(raw[i]) {
|
|
|
|
|
return "", errors.NewError(InvalidRequestErr).Extend("escaping host " + raw)
|
|
|
|
|
return "", errors.NewError(InvalidRequestErr).Extend("unescaping host " + raw)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Iter
|
|
|
|
@ -181,27 +181,22 @@ func unescapeHost(raw string) (string, *errors.Error) {
|
|
|
|
|
func unescapePath(raw string) (string, *errors.Error) {
|
|
|
|
|
// Count all the percent signs
|
|
|
|
|
count := 0
|
|
|
|
|
for i := 0; i < len(raw); {
|
|
|
|
|
length := len(raw)
|
|
|
|
|
for i := 0; i < length; {
|
|
|
|
|
switch raw[i] {
|
|
|
|
|
case '%':
|
|
|
|
|
// Increase count
|
|
|
|
|
count++
|
|
|
|
|
|
|
|
|
|
// If not a valid % encoded hex value, return with error
|
|
|
|
|
if i+2 >= len(raw) || !isHex(raw[i+1]) || !isHex(raw[i+2]) {
|
|
|
|
|
return "", errors.NewError(InvalidRequestErr).Extend("escaping path " + raw)
|
|
|
|
|
if i+2 >= length || !isHex(raw[i+1]) || !isHex(raw[i+2]) {
|
|
|
|
|
return "", errors.NewError(InvalidRequestErr).Extend("unescaping path " + raw)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Skip iteration past the
|
|
|
|
|
// hex we just confirmed
|
|
|
|
|
i += 3
|
|
|
|
|
default:
|
|
|
|
|
// If within ASCII range, and shoud be escaped, return error
|
|
|
|
|
if raw[i] < 0x80 && shouldPathEscape(raw[i]) {
|
|
|
|
|
return "", errors.NewError(InvalidRequestErr).Extend("escaping path " + raw)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Iter
|
|
|
|
|
i++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -213,6 +208,38 @@ func unescapePath(raw string) (string, *errors.Error) {
|
|
|
|
|
return unescape(raw, count), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// EscapePath escapes a URL path
|
|
|
|
|
func EscapePath(path string) string {
|
|
|
|
|
const defaultBufSize = 64
|
|
|
|
|
const upperhex = "0123456789ABCDEF"
|
|
|
|
|
|
|
|
|
|
count := 0
|
|
|
|
|
for i := 0; i < len(path); i++ {
|
|
|
|
|
if shouldPathEscape(path[i]) {
|
|
|
|
|
count++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if count == 0 {
|
|
|
|
|
return path
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sb := strings.Builder{}
|
|
|
|
|
sb.Grow(len(path) + 2*count)
|
|
|
|
|
for i := 0; i < len(path); i++ {
|
|
|
|
|
c := path[i]
|
|
|
|
|
if shouldPathEscape(c) {
|
|
|
|
|
sb.WriteByte('%')
|
|
|
|
|
sb.WriteByte(upperhex[c>>4])
|
|
|
|
|
sb.WriteByte(upperhex[c&15])
|
|
|
|
|
} else {
|
|
|
|
|
sb.WriteByte(c)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sb.String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ParseEncodedHost parses encoded host info, safely returning unescape host and port
|
|
|
|
|
func ParseEncodedHost(raw string) (string, string, *errors.Error) {
|
|
|
|
|
// Unescape the host info
|
|
|
|
|