Simplify code
Move DATA frame handling code to switch-case of frame type.
This commit is contained in:
parent
8099dd9558
commit
9d4e8eeb12
|
@ -816,99 +816,96 @@ int nghttp2_session_add_item(nghttp2_session *session,
|
||||||
frame = &item->frame;
|
frame = &item->frame;
|
||||||
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
||||||
|
|
||||||
if (frame->hd.type != NGHTTP2_DATA) {
|
switch (frame->hd.type) {
|
||||||
|
case NGHTTP2_DATA:
|
||||||
switch (frame->hd.type) {
|
if (!stream) {
|
||||||
case NGHTTP2_HEADERS:
|
return NGHTTP2_ERR_STREAM_CLOSED;
|
||||||
/* We push request HEADERS and push response HEADERS to
|
|
||||||
dedicated queue because their transmission is affected by
|
|
||||||
SETTINGS_MAX_CONCURRENT_STREAMS */
|
|
||||||
/* TODO If 2 HEADERS are submitted for reserved stream, then
|
|
||||||
both of them are queued into ob_syn, which is not
|
|
||||||
desirable. */
|
|
||||||
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST ||
|
|
||||||
(stream && stream->state == NGHTTP2_STREAM_RESERVED)) {
|
|
||||||
nghttp2_outbound_queue_push(&session->ob_syn, item);
|
|
||||||
item->queued = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
nghttp2_outbound_queue_push(&session->ob_reg, item);
|
|
||||||
item->queued = 1;
|
|
||||||
break;
|
|
||||||
case NGHTTP2_SETTINGS:
|
|
||||||
case NGHTTP2_PING:
|
|
||||||
nghttp2_outbound_queue_push(&session->ob_urgent, item);
|
|
||||||
item->queued = 1;
|
|
||||||
break;
|
|
||||||
case NGHTTP2_RST_STREAM:
|
|
||||||
if (stream) {
|
|
||||||
stream->state = NGHTTP2_STREAM_CLOSING;
|
|
||||||
}
|
|
||||||
nghttp2_outbound_queue_push(&session->ob_reg, item);
|
|
||||||
item->queued = 1;
|
|
||||||
break;
|
|
||||||
case NGHTTP2_PUSH_PROMISE: {
|
|
||||||
nghttp2_headers_aux_data *aux_data;
|
|
||||||
nghttp2_priority_spec pri_spec;
|
|
||||||
|
|
||||||
aux_data = &item->aux_data.headers;
|
|
||||||
|
|
||||||
if (!stream) {
|
|
||||||
return NGHTTP2_ERR_STREAM_CLOSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
nghttp2_priority_spec_init(&pri_spec, stream->stream_id,
|
|
||||||
NGHTTP2_DEFAULT_WEIGHT, 0);
|
|
||||||
|
|
||||||
if (!nghttp2_session_open_stream(
|
|
||||||
session, frame->push_promise.promised_stream_id,
|
|
||||||
NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_RESERVED,
|
|
||||||
aux_data->stream_user_data)) {
|
|
||||||
return NGHTTP2_ERR_NOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We don't have to call nghttp2_session_adjust_closed_stream()
|
|
||||||
here, since stream->stream_id is local stream_id, and it does
|
|
||||||
not affect closed stream count. */
|
|
||||||
|
|
||||||
nghttp2_outbound_queue_push(&session->ob_reg, item);
|
|
||||||
item->queued = 1;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case NGHTTP2_WINDOW_UPDATE:
|
|
||||||
if (stream) {
|
if (stream->item) {
|
||||||
stream->window_update_queued = 1;
|
return NGHTTP2_ERR_DATA_EXIST;
|
||||||
} else if (frame->hd.stream_id == 0) {
|
}
|
||||||
session->window_update_queued = 1;
|
|
||||||
}
|
rv = nghttp2_stream_attach_item(stream, item);
|
||||||
nghttp2_outbound_queue_push(&session->ob_reg, item);
|
|
||||||
item->queued = 1;
|
if (rv != 0) {
|
||||||
break;
|
return rv;
|
||||||
default:
|
|
||||||
nghttp2_outbound_queue_push(&session->ob_reg, item);
|
|
||||||
item->queued = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case NGHTTP2_HEADERS:
|
||||||
|
/* We push request HEADERS and push response HEADERS to
|
||||||
|
dedicated queue because their transmission is affected by
|
||||||
|
SETTINGS_MAX_CONCURRENT_STREAMS */
|
||||||
|
/* TODO If 2 HEADERS are submitted for reserved stream, then
|
||||||
|
both of them are queued into ob_syn, which is not
|
||||||
|
desirable. */
|
||||||
|
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST ||
|
||||||
|
(stream && stream->state == NGHTTP2_STREAM_RESERVED)) {
|
||||||
|
nghttp2_outbound_queue_push(&session->ob_syn, item);
|
||||||
|
item->queued = 1;
|
||||||
|
return 0;
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_outbound_queue_push(&session->ob_reg, item);
|
||||||
|
item->queued = 1;
|
||||||
|
return 0;
|
||||||
|
case NGHTTP2_SETTINGS:
|
||||||
|
case NGHTTP2_PING:
|
||||||
|
nghttp2_outbound_queue_push(&session->ob_urgent, item);
|
||||||
|
item->queued = 1;
|
||||||
|
return 0;
|
||||||
|
case NGHTTP2_RST_STREAM:
|
||||||
|
if (stream) {
|
||||||
|
stream->state = NGHTTP2_STREAM_CLOSING;
|
||||||
|
}
|
||||||
|
nghttp2_outbound_queue_push(&session->ob_reg, item);
|
||||||
|
item->queued = 1;
|
||||||
|
return 0;
|
||||||
|
case NGHTTP2_PUSH_PROMISE: {
|
||||||
|
nghttp2_headers_aux_data *aux_data;
|
||||||
|
nghttp2_priority_spec pri_spec;
|
||||||
|
|
||||||
|
aux_data = &item->aux_data.headers;
|
||||||
|
|
||||||
|
if (!stream) {
|
||||||
|
return NGHTTP2_ERR_STREAM_CLOSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_priority_spec_init(&pri_spec, stream->stream_id,
|
||||||
|
NGHTTP2_DEFAULT_WEIGHT, 0);
|
||||||
|
|
||||||
|
if (!nghttp2_session_open_stream(
|
||||||
|
session, frame->push_promise.promised_stream_id,
|
||||||
|
NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_RESERVED,
|
||||||
|
aux_data->stream_user_data)) {
|
||||||
|
return NGHTTP2_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We don't have to call nghttp2_session_adjust_closed_stream()
|
||||||
|
here, since stream->stream_id is local stream_id, and it does
|
||||||
|
not affect closed stream count. */
|
||||||
|
|
||||||
|
nghttp2_outbound_queue_push(&session->ob_reg, item);
|
||||||
|
item->queued = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
case NGHTTP2_WINDOW_UPDATE:
|
||||||
if (!stream) {
|
if (stream) {
|
||||||
return NGHTTP2_ERR_STREAM_CLOSED;
|
stream->window_update_queued = 1;
|
||||||
|
} else if (frame->hd.stream_id == 0) {
|
||||||
|
session->window_update_queued = 1;
|
||||||
|
}
|
||||||
|
nghttp2_outbound_queue_push(&session->ob_reg, item);
|
||||||
|
item->queued = 1;
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
nghttp2_outbound_queue_push(&session->ob_reg, item);
|
||||||
|
item->queued = 1;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream->item) {
|
|
||||||
return NGHTTP2_ERR_DATA_EXIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = nghttp2_stream_attach_item(stream, item);
|
|
||||||
|
|
||||||
if (rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
|
int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
|
||||||
|
@ -1941,276 +1938,8 @@ static int session_prep_frame(nghttp2_session *session,
|
||||||
mem = &session->mem;
|
mem = &session->mem;
|
||||||
frame = &item->frame;
|
frame = &item->frame;
|
||||||
|
|
||||||
if (frame->hd.type != NGHTTP2_DATA) {
|
switch (frame->hd.type) {
|
||||||
switch (frame->hd.type) {
|
case NGHTTP2_DATA: {
|
||||||
case NGHTTP2_HEADERS: {
|
|
||||||
nghttp2_headers_aux_data *aux_data;
|
|
||||||
size_t estimated_payloadlen;
|
|
||||||
|
|
||||||
aux_data = &item->aux_data.headers;
|
|
||||||
|
|
||||||
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
|
|
||||||
/* initial HEADERS, which opens stream */
|
|
||||||
nghttp2_stream *stream;
|
|
||||||
|
|
||||||
stream = nghttp2_session_open_stream(
|
|
||||||
session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE,
|
|
||||||
&frame->headers.pri_spec, NGHTTP2_STREAM_INITIAL,
|
|
||||||
aux_data->stream_user_data);
|
|
||||||
|
|
||||||
if (stream == NULL) {
|
|
||||||
return NGHTTP2_ERR_NOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (session_enforce_http_messaging(session)) {
|
|
||||||
nghttp2_http_record_request_method(stream, frame);
|
|
||||||
}
|
|
||||||
} 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) {
|
|
||||||
rv = session_predicate_push_response_headers_send(session, stream);
|
|
||||||
if (rv == 0) {
|
|
||||||
frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE;
|
|
||||||
|
|
||||||
if (aux_data->stream_user_data) {
|
|
||||||
stream->stream_user_data = aux_data->stream_user_data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (session_predicate_response_headers_send(session, stream) ==
|
|
||||||
0) {
|
|
||||||
frame->headers.cat = NGHTTP2_HCAT_RESPONSE;
|
|
||||||
rv = 0;
|
|
||||||
} else {
|
|
||||||
frame->headers.cat = NGHTTP2_HCAT_HEADERS;
|
|
||||||
|
|
||||||
rv = session_predicate_headers_send(session, stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rv != 0) {
|
|
||||||
// If stream was already closed, nghttp2_session_get_stream()
|
|
||||||
// returns NULL, but item is still attached to the stream.
|
|
||||||
// Search stream including closed again.
|
|
||||||
stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id);
|
|
||||||
if (stream && stream->item == item) {
|
|
||||||
int rv2;
|
|
||||||
|
|
||||||
rv2 = nghttp2_stream_detach_item(stream);
|
|
||||||
|
|
||||||
if (nghttp2_is_fatal(rv2)) {
|
|
||||||
return rv2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = nghttp2_frame_pack_headers(&session->aob.framebufs, &frame->headers,
|
|
||||||
&session->hd_deflater);
|
|
||||||
|
|
||||||
if (rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUGF(fprintf(stderr,
|
|
||||||
"send: before padding, HEADERS serialized in %zd bytes\n",
|
|
||||||
nghttp2_bufs_len(&session->aob.framebufs)));
|
|
||||||
|
|
||||||
rv = session_headers_add_pad(session, frame);
|
|
||||||
|
|
||||||
if (rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUGF(fprintf(stderr, "send: HEADERS finally serialized in %zd bytes\n",
|
|
||||||
nghttp2_bufs_len(&session->aob.framebufs)));
|
|
||||||
|
|
||||||
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
|
|
||||||
assert(session->last_sent_stream_id < frame->hd.stream_id);
|
|
||||||
session->last_sent_stream_id = frame->hd.stream_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NGHTTP2_PRIORITY: {
|
|
||||||
if (session_is_closing(session)) {
|
|
||||||
return NGHTTP2_ERR_SESSION_CLOSING;
|
|
||||||
}
|
|
||||||
/* PRIORITY frame can be sent at any time and to any stream
|
|
||||||
ID. */
|
|
||||||
nghttp2_frame_pack_priority(&session->aob.framebufs, &frame->priority);
|
|
||||||
|
|
||||||
/* Peer can send PRIORITY frame against idle stream to create
|
|
||||||
"anchor" in dependency tree. Only client can do this in
|
|
||||||
nghttp2. In nghttp2, only server retains non-active (closed
|
|
||||||
or idle) streams in memory, so we don't open stream here. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NGHTTP2_RST_STREAM:
|
|
||||||
if (session_is_closing(session)) {
|
|
||||||
return NGHTTP2_ERR_SESSION_CLOSING;
|
|
||||||
}
|
|
||||||
nghttp2_frame_pack_rst_stream(&session->aob.framebufs,
|
|
||||||
&frame->rst_stream);
|
|
||||||
break;
|
|
||||||
case NGHTTP2_SETTINGS: {
|
|
||||||
if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
|
|
||||||
assert(session->obq_flood_counter_ > 0);
|
|
||||||
--session->obq_flood_counter_;
|
|
||||||
/* When session is about to close, don't send SETTINGS ACK.
|
|
||||||
We are required to send SETTINGS without ACK though; for
|
|
||||||
example, we have to send SETTINGS as a part of connection
|
|
||||||
preface. */
|
|
||||||
if (session_is_closing(session)) {
|
|
||||||
return NGHTTP2_ERR_SESSION_CLOSING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = nghttp2_frame_pack_settings(&session->aob.framebufs,
|
|
||||||
&frame->settings);
|
|
||||||
if (rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NGHTTP2_PUSH_PROMISE: {
|
|
||||||
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);
|
|
||||||
|
|
||||||
/* predicte should fail if stream is NULL. */
|
|
||||||
rv = session_predicate_push_promise_send(session, stream);
|
|
||||||
if (rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(stream);
|
|
||||||
|
|
||||||
rv = nghttp2_frame_pack_push_promise(
|
|
||||||
&session->aob.framebufs, &frame->push_promise, &session->hd_deflater);
|
|
||||||
if (rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
rv = session_headers_add_pad(session, frame);
|
|
||||||
if (rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(session->last_sent_stream_id + 2 <=
|
|
||||||
frame->push_promise.promised_stream_id);
|
|
||||||
session->last_sent_stream_id = frame->push_promise.promised_stream_id;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NGHTTP2_PING:
|
|
||||||
if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
|
|
||||||
assert(session->obq_flood_counter_ > 0);
|
|
||||||
--session->obq_flood_counter_;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (session_is_closing(session)) {
|
|
||||||
return NGHTTP2_ERR_SESSION_CLOSING;
|
|
||||||
}
|
|
||||||
nghttp2_frame_pack_ping(&session->aob.framebufs, &frame->ping);
|
|
||||||
break;
|
|
||||||
case NGHTTP2_GOAWAY:
|
|
||||||
rv = nghttp2_frame_pack_goaway(&session->aob.framebufs, &frame->goaway);
|
|
||||||
if (rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
session->local_last_stream_id = frame->goaway.last_stream_id;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case NGHTTP2_WINDOW_UPDATE:
|
|
||||||
rv = session_predicate_window_update_send(session, frame->hd.stream_id);
|
|
||||||
if (rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
nghttp2_frame_pack_window_update(&session->aob.framebufs,
|
|
||||||
&frame->window_update);
|
|
||||||
break;
|
|
||||||
case NGHTTP2_CONTINUATION:
|
|
||||||
/* We never handle CONTINUATION here. */
|
|
||||||
assert(0);
|
|
||||||
break;
|
|
||||||
default: {
|
|
||||||
nghttp2_ext_aux_data *aux_data;
|
|
||||||
|
|
||||||
/* extension frame */
|
|
||||||
|
|
||||||
aux_data = &item->aux_data.ext;
|
|
||||||
|
|
||||||
if (aux_data->builtin == 0) {
|
|
||||||
if (session_is_closing(session)) {
|
|
||||||
return NGHTTP2_ERR_SESSION_CLOSING;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = session_pack_extension(session, &session->aob.framebufs, frame);
|
|
||||||
if (rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (frame->hd.type) {
|
|
||||||
case NGHTTP2_ALTSVC:
|
|
||||||
rv = session_predicate_altsvc_send(session, frame->hd.stream_id);
|
|
||||||
if (rv != 0) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
nghttp2_frame_pack_altsvc(&session->aob.framebufs, &frame->ext);
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Unreachable here */
|
|
||||||
assert(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
size_t next_readmax;
|
size_t next_readmax;
|
||||||
nghttp2_stream *stream;
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
|
@ -2304,6 +2033,249 @@ static int session_prep_frame(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
case NGHTTP2_HEADERS: {
|
||||||
|
nghttp2_headers_aux_data *aux_data;
|
||||||
|
size_t estimated_payloadlen;
|
||||||
|
|
||||||
|
aux_data = &item->aux_data.headers;
|
||||||
|
|
||||||
|
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
|
||||||
|
/* initial HEADERS, which opens stream */
|
||||||
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
|
stream = nghttp2_session_open_stream(
|
||||||
|
session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE,
|
||||||
|
&frame->headers.pri_spec, NGHTTP2_STREAM_INITIAL,
|
||||||
|
aux_data->stream_user_data);
|
||||||
|
|
||||||
|
if (stream == NULL) {
|
||||||
|
return NGHTTP2_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session_enforce_http_messaging(session)) {
|
||||||
|
nghttp2_http_record_request_method(stream, frame);
|
||||||
|
}
|
||||||
|
} 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) {
|
||||||
|
rv = session_predicate_push_response_headers_send(session, stream);
|
||||||
|
if (rv == 0) {
|
||||||
|
frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE;
|
||||||
|
|
||||||
|
if (aux_data->stream_user_data) {
|
||||||
|
stream->stream_user_data = aux_data->stream_user_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (session_predicate_response_headers_send(session, stream) ==
|
||||||
|
0) {
|
||||||
|
frame->headers.cat = NGHTTP2_HCAT_RESPONSE;
|
||||||
|
rv = 0;
|
||||||
|
} else {
|
||||||
|
frame->headers.cat = NGHTTP2_HCAT_HEADERS;
|
||||||
|
|
||||||
|
rv = session_predicate_headers_send(session, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = nghttp2_frame_pack_headers(&session->aob.framebufs, &frame->headers,
|
||||||
|
&session->hd_deflater);
|
||||||
|
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGF(fprintf(stderr,
|
||||||
|
"send: before padding, HEADERS serialized in %zd bytes\n",
|
||||||
|
nghttp2_bufs_len(&session->aob.framebufs)));
|
||||||
|
|
||||||
|
rv = session_headers_add_pad(session, frame);
|
||||||
|
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGF(fprintf(stderr, "send: HEADERS finally serialized in %zd bytes\n",
|
||||||
|
nghttp2_bufs_len(&session->aob.framebufs)));
|
||||||
|
|
||||||
|
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
|
||||||
|
assert(session->last_sent_stream_id < frame->hd.stream_id);
|
||||||
|
session->last_sent_stream_id = frame->hd.stream_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case NGHTTP2_PRIORITY: {
|
||||||
|
if (session_is_closing(session)) {
|
||||||
|
return NGHTTP2_ERR_SESSION_CLOSING;
|
||||||
|
}
|
||||||
|
/* PRIORITY frame can be sent at any time and to any stream
|
||||||
|
ID. */
|
||||||
|
nghttp2_frame_pack_priority(&session->aob.framebufs, &frame->priority);
|
||||||
|
|
||||||
|
/* Peer can send PRIORITY frame against idle stream to create
|
||||||
|
"anchor" in dependency tree. Only client can do this in
|
||||||
|
nghttp2. In nghttp2, only server retains non-active (closed
|
||||||
|
or idle) streams in memory, so we don't open stream here. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case NGHTTP2_RST_STREAM:
|
||||||
|
if (session_is_closing(session)) {
|
||||||
|
return NGHTTP2_ERR_SESSION_CLOSING;
|
||||||
|
}
|
||||||
|
nghttp2_frame_pack_rst_stream(&session->aob.framebufs, &frame->rst_stream);
|
||||||
|
return 0;
|
||||||
|
case NGHTTP2_SETTINGS: {
|
||||||
|
if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
|
||||||
|
assert(session->obq_flood_counter_ > 0);
|
||||||
|
--session->obq_flood_counter_;
|
||||||
|
/* When session is about to close, don't send SETTINGS ACK.
|
||||||
|
We are required to send SETTINGS without ACK though; for
|
||||||
|
example, we have to send SETTINGS as a part of connection
|
||||||
|
preface. */
|
||||||
|
if (session_is_closing(session)) {
|
||||||
|
return NGHTTP2_ERR_SESSION_CLOSING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = nghttp2_frame_pack_settings(&session->aob.framebufs, &frame->settings);
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case NGHTTP2_PUSH_PROMISE: {
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* predicte should fail if stream is NULL. */
|
||||||
|
rv = session_predicate_push_promise_send(session, stream);
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(stream);
|
||||||
|
|
||||||
|
rv = nghttp2_frame_pack_push_promise(
|
||||||
|
&session->aob.framebufs, &frame->push_promise, &session->hd_deflater);
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
rv = session_headers_add_pad(session, frame);
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(session->last_sent_stream_id + 2 <=
|
||||||
|
frame->push_promise.promised_stream_id);
|
||||||
|
session->last_sent_stream_id = frame->push_promise.promised_stream_id;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case NGHTTP2_PING:
|
||||||
|
if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
|
||||||
|
assert(session->obq_flood_counter_ > 0);
|
||||||
|
--session->obq_flood_counter_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session_is_closing(session)) {
|
||||||
|
return NGHTTP2_ERR_SESSION_CLOSING;
|
||||||
|
}
|
||||||
|
nghttp2_frame_pack_ping(&session->aob.framebufs, &frame->ping);
|
||||||
|
return 0;
|
||||||
|
case NGHTTP2_GOAWAY:
|
||||||
|
rv = nghttp2_frame_pack_goaway(&session->aob.framebufs, &frame->goaway);
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
session->local_last_stream_id = frame->goaway.last_stream_id;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case NGHTTP2_WINDOW_UPDATE:
|
||||||
|
rv = session_predicate_window_update_send(session, frame->hd.stream_id);
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
nghttp2_frame_pack_window_update(&session->aob.framebufs,
|
||||||
|
&frame->window_update);
|
||||||
|
return 0;
|
||||||
|
case NGHTTP2_CONTINUATION:
|
||||||
|
/* We never handle CONTINUATION here. */
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
default: {
|
||||||
|
nghttp2_ext_aux_data *aux_data;
|
||||||
|
|
||||||
|
/* extension frame */
|
||||||
|
|
||||||
|
aux_data = &item->aux_data.ext;
|
||||||
|
|
||||||
|
if (aux_data->builtin == 0) {
|
||||||
|
if (session_is_closing(session)) {
|
||||||
|
return NGHTTP2_ERR_SESSION_CLOSING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session_pack_extension(session, &session->aob.framebufs, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (frame->hd.type) {
|
||||||
|
case NGHTTP2_ALTSVC:
|
||||||
|
rv = session_predicate_altsvc_send(session, frame->hd.stream_id);
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_frame_pack_altsvc(&session->aob.framebufs, &frame->ext);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
/* Unreachable here */
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_outbound_item *
|
nghttp2_outbound_item *
|
||||||
|
@ -2538,14 +2510,6 @@ static int session_after_frame_sent1(nghttp2_session *session) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream->item == item) {
|
|
||||||
rv = nghttp2_stream_detach_item(stream);
|
|
||||||
|
|
||||||
if (nghttp2_is_fatal(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (frame->headers.cat) {
|
switch (frame->headers.cat) {
|
||||||
case NGHTTP2_HCAT_REQUEST: {
|
case NGHTTP2_HCAT_REQUEST: {
|
||||||
stream->state = NGHTTP2_STREAM_OPENING;
|
stream->state = NGHTTP2_STREAM_OPENING;
|
||||||
|
|
Loading…
Reference in New Issue