Skip to content

transport/grpchttp2: change types to include mem package #7477

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 6, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
Loading