xref: /aosp_15_r20/external/grpc-grpc/tools/http2_interop/frameheader.go (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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