github.com/alejandroesc/spdy@v0.0.0-20200317064415-01a02f0eb389/spdy3/frames/goaway.go (about) 1 // Copyright 2014 Jamie Hall. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package frames 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 12 "github.com/SlyMarbo/spdy/common" 13 ) 14 15 type GOAWAY struct { 16 LastGoodStreamID common.StreamID 17 Status common.StatusCode 18 } 19 20 func (frame *GOAWAY) Compress(comp common.Compressor) error { 21 return nil 22 } 23 24 func (frame *GOAWAY) Decompress(decomp common.Decompressor) error { 25 return nil 26 } 27 28 func (frame *GOAWAY) Error() string { 29 if err := frame.Status.String(); err != "" { 30 return err 31 } 32 33 return fmt.Sprintf("[unknown status code %d]", frame.Status) 34 } 35 36 func (frame *GOAWAY) Name() string { 37 return "GOAWAY" 38 } 39 40 func (frame *GOAWAY) ReadFrom(reader io.Reader) (int64, error) { 41 c := common.ReadCounter{R: reader} 42 data, err := common.ReadExactly(&c, 16) 43 if err != nil { 44 return c.N, err 45 } 46 47 err = controlFrameCommonProcessing(data[:5], _GOAWAY, 0) 48 if err != nil { 49 return c.N, err 50 } 51 52 // Get and check length. 53 length := int(common.BytesToUint24(data[5:8])) 54 if length != 8 { 55 return c.N, common.IncorrectDataLength(length, 8) 56 } 57 58 frame.LastGoodStreamID = common.StreamID(common.BytesToUint32(data[8:12])) 59 frame.Status = common.StatusCode(common.BytesToUint32(data[12:16])) 60 61 if !frame.LastGoodStreamID.Valid() { 62 return c.N, common.StreamIdTooLarge 63 } 64 65 return c.N, nil 66 } 67 68 func (frame *GOAWAY) String() string { 69 buf := new(bytes.Buffer) 70 71 buf.WriteString("GOAWAY {\n\t") 72 buf.WriteString(fmt.Sprintf("Version: 3\n\t")) 73 buf.WriteString(fmt.Sprintf("Last good stream ID: %d\n\t", frame.LastGoodStreamID)) 74 buf.WriteString(fmt.Sprintf("Status code: %s (%d)\n}\n", frame.Status, frame.Status)) 75 76 return buf.String() 77 } 78 79 func (frame *GOAWAY) WriteTo(writer io.Writer) (int64, error) { 80 c := common.WriteCounter{W: writer} 81 if !frame.LastGoodStreamID.Valid() { 82 return c.N, common.StreamIdTooLarge 83 } 84 85 out := make([]byte, 16) 86 87 out[0] = 128 // Control bit and Version 88 out[1] = 3 // Version 89 out[2] = 0 // Type 90 out[3] = 7 // Type 91 out[4] = 0 // Flags 92 out[5] = 0 // Length 93 out[6] = 0 // Length 94 out[7] = 8 // Length 95 out[8] = frame.LastGoodStreamID.B1() // Last Good Stream ID 96 out[9] = frame.LastGoodStreamID.B2() // Last Good Stream ID 97 out[10] = frame.LastGoodStreamID.B3() // Last Good Stream ID 98 out[11] = frame.LastGoodStreamID.B4() // Last Good Stream ID 99 out[12] = byte(frame.Status >> 24) // Status Code 100 out[13] = byte(frame.Status >> 16) // Status Code 101 out[14] = byte(frame.Status >> 8) // Status Code 102 out[15] = byte(frame.Status) // Status Code 103 104 err := common.WriteExactly(&c, out) 105 if err != nil { 106 return c.N, err 107 } 108 109 return c.N, nil 110 }