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