Skip to content

Commit 84c13af

Browse files
Thorleonneild
authored andcommitted
http2/hpack: build static table with go generate
As the static version of headerFieldTable in hpack is generated in runtime, we may use the go:generate to prepare the struct before the initialization phase. This is supposed to save init time and allocations for many binaries, as net/http imports hpack. Before: init golang.org/x/net/http2/hpack @1.1 ms, 0.097 ms clock, 21240 bytes, 29 allocs After: init golang.org/x/net/http2/hpack @0.67 ms, 0.015 ms clock, 8120 bytes, 9 allocs Fixes golang/go#55881 Change-Id: Ia6575f67ffcba7cc4d75899b24a9c56deb58ccac Reviewed-on: https://go-review.googlesource.com/c/net/+/434875 Run-TryBot: Damien Neil <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Damien Neil <[email protected]> Reviewed-by: Bryan Mills <[email protected]>
1 parent 430a433 commit 84c13af

File tree

4 files changed

+379
-77
lines changed

4 files changed

+379
-77
lines changed

http2/hpack/gen.go

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
// Copyright 2022 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+
//go:build ignore
6+
// +build ignore
7+
8+
package main
9+
10+
import (
11+
"bytes"
12+
"fmt"
13+
"go/format"
14+
"io/ioutil"
15+
"os"
16+
"sort"
17+
18+
"golang.org/x/net/http2/hpack"
19+
)
20+
21+
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B
22+
var staticTableEntries = [...]hpack.HeaderField{
23+
{Name: ":authority"},
24+
{Name: ":method", Value: "GET"},
25+
{Name: ":method", Value: "POST"},
26+
{Name: ":path", Value: "/"},
27+
{Name: ":path", Value: "/index.html"},
28+
{Name: ":scheme", Value: "http"},
29+
{Name: ":scheme", Value: "https"},
30+
{Name: ":status", Value: "200"},
31+
{Name: ":status", Value: "204"},
32+
{Name: ":status", Value: "206"},
33+
{Name: ":status", Value: "304"},
34+
{Name: ":status", Value: "400"},
35+
{Name: ":status", Value: "404"},
36+
{Name: ":status", Value: "500"},
37+
{Name: "accept-charset"},
38+
{Name: "accept-encoding", Value: "gzip, deflate"},
39+
{Name: "accept-language"},
40+
{Name: "accept-ranges"},
41+
{Name: "accept"},
42+
{Name: "access-control-allow-origin"},
43+
{Name: "age"},
44+
{Name: "allow"},
45+
{Name: "authorization"},
46+
{Name: "cache-control"},
47+
{Name: "content-disposition"},
48+
{Name: "content-encoding"},
49+
{Name: "content-language"},
50+
{Name: "content-length"},
51+
{Name: "content-location"},
52+
{Name: "content-range"},
53+
{Name: "content-type"},
54+
{Name: "cookie"},
55+
{Name: "date"},
56+
{Name: "etag"},
57+
{Name: "expect"},
58+
{Name: "expires"},
59+
{Name: "from"},
60+
{Name: "host"},
61+
{Name: "if-match"},
62+
{Name: "if-modified-since"},
63+
{Name: "if-none-match"},
64+
{Name: "if-range"},
65+
{Name: "if-unmodified-since"},
66+
{Name: "last-modified"},
67+
{Name: "link"},
68+
{Name: "location"},
69+
{Name: "max-forwards"},
70+
{Name: "proxy-authenticate"},
71+
{Name: "proxy-authorization"},
72+
{Name: "range"},
73+
{Name: "referer"},
74+
{Name: "refresh"},
75+
{Name: "retry-after"},
76+
{Name: "server"},
77+
{Name: "set-cookie"},
78+
{Name: "strict-transport-security"},
79+
{Name: "transfer-encoding"},
80+
{Name: "user-agent"},
81+
{Name: "vary"},
82+
{Name: "via"},
83+
{Name: "www-authenticate"},
84+
}
85+
86+
type pairNameValue struct {
87+
name, value string
88+
}
89+
90+
type byNameItem struct {
91+
name string
92+
id uint64
93+
}
94+
95+
type byNameValueItem struct {
96+
pairNameValue
97+
id uint64
98+
}
99+
100+
func headerFieldToString(f hpack.HeaderField) string {
101+
return fmt.Sprintf("{Name: \"%s\", Value:\"%s\", Sensitive: %t}", f.Name, f.Value, f.Sensitive)
102+
}
103+
104+
func pairNameValueToString(v pairNameValue) string {
105+
return fmt.Sprintf("{name: \"%s\", value:\"%s\"}", v.name, v.value)
106+
}
107+
108+
const header = `
109+
// go generate gen.go
110+
// Code generated by the command above; DO NOT EDIT.
111+
112+
package hpack
113+
114+
var staticTable = &headerFieldTable{
115+
evictCount: 0,
116+
byName: map[string]uint64{
117+
`
118+
119+
//go:generate go run gen.go
120+
func main() {
121+
var bb bytes.Buffer
122+
fmt.Fprintf(&bb, header)
123+
byName := make(map[string]uint64)
124+
byNameValue := make(map[pairNameValue]uint64)
125+
for index, entry := range staticTableEntries {
126+
id := uint64(index) + 1
127+
byName[entry.Name] = id
128+
byNameValue[pairNameValue{entry.Name, entry.Value}] = id
129+
}
130+
// Sort maps for deterministic generation.
131+
byNameItems := sortByName(byName)
132+
byNameValueItems := sortByNameValue(byNameValue)
133+
134+
for _, item := range byNameItems {
135+
fmt.Fprintf(&bb, "\"%s\":%d,\n", item.name, item.id)
136+
}
137+
fmt.Fprintf(&bb, "},\n")
138+
fmt.Fprintf(&bb, "byNameValue: map[pairNameValue]uint64{\n")
139+
for _, item := range byNameValueItems {
140+
fmt.Fprintf(&bb, "%s:%d,\n", pairNameValueToString(item.pairNameValue), item.id)
141+
}
142+
fmt.Fprintf(&bb, "},\n")
143+
fmt.Fprintf(&bb, "ents: []HeaderField{\n")
144+
for _, value := range staticTableEntries {
145+
fmt.Fprintf(&bb, "%s,\n", headerFieldToString(value))
146+
}
147+
fmt.Fprintf(&bb, "},\n")
148+
fmt.Fprintf(&bb, "}\n")
149+
genFile("static_table.go", &bb)
150+
}
151+
152+
func sortByNameValue(byNameValue map[pairNameValue]uint64) []byNameValueItem {
153+
var byNameValueItems []byNameValueItem
154+
for k, v := range byNameValue {
155+
byNameValueItems = append(byNameValueItems, byNameValueItem{k, v})
156+
}
157+
sort.Slice(byNameValueItems, func(i, j int) bool {
158+
return byNameValueItems[i].id < byNameValueItems[j].id
159+
})
160+
return byNameValueItems
161+
}
162+
163+
func sortByName(byName map[string]uint64) []byNameItem {
164+
var byNameItems []byNameItem
165+
for k, v := range byName {
166+
byNameItems = append(byNameItems, byNameItem{k, v})
167+
}
168+
sort.Slice(byNameItems, func(i, j int) bool {
169+
return byNameItems[i].id < byNameItems[j].id
170+
})
171+
return byNameItems
172+
}
173+
174+
func genFile(name string, buf *bytes.Buffer) {
175+
b, err := format.Source(buf.Bytes())
176+
if err != nil {
177+
fmt.Fprintln(os.Stderr, err)
178+
os.Exit(1)
179+
}
180+
if err := ioutil.WriteFile(name, b, 0644); err != nil {
181+
fmt.Fprintln(os.Stderr, err)
182+
os.Exit(1)
183+
}
184+
}

http2/hpack/static_table.go

Lines changed: 188 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)