// Copyright 2026 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. package http2 import ( "errors" "fmt" "strings" "testing" ) func TestCheckValidHTTP2Request(t *testing.T) { tests := []struct { h Header want error }{ { h: Header{"Te": {"trailers"}}, want: nil, }, { h: Header{"Te": {"trailers", "bogus"}}, want: errors.New(`request header "TE" may only be "trailers" in HTTP/2`), }, { h: Header{"Foo": {""}}, want: nil, }, { h: Header{"Connection": {""}}, want: errors.New(`request header "Connection" is not valid in HTTP/2`), }, { h: Header{"Proxy-Connection": {""}}, want: errors.New(`request header "Proxy-Connection" is not valid in HTTP/2`), }, { h: Header{"Keep-Alive": {""}}, want: errors.New(`request header "Keep-Alive" is not valid in HTTP/2`), }, { h: Header{"Upgrade": {""}}, want: errors.New(`request header "Upgrade" is not valid in HTTP/2`), }, } for i, tt := range tests { got := checkValidHTTP2RequestHeaders(tt.h) if !equalError(got, tt.want) { t.Errorf("%d. checkValidHTTP2Request = %v; want %v", i, got, tt.want) } } } // TestCanonicalHeaderCacheGrowth verifies that the canonical header cache // size is capped to a reasonable level. func TestCanonicalHeaderCacheGrowth(t *testing.T) { for _, size := range []int{1, (1 << 20) - 10} { base := strings.Repeat("X", size) sc := &serverConn{ serveG: newGoroutineLock(), } count := 0 added := 0 for added < 10*maxCachedCanonicalHeadersKeysSize { h := fmt.Sprintf("%v-%v", base, count) c := sc.canonicalHeader(h) if len(h) != len(c) { t.Errorf("sc.canonicalHeader(%q) = %q, want same length", h, c) } count++ added += len(h) } total := 0 for k, v := range sc.canonHeader { total += len(k) + len(v) + 100 } if total > maxCachedCanonicalHeadersKeysSize { t.Errorf("after adding %v ~%v-byte headers, canonHeader cache is ~%v bytes, want <%v", count, size, total, maxCachedCanonicalHeadersKeysSize) } } }