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  }