1
2
3
4
5 package http2
6
7 import (
8 "bytes"
9 "fmt"
10 "log"
11 "net/http"
12 "net/url"
13
14 "golang.org/x/net/http/httpguts"
15 "golang.org/x/net/http2/hpack"
16 )
17
18
19 type writeFramer interface {
20 writeFrame(writeContext) error
21
22
23
24
25 staysWithinBuffer(size int) bool
26 }
27
28
29
30
31
32
33
34
35
36
37
38 type writeContext interface {
39 Framer() *Framer
40 Flush() error
41 CloseConn() error
42
43
44 HeaderEncoder() (*hpack.Encoder, *bytes.Buffer)
45 }
46
47
48
49
50 func writeEndsStream(w writeFramer) bool {
51 switch v := w.(type) {
52 case *writeData:
53 return v.endStream
54 case *writeResHeaders:
55 return v.endStream
56 case nil:
57
58
59
60 panic("writeEndsStream called on nil writeFramer")
61 }
62 return false
63 }
64
65 type flushFrameWriter struct{}
66
67 func (flushFrameWriter) writeFrame(ctx writeContext) error {
68 return ctx.Flush()
69 }
70
71 func (flushFrameWriter) staysWithinBuffer(max int) bool { return false }
72
73 type writeSettings []Setting
74
75 func (s writeSettings) staysWithinBuffer(max int) bool {
76 const settingSize = 6
77 return frameHeaderLen+settingSize*len(s) <= max
78
79 }
80
81 func (s writeSettings) writeFrame(ctx writeContext) error {
82 return ctx.Framer().WriteSettings([]Setting(s)...)
83 }
84
85 type writeGoAway struct {
86 maxStreamID uint32
87 code ErrCode
88 }
89
90 func (p *writeGoAway) writeFrame(ctx writeContext) error {
91 err := ctx.Framer().WriteGoAway(p.maxStreamID, p.code, nil)
92 ctx.Flush()
93 return err
94 }
95
96 func (*writeGoAway) staysWithinBuffer(max int) bool { return false }
97
98 type writeData struct {
99 streamID uint32
100 p []byte
101 endStream bool
102 }
103
104 func (w *writeData) String() string {
105 return fmt.Sprintf("writeData(stream=%d, p=%d, endStream=%v)", w.streamID, len(w.p), w.endStream)
106 }
107
108 func (w *writeData) writeFrame(ctx writeContext) error {
109 return ctx.Framer().WriteData(w.streamID, w.endStream, w.p)
110 }
111
112 func (w *writeData) staysWithinBuffer(max int) bool {
113 return frameHeaderLen+len(w.p) <= max
114 }
115
116
117
118 type handlerPanicRST struct {
119 StreamID uint32
120 }
121
122 func (hp handlerPanicRST) writeFrame(ctx writeContext) error {
123 return ctx.Framer().WriteRSTStream(hp.StreamID, ErrCodeInternal)
124 }
125
126 func (hp handlerPanicRST) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
127
128 func (se StreamError) writeFrame(ctx writeContext) error {
129 return ctx.Framer().WriteRSTStream(se.StreamID, se.Code)
130 }
131
132 func (se StreamError) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
133
134 type writePingAck struct{ pf *PingFrame }
135
136 func (w writePingAck) writeFrame(ctx writeContext) error {
137 return ctx.Framer().WritePing(true, w.pf.Data)
138 }
139
140 func (w writePingAck) staysWithinBuffer(max int) bool { return frameHeaderLen+len(w.pf.Data) <= max }
141
142 type writeSettingsAck struct{}
143
144 func (writeSettingsAck) writeFrame(ctx writeContext) error {
145 return ctx.Framer().WriteSettingsAck()
146 }
147
148 func (writeSettingsAck) staysWithinBuffer(max int) bool { return frameHeaderLen <= max }
149
150
151
152
153 func splitHeaderBlock(ctx writeContext, headerBlock []byte, fn func(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error) error {
154
155
156
157
158
159
160 const maxFrameSize = 16384
161
162 first := true
163 for len(headerBlock) > 0 {
164 frag := headerBlock
165 if len(frag) > maxFrameSize {
166 frag = frag[:maxFrameSize]
167 }
168 headerBlock = headerBlock[len(frag):]
169 if err := fn(ctx, frag, first, len(headerBlock) == 0); err != nil {
170 return err
171 }
172 first = false
173 }
174 return nil
175 }
176
177
178
179 type writeResHeaders struct {
180 streamID uint32
181 httpResCode int
182 h http.Header
183 trailers []string
184 endStream bool
185
186 date string
187 contentType string
188 contentLength string
189 }
190
191 func encKV(enc *hpack.Encoder, k, v string) {
192 if VerboseLogs {
193 log.Printf("http2: server encoding header %q = %q", k, v)
194 }
195 enc.WriteField(hpack.HeaderField{Name: k, Value: v})
196 }
197
198 func (w *writeResHeaders) staysWithinBuffer(max int) bool {
199
200
201
202
203
204
205
206 return false
207 }
208
209 func (w *writeResHeaders) writeFrame(ctx writeContext) error {
210 enc, buf := ctx.HeaderEncoder()
211 buf.Reset()
212
213 if w.httpResCode != 0 {
214 encKV(enc, ":status", httpCodeString(w.httpResCode))
215 }
216
217 encodeHeaders(enc, w.h, w.trailers)
218
219 if w.contentType != "" {
220 encKV(enc, "content-type", w.contentType)
221 }
222 if w.contentLength != "" {
223 encKV(enc, "content-length", w.contentLength)
224 }
225 if w.date != "" {
226 encKV(enc, "date", w.date)
227 }
228
229 headerBlock := buf.Bytes()
230 if len(headerBlock) == 0 && w.trailers == nil {
231 panic("unexpected empty hpack")
232 }
233
234 return splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
235 }
236
237 func (w *writeResHeaders) writeHeaderBlock(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error {
238 if firstFrag {
239 return ctx.Framer().WriteHeaders(HeadersFrameParam{
240 StreamID: w.streamID,
241 BlockFragment: frag,
242 EndStream: w.endStream,
243 EndHeaders: lastFrag,
244 })
245 } else {
246 return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
247 }
248 }
249
250
251 type writePushPromise struct {
252 streamID uint32
253 method string
254 url *url.URL
255 h http.Header
256
257
258
259 allocatePromisedID func() (uint32, error)
260 promisedID uint32
261 }
262
263 func (w *writePushPromise) staysWithinBuffer(max int) bool {
264
265 return false
266 }
267
268 func (w *writePushPromise) writeFrame(ctx writeContext) error {
269 enc, buf := ctx.HeaderEncoder()
270 buf.Reset()
271
272 encKV(enc, ":method", w.method)
273 encKV(enc, ":scheme", w.url.Scheme)
274 encKV(enc, ":authority", w.url.Host)
275 encKV(enc, ":path", w.url.RequestURI())
276 encodeHeaders(enc, w.h, nil)
277
278 headerBlock := buf.Bytes()
279 if len(headerBlock) == 0 {
280 panic("unexpected empty hpack")
281 }
282
283 return splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
284 }
285
286 func (w *writePushPromise) writeHeaderBlock(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error {
287 if firstFrag {
288 return ctx.Framer().WritePushPromise(PushPromiseParam{
289 StreamID: w.streamID,
290 PromiseID: w.promisedID,
291 BlockFragment: frag,
292 EndHeaders: lastFrag,
293 })
294 } else {
295 return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
296 }
297 }
298
299 type write100ContinueHeadersFrame struct {
300 streamID uint32
301 }
302
303 func (w write100ContinueHeadersFrame) writeFrame(ctx writeContext) error {
304 enc, buf := ctx.HeaderEncoder()
305 buf.Reset()
306 encKV(enc, ":status", "100")
307 return ctx.Framer().WriteHeaders(HeadersFrameParam{
308 StreamID: w.streamID,
309 BlockFragment: buf.Bytes(),
310 EndStream: false,
311 EndHeaders: true,
312 })
313 }
314
315 func (w write100ContinueHeadersFrame) staysWithinBuffer(max int) bool {
316
317 return 9+2*(len(":status")+len("100")) <= max
318 }
319
320 type writeWindowUpdate struct {
321 streamID uint32
322 n uint32
323 }
324
325 func (wu writeWindowUpdate) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
326
327 func (wu writeWindowUpdate) writeFrame(ctx writeContext) error {
328 return ctx.Framer().WriteWindowUpdate(wu.streamID, wu.n)
329 }
330
331
332
333 func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) {
334 if keys == nil {
335 sorter := sorterPool.Get().(*sorter)
336
337
338
339 defer sorterPool.Put(sorter)
340 keys = sorter.Keys(h)
341 }
342 for _, k := range keys {
343 vv := h[k]
344 k, ascii := lowerHeader(k)
345 if !ascii {
346
347
348 continue
349 }
350 if !validWireHeaderFieldName(k) {
351
352
353
354 continue
355 }
356 isTE := k == "transfer-encoding"
357 for _, v := range vv {
358 if !httpguts.ValidHeaderFieldValue(v) {
359
360
361 continue
362 }
363
364 if isTE && v != "trailers" {
365 continue
366 }
367 encKV(enc, k, v)
368 }
369 }
370 }
371
View as plain text