google.golang.org/grpc@v1.74.2/internal/transport/http_util_test.go (about) 1 /* 2 * 3 * Copyright 2014 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package transport 20 21 import ( 22 "errors" 23 "fmt" 24 "io" 25 "math" 26 "net" 27 "reflect" 28 "testing" 29 "time" 30 ) 31 32 func (s) TestDecodeTimeout(t *testing.T) { 33 for _, test := range []struct { 34 // input 35 s string 36 // output 37 d time.Duration 38 wantErr bool 39 }{ 40 41 {"00000001n", time.Nanosecond, false}, 42 {"10u", time.Microsecond * 10, false}, 43 {"00000010m", time.Millisecond * 10, false}, 44 {"1234S", time.Second * 1234, false}, 45 {"00000001M", time.Minute, false}, 46 {"09999999S", time.Second * 9999999, false}, 47 {"99999999S", time.Second * 99999999, false}, 48 {"99999999M", time.Minute * 99999999, false}, 49 {"2562047H", time.Hour * 2562047, false}, 50 {"2562048H", time.Duration(math.MaxInt64), false}, 51 {"99999999H", time.Duration(math.MaxInt64), false}, 52 {"-1S", 0, true}, 53 {"1234x", 0, true}, 54 {"1234s", 0, true}, 55 {"1234", 0, true}, 56 {"1", 0, true}, 57 {"", 0, true}, 58 {"9a1S", 0, true}, 59 {"0S", 0, false}, // PROTOCOL-HTTP2.md requires positive integers, but we allow it to timeout instead 60 {"00000000S", 0, false}, 61 {"000000000S", 0, true}, // PROTOCOL-HTTP2.md allows at most 8 digits 62 } { 63 d, err := decodeTimeout(test.s) 64 gotErr := err != nil 65 if d != test.d || gotErr != test.wantErr { 66 t.Errorf("timeoutDecode(%q) = %d, %v, want %d, wantErr=%v", 67 test.s, int64(d), err, int64(test.d), test.wantErr) 68 } 69 } 70 } 71 72 func (s) TestEncodeGrpcMessage(t *testing.T) { 73 for _, tt := range []struct { 74 input string 75 expected string 76 }{ 77 {"", ""}, 78 {"Hello", "Hello"}, 79 {"\u0000", "%00"}, 80 {"%", "%25"}, 81 {"系统", "%E7%B3%BB%E7%BB%9F"}, 82 {string([]byte{0xff, 0xfe, 0xfd}), "%EF%BF%BD%EF%BF%BD%EF%BF%BD"}, 83 } { 84 actual := encodeGrpcMessage(tt.input) 85 if tt.expected != actual { 86 t.Errorf("encodeGrpcMessage(%q) = %q, want %q", tt.input, actual, tt.expected) 87 } 88 } 89 90 // make sure that all the visible ASCII chars except '%' are not percent encoded. 91 for i := ' '; i <= '~' && i != '%'; i++ { 92 output := encodeGrpcMessage(string(i)) 93 if output != string(i) { 94 t.Errorf("encodeGrpcMessage(%v) = %v, want %v", string(i), output, string(i)) 95 } 96 } 97 98 // make sure that all the invisible ASCII chars and '%' are percent encoded. 99 for i := rune(0); i == '%' || (i >= rune(0) && i < ' ') || (i > '~' && i <= rune(127)); i++ { 100 output := encodeGrpcMessage(string(i)) 101 expected := fmt.Sprintf("%%%02X", i) 102 if output != expected { 103 t.Errorf("encodeGrpcMessage(%v) = %v, want %v", string(i), output, expected) 104 } 105 } 106 } 107 108 func (s) TestDecodeGrpcMessage(t *testing.T) { 109 for _, tt := range []struct { 110 input string 111 expected string 112 }{ 113 {"", ""}, 114 {"Hello", "Hello"}, 115 {"H%61o", "Hao"}, 116 {"H%6", "H%6"}, 117 {"%G0", "%G0"}, 118 {"%E7%B3%BB%E7%BB%9F", "系统"}, 119 {"%EF%BF%BD", "�"}, 120 } { 121 actual := decodeGrpcMessage(tt.input) 122 if tt.expected != actual { 123 t.Errorf("decodeGrpcMessage(%q) = %q, want %q", tt.input, actual, tt.expected) 124 } 125 } 126 127 // make sure that all the visible ASCII chars except '%' are not percent decoded. 128 for i := ' '; i <= '~' && i != '%'; i++ { 129 output := decodeGrpcMessage(string(i)) 130 if output != string(i) { 131 t.Errorf("decodeGrpcMessage(%v) = %v, want %v", string(i), output, string(i)) 132 } 133 } 134 135 // make sure that all the invisible ASCII chars and '%' are percent decoded. 136 for i := rune(0); i == '%' || (i >= rune(0) && i < ' ') || (i > '~' && i <= rune(127)); i++ { 137 output := decodeGrpcMessage(fmt.Sprintf("%%%02X", i)) 138 if output != string(i) { 139 t.Errorf("decodeGrpcMessage(%v) = %v, want %v", fmt.Sprintf("%%%02X", i), output, string(i)) 140 } 141 } 142 } 143 144 // Decode an encoded string should get the same thing back, except for invalid 145 // utf8 chars. 146 func (s) TestDecodeEncodeGrpcMessage(t *testing.T) { 147 testCases := []struct { 148 orig string 149 want string 150 }{ 151 {"", ""}, 152 {"hello", "hello"}, 153 {"h%6", "h%6"}, 154 {"%G0", "%G0"}, 155 {"系统", "系统"}, 156 {"Hello, 世界", "Hello, 世界"}, 157 158 {string([]byte{0xff, 0xfe, 0xfd}), "���"}, 159 {string([]byte{0xff}) + "Hello" + string([]byte{0xfe}) + "世界" + string([]byte{0xfd}), "�Hello�世界�"}, 160 } 161 for _, tC := range testCases { 162 got := decodeGrpcMessage(encodeGrpcMessage(tC.orig)) 163 if got != tC.want { 164 t.Errorf("decodeGrpcMessage(encodeGrpcMessage(%q)) = %q, want %q", tC.orig, got, tC.want) 165 } 166 } 167 } 168 169 const binaryValue = "\u0080" 170 171 func (s) TestEncodeMetadataHeader(t *testing.T) { 172 for _, test := range []struct { 173 // input 174 kin string 175 vin string 176 // output 177 vout string 178 }{ 179 {"key", "abc", "abc"}, 180 {"KEY", "abc", "abc"}, 181 {"key-bin", "abc", "YWJj"}, 182 {"key-bin", binaryValue, "woA"}, 183 } { 184 v := encodeMetadataHeader(test.kin, test.vin) 185 if !reflect.DeepEqual(v, test.vout) { 186 t.Fatalf("encodeMetadataHeader(%q, %q) = %q, want %q", test.kin, test.vin, v, test.vout) 187 } 188 } 189 } 190 191 func (s) TestDecodeMetadataHeader(t *testing.T) { 192 for _, test := range []struct { 193 // input 194 kin string 195 vin string 196 // output 197 vout string 198 err error 199 }{ 200 {"a", "abc", "abc", nil}, 201 {"key-bin", "Zm9vAGJhcg==", "foo\x00bar", nil}, 202 {"key-bin", "Zm9vAGJhcg", "foo\x00bar", nil}, 203 {"key-bin", "woA=", binaryValue, nil}, 204 {"a", "abc,efg", "abc,efg", nil}, 205 } { 206 v, err := decodeMetadataHeader(test.kin, test.vin) 207 if !reflect.DeepEqual(v, test.vout) || !reflect.DeepEqual(err, test.err) { 208 t.Fatalf("decodeMetadataHeader(%q, %q) = %q, %v, want %q, %v", test.kin, test.vin, v, err, test.vout, test.err) 209 } 210 } 211 } 212 213 func (s) TestParseDialTarget(t *testing.T) { 214 for _, test := range []struct { 215 target, wantNet, wantAddr string 216 }{ 217 {"unix:a", "unix", "a"}, 218 {"unix:a/b/c", "unix", "a/b/c"}, 219 {"unix:/a", "unix", "/a"}, 220 {"unix:/a/b/c", "unix", "/a/b/c"}, 221 {"unix://a", "unix", "a"}, 222 {"unix://a/b/c", "unix", "/b/c"}, 223 {"unix:///a", "unix", "/a"}, 224 {"unix:///a/b/c", "unix", "/a/b/c"}, 225 {"unix:etcd:0", "unix", "etcd:0"}, 226 {"unix:///tmp/unix-3", "unix", "/tmp/unix-3"}, 227 {"unix://domain", "unix", "domain"}, 228 {"unix://etcd:0", "unix", "etcd:0"}, 229 {"unix:///etcd:0", "unix", "/etcd:0"}, 230 {"passthrough://unix://domain", "tcp", "passthrough://unix://domain"}, 231 {"https://google.com:443", "tcp", "https://google.com:443"}, 232 {"dns:///google.com", "tcp", "dns:///google.com"}, 233 {"/unix/socket/address", "tcp", "/unix/socket/address"}, 234 } { 235 gotNet, gotAddr := ParseDialTarget(test.target) 236 if gotNet != test.wantNet || gotAddr != test.wantAddr { 237 t.Errorf("ParseDialTarget(%q) = %s, %s want %s, %s", test.target, gotNet, gotAddr, test.wantNet, test.wantAddr) 238 } 239 } 240 } 241 242 type badNetworkConn struct { 243 net.Conn 244 } 245 246 func (c *badNetworkConn) Write([]byte) (int, error) { 247 return 0, io.EOF 248 } 249 250 // This test ensures Write() on a broken network connection does not lead to 251 // an infinite loop. See https://github.com/grpc/grpc-go/issues/7389 for more details. 252 func (s) TestWriteBadConnection(t *testing.T) { 253 data := []byte("test_data") 254 // Configure the bufWriter with a batchsize that results in data being flushed 255 // to the underlying conn, midway through Write(). 256 writeBufferSize := (len(data) - 1) / 2 257 writer := newBufWriter(&badNetworkConn{}, writeBufferSize, getWriteBufferPool(writeBufferSize)) 258 259 errCh := make(chan error, 1) 260 go func() { 261 _, err := writer.Write(data) 262 errCh <- err 263 }() 264 265 select { 266 case <-time.After(time.Second): 267 t.Fatalf("Write() did not return in time") 268 case err := <-errCh: 269 if !errors.Is(err, io.EOF) { 270 t.Fatalf("Write() = %v, want error presence = %v", err, io.EOF) 271 } 272 } 273 } 274 275 func BenchmarkDecodeGrpcMessage(b *testing.B) { 276 input := "Hello, %E4%B8%96%E7%95%8C" 277 want := "Hello, 世界" 278 b.ReportAllocs() 279 for i := 0; i < b.N; i++ { 280 got := decodeGrpcMessage(input) 281 if got != want { 282 b.Fatalf("decodeGrpcMessage(%q) = %s, want %s", input, got, want) 283 } 284 } 285 } 286 287 func BenchmarkEncodeGrpcMessage(b *testing.B) { 288 input := "Hello, 世界" 289 want := "Hello, %E4%B8%96%E7%95%8C" 290 b.ReportAllocs() 291 for i := 0; i < b.N; i++ { 292 got := encodeGrpcMessage(input) 293 if got != want { 294 b.Fatalf("encodeGrpcMessage(%q) = %s, want %s", input, got, want) 295 } 296 } 297 }