Skip to content
Merged
Show file tree
Hide file tree
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
67 changes: 58 additions & 9 deletions include/aws/http/private/h2_decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,83 @@
#include <aws/http/private/h2_frames.h>
#include <aws/http/private/http_impl.h>

/* Decoder design goals:
* - Minimize state tracking and verification required by user.
* For example, we have _begin()/_i()/_end() callbacks when something happens N times.
* The _begin() and _end() callbacks tell the user when to transition states.
* Without them the user needs to be like, oh, I was doing X but now I'm doing Y,
* so I guess I need to end X and start Y.
* - A callback should result in 1 distinct action.
* For example, we have distinct callbacks for `on_ping()` and `on_ping_ack()`.
* We COULD have had just one `on_ping(bool ack)` callback, but since user must
* take two complete different actions based on the ACK, we opted for two callbacks.
*/

struct aws_h2_decoder_vtable {
/* For HEADERS header-block: _begin() is called, then 0+ _i() calls, then _end().
* No other decoder callbacks will occur in this time. */
int (*on_headers_begin)(uint32_t stream_id, void *userdata);
int (*on_headers_i)(
uint32_t stream_id,
const struct aws_http_header *header,
enum aws_h2_header_field_hpack_behavior hpack_behavior,
void *userdata);
int (*on_headers_end)(uint32_t stream_id, void *userdata);

int (*on_header)(
/* For PUSH_PROMISE header-block: _begin() is called, then 0+ _i() calls, then _end().
* No other decoder callbacks will occur in this time. */
int (*on_push_promise_begin)(uint32_t stream_id, uint32_t promised_stream_id, void *userdata);
int (*on_push_promise_i)(
uint32_t stream_id,
const struct aws_http_header *header,
enum aws_h2_header_field_hpack_behavior hpack_behavior,
void *userdata);
int (*on_end_headers)(uint32_t stream_id, void *userdata);

int (*on_data)(uint32_t stream_id, const struct aws_byte_cursor *data, void *userdata);
int (*on_push_promise_end)(uint32_t stream_id, void *userdata);

/* Called repeatedly as DATA frames are processed.
* This may fire multiple times per actual DATA frame. */
int (*on_data)(uint32_t stream_id, struct aws_byte_cursor data, void *userdata);

/* Called at end of DATA frame containing the END_STREAM flag.
* OR called at end of header-block which began with HEADERS frame containing the END_STREAM flag */
int (*on_end_stream)(uint32_t stream_id, void *userdata);

/* Called once for RST_STREAM frame */
int (*on_rst_stream)(uint32_t stream_id, uint32_t error_code, void *userdata);

int (*on_push_promise)(uint32_t stream_id, uint32_t promised_stream_id, void *userdata);
/* Called once For PING frame with ACK flag set */
int (*on_ping_ack)(uint8_t opaque_data[AWS_H2_PING_DATA_SIZE], void *userdata);

/* Called once for PING frame (no ACK flag set)*/
int (*on_ping)(uint8_t opaque_data[AWS_H2_PING_DATA_SIZE], void *userdata);

int (*on_ping)(bool ack, uint8_t opaque_data[8], void *userdata);
int (*on_setting)(uint16_t setting, uint32_t value, void *userdata);
/* Called once for SETTINGS frame with ACK flag */
int (*on_settings_ack)(void *userdata);
int (*on_goaway)(uint32_t last_stream, uint32_t error_code, uint32_t debug_data_length, void *userdata);
int (*on_goaway_debug_data)(const struct aws_byte_cursor *data, void *userdata);

/* For SETTINGS frame (no ACK flag set): _begin() is called, then 0+ _i() calls, then _end().
* No other decoder callbacks will occur in this time. */
int (*on_settings_begin)(void *userdata);
int (*on_settings_i)(uint16_t setting_id, uint32_t value, void *userdata);
int (*on_settings_end)(void *userdata);

/* For GOAWAY frame: _begin() is called, then 0+ _i() calls, then _end().
* No other decoder callbacks will occur in this time. */
int (*on_goaway_begin)(uint32_t last_stream, uint32_t error_code, uint32_t debug_data_length, void *userdata);
int (*on_goaway_i)(struct aws_byte_cursor debug_data, void *userdata);
int (*on_goaway_end)(void *userdata);

/* Called once for WINDOW_UPDATE frame */
int (*on_window_update)(uint32_t stream_id, uint32_t window_size_increment, void *userdata);
};

/**
* Structure used to initialize an `aws_h2_decoder`.
*/
struct aws_h2_decoder_params {
struct aws_allocator *alloc;
struct aws_h2_decoder_vtable vtable;
const struct aws_h2_decoder_vtable *vtable;
void *userdata;
void *logging_id;
};
Expand Down
2 changes: 2 additions & 0 deletions include/aws/http/private/h2_frames.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,14 @@ enum aws_h2_error_codes {

/* Predefined settings identifiers (RFC-7540 6.5.2) */
enum aws_h2_settings {
AWS_H2_SETTINGS_BEGIN_RANGE = 0x1, /* Beginning of known values */
AWS_H2_SETTINGS_HEADER_TABLE_SIZE = 0x1,
AWS_H2_SETTINGS_ENABLE_PUSH = 0x2,
AWS_H2_SETTINGS_MAX_CONCURRENT_STREAMS = 0x3,
AWS_H2_SETTINGS_INITIAL_WINDOW_SIZE = 0x4,
AWS_H2_SETTINGS_MAX_FRAME_SIZE = 0x5,
AWS_H2_SETTINGS_MAX_HEADER_LIST_SIZE = 0x6,
AWS_H2_SETTINGS_END_RANGE, /* End of known values */
};

/* RFC-7541 2.4 */
Expand Down
2 changes: 1 addition & 1 deletion source/h2_connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ static struct aws_h2_connection *s_connection_new(
/* Create a new decoder */
struct aws_h2_decoder_params params = {
.alloc = alloc,
.vtable = s_h2_decoder_vtable,
.vtable = &s_h2_decoder_vtable,
.userdata = connection,
.logging_id = connection,
};
Expand Down
Loading