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 23const ( 24 SETTINGS_ACK = 1 25) 26 27type SettingsFrame struct { 28 Header FrameHeader 29 Params []SettingsParameter 30} 31 32type SettingsIdentifier uint16 33 34const ( 35 SettingsHeaderTableSize SettingsIdentifier = 1 36 SettingsEnablePush SettingsIdentifier = 2 37 SettingsMaxConcurrentStreams SettingsIdentifier = 3 38 SettingsInitialWindowSize SettingsIdentifier = 4 39 SettingsMaxFrameSize SettingsIdentifier = 5 40 SettingsMaxHeaderListSize SettingsIdentifier = 6 41) 42 43const ( 44 SETTINGS_FLAG_ACK byte = 0x01 45) 46 47func (si SettingsIdentifier) String() string { 48 switch si { 49 case SettingsHeaderTableSize: 50 return "SETTINGS_HEADER_TABLE_SIZE" 51 case SettingsEnablePush: 52 return "SETTINGS_ENABLE_PUSH" 53 case SettingsMaxConcurrentStreams: 54 return "SETTINGS_MAX_CONCURRENT_STREAMS" 55 case SettingsInitialWindowSize: 56 return "SETTINGS_INITIAL_WINDOW_SIZE" 57 case SettingsMaxFrameSize: 58 return "SETTINGS_MAX_FRAME_SIZE" 59 case SettingsMaxHeaderListSize: 60 return "SETTINGS_MAX_HEADER_LIST_SIZE" 61 default: 62 return fmt.Sprintf("SETTINGS_UNKNOWN(%d)", uint16(si)) 63 } 64} 65 66type SettingsParameter struct { 67 Identifier SettingsIdentifier 68 Value uint32 69} 70 71func (f *SettingsFrame) GetHeader() *FrameHeader { 72 return &f.Header 73} 74 75func (f *SettingsFrame) ParsePayload(r io.Reader) error { 76 raw := make([]byte, f.Header.Length) 77 if _, err := io.ReadFull(r, raw); err != nil { 78 return err 79 } 80 return f.UnmarshalPayload(raw) 81} 82 83func (f *SettingsFrame) UnmarshalPayload(raw []byte) error { 84 if f.Header.Length != len(raw) { 85 return fmt.Errorf("Invalid Payload length %d != %d", f.Header.Length, len(raw)) 86 } 87 88 if f.Header.Length%6 != 0 { 89 return fmt.Errorf("Invalid Payload length %d", f.Header.Length) 90 } 91 92 f.Params = make([]SettingsParameter, 0, f.Header.Length/6) 93 for i := 0; i < len(raw); i += 6 { 94 f.Params = append(f.Params, SettingsParameter{ 95 Identifier: SettingsIdentifier(binary.BigEndian.Uint16(raw[i : i+2])), 96 Value: binary.BigEndian.Uint32(raw[i+2 : i+6]), 97 }) 98 } 99 return nil 100} 101 102func (f *SettingsFrame) MarshalPayload() ([]byte, error) { 103 raw := make([]byte, len(f.Params)*6) 104 for i, p := range f.Params { 105 binary.BigEndian.PutUint16(raw[i*6:i*6+2], uint16(p.Identifier)) 106 binary.BigEndian.PutUint32(raw[i*6+2:i*6+6], p.Value) 107 } 108 return raw, nil 109} 110 111func (f *SettingsFrame) MarshalBinary() ([]byte, error) { 112 payload, err := f.MarshalPayload() 113 if err != nil { 114 return nil, err 115 } 116 117 f.Header.Length = len(payload) 118 f.Header.Type = SettingsFrameType 119 header, err := f.Header.MarshalBinary() 120 if err != nil { 121 return nil, err 122 } 123 header = append(header, payload...) 124 125 return header, nil 126} 127