diff options
Diffstat (limited to 'tools/http2_interop/frameheader.go')
-rw-r--r-- | tools/http2_interop/frameheader.go | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/tools/http2_interop/frameheader.go b/tools/http2_interop/frameheader.go new file mode 100644 index 0000000000..78fe4201f6 --- /dev/null +++ b/tools/http2_interop/frameheader.go @@ -0,0 +1,109 @@ +package http2interop + +import ( + "encoding/binary" + "fmt" + "io" +) + +type FrameHeader struct { + Length int + Type FrameType + Flags byte + Reserved Reserved + StreamID +} + +type Reserved bool + +func (r Reserved) String() string { + if r { + return "R" + } + return "" +} + +func (fh *FrameHeader) Parse(r io.Reader) error { + buf := make([]byte, 9) + if _, err := io.ReadFull(r, buf); err != nil { + return err + } + return fh.UnmarshalBinary(buf) +} + +func (fh *FrameHeader) UnmarshalBinary(b []byte) error { + if len(b) != 9 { + return fmt.Errorf("Invalid frame header length %d", len(b)) + } + *fh = FrameHeader{ + Length: int(b[0])<<16 | int(b[1])<<8 | int(b[2]), + Type: FrameType(b[3]), + Flags: b[4], + Reserved: Reserved(b[5]>>7 == 1), + StreamID: StreamID(binary.BigEndian.Uint32(b[5:9]) & 0x7fffffff), + } + return nil +} + +func (fh *FrameHeader) MarshalBinary() ([]byte, error) { + buf := make([]byte, 9, 9+fh.Length) + + if fh.Length > 0xFFFFFF || fh.Length < 0 { + return nil, fmt.Errorf("Invalid frame header length: %d", fh.Length) + } + if fh.StreamID < 0 { + return nil, fmt.Errorf("Invalid Stream ID: %v", fh.StreamID) + } + + buf[0], buf[1], buf[2] = byte(fh.Length>>16), byte(fh.Length>>8), byte(fh.Length) + buf[3] = byte(fh.Type) + buf[4] = fh.Flags + binary.BigEndian.PutUint32(buf[5:], uint32(fh.StreamID)) + + return buf, nil +} + +type StreamID int32 + +type FrameType byte + +func (ft FrameType) String() string { + switch ft { + case DataFrameType: + return "DATA" + case HeadersFrameType: + return "HEADERS" + case PriorityFrameType: + return "PRIORITY" + case ResetStreamFrameType: + return "RST_STREAM" + case SettingsFrameType: + return "SETTINGS" + case PushPromiseFrameType: + return "PUSH_PROMISE" + case PingFrameType: + return "PING" + case GoAwayFrameType: + return "GOAWAY" + case WindowUpdateFrameType: + return "WINDOW_UPDATE" + case ContinuationFrameType: + return "CONTINUATION" + default: + return fmt.Sprintf("UNKNOWN(%d)", byte(ft)) + } +} + +// Types +const ( + DataFrameType FrameType = 0 + HeadersFrameType FrameType = 1 + PriorityFrameType FrameType = 2 + ResetStreamFrameType FrameType = 3 + SettingsFrameType FrameType = 4 + PushPromiseFrameType FrameType = 5 + PingFrameType FrameType = 6 + GoAwayFrameType FrameType = 7 + WindowUpdateFrameType FrameType = 8 + ContinuationFrameType FrameType = 9 +) |