package url import "strings" var tblEscapeURLQuery = [128]byte{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, } var tblEscapeURLQueryParam = [128]byte{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, } // The code below is mostly borrowed from the standard Go url package const upperhex = "0123456789ABCDEF" func ishex(c byte) bool { switch { case '0' <= c && c <= '9': return true case 'a' <= c && c <= 'f': return true case 'A' <= c && c <= 'F': return true } return false } func unhex(c byte) byte { switch { case '0' <= c && c <= '9': return c - '0' case 'a' <= c && c <= 'f': return c - 'a' + 10 case 'A' <= c && c <= 'F': return c - 'A' + 10 } return 0 } func escape(s string, table *[128]byte, spaceToPlus bool) string { spaceCount, hexCount := 0, 0 for i := 0; i < len(s); i++ { c := s[i] if c > 127 || table[c] == 0 { if c == ' ' && spaceToPlus { spaceCount++ } else { hexCount++ } } } if spaceCount == 0 && hexCount == 0 { return s } var sb strings.Builder hexBuf := [3]byte{'%', 0, 0} sb.Grow(len(s) + 2*hexCount) for i := 0; i < len(s); i++ { switch c := s[i]; { case c == ' ' && spaceToPlus: sb.WriteByte('+') case c > 127 || table[c] == 0: hexBuf[1] = upperhex[c>>4] hexBuf[2] = upperhex[c&15] sb.Write(hexBuf[:]) default: sb.WriteByte(c) } } return sb.String() } func unescapeSearchParam(s string) string { n := 0 hasPlus := false for i := 0; i < len(s); { switch s[i] { case '%': if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { i++ continue } n++ i += 3 case '+': hasPlus = true i++ default: i++ } } if n == 0 && !hasPlus { return s } var t strings.Builder t.Grow(len(s) - 2*n) for i := 0; i < len(s); i++ { switch s[i] { case '%': if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { t.WriteByte('%') } else { t.WriteByte(unhex(s[i+1])<<4 | unhex(s[i+2])) i += 2 } case '+': t.WriteByte(' ') default: t.WriteByte(s[i]) } } return t.String() }