From b7c0576eb5fa6c290323d621068eb3d00d8d08cf Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Wed, 12 Nov 2014 00:26:23 +0900 Subject: [PATCH] Make certain type of HEADERS subject to priority We make following HEADERS under priority control: * push response HEADERS * HEADERS submitted by nghttp2_submit_response Currently, HEADERS submitted by nghttp2_submit_headers is not attached to stream. This is because it may be used as non-final response header and application may submit final response using nghttp2_submit_response without checking non-final response header transmission. --- lib/nghttp2_outbound_item.h | 3 + lib/nghttp2_session.c | 148 ++++++++++++++++++++--------------- lib/nghttp2_stream.c | 103 ++++++++++++------------ lib/nghttp2_stream.h | 32 +++----- lib/nghttp2_submit.c | 15 ++-- tests/nghttp2_session_test.c | 74 +++++++----------- 6 files changed, 190 insertions(+), 185 deletions(-) diff --git a/lib/nghttp2_outbound_item.h b/lib/nghttp2_outbound_item.h index 39166b89..ca936a86 100644 --- a/lib/nghttp2_outbound_item.h +++ b/lib/nghttp2_outbound_item.h @@ -43,6 +43,9 @@ typedef struct { nghttp2_data_provider data_prd; void *stream_user_data; + /* nonzero if this item should be attached to stream object to make + it under priority control */ + uint8_t attach_stream; } nghttp2_headers_aux_data; /* struct used for DATA frame */ diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index d1667e02..3a255b90 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -604,11 +604,9 @@ int nghttp2_session_reprioritize_stream session->roots.num_streams <= NGHTTP2_MAX_DEP_TREE_LENGTH) { rv = nghttp2_stream_dep_all_your_stream_are_belong_to_us - (stream, &session->ob_da_pq, session->last_cycle, session->aob.item); + (stream, session); } else { - rv = nghttp2_stream_dep_make_root(stream, &session->ob_da_pq, - session->last_cycle, - session->aob.item); + rv = nghttp2_stream_dep_make_root(stream, session); } return rv; @@ -624,8 +622,7 @@ int nghttp2_session_reprioritize_stream stream, stream->stream_id)); nghttp2_stream_dep_remove_subtree(dep_stream); - nghttp2_stream_dep_make_root(dep_stream, &session->ob_da_pq, - session->last_cycle, session->aob.item); + nghttp2_stream_dep_make_root(dep_stream, session); } nghttp2_stream_dep_remove_subtree(stream); @@ -639,19 +636,12 @@ int nghttp2_session_reprioritize_stream NGHTTP2_MAX_DEP_TREE_LENGTH) { stream->weight = NGHTTP2_DEFAULT_WEIGHT; - rv = nghttp2_stream_dep_make_root(stream, &session->ob_da_pq, - session->last_cycle, session->aob.item); + rv = nghttp2_stream_dep_make_root(stream, session); } else { if(pri_spec->exclusive) { - rv = nghttp2_stream_dep_insert_subtree(dep_stream, stream, - &session->ob_da_pq, - session->last_cycle, - session->aob.item); + rv = nghttp2_stream_dep_insert_subtree(dep_stream, stream, session); } else { - rv = nghttp2_stream_dep_add_subtree(dep_stream, stream, - &session->ob_da_pq, - session->last_cycle, - session->aob.item); + rv = nghttp2_stream_dep_add_subtree(dep_stream, stream, session); } } @@ -717,25 +707,50 @@ int nghttp2_session_add_item(nghttp2_session *session, break; } - if(frame->hd.type == NGHTTP2_HEADERS && - (frame->headers.cat == NGHTTP2_HCAT_REQUEST || - (stream && stream->state == NGHTTP2_STREAM_RESERVED))) { + if(frame->hd.type == 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_ss_pq, which is not desirable. */ - rv = nghttp2_pq_push(&session->ob_ss_pq, item); + if(frame->headers.cat == NGHTTP2_HCAT_REQUEST) { + rv = nghttp2_pq_push(&session->ob_ss_pq, item); + + if(rv != 0) { + return rv; + } + + item->queued = 1; + } else if(stream && (stream->state == NGHTTP2_STREAM_RESERVED || + item->aux_data.headers.attach_stream)) { + item->weight = stream->effective_weight; + item->cycle = session->last_cycle; + + rv = nghttp2_stream_attach_data(stream, item, session); + + if(rv != 0) { + return rv; + } + } else { + rv = nghttp2_pq_push(&session->ob_pq, item); + + if(rv != 0) { + return rv; + } + + item->queued = 1; + } } else { rv = nghttp2_pq_push(&session->ob_pq, item); + + if(rv != 0) { + return rv; + } + + item->queued = 1; } - if(rv != 0) { - return rv; - } - - item->queued = 1; return 0; } @@ -751,9 +766,7 @@ int nghttp2_session_add_item(nghttp2_session *session, item->weight = stream->effective_weight; item->cycle = session->last_cycle; - rv = nghttp2_stream_attach_data(stream, item, &session->ob_da_pq, - session->last_cycle, - session->aob.item); + rv = nghttp2_stream_attach_data(stream, item, session); if(rv != 0) { return rv; @@ -906,7 +919,7 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session, if(pri_spec->exclusive && session->roots.num_streams <= NGHTTP2_MAX_DEP_TREE_LENGTH) { rv = nghttp2_stream_dep_all_your_stream_are_belong_to_us - (stream, &session->ob_da_pq, session->last_cycle, session->aob.item); + (stream, session); /* Since no dpri is changed in dependency tree, the above function call never fail. */ @@ -961,8 +974,7 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, item = stream->data_item; - rv = nghttp2_stream_detach_data(stream, &session->ob_da_pq, - session->last_cycle, session->aob.item); + rv = nghttp2_stream_detach_data(stream, session); if(rv != 0) { return rv; @@ -1692,8 +1704,24 @@ static int session_prep_frame(nghttp2_session *session, frame->headers.cat = NGHTTP2_HCAT_RESPONSE; } else { frame->headers.cat = NGHTTP2_HCAT_HEADERS; + rv = session_predicate_headers_send(session, frame->hd.stream_id); + if(rv != 0) { + nghttp2_stream *stream; + + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); + + if(stream && stream->data_item == item) { + int rv2; + + rv2 = nghttp2_stream_detach_data(stream, session); + + if(nghttp2_is_fatal(rv2)) { + return rv2; + } + } + return rv; } } @@ -1883,9 +1911,7 @@ static int session_prep_frame(nghttp2_session *session, if(stream) { int rv2; - rv2 = nghttp2_stream_detach_data(stream, &session->ob_da_pq, - session->last_cycle, - session->aob.item); + rv2 = nghttp2_stream_detach_data(stream, session); if(nghttp2_is_fatal(rv2)) { return rv2; @@ -1905,8 +1931,7 @@ static int session_prep_frame(nghttp2_session *session, assert(session->remote_window_size > 0); rv = nghttp2_stream_defer_data - (stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL, - &session->ob_da_pq, session->last_cycle, session->aob.item); + (stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL, session); if(nghttp2_is_fatal(rv)) { return rv; @@ -1924,8 +1949,7 @@ static int session_prep_frame(nghttp2_session *session, &item->aux_data.data); if(framerv == NGHTTP2_ERR_DEFERRED) { rv = nghttp2_stream_defer_data(stream, NGHTTP2_STREAM_FLAG_DEFERRED_USER, - &session->ob_da_pq, session->last_cycle, - session->aob.item); + session); if(nghttp2_is_fatal(rv)) { return rv; @@ -1936,9 +1960,7 @@ static int session_prep_frame(nghttp2_session *session, return NGHTTP2_ERR_DEFERRED; } if(framerv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - rv = nghttp2_stream_detach_data(stream, &session->ob_da_pq, - session->last_cycle, - session->aob.item); + rv = nghttp2_stream_detach_data(stream, session); if(nghttp2_is_fatal(rv)) { return rv; @@ -1952,9 +1974,7 @@ static int session_prep_frame(nghttp2_session *session, return framerv; } if(framerv < 0) { - rv = nghttp2_stream_detach_data(stream, &session->ob_da_pq, - session->last_cycle, - session->aob.item); + rv = nghttp2_stream_detach_data(stream, session); if(nghttp2_is_fatal(rv)) { return rv; @@ -2186,6 +2206,15 @@ static int session_after_frame_sent(nghttp2_session *session) if(!stream) { break; } + + if(stream->data_item == item) { + rv = nghttp2_stream_detach_data(stream, session); + + if(nghttp2_is_fatal(rv)) { + return rv; + } + } + switch(frame->headers.cat) { case NGHTTP2_HCAT_REQUEST: { stream->state = NGHTTP2_STREAM_OPENING; @@ -2293,8 +2322,7 @@ static int session_after_frame_sent(nghttp2_session *session) } if(stream && aux_data->eof) { - rv = nghttp2_stream_detach_data(stream, &session->ob_da_pq, - session->last_cycle, aob->item); + rv = nghttp2_stream_detach_data(stream, session); if(nghttp2_is_fatal(rv)) { return rv; @@ -2352,8 +2380,7 @@ static int session_after_frame_sent(nghttp2_session *session) if(nghttp2_session_predicate_data_send(session, frame->hd.stream_id) != 0) { if(stream) { - rv = nghttp2_stream_detach_data(stream, &session->ob_da_pq, - session->last_cycle, aob->item); + rv = nghttp2_stream_detach_data(stream, session); if(nghttp2_is_fatal(rv)) { return rv; @@ -2398,8 +2425,7 @@ static int session_after_frame_sent(nghttp2_session *session) aob->item->queued = 1; } else { rv = nghttp2_stream_defer_data - (stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL, - &session->ob_da_pq, session->last_cycle, aob->item); + (stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL, session); if(nghttp2_is_fatal(rv)) { return rv; @@ -2421,8 +2447,7 @@ static int session_after_frame_sent(nghttp2_session *session) } if(rv == NGHTTP2_ERR_DEFERRED) { rv = nghttp2_stream_defer_data - (stream, NGHTTP2_STREAM_FLAG_DEFERRED_USER, - &session->ob_da_pq, session->last_cycle, aob->item); + (stream, NGHTTP2_STREAM_FLAG_DEFERRED_USER, session); if(nghttp2_is_fatal(rv)) { return rv; @@ -2445,8 +2470,7 @@ static int session_after_frame_sent(nghttp2_session *session) return rv; } - rv = nghttp2_stream_detach_data(stream, &session->ob_da_pq, - session->last_cycle, aob->item); + rv = nghttp2_stream_detach_data(stream, session); if(nghttp2_is_fatal(rv)) { return rv; @@ -2501,14 +2525,16 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session, return 0; } - if(item->frame.hd.type == NGHTTP2_DATA) { + if(item->frame.hd.type == NGHTTP2_DATA || + item->frame.hd.type == NGHTTP2_HEADERS) { nghttp2_frame *frame; nghttp2_stream *stream; frame = &item->frame; stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - if(stream && stream->dpri != NGHTTP2_STREAM_DPRI_TOP) { + if(stream && item == stream->data_item && + stream->dpri != NGHTTP2_STREAM_DPRI_TOP) { /* We have DATA with higher priority in queue within the same dependency tree. */ break; @@ -3387,9 +3413,7 @@ static int update_remote_initial_window_size_func nghttp2_stream_check_deferred_by_flow_control(stream)) { rv = nghttp2_stream_resume_deferred_data - (stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL, - &arg->session->ob_da_pq, arg->session->last_cycle, - arg->session->aob.item); + (stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL, arg->session); if(nghttp2_is_fatal(rv)) { return rv; @@ -4009,8 +4033,7 @@ static int session_on_stream_window_update_received nghttp2_stream_check_deferred_by_flow_control(stream)) { rv = nghttp2_stream_resume_deferred_data - (stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL, &session->ob_da_pq, - session->last_cycle, session->aob.item); + (stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL, session); if(nghttp2_is_fatal(rv)) { return rv; @@ -6028,8 +6051,7 @@ int nghttp2_session_resume_data(nghttp2_session *session, int32_t stream_id) } rv = nghttp2_stream_resume_deferred_data - (stream, NGHTTP2_STREAM_FLAG_DEFERRED_USER, &session->ob_da_pq, - session->last_cycle, session->aob.item); + (stream, NGHTTP2_STREAM_FLAG_DEFERRED_USER, session); if(nghttp2_is_fatal(rv)) { return rv; diff --git a/lib/nghttp2_stream.c b/lib/nghttp2_stream.c index 6dc385ce..368d9d2f 100644 --- a/lib/nghttp2_stream.c +++ b/lib/nghttp2_stream.c @@ -27,6 +27,7 @@ #include #include +#include "nghttp2_session.h" #include "nghttp2_helper.h" void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, @@ -86,33 +87,49 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) stream->shut_flags |= flag; } -static int stream_push_data(nghttp2_stream *stream, nghttp2_pq *pq, - uint64_t cycle, nghttp2_outbound_item *active_item) +static int stream_push_data(nghttp2_stream *stream, nghttp2_session *session) { int rv; + nghttp2_outbound_item *item; assert(stream->data_item); assert(stream->data_item->queued == 0); - /* If stream->data_item is now sent, don't push it to the queue. - Otherwise, we may push same item twice. */ - if(active_item == stream->data_item) { + item = stream->data_item; + + /* If item is now sent, don't push it to the queue. Otherwise, we + may push same item twice. */ + if(session->aob.item == item) { return 0; } - if(stream->data_item->weight > stream->effective_weight) { - stream->data_item->weight = stream->effective_weight; + if(item->weight > stream->effective_weight) { + item->weight = stream->effective_weight; } - stream->data_item->cycle = cycle; + item->cycle = session->last_cycle; - rv = nghttp2_pq_push(pq, stream->data_item); + switch(item->frame.hd.type) { + case NGHTTP2_DATA: + rv = nghttp2_pq_push(&session->ob_da_pq, item); + break; + case NGHTTP2_HEADERS: + if(stream->state == NGHTTP2_STREAM_RESERVED) { + rv = nghttp2_pq_push(&session->ob_ss_pq, item); + } else { + rv = nghttp2_pq_push(&session->ob_pq, item); + } + break; + default: + /* should not reach here */ + assert(0); + } if(rv != 0) { return rv; } - stream->data_item->queued = 1; + item->queued = 1; return 0; } @@ -303,9 +320,8 @@ static void stream_update_dep_set_top(nghttp2_stream *stream) * NGHTTP2_ERR_NOMEM * Out of memory. */ -static int stream_update_dep_queue_top(nghttp2_stream *stream, nghttp2_pq *pq, - uint64_t cycle, - nghttp2_outbound_item *active_item) +static int stream_update_dep_queue_top(nghttp2_stream *stream, + nghttp2_session *session) { int rv; nghttp2_stream *si; @@ -318,7 +334,7 @@ static int stream_update_dep_queue_top(nghttp2_stream *stream, nghttp2_pq *pq, if(!stream->data_item->queued) { DEBUGF(fprintf(stderr, "stream: stream=%d enqueue\n", stream->stream_id)); - rv = stream_push_data(stream, pq, cycle, active_item); + rv = stream_push_data(stream, session); if(rv != 0) { return rv; @@ -329,7 +345,7 @@ static int stream_update_dep_queue_top(nghttp2_stream *stream, nghttp2_pq *pq, } for(si = stream->dep_next; si; si = si->sib_next) { - rv = stream_update_dep_queue_top(si, pq, cycle, active_item); + rv = stream_update_dep_queue_top(si, session); if(rv != 0) { return rv; @@ -387,8 +403,7 @@ static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream) } static int stream_update_dep_on_attach_data(nghttp2_stream *stream, - nghttp2_pq *pq, uint64_t cycle, - nghttp2_outbound_item *active_item) + nghttp2_session *session) { nghttp2_stream *root_stream; @@ -405,12 +420,11 @@ static int stream_update_dep_on_attach_data(nghttp2_stream *stream, stream_update_dep_sum_norest_weight(root_stream); stream_update_dep_effective_weight(root_stream); - return stream_update_dep_queue_top(root_stream, pq, cycle, active_item); + return stream_update_dep_queue_top(root_stream, session); } static int stream_update_dep_on_detach_data(nghttp2_stream *stream, - nghttp2_pq *pq, uint64_t cycle, - nghttp2_outbound_item *active_item) + nghttp2_session *session) { nghttp2_stream *root_stream; @@ -423,14 +437,12 @@ static int stream_update_dep_on_detach_data(nghttp2_stream *stream, stream_update_dep_sum_norest_weight(root_stream); stream_update_dep_effective_weight(root_stream); - return stream_update_dep_queue_top(root_stream, pq, cycle, active_item); + return stream_update_dep_queue_top(root_stream, session); } int nghttp2_stream_attach_data(nghttp2_stream *stream, nghttp2_outbound_item *data_item, - nghttp2_pq *pq, - uint64_t cycle, - nghttp2_outbound_item *active_item) + nghttp2_session *session) { assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0); assert(stream->data_item == NULL); @@ -440,12 +452,11 @@ int nghttp2_stream_attach_data(nghttp2_stream *stream, stream->data_item = data_item; - return stream_update_dep_on_attach_data(stream, pq, cycle, active_item); + return stream_update_dep_on_attach_data(stream, session); } -int nghttp2_stream_detach_data(nghttp2_stream *stream, nghttp2_pq *pq, - uint64_t cycle, - nghttp2_outbound_item *active_item) +int nghttp2_stream_detach_data(nghttp2_stream *stream, + nghttp2_session *session) { DEBUGF(fprintf(stderr, "stream: stream=%d detach data=%p\n", stream->stream_id, stream->data_item)); @@ -453,12 +464,11 @@ int nghttp2_stream_detach_data(nghttp2_stream *stream, nghttp2_pq *pq, stream->data_item = NULL; stream->flags &= ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL; - return stream_update_dep_on_detach_data(stream, pq, cycle, active_item); + return stream_update_dep_on_detach_data(stream, session); } int nghttp2_stream_defer_data(nghttp2_stream *stream, uint8_t flags, - nghttp2_pq *pq, uint64_t cycle, - nghttp2_outbound_item *active_item) + nghttp2_session *session) { assert(stream->data_item); @@ -467,12 +477,11 @@ int nghttp2_stream_defer_data(nghttp2_stream *stream, uint8_t flags, stream->flags |= flags; - return stream_update_dep_on_detach_data(stream, pq, cycle, active_item); + return stream_update_dep_on_detach_data(stream, session); } int nghttp2_stream_resume_deferred_data(nghttp2_stream *stream, uint8_t flags, - nghttp2_pq *pq, uint64_t cycle, - nghttp2_outbound_item *active_item) + nghttp2_session *session) { assert(stream->data_item); @@ -485,7 +494,7 @@ int nghttp2_stream_resume_deferred_data(nghttp2_stream *stream, uint8_t flags, return 0; } - return stream_update_dep_on_attach_data(stream, pq, cycle, active_item); + return stream_update_dep_on_attach_data(stream, session); } int nghttp2_stream_check_deferred_data(nghttp2_stream *stream) @@ -818,9 +827,7 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream) int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, nghttp2_stream *stream, - nghttp2_pq *pq, - uint64_t cycle, - nghttp2_outbound_item *active_item) + nghttp2_session *session) { nghttp2_stream *last_sib; nghttp2_stream *dep_next; @@ -872,14 +879,12 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, stream_update_dep_sum_norest_weight(root_stream); stream_update_dep_effective_weight(root_stream); - return stream_update_dep_queue_top(root_stream, pq, cycle, active_item); + return stream_update_dep_queue_top(root_stream, session); } int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, nghttp2_stream *stream, - nghttp2_pq *pq, - uint64_t cycle, - nghttp2_outbound_item *active_item) + nghttp2_session *session) { nghttp2_stream *root_stream; @@ -908,7 +913,7 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, stream_update_dep_sum_norest_weight(root_stream); stream_update_dep_effective_weight(root_stream); - return stream_update_dep_queue_top(root_stream, pq, cycle, active_item); + return stream_update_dep_queue_top(root_stream, session); } void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) @@ -962,9 +967,8 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) stream->dep_prev = NULL; } -int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq, - uint64_t cycle, - nghttp2_outbound_item *active_item) +int nghttp2_stream_dep_make_root(nghttp2_stream *stream, + nghttp2_session *session) { DEBUGF(fprintf(stderr, "stream: dep_make_root stream(%p)=%d\n", stream, stream->stream_id)); @@ -980,12 +984,11 @@ int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq, stream_update_dep_sum_norest_weight(stream); stream_update_dep_effective_weight(stream); - return stream_update_dep_queue_top(stream, pq, cycle, active_item); + return stream_update_dep_queue_top(stream, session); } int nghttp2_stream_dep_all_your_stream_are_belong_to_us -(nghttp2_stream *stream, nghttp2_pq *pq, uint64_t cycle, - nghttp2_outbound_item *active_item) +(nghttp2_stream *stream, nghttp2_session *session) { nghttp2_stream *first, *si; @@ -1040,7 +1043,7 @@ int nghttp2_stream_dep_all_your_stream_are_belong_to_us nghttp2_stream_roots_remove_all(stream->roots); - return nghttp2_stream_dep_make_root(stream, pq, cycle, active_item); + return nghttp2_stream_dep_make_root(stream, session); } int nghttp2_stream_in_dep_tree(nghttp2_stream *stream) diff --git a/lib/nghttp2_stream.h b/lib/nghttp2_stream.h index 2a670973..2e36e0c9 100644 --- a/lib/nghttp2_stream.h +++ b/lib/nghttp2_stream.h @@ -219,8 +219,7 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag); * Out of memory */ int nghttp2_stream_defer_data(nghttp2_stream *stream, uint8_t flags, - nghttp2_pq *pq, uint64_t cycle, - nghttp2_outbound_item *active_item); + nghttp2_session *session); /* * Put back deferred data in this stream to active state. The |flags| @@ -231,8 +230,7 @@ int nghttp2_stream_defer_data(nghttp2_stream *stream, uint8_t flags, * one of flag is still set, data does not become active. */ int nghttp2_stream_resume_deferred_data(nghttp2_stream *stream, uint8_t flags, - nghttp2_pq *pq, uint64_t cycle, - nghttp2_outbound_item *active_item); + nghttp2_session *session); /* * Returns nonzero if data item is deferred by whatever reason. @@ -343,9 +341,7 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream); */ int nghttp2_stream_attach_data(nghttp2_stream *stream, nghttp2_outbound_item *data_item, - nghttp2_pq *pq, - uint64_t cycle, - nghttp2_outbound_item *active_item); + nghttp2_session *session); /* * Detaches |stream->data_item|. Updates dpri members in this @@ -358,10 +354,8 @@ int nghttp2_stream_attach_data(nghttp2_stream *stream, * NGHTTP2_ERR_NOMEM * Out of memory */ -int nghttp2_stream_detach_data(nghttp2_stream *stream, nghttp2_pq *pq, - uint64_t cycle, - nghttp2_outbound_item *active_item); - +int nghttp2_stream_detach_data(nghttp2_stream *stream, + nghttp2_session *session); /* * Makes the |stream| depend on the |dep_stream|. This dependency is @@ -375,9 +369,7 @@ int nghttp2_stream_detach_data(nghttp2_stream *stream, nghttp2_pq *pq, */ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, nghttp2_stream *stream, - nghttp2_pq *pq, - uint64_t cycle, - nghttp2_outbound_item *active_item); + nghttp2_session *session); /* * Makes the |stream| depend on the |dep_stream|. This dependency is @@ -391,9 +383,7 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, */ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, nghttp2_stream *stream, - nghttp2_pq *pq, - uint64_t cycle, - nghttp2_outbound_item *active_item); + nghttp2_session *session); /* * Removes subtree whose root stream is |stream|. Removing subtree @@ -418,9 +408,8 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream); * NGHTTP2_ERR_NOMEM * Out of memory */ -int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq, - uint64_t cycle, - nghttp2_outbound_item *active_item); +int nghttp2_stream_dep_make_root(nghttp2_stream *stream, + nghttp2_session *session); /* * Makes the |stream| as root and all existing root streams become @@ -433,8 +422,7 @@ int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq, * Out of memory */ int nghttp2_stream_dep_all_your_stream_are_belong_to_us -(nghttp2_stream *stream, nghttp2_pq *pq, uint64_t cycle, - nghttp2_outbound_item *active_item); +(nghttp2_stream *stream, nghttp2_session *session); /* * Returns nonzero if |stream| is in any dependency tree. diff --git a/lib/nghttp2_submit.c b/lib/nghttp2_submit.c index 32ad0e2e..497e421a 100644 --- a/lib/nghttp2_submit.c +++ b/lib/nghttp2_submit.c @@ -43,7 +43,8 @@ static int32_t submit_headers_shared nghttp2_nv *nva_copy, size_t nvlen, const nghttp2_data_provider *data_prd, - void *stream_user_data) + void *stream_user_data, + uint8_t attach_stream) { int rv; uint8_t flags_copy; @@ -69,6 +70,7 @@ static int32_t submit_headers_shared } item->aux_data.headers.stream_user_data = stream_user_data; + item->aux_data.headers.attach_stream = attach_stream; flags_copy = (flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) | @@ -133,7 +135,8 @@ static int32_t submit_headers_shared_nva const nghttp2_nv *nva, size_t nvlen, const nghttp2_data_provider *data_prd, - void *stream_user_data) + void *stream_user_data, + uint8_t attach_stream) { int rv; nghttp2_nv *nva_copy; @@ -153,7 +156,7 @@ static int32_t submit_headers_shared_nva return submit_headers_shared(session, flags, stream_id, ©_pri_spec, nva_copy, nvlen, data_prd, - stream_user_data); + stream_user_data, attach_stream); } int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags, @@ -171,7 +174,7 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags, } return submit_headers_shared_nva(session, flags, stream_id, pri_spec, - nva, nvlen, NULL, stream_user_data); + nva, nvlen, NULL, stream_user_data, 0); } @@ -498,7 +501,7 @@ int32_t nghttp2_submit_request(nghttp2_session *session, return submit_headers_shared_nva(session, flags, -1, pri_spec, nva, nvlen, - data_prd, stream_user_data); + data_prd, stream_user_data, 0); } static uint8_t set_response_flags(const nghttp2_data_provider *data_prd) @@ -518,7 +521,7 @@ int nghttp2_submit_response(nghttp2_session *session, uint8_t flags = set_response_flags(data_prd); return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen, - data_prd, NULL); + data_prd, NULL, 1); } int nghttp2_submit_data(nghttp2_session *session, uint8_t flags, diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index acdec7fa..69bd12f2 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -2541,10 +2541,7 @@ void test_nghttp2_session_on_window_update_received(void) data_item = create_data_ob_item(); - CU_ASSERT(0 == nghttp2_stream_attach_data(stream, data_item, - &session->ob_da_pq, - session->last_cycle, - NULL)); + CU_ASSERT(0 == nghttp2_stream_attach_data(stream, data_item, session)); nghttp2_frame_window_update_init(&frame.window_update, NGHTTP2_FLAG_NONE, 1, 16*1024); @@ -2554,8 +2551,7 @@ void test_nghttp2_session_on_window_update_received(void) CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE+16*1024 == stream->remote_window_size); CU_ASSERT(0 == nghttp2_stream_defer_data - (stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL, - &session->ob_da_pq, session->last_cycle, NULL)); + (stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL, session)); CU_ASSERT(0 == nghttp2_session_on_window_update_received(session, &frame)); CU_ASSERT(2 == user_data.frame_recv_cb_called); @@ -4316,6 +4312,7 @@ void test_nghttp2_session_pop_next_ob_item(void) nghttp2_session_callbacks callbacks; nghttp2_outbound_item *item; nghttp2_priority_spec pri_spec; + nghttp2_stream *stream; memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); callbacks.send_callback = null_send_callback; @@ -4359,6 +4356,11 @@ void test_nghttp2_session_pop_next_ob_item(void) item = nghttp2_session_pop_next_ob_item(session); CU_ASSERT(NGHTTP2_HEADERS == item->frame.hd.type); CU_ASSERT(1 == item->frame.hd.stream_id); + + stream = nghttp2_session_get_stream(session, 1); + + nghttp2_stream_detach_data(stream, session); + nghttp2_outbound_item_free(item); free(item); @@ -5606,8 +5608,7 @@ void test_nghttp2_session_stream_dep_add_subtree(void) * d */ - nghttp2_stream_dep_add_subtree(a, e, &session->ob_da_pq, - session->last_cycle, NULL); + nghttp2_stream_dep_add_subtree(a, e, session); /* becomes * a @@ -5658,8 +5659,7 @@ void test_nghttp2_session_stream_dep_add_subtree(void) * d */ - nghttp2_stream_dep_insert_subtree(a, e, &session->ob_da_pq, - session->last_cycle, NULL); + nghttp2_stream_dep_insert_subtree(a, e, session); /* becomes * a @@ -5852,7 +5852,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) nghttp2_stream_dep_remove_subtree(c); CU_ASSERT(0 == nghttp2_stream_dep_all_your_stream_are_belong_to_us - (c, &session->ob_da_pq, session->last_cycle, NULL)); + (c, session)); /* * c @@ -5890,7 +5890,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) nghttp2_stream_dep_remove_subtree(c); CU_ASSERT(0 == nghttp2_stream_dep_all_your_stream_are_belong_to_us - (c, &session->ob_da_pq, session->last_cycle, NULL)); + (c, session)); /* * c @@ -5927,7 +5927,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) nghttp2_stream_dep_remove_subtree(c); CU_ASSERT(0 == nghttp2_stream_dep_all_your_stream_are_belong_to_us - (c, &session->ob_da_pq, session->last_cycle, NULL)); + (c, session)); /* * c @@ -5980,8 +5980,7 @@ void test_nghttp2_session_stream_attach_data(void) db = create_data_ob_item(); - nghttp2_stream_attach_data(b, db, &session->ob_da_pq, session->last_cycle, - NULL); + nghttp2_stream_attach_data(b, db, session); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); @@ -5996,8 +5995,7 @@ void test_nghttp2_session_stream_attach_data(void) dc = create_data_ob_item(); - nghttp2_stream_attach_data(c, dc, &session->ob_da_pq, session->last_cycle, - NULL); + nghttp2_stream_attach_data(c, dc, session); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); @@ -6013,8 +6011,7 @@ void test_nghttp2_session_stream_attach_data(void) da = create_data_ob_item(); - nghttp2_stream_attach_data(a, da, &session->ob_da_pq, session->last_cycle, - NULL); + nghttp2_stream_attach_data(a, da, session); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == b->dpri); @@ -6025,7 +6022,7 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(1 == da->queued); - nghttp2_stream_detach_data(a, &session->ob_da_pq, session->last_cycle, NULL); + nghttp2_stream_detach_data(a, session); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); @@ -6037,8 +6034,7 @@ void test_nghttp2_session_stream_attach_data(void) dd = create_data_ob_item(); - nghttp2_stream_attach_data(d, dd, &session->ob_da_pq, session->last_cycle, - NULL); + nghttp2_stream_attach_data(d, dd, session); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); @@ -6050,7 +6046,7 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(0 == dd->queued); - nghttp2_stream_detach_data(c, &session->ob_da_pq, session->last_cycle, NULL); + nghttp2_stream_detach_data(c, session); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); @@ -6061,7 +6057,7 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(0 == dd->queued); - nghttp2_stream_detach_data(b, &session->ob_da_pq, session->last_cycle, NULL); + nghttp2_stream_detach_data(b, session); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == b->dpri); @@ -6103,13 +6099,11 @@ void test_nghttp2_session_stream_attach_data_subtree(void) de = create_data_ob_item(); - nghttp2_stream_attach_data(e, de, &session->ob_da_pq, session->last_cycle, - NULL); + nghttp2_stream_attach_data(e, de, session); db = create_data_ob_item(); - nghttp2_stream_attach_data(b, db, &session->ob_da_pq, session->last_cycle, - NULL); + nghttp2_stream_attach_data(b, db, session); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); @@ -6124,8 +6118,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void) /* Insert subtree e under a */ nghttp2_stream_dep_remove_subtree(e); - nghttp2_stream_dep_insert_subtree(a, e, &session->ob_da_pq, - session->last_cycle, NULL); + nghttp2_stream_dep_insert_subtree(a, e, session); /* * a @@ -6150,8 +6143,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void) nghttp2_stream_dep_remove_subtree(b); - nghttp2_stream_dep_make_root(b, &session->ob_da_pq, session->last_cycle, - NULL); + nghttp2_stream_dep_make_root(b, session); /* * a b @@ -6177,8 +6169,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void) nghttp2_stream_dep_remove_subtree(a); - nghttp2_stream_dep_make_root(a, &session->ob_da_pq, session->last_cycle, - NULL); + nghttp2_stream_dep_make_root(a, session); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); @@ -6191,8 +6182,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void) nghttp2_stream_dep_remove_subtree(c); - nghttp2_stream_dep_make_root(c, &session->ob_da_pq, session->last_cycle, - NULL); + nghttp2_stream_dep_make_root(c, session); /* * a b c @@ -6211,14 +6201,12 @@ void test_nghttp2_session_stream_attach_data_subtree(void) dd = create_data_ob_item(); - nghttp2_stream_attach_data(d, dd, &session->ob_da_pq, session->last_cycle, - NULL); + nghttp2_stream_attach_data(d, dd, session); /* Add subtree c to a */ nghttp2_stream_dep_remove_subtree(c); - nghttp2_stream_dep_add_subtree(a, c, &session->ob_da_pq, - session->last_cycle, NULL); + nghttp2_stream_dep_add_subtree(a, c, session); /* * a b @@ -6244,8 +6232,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void) /* Insert b under a */ nghttp2_stream_dep_remove_subtree(b); - nghttp2_stream_dep_insert_subtree(a, b, &session->ob_da_pq, - session->last_cycle, NULL); + nghttp2_stream_dep_insert_subtree(a, b, session); /* * a @@ -6272,8 +6259,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void) /* Remove subtree b */ nghttp2_stream_dep_remove_subtree(b); - nghttp2_stream_dep_make_root(b, &session->ob_da_pq, session->last_cycle, - NULL); + nghttp2_stream_dep_make_root(b, session); /* * b a