1
2
3
4
5 package hpack
6
7 import (
8 "io"
9 )
10
11 const (
12 uint32Max = ^uint32(0)
13 initialHeaderTableSize = 4096
14 )
15
16 type Encoder struct {
17 dynTab dynamicTable
18
19
20
21 minSize uint32
22
23
24
25 maxSizeLimit uint32
26
27
28 tableSizeUpdate bool
29 w io.Writer
30 buf []byte
31 }
32
33
34
35 func NewEncoder(w io.Writer) *Encoder {
36 e := &Encoder{
37 minSize: uint32Max,
38 maxSizeLimit: initialHeaderTableSize,
39 tableSizeUpdate: false,
40 w: w,
41 }
42 e.dynTab.table.init()
43 e.dynTab.setMaxSize(initialHeaderTableSize)
44 return e
45 }
46
47
48
49
50 func (e *Encoder) WriteField(f HeaderField) error {
51 e.buf = e.buf[:0]
52
53 if e.tableSizeUpdate {
54 e.tableSizeUpdate = false
55 if e.minSize < e.dynTab.maxSize {
56 e.buf = appendTableSize(e.buf, e.minSize)
57 }
58 e.minSize = uint32Max
59 e.buf = appendTableSize(e.buf, e.dynTab.maxSize)
60 }
61
62 idx, nameValueMatch := e.searchTable(f)
63 if nameValueMatch {
64 e.buf = appendIndexed(e.buf, idx)
65 } else {
66 indexing := e.shouldIndex(f)
67 if indexing {
68 e.dynTab.add(f)
69 }
70
71 if idx == 0 {
72 e.buf = appendNewName(e.buf, f, indexing)
73 } else {
74 e.buf = appendIndexedName(e.buf, f, idx, indexing)
75 }
76 }
77 n, err := e.w.Write(e.buf)
78 if err == nil && n != len(e.buf) {
79 err = io.ErrShortWrite
80 }
81 return err
82 }
83
84
85
86
87
88
89
90
91 func (e *Encoder) searchTable(f HeaderField) (i uint64, nameValueMatch bool) {
92 i, nameValueMatch = staticTable.search(f)
93 if nameValueMatch {
94 return i, true
95 }
96
97 j, nameValueMatch := e.dynTab.table.search(f)
98 if nameValueMatch || (i == 0 && j != 0) {
99 return j + uint64(staticTable.len()), nameValueMatch
100 }
101
102 return i, false
103 }
104
105
106
107
108 func (e *Encoder) SetMaxDynamicTableSize(v uint32) {
109 if v > e.maxSizeLimit {
110 v = e.maxSizeLimit
111 }
112 if v < e.minSize {
113 e.minSize = v
114 }
115 e.tableSizeUpdate = true
116 e.dynTab.setMaxSize(v)
117 }
118
119
120 func (e *Encoder) MaxDynamicTableSize() (v uint32) {
121 return e.dynTab.maxSize
122 }
123
124
125
126
127
128
129
130
131 func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32) {
132 e.maxSizeLimit = v
133 if e.dynTab.maxSize > v {
134 e.tableSizeUpdate = true
135 e.dynTab.setMaxSize(v)
136 }
137 }
138
139
140 func (e *Encoder) shouldIndex(f HeaderField) bool {
141 return !f.Sensitive && f.Size() <= e.dynTab.maxSize
142 }
143
144
145
146 func appendIndexed(dst []byte, i uint64) []byte {
147 first := len(dst)
148 dst = appendVarInt(dst, 7, i)
149 dst[first] |= 0x80
150 return dst
151 }
152
153
154
155
156
157
158
159
160 func appendNewName(dst []byte, f HeaderField, indexing bool) []byte {
161 dst = append(dst, encodeTypeByte(indexing, f.Sensitive))
162 dst = appendHpackString(dst, f.Name)
163 return appendHpackString(dst, f.Value)
164 }
165
166
167
168
169
170
171
172
173 func appendIndexedName(dst []byte, f HeaderField, i uint64, indexing bool) []byte {
174 first := len(dst)
175 var n byte
176 if indexing {
177 n = 6
178 } else {
179 n = 4
180 }
181 dst = appendVarInt(dst, n, i)
182 dst[first] |= encodeTypeByte(indexing, f.Sensitive)
183 return appendHpackString(dst, f.Value)
184 }
185
186
187
188 func appendTableSize(dst []byte, v uint32) []byte {
189 first := len(dst)
190 dst = appendVarInt(dst, 5, uint64(v))
191 dst[first] |= 0x20
192 return dst
193 }
194
195
196
197
198
199
200 func appendVarInt(dst []byte, n byte, i uint64) []byte {
201 k := uint64((1 << n) - 1)
202 if i < k {
203 return append(dst, byte(i))
204 }
205 dst = append(dst, byte(k))
206 i -= k
207 for ; i >= 128; i >>= 7 {
208 dst = append(dst, byte(0x80|(i&0x7f)))
209 }
210 return append(dst, byte(i))
211 }
212
213
214
215
216
217
218 func appendHpackString(dst []byte, s string) []byte {
219 huffmanLength := HuffmanEncodeLength(s)
220 if huffmanLength < uint64(len(s)) {
221 first := len(dst)
222 dst = appendVarInt(dst, 7, huffmanLength)
223 dst = AppendHuffmanString(dst, s)
224 dst[first] |= 0x80
225 } else {
226 dst = appendVarInt(dst, 7, uint64(len(s)))
227 dst = append(dst, s...)
228 }
229 return dst
230 }
231
232
233
234
235
236
237 func encodeTypeByte(indexing, sensitive bool) byte {
238 if sensitive {
239 return 0x10
240 }
241 if indexing {
242 return 0x40
243 }
244 return 0
245 }
246
View as plain text