| // Copyright 2025 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| //go:build go1.24 |
| |
| package http3 |
| |
| import ( |
| "bytes" |
| "testing" |
| ) |
| |
| func TestPrefixedInt(t *testing.T) { |
| st1, st2 := newStreamPair(t) |
| for _, test := range []struct { |
| value int64 |
| prefixLen uint8 |
| encoded []byte |
| }{ |
| // https://www.rfc-editor.org/rfc/rfc7541#appendix-C.1.1 |
| { |
| value: 10, |
| prefixLen: 5, |
| encoded: []byte{ |
| 0b_0000_1010, |
| }, |
| }, |
| // https://www.rfc-editor.org/rfc/rfc7541#appendix-C.1.2 |
| { |
| value: 1337, |
| prefixLen: 5, |
| encoded: []byte{ |
| 0b0001_1111, |
| 0b1001_1010, |
| 0b0000_1010, |
| }, |
| }, |
| // https://www.rfc-editor.org/rfc/rfc7541#appendix-C.1.3 |
| { |
| value: 42, |
| prefixLen: 8, |
| encoded: []byte{ |
| 0b0010_1010, |
| }, |
| }, |
| } { |
| highBitMask := ^((byte(1) << test.prefixLen) - 1) |
| for _, highBits := range []byte{ |
| 0, highBitMask, 0b1010_1010 & highBitMask, |
| } { |
| gotEnc := appendPrefixedInt(nil, highBits, test.prefixLen, test.value) |
| wantEnc := append([]byte{}, test.encoded...) |
| wantEnc[0] |= highBits |
| if !bytes.Equal(gotEnc, wantEnc) { |
| t.Errorf("appendPrefixedInt(nil, 0b%08b, %v, %v) = {%x}, want {%x}", |
| highBits, test.prefixLen, test.value, gotEnc, wantEnc) |
| } |
| |
| st1.Write(gotEnc) |
| if err := st1.Flush(); err != nil { |
| t.Fatal(err) |
| } |
| gotFirstByte, v, err := st2.readPrefixedInt(test.prefixLen) |
| if err != nil || gotFirstByte&highBitMask != highBits || v != test.value { |
| t.Errorf("st.readPrefixedInt(%v) = 0b%08b, %v, %v; want 0b%08b, %v, nil", test.prefixLen, gotFirstByte, v, err, highBits, test.value) |
| } |
| } |
| } |
| } |
| |
| func TestPrefixedString(t *testing.T) { |
| st1, st2 := newStreamPair(t) |
| for _, test := range []struct { |
| value string |
| prefixLen uint8 |
| encoded []byte |
| }{ |
| // https://www.rfc-editor.org/rfc/rfc7541#appendix-C.6.1 |
| { |
| value: "302", |
| prefixLen: 7, |
| encoded: []byte{ |
| 0x82, // H bit + length 2 |
| 0x64, 0x02, |
| }, |
| }, |
| { |
| value: "private", |
| prefixLen: 5, |
| encoded: []byte{ |
| 0x25, // H bit + length 5 |
| 0xae, 0xc3, 0x77, 0x1a, 0x4b, |
| }, |
| }, |
| { |
| value: "Mon, 21 Oct 2013 20:13:21 GMT", |
| prefixLen: 7, |
| encoded: []byte{ |
| 0x96, // H bit + length 22 |
| 0xd0, 0x7a, 0xbe, 0x94, 0x10, 0x54, 0xd4, 0x44, |
| 0xa8, 0x20, 0x05, 0x95, 0x04, 0x0b, 0x81, 0x66, |
| 0xe0, 0x82, 0xa6, 0x2d, 0x1b, 0xff, |
| }, |
| }, |
| { |
| value: "https://www.example.com", |
| prefixLen: 7, |
| encoded: []byte{ |
| 0x91, // H bit + length 17 |
| 0x9d, 0x29, 0xad, 0x17, 0x18, 0x63, 0xc7, 0x8f, |
| 0x0b, 0x97, 0xc8, 0xe9, 0xae, 0x82, 0xae, 0x43, |
| 0xd3, |
| }, |
| }, |
| // Not Huffman encoded (encoded size == unencoded size). |
| { |
| value: "a", |
| prefixLen: 7, |
| encoded: []byte{ |
| 0x01, // length 1 |
| 0x61, |
| }, |
| }, |
| // Empty string. |
| { |
| value: "", |
| prefixLen: 7, |
| encoded: []byte{ |
| 0x00, // length 0 |
| }, |
| }, |
| } { |
| highBitMask := ^((byte(1) << (test.prefixLen + 1)) - 1) |
| for _, highBits := range []byte{ |
| 0, highBitMask, 0b1010_1010 & highBitMask, |
| } { |
| gotEnc := appendPrefixedString(nil, highBits, test.prefixLen, test.value) |
| wantEnc := append([]byte{}, test.encoded...) |
| wantEnc[0] |= highBits |
| if !bytes.Equal(gotEnc, wantEnc) { |
| t.Errorf("appendPrefixedString(nil, 0b%08b, %v, %v) = {%x}, want {%x}", |
| highBits, test.prefixLen, test.value, gotEnc, wantEnc) |
| } |
| |
| st1.Write(gotEnc) |
| if err := st1.Flush(); err != nil { |
| t.Fatal(err) |
| } |
| gotFirstByte, v, err := st2.readPrefixedString(test.prefixLen) |
| if err != nil || gotFirstByte&highBitMask != highBits || v != test.value { |
| t.Errorf("st.readPrefixedInt(%v) = 0b%08b, %q, %v; want 0b%08b, %q, nil", test.prefixLen, gotFirstByte, v, err, highBits, test.value) |
| } |
| } |
| } |
| } |
| |
| func TestHuffmanDecodingFailure(t *testing.T) { |
| st1, st2 := newStreamPair(t) |
| st1.Write([]byte{ |
| 0x82, // H bit + length 4 |
| 0b_1111_1111, |
| 0b_1111_1111, |
| 0b_1111_1111, |
| 0b_1111_1111, |
| }) |
| if err := st1.Flush(); err != nil { |
| t.Fatal(err) |
| } |
| if b, v, err := st2.readPrefixedString(7); err == nil { |
| t.Fatalf("readPrefixedString(7) = %x, %v, nil; want error", b, v) |
| } |
| } |