The general philosophy used here is to do as little as possible. In particular, this means that member variables aren't read or written if not absolutely necessary, especially in optimized builds.
If we can reasonably expect the listener to double check our work (i.e. looking up a stream id, and therefore noticing if it is supposed to be non-zero but isn‘t), then we’ll skip that check.
FrameDecoderState
This class provides common state and behaviors needed by all of the payload decoders, including:
Providing the common frame header (Http2FrameHeader
) for the frame being decoded.
Tracking the amount of payload remaining to be decoded (often tracked only if the payload is split across decode buffers);
Decoding fixed size structures in the payload (e.g. Http2PriorityFields
), updating the amount of payload remaining to be decoded as it does so, or reporting a Frame Size Error if a fixed size structure is truncated.
For DATA
, HEADERS
and PUSH_PROMISE
frames, which support padding, FrameDecoderState
also supports:
Reading the (optional) Pad Length field and reporting its value to the listener.
Tracking the amount of trailing padding that remains to be skipped.
Skipping the trailing padding, reporting to the listener as it does so.
Http2FrameDecoderListener
Defines the interface which HTTP/2 decoder clients must implement in order to receive callbacks from the decoder as it decodes each frame.
Simple frames that contain a single fixed size payload have correspondingly simple callback methods. For example:
WINDOW_UPDATE
frames are reported via OnWindowUpdate()
.PING
frames are reported via OnPing()
or OnPingAck()
, depending on whether the ACK
flag is set.However a frame type X with a variable length payload will be reported via OnXStart()
and OnXEnd()
methods, which bracket calls to other methods that report on the payload. For example:
DATA
frames are reported via OnDataStart()
, OnPadLength()
(if the PADDED
flag is set), OnDataPayload()
(more than once if necessary), OnPadding()
(if OnPadLength()
reports a non-zero amount of trailing padding), and OnDataEnd()
once all the payload and padding has been reported to the listener.GOAWAY
frames are reported via OnGoAwayStart()
, OnGoAwayOpaqueData()
(more than once if necessary), and OnGoAwayEnd()
once all the opaque data has been reported to the listener.In addition there are two error callbacks:
OnPaddingTooLong()
: There isn‘t enough room in the frame’s payload for all of the padding, let alone anything else.OnFrameSizeError()
: The frame size isn‘t correct, except for errors reported by OnPaddingTooLong()
. For example, a PRIORITY
frame isn’t exactly 5 bytes long, or a SETTINGS
frame payload isn't a multiple of 6 bytes long.FailingHttp2FrameDecoderListener
This is a test-only sub-class of Http2FrameDecoderListener
that treats any call as a test failure. Its purpose is to make it easy to detect when a payload decoder has called the wrong method or a test listener has failed to implement all necessary methods.
FrameParts
This is a test-only sub-class of Http2FrameDecoderListener
that implements ALL of the Http2FrameDecoderListener
methods. Its purpose is to record all the provided info during the decoding of a single frame, and also to provide some validation of the callbacks as they are received (e.g. it generates a test failure if OnPadLength()
is called for a frame that doesn't have padding).
FrameParts
instances are also directly created by tests for comparing against those instances that are created while decoding. See FrameParts::VerifyEquals()
.
FramePartsCollector
This is a test-only sub-class of FailingHttp2FrameDecoderListener
, which implements NONE of the Http2FrameDecoderListener
methods, but instead serves as a base class for test listeners for each payload decoder. It provides these protected methods:
Method | Purpose |
---|---|
StartFrame() | For use when implementing the OnXStart() method for |
: : frame type X. Creates a new FrameParts instance, : | |
: : and making it available to CurrentFrame() , : | |
: : EndFrame() and FrameError() (see below). : | |
CurrentFrame() | For use when implementing the listener methods for |
: : variable length and optional payload components (e.g. : | |
: : OnDataPayload() , OnHeadersPriority() , or : | |
: : OnPadding() ). StartFrame() must have already been : | |
: : called for the frame. : | |
EndFrame() | For use when implementing the OnXEnd() method for |
: : frame type X. Pushes the frame that CurrentFrame() : | |
: : would report onto the list of completely decoded : | |
: : frames that it has recorded. StartFrame() must have : | |
: : already been called for the frame. : | |
StartAndEndFrame() | For use when implementing the OnX() method for |
: : frame type X that has a fixed size payload (e.g. : | |
: : OnRstStream() ), and hence is not reported via : | |
: : bracketed OnXStart() and OnXEnd() methods. : | |
FrameError() | For use in handling OnPaddingTooLong() and |
: : OnFrameSizeError() , where an earlier OnXStart() : | |
: : method may or may not have already been called. : |
For consideration: If FramePartsCollector
implemented ALL of the Http2FrameDecoderListener
methods, then we could eliminate the Listener
classes in payload decoder tests. Instead we could add a FramePartsCollector
constructor overload which takes the expected Http2FrameType
. If the frame type has been provided, then FramePartsCollector
will validate it, but otherwise will forward all calls to the current FrameParts
instance, using the methods described above just as a Listener
might today.