| Index: third_party/grpc/tools/http2_interop/frameheader.go
|
| diff --git a/third_party/grpc/tools/http2_interop/frameheader.go b/third_party/grpc/tools/http2_interop/frameheader.go
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..84f6fa5c55822277ff51d100679ab0a07042f5a6
|
| --- /dev/null
|
| +++ b/third_party/grpc/tools/http2_interop/frameheader.go
|
| @@ -0,0 +1,120 @@
|
| +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
|
| + var res uint32
|
| + if fh.Reserved {
|
| + res = 0x80000000
|
| + }
|
| + binary.BigEndian.PutUint32(buf[5:], uint32(fh.StreamID)|res)
|
| +
|
| + 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"
|
| + case HTTP1FrameType:
|
| + return "HTTP/1.? (Bad)"
|
| + 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
|
| +
|
| + // HTTP1FrameType is not a real type, but rather a convenient way to check if the response
|
| + // is an http response. The type of a frame header is the 4th byte, which in an http1
|
| + // response will be "HTTP/1.1 200 OK" or something like that. The character for "P" is 80.
|
| + HTTP1FrameType FrameType = 80
|
| +)
|
|
|