static struct aws_h2err s_state_fn_prefix()

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);
}