in source/h2_decoder.c [570:684]
static struct aws_h2err s_state_fn_prefix(struct aws_h2_decoder *decoder, struct aws_byte_cursor *input) {
AWS_ASSERT(input->len >= s_state_prefix_requires_9_bytes);
struct aws_frame_in_progress *frame = &decoder->frame_in_progress;
uint8_t raw_type = 0;
uint8_t raw_flags = 0;
/* Read the raw values from the first 9 bytes */
bool all_read = true;
all_read &= aws_byte_cursor_read_be24(input, &frame->payload_len);
all_read &= aws_byte_cursor_read_u8(input, &raw_type);
all_read &= aws_byte_cursor_read_u8(input, &raw_flags);
all_read &= aws_byte_cursor_read_be32(input, &frame->stream_id);
AWS_ASSERT(all_read);
(void)all_read;
/* Validate frame type */
frame->type = raw_type < AWS_H2_FRAME_T_UNKNOWN ? raw_type : AWS_H2_FRAME_T_UNKNOWN;
/* Validate the frame's flags
* Flags that have no defined semantics for a particular frame type MUST be ignored (RFC-7540 4.1) */
const uint8_t flags = raw_flags & s_acceptable_flags_for_frame[decoder->frame_in_progress.type];
bool is_padded = flags & AWS_H2_FRAME_F_PADDED;
decoder->frame_in_progress.flags.ack = flags & AWS_H2_FRAME_F_ACK;
decoder->frame_in_progress.flags.end_stream = flags & AWS_H2_FRAME_F_END_STREAM;
decoder->frame_in_progress.flags.end_headers = flags & AWS_H2_FRAME_F_END_HEADERS;
decoder->frame_in_progress.flags.priority =
flags & AWS_H2_FRAME_F_PRIORITY || decoder->frame_in_progress.type == AWS_H2_FRAME_T_PRIORITY;
/* Connection preface requires that SETTINGS be sent first (RFC-7540 3.5).
* This should be the first error we check for, so that a connection sending
* total garbage data is likely to trigger this PROTOCOL_ERROR */
if (!decoder->connection_preface_complete) {
if (frame->type == AWS_H2_FRAME_T_SETTINGS && !frame->flags.ack) {
DECODER_LOG(TRACE, decoder, "Connection preface satisfied.");
decoder->connection_preface_complete = true;
} else {
DECODER_LOG(ERROR, decoder, "First frame must be SETTINGS");
return aws_h2err_from_h2_code(AWS_HTTP2_ERR_PROTOCOL_ERROR);
}
}
/* Validate the frame's stream ID. */
/* Reserved bit (1st bit) MUST be ignored when receiving (RFC-7540 4.1) */
frame->stream_id &= s_31_bit_mask;
/* Some frame types require a stream ID, some frame types require that stream ID be zero. */
const enum stream_id_rules stream_id_rules = s_stream_id_rules_for_frame[frame->type];
if (frame->stream_id) {
if (stream_id_rules == STREAM_ID_FORBIDDEN) {
DECODER_LOGF(ERROR, decoder, "Stream ID for %s frame must be 0.", aws_h2_frame_type_to_str(frame->type));
return aws_h2err_from_h2_code(AWS_HTTP2_ERR_PROTOCOL_ERROR);
}
} else {
if (stream_id_rules == STREAM_ID_REQUIRED) {
DECODER_LOGF(ERROR, decoder, "Stream ID for %s frame cannot be 0.", aws_h2_frame_type_to_str(frame->type));
return aws_h2err_from_h2_code(AWS_HTTP2_ERR_PROTOCOL_ERROR);
}
}
/* A header-block starts with a HEADERS or PUSH_PROMISE frame, followed by 0 or more CONTINUATION frames.
* It's an error for any other frame-type or stream ID to arrive while a header-block is in progress.
* (RFC-7540 4.3) */
if (frame->type == AWS_H2_FRAME_T_CONTINUATION) {
if (decoder->header_block_in_progress.stream_id != frame->stream_id) {
DECODER_LOG(ERROR, decoder, "Unexpected CONTINUATION frame.");
return aws_h2err_from_h2_code(AWS_HTTP2_ERR_PROTOCOL_ERROR);
}
} else {
if (decoder->header_block_in_progress.stream_id) {
DECODER_LOG(ERROR, decoder, "Expected CONTINUATION frame.");
return aws_h2err_from_h2_code(AWS_HTTP2_ERR_PROTOCOL_ERROR);
}
}
/* Validate payload length. */
uint32_t max_frame_size = decoder->settings.max_frame_size;
if (frame->payload_len > max_frame_size) {
DECODER_LOGF(
ERROR,
decoder,
"Decoder's max frame size is %" PRIu32 ", but frame of size %" PRIu32 " was received.",
max_frame_size,
frame->payload_len);
return aws_h2err_from_h2_code(AWS_HTTP2_ERR_FRAME_SIZE_ERROR);
}
DECODER_LOGF(
TRACE,
decoder,
"Done decoding frame prefix (type=%s stream-id=%" PRIu32 " payload-len=%" PRIu32 "), moving on to payload",
aws_h2_frame_type_to_str(frame->type),
frame->stream_id,
frame->payload_len);
if (is_padded) {
/* Read padding length if necessary */
return s_decoder_switch_state(decoder, &s_state_padding_len);
}
if (decoder->frame_in_progress.type == AWS_H2_FRAME_T_DATA) {
/* We invoke the on_data_begin here to report the whole payload size */
DECODER_CALL_VTABLE_STREAM_ARGS(
decoder, on_data_begin, frame->payload_len, 0 /*padding_len*/, frame->flags.end_stream);
}
if (decoder->frame_in_progress.flags.priority) {
/* Read the stream dependency and weight if PRIORITY is set */
return s_decoder_switch_state(decoder, &s_state_priority_block);
}
/* Set the state to the appropriate frame's state */
return s_decoder_switch_to_frame_state(decoder);
}