mirror of https://github.com/grpc/grpc.git
The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)
https://grpc.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
2.3 KiB
110 lines
2.3 KiB
9 years ago
|
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
|
||
|
)
|