blob: db292d01b4a5c4ba2d2728166ce6846f3ac36148 [file] [log] [blame]
#ifndef QUICHE_HTTP2_ADAPTER_HTTP2_VISITOR_INTERFACE_H_
#define QUICHE_HTTP2_ADAPTER_HTTP2_VISITOR_INTERFACE_H_
#include <cstdint>
#include <vector>
#include "absl/strings/string_view.h"
#include "http2/adapter/http2_protocol.h"
#include "common/platform/api/quiche_export.h"
namespace http2 {
namespace adapter {
// Http2VisitorInterface contains callbacks for receiving HTTP/2-level events. A
// processor like NghttpAdapter parses HTTP/2 frames and invokes the callbacks
// on an instance of this interface. Prefer a void return type for these
// callbacks, instead setting output parameters as needed.
//
// Example sequences of calls/events:
// GET:
// - OnBeginHeadersForStream()
// - OnHeaderForStream()
// - OnEndHeadersForStream()
// - OnEndStream()
//
// POST:
// - OnBeginHeadersForStream()
// - OnHeaderForStream()
// - OnEndHeadersForStream()
// - OnBeginDataForStream()
// - OnDataForStream()
// - OnEndStream()
//
// Request canceled mid-stream, e.g, with error code CANCEL:
// - OnBeginHeadersForStream()
// - OnHeaderForStream()
// - OnEndHeadersForStream()
// - OnRstStream()
// - OnCloseStream()
//
// Request closed mid-stream, e.g., with error code NO_ERROR:
// - OnBeginHeadersForStream()
// - OnHeaderForStream()
// - OnEndHeadersForStream()
// - OnRstStream()
// - OnCloseStream()
//
// More details are at RFC 7540 (go/http2spec).
class QUICHE_EXPORT_PRIVATE Http2VisitorInterface {
public:
Http2VisitorInterface(const Http2VisitorInterface&) = delete;
Http2VisitorInterface& operator=(const Http2VisitorInterface&) = delete;
virtual ~Http2VisitorInterface() = default;
enum : int64_t {
kSendBlocked = 0,
kSendError = -1,
};
// Called when there are serialized frames to send. Should return how many
// bytes were actually sent. May return kSendBlocked or kSendError.
virtual int64_t OnReadyToSend(absl::string_view serialized) = 0;
// Called when a connection-level error has occurred.
enum class ConnectionError {
// The peer sent an invalid connection preface.
kInvalidConnectionPreface,
// The visitor encountered an error sending bytes to the peer.
kSendError,
// There was an error reading and framing bytes from the peer.
kParseError,
// The visitor considered a received header to be a connection error.
kHeaderError,
// The peer attempted to open a stream with an invalid stream ID.
kInvalidNewStreamId,
// The peer sent a frame that is invalid on an idle stream (before HEADERS).
kWrongFrameSequence,
// The peer sent an invalid PUSH_PROMISE frame.
kInvalidPushPromise,
// The peer exceeded the max concurrent streams limit.
kExceededMaxConcurrentStreams,
// The peer caused a flow control error.
kFlowControlError,
};
virtual void OnConnectionError(ConnectionError error) = 0;
// Called when the header for a frame is received.
virtual bool OnFrameHeader(Http2StreamId /*stream_id*/, size_t /*length*/,
uint8_t /*type*/, uint8_t /*flags*/) {
return true;
}
// Called when a non-ack SETTINGS frame is received.
virtual void OnSettingsStart() = 0;
// Called for each SETTINGS id-value pair.
virtual void OnSetting(Http2Setting setting) = 0;
// Called at the end of a non-ack SETTINGS frame.
virtual void OnSettingsEnd() = 0;
// Called when a SETTINGS ack frame is received.
virtual void OnSettingsAck() = 0;
// Called when the connection receives the header block for a HEADERS frame on
// a stream but has not yet parsed individual headers. Returns false if a
// fatal error has occurred.
virtual bool OnBeginHeadersForStream(Http2StreamId stream_id) = 0;
// Called when the connection receives the header |key| and |value| for a
// stream. The HTTP/2 pseudo-headers defined in RFC 7540 Sections 8.1.2.3 and
// 8.1.2.4 are also conveyed in this callback. This method is called after
// OnBeginHeadersForStream(). May return HEADER_RST_STREAM to indicate the
// header block should be rejected. This will cause the library to queue a
// RST_STREAM frame, which will have a default error code of INTERNAL_ERROR.
// The visitor implementation may choose to queue a RST_STREAM with a
// different error code instead, which should be done before returning
// HEADER_RST_STREAM. Returning HEADER_CONNECTION_ERROR will lead to a
// non-recoverable error on the connection.
enum OnHeaderResult {
// The header was accepted.
HEADER_OK,
// The application considers the header a connection error.
HEADER_CONNECTION_ERROR,
// The application rejects the header and requests the stream be reset.
HEADER_RST_STREAM,
// The header field is invalid and will be reset with error code
// PROTOCOL_ERROR.
HEADER_FIELD_INVALID,
// The headers are a violation of HTTP messaging semantics and will be reset
// with error code PROTOCOL_ERROR.
HEADER_HTTP_MESSAGING,
// The headers caused a compression context error.
HEADER_COMPRESSION_ERROR,
};
virtual OnHeaderResult OnHeaderForStream(Http2StreamId stream_id,
absl::string_view key,
absl::string_view value) = 0;
// Called when the connection has received the complete header block for a
// logical HEADERS frame on a stream (which may contain CONTINUATION frames,
// transparent to the user).
virtual bool OnEndHeadersForStream(Http2StreamId stream_id) = 0;
// Called when the connection receives the beginning of a DATA frame. The data
// payload will be provided via subsequent calls to OnDataForStream().
virtual bool OnBeginDataForStream(Http2StreamId stream_id,
size_t payload_length) = 0;
// Called when the optional padding length field is parsed as part of a DATA
// frame payload. `padding_length` represents the total amount of padding for
// this frame, including the length byte itself.
virtual bool OnDataPaddingLength(Http2StreamId stream_id,
size_t padding_length) = 0;
// Called when the connection receives some |data| (as part of a DATA frame
// payload) for a stream.
virtual bool OnDataForStream(Http2StreamId stream_id,
absl::string_view data) = 0;
// Called when the peer sends the END_STREAM flag on a stream, indicating that
// the peer will not send additional headers or data for that stream.
virtual void OnEndStream(Http2StreamId stream_id) = 0;
// Called when the connection receives a RST_STREAM for a stream. This call
// will be followed by either OnCloseStream().
virtual void OnRstStream(Http2StreamId stream_id,
Http2ErrorCode error_code) = 0;
// Called when a stream is closed.
virtual void OnCloseStream(Http2StreamId stream_id,
Http2ErrorCode error_code) = 0;
// Called when the connection receives a PRIORITY frame.
virtual void OnPriorityForStream(Http2StreamId stream_id,
Http2StreamId parent_stream_id, int weight,
bool exclusive) = 0;
// Called when the connection receives a PING frame.
virtual void OnPing(Http2PingId ping_id, bool is_ack) = 0;
// Called when the connection receives a PUSH_PROMISE frame. The server push
// request headers follow in calls to OnHeaderForStream() with |stream_id|.
virtual void OnPushPromiseForStream(Http2StreamId stream_id,
Http2StreamId promised_stream_id) = 0;
// Called when the connection receives a GOAWAY frame.
virtual bool OnGoAway(Http2StreamId last_accepted_stream_id,
Http2ErrorCode error_code,
absl::string_view opaque_data) = 0;
// Called when the connection receives a WINDOW_UPDATE frame. For
// connection-level window updates, the |stream_id| will be 0.
virtual void OnWindowUpdate(Http2StreamId stream_id,
int window_increment) = 0;
// Called immediately before a frame of the given type is sent. Should return
// 0 on success.
virtual int OnBeforeFrameSent(uint8_t frame_type, Http2StreamId stream_id,
size_t length, uint8_t flags) = 0;
// Called immediately after a frame of the given type is sent. Should return 0
// on success. |error_code| is only populated for RST_STREAM and GOAWAY frame
// types.
virtual int OnFrameSent(uint8_t frame_type, Http2StreamId stream_id,
size_t length, uint8_t flags,
uint32_t error_code) = 0;
// Called when the connection receives an invalid frame. A return value of
// false will result in the connection entering an error state, with no
// further frame processing possible.
enum class InvalidFrameError {
// The frame contains a general protocol error.
kProtocol,
// The frame would have caused a new (invalid) stream to be opened.
kRefusedStream,
// The frame contains an invalid header field.
kHttpHeader,
// The frame contains a violation in HTTP messaging rules.
kHttpMessaging,
// The frame causes a flow control error.
kFlowControl,
// The frame is on an already closed stream or has an invalid stream ID.
kStreamClosed,
};
virtual bool OnInvalidFrame(Http2StreamId stream_id,
InvalidFrameError error) = 0;
// Called when the connection receives the beginning of a METADATA frame
// (which may itself be the middle of a logical metadata block). The metadata
// payload will be provided via subsequent calls to OnMetadataForStream().
// TODO(birenroy): Consider removing this unnecessary method.
virtual void OnBeginMetadataForStream(Http2StreamId stream_id,
size_t payload_length) = 0;
// Called when the connection receives |metadata| as part of a METADATA frame
// payload for a stream. Returns false if a fatal error has occurred.
virtual bool OnMetadataForStream(Http2StreamId stream_id,
absl::string_view metadata) = 0;
// Called when the connection has finished receiving a logical metadata block
// for a stream. Note that there may be multiple metadata blocks for a stream.
// Returns false if there was an error unpacking the metadata payload.
virtual bool OnMetadataEndForStream(Http2StreamId stream_id) = 0;
// Invoked with an error message from the application.
virtual void OnErrorDebug(absl::string_view message) = 0;
protected:
Http2VisitorInterface() = default;
};
} // namespace adapter
} // namespace http2
#endif // QUICHE_HTTP2_ADAPTER_HTTP2_VISITOR_INTERFACE_H_