diff --git a/transport/controlbuf.go b/transport/controlbuf.go index e147cd51bf19..6b15f3c294e6 100644 --- a/transport/controlbuf.go +++ b/transport/controlbuf.go @@ -28,6 +28,10 @@ import ( "golang.org/x/net/http2/hpack" ) +var updateHeaderTblSize = func(e *hpack.Encoder, v uint32) { + e.SetMaxDynamicTableSizeLimit(v) +} + type itemNode struct { it interface{} next *itemNode @@ -664,6 +668,8 @@ func (l *loopyWriter) applySettings(ss []http2.Setting) error { } } } + case http2.SettingHeaderTableSize: + updateHeaderTblSize(l.hEnc, s.Val) } } return nil diff --git a/transport/transport_test.go b/transport/transport_test.go index 07a81fde2271..408b36a2994e 100644 --- a/transport/transport_test.go +++ b/transport/transport_test.go @@ -2086,3 +2086,113 @@ func runPingPongTest(t *testing.T, msgSize int) { } } } + +type tableSizeLimit struct { + mu sync.Mutex + limits []uint32 +} + +func (t *tableSizeLimit) add(limit uint32) { + t.mu.Lock() + t.limits = append(t.limits, limit) + t.mu.Unlock() +} + +func (t *tableSizeLimit) getLen() int { + t.mu.Lock() + defer t.mu.Unlock() + return len(t.limits) +} + +func (t *tableSizeLimit) getIndex(i int) uint32 { + t.mu.Lock() + defer t.mu.Unlock() + return t.limits[i] +} + +func TestHeaderTblSize(t *testing.T) { + limits := &tableSizeLimit{} + updateHeaderTblSize = func(e *hpack.Encoder, v uint32) { + e.SetMaxDynamicTableSizeLimit(v) + limits.add(v) + } + defer func() { + updateHeaderTblSize = func(e *hpack.Encoder, v uint32) { + e.SetMaxDynamicTableSizeLimit(v) + } + }() + + server, ct := setUp(t, 0, math.MaxUint32, normal) + defer ct.Close() + defer server.stop() + _, err := ct.NewStream(context.Background(), &CallHdr{}) + if err != nil { + t.Fatalf("failed to open stream: %v", err) + } + + var svrTransport ServerTransport + var i int + for i = 0; i < 1000; i++ { + server.mu.Lock() + if len(server.conns) != 0 { + server.mu.Unlock() + break + } + server.mu.Unlock() + time.Sleep(10 * time.Millisecond) + continue + } + if i == 1000 { + t.Fatalf("unable to create any server transport after 10s") + } + + for st := range server.conns { + svrTransport = st + break + } + svrTransport.(*http2Server).controlBuf.put(&outgoingSettings{ + ss: []http2.Setting{ + { + ID: http2.SettingHeaderTableSize, + Val: uint32(100), + }, + }, + }) + + for i = 0; i < 1000; i++ { + if limits.getLen() != 1 { + time.Sleep(10 * time.Millisecond) + continue + } + if val := limits.getIndex(0); val != uint32(100) { + t.Fatalf("expected limits[0] = 100, got %d", val) + } + break + } + if i == 1000 { + t.Fatalf("expected len(limits) = 1 within 10s, got != 1") + } + + ct.(*http2Client).controlBuf.put(&outgoingSettings{ + ss: []http2.Setting{ + { + ID: http2.SettingHeaderTableSize, + Val: uint32(200), + }, + }, + }) + + for i := 0; i < 1000; i++ { + if limits.getLen() != 2 { + time.Sleep(10 * time.Millisecond) + continue + } + if val := limits.getIndex(1); val != uint32(200) { + t.Fatalf("expected limits[1] = 200, got %d", val) + } + break + } + if i == 1000 { + t.Fatalf("expected len(limits) = 2 within 10s, got != 2") + } +}