Source file src/net/http/internal/http3/qpack_encode_test.go

     1  // Copyright 2025 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package http3
     6  
     7  import (
     8  	"bytes"
     9  	"strings"
    10  	"testing"
    11  )
    12  
    13  func TestQPACKEncode(t *testing.T) {
    14  	type header struct {
    15  		itype       indexType
    16  		name, value string
    17  	}
    18  	// Many test cases here taken from Google QUICHE,
    19  	// quiche/quic/core/qpack/qpack_encoder_test.cc.
    20  	for _, test := range []struct {
    21  		name    string
    22  		headers []header
    23  		want    []byte
    24  	}{{
    25  		name:    "empty",
    26  		headers: []header{},
    27  		want:    unhex("0000"),
    28  	}, {
    29  		name: "empty name",
    30  		headers: []header{
    31  			{mayIndex, "", "foo"},
    32  		},
    33  		want: unhex("0000208294e7"),
    34  	}, {
    35  		name: "empty value",
    36  		headers: []header{
    37  			{mayIndex, "foo", ""},
    38  		},
    39  		want: unhex("00002a94e700"),
    40  	}, {
    41  		name: "empty name and value",
    42  		headers: []header{
    43  			{mayIndex, "", ""},
    44  		},
    45  		want: unhex("00002000"),
    46  	}, {
    47  		name: "simple",
    48  		headers: []header{
    49  			{mayIndex, "foo", "bar"},
    50  		},
    51  		want: unhex("00002a94e703626172"),
    52  	}, {
    53  		name: "multiple",
    54  		headers: []header{
    55  			{mayIndex, "foo", "bar"},
    56  			{mayIndex, "ZZZZZZZ", strings.Repeat("Z", 127)},
    57  		},
    58  		want: unhex("0000" + // prefix
    59  			// foo: bar
    60  			"2a94e703626172" +
    61  			// 7 octet long header name, the smallest number
    62  			// that does not fit on a 3-bit prefix.
    63  			"27007a7a7a7a7a7a7a" +
    64  			// 127 octet long header value, the smallest
    65  			// number that does not fit on a 7-bit prefix.
    66  			"7f005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a" +
    67  			"5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a" +
    68  			"5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a" +
    69  			"5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"),
    70  	}, {
    71  		name: "static table 1",
    72  		headers: []header{
    73  			{mayIndex, ":method", "GET"},
    74  			{mayIndex, "accept-encoding", "gzip, deflate, br"},
    75  			{mayIndex, "location", ""},
    76  		},
    77  		want: unhex("0000d1dfcc"),
    78  	}, {
    79  		name: "static table 2",
    80  		headers: []header{
    81  			{mayIndex, ":method", "POST"},
    82  			{mayIndex, "accept-encoding", "compress"},
    83  			{mayIndex, "location", "foo"},
    84  		},
    85  		want: unhex("0000d45f108621e9aec2a11f5c8294e7"),
    86  	}, {
    87  		name: "static table 3",
    88  		headers: []header{
    89  			{mayIndex, ":method", "TRACE"},
    90  			{mayIndex, "accept-encoding", ""},
    91  		},
    92  		want: unhex("00005f000554524143455f1000"),
    93  	}, {
    94  		name: "never indexed literal field line with name reference",
    95  		headers: []header{
    96  			{neverIndex, ":method", ""},
    97  		},
    98  		want: unhex("00007f0000"),
    99  	}, {
   100  		name: "never indexed literal field line with literal name",
   101  		headers: []header{
   102  			{neverIndex, "a", "b"},
   103  		},
   104  		want: unhex("000031610162"),
   105  	}} {
   106  		t.Run(test.name, func(t *testing.T) {
   107  			var enc qpackEncoder
   108  			enc.init()
   109  
   110  			got := enc.encode(func(f func(itype indexType, name, value string)) {
   111  				for _, h := range test.headers {
   112  					f(h.itype, h.name, h.value)
   113  				}
   114  			})
   115  			if !bytes.Equal(got, test.want) {
   116  				for _, h := range test.headers {
   117  					t.Logf("header %v: %q", h.name, h.value)
   118  				}
   119  				t.Errorf("got:  %x", got)
   120  				t.Errorf("want: %x", test.want)
   121  			}
   122  		})
   123  	}
   124  }
   125  

View as plain text