in source/h2_decoder.c [1128:1229]
static struct aws_h2err s_flush_pseudoheaders(struct aws_h2_decoder *decoder) {
struct aws_header_block_in_progress *current_block = &decoder->header_block_in_progress;
if (current_block->malformed) {
goto already_malformed;
}
if (current_block->pseudoheaders_done) {
return AWS_H2ERR_SUCCESS;
}
current_block->pseudoheaders_done = true;
/* s_process_header_field() already checked that we're not mixing request & response pseudoheaders */
bool has_request_pseudoheaders = false;
for (int i = PSEUDOHEADER_METHOD; i <= PSEUDOHEADER_PATH; ++i) {
if (current_block->pseudoheader_values[i] != NULL) {
has_request_pseudoheaders = true;
break;
}
}
bool has_response_pseudoheaders = current_block->pseudoheader_values[PSEUDOHEADER_STATUS] != NULL;
if (current_block->is_push_promise && !has_request_pseudoheaders) {
DECODER_LOG(ERROR, decoder, "PUSH_PROMISE is missing :method");
goto malformed;
}
if (has_request_pseudoheaders) {
/* Request header-block. */
current_block->block_type = AWS_HTTP_HEADER_BLOCK_MAIN;
} else if (has_response_pseudoheaders) {
/* Response header block. */
/* Determine whether this is an Informational (1xx) response */
struct aws_byte_cursor status_value =
aws_byte_cursor_from_string(current_block->pseudoheader_values[PSEUDOHEADER_STATUS]);
uint64_t status_code;
if (status_value.len != 3 || aws_byte_cursor_utf8_parse_u64(status_value, &status_code)) {
DECODER_LOG(ERROR, decoder, ":status header has invalid value");
DECODER_LOGF(DEBUG, decoder, "Bad :status value is '" PRInSTR "'", AWS_BYTE_CURSOR_PRI(status_value));
goto malformed;
}
if (status_code / 100 == 1) {
current_block->block_type = AWS_HTTP_HEADER_BLOCK_INFORMATIONAL;
if (current_block->ends_stream) {
/* Informational headers do not constitute a full response (RFC-7540 8.1) */
DECODER_LOG(ERROR, decoder, "Informational (1xx) response cannot END_STREAM");
goto malformed;
}
} else {
current_block->block_type = AWS_HTTP_HEADER_BLOCK_MAIN;
}
} else {
/* Trailing header block. */
if (!current_block->ends_stream) {
DECODER_LOG(ERROR, decoder, "HEADERS appear to be trailer, but lack END_STREAM");
goto malformed;
}
current_block->block_type = AWS_HTTP_HEADER_BLOCK_TRAILING;
}
/* #TODO RFC-7540 8.1.2.3 & 8.3 Validate request has correct pseudoheaders. Note different rules for CONNECT */
/* #TODO validate pseudoheader values. each one has its own special rules */
/* Finally, deliver header-fields via callback */
for (size_t i = 0; i < PSEUDOHEADER_COUNT; ++i) {
const struct aws_string *value_string = current_block->pseudoheader_values[i];
if (value_string) {
struct aws_http_header header_field = {
.name = *s_pseudoheader_name_to_cursor[i],
.value = aws_byte_cursor_from_string(value_string),
.compression = current_block->pseudoheader_compression[i],
};
enum aws_http_header_name name_enum = s_pseudoheader_to_header_name[i];
if (current_block->is_push_promise) {
DECODER_CALL_VTABLE_STREAM_ARGS(decoder, on_push_promise_i, &header_field, name_enum);
} else {
DECODER_CALL_VTABLE_STREAM_ARGS(
decoder, on_headers_i, &header_field, name_enum, current_block->block_type);
}
}
}
return AWS_H2ERR_SUCCESS;
malformed:
/* A malformed header-block is not a connection error, it's a Stream Error (RFC-7540 5.4.2).
* We continue decoding and report that it's malformed in on_headers_end(). */
current_block->malformed = true;
return AWS_H2ERR_SUCCESS;
already_malformed:
return AWS_H2ERR_SUCCESS;
}