1// Copyright 2019 The gRPC Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package http2interop 16 17import ( 18 "encoding/binary" 19 "fmt" 20 "io" 21) 22 23type FrameHeader struct { 24 Length int 25 Type FrameType 26 Flags byte 27 Reserved Reserved 28 StreamID 29} 30 31type Reserved bool 32 33func (r Reserved) String() string { 34 if r { 35 return "R" 36 } 37 return "" 38} 39 40func (fh *FrameHeader) Parse(r io.Reader) error { 41 buf := make([]byte, 9) 42 if _, err := io.ReadFull(r, buf); err != nil { 43 return err 44 } 45 return fh.UnmarshalBinary(buf) 46} 47 48func (fh *FrameHeader) UnmarshalBinary(b []byte) error { 49 if len(b) != 9 { 50 return fmt.Errorf("Invalid frame header length %d", len(b)) 51 } 52 *fh = FrameHeader{ 53 Length: int(b[0])<<16 | int(b[1])<<8 | int(b[2]), 54 Type: FrameType(b[3]), 55 Flags: b[4], 56 Reserved: Reserved(b[5]>>7 == 1), 57 StreamID: StreamID(binary.BigEndian.Uint32(b[5:9]) & 0x7fffffff), 58 } 59 return nil 60} 61 62func (fh *FrameHeader) MarshalBinary() ([]byte, error) { 63 buf := make([]byte, 9, 9+fh.Length) 64 65 if fh.Length > 0xFFFFFF || fh.Length < 0 { 66 return nil, fmt.Errorf("Invalid frame header length: %d", fh.Length) 67 } 68 if fh.StreamID < 0 { 69 return nil, fmt.Errorf("Invalid Stream ID: %v", fh.StreamID) 70 } 71 72 buf[0], buf[1], buf[2] = byte(fh.Length>>16), byte(fh.Length>>8), byte(fh.Length) 73 buf[3] = byte(fh.Type) 74 buf[4] = fh.Flags 75 var res uint32 76 if fh.Reserved { 77 res = 0x80000000 78 } 79 binary.BigEndian.PutUint32(buf[5:], uint32(fh.StreamID)|res) 80 81 return buf, nil 82} 83 84type StreamID int32 85 86type FrameType byte 87 88func (ft FrameType) String() string { 89 switch ft { 90 case DataFrameType: 91 return "DATA" 92 case HeadersFrameType: 93 return "HEADERS" 94 case PriorityFrameType: 95 return "PRIORITY" 96 case ResetStreamFrameType: 97 return "RST_STREAM" 98 case SettingsFrameType: 99 return "SETTINGS" 100 case PushPromiseFrameType: 101 return "PUSH_PROMISE" 102 case PingFrameType: 103 return "PING" 104 case GoAwayFrameType: 105 return "GOAWAY" 106 case WindowUpdateFrameType: 107 return "WINDOW_UPDATE" 108 case ContinuationFrameType: 109 return "CONTINUATION" 110 case HTTP1FrameType: 111 return "HTTP/1.? (Bad)" 112 default: 113 return fmt.Sprintf("UNKNOWN(%d)", byte(ft)) 114 } 115} 116 117// Types 118const ( 119 DataFrameType FrameType = 0 120 HeadersFrameType FrameType = 1 121 PriorityFrameType FrameType = 2 122 ResetStreamFrameType FrameType = 3 123 SettingsFrameType FrameType = 4 124 PushPromiseFrameType FrameType = 5 125 PingFrameType FrameType = 6 126 GoAwayFrameType FrameType = 7 127 WindowUpdateFrameType FrameType = 8 128 ContinuationFrameType FrameType = 9 129 130 // HTTP1FrameType is not a real type, but rather a convenient way to check if the response 131 // is an http response. The type of a frame header is the 4th byte, which in an http1 132 // response will be "HTTP/1.1 200 OK" or something like that. The character for "P" is 80. 133 HTTP1FrameType FrameType = 80 134) 135