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