diff --git a/transport/http_util.go b/transport/http_util.go index fe555473..7d15c7d7 100644 --- a/transport/http_util.go +++ b/transport/http_util.go @@ -438,7 +438,7 @@ func decodeTimeout(s string) (time.Duration, error) { const ( spaceByte = ' ' - tildaByte = '~' + tildeByte = '~' percentByte = '%' ) @@ -456,7 +456,7 @@ func encodeGrpcMessage(msg string) string { lenMsg := len(msg) for i := 0; i < lenMsg; i++ { c := msg[i] - if !(c >= spaceByte && c < tildaByte && c != percentByte) { + if !(c >= spaceByte && c <= tildeByte && c != percentByte) { return encodeGrpcMessageUnchecked(msg) } } @@ -478,7 +478,7 @@ func encodeGrpcMessageUnchecked(msg string) string { // utf8.RuneError. // // fmt.Sprintf("%%%02X", utf8.RuneError) gives "%FFFD". - if b >= spaceByte && b < tildaByte && b != percentByte { + if b >= spaceByte && b <= tildeByte && b != percentByte { buf.WriteByte(b) } else { buf.WriteString(fmt.Sprintf("%%%02X", b)) diff --git a/transport/http_util_test.go b/transport/http_util_test.go index 1295a2f6..44169b65 100644 --- a/transport/http_util_test.go +++ b/transport/http_util_test.go @@ -112,6 +112,23 @@ func TestEncodeGrpcMessage(t *testing.T) { t.Errorf("encodeGrpcMessage(%q) = %q, want %q", tt.input, actual, tt.expected) } } + + // make sure that all the visible ASCII chars except '%' are not percent encoded. + for i := ' '; i <= '~' && i != '%'; i++ { + output := encodeGrpcMessage(string(i)) + if output != string(i) { + t.Errorf("encodeGrpcMessage(%v) = %v, want %v", string(i), output, string(i)) + } + } + + // make sure that all the invisible ASCII chars and '%' are percent encoded. + for i := rune(0); i == '%' || (i >= rune(0) && i < ' ') || (i > '~' && i <= rune(127)); i++ { + output := encodeGrpcMessage(string(i)) + expected := fmt.Sprintf("%%%02X", i) + if output != expected { + t.Errorf("encodeGrpcMessage(%v) = %v, want %v", string(i), output, expected) + } + } } func TestDecodeGrpcMessage(t *testing.T) { @@ -129,7 +146,23 @@ func TestDecodeGrpcMessage(t *testing.T) { } { actual := decodeGrpcMessage(tt.input) if tt.expected != actual { - t.Errorf("dncodeGrpcMessage(%q) = %q, want %q", tt.input, actual, tt.expected) + t.Errorf("decodeGrpcMessage(%q) = %q, want %q", tt.input, actual, tt.expected) + } + } + + // make sure that all the visible ASCII chars except '%' are not percent decoded. + for i := ' '; i <= '~' && i != '%'; i++ { + output := decodeGrpcMessage(string(i)) + if output != string(i) { + t.Errorf("decodeGrpcMessage(%v) = %v, want %v", string(i), output, string(i)) + } + } + + // make sure that all the invisible ASCII chars and '%' are percent decoded. + for i := rune(0); i == '%' || (i >= rune(0) && i < ' ') || (i > '~' && i <= rune(127)); i++ { + output := decodeGrpcMessage(fmt.Sprintf("%%%02X", i)) + if output != string(i) { + t.Errorf("decodeGrpcMessage(%v) = %v, want %v", fmt.Sprintf("%%%02X", i), output, string(i)) } } }