Skip to content

Commit

Permalink
transport/grpchttp2: change types to include mem package (#7477)
Browse files Browse the repository at this point in the history
  • Loading branch information
printchard authored Aug 6, 2024
1 parent 6d0aaae commit e6b6318
Showing 1 changed file with 34 additions and 86 deletions.
120 changes: 34 additions & 86 deletions internal/transport/grpchttp2/framer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
// Package grpchttp2 defines HTTP/2 types and a framer API and implementation.
package grpchttp2

import "golang.org/x/net/http2/hpack"
import (
"golang.org/x/net/http2/hpack"
"google.golang.org/grpc/mem"
)

// FrameType represents the type of an HTTP/2 Frame.
// See [Frame Type].
Expand Down Expand Up @@ -106,60 +109,41 @@ type FrameHeader struct {
// Each concrete Frame type defined below implements the Frame interface.
type Frame interface {
Header() *FrameHeader
// Free frees the underlying buffer if present so it can be reused by the
// framer.
//
// TODO: Remove method from the interface once the mem package gets merged.
// Free will be called on each mem.Buffer individually.
Free()
}

// DataFrame is the representation of a [DATA frame]. DATA frames convey
// arbitrary, variable-length sequences of octets associated with a stream.
// arbitrary, variable-length sequences of octets associated with a stream. It
// is the user's responsibility to call Data.Free() when it is no longer
// needed.
//
// [DATA frame]: https://httpwg.org/specs/rfc7540.html#DATA
type DataFrame struct {
hdr *FrameHeader
free func()
Data []byte
Data *mem.Buffer
}

// Header returns the 9 byte HTTP/2 header for this frame.
func (f *DataFrame) Header() *FrameHeader {
return f.hdr
}

// Free frees the buffer containing the data in this frame.
func (f *DataFrame) Free() {
if f.free != nil {
f.free()
}
}

// HeadersFrame is the representation of a [HEADERS Frame]. The HEADERS frame
// is used to open a stream, and additionally carries a header block fragment.
// It is the user's responsibility to call HdrBlock.Free() when it is no longer
// needed.
//
// [HEADERS Frame]: https://httpwg.org/specs/rfc7540.html#HEADERS
type HeadersFrame struct {
hdr *FrameHeader
free func()
HdrBlock []byte
HdrBlock *mem.Buffer
}

// Header returns the 9 byte HTTP/2 header for this frame.
func (f *HeadersFrame) Header() *FrameHeader {
return f.hdr
}

// Free frees the buffer containing the header block in this frame.
func (f *HeadersFrame) Free() {
if f.free != nil {
f.free()
}
}

// RSTStreamFrame is the representation of a [RST_STREAM Frame]. There is no
// underlying byte array in this frame, so Free() is a no-op. The RST_STREAM
// RSTStreamFrame is the representation of a [RST_STREAM Frame]. The RST_STREAM
// frame allows for immediate termination of a stream
//
// [RST_STREAM Frame]: https://httpwg.org/specs/rfc7540.html#RST_STREAM
Expand All @@ -173,14 +157,9 @@ func (f *RSTStreamFrame) Header() *FrameHeader {
return f.hdr
}

// Free is a no-op for RSTStreamFrame.
func (f *RSTStreamFrame) Free() {}

// SettingsFrame is the representation of a [SETTINGS Frame]. There is no
// underlying byte array in this frame, so Free() is a no-op.
//
// The SETTINGS frame conveys configuration parameters that affect how
// endpoints communicate, such as preferences and constraints on peer behavior.
// SettingsFrame is the representation of a [SETTINGS Frame]. The SETTINGS frame
// conveys configuration parameters that affect how endpoints communicate, such
// as preferences and constraints on peer behavior.
//
// [SETTINGS Frame]: https://httpwg.org/specs/rfc7540.html#SETTINGS
type SettingsFrame struct {
Expand All @@ -193,57 +172,44 @@ func (f *SettingsFrame) Header() *FrameHeader {
return f.hdr
}

// Free is a no-op for SettingsFrame.
func (f *SettingsFrame) Free() {}

// PingFrame is the representation of a [PING Frame]. The PING frame is a
// mechanism for measuring a minimal round-trip time from the sender, as well
// as determining whether an idle connection is still functional.
//
// It is the user's responsibility to call Data.Free() when it is no longer
// needed.
//
// [PING Frame]: https://httpwg.org/specs/rfc7540.html#PING
type PingFrame struct {
hdr *FrameHeader
free func()
Data []byte
Data *mem.Buffer
}

// Header returns the 9 byte HTTP/2 header for this frame.
func (f *PingFrame) Header() *FrameHeader {
return f.hdr
}

// Free frees the buffer containing the data in this frame.
func (f *PingFrame) Free() {
if f.free != nil {
f.free()
}
}

// GoAwayFrame is the representation of a [GOAWAY Frame]. The GOAWAY frame is
// used to initiate shutdown of a connection or to signal serious error
// conditions.
//
// It is the user's responsibility to call DebugData.Free() when it is no longer
// needed.
//
// [GOAWAY Frame]: https://httpwg.org/specs/rfc7540.html#GOAWAY
type GoAwayFrame struct {
hdr *FrameHeader
free func()
LastStreamID uint32
Code ErrCode
DebugData []byte
DebugData *mem.Buffer
}

// Header returns the 9 byte HTTP/2 header for this frame.
func (f *GoAwayFrame) Header() *FrameHeader {
return f.hdr
}

// Free frees the buffer containing the debug data in this frame.
func (f *GoAwayFrame) Free() {
if f.free != nil {
f.free()
}
}

// WindowUpdateFrame is the representation of a [WINDOW_UPDATE Frame]. The
// WINDOW_UPDATE frame is used to implement flow control.
//
Expand All @@ -261,31 +227,24 @@ func (f *WindowUpdateFrame) Header() *FrameHeader {
// ContinuationFrame is the representation of a [CONTINUATION Frame]. The
// CONTINUATION frame is used to continue a sequence of header block fragments.
//
// It is the user's responsibility to call HdrBlock.Free() when it is no longer
// needed.
//
// [CONTINUATION Frame]: https://httpwg.org/specs/rfc7540.html#CONTINUATION
type ContinuationFrame struct {
hdr *FrameHeader
free func()
HdrBlock []byte
HdrBlock *mem.Buffer
}

// Header returns the 9 byte HTTP/2 header for this frame.
func (f *ContinuationFrame) Header() *FrameHeader {
return f.hdr
}

// Free frees the buffer containing the header block in this frame.
func (f *ContinuationFrame) Free() {
if f.free != nil {
f.free()
}
}

// MetaHeadersFrame is the representation of one HEADERS frame and zero or more
// contiguous CONTINUATION frames and the decoding of their HPACK-encoded
// contents. This frame type is not transmitted over the network and is only
// generated by the ReadFrame() function.
//
// Since there is no underlying buffer in this Frame, Free() is a no-op.
type MetaHeadersFrame struct {
hdr *FrameHeader
Fields []hpack.HeaderField
Expand All @@ -299,24 +258,17 @@ func (f *MetaHeadersFrame) Header() *FrameHeader {
return f.hdr
}

// Free is a no-op for MetaHeadersFrame.
func (f *MetaHeadersFrame) Free() {}

// Framer encapsulates the functionality to read and write HTTP/2 frames.
type Framer interface {
// ReadFrame returns grpchttp2.Frame. It is the caller's responsibility to
// call Frame.Free() once it is done using it. Note that once the mem
// package gets merged, this API will change in favor of Buffer.Free().
// free the underlying buffer when done using the Frame.
ReadFrame() (Frame, error)
// WriteData writes an HTTP/2 DATA frame to the stream.
// TODO: Once the mem package gets merged, data will change type to
// mem.BufferSlice.
WriteData(streamID uint32, endStream bool, data ...[]byte) error
// WriteData writes an HTTP/2 HEADERS frame to the stream.
// TODO: Once the mem package gets merged, headerBlock will change type to
// mem.Buffer.
WriteHeaders(streamID uint32, endStream, endHeaders bool, headerBlocks []byte) error
// WriteData writes an HTTP/2 RST_STREAM frame to the stream.
// WriteData writes an HTTP/2 DATA frame to the stream. The data is expected
// to be freed by the caller.
WriteData(streamID uint32, endStream bool, data mem.BufferSlice) error
// WriteHeaders writes an HTTP/2 HEADERS frame to the stream.
WriteHeaders(streamID uint32, endStream, endHeaders bool, headerBlock []byte) error
// WriteRSTStream writes an HTTP/2 RST_STREAM frame to the stream.
WriteRSTStream(streamID uint32, code ErrCode) error
// WriteSettings writes an HTTP/2 SETTINGS frame to the connection.
WriteSettings(settings ...Setting) error
Expand All @@ -325,13 +277,9 @@ type Framer interface {
// WritePing writes an HTTP/2 PING frame to the connection.
WritePing(ack bool, data [8]byte) error
// WriteGoAway writes an HTTP/2 GOAWAY frame to the connection.
// TODO: Once the mem package gets merged, debugData will change type to
// mem.Buffer.
WriteGoAway(maxStreamID uint32, code ErrCode, debugData []byte) error
// WriteWindowUpdate writes an HTTP/2 WINDOW_UPDATE frame to the stream.
WriteWindowUpdate(streamID, inc uint32) error
// WriteContinuation writes an HTTP/2 CONTINUATION frame to the stream.
// TODO: Once the mem package gets merged, data will change type to
// mem.Buffer.
WriteContinuation(streamID uint32, endHeaders bool, headerBlock []byte) error
}

0 comments on commit e6b6318

Please sign in to comment.