github.com/cloudwego/kitex@v0.9.0/pkg/remote/trans/nphttp2/grpc/grpcframe/frame_parser.go (about)

     1  /*
     2   * Copyright 2021 The Go Authors. All rights reserved.
     3   *
     4   * Use of this source code is governed by a BSD-style
     5   * license that can be found in the LICENSE file.
     6   *
     7   * This file may have been modified by CloudWeGo authors. All CloudWeGo
     8   * Modifications are Copyright 2022 CloudWeGo Authors.
     9   *
    10   * Code forked and modified from golang v1.17.4
    11   */
    12  
    13  package grpcframe
    14  
    15  import (
    16  	"encoding/binary"
    17  	"fmt"
    18  
    19  	"github.com/cloudwego/netpoll"
    20  	"golang.org/x/net/http2"
    21  	"golang.org/x/net/http2/hpack"
    22  )
    23  
    24  /* struct:
    25   * DataFrame
    26   * HeadersFrame
    27   * SettingsFrame
    28   * PushPromiseFrame
    29   * GoAwayFrame
    30   * ContinuationFrame
    31   * MetaHeadersFrame
    32   */
    33  
    34  // a frameParser parses a frame given its FrameHeader and payload
    35  // bytes. The length of payload will always equal fh.Length (which
    36  // might be 0).
    37  type frameParser func(fc *frameCache, fh http2.FrameHeader, payload []byte) (http2.Frame, error)
    38  
    39  var frameParsers = []frameParser{
    40  	// FrameData:         parseDataFrame,
    41  	http2.FrameHeaders:      parseHeadersFrame,
    42  	http2.FramePriority:     parsePriorityFrame,
    43  	http2.FrameRSTStream:    parseRSTStreamFrame,
    44  	http2.FrameSettings:     parseSettingsFrame,
    45  	http2.FramePushPromise:  parsePushPromise,
    46  	http2.FramePing:         parsePingFrame,
    47  	http2.FrameGoAway:       parseGoAwayFrame,
    48  	http2.FrameWindowUpdate: parseWindowUpdateFrame,
    49  	http2.FrameContinuation: parseContinuationFrame,
    50  }
    51  
    52  func typeFrameParser(t http2.FrameType) frameParser {
    53  	if 1 <= t && t <= 9 {
    54  		return frameParsers[t]
    55  	}
    56  	return parseUnknownFrame
    57  }
    58  
    59  // A DataFrame conveys arbitrary, variable-length sequences of octets
    60  // associated with a stream.
    61  // See http://http2.github.io/http2-spec/#rfc.section.6.1
    62  type DataFrame struct {
    63  	http2.FrameHeader
    64  	data []byte // TODO: data = netpoll.Reader here
    65  }
    66  
    67  func (f *DataFrame) StreamEnded() bool {
    68  	return f.FrameHeader.Flags.Has(http2.FlagDataEndStream)
    69  }
    70  
    71  // Data returns the frame's data octets, not including any padding
    72  // size byte or padding suffix bytes.
    73  // The caller must not retain the returned memory past the next
    74  // call to ReadFrame.
    75  func (f *DataFrame) Data() []byte {
    76  	return f.data
    77  }
    78  
    79  func parseDataFrame(fc *frameCache, fh http2.FrameHeader, payload netpoll.Reader) (http2.Frame, error) {
    80  	if fh.StreamID == 0 {
    81  		// DATA frames MUST be associated with a stream. If a
    82  		// DATA frame is received whose stream identifier
    83  		// field is 0x0, the recipient MUST respond with a
    84  		// connection error (Section 5.4.1) of type
    85  		// PROTOCOL_ERROR.
    86  		return nil, connError{http2.ErrCodeProtocol, "DATA frame with stream ID 0"}
    87  	}
    88  	f := fc.getDataFrame()
    89  	f.FrameHeader = fh
    90  
    91  	var padSize byte
    92  	payloadLen := int(fh.Length)
    93  	if fh.Flags.Has(http2.FlagDataPadded) {
    94  		var err error
    95  		padSize, err = payload.ReadByte()
    96  		payloadLen--
    97  		if err != nil {
    98  			return nil, err
    99  		}
   100  	}
   101  	if int(padSize) > payloadLen {
   102  		// If the length of the padding is greater than the
   103  		// length of the frame payload, the recipient MUST
   104  		// treat this as a connection error.
   105  		// Filed: https://github.com/http2/http2-spec/issues/610
   106  		return nil, connError{http2.ErrCodeProtocol, "pad size larger than data payload"}
   107  	}
   108  	data, err := payload.Next(payloadLen)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	f.data = data[:payloadLen-int(padSize)]
   113  	return f, nil
   114  }
   115  
   116  // A HeadersFrame is used to open a stream and additionally carries a
   117  // header block fragment.
   118  type HeadersFrame struct {
   119  	http2.FrameHeader
   120  
   121  	// Priority is set if FlagHeadersPriority is set in the FrameHeader.
   122  	Priority http2.PriorityParam
   123  
   124  	headerFragBuf []byte // not owned
   125  }
   126  
   127  func (f *HeadersFrame) HeaderBlockFragment() []byte {
   128  	return f.headerFragBuf
   129  }
   130  
   131  func (f *HeadersFrame) HeadersEnded() bool {
   132  	return f.FrameHeader.Flags.Has(http2.FlagHeadersEndHeaders)
   133  }
   134  
   135  func (f *HeadersFrame) StreamEnded() bool {
   136  	return f.FrameHeader.Flags.Has(http2.FlagHeadersEndStream)
   137  }
   138  
   139  func (f *HeadersFrame) HasPriority() bool {
   140  	return f.FrameHeader.Flags.Has(http2.FlagHeadersPriority)
   141  }
   142  
   143  func parseHeadersFrame(_ *frameCache, fh http2.FrameHeader, p []byte) (_ http2.Frame, err error) {
   144  	hf := &HeadersFrame{
   145  		FrameHeader: fh,
   146  	}
   147  	if fh.StreamID == 0 {
   148  		// HEADERS frames MUST be associated with a stream. If a HEADERS frame
   149  		// is received whose stream identifier field is 0x0, the recipient MUST
   150  		// respond with a connection error (Section 5.4.1) of type
   151  		// PROTOCOL_ERROR.
   152  		return nil, connError{http2.ErrCodeProtocol, "HEADERS frame with stream ID 0"}
   153  	}
   154  	var padLength uint8
   155  	if fh.Flags.Has(http2.FlagHeadersPadded) {
   156  		if p, padLength, err = readByte(p); err != nil {
   157  			return
   158  		}
   159  	}
   160  	if fh.Flags.Has(http2.FlagHeadersPriority) {
   161  		var v uint32
   162  		p, v, err = readUint32(p)
   163  		if err != nil {
   164  			return nil, err
   165  		}
   166  		hf.Priority.StreamDep = v & 0x7fffffff
   167  		hf.Priority.Exclusive = (v != hf.Priority.StreamDep) // high bit was set
   168  		p, hf.Priority.Weight, err = readByte(p)
   169  		if err != nil {
   170  			return nil, err
   171  		}
   172  	}
   173  	if len(p)-int(padLength) <= 0 {
   174  		return nil, http2.StreamError{StreamID: fh.StreamID, Code: http2.ErrCodeProtocol}
   175  	}
   176  	hf.headerFragBuf = p[:len(p)-int(padLength)]
   177  	return hf, nil
   178  }
   179  
   180  func parsePriorityFrame(_ *frameCache, fh http2.FrameHeader, payload []byte) (http2.Frame, error) {
   181  	if fh.StreamID == 0 {
   182  		return nil, connError{http2.ErrCodeProtocol, "PRIORITY frame with stream ID 0"}
   183  	}
   184  	if len(payload) != 5 {
   185  		return nil, connError{http2.ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len(payload))}
   186  	}
   187  	v := binary.BigEndian.Uint32(payload[:4])
   188  	streamID := v & 0x7fffffff // mask off high bit
   189  	return &http2.PriorityFrame{
   190  		FrameHeader: fh,
   191  		PriorityParam: http2.PriorityParam{
   192  			Weight:    payload[4],
   193  			StreamDep: streamID,
   194  			Exclusive: streamID != v, // was high bit set?
   195  		},
   196  	}, nil
   197  }
   198  
   199  func parseRSTStreamFrame(_ *frameCache, fh http2.FrameHeader, p []byte) (http2.Frame, error) {
   200  	if len(p) != 4 {
   201  		return nil, http2.ConnectionError(http2.ErrCodeFrameSize)
   202  	}
   203  	if fh.StreamID == 0 {
   204  		return nil, http2.ConnectionError(http2.ErrCodeProtocol)
   205  	}
   206  	return &http2.RSTStreamFrame{FrameHeader: fh, ErrCode: http2.ErrCode(binary.BigEndian.Uint32(p[:4]))}, nil
   207  }
   208  
   209  // A SettingsFrame conveys configuration parameters that affect how
   210  // endpoints communicate, such as preferences and constraints on peer
   211  // behavior.
   212  //
   213  // See http://http2.github.io/http2-spec/#SETTINGS
   214  type SettingsFrame struct {
   215  	http2.FrameHeader
   216  	p []byte
   217  }
   218  
   219  func parseSettingsFrame(_ *frameCache, fh http2.FrameHeader, p []byte) (http2.Frame, error) {
   220  	if fh.Flags.Has(http2.FlagSettingsAck) && fh.Length > 0 {
   221  		// When this (ACK 0x1) bit is set, the payload of the
   222  		// SETTINGS frame MUST be empty. Receipt of a
   223  		// SETTINGS frame with the ACK flag set and a length
   224  		// field value other than 0 MUST be treated as a
   225  		// connection error (Section 5.4.1) of type
   226  		// FRAME_SIZE_ERROR.
   227  		return nil, http2.ConnectionError(http2.ErrCodeFrameSize)
   228  	}
   229  	if fh.StreamID != 0 {
   230  		// SETTINGS frames always apply to a connection,
   231  		// never a single stream. The stream identifier for a
   232  		// SETTINGS frame MUST be zero (0x0).  If an endpoint
   233  		// receives a SETTINGS frame whose stream identifier
   234  		// field is anything other than 0x0, the endpoint MUST
   235  		// respond with a connection error (Section 5.4.1) of
   236  		// type PROTOCOL_ERROR.
   237  		return nil, http2.ConnectionError(http2.ErrCodeProtocol)
   238  	}
   239  	if len(p)%6 != 0 {
   240  		// Expecting even number of 6 byte settings.
   241  		return nil, http2.ConnectionError(http2.ErrCodeFrameSize)
   242  	}
   243  	f := &SettingsFrame{FrameHeader: fh, p: p}
   244  	if v, ok := f.Value(http2.SettingInitialWindowSize); ok && v > (1<<31)-1 {
   245  		// Values above the maximum flow control window size of 2^31 - 1 MUST
   246  		// be treated as a connection error (Section 5.4.1) of type
   247  		// FLOW_CONTROL_ERROR.
   248  		return nil, http2.ConnectionError(http2.ErrCodeFlowControl)
   249  	}
   250  	return f, nil
   251  }
   252  
   253  func (f *SettingsFrame) IsAck() bool {
   254  	return f.FrameHeader.Flags.Has(http2.FlagSettingsAck)
   255  }
   256  
   257  func (f *SettingsFrame) Value(id http2.SettingID) (v uint32, ok bool) {
   258  	for i := 0; i < f.NumSettings(); i++ {
   259  		if s := f.Setting(i); s.ID == id {
   260  			return s.Val, true
   261  		}
   262  	}
   263  	return 0, false
   264  }
   265  
   266  // Setting returns the setting from the frame at the given 0-based index.
   267  // The index must be >= 0 and less than f.NumSettings().
   268  func (f *SettingsFrame) Setting(i int) http2.Setting {
   269  	buf := f.p
   270  	return http2.Setting{
   271  		ID:  http2.SettingID(binary.BigEndian.Uint16(buf[i*6 : i*6+2])),
   272  		Val: binary.BigEndian.Uint32(buf[i*6+2 : i*6+6]),
   273  	}
   274  }
   275  
   276  func (f *SettingsFrame) NumSettings() int { return len(f.p) / 6 }
   277  
   278  // HasDuplicates reports whether f contains any duplicate setting IDs.
   279  func (f *SettingsFrame) HasDuplicates() bool {
   280  	num := f.NumSettings()
   281  	if num == 0 {
   282  		return false
   283  	}
   284  	// If it's small enough (the common case), just do the n^2
   285  	// thing and avoid a map allocation.
   286  	if num < 10 {
   287  		for i := 0; i < num; i++ {
   288  			idi := f.Setting(i).ID
   289  			for j := i + 1; j < num; j++ {
   290  				idj := f.Setting(j).ID
   291  				if idi == idj {
   292  					return true
   293  				}
   294  			}
   295  		}
   296  		return false
   297  	}
   298  	seen := map[http2.SettingID]bool{}
   299  	for i := 0; i < num; i++ {
   300  		id := f.Setting(i).ID
   301  		if seen[id] {
   302  			return true
   303  		}
   304  		seen[id] = true
   305  	}
   306  	return false
   307  }
   308  
   309  // ForeachSetting runs fn for each setting.
   310  // It stops and returns the first error.
   311  func (f *SettingsFrame) ForeachSetting(fn func(http2.Setting) error) error {
   312  	for i := 0; i < f.NumSettings(); i++ {
   313  		if err := fn(f.Setting(i)); err != nil {
   314  			return err
   315  		}
   316  	}
   317  	return nil
   318  }
   319  
   320  // A PushPromiseFrame is used to initiate a server stream.
   321  // See http://http2.github.io/http2-spec/#rfc.section.6.6
   322  
   323  // A PushPromiseFrame is used to initiate a server stream.
   324  // See http://http2.github.io/http2-spec/#rfc.section.6.6
   325  type PushPromiseFrame struct {
   326  	http2.FrameHeader
   327  	PromiseID     uint32
   328  	headerFragBuf []byte // not owned
   329  }
   330  
   331  func (f *PushPromiseFrame) HeaderBlockFragment() []byte {
   332  	return f.headerFragBuf
   333  }
   334  
   335  func (f *PushPromiseFrame) HeadersEnded() bool {
   336  	return f.FrameHeader.Flags.Has(http2.FlagPushPromiseEndHeaders)
   337  }
   338  
   339  func parsePushPromise(_ *frameCache, fh http2.FrameHeader, p []byte) (_ http2.Frame, err error) {
   340  	pp := &PushPromiseFrame{
   341  		FrameHeader: fh,
   342  	}
   343  	if pp.StreamID == 0 {
   344  		// PUSH_PROMISE frames MUST be associated with an existing,
   345  		// peer-initiated stream. The stream identifier of a
   346  		// PUSH_PROMISE frame indicates the stream it is associated
   347  		// with. If the stream identifier field specifies the value
   348  		// 0x0, a recipient MUST respond with a connection error
   349  		// (Section 5.4.1) of type PROTOCOL_ERROR.
   350  		return nil, http2.ConnectionError(http2.ErrCodeProtocol)
   351  	}
   352  	// The PUSH_PROMISE frame includes optional padding.
   353  	// Padding fields and flags are identical to those defined for DATA frames
   354  	var padLength uint8
   355  	if fh.Flags.Has(http2.FlagPushPromisePadded) {
   356  		if p, padLength, err = readByte(p); err != nil {
   357  			return
   358  		}
   359  	}
   360  
   361  	p, pp.PromiseID, err = readUint32(p)
   362  	if err != nil {
   363  		return
   364  	}
   365  	pp.PromiseID = pp.PromiseID & (1<<31 - 1)
   366  
   367  	if int(padLength) > len(p) {
   368  		// like the DATA frame, error out if padding is longer than the body.
   369  		return nil, http2.ConnectionError(http2.ErrCodeProtocol)
   370  	}
   371  	pp.headerFragBuf = p[:len(p)-int(padLength)]
   372  	return pp, nil
   373  }
   374  
   375  func parsePingFrame(_ *frameCache, fh http2.FrameHeader, payload []byte) (http2.Frame, error) {
   376  	if len(payload) != 8 {
   377  		return nil, http2.ConnectionError(http2.ErrCodeFrameSize)
   378  	}
   379  	if fh.StreamID != 0 {
   380  		return nil, http2.ConnectionError(http2.ErrCodeProtocol)
   381  	}
   382  	f := &http2.PingFrame{FrameHeader: fh}
   383  	copy(f.Data[:], payload)
   384  	return f, nil
   385  }
   386  
   387  // A GoAwayFrame informs the remote peer to stop creating streams on this connection.
   388  // See http://http2.github.io/http2-spec/#rfc.section.6.8
   389  type GoAwayFrame struct {
   390  	http2.FrameHeader
   391  	LastStreamID uint32
   392  	ErrCode      http2.ErrCode
   393  	debugData    []byte
   394  }
   395  
   396  // DebugData returns any debug data in the GOAWAY frame. Its contents
   397  // are not defined.
   398  // The caller must not retain the returned memory past the next
   399  // call to ReadFrame.
   400  func (f *GoAwayFrame) DebugData() []byte {
   401  	return f.debugData
   402  }
   403  
   404  func parseGoAwayFrame(_ *frameCache, fh http2.FrameHeader, p []byte) (http2.Frame, error) {
   405  	if fh.StreamID != 0 {
   406  		return nil, http2.ConnectionError(http2.ErrCodeProtocol)
   407  	}
   408  	if len(p) < 8 {
   409  		return nil, http2.ConnectionError(http2.ErrCodeFrameSize)
   410  	}
   411  	return &GoAwayFrame{
   412  		FrameHeader:  fh,
   413  		LastStreamID: binary.BigEndian.Uint32(p[:4]) & (1<<31 - 1),
   414  		ErrCode:      http2.ErrCode(binary.BigEndian.Uint32(p[4:8])),
   415  		debugData:    p[8:],
   416  	}, nil
   417  }
   418  
   419  func parseWindowUpdateFrame(_ *frameCache, fh http2.FrameHeader, p []byte) (http2.Frame, error) {
   420  	if len(p) != 4 {
   421  		return nil, http2.ConnectionError(http2.ErrCodeFrameSize)
   422  	}
   423  	inc := binary.BigEndian.Uint32(p[:4]) & 0x7fffffff // mask off high reserved bit
   424  	if inc == 0 {
   425  		// A receiver MUST treat the receipt of a
   426  		// WINDOW_UPDATE frame with an flow control window
   427  		// increment of 0 as a stream error (Section 5.4.2) of
   428  		// type PROTOCOL_ERROR; errors on the connection flow
   429  		// control window MUST be treated as a connection
   430  		// error (Section 5.4.1).
   431  		if fh.StreamID == 0 {
   432  			return nil, http2.ConnectionError(http2.ErrCodeProtocol)
   433  		}
   434  		return nil, http2.StreamError{StreamID: fh.StreamID, Code: http2.ErrCodeProtocol}
   435  	}
   436  	return &http2.WindowUpdateFrame{
   437  		FrameHeader: fh,
   438  		Increment:   inc,
   439  	}, nil
   440  }
   441  
   442  // A ContinuationFrame is used to continue a sequence of header block fragments.
   443  // See http://http2.github.io/http2-spec/#rfc.section.6.10
   444  type ContinuationFrame struct {
   445  	http2.FrameHeader
   446  	headerFragBuf []byte
   447  }
   448  
   449  func parseContinuationFrame(_ *frameCache, fh http2.FrameHeader, p []byte) (http2.Frame, error) {
   450  	if fh.StreamID == 0 {
   451  		return nil, connError{http2.ErrCodeProtocol, "CONTINUATION frame with stream ID 0"}
   452  	}
   453  	return &ContinuationFrame{FrameHeader: fh, headerFragBuf: p}, nil
   454  }
   455  
   456  func (f *ContinuationFrame) HeaderBlockFragment() []byte {
   457  	return f.headerFragBuf
   458  }
   459  
   460  func (f *ContinuationFrame) HeadersEnded() bool {
   461  	return f.FrameHeader.Flags.Has(http2.FlagContinuationEndHeaders)
   462  }
   463  
   464  // An UnknownFrame is the frame type returned when the frame type is unknown
   465  // or no specific frame type parser exists.
   466  type UnknownFrame struct {
   467  	http2.FrameHeader
   468  	p []byte
   469  }
   470  
   471  // Payload returns the frame's payload (after the header).  It is not
   472  // valid to call this method after a subsequent call to
   473  // Framer.ReadFrame, nor is it valid to retain the returned slice.
   474  // The memory is owned by the Framer and is invalidated when the next
   475  // frame is read.
   476  func (f *UnknownFrame) Payload() []byte {
   477  	return f.p
   478  }
   479  
   480  func parseUnknownFrame(_ *frameCache, fh http2.FrameHeader, p []byte) (http2.Frame, error) {
   481  	return &UnknownFrame{fh, p}, nil
   482  }
   483  
   484  // A MetaHeadersFrame is the representation of one HEADERS frame and
   485  // zero or more contiguous CONTINUATION frames and the decoding of
   486  // their HPACK-encoded contents.
   487  //
   488  // This type of frame does not appear on the wire and is only returned
   489  // by the Framer when Framer.ReadMetaHeaders is set.
   490  type MetaHeadersFrame struct {
   491  	*HeadersFrame
   492  
   493  	// Fields are the fields contained in the HEADERS and
   494  	// CONTINUATION frames. The underlying slice is owned by the
   495  	// Framer and must not be retained after the next call to
   496  	// ReadFrame.
   497  	//
   498  	// Fields are guaranteed to be in the correct http2 order and
   499  	// not have unknown pseudo header fields or invalid header
   500  	// field names or values. Required pseudo header fields may be
   501  	// missing, however. Use the MetaHeadersFrame.Pseudo accessor
   502  	// method access pseudo headers.
   503  	Fields []hpack.HeaderField
   504  
   505  	// Truncated is whether the max header list size limit was hit
   506  	// and Fields is incomplete. The hpack decoder state is still
   507  	// valid, however.
   508  	Truncated bool
   509  }
   510  
   511  // PseudoValue returns the given pseudo header field's value.
   512  // The provided pseudo field should not contain the leading colon.
   513  func (mh *MetaHeadersFrame) PseudoValue(pseudo string) string {
   514  	for _, hf := range mh.Fields {
   515  		if !hf.IsPseudo() {
   516  			return ""
   517  		}
   518  		if hf.Name[1:] == pseudo {
   519  			return hf.Value
   520  		}
   521  	}
   522  	return ""
   523  }
   524  
   525  // RegularFields returns the regular (non-pseudo) header fields of mh.
   526  // The caller does not own the returned slice.
   527  func (mh *MetaHeadersFrame) RegularFields() []hpack.HeaderField {
   528  	for i, hf := range mh.Fields {
   529  		if !hf.IsPseudo() {
   530  			return mh.Fields[i:]
   531  		}
   532  	}
   533  	return nil
   534  }
   535  
   536  // PseudoFields returns the pseudo header fields of mh.
   537  // The caller does not own the returned slice.
   538  func (mh *MetaHeadersFrame) PseudoFields() []hpack.HeaderField {
   539  	for i, hf := range mh.Fields {
   540  		if !hf.IsPseudo() {
   541  			return mh.Fields[:i]
   542  		}
   543  	}
   544  	return mh.Fields
   545  }
   546  
   547  func (mh *MetaHeadersFrame) checkPseudos() error {
   548  	var isRequest, isResponse bool
   549  	pf := mh.PseudoFields()
   550  	for i, hf := range pf {
   551  		switch hf.Name {
   552  		case ":method", ":path", ":scheme", ":authority":
   553  			isRequest = true
   554  		case ":status":
   555  			isResponse = true
   556  		default:
   557  			return pseudoHeaderError(hf.Name)
   558  		}
   559  		// Check for duplicates.
   560  		// This would be a bad algorithm, but N is 4.
   561  		// And this doesn't allocate.
   562  		for _, hf2 := range pf[:i] {
   563  			if hf.Name == hf2.Name {
   564  				return duplicatePseudoHeaderError(hf.Name)
   565  			}
   566  		}
   567  	}
   568  	if isRequest && isResponse {
   569  		return errMixPseudoHeaderTypes
   570  	}
   571  	return nil
   572  }