grpcPercentEncode follows RFC 3986 Section 2.1 and the gRPC HTTP/2 spec. It's a variant of URL-encoding with fewer reserved characters. It's intended to take UTF-8 encoded text and escape non-ASCII bytes so that they're valid HTTP/1 headers, while still maximizing readability of the data on the wire
(msg string)
| 893 | // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#responses |
| 894 | // https://datatracker.ietf.org/doc/html/rfc3986#section-2.1 |
| 895 | func grpcPercentEncode(msg string) string { |
| 896 | var hexCount int |
| 897 | for i := range len(msg) { |
| 898 | if grpcShouldEscape(msg[i]) { |
| 899 | hexCount++ |
| 900 | } |
| 901 | } |
| 902 | if hexCount == 0 { |
| 903 | return msg |
| 904 | } |
| 905 | // We need to escape some characters, so we'll need to allocate a new string. |
| 906 | var out strings.Builder |
| 907 | out.Grow(len(msg) + 2*hexCount) |
| 908 | for i := range len(msg) { |
| 909 | switch char := msg[i]; { |
| 910 | case grpcShouldEscape(char): |
| 911 | out.WriteByte('%') |
| 912 | out.WriteByte(upperhex[char>>4]) |
| 913 | out.WriteByte(upperhex[char&15]) |
| 914 | default: |
| 915 | out.WriteByte(char) |
| 916 | } |
| 917 | } |
| 918 | return out.String() |
| 919 | } |
| 920 | |
| 921 | func grpcPercentDecode(input string) (string, error) { |
| 922 | percentCount := 0 |