|
|
@ -1524,14 +1524,15 @@ static int session_predicate_response_headers_send(nghttp2_session *session, |
|
|
|
if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { |
|
|
|
return NGHTTP2_ERR_INVALID_STREAM_ID; |
|
|
|
} |
|
|
|
if (stream->state == NGHTTP2_STREAM_OPENING) { |
|
|
|
switch (stream->state) { |
|
|
|
case NGHTTP2_STREAM_OPENING: |
|
|
|
return 0; |
|
|
|
} |
|
|
|
if (stream->state == NGHTTP2_STREAM_CLOSING) { |
|
|
|
case NGHTTP2_STREAM_CLOSING: |
|
|
|
return NGHTTP2_ERR_STREAM_CLOSING; |
|
|
|
} |
|
|
|
default: |
|
|
|
return NGHTTP2_ERR_INVALID_STREAM_STATE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* This function checks HEADERS for reserved stream can be sent. The |
|
|
@ -1573,9 +1574,6 @@ session_predicate_push_response_headers_send(nghttp2_session *session, |
|
|
|
if (stream->state != NGHTTP2_STREAM_RESERVED) { |
|
|
|
return NGHTTP2_ERR_PROTO; |
|
|
|
} |
|
|
|
if (stream->state == NGHTTP2_STREAM_CLOSING) { |
|
|
|
return NGHTTP2_ERR_STREAM_CLOSING; |
|
|
|
} |
|
|
|
if (session->goaway_flags & NGHTTP2_GOAWAY_RECV) { |
|
|
|
return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED; |
|
|
|
} |
|
|
@ -1610,20 +1608,19 @@ static int session_predicate_headers_send(nghttp2_session *session, |
|
|
|
return rv; |
|
|
|
} |
|
|
|
assert(stream); |
|
|
|
if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { |
|
|
|
if (stream->state == NGHTTP2_STREAM_CLOSING) { |
|
|
|
return NGHTTP2_ERR_STREAM_CLOSING; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
if (stream->state == NGHTTP2_STREAM_OPENED) { |
|
|
|
|
|
|
|
switch (stream->state) { |
|
|
|
case NGHTTP2_STREAM_OPENED: |
|
|
|
return 0; |
|
|
|
} |
|
|
|
if (stream->state == NGHTTP2_STREAM_CLOSING) { |
|
|
|
case NGHTTP2_STREAM_CLOSING: |
|
|
|
return NGHTTP2_ERR_STREAM_CLOSING; |
|
|
|
default: |
|
|
|
if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
return NGHTTP2_ERR_INVALID_STREAM_STATE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* This function checks PUSH_PROMISE frame |frame| with the |stream| |
|
|
@ -2068,14 +2065,6 @@ static int session_prep_frame(nghttp2_session *session, |
|
|
|
/* We don't call nghttp2_session_adjust_closed_stream() here,
|
|
|
|
since we don't keep closed stream in client side */ |
|
|
|
|
|
|
|
estimated_payloadlen = session_estimate_headers_payload( |
|
|
|
session, frame->headers.nva, frame->headers.nvlen, |
|
|
|
NGHTTP2_PRIORITY_SPECLEN); |
|
|
|
|
|
|
|
if (estimated_payloadlen > session->max_send_header_block_length) { |
|
|
|
return NGHTTP2_ERR_FRAME_SIZE_ERROR; |
|
|
|
} |
|
|
|
|
|
|
|
rv = session_predicate_request_headers_send(session, item); |
|
|
|
if (rv != 0) { |
|
|
|
return rv; |
|
|
@ -2087,14 +2076,6 @@ static int session_prep_frame(nghttp2_session *session, |
|
|
|
} else { |
|
|
|
nghttp2_stream *stream; |
|
|
|
|
|
|
|
estimated_payloadlen = session_estimate_headers_payload( |
|
|
|
session, frame->headers.nva, frame->headers.nvlen, |
|
|
|
NGHTTP2_PRIORITY_SPECLEN); |
|
|
|
|
|
|
|
if (estimated_payloadlen > session->max_send_header_block_length) { |
|
|
|
return NGHTTP2_ERR_FRAME_SIZE_ERROR; |
|
|
|
} |
|
|
|
|
|
|
|
stream = nghttp2_session_get_stream(session, frame->hd.stream_id); |
|
|
|
|
|
|
|
if (stream && stream->state == NGHTTP2_STREAM_RESERVED) { |
|
|
@ -2121,6 +2102,14 @@ static int session_prep_frame(nghttp2_session *session, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
estimated_payloadlen = session_estimate_headers_payload( |
|
|
|
session, frame->headers.nva, frame->headers.nvlen, |
|
|
|
NGHTTP2_PRIORITY_SPECLEN); |
|
|
|
|
|
|
|
if (estimated_payloadlen > session->max_send_header_block_length) { |
|
|
|
return NGHTTP2_ERR_FRAME_SIZE_ERROR; |
|
|
|
} |
|
|
|
|
|
|
|
rv = nghttp2_frame_pack_headers(&session->aob.framebufs, &frame->headers, |
|
|
|
&session->hd_deflater); |
|
|
|
|
|
|
@ -2190,13 +2179,6 @@ static int session_prep_frame(nghttp2_session *session, |
|
|
|
nghttp2_stream *stream; |
|
|
|
size_t estimated_payloadlen; |
|
|
|
|
|
|
|
estimated_payloadlen = session_estimate_headers_payload( |
|
|
|
session, frame->push_promise.nva, frame->push_promise.nvlen, 0); |
|
|
|
|
|
|
|
if (estimated_payloadlen > session->max_send_header_block_length) { |
|
|
|
return NGHTTP2_ERR_FRAME_SIZE_ERROR; |
|
|
|
} |
|
|
|
|
|
|
|
/* stream could be NULL if associated stream was already
|
|
|
|
closed. */ |
|
|
|
stream = nghttp2_session_get_stream(session, frame->hd.stream_id); |
|
|
@ -2209,6 +2191,13 @@ static int session_prep_frame(nghttp2_session *session, |
|
|
|
|
|
|
|
assert(stream); |
|
|
|
|
|
|
|
estimated_payloadlen = session_estimate_headers_payload( |
|
|
|
session, frame->push_promise.nva, frame->push_promise.nvlen, 0); |
|
|
|
|
|
|
|
if (estimated_payloadlen > session->max_send_header_block_length) { |
|
|
|
return NGHTTP2_ERR_FRAME_SIZE_ERROR; |
|
|
|
} |
|
|
|
|
|
|
|
rv = nghttp2_frame_pack_push_promise( |
|
|
|
&session->aob.framebufs, &frame->push_promise, &session->hd_deflater); |
|
|
|
if (rv != 0) { |
|
|
@ -3332,7 +3321,7 @@ static int session_call_on_invalid_header(nghttp2_session *session, |
|
|
|
session, frame, nv->name->base, nv->name->len, nv->value->base, |
|
|
|
nv->value->len, nv->flags, session->user_data); |
|
|
|
} else { |
|
|
|
return 0; |
|
|
|
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; |
|
|
|
} |
|
|
|
|
|
|
|
if (rv == NGHTTP2_ERR_PAUSE || rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { |
|
|
@ -3422,6 +3411,27 @@ static uint32_t get_error_code_from_lib_error_code(int lib_error_code) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Calls on_invalid_frame_recv_callback if it is set to |session|. |
|
|
|
* |
|
|
|
* This function returns 0 if it succeeds, or one of the following |
|
|
|
* negative error codes: |
|
|
|
* |
|
|
|
* NGHTTP2_ERR_CALLBACK_FAILURE |
|
|
|
* User defined callback function fails. |
|
|
|
*/ |
|
|
|
static int session_call_on_invalid_frame_recv_callback(nghttp2_session *session, |
|
|
|
nghttp2_frame *frame, |
|
|
|
int lib_error_code) { |
|
|
|
if (session->callbacks.on_invalid_frame_recv_callback) { |
|
|
|
if (session->callbacks.on_invalid_frame_recv_callback( |
|
|
|
session, frame, lib_error_code, session->user_data) != 0) { |
|
|
|
return NGHTTP2_ERR_CALLBACK_FAILURE; |
|
|
|
} |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int session_handle_invalid_stream2(nghttp2_session *session, |
|
|
|
int32_t stream_id, |
|
|
|
nghttp2_frame *frame, |
|
|
@ -3579,37 +3589,15 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame, |
|
|
|
if (subject_stream && session_enforce_http_messaging(session)) { |
|
|
|
rv = nghttp2_http_on_header(session, subject_stream, frame, &nv, |
|
|
|
trailer); |
|
|
|
if (rv == NGHTTP2_ERR_HTTP_HEADER) { |
|
|
|
DEBUGF("recv: HTTP error: type=%u, id=%d, header %.*s: %.*s\n", |
|
|
|
frame->hd.type, frame->hd.stream_id, (int)nv.name->len, |
|
|
|
nv.name->base, (int)nv.value->len, nv.value->base); |
|
|
|
|
|
|
|
rv = session_call_error_callback( |
|
|
|
session, "Invalid HTTP header field was received: frame type: " |
|
|
|
"%u, stream: %d, name: [%.*s], value: [%.*s]", |
|
|
|
frame->hd.type, frame->hd.stream_id, (int)nv.name->len, |
|
|
|
nv.name->base, (int)nv.value->len, nv.value->base); |
|
|
|
|
|
|
|
if (nghttp2_is_fatal(rv)) { |
|
|
|
return rv; |
|
|
|
} |
|
|
|
|
|
|
|
rv = |
|
|
|
session_handle_invalid_stream2(session, subject_stream->stream_id, |
|
|
|
frame, NGHTTP2_ERR_HTTP_HEADER); |
|
|
|
if (nghttp2_is_fatal(rv)) { |
|
|
|
return rv; |
|
|
|
} |
|
|
|
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; |
|
|
|
} |
|
|
|
|
|
|
|
if (rv == NGHTTP2_ERR_IGN_HTTP_HEADER) { |
|
|
|
/* Don't overwrite rv here */ |
|
|
|
int rv2; |
|
|
|
|
|
|
|
rv2 = session_call_on_invalid_header(session, frame, &nv); |
|
|
|
/* This handles NGHTTP2_ERR_PAUSE and
|
|
|
|
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE as well */ |
|
|
|
if (rv2 == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { |
|
|
|
rv = NGHTTP2_ERR_HTTP_HEADER; |
|
|
|
} else { |
|
|
|
if (rv2 != 0) { |
|
|
|
return rv2; |
|
|
|
} |
|
|
@ -3631,6 +3619,31 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (rv == NGHTTP2_ERR_HTTP_HEADER) { |
|
|
|
DEBUGF("recv: HTTP error: type=%u, id=%d, header %.*s: %.*s\n", |
|
|
|
frame->hd.type, frame->hd.stream_id, (int)nv.name->len, |
|
|
|
nv.name->base, (int)nv.value->len, nv.value->base); |
|
|
|
|
|
|
|
rv = session_call_error_callback( |
|
|
|
session, "Invalid HTTP header field was received: frame type: " |
|
|
|
"%u, stream: %d, name: [%.*s], value: [%.*s]", |
|
|
|
frame->hd.type, frame->hd.stream_id, (int)nv.name->len, |
|
|
|
nv.name->base, (int)nv.value->len, nv.value->base); |
|
|
|
|
|
|
|
if (nghttp2_is_fatal(rv)) { |
|
|
|
return rv; |
|
|
|
} |
|
|
|
|
|
|
|
rv = |
|
|
|
session_handle_invalid_stream2(session, subject_stream->stream_id, |
|
|
|
frame, NGHTTP2_ERR_HTTP_HEADER); |
|
|
|
if (nghttp2_is_fatal(rv)) { |
|
|
|
return rv; |
|
|
|
} |
|
|
|
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; |
|
|
|
} |
|
|
|
} |
|
|
|
if (rv == 0) { |
|
|
|
rv = session_call_on_header(session, frame, &nv); |
|
|
|
/* This handles NGHTTP2_ERR_PAUSE and
|
|
|
@ -4772,11 +4785,13 @@ int nghttp2_session_on_altsvc_received(nghttp2_session *session, |
|
|
|
|
|
|
|
if (frame->hd.stream_id == 0) { |
|
|
|
if (altsvc->origin_len == 0) { |
|
|
|
return 0; |
|
|
|
return session_call_on_invalid_frame_recv_callback(session, frame, |
|
|
|
NGHTTP2_ERR_PROTO); |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (altsvc->origin_len > 0) { |
|
|
|
return 0; |
|
|
|
return session_call_on_invalid_frame_recv_callback(session, frame, |
|
|
|
NGHTTP2_ERR_PROTO); |
|
|
|
} |
|
|
|
|
|
|
|
stream = nghttp2_session_get_stream(session, frame->hd.stream_id); |
|
|
@ -4789,6 +4804,11 @@ int nghttp2_session_on_altsvc_received(nghttp2_session *session, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (altsvc->field_value_len == 0) { |
|
|
|
return session_call_on_invalid_frame_recv_callback(session, frame, |
|
|
|
NGHTTP2_ERR_PROTO); |
|
|
|
} |
|
|
|
|
|
|
|
return session_call_on_frame_received(session, frame); |
|
|
|
} |
|
|
|
|
|
|
@ -5573,8 +5593,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, |
|
|
|
iframe->max_niv = |
|
|
|
iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1; |
|
|
|
|
|
|
|
iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) * |
|
|
|
iframe->max_niv); |
|
|
|
iframe->iv = nghttp2_mem_malloc( |
|
|
|
mem, sizeof(nghttp2_settings_entry) * iframe->max_niv); |
|
|
|
|
|
|
|
if (!iframe->iv) { |
|
|
|
return NGHTTP2_ERR_NOMEM; |
|
|
@ -5951,7 +5971,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, |
|
|
|
|
|
|
|
DEBUGF("recv: origin_len=%zu\n", origin_len); |
|
|
|
|
|
|
|
if (2 + origin_len > iframe->payloadleft) { |
|
|
|
if (origin_len > iframe->payloadleft) { |
|
|
|
busy = 1; |
|
|
|
iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; |
|
|
|
break; |
|
|
@ -6037,7 +6057,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, |
|
|
|
|
|
|
|
/* Use promised stream ID for PUSH_PROMISE */ |
|
|
|
rv = nghttp2_session_add_rst_stream( |
|
|
|
session, iframe->frame.hd.type == NGHTTP2_PUSH_PROMISE |
|
|
|
session, |
|
|
|
iframe->frame.hd.type == NGHTTP2_PUSH_PROMISE |
|
|
|
? iframe->frame.push_promise.promised_stream_id |
|
|
|
: iframe->frame.hd.stream_id, |
|
|
|
NGHTTP2_INTERNAL_ERROR); |
|
|
@ -7129,6 +7150,7 @@ uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session, |
|
|
|
} |
|
|
|
|
|
|
|
assert(0); |
|
|
|
abort(); /* if NDEBUG is set */ |
|
|
|
} |
|
|
|
|
|
|
|
uint32_t nghttp2_session_get_local_settings(nghttp2_session *session, |
|
|
@ -7149,6 +7171,7 @@ uint32_t nghttp2_session_get_local_settings(nghttp2_session *session, |
|
|
|
} |
|
|
|
|
|
|
|
assert(0); |
|
|
|
abort(); /* if NDEBUG is set */ |
|
|
|
} |
|
|
|
|
|
|
|
static int nghttp2_session_upgrade_internal(nghttp2_session *session, |
|
|
|