Change H2 frame handlers to member functions (#8988)
* Change H2 frame handlers to member functions
This closes #8183
* Make the handlers table static
diff --git a/proxy/http2/Http2ConnectionState.cc b/proxy/http2/Http2ConnectionState.cc
index 648d9d9..4f60d58 100644
--- a/proxy/http2/Http2ConnectionState.cc
+++ b/proxy/http2/Http2ConnectionState.cc
@@ -49,8 +49,6 @@
SsnDebug(session->get_proxy_session(), "http2_con", "[%" PRId64 "] [%u] " fmt, session->get_connection_id(), stream_id, \
##__VA_ARGS__);
-using http2_frame_dispatch = Http2Error (*)(Http2ConnectionState &, const Http2Frame &);
-
static const int buffer_size_index[HTTP2_FRAME_TYPE_MAX] = {
BUFFER_SIZE_INDEX_16K, // HTTP2_FRAME_TYPE_DATA
BUFFER_SIZE_INDEX_16K, // HTTP2_FRAME_TYPE_HEADERS
@@ -79,18 +77,18 @@
return end - buf;
}
-static Http2Error
-rcv_data_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
+Http2Error
+Http2ConnectionState::rcv_data_frame(const Http2Frame &frame)
{
unsigned nbytes = 0;
Http2StreamId id = frame.header().streamid;
uint8_t pad_length = 0;
const uint32_t payload_length = frame.header().length;
- Http2StreamDebug(cstate.session, id, "Received DATA frame");
+ Http2StreamDebug(this->session, id, "Received DATA frame");
- if (cstate.get_zombie_event()) {
- Warning("Data frame for zombied session %" PRId64, cstate.session->get_connection_id());
+ if (this->get_zombie_event()) {
+ Warning("Data frame for zombied session %" PRId64, this->session->get_connection_id());
}
// If a DATA frame is received whose stream identifier field is 0x0, the
@@ -101,9 +99,9 @@
"recv data bad frame client id");
}
- Http2Stream *stream = cstate.find_stream(id);
+ Http2Stream *stream = this->find_stream(id);
if (stream == nullptr) {
- if (cstate.is_valid_streamid(id)) {
+ if (this->is_valid_streamid(id)) {
// This error occurs fairly often, and is probably innocuous (SM initiates the shutdown)
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED, nullptr);
} else {
@@ -137,7 +135,7 @@
if (frame.header().flags & HTTP2_FLAGS_DATA_END_STREAM) {
stream->recv_end_stream = true;
if (!stream->change_state(frame.header().type, frame.header().flags)) {
- cstate.send_rst_stream_frame(id, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED);
+ this->send_rst_stream_frame(id, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED);
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
}
if (!stream->payload_length_is_valid()) {
@@ -158,7 +156,7 @@
}
// Check whether Window Size is acceptable
- if (cstate.server_rwnd() < payload_length) {
+ if (this->server_rwnd() < payload_length) {
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_FLOW_CONTROL_ERROR,
"recv data cstate.server_rwnd < payload_length");
}
@@ -168,12 +166,12 @@
}
// Update Window size
- cstate.decrement_server_rwnd(payload_length);
+ this->decrement_server_rwnd(payload_length);
stream->decrement_server_rwnd(payload_length);
if (is_debug_tag_set("http2_con")) {
- uint32_t rwnd = cstate.server_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE);
- Http2StreamDebug(cstate.session, id, "Received DATA frame: rwnd con=%zd/%" PRId32 " stream=%zd/%" PRId32, cstate.server_rwnd(),
+ uint32_t rwnd = this->server_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE);
+ Http2StreamDebug(this->session, id, "Received DATA frame: rwnd con=%zd/%" PRId32 " stream=%zd/%" PRId32, this->server_rwnd(),
rwnd, stream->server_rwnd(), rwnd);
}
@@ -225,13 +223,13 @@
* 2. A HEADERS frame without the END_HEADERS flag set MUST be followed by a
* CONTINUATION frame
*/
-static Http2Error
-rcv_headers_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
+Http2Error
+Http2ConnectionState::rcv_headers_frame(const Http2Frame &frame)
{
const Http2StreamId stream_id = frame.header().streamid;
const uint32_t payload_length = frame.header().length;
- Http2StreamDebug(cstate.session, stream_id, "Received HEADERS frame");
+ Http2StreamDebug(this->session, stream_id, "Received HEADERS frame");
if (!http2_is_client_streamid(stream_id)) {
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
@@ -241,8 +239,8 @@
Http2Stream *stream = nullptr;
bool new_stream = false;
- if (cstate.is_valid_streamid(stream_id)) {
- stream = cstate.find_stream(stream_id);
+ if (this->is_valid_streamid(stream_id)) {
+ stream = this->find_stream(stream_id);
if (stream == nullptr) {
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED,
"recv headers cannot find existing stream_id");
@@ -256,7 +254,7 @@
} else {
// Create new stream
Http2Error error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
- stream = cstate.create_stream(stream_id, error);
+ stream = this->create_stream(stream_id, error);
new_stream = true;
if (!stream) {
return error;
@@ -322,17 +320,17 @@
}
if (new_stream && Http2::stream_priority_enabled) {
- Http2DependencyTree::Node *node = cstate.dependency_tree->find(stream_id);
+ Http2DependencyTree::Node *node = this->dependency_tree->find(stream_id);
if (node != nullptr) {
stream->priority_node = node;
node->t = stream;
} else {
- Http2StreamDebug(cstate.session, stream_id, "HEADER PRIORITY - dep: %d, weight: %d, excl: %d, tree size: %d",
+ Http2StreamDebug(this->session, stream_id, "HEADER PRIORITY - dep: %d, weight: %d, excl: %d, tree size: %d",
params.priority.stream_dependency, params.priority.weight, params.priority.exclusive_flag,
- cstate.dependency_tree->size());
+ this->dependency_tree->size());
- stream->priority_node = cstate.dependency_tree->add(params.priority.stream_dependency, stream_id, params.priority.weight,
- params.priority.exclusive_flag, stream);
+ stream->priority_node = this->dependency_tree->add(params.priority.stream_dependency, stream_id, params.priority.weight,
+ params.priority.exclusive_flag, stream);
}
}
@@ -371,7 +369,7 @@
stream->mark_milestone(Http2StreamMilestone::START_DECODE_HEADERS);
Http2ErrorCode result =
- stream->decode_header_blocks(*cstate.local_hpack_handle, cstate.server_settings.get(HTTP2_SETTINGS_HEADER_TABLE_SIZE));
+ stream->decode_header_blocks(*this->local_hpack_handle, this->server_settings.get(HTTP2_SETTINGS_HEADER_TABLE_SIZE));
if (result != Http2ErrorCode::HTTP2_ERROR_NO_ERROR) {
if (result == Http2ErrorCode::HTTP2_ERROR_COMPRESSION_ERROR) {
@@ -392,7 +390,7 @@
stream->mark_milestone(Http2StreamMilestone::START_TXN);
stream->new_transaction(frame.is_from_early_data());
// Send request header to SM
- stream->send_request(cstate);
+ stream->send_request(*this);
} else {
// Signal VC_EVENT_READ_COMPLETE because received trailing header fields with END_STREAM flag
stream->signal_read_event(VC_EVENT_READ_COMPLETE);
@@ -400,8 +398,8 @@
} else {
// NOTE: Expect CONTINUATION Frame. Do NOT change state of stream or decode
// Header Blocks.
- Http2StreamDebug(cstate.session, stream_id, "No END_HEADERS flag, expecting CONTINUATION frame");
- cstate.set_continued_stream_id(stream_id);
+ Http2StreamDebug(this->session, stream_id, "No END_HEADERS flag, expecting CONTINUATION frame");
+ this->set_continued_stream_id(stream_id);
}
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
@@ -411,16 +409,16 @@
* [RFC 7540] 6.3 PRIORITY
*
*/
-static Http2Error
-rcv_priority_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
+Http2Error
+Http2ConnectionState::rcv_priority_frame(const Http2Frame &frame)
{
const Http2StreamId stream_id = frame.header().streamid;
const uint32_t payload_length = frame.header().length;
- Http2StreamDebug(cstate.session, stream_id, "Received PRIORITY frame");
+ Http2StreamDebug(this->session, stream_id, "Received PRIORITY frame");
- if (cstate.get_zombie_event()) {
- Warning("Priority frame for zombied session %" PRId64, cstate.session->get_connection_id());
+ if (this->get_zombie_event()) {
+ Warning("Priority frame for zombied session %" PRId64, this->session->get_connection_id());
}
// If a PRIORITY frame is received with a stream identifier of 0x0, the
@@ -457,53 +455,53 @@
}
// Update PRIORITY frame count per minute
- cstate.increment_received_priority_frame_count();
+ this->increment_received_priority_frame_count();
// Close this connection if its priority frame count received exceeds a limit
if (Http2::max_priority_frames_per_minute != 0 &&
- cstate.get_received_priority_frame_count() > Http2::max_priority_frames_per_minute) {
+ this->get_received_priority_frame_count() > Http2::max_priority_frames_per_minute) {
HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_MAX_PRIORITY_FRAMES_PER_MINUTE_EXCEEDED, this_ethread());
- Http2StreamDebug(cstate.session, stream_id, "Observed too frequent priority changes: %u priority changes within a last minute",
- cstate.get_received_priority_frame_count());
+ Http2StreamDebug(this->session, stream_id, "Observed too frequent priority changes: %u priority changes within a last minute",
+ this->get_received_priority_frame_count());
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
"recv priority too frequent priority changes");
}
- Http2StreamDebug(cstate.session, stream_id, "PRIORITY - dep: %d, weight: %d, excl: %d, tree size: %d", priority.stream_dependency,
- priority.weight, priority.exclusive_flag, cstate.dependency_tree->size());
+ Http2StreamDebug(this->session, stream_id, "PRIORITY - dep: %d, weight: %d, excl: %d, tree size: %d", priority.stream_dependency,
+ priority.weight, priority.exclusive_flag, this->dependency_tree->size());
- Http2DependencyTree::Node *node = cstate.dependency_tree->find(stream_id);
+ Http2DependencyTree::Node *node = this->dependency_tree->find(stream_id);
if (node != nullptr) {
// [RFC 7540] 5.3.3 Reprioritization
- Http2StreamDebug(cstate.session, stream_id, "Reprioritize");
- cstate.dependency_tree->reprioritize(node, priority.stream_dependency, priority.exclusive_flag);
+ Http2StreamDebug(this->session, stream_id, "Reprioritize");
+ this->dependency_tree->reprioritize(node, priority.stream_dependency, priority.exclusive_flag);
if (is_debug_tag_set("http2_priority")) {
std::stringstream output;
- cstate.dependency_tree->dump_tree(output);
- Debug("http2_priority", "[%" PRId64 "] reprioritize %s", cstate.session->get_connection_id(), output.str().c_str());
+ this->dependency_tree->dump_tree(output);
+ Debug("http2_priority", "[%" PRId64 "] reprioritize %s", this->session->get_connection_id(), output.str().c_str());
}
} else {
// PRIORITY frame is received before HEADERS frame.
// Restrict number of inactive node in dependency tree smaller than max_concurrent_streams.
// Current number of inactive node is size of tree minus active node count.
- if (Http2::max_concurrent_streams_in > cstate.dependency_tree->size() - cstate.get_client_stream_count() + 1) {
- cstate.dependency_tree->add(priority.stream_dependency, stream_id, priority.weight, priority.exclusive_flag, nullptr);
+ if (Http2::max_concurrent_streams_in > this->dependency_tree->size() - this->get_client_stream_count() + 1) {
+ this->dependency_tree->add(priority.stream_dependency, stream_id, priority.weight, priority.exclusive_flag, nullptr);
}
}
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
}
-static Http2Error
-rcv_rst_stream_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
+Http2Error
+Http2ConnectionState::rcv_rst_stream_frame(const Http2Frame &frame)
{
Http2RstStream rst_stream;
char buf[HTTP2_RST_STREAM_LEN];
char *end;
const Http2StreamId stream_id = frame.header().streamid;
- Http2StreamDebug(cstate.session, frame.header().streamid, "Received RST_STREAM frame");
+ Http2StreamDebug(this->session, frame.header().streamid, "Received RST_STREAM frame");
// RST_STREAM frames MUST be associated with a stream. If a RST_STREAM
// frame is received with a stream identifier of 0x0, the recipient MUST
@@ -514,9 +512,9 @@
"reset access stream with invalid id");
}
- Http2Stream *stream = cstate.find_stream(stream_id);
+ Http2Stream *stream = this->find_stream(stream_id);
if (stream == nullptr) {
- if (cstate.is_valid_streamid(stream_id)) {
+ if (this->is_valid_streamid(stream_id)) {
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
} else {
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
@@ -546,7 +544,7 @@
}
if (stream != nullptr) {
- Http2StreamDebug(cstate.session, stream_id, "RST_STREAM: Error Code: %u", rst_stream.error_code);
+ Http2StreamDebug(this->session, stream_id, "RST_STREAM: Error Code: %u", rst_stream.error_code);
stream->set_rx_error_code({ProxyErrorClass::TXN, static_cast<uint32_t>(rst_stream.error_code)});
stream->initiating_close();
@@ -555,27 +553,27 @@
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
}
-static Http2Error
-rcv_settings_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
+Http2Error
+Http2ConnectionState::rcv_settings_frame(const Http2Frame &frame)
{
Http2SettingsParameter param;
char buf[HTTP2_SETTINGS_PARAMETER_LEN];
unsigned nbytes = 0;
const Http2StreamId stream_id = frame.header().streamid;
- Http2StreamDebug(cstate.session, stream_id, "Received SETTINGS frame");
+ Http2StreamDebug(this->session, stream_id, "Received SETTINGS frame");
- if (cstate.get_zombie_event()) {
- Warning("Setting frame for zombied session %" PRId64, cstate.session->get_connection_id());
+ if (this->get_zombie_event()) {
+ Warning("Setting frame for zombied session %" PRId64, this->session->get_connection_id());
}
// Update SETTIGNS frame count per minute
- cstate.increment_received_settings_frame_count();
+ this->increment_received_settings_frame_count();
// Close this connection if its SETTINGS frame count exceeds a limit
- if (cstate.get_received_settings_frame_count() > Http2::max_settings_frames_per_minute) {
+ if (this->get_received_settings_frame_count() > Http2::max_settings_frames_per_minute) {
HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_MAX_SETTINGS_FRAMES_PER_MINUTE_EXCEEDED, this_ethread());
- Http2StreamDebug(cstate.session, stream_id, "Observed too frequent SETTINGS frames: %u frames within a last minute",
- cstate.get_received_settings_frame_count());
+ Http2StreamDebug(this->session, stream_id, "Observed too frequent SETTINGS frames: %u frames within a last minute",
+ this->get_received_settings_frame_count());
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
"recv settings too frequent SETTINGS frames");
}
@@ -613,7 +611,7 @@
while (nbytes < frame.header().length) {
if (n_settings >= Http2::max_settings_per_frame) {
HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_MAX_SETTINGS_PER_FRAME_EXCEEDED, this_ethread());
- Http2StreamDebug(cstate.session, stream_id, "Observed too many settings in a frame");
+ Http2StreamDebug(this->session, stream_id, "Observed too many settings in a frame");
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
"recv settings too many settings in a frame");
}
@@ -635,27 +633,27 @@
}
}
- Http2StreamDebug(cstate.session, stream_id, " %s : %u", Http2DebugNames::get_settings_param_name(param.id), param.value);
+ Http2StreamDebug(this->session, stream_id, " %s : %u", Http2DebugNames::get_settings_param_name(param.id), param.value);
// [RFC 7540] 6.9.2. When the value of SETTINGS_INITIAL_WINDOW_SIZE
// changes, a receiver MUST adjust the size of all stream flow control
// windows that it maintains by the difference between the new value and
// the old value.
if (param.id == HTTP2_SETTINGS_INITIAL_WINDOW_SIZE) {
- cstate.update_initial_rwnd(param.value);
+ this->update_initial_rwnd(param.value);
}
- cstate.client_settings.set(static_cast<Http2SettingsIdentifier>(param.id), param.value);
+ this->client_settings.set(static_cast<Http2SettingsIdentifier>(param.id), param.value);
++n_settings;
}
// Update settings count per minute
- cstate.increment_received_settings_count(n_settings);
+ this->increment_received_settings_count(n_settings);
// Close this connection if its settings count received exceeds a limit
- if (cstate.get_received_settings_count() > Http2::max_settings_per_minute) {
+ if (this->get_received_settings_count() > Http2::max_settings_per_minute) {
HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_MAX_SETTINGS_PER_MINUTE_EXCEEDED, this_ethread());
- Http2StreamDebug(cstate.session, stream_id, "Observed too frequent setting changes: %u settings within a last minute",
- cstate.get_received_settings_count());
+ Http2StreamDebug(this->session, stream_id, "Observed too frequent setting changes: %u settings within a last minute",
+ this->get_received_settings_count());
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
"recv settings too frequent setting changes");
}
@@ -663,15 +661,15 @@
// [RFC 7540] 6.5. Once all values have been applied, the recipient MUST
// immediately emit a SETTINGS frame with the ACK flag set.
Http2SettingsFrame ack_frame(0, HTTP2_FLAGS_SETTINGS_ACK);
- cstate.session->xmit(ack_frame);
+ this->session->xmit(ack_frame);
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
}
-static Http2Error
-rcv_push_promise_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
+Http2Error
+Http2ConnectionState::rcv_push_promise_frame(const Http2Frame &frame)
{
- Http2StreamDebug(cstate.session, frame.header().streamid, "Received PUSH_PROMISE frame");
+ Http2StreamDebug(this->session, frame.header().streamid, "Received PUSH_PROMISE frame");
// [RFC 7540] 8.2. A client cannot push. Thus, servers MUST treat the receipt of a
// PUSH_PROMISE frame as a connection error of type PROTOCOL_ERROR.
@@ -679,15 +677,15 @@
"promise not allowed");
}
-static Http2Error
-rcv_ping_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
+Http2Error
+Http2ConnectionState::rcv_ping_frame(const Http2Frame &frame)
{
uint8_t opaque_data[HTTP2_PING_LEN];
const Http2StreamId stream_id = frame.header().streamid;
- Http2StreamDebug(cstate.session, stream_id, "Received PING frame");
+ Http2StreamDebug(this->session, stream_id, "Received PING frame");
- cstate.schedule_zombie_event();
+ this->schedule_zombie_event();
// If a PING frame is received with a stream identifier field value other
// than 0x0, the recipient MUST respond with a connection error of type
@@ -704,12 +702,12 @@
}
// Update PING frame count per minute
- cstate.increment_received_ping_frame_count();
+ this->increment_received_ping_frame_count();
// Close this connection if its ping count received exceeds a limit
- if (cstate.get_received_ping_frame_count() > Http2::max_ping_frames_per_minute) {
+ if (this->get_received_ping_frame_count() > Http2::max_ping_frames_per_minute) {
HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_MAX_PING_FRAMES_PER_MINUTE_EXCEEDED, this_ethread());
- Http2StreamDebug(cstate.session, stream_id, "Observed too frequent PING frames: %u PING frames within a last minute",
- cstate.get_received_ping_frame_count());
+ Http2StreamDebug(this->session, stream_id, "Observed too frequent PING frames: %u PING frames within a last minute",
+ this->get_received_ping_frame_count());
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
"recv ping too frequent PING frame");
}
@@ -722,20 +720,20 @@
frame.reader()->memcpy(opaque_data, HTTP2_PING_LEN, 0);
// ACK (0x1): An endpoint MUST set this flag in PING responses.
- cstate.send_ping_frame(stream_id, HTTP2_FLAGS_PING_ACK, opaque_data);
+ this->send_ping_frame(stream_id, HTTP2_FLAGS_PING_ACK, opaque_data);
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
}
-static Http2Error
-rcv_goaway_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
+Http2Error
+Http2ConnectionState::rcv_goaway_frame(const Http2Frame &frame)
{
Http2Goaway goaway;
char buf[HTTP2_GOAWAY_LEN];
unsigned nbytes = 0;
const Http2StreamId stream_id = frame.header().streamid;
- Http2StreamDebug(cstate.session, stream_id, "Received GOAWAY frame");
+ Http2StreamDebug(this->session, stream_id, "Received GOAWAY frame");
// An endpoint MUST treat a GOAWAY frame with a stream identifier other
// than 0x0 as a connection error of type PROTOCOL_ERROR.
@@ -753,17 +751,17 @@
}
}
- Http2StreamDebug(cstate.session, stream_id, "GOAWAY: last stream id=%d, error code=%d", goaway.last_streamid,
+ Http2StreamDebug(this->session, stream_id, "GOAWAY: last stream id=%d, error code=%d", goaway.last_streamid,
static_cast<int>(goaway.error_code));
- cstate.rx_error_code = {ProxyErrorClass::SSN, static_cast<uint32_t>(goaway.error_code)};
- cstate.session->get_proxy_session()->do_io_close();
+ this->rx_error_code = {ProxyErrorClass::SSN, static_cast<uint32_t>(goaway.error_code)};
+ this->session->get_proxy_session()->do_io_close();
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
}
-static Http2Error
-rcv_window_update_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
+Http2Error
+Http2ConnectionState::rcv_window_update_frame(const Http2Frame &frame)
{
char buf[HTTP2_WINDOW_UPDATE_LEN];
uint32_t size;
@@ -772,7 +770,7 @@
// A WINDOW_UPDATE frame with a length other than 4 octets MUST be
// treated as a connection error of type FRAME_SIZE_ERROR.
if (frame.header().length != HTTP2_WINDOW_UPDATE_LEN) {
- Http2StreamDebug(cstate.session, stream_id, "Received WINDOW_UPDATE frame - length incorrect");
+ Http2StreamDebug(this->session, stream_id, "Received WINDOW_UPDATE frame - length incorrect");
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_FRAME_SIZE_ERROR,
"window update bad length");
}
@@ -794,8 +792,8 @@
if (stream_id == 0) {
// Connection level window update
- Http2StreamDebug(cstate.session, stream_id, "Received WINDOW_UPDATE frame - updated to: %zd delta: %u",
- (cstate.client_rwnd() + size), size);
+ Http2StreamDebug(this->session, stream_id, "Received WINDOW_UPDATE frame - updated to: %zd delta: %u",
+ (this->client_rwnd() + size), size);
// A sender MUST NOT allow a flow-control window to exceed 2^31-1
// octets. If a sender receives a WINDOW_UPDATE that causes a flow-
@@ -804,23 +802,23 @@
// sends a RST_STREAM with an error code of FLOW_CONTROL_ERROR; for the
// connection, a GOAWAY frame with an error code of FLOW_CONTROL_ERROR
// is sent.
- if (size > HTTP2_MAX_WINDOW_SIZE - cstate.client_rwnd()) {
+ if (size > HTTP2_MAX_WINDOW_SIZE - this->client_rwnd()) {
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_FLOW_CONTROL_ERROR,
"window update too big");
}
- auto error = cstate.increment_client_rwnd(size);
+ auto error = this->increment_client_rwnd(size);
if (error != Http2ErrorCode::HTTP2_ERROR_NO_ERROR) {
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, error, "Erroneous client window update");
}
- cstate.restart_streams();
+ this->restart_streams();
} else {
// Stream level window update
- Http2Stream *stream = cstate.find_stream(stream_id);
+ Http2Stream *stream = this->find_stream(stream_id);
if (stream == nullptr) {
- if (cstate.is_valid_streamid(stream_id)) {
+ if (this->is_valid_streamid(stream_id)) {
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
} else {
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
@@ -828,7 +826,7 @@
}
}
- Http2StreamDebug(cstate.session, stream_id, "Received WINDOW_UPDATE frame - updated to: %zd delta: %u",
+ Http2StreamDebug(this->session, stream_id, "Received WINDOW_UPDATE frame - updated to: %zd delta: %u",
(stream->client_rwnd() + size), size);
// A sender MUST NOT allow a flow-control window to exceed 2^31-1
@@ -848,7 +846,7 @@
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, error);
}
- ssize_t wnd = std::min(cstate.client_rwnd(), stream->client_rwnd());
+ ssize_t wnd = std::min(this->client_rwnd(), stream->client_rwnd());
if (!stream->is_closed() && stream->get_state() == Http2StreamState::HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE && wnd > 0) {
SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread());
stream->restart_sending();
@@ -865,13 +863,13 @@
*7540] 6.2 HEADERS)
*
*/
-static Http2Error
-rcv_continuation_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
+Http2Error
+Http2ConnectionState::rcv_continuation_frame(const Http2Frame &frame)
{
const Http2StreamId stream_id = frame.header().streamid;
const uint32_t payload_length = frame.header().length;
- Http2StreamDebug(cstate.session, stream_id, "Received CONTINUATION frame");
+ Http2StreamDebug(this->session, stream_id, "Received CONTINUATION frame");
if (!http2_is_client_streamid(stream_id)) {
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
@@ -883,9 +881,9 @@
// CONTINUATION frame is received whose stream identifier field is 0x0,
// the recipient MUST respond with a connection error ([RFC 7540] Section
// 5.4.1) of type PROTOCOL_ERROR.
- Http2Stream *stream = cstate.find_stream(stream_id);
+ Http2Stream *stream = this->find_stream(stream_id);
if (stream == nullptr) {
- if (cstate.is_valid_streamid(stream_id)) {
+ if (this->is_valid_streamid(stream_id)) {
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED,
"continuation stream freed with valid id");
} else {
@@ -921,7 +919,7 @@
if (frame.header().flags & HTTP2_FLAGS_HEADERS_END_HEADERS) {
// NOTE: If there are END_HEADERS flag, decode stored Header Blocks.
- cstate.clear_continued_stream_id();
+ this->clear_continued_stream_id();
if (!stream->change_state(HTTP2_FRAME_TYPE_CONTINUATION, frame.header().flags)) {
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
@@ -929,7 +927,7 @@
}
Http2ErrorCode result =
- stream->decode_header_blocks(*cstate.local_hpack_handle, cstate.server_settings.get(HTTP2_SETTINGS_HEADER_TABLE_SIZE));
+ stream->decode_header_blocks(*this->local_hpack_handle, this->server_settings.get(HTTP2_SETTINGS_HEADER_TABLE_SIZE));
if (result != Http2ErrorCode::HTTP2_ERROR_NO_ERROR) {
if (result == Http2ErrorCode::HTTP2_ERROR_COMPRESSION_ERROR) {
@@ -951,28 +949,15 @@
// "from_early_data" flag from the associated HEADERS frame.
stream->new_transaction(frame.is_from_early_data());
// Send request header to SM
- stream->send_request(cstate);
+ stream->send_request(*this);
} else {
// NOTE: Expect another CONTINUATION Frame. Do nothing.
- Http2StreamDebug(cstate.session, stream_id, "No END_HEADERS flag, expecting CONTINUATION frame");
+ Http2StreamDebug(this->session, stream_id, "No END_HEADERS flag, expecting CONTINUATION frame");
}
return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
}
-static const http2_frame_dispatch frame_handlers[HTTP2_FRAME_TYPE_MAX] = {
- rcv_data_frame, // HTTP2_FRAME_TYPE_DATA
- rcv_headers_frame, // HTTP2_FRAME_TYPE_HEADERS
- rcv_priority_frame, // HTTP2_FRAME_TYPE_PRIORITY
- rcv_rst_stream_frame, // HTTP2_FRAME_TYPE_RST_STREAM
- rcv_settings_frame, // HTTP2_FRAME_TYPE_SETTINGS
- rcv_push_promise_frame, // HTTP2_FRAME_TYPE_PUSH_PROMISE
- rcv_ping_frame, // HTTP2_FRAME_TYPE_PING
- rcv_goaway_frame, // HTTP2_FRAME_TYPE_GOAWAY
- rcv_window_update_frame, // HTTP2_FRAME_TYPE_WINDOW_UPDATE
- rcv_continuation_frame, // HTTP2_FRAME_TYPE_CONTINUATION
-};
-
////////
// Http2ConnectionSettings
//
@@ -1148,8 +1133,8 @@
return;
}
- if (frame_handlers[frame->header().type]) {
- error = frame_handlers[frame->header().type](*this, *frame);
+ if (this->_frame_handlers[frame->header().type]) {
+ error = (this->*_frame_handlers[frame->header().type])(*frame);
} else {
error = Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_INTERNAL_ERROR, "no handler");
}
diff --git a/proxy/http2/Http2ConnectionState.h b/proxy/http2/Http2ConnectionState.h
index 5b6384c..9fc8e76 100644
--- a/proxy/http2/Http2ConnectionState.h
+++ b/proxy/http2/Http2ConnectionState.h
@@ -164,6 +164,31 @@
Http2ErrorCode decrement_server_rwnd(size_t amount);
private:
+ Http2Error rcv_data_frame(const Http2Frame &);
+ Http2Error rcv_headers_frame(const Http2Frame &);
+ Http2Error rcv_priority_frame(const Http2Frame &);
+ Http2Error rcv_rst_stream_frame(const Http2Frame &);
+ Http2Error rcv_settings_frame(const Http2Frame &);
+ Http2Error rcv_push_promise_frame(const Http2Frame &);
+ Http2Error rcv_ping_frame(const Http2Frame &);
+ Http2Error rcv_goaway_frame(const Http2Frame &);
+ Http2Error rcv_window_update_frame(const Http2Frame &);
+ Http2Error rcv_continuation_frame(const Http2Frame &);
+
+ using http2_frame_dispatch = Http2Error (Http2ConnectionState::*)(const Http2Frame &);
+ static constexpr http2_frame_dispatch _frame_handlers[HTTP2_FRAME_TYPE_MAX] = {
+ &Http2ConnectionState::rcv_data_frame, // HTTP2_FRAME_TYPE_DATA
+ &Http2ConnectionState::rcv_headers_frame, // HTTP2_FRAME_TYPE_HEADERS
+ &Http2ConnectionState::rcv_priority_frame, // HTTP2_FRAME_TYPE_PRIORITY
+ &Http2ConnectionState::rcv_rst_stream_frame, // HTTP2_FRAME_TYPE_RST_STREAM
+ &Http2ConnectionState::rcv_settings_frame, // HTTP2_FRAME_TYPE_SETTINGS
+ &Http2ConnectionState::rcv_push_promise_frame, // HTTP2_FRAME_TYPE_PUSH_PROMISE
+ &Http2ConnectionState::rcv_ping_frame, // HTTP2_FRAME_TYPE_PING
+ &Http2ConnectionState::rcv_goaway_frame, // HTTP2_FRAME_TYPE_GOAWAY
+ &Http2ConnectionState::rcv_window_update_frame, // HTTP2_FRAME_TYPE_WINDOW_UPDATE
+ &Http2ConnectionState::rcv_continuation_frame, // HTTP2_FRAME_TYPE_CONTINUATION
+ };
+
unsigned _adjust_concurrent_stream();
// NOTE: 'stream_list' has only active streams.