]>
Commit | Line | Data |
---|---|---|
15c0b25d AP |
1 | // Copyright 2014 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 | package http2 | |
6 | ||
7 | import ( | |
8 | "bytes" | |
9 | "encoding/binary" | |
10 | "errors" | |
11 | "fmt" | |
12 | "io" | |
13 | "log" | |
14 | "strings" | |
15 | "sync" | |
16 | ||
17 | "golang.org/x/net/http2/hpack" | |
18 | "golang.org/x/net/lex/httplex" | |
19 | ) | |
20 | ||
21 | const frameHeaderLen = 9 | |
22 | ||
23 | var padZeros = make([]byte, 255) // zeros for padding | |
24 | ||
25 | // A FrameType is a registered frame type as defined in | |
26 | // http://http2.github.io/http2-spec/#rfc.section.11.2 | |
27 | type FrameType uint8 | |
28 | ||
29 | const ( | |
30 | FrameData FrameType = 0x0 | |
31 | FrameHeaders FrameType = 0x1 | |
32 | FramePriority FrameType = 0x2 | |
33 | FrameRSTStream FrameType = 0x3 | |
34 | FrameSettings FrameType = 0x4 | |
35 | FramePushPromise FrameType = 0x5 | |
36 | FramePing FrameType = 0x6 | |
37 | FrameGoAway FrameType = 0x7 | |
38 | FrameWindowUpdate FrameType = 0x8 | |
39 | FrameContinuation FrameType = 0x9 | |
40 | ) | |
41 | ||
42 | var frameName = map[FrameType]string{ | |
43 | FrameData: "DATA", | |
44 | FrameHeaders: "HEADERS", | |
45 | FramePriority: "PRIORITY", | |
46 | FrameRSTStream: "RST_STREAM", | |
47 | FrameSettings: "SETTINGS", | |
48 | FramePushPromise: "PUSH_PROMISE", | |
49 | FramePing: "PING", | |
50 | FrameGoAway: "GOAWAY", | |
51 | FrameWindowUpdate: "WINDOW_UPDATE", | |
52 | FrameContinuation: "CONTINUATION", | |
53 | } | |
54 | ||
55 | func (t FrameType) String() string { | |
56 | if s, ok := frameName[t]; ok { | |
57 | return s | |
58 | } | |
59 | return fmt.Sprintf("UNKNOWN_FRAME_TYPE_%d", uint8(t)) | |
60 | } | |
61 | ||
62 | // Flags is a bitmask of HTTP/2 flags. | |
63 | // The meaning of flags varies depending on the frame type. | |
64 | type Flags uint8 | |
65 | ||
66 | // Has reports whether f contains all (0 or more) flags in v. | |
67 | func (f Flags) Has(v Flags) bool { | |
68 | return (f & v) == v | |
69 | } | |
70 | ||
71 | // Frame-specific FrameHeader flag bits. | |
72 | const ( | |
73 | // Data Frame | |
74 | FlagDataEndStream Flags = 0x1 | |
75 | FlagDataPadded Flags = 0x8 | |
76 | ||
77 | // Headers Frame | |
78 | FlagHeadersEndStream Flags = 0x1 | |
79 | FlagHeadersEndHeaders Flags = 0x4 | |
80 | FlagHeadersPadded Flags = 0x8 | |
81 | FlagHeadersPriority Flags = 0x20 | |
82 | ||
83 | // Settings Frame | |
84 | FlagSettingsAck Flags = 0x1 | |
85 | ||
86 | // Ping Frame | |
87 | FlagPingAck Flags = 0x1 | |
88 | ||
89 | // Continuation Frame | |
90 | FlagContinuationEndHeaders Flags = 0x4 | |
91 | ||
92 | FlagPushPromiseEndHeaders Flags = 0x4 | |
93 | FlagPushPromisePadded Flags = 0x8 | |
94 | ) | |
95 | ||
96 | var flagName = map[FrameType]map[Flags]string{ | |
97 | FrameData: { | |
98 | FlagDataEndStream: "END_STREAM", | |
99 | FlagDataPadded: "PADDED", | |
100 | }, | |
101 | FrameHeaders: { | |
102 | FlagHeadersEndStream: "END_STREAM", | |
103 | FlagHeadersEndHeaders: "END_HEADERS", | |
104 | FlagHeadersPadded: "PADDED", | |
105 | FlagHeadersPriority: "PRIORITY", | |
106 | }, | |
107 | FrameSettings: { | |
108 | FlagSettingsAck: "ACK", | |
109 | }, | |
110 | FramePing: { | |
111 | FlagPingAck: "ACK", | |
112 | }, | |
113 | FrameContinuation: { | |
114 | FlagContinuationEndHeaders: "END_HEADERS", | |
115 | }, | |
116 | FramePushPromise: { | |
117 | FlagPushPromiseEndHeaders: "END_HEADERS", | |
118 | FlagPushPromisePadded: "PADDED", | |
119 | }, | |
120 | } | |
121 | ||
122 | // a frameParser parses a frame given its FrameHeader and payload | |
123 | // bytes. The length of payload will always equal fh.Length (which | |
124 | // might be 0). | |
125 | type frameParser func(fc *frameCache, fh FrameHeader, payload []byte) (Frame, error) | |
126 | ||
127 | var frameParsers = map[FrameType]frameParser{ | |
128 | FrameData: parseDataFrame, | |
129 | FrameHeaders: parseHeadersFrame, | |
130 | FramePriority: parsePriorityFrame, | |
131 | FrameRSTStream: parseRSTStreamFrame, | |
132 | FrameSettings: parseSettingsFrame, | |
133 | FramePushPromise: parsePushPromise, | |
134 | FramePing: parsePingFrame, | |
135 | FrameGoAway: parseGoAwayFrame, | |
136 | FrameWindowUpdate: parseWindowUpdateFrame, | |
137 | FrameContinuation: parseContinuationFrame, | |
138 | } | |
139 | ||
140 | func typeFrameParser(t FrameType) frameParser { | |
141 | if f := frameParsers[t]; f != nil { | |
142 | return f | |
143 | } | |
144 | return parseUnknownFrame | |
145 | } | |
146 | ||
147 | // A FrameHeader is the 9 byte header of all HTTP/2 frames. | |
148 | // | |
149 | // See http://http2.github.io/http2-spec/#FrameHeader | |
150 | type FrameHeader struct { | |
151 | valid bool // caller can access []byte fields in the Frame | |
152 | ||
153 | // Type is the 1 byte frame type. There are ten standard frame | |
154 | // types, but extension frame types may be written by WriteRawFrame | |
155 | // and will be returned by ReadFrame (as UnknownFrame). | |
156 | Type FrameType | |
157 | ||
158 | // Flags are the 1 byte of 8 potential bit flags per frame. | |
159 | // They are specific to the frame type. | |
160 | Flags Flags | |
161 | ||
162 | // Length is the length of the frame, not including the 9 byte header. | |
163 | // The maximum size is one byte less than 16MB (uint24), but only | |
164 | // frames up to 16KB are allowed without peer agreement. | |
165 | Length uint32 | |
166 | ||
167 | // StreamID is which stream this frame is for. Certain frames | |
168 | // are not stream-specific, in which case this field is 0. | |
169 | StreamID uint32 | |
170 | } | |
171 | ||
172 | // Header returns h. It exists so FrameHeaders can be embedded in other | |
173 | // specific frame types and implement the Frame interface. | |
174 | func (h FrameHeader) Header() FrameHeader { return h } | |
175 | ||
176 | func (h FrameHeader) String() string { | |
177 | var buf bytes.Buffer | |
178 | buf.WriteString("[FrameHeader ") | |
179 | h.writeDebug(&buf) | |
180 | buf.WriteByte(']') | |
181 | return buf.String() | |
182 | } | |
183 | ||
184 | func (h FrameHeader) writeDebug(buf *bytes.Buffer) { | |
185 | buf.WriteString(h.Type.String()) | |
186 | if h.Flags != 0 { | |
187 | buf.WriteString(" flags=") | |
188 | set := 0 | |
189 | for i := uint8(0); i < 8; i++ { | |
190 | if h.Flags&(1<<i) == 0 { | |
191 | continue | |
192 | } | |
193 | set++ | |
194 | if set > 1 { | |
195 | buf.WriteByte('|') | |
196 | } | |
197 | name := flagName[h.Type][Flags(1<<i)] | |
198 | if name != "" { | |
199 | buf.WriteString(name) | |
200 | } else { | |
201 | fmt.Fprintf(buf, "0x%x", 1<<i) | |
202 | } | |
203 | } | |
204 | } | |
205 | if h.StreamID != 0 { | |
206 | fmt.Fprintf(buf, " stream=%d", h.StreamID) | |
207 | } | |
208 | fmt.Fprintf(buf, " len=%d", h.Length) | |
209 | } | |
210 | ||
211 | func (h *FrameHeader) checkValid() { | |
212 | if !h.valid { | |
213 | panic("Frame accessor called on non-owned Frame") | |
214 | } | |
215 | } | |
216 | ||
217 | func (h *FrameHeader) invalidate() { h.valid = false } | |
218 | ||
219 | // frame header bytes. | |
220 | // Used only by ReadFrameHeader. | |
221 | var fhBytes = sync.Pool{ | |
222 | New: func() interface{} { | |
223 | buf := make([]byte, frameHeaderLen) | |
224 | return &buf | |
225 | }, | |
226 | } | |
227 | ||
228 | // ReadFrameHeader reads 9 bytes from r and returns a FrameHeader. | |
229 | // Most users should use Framer.ReadFrame instead. | |
230 | func ReadFrameHeader(r io.Reader) (FrameHeader, error) { | |
231 | bufp := fhBytes.Get().(*[]byte) | |
232 | defer fhBytes.Put(bufp) | |
233 | return readFrameHeader(*bufp, r) | |
234 | } | |
235 | ||
236 | func readFrameHeader(buf []byte, r io.Reader) (FrameHeader, error) { | |
237 | _, err := io.ReadFull(r, buf[:frameHeaderLen]) | |
238 | if err != nil { | |
239 | return FrameHeader{}, err | |
240 | } | |
241 | return FrameHeader{ | |
242 | Length: (uint32(buf[0])<<16 | uint32(buf[1])<<8 | uint32(buf[2])), | |
243 | Type: FrameType(buf[3]), | |
244 | Flags: Flags(buf[4]), | |
245 | StreamID: binary.BigEndian.Uint32(buf[5:]) & (1<<31 - 1), | |
246 | valid: true, | |
247 | }, nil | |
248 | } | |
249 | ||
250 | // A Frame is the base interface implemented by all frame types. | |
251 | // Callers will generally type-assert the specific frame type: | |
252 | // *HeadersFrame, *SettingsFrame, *WindowUpdateFrame, etc. | |
253 | // | |
254 | // Frames are only valid until the next call to Framer.ReadFrame. | |
255 | type Frame interface { | |
256 | Header() FrameHeader | |
257 | ||
258 | // invalidate is called by Framer.ReadFrame to make this | |
259 | // frame's buffers as being invalid, since the subsequent | |
260 | // frame will reuse them. | |
261 | invalidate() | |
262 | } | |
263 | ||
264 | // A Framer reads and writes Frames. | |
265 | type Framer struct { | |
266 | r io.Reader | |
267 | lastFrame Frame | |
268 | errDetail error | |
269 | ||
270 | // lastHeaderStream is non-zero if the last frame was an | |
271 | // unfinished HEADERS/CONTINUATION. | |
272 | lastHeaderStream uint32 | |
273 | ||
274 | maxReadSize uint32 | |
275 | headerBuf [frameHeaderLen]byte | |
276 | ||
277 | // TODO: let getReadBuf be configurable, and use a less memory-pinning | |
278 | // allocator in server.go to minimize memory pinned for many idle conns. | |
279 | // Will probably also need to make frame invalidation have a hook too. | |
280 | getReadBuf func(size uint32) []byte | |
281 | readBuf []byte // cache for default getReadBuf | |
282 | ||
283 | maxWriteSize uint32 // zero means unlimited; TODO: implement | |
284 | ||
285 | w io.Writer | |
286 | wbuf []byte | |
287 | ||
288 | // AllowIllegalWrites permits the Framer's Write methods to | |
289 | // write frames that do not conform to the HTTP/2 spec. This | |
290 | // permits using the Framer to test other HTTP/2 | |
291 | // implementations' conformance to the spec. | |
292 | // If false, the Write methods will prefer to return an error | |
293 | // rather than comply. | |
294 | AllowIllegalWrites bool | |
295 | ||
296 | // AllowIllegalReads permits the Framer's ReadFrame method | |
297 | // to return non-compliant frames or frame orders. | |
298 | // This is for testing and permits using the Framer to test | |
299 | // other HTTP/2 implementations' conformance to the spec. | |
300 | // It is not compatible with ReadMetaHeaders. | |
301 | AllowIllegalReads bool | |
302 | ||
303 | // ReadMetaHeaders if non-nil causes ReadFrame to merge | |
304 | // HEADERS and CONTINUATION frames together and return | |
305 | // MetaHeadersFrame instead. | |
306 | ReadMetaHeaders *hpack.Decoder | |
307 | ||
308 | // MaxHeaderListSize is the http2 MAX_HEADER_LIST_SIZE. | |
309 | // It's used only if ReadMetaHeaders is set; 0 means a sane default | |
310 | // (currently 16MB) | |
311 | // If the limit is hit, MetaHeadersFrame.Truncated is set true. | |
312 | MaxHeaderListSize uint32 | |
313 | ||
314 | // TODO: track which type of frame & with which flags was sent | |
315 | // last. Then return an error (unless AllowIllegalWrites) if | |
316 | // we're in the middle of a header block and a | |
317 | // non-Continuation or Continuation on a different stream is | |
318 | // attempted to be written. | |
319 | ||
320 | logReads, logWrites bool | |
321 | ||
322 | debugFramer *Framer // only use for logging written writes | |
323 | debugFramerBuf *bytes.Buffer | |
324 | debugReadLoggerf func(string, ...interface{}) | |
325 | debugWriteLoggerf func(string, ...interface{}) | |
326 | ||
327 | frameCache *frameCache // nil if frames aren't reused (default) | |
328 | } | |
329 | ||
330 | func (fr *Framer) maxHeaderListSize() uint32 { | |
331 | if fr.MaxHeaderListSize == 0 { | |
332 | return 16 << 20 // sane default, per docs | |
333 | } | |
334 | return fr.MaxHeaderListSize | |
335 | } | |
336 | ||
337 | func (f *Framer) startWrite(ftype FrameType, flags Flags, streamID uint32) { | |
338 | // Write the FrameHeader. | |
339 | f.wbuf = append(f.wbuf[:0], | |
340 | 0, // 3 bytes of length, filled in in endWrite | |
341 | 0, | |
342 | 0, | |
343 | byte(ftype), | |
344 | byte(flags), | |
345 | byte(streamID>>24), | |
346 | byte(streamID>>16), | |
347 | byte(streamID>>8), | |
348 | byte(streamID)) | |
349 | } | |
350 | ||
351 | func (f *Framer) endWrite() error { | |
352 | // Now that we know the final size, fill in the FrameHeader in | |
353 | // the space previously reserved for it. Abuse append. | |
354 | length := len(f.wbuf) - frameHeaderLen | |
355 | if length >= (1 << 24) { | |
356 | return ErrFrameTooLarge | |
357 | } | |
358 | _ = append(f.wbuf[:0], | |
359 | byte(length>>16), | |
360 | byte(length>>8), | |
361 | byte(length)) | |
362 | if f.logWrites { | |
363 | f.logWrite() | |
364 | } | |
365 | ||
366 | n, err := f.w.Write(f.wbuf) | |
367 | if err == nil && n != len(f.wbuf) { | |
368 | err = io.ErrShortWrite | |
369 | } | |
370 | return err | |
371 | } | |
372 | ||
373 | func (f *Framer) logWrite() { | |
374 | if f.debugFramer == nil { | |
375 | f.debugFramerBuf = new(bytes.Buffer) | |
376 | f.debugFramer = NewFramer(nil, f.debugFramerBuf) | |
377 | f.debugFramer.logReads = false // we log it ourselves, saying "wrote" below | |
378 | // Let us read anything, even if we accidentally wrote it | |
379 | // in the wrong order: | |
380 | f.debugFramer.AllowIllegalReads = true | |
381 | } | |
382 | f.debugFramerBuf.Write(f.wbuf) | |
383 | fr, err := f.debugFramer.ReadFrame() | |
384 | if err != nil { | |
385 | f.debugWriteLoggerf("http2: Framer %p: failed to decode just-written frame", f) | |
386 | return | |
387 | } | |
388 | f.debugWriteLoggerf("http2: Framer %p: wrote %v", f, summarizeFrame(fr)) | |
389 | } | |
390 | ||
391 | func (f *Framer) writeByte(v byte) { f.wbuf = append(f.wbuf, v) } | |
392 | func (f *Framer) writeBytes(v []byte) { f.wbuf = append(f.wbuf, v...) } | |
393 | func (f *Framer) writeUint16(v uint16) { f.wbuf = append(f.wbuf, byte(v>>8), byte(v)) } | |
394 | func (f *Framer) writeUint32(v uint32) { | |
395 | f.wbuf = append(f.wbuf, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) | |
396 | } | |
397 | ||
398 | const ( | |
399 | minMaxFrameSize = 1 << 14 | |
400 | maxFrameSize = 1<<24 - 1 | |
401 | ) | |
402 | ||
403 | // SetReuseFrames allows the Framer to reuse Frames. | |
404 | // If called on a Framer, Frames returned by calls to ReadFrame are only | |
405 | // valid until the next call to ReadFrame. | |
406 | func (fr *Framer) SetReuseFrames() { | |
407 | if fr.frameCache != nil { | |
408 | return | |
409 | } | |
410 | fr.frameCache = &frameCache{} | |
411 | } | |
412 | ||
413 | type frameCache struct { | |
414 | dataFrame DataFrame | |
415 | } | |
416 | ||
417 | func (fc *frameCache) getDataFrame() *DataFrame { | |
418 | if fc == nil { | |
419 | return &DataFrame{} | |
420 | } | |
421 | return &fc.dataFrame | |
422 | } | |
423 | ||
424 | // NewFramer returns a Framer that writes frames to w and reads them from r. | |
425 | func NewFramer(w io.Writer, r io.Reader) *Framer { | |
426 | fr := &Framer{ | |
427 | w: w, | |
428 | r: r, | |
429 | logReads: logFrameReads, | |
430 | logWrites: logFrameWrites, | |
431 | debugReadLoggerf: log.Printf, | |
432 | debugWriteLoggerf: log.Printf, | |
433 | } | |
434 | fr.getReadBuf = func(size uint32) []byte { | |
435 | if cap(fr.readBuf) >= int(size) { | |
436 | return fr.readBuf[:size] | |
437 | } | |
438 | fr.readBuf = make([]byte, size) | |
439 | return fr.readBuf | |
440 | } | |
441 | fr.SetMaxReadFrameSize(maxFrameSize) | |
442 | return fr | |
443 | } | |
444 | ||
445 | // SetMaxReadFrameSize sets the maximum size of a frame | |
446 | // that will be read by a subsequent call to ReadFrame. | |
447 | // It is the caller's responsibility to advertise this | |
448 | // limit with a SETTINGS frame. | |
449 | func (fr *Framer) SetMaxReadFrameSize(v uint32) { | |
450 | if v > maxFrameSize { | |
451 | v = maxFrameSize | |
452 | } | |
453 | fr.maxReadSize = v | |
454 | } | |
455 | ||
456 | // ErrorDetail returns a more detailed error of the last error | |
457 | // returned by Framer.ReadFrame. For instance, if ReadFrame | |
458 | // returns a StreamError with code PROTOCOL_ERROR, ErrorDetail | |
459 | // will say exactly what was invalid. ErrorDetail is not guaranteed | |
460 | // to return a non-nil value and like the rest of the http2 package, | |
461 | // its return value is not protected by an API compatibility promise. | |
462 | // ErrorDetail is reset after the next call to ReadFrame. | |
463 | func (fr *Framer) ErrorDetail() error { | |
464 | return fr.errDetail | |
465 | } | |
466 | ||
467 | // ErrFrameTooLarge is returned from Framer.ReadFrame when the peer | |
468 | // sends a frame that is larger than declared with SetMaxReadFrameSize. | |
469 | var ErrFrameTooLarge = errors.New("http2: frame too large") | |
470 | ||
471 | // terminalReadFrameError reports whether err is an unrecoverable | |
472 | // error from ReadFrame and no other frames should be read. | |
473 | func terminalReadFrameError(err error) bool { | |
474 | if _, ok := err.(StreamError); ok { | |
475 | return false | |
476 | } | |
477 | return err != nil | |
478 | } | |
479 | ||
480 | // ReadFrame reads a single frame. The returned Frame is only valid | |
481 | // until the next call to ReadFrame. | |
482 | // | |
483 | // If the frame is larger than previously set with SetMaxReadFrameSize, the | |
484 | // returned error is ErrFrameTooLarge. Other errors may be of type | |
485 | // ConnectionError, StreamError, or anything else from the underlying | |
486 | // reader. | |
487 | func (fr *Framer) ReadFrame() (Frame, error) { | |
488 | fr.errDetail = nil | |
489 | if fr.lastFrame != nil { | |
490 | fr.lastFrame.invalidate() | |
491 | } | |
492 | fh, err := readFrameHeader(fr.headerBuf[:], fr.r) | |
493 | if err != nil { | |
494 | return nil, err | |
495 | } | |
496 | if fh.Length > fr.maxReadSize { | |
497 | return nil, ErrFrameTooLarge | |
498 | } | |
499 | payload := fr.getReadBuf(fh.Length) | |
500 | if _, err := io.ReadFull(fr.r, payload); err != nil { | |
501 | return nil, err | |
502 | } | |
503 | f, err := typeFrameParser(fh.Type)(fr.frameCache, fh, payload) | |
504 | if err != nil { | |
505 | if ce, ok := err.(connError); ok { | |
506 | return nil, fr.connError(ce.Code, ce.Reason) | |
507 | } | |
508 | return nil, err | |
509 | } | |
510 | if err := fr.checkFrameOrder(f); err != nil { | |
511 | return nil, err | |
512 | } | |
513 | if fr.logReads { | |
514 | fr.debugReadLoggerf("http2: Framer %p: read %v", fr, summarizeFrame(f)) | |
515 | } | |
516 | if fh.Type == FrameHeaders && fr.ReadMetaHeaders != nil { | |
517 | return fr.readMetaFrame(f.(*HeadersFrame)) | |
518 | } | |
519 | return f, nil | |
520 | } | |
521 | ||
522 | // connError returns ConnectionError(code) but first | |
523 | // stashes away a public reason to the caller can optionally relay it | |
524 | // to the peer before hanging up on them. This might help others debug | |
525 | // their implementations. | |
526 | func (fr *Framer) connError(code ErrCode, reason string) error { | |
527 | fr.errDetail = errors.New(reason) | |
528 | return ConnectionError(code) | |
529 | } | |
530 | ||
531 | // checkFrameOrder reports an error if f is an invalid frame to return | |
532 | // next from ReadFrame. Mostly it checks whether HEADERS and | |
533 | // CONTINUATION frames are contiguous. | |
534 | func (fr *Framer) checkFrameOrder(f Frame) error { | |
535 | last := fr.lastFrame | |
536 | fr.lastFrame = f | |
537 | if fr.AllowIllegalReads { | |
538 | return nil | |
539 | } | |
540 | ||
541 | fh := f.Header() | |
542 | if fr.lastHeaderStream != 0 { | |
543 | if fh.Type != FrameContinuation { | |
544 | return fr.connError(ErrCodeProtocol, | |
545 | fmt.Sprintf("got %s for stream %d; expected CONTINUATION following %s for stream %d", | |
546 | fh.Type, fh.StreamID, | |
547 | last.Header().Type, fr.lastHeaderStream)) | |
548 | } | |
549 | if fh.StreamID != fr.lastHeaderStream { | |
550 | return fr.connError(ErrCodeProtocol, | |
551 | fmt.Sprintf("got CONTINUATION for stream %d; expected stream %d", | |
552 | fh.StreamID, fr.lastHeaderStream)) | |
553 | } | |
554 | } else if fh.Type == FrameContinuation { | |
555 | return fr.connError(ErrCodeProtocol, fmt.Sprintf("unexpected CONTINUATION for stream %d", fh.StreamID)) | |
556 | } | |
557 | ||
558 | switch fh.Type { | |
559 | case FrameHeaders, FrameContinuation: | |
560 | if fh.Flags.Has(FlagHeadersEndHeaders) { | |
561 | fr.lastHeaderStream = 0 | |
562 | } else { | |
563 | fr.lastHeaderStream = fh.StreamID | |
564 | } | |
565 | } | |
566 | ||
567 | return nil | |
568 | } | |
569 | ||
570 | // A DataFrame conveys arbitrary, variable-length sequences of octets | |
571 | // associated with a stream. | |
572 | // See http://http2.github.io/http2-spec/#rfc.section.6.1 | |
573 | type DataFrame struct { | |
574 | FrameHeader | |
575 | data []byte | |
576 | } | |
577 | ||
578 | func (f *DataFrame) StreamEnded() bool { | |
579 | return f.FrameHeader.Flags.Has(FlagDataEndStream) | |
580 | } | |
581 | ||
582 | // Data returns the frame's data octets, not including any padding | |
583 | // size byte or padding suffix bytes. | |
584 | // The caller must not retain the returned memory past the next | |
585 | // call to ReadFrame. | |
586 | func (f *DataFrame) Data() []byte { | |
587 | f.checkValid() | |
588 | return f.data | |
589 | } | |
590 | ||
591 | func parseDataFrame(fc *frameCache, fh FrameHeader, payload []byte) (Frame, error) { | |
592 | if fh.StreamID == 0 { | |
593 | // DATA frames MUST be associated with a stream. If a | |
594 | // DATA frame is received whose stream identifier | |
595 | // field is 0x0, the recipient MUST respond with a | |
596 | // connection error (Section 5.4.1) of type | |
597 | // PROTOCOL_ERROR. | |
598 | return nil, connError{ErrCodeProtocol, "DATA frame with stream ID 0"} | |
599 | } | |
600 | f := fc.getDataFrame() | |
601 | f.FrameHeader = fh | |
602 | ||
603 | var padSize byte | |
604 | if fh.Flags.Has(FlagDataPadded) { | |
605 | var err error | |
606 | payload, padSize, err = readByte(payload) | |
607 | if err != nil { | |
608 | return nil, err | |
609 | } | |
610 | } | |
611 | if int(padSize) > len(payload) { | |
612 | // If the length of the padding is greater than the | |
613 | // length of the frame payload, the recipient MUST | |
614 | // treat this as a connection error. | |
615 | // Filed: https://github.com/http2/http2-spec/issues/610 | |
616 | return nil, connError{ErrCodeProtocol, "pad size larger than data payload"} | |
617 | } | |
618 | f.data = payload[:len(payload)-int(padSize)] | |
619 | return f, nil | |
620 | } | |
621 | ||
622 | var ( | |
623 | errStreamID = errors.New("invalid stream ID") | |
624 | errDepStreamID = errors.New("invalid dependent stream ID") | |
625 | errPadLength = errors.New("pad length too large") | |
626 | errPadBytes = errors.New("padding bytes must all be zeros unless AllowIllegalWrites is enabled") | |
627 | ) | |
628 | ||
629 | func validStreamIDOrZero(streamID uint32) bool { | |
630 | return streamID&(1<<31) == 0 | |
631 | } | |
632 | ||
633 | func validStreamID(streamID uint32) bool { | |
634 | return streamID != 0 && streamID&(1<<31) == 0 | |
635 | } | |
636 | ||
637 | // WriteData writes a DATA frame. | |
638 | // | |
639 | // It will perform exactly one Write to the underlying Writer. | |
640 | // It is the caller's responsibility not to violate the maximum frame size | |
641 | // and to not call other Write methods concurrently. | |
642 | func (f *Framer) WriteData(streamID uint32, endStream bool, data []byte) error { | |
643 | return f.WriteDataPadded(streamID, endStream, data, nil) | |
644 | } | |
645 | ||
646 | // WriteData writes a DATA frame with optional padding. | |
647 | // | |
648 | // If pad is nil, the padding bit is not sent. | |
649 | // The length of pad must not exceed 255 bytes. | |
650 | // The bytes of pad must all be zero, unless f.AllowIllegalWrites is set. | |
651 | // | |
652 | // It will perform exactly one Write to the underlying Writer. | |
653 | // It is the caller's responsibility not to violate the maximum frame size | |
654 | // and to not call other Write methods concurrently. | |
655 | func (f *Framer) WriteDataPadded(streamID uint32, endStream bool, data, pad []byte) error { | |
656 | if !validStreamID(streamID) && !f.AllowIllegalWrites { | |
657 | return errStreamID | |
658 | } | |
659 | if len(pad) > 0 { | |
660 | if len(pad) > 255 { | |
661 | return errPadLength | |
662 | } | |
663 | if !f.AllowIllegalWrites { | |
664 | for _, b := range pad { | |
665 | if b != 0 { | |
666 | // "Padding octets MUST be set to zero when sending." | |
667 | return errPadBytes | |
668 | } | |
669 | } | |
670 | } | |
671 | } | |
672 | var flags Flags | |
673 | if endStream { | |
674 | flags |= FlagDataEndStream | |
675 | } | |
676 | if pad != nil { | |
677 | flags |= FlagDataPadded | |
678 | } | |
679 | f.startWrite(FrameData, flags, streamID) | |
680 | if pad != nil { | |
681 | f.wbuf = append(f.wbuf, byte(len(pad))) | |
682 | } | |
683 | f.wbuf = append(f.wbuf, data...) | |
684 | f.wbuf = append(f.wbuf, pad...) | |
685 | return f.endWrite() | |
686 | } | |
687 | ||
688 | // A SettingsFrame conveys configuration parameters that affect how | |
689 | // endpoints communicate, such as preferences and constraints on peer | |
690 | // behavior. | |
691 | // | |
692 | // See http://http2.github.io/http2-spec/#SETTINGS | |
693 | type SettingsFrame struct { | |
694 | FrameHeader | |
695 | p []byte | |
696 | } | |
697 | ||
698 | func parseSettingsFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) { | |
699 | if fh.Flags.Has(FlagSettingsAck) && fh.Length > 0 { | |
700 | // When this (ACK 0x1) bit is set, the payload of the | |
701 | // SETTINGS frame MUST be empty. Receipt of a | |
702 | // SETTINGS frame with the ACK flag set and a length | |
703 | // field value other than 0 MUST be treated as a | |
704 | // connection error (Section 5.4.1) of type | |
705 | // FRAME_SIZE_ERROR. | |
706 | return nil, ConnectionError(ErrCodeFrameSize) | |
707 | } | |
708 | if fh.StreamID != 0 { | |
709 | // SETTINGS frames always apply to a connection, | |
710 | // never a single stream. The stream identifier for a | |
711 | // SETTINGS frame MUST be zero (0x0). If an endpoint | |
712 | // receives a SETTINGS frame whose stream identifier | |
713 | // field is anything other than 0x0, the endpoint MUST | |
714 | // respond with a connection error (Section 5.4.1) of | |
715 | // type PROTOCOL_ERROR. | |
716 | return nil, ConnectionError(ErrCodeProtocol) | |
717 | } | |
718 | if len(p)%6 != 0 { | |
719 | // Expecting even number of 6 byte settings. | |
720 | return nil, ConnectionError(ErrCodeFrameSize) | |
721 | } | |
722 | f := &SettingsFrame{FrameHeader: fh, p: p} | |
723 | if v, ok := f.Value(SettingInitialWindowSize); ok && v > (1<<31)-1 { | |
724 | // Values above the maximum flow control window size of 2^31 - 1 MUST | |
725 | // be treated as a connection error (Section 5.4.1) of type | |
726 | // FLOW_CONTROL_ERROR. | |
727 | return nil, ConnectionError(ErrCodeFlowControl) | |
728 | } | |
729 | return f, nil | |
730 | } | |
731 | ||
732 | func (f *SettingsFrame) IsAck() bool { | |
733 | return f.FrameHeader.Flags.Has(FlagSettingsAck) | |
734 | } | |
735 | ||
736 | func (f *SettingsFrame) Value(s SettingID) (v uint32, ok bool) { | |
737 | f.checkValid() | |
738 | buf := f.p | |
739 | for len(buf) > 0 { | |
740 | settingID := SettingID(binary.BigEndian.Uint16(buf[:2])) | |
741 | if settingID == s { | |
742 | return binary.BigEndian.Uint32(buf[2:6]), true | |
743 | } | |
744 | buf = buf[6:] | |
745 | } | |
746 | return 0, false | |
747 | } | |
748 | ||
749 | // ForeachSetting runs fn for each setting. | |
750 | // It stops and returns the first error. | |
751 | func (f *SettingsFrame) ForeachSetting(fn func(Setting) error) error { | |
752 | f.checkValid() | |
753 | buf := f.p | |
754 | for len(buf) > 0 { | |
755 | if err := fn(Setting{ | |
756 | SettingID(binary.BigEndian.Uint16(buf[:2])), | |
757 | binary.BigEndian.Uint32(buf[2:6]), | |
758 | }); err != nil { | |
759 | return err | |
760 | } | |
761 | buf = buf[6:] | |
762 | } | |
763 | return nil | |
764 | } | |
765 | ||
766 | // WriteSettings writes a SETTINGS frame with zero or more settings | |
767 | // specified and the ACK bit not set. | |
768 | // | |
769 | // It will perform exactly one Write to the underlying Writer. | |
770 | // It is the caller's responsibility to not call other Write methods concurrently. | |
771 | func (f *Framer) WriteSettings(settings ...Setting) error { | |
772 | f.startWrite(FrameSettings, 0, 0) | |
773 | for _, s := range settings { | |
774 | f.writeUint16(uint16(s.ID)) | |
775 | f.writeUint32(s.Val) | |
776 | } | |
777 | return f.endWrite() | |
778 | } | |
779 | ||
780 | // WriteSettingsAck writes an empty SETTINGS frame with the ACK bit set. | |
781 | // | |
782 | // It will perform exactly one Write to the underlying Writer. | |
783 | // It is the caller's responsibility to not call other Write methods concurrently. | |
784 | func (f *Framer) WriteSettingsAck() error { | |
785 | f.startWrite(FrameSettings, FlagSettingsAck, 0) | |
786 | return f.endWrite() | |
787 | } | |
788 | ||
789 | // A PingFrame is a mechanism for measuring a minimal round trip time | |
790 | // from the sender, as well as determining whether an idle connection | |
791 | // is still functional. | |
792 | // See http://http2.github.io/http2-spec/#rfc.section.6.7 | |
793 | type PingFrame struct { | |
794 | FrameHeader | |
795 | Data [8]byte | |
796 | } | |
797 | ||
798 | func (f *PingFrame) IsAck() bool { return f.Flags.Has(FlagPingAck) } | |
799 | ||
800 | func parsePingFrame(_ *frameCache, fh FrameHeader, payload []byte) (Frame, error) { | |
801 | if len(payload) != 8 { | |
802 | return nil, ConnectionError(ErrCodeFrameSize) | |
803 | } | |
804 | if fh.StreamID != 0 { | |
805 | return nil, ConnectionError(ErrCodeProtocol) | |
806 | } | |
807 | f := &PingFrame{FrameHeader: fh} | |
808 | copy(f.Data[:], payload) | |
809 | return f, nil | |
810 | } | |
811 | ||
812 | func (f *Framer) WritePing(ack bool, data [8]byte) error { | |
813 | var flags Flags | |
814 | if ack { | |
815 | flags = FlagPingAck | |
816 | } | |
817 | f.startWrite(FramePing, flags, 0) | |
818 | f.writeBytes(data[:]) | |
819 | return f.endWrite() | |
820 | } | |
821 | ||
822 | // A GoAwayFrame informs the remote peer to stop creating streams on this connection. | |
823 | // See http://http2.github.io/http2-spec/#rfc.section.6.8 | |
824 | type GoAwayFrame struct { | |
825 | FrameHeader | |
826 | LastStreamID uint32 | |
827 | ErrCode ErrCode | |
828 | debugData []byte | |
829 | } | |
830 | ||
831 | // DebugData returns any debug data in the GOAWAY frame. Its contents | |
832 | // are not defined. | |
833 | // The caller must not retain the returned memory past the next | |
834 | // call to ReadFrame. | |
835 | func (f *GoAwayFrame) DebugData() []byte { | |
836 | f.checkValid() | |
837 | return f.debugData | |
838 | } | |
839 | ||
840 | func parseGoAwayFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) { | |
841 | if fh.StreamID != 0 { | |
842 | return nil, ConnectionError(ErrCodeProtocol) | |
843 | } | |
844 | if len(p) < 8 { | |
845 | return nil, ConnectionError(ErrCodeFrameSize) | |
846 | } | |
847 | return &GoAwayFrame{ | |
848 | FrameHeader: fh, | |
849 | LastStreamID: binary.BigEndian.Uint32(p[:4]) & (1<<31 - 1), | |
850 | ErrCode: ErrCode(binary.BigEndian.Uint32(p[4:8])), | |
851 | debugData: p[8:], | |
852 | }, nil | |
853 | } | |
854 | ||
855 | func (f *Framer) WriteGoAway(maxStreamID uint32, code ErrCode, debugData []byte) error { | |
856 | f.startWrite(FrameGoAway, 0, 0) | |
857 | f.writeUint32(maxStreamID & (1<<31 - 1)) | |
858 | f.writeUint32(uint32(code)) | |
859 | f.writeBytes(debugData) | |
860 | return f.endWrite() | |
861 | } | |
862 | ||
863 | // An UnknownFrame is the frame type returned when the frame type is unknown | |
864 | // or no specific frame type parser exists. | |
865 | type UnknownFrame struct { | |
866 | FrameHeader | |
867 | p []byte | |
868 | } | |
869 | ||
870 | // Payload returns the frame's payload (after the header). It is not | |
871 | // valid to call this method after a subsequent call to | |
872 | // Framer.ReadFrame, nor is it valid to retain the returned slice. | |
873 | // The memory is owned by the Framer and is invalidated when the next | |
874 | // frame is read. | |
875 | func (f *UnknownFrame) Payload() []byte { | |
876 | f.checkValid() | |
877 | return f.p | |
878 | } | |
879 | ||
880 | func parseUnknownFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) { | |
881 | return &UnknownFrame{fh, p}, nil | |
882 | } | |
883 | ||
884 | // A WindowUpdateFrame is used to implement flow control. | |
885 | // See http://http2.github.io/http2-spec/#rfc.section.6.9 | |
886 | type WindowUpdateFrame struct { | |
887 | FrameHeader | |
888 | Increment uint32 // never read with high bit set | |
889 | } | |
890 | ||
891 | func parseWindowUpdateFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) { | |
892 | if len(p) != 4 { | |
893 | return nil, ConnectionError(ErrCodeFrameSize) | |
894 | } | |
895 | inc := binary.BigEndian.Uint32(p[:4]) & 0x7fffffff // mask off high reserved bit | |
896 | if inc == 0 { | |
897 | // A receiver MUST treat the receipt of a | |
898 | // WINDOW_UPDATE frame with an flow control window | |
899 | // increment of 0 as a stream error (Section 5.4.2) of | |
900 | // type PROTOCOL_ERROR; errors on the connection flow | |
901 | // control window MUST be treated as a connection | |
902 | // error (Section 5.4.1). | |
903 | if fh.StreamID == 0 { | |
904 | return nil, ConnectionError(ErrCodeProtocol) | |
905 | } | |
906 | return nil, streamError(fh.StreamID, ErrCodeProtocol) | |
907 | } | |
908 | return &WindowUpdateFrame{ | |
909 | FrameHeader: fh, | |
910 | Increment: inc, | |
911 | }, nil | |
912 | } | |
913 | ||
914 | // WriteWindowUpdate writes a WINDOW_UPDATE frame. | |
915 | // The increment value must be between 1 and 2,147,483,647, inclusive. | |
916 | // If the Stream ID is zero, the window update applies to the | |
917 | // connection as a whole. | |
918 | func (f *Framer) WriteWindowUpdate(streamID, incr uint32) error { | |
919 | // "The legal range for the increment to the flow control window is 1 to 2^31-1 (2,147,483,647) octets." | |
920 | if (incr < 1 || incr > 2147483647) && !f.AllowIllegalWrites { | |
921 | return errors.New("illegal window increment value") | |
922 | } | |
923 | f.startWrite(FrameWindowUpdate, 0, streamID) | |
924 | f.writeUint32(incr) | |
925 | return f.endWrite() | |
926 | } | |
927 | ||
928 | // A HeadersFrame is used to open a stream and additionally carries a | |
929 | // header block fragment. | |
930 | type HeadersFrame struct { | |
931 | FrameHeader | |
932 | ||
933 | // Priority is set if FlagHeadersPriority is set in the FrameHeader. | |
934 | Priority PriorityParam | |
935 | ||
936 | headerFragBuf []byte // not owned | |
937 | } | |
938 | ||
939 | func (f *HeadersFrame) HeaderBlockFragment() []byte { | |
940 | f.checkValid() | |
941 | return f.headerFragBuf | |
942 | } | |
943 | ||
944 | func (f *HeadersFrame) HeadersEnded() bool { | |
945 | return f.FrameHeader.Flags.Has(FlagHeadersEndHeaders) | |
946 | } | |
947 | ||
948 | func (f *HeadersFrame) StreamEnded() bool { | |
949 | return f.FrameHeader.Flags.Has(FlagHeadersEndStream) | |
950 | } | |
951 | ||
952 | func (f *HeadersFrame) HasPriority() bool { | |
953 | return f.FrameHeader.Flags.Has(FlagHeadersPriority) | |
954 | } | |
955 | ||
956 | func parseHeadersFrame(_ *frameCache, fh FrameHeader, p []byte) (_ Frame, err error) { | |
957 | hf := &HeadersFrame{ | |
958 | FrameHeader: fh, | |
959 | } | |
960 | if fh.StreamID == 0 { | |
961 | // HEADERS frames MUST be associated with a stream. If a HEADERS frame | |
962 | // is received whose stream identifier field is 0x0, the recipient MUST | |
963 | // respond with a connection error (Section 5.4.1) of type | |
964 | // PROTOCOL_ERROR. | |
965 | return nil, connError{ErrCodeProtocol, "HEADERS frame with stream ID 0"} | |
966 | } | |
967 | var padLength uint8 | |
968 | if fh.Flags.Has(FlagHeadersPadded) { | |
969 | if p, padLength, err = readByte(p); err != nil { | |
970 | return | |
971 | } | |
972 | } | |
973 | if fh.Flags.Has(FlagHeadersPriority) { | |
974 | var v uint32 | |
975 | p, v, err = readUint32(p) | |
976 | if err != nil { | |
977 | return nil, err | |
978 | } | |
979 | hf.Priority.StreamDep = v & 0x7fffffff | |
980 | hf.Priority.Exclusive = (v != hf.Priority.StreamDep) // high bit was set | |
981 | p, hf.Priority.Weight, err = readByte(p) | |
982 | if err != nil { | |
983 | return nil, err | |
984 | } | |
985 | } | |
986 | if len(p)-int(padLength) <= 0 { | |
987 | return nil, streamError(fh.StreamID, ErrCodeProtocol) | |
988 | } | |
989 | hf.headerFragBuf = p[:len(p)-int(padLength)] | |
990 | return hf, nil | |
991 | } | |
992 | ||
993 | // HeadersFrameParam are the parameters for writing a HEADERS frame. | |
994 | type HeadersFrameParam struct { | |
995 | // StreamID is the required Stream ID to initiate. | |
996 | StreamID uint32 | |
997 | // BlockFragment is part (or all) of a Header Block. | |
998 | BlockFragment []byte | |
999 | ||
1000 | // EndStream indicates that the header block is the last that | |
1001 | // the endpoint will send for the identified stream. Setting | |
1002 | // this flag causes the stream to enter one of "half closed" | |
1003 | // states. | |
1004 | EndStream bool | |
1005 | ||
1006 | // EndHeaders indicates that this frame contains an entire | |
1007 | // header block and is not followed by any | |
1008 | // CONTINUATION frames. | |
1009 | EndHeaders bool | |
1010 | ||
1011 | // PadLength is the optional number of bytes of zeros to add | |
1012 | // to this frame. | |
1013 | PadLength uint8 | |
1014 | ||
1015 | // Priority, if non-zero, includes stream priority information | |
1016 | // in the HEADER frame. | |
1017 | Priority PriorityParam | |
1018 | } | |
1019 | ||
1020 | // WriteHeaders writes a single HEADERS frame. | |
1021 | // | |
1022 | // This is a low-level header writing method. Encoding headers and | |
1023 | // splitting them into any necessary CONTINUATION frames is handled | |
1024 | // elsewhere. | |
1025 | // | |
1026 | // It will perform exactly one Write to the underlying Writer. | |
1027 | // It is the caller's responsibility to not call other Write methods concurrently. | |
1028 | func (f *Framer) WriteHeaders(p HeadersFrameParam) error { | |
1029 | if !validStreamID(p.StreamID) && !f.AllowIllegalWrites { | |
1030 | return errStreamID | |
1031 | } | |
1032 | var flags Flags | |
1033 | if p.PadLength != 0 { | |
1034 | flags |= FlagHeadersPadded | |
1035 | } | |
1036 | if p.EndStream { | |
1037 | flags |= FlagHeadersEndStream | |
1038 | } | |
1039 | if p.EndHeaders { | |
1040 | flags |= FlagHeadersEndHeaders | |
1041 | } | |
1042 | if !p.Priority.IsZero() { | |
1043 | flags |= FlagHeadersPriority | |
1044 | } | |
1045 | f.startWrite(FrameHeaders, flags, p.StreamID) | |
1046 | if p.PadLength != 0 { | |
1047 | f.writeByte(p.PadLength) | |
1048 | } | |
1049 | if !p.Priority.IsZero() { | |
1050 | v := p.Priority.StreamDep | |
1051 | if !validStreamIDOrZero(v) && !f.AllowIllegalWrites { | |
1052 | return errDepStreamID | |
1053 | } | |
1054 | if p.Priority.Exclusive { | |
1055 | v |= 1 << 31 | |
1056 | } | |
1057 | f.writeUint32(v) | |
1058 | f.writeByte(p.Priority.Weight) | |
1059 | } | |
1060 | f.wbuf = append(f.wbuf, p.BlockFragment...) | |
1061 | f.wbuf = append(f.wbuf, padZeros[:p.PadLength]...) | |
1062 | return f.endWrite() | |
1063 | } | |
1064 | ||
1065 | // A PriorityFrame specifies the sender-advised priority of a stream. | |
1066 | // See http://http2.github.io/http2-spec/#rfc.section.6.3 | |
1067 | type PriorityFrame struct { | |
1068 | FrameHeader | |
1069 | PriorityParam | |
1070 | } | |
1071 | ||
1072 | // PriorityParam are the stream prioritzation parameters. | |
1073 | type PriorityParam struct { | |
1074 | // StreamDep is a 31-bit stream identifier for the | |
1075 | // stream that this stream depends on. Zero means no | |
1076 | // dependency. | |
1077 | StreamDep uint32 | |
1078 | ||
1079 | // Exclusive is whether the dependency is exclusive. | |
1080 | Exclusive bool | |
1081 | ||
1082 | // Weight is the stream's zero-indexed weight. It should be | |
1083 | // set together with StreamDep, or neither should be set. Per | |
1084 | // the spec, "Add one to the value to obtain a weight between | |
1085 | // 1 and 256." | |
1086 | Weight uint8 | |
1087 | } | |
1088 | ||
1089 | func (p PriorityParam) IsZero() bool { | |
1090 | return p == PriorityParam{} | |
1091 | } | |
1092 | ||
1093 | func parsePriorityFrame(_ *frameCache, fh FrameHeader, payload []byte) (Frame, error) { | |
1094 | if fh.StreamID == 0 { | |
1095 | return nil, connError{ErrCodeProtocol, "PRIORITY frame with stream ID 0"} | |
1096 | } | |
1097 | if len(payload) != 5 { | |
1098 | return nil, connError{ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len(payload))} | |
1099 | } | |
1100 | v := binary.BigEndian.Uint32(payload[:4]) | |
1101 | streamID := v & 0x7fffffff // mask off high bit | |
1102 | return &PriorityFrame{ | |
1103 | FrameHeader: fh, | |
1104 | PriorityParam: PriorityParam{ | |
1105 | Weight: payload[4], | |
1106 | StreamDep: streamID, | |
1107 | Exclusive: streamID != v, // was high bit set? | |
1108 | }, | |
1109 | }, nil | |
1110 | } | |
1111 | ||
1112 | // WritePriority writes a PRIORITY frame. | |
1113 | // | |
1114 | // It will perform exactly one Write to the underlying Writer. | |
1115 | // It is the caller's responsibility to not call other Write methods concurrently. | |
1116 | func (f *Framer) WritePriority(streamID uint32, p PriorityParam) error { | |
1117 | if !validStreamID(streamID) && !f.AllowIllegalWrites { | |
1118 | return errStreamID | |
1119 | } | |
1120 | if !validStreamIDOrZero(p.StreamDep) { | |
1121 | return errDepStreamID | |
1122 | } | |
1123 | f.startWrite(FramePriority, 0, streamID) | |
1124 | v := p.StreamDep | |
1125 | if p.Exclusive { | |
1126 | v |= 1 << 31 | |
1127 | } | |
1128 | f.writeUint32(v) | |
1129 | f.writeByte(p.Weight) | |
1130 | return f.endWrite() | |
1131 | } | |
1132 | ||
1133 | // A RSTStreamFrame allows for abnormal termination of a stream. | |
1134 | // See http://http2.github.io/http2-spec/#rfc.section.6.4 | |
1135 | type RSTStreamFrame struct { | |
1136 | FrameHeader | |
1137 | ErrCode ErrCode | |
1138 | } | |
1139 | ||
1140 | func parseRSTStreamFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) { | |
1141 | if len(p) != 4 { | |
1142 | return nil, ConnectionError(ErrCodeFrameSize) | |
1143 | } | |
1144 | if fh.StreamID == 0 { | |
1145 | return nil, ConnectionError(ErrCodeProtocol) | |
1146 | } | |
1147 | return &RSTStreamFrame{fh, ErrCode(binary.BigEndian.Uint32(p[:4]))}, nil | |
1148 | } | |
1149 | ||
1150 | // WriteRSTStream writes a RST_STREAM frame. | |
1151 | // | |
1152 | // It will perform exactly one Write to the underlying Writer. | |
1153 | // It is the caller's responsibility to not call other Write methods concurrently. | |
1154 | func (f *Framer) WriteRSTStream(streamID uint32, code ErrCode) error { | |
1155 | if !validStreamID(streamID) && !f.AllowIllegalWrites { | |
1156 | return errStreamID | |
1157 | } | |
1158 | f.startWrite(FrameRSTStream, 0, streamID) | |
1159 | f.writeUint32(uint32(code)) | |
1160 | return f.endWrite() | |
1161 | } | |
1162 | ||
1163 | // A ContinuationFrame is used to continue a sequence of header block fragments. | |
1164 | // See http://http2.github.io/http2-spec/#rfc.section.6.10 | |
1165 | type ContinuationFrame struct { | |
1166 | FrameHeader | |
1167 | headerFragBuf []byte | |
1168 | } | |
1169 | ||
1170 | func parseContinuationFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) { | |
1171 | if fh.StreamID == 0 { | |
1172 | return nil, connError{ErrCodeProtocol, "CONTINUATION frame with stream ID 0"} | |
1173 | } | |
1174 | return &ContinuationFrame{fh, p}, nil | |
1175 | } | |
1176 | ||
1177 | func (f *ContinuationFrame) HeaderBlockFragment() []byte { | |
1178 | f.checkValid() | |
1179 | return f.headerFragBuf | |
1180 | } | |
1181 | ||
1182 | func (f *ContinuationFrame) HeadersEnded() bool { | |
1183 | return f.FrameHeader.Flags.Has(FlagContinuationEndHeaders) | |
1184 | } | |
1185 | ||
1186 | // WriteContinuation writes a CONTINUATION frame. | |
1187 | // | |
1188 | // It will perform exactly one Write to the underlying Writer. | |
1189 | // It is the caller's responsibility to not call other Write methods concurrently. | |
1190 | func (f *Framer) WriteContinuation(streamID uint32, endHeaders bool, headerBlockFragment []byte) error { | |
1191 | if !validStreamID(streamID) && !f.AllowIllegalWrites { | |
1192 | return errStreamID | |
1193 | } | |
1194 | var flags Flags | |
1195 | if endHeaders { | |
1196 | flags |= FlagContinuationEndHeaders | |
1197 | } | |
1198 | f.startWrite(FrameContinuation, flags, streamID) | |
1199 | f.wbuf = append(f.wbuf, headerBlockFragment...) | |
1200 | return f.endWrite() | |
1201 | } | |
1202 | ||
1203 | // A PushPromiseFrame is used to initiate a server stream. | |
1204 | // See http://http2.github.io/http2-spec/#rfc.section.6.6 | |
1205 | type PushPromiseFrame struct { | |
1206 | FrameHeader | |
1207 | PromiseID uint32 | |
1208 | headerFragBuf []byte // not owned | |
1209 | } | |
1210 | ||
1211 | func (f *PushPromiseFrame) HeaderBlockFragment() []byte { | |
1212 | f.checkValid() | |
1213 | return f.headerFragBuf | |
1214 | } | |
1215 | ||
1216 | func (f *PushPromiseFrame) HeadersEnded() bool { | |
1217 | return f.FrameHeader.Flags.Has(FlagPushPromiseEndHeaders) | |
1218 | } | |
1219 | ||
1220 | func parsePushPromise(_ *frameCache, fh FrameHeader, p []byte) (_ Frame, err error) { | |
1221 | pp := &PushPromiseFrame{ | |
1222 | FrameHeader: fh, | |
1223 | } | |
1224 | if pp.StreamID == 0 { | |
1225 | // PUSH_PROMISE frames MUST be associated with an existing, | |
1226 | // peer-initiated stream. The stream identifier of a | |
1227 | // PUSH_PROMISE frame indicates the stream it is associated | |
1228 | // with. If the stream identifier field specifies the value | |
1229 | // 0x0, a recipient MUST respond with a connection error | |
1230 | // (Section 5.4.1) of type PROTOCOL_ERROR. | |
1231 | return nil, ConnectionError(ErrCodeProtocol) | |
1232 | } | |
1233 | // The PUSH_PROMISE frame includes optional padding. | |
1234 | // Padding fields and flags are identical to those defined for DATA frames | |
1235 | var padLength uint8 | |
1236 | if fh.Flags.Has(FlagPushPromisePadded) { | |
1237 | if p, padLength, err = readByte(p); err != nil { | |
1238 | return | |
1239 | } | |
1240 | } | |
1241 | ||
1242 | p, pp.PromiseID, err = readUint32(p) | |
1243 | if err != nil { | |
1244 | return | |
1245 | } | |
1246 | pp.PromiseID = pp.PromiseID & (1<<31 - 1) | |
1247 | ||
1248 | if int(padLength) > len(p) { | |
1249 | // like the DATA frame, error out if padding is longer than the body. | |
1250 | return nil, ConnectionError(ErrCodeProtocol) | |
1251 | } | |
1252 | pp.headerFragBuf = p[:len(p)-int(padLength)] | |
1253 | return pp, nil | |
1254 | } | |
1255 | ||
1256 | // PushPromiseParam are the parameters for writing a PUSH_PROMISE frame. | |
1257 | type PushPromiseParam struct { | |
1258 | // StreamID is the required Stream ID to initiate. | |
1259 | StreamID uint32 | |
1260 | ||
1261 | // PromiseID is the required Stream ID which this | |
1262 | // Push Promises | |
1263 | PromiseID uint32 | |
1264 | ||
1265 | // BlockFragment is part (or all) of a Header Block. | |
1266 | BlockFragment []byte | |
1267 | ||
1268 | // EndHeaders indicates that this frame contains an entire | |
1269 | // header block and is not followed by any | |
1270 | // CONTINUATION frames. | |
1271 | EndHeaders bool | |
1272 | ||
1273 | // PadLength is the optional number of bytes of zeros to add | |
1274 | // to this frame. | |
1275 | PadLength uint8 | |
1276 | } | |
1277 | ||
1278 | // WritePushPromise writes a single PushPromise Frame. | |
1279 | // | |
1280 | // As with Header Frames, This is the low level call for writing | |
1281 | // individual frames. Continuation frames are handled elsewhere. | |
1282 | // | |
1283 | // It will perform exactly one Write to the underlying Writer. | |
1284 | // It is the caller's responsibility to not call other Write methods concurrently. | |
1285 | func (f *Framer) WritePushPromise(p PushPromiseParam) error { | |
1286 | if !validStreamID(p.StreamID) && !f.AllowIllegalWrites { | |
1287 | return errStreamID | |
1288 | } | |
1289 | var flags Flags | |
1290 | if p.PadLength != 0 { | |
1291 | flags |= FlagPushPromisePadded | |
1292 | } | |
1293 | if p.EndHeaders { | |
1294 | flags |= FlagPushPromiseEndHeaders | |
1295 | } | |
1296 | f.startWrite(FramePushPromise, flags, p.StreamID) | |
1297 | if p.PadLength != 0 { | |
1298 | f.writeByte(p.PadLength) | |
1299 | } | |
1300 | if !validStreamID(p.PromiseID) && !f.AllowIllegalWrites { | |
1301 | return errStreamID | |
1302 | } | |
1303 | f.writeUint32(p.PromiseID) | |
1304 | f.wbuf = append(f.wbuf, p.BlockFragment...) | |
1305 | f.wbuf = append(f.wbuf, padZeros[:p.PadLength]...) | |
1306 | return f.endWrite() | |
1307 | } | |
1308 | ||
1309 | // WriteRawFrame writes a raw frame. This can be used to write | |
1310 | // extension frames unknown to this package. | |
1311 | func (f *Framer) WriteRawFrame(t FrameType, flags Flags, streamID uint32, payload []byte) error { | |
1312 | f.startWrite(t, flags, streamID) | |
1313 | f.writeBytes(payload) | |
1314 | return f.endWrite() | |
1315 | } | |
1316 | ||
1317 | func readByte(p []byte) (remain []byte, b byte, err error) { | |
1318 | if len(p) == 0 { | |
1319 | return nil, 0, io.ErrUnexpectedEOF | |
1320 | } | |
1321 | return p[1:], p[0], nil | |
1322 | } | |
1323 | ||
1324 | func readUint32(p []byte) (remain []byte, v uint32, err error) { | |
1325 | if len(p) < 4 { | |
1326 | return nil, 0, io.ErrUnexpectedEOF | |
1327 | } | |
1328 | return p[4:], binary.BigEndian.Uint32(p[:4]), nil | |
1329 | } | |
1330 | ||
1331 | type streamEnder interface { | |
1332 | StreamEnded() bool | |
1333 | } | |
1334 | ||
1335 | type headersEnder interface { | |
1336 | HeadersEnded() bool | |
1337 | } | |
1338 | ||
1339 | type headersOrContinuation interface { | |
1340 | headersEnder | |
1341 | HeaderBlockFragment() []byte | |
1342 | } | |
1343 | ||
1344 | // A MetaHeadersFrame is the representation of one HEADERS frame and | |
1345 | // zero or more contiguous CONTINUATION frames and the decoding of | |
1346 | // their HPACK-encoded contents. | |
1347 | // | |
1348 | // This type of frame does not appear on the wire and is only returned | |
1349 | // by the Framer when Framer.ReadMetaHeaders is set. | |
1350 | type MetaHeadersFrame struct { | |
1351 | *HeadersFrame | |
1352 | ||
1353 | // Fields are the fields contained in the HEADERS and | |
1354 | // CONTINUATION frames. The underlying slice is owned by the | |
1355 | // Framer and must not be retained after the next call to | |
1356 | // ReadFrame. | |
1357 | // | |
1358 | // Fields are guaranteed to be in the correct http2 order and | |
1359 | // not have unknown pseudo header fields or invalid header | |
1360 | // field names or values. Required pseudo header fields may be | |
1361 | // missing, however. Use the MetaHeadersFrame.Pseudo accessor | |
1362 | // method access pseudo headers. | |
1363 | Fields []hpack.HeaderField | |
1364 | ||
1365 | // Truncated is whether the max header list size limit was hit | |
1366 | // and Fields is incomplete. The hpack decoder state is still | |
1367 | // valid, however. | |
1368 | Truncated bool | |
1369 | } | |
1370 | ||
1371 | // PseudoValue returns the given pseudo header field's value. | |
1372 | // The provided pseudo field should not contain the leading colon. | |
1373 | func (mh *MetaHeadersFrame) PseudoValue(pseudo string) string { | |
1374 | for _, hf := range mh.Fields { | |
1375 | if !hf.IsPseudo() { | |
1376 | return "" | |
1377 | } | |
1378 | if hf.Name[1:] == pseudo { | |
1379 | return hf.Value | |
1380 | } | |
1381 | } | |
1382 | return "" | |
1383 | } | |
1384 | ||
1385 | // RegularFields returns the regular (non-pseudo) header fields of mh. | |
1386 | // The caller does not own the returned slice. | |
1387 | func (mh *MetaHeadersFrame) RegularFields() []hpack.HeaderField { | |
1388 | for i, hf := range mh.Fields { | |
1389 | if !hf.IsPseudo() { | |
1390 | return mh.Fields[i:] | |
1391 | } | |
1392 | } | |
1393 | return nil | |
1394 | } | |
1395 | ||
1396 | // PseudoFields returns the pseudo header fields of mh. | |
1397 | // The caller does not own the returned slice. | |
1398 | func (mh *MetaHeadersFrame) PseudoFields() []hpack.HeaderField { | |
1399 | for i, hf := range mh.Fields { | |
1400 | if !hf.IsPseudo() { | |
1401 | return mh.Fields[:i] | |
1402 | } | |
1403 | } | |
1404 | return mh.Fields | |
1405 | } | |
1406 | ||
1407 | func (mh *MetaHeadersFrame) checkPseudos() error { | |
1408 | var isRequest, isResponse bool | |
1409 | pf := mh.PseudoFields() | |
1410 | for i, hf := range pf { | |
1411 | switch hf.Name { | |
1412 | case ":method", ":path", ":scheme", ":authority": | |
1413 | isRequest = true | |
1414 | case ":status": | |
1415 | isResponse = true | |
1416 | default: | |
1417 | return pseudoHeaderError(hf.Name) | |
1418 | } | |
1419 | // Check for duplicates. | |
1420 | // This would be a bad algorithm, but N is 4. | |
1421 | // And this doesn't allocate. | |
1422 | for _, hf2 := range pf[:i] { | |
1423 | if hf.Name == hf2.Name { | |
1424 | return duplicatePseudoHeaderError(hf.Name) | |
1425 | } | |
1426 | } | |
1427 | } | |
1428 | if isRequest && isResponse { | |
1429 | return errMixPseudoHeaderTypes | |
1430 | } | |
1431 | return nil | |
1432 | } | |
1433 | ||
1434 | func (fr *Framer) maxHeaderStringLen() int { | |
1435 | v := fr.maxHeaderListSize() | |
1436 | if uint32(int(v)) == v { | |
1437 | return int(v) | |
1438 | } | |
1439 | // They had a crazy big number for MaxHeaderBytes anyway, | |
1440 | // so give them unlimited header lengths: | |
1441 | return 0 | |
1442 | } | |
1443 | ||
1444 | // readMetaFrame returns 0 or more CONTINUATION frames from fr and | |
1445 | // merge them into into the provided hf and returns a MetaHeadersFrame | |
1446 | // with the decoded hpack values. | |
1447 | func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) { | |
1448 | if fr.AllowIllegalReads { | |
1449 | return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders") | |
1450 | } | |
1451 | mh := &MetaHeadersFrame{ | |
1452 | HeadersFrame: hf, | |
1453 | } | |
1454 | var remainSize = fr.maxHeaderListSize() | |
1455 | var sawRegular bool | |
1456 | ||
1457 | var invalid error // pseudo header field errors | |
1458 | hdec := fr.ReadMetaHeaders | |
1459 | hdec.SetEmitEnabled(true) | |
1460 | hdec.SetMaxStringLength(fr.maxHeaderStringLen()) | |
1461 | hdec.SetEmitFunc(func(hf hpack.HeaderField) { | |
1462 | if VerboseLogs && fr.logReads { | |
1463 | fr.debugReadLoggerf("http2: decoded hpack field %+v", hf) | |
1464 | } | |
1465 | if !httplex.ValidHeaderFieldValue(hf.Value) { | |
1466 | invalid = headerFieldValueError(hf.Value) | |
1467 | } | |
1468 | isPseudo := strings.HasPrefix(hf.Name, ":") | |
1469 | if isPseudo { | |
1470 | if sawRegular { | |
1471 | invalid = errPseudoAfterRegular | |
1472 | } | |
1473 | } else { | |
1474 | sawRegular = true | |
1475 | if !validWireHeaderFieldName(hf.Name) { | |
1476 | invalid = headerFieldNameError(hf.Name) | |
1477 | } | |
1478 | } | |
1479 | ||
1480 | if invalid != nil { | |
1481 | hdec.SetEmitEnabled(false) | |
1482 | return | |
1483 | } | |
1484 | ||
1485 | size := hf.Size() | |
1486 | if size > remainSize { | |
1487 | hdec.SetEmitEnabled(false) | |
1488 | mh.Truncated = true | |
1489 | return | |
1490 | } | |
1491 | remainSize -= size | |
1492 | ||
1493 | mh.Fields = append(mh.Fields, hf) | |
1494 | }) | |
1495 | // Lose reference to MetaHeadersFrame: | |
1496 | defer hdec.SetEmitFunc(func(hf hpack.HeaderField) {}) | |
1497 | ||
1498 | var hc headersOrContinuation = hf | |
1499 | for { | |
1500 | frag := hc.HeaderBlockFragment() | |
1501 | if _, err := hdec.Write(frag); err != nil { | |
1502 | return nil, ConnectionError(ErrCodeCompression) | |
1503 | } | |
1504 | ||
1505 | if hc.HeadersEnded() { | |
1506 | break | |
1507 | } | |
1508 | if f, err := fr.ReadFrame(); err != nil { | |
1509 | return nil, err | |
1510 | } else { | |
1511 | hc = f.(*ContinuationFrame) // guaranteed by checkFrameOrder | |
1512 | } | |
1513 | } | |
1514 | ||
1515 | mh.HeadersFrame.headerFragBuf = nil | |
1516 | mh.HeadersFrame.invalidate() | |
1517 | ||
1518 | if err := hdec.Close(); err != nil { | |
1519 | return nil, ConnectionError(ErrCodeCompression) | |
1520 | } | |
1521 | if invalid != nil { | |
1522 | fr.errDetail = invalid | |
1523 | if VerboseLogs { | |
1524 | log.Printf("http2: invalid header: %v", invalid) | |
1525 | } | |
1526 | return nil, StreamError{mh.StreamID, ErrCodeProtocol, invalid} | |
1527 | } | |
1528 | if err := mh.checkPseudos(); err != nil { | |
1529 | fr.errDetail = err | |
1530 | if VerboseLogs { | |
1531 | log.Printf("http2: invalid pseudo headers: %v", err) | |
1532 | } | |
1533 | return nil, StreamError{mh.StreamID, ErrCodeProtocol, err} | |
1534 | } | |
1535 | return mh, nil | |
1536 | } | |
1537 | ||
1538 | func summarizeFrame(f Frame) string { | |
1539 | var buf bytes.Buffer | |
1540 | f.Header().writeDebug(&buf) | |
1541 | switch f := f.(type) { | |
1542 | case *SettingsFrame: | |
1543 | n := 0 | |
1544 | f.ForeachSetting(func(s Setting) error { | |
1545 | n++ | |
1546 | if n == 1 { | |
1547 | buf.WriteString(", settings:") | |
1548 | } | |
1549 | fmt.Fprintf(&buf, " %v=%v,", s.ID, s.Val) | |
1550 | return nil | |
1551 | }) | |
1552 | if n > 0 { | |
1553 | buf.Truncate(buf.Len() - 1) // remove trailing comma | |
1554 | } | |
1555 | case *DataFrame: | |
1556 | data := f.Data() | |
1557 | const max = 256 | |
1558 | if len(data) > max { | |
1559 | data = data[:max] | |
1560 | } | |
1561 | fmt.Fprintf(&buf, " data=%q", data) | |
1562 | if len(f.Data()) > max { | |
1563 | fmt.Fprintf(&buf, " (%d bytes omitted)", len(f.Data())-max) | |
1564 | } | |
1565 | case *WindowUpdateFrame: | |
1566 | if f.StreamID == 0 { | |
1567 | buf.WriteString(" (conn)") | |
1568 | } | |
1569 | fmt.Fprintf(&buf, " incr=%v", f.Increment) | |
1570 | case *PingFrame: | |
1571 | fmt.Fprintf(&buf, " ping=%q", f.Data[:]) | |
1572 | case *GoAwayFrame: | |
1573 | fmt.Fprintf(&buf, " LastStreamID=%v ErrCode=%v Debug=%q", | |
1574 | f.LastStreamID, f.ErrCode, f.debugData) | |
1575 | case *RSTStreamFrame: | |
1576 | fmt.Fprintf(&buf, " ErrCode=%v", f.ErrCode) | |
1577 | } | |
1578 | return buf.String() | |
1579 | } |