blob: 78fe4201f627c75fa985c434302d087ae28cf3db [file] [log] [blame]
Carl Mastrangelo4aca7962015-10-05 16:17:47 -07001package http2interop
2
3import (
4 "encoding/binary"
5 "fmt"
6 "io"
7)
8
9type FrameHeader struct {
10 Length int
11 Type FrameType
12 Flags byte
13 Reserved Reserved
14 StreamID
15}
16
17type Reserved bool
18
19func (r Reserved) String() string {
20 if r {
21 return "R"
22 }
23 return ""
24}
25
26func (fh *FrameHeader) Parse(r io.Reader) error {
27 buf := make([]byte, 9)
28 if _, err := io.ReadFull(r, buf); err != nil {
29 return err
30 }
31 return fh.UnmarshalBinary(buf)
32}
33
34func (fh *FrameHeader) UnmarshalBinary(b []byte) error {
35 if len(b) != 9 {
36 return fmt.Errorf("Invalid frame header length %d", len(b))
37 }
38 *fh = FrameHeader{
39 Length: int(b[0])<<16 | int(b[1])<<8 | int(b[2]),
40 Type: FrameType(b[3]),
41 Flags: b[4],
42 Reserved: Reserved(b[5]>>7 == 1),
43 StreamID: StreamID(binary.BigEndian.Uint32(b[5:9]) & 0x7fffffff),
44 }
45 return nil
46}
47
48func (fh *FrameHeader) MarshalBinary() ([]byte, error) {
49 buf := make([]byte, 9, 9+fh.Length)
50
51 if fh.Length > 0xFFFFFF || fh.Length < 0 {
52 return nil, fmt.Errorf("Invalid frame header length: %d", fh.Length)
53 }
54 if fh.StreamID < 0 {
55 return nil, fmt.Errorf("Invalid Stream ID: %v", fh.StreamID)
56 }
57
58 buf[0], buf[1], buf[2] = byte(fh.Length>>16), byte(fh.Length>>8), byte(fh.Length)
59 buf[3] = byte(fh.Type)
60 buf[4] = fh.Flags
61 binary.BigEndian.PutUint32(buf[5:], uint32(fh.StreamID))
62
63 return buf, nil
64}
65
66type StreamID int32
67
68type FrameType byte
69
70func (ft FrameType) String() string {
71 switch ft {
72 case DataFrameType:
73 return "DATA"
74 case HeadersFrameType:
75 return "HEADERS"
76 case PriorityFrameType:
77 return "PRIORITY"
78 case ResetStreamFrameType:
79 return "RST_STREAM"
80 case SettingsFrameType:
81 return "SETTINGS"
82 case PushPromiseFrameType:
83 return "PUSH_PROMISE"
84 case PingFrameType:
85 return "PING"
86 case GoAwayFrameType:
87 return "GOAWAY"
88 case WindowUpdateFrameType:
89 return "WINDOW_UPDATE"
90 case ContinuationFrameType:
91 return "CONTINUATION"
92 default:
93 return fmt.Sprintf("UNKNOWN(%d)", byte(ft))
94 }
95}
96
97// Types
98const (
99 DataFrameType FrameType = 0
100 HeadersFrameType FrameType = 1
101 PriorityFrameType FrameType = 2
102 ResetStreamFrameType FrameType = 3
103 SettingsFrameType FrameType = 4
104 PushPromiseFrameType FrameType = 5
105 PingFrameType FrameType = 6
106 GoAwayFrameType FrameType = 7
107 WindowUpdateFrameType FrameType = 8
108 ContinuationFrameType FrameType = 9
109)