From: Stefan Eissing Date: Tue, 24 Nov 2015 16:22:50 +0000 (+0000) Subject: priorities for pushed streams are changed if nghttp2 library supports this, configura... X-Git-Tag: 2.5.0-alpha~2591 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=07517e5da68d3de5c2d6da798dedccc598cc38a4;p=thirdparty%2Fapache%2Fhttpd.git priorities for pushed streams are changed if nghttp2 library supports this, configurations for type based priority specs TBD git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1716197 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/http2/h2_h2.h b/modules/http2/h2_h2.h index 4974d866115..563abe3fded 100644 --- a/modules/http2/h2_h2.h +++ b/modules/http2/h2_h2.h @@ -58,6 +58,17 @@ extern const char *H2_MAGIC_TOKEN; #define H2_STREAM_CLIENT_INITIATED(id) (id&0x01) +typedef enum { + H2_DEPENDANT_AFTER, + H2_DEPENDANT_INTERLEAVED, + H2_DEPENDANT_BEFORE, +} h2_dependency; + +typedef struct h2_priority { + h2_dependency dependency; + int weight; +} h2_priority; + /** * Provide a user readable description of the HTTP/2 error code- * @param h2_error http/2 error code, as in rfc 7540, ch. 7 diff --git a/modules/http2/h2_push.c b/modules/http2/h2_push.c index 3cfacd7fe39..65b2b7b6251 100644 --- a/modules/http2/h2_push.c +++ b/modules/http2/h2_push.c @@ -301,8 +301,8 @@ static int add_push(link_ctx *ctx) h2_request_end_headers(req, ctx->pool, 1); push->req = req; - push->dep_pref = H2_PUSH_DEP_AFTER; - push->weight = NGHTTP2_DEFAULT_WEIGHT; + push->prio.dependency = H2_DEPENDANT_AFTER; + push->prio.weight = NGHTTP2_DEFAULT_WEIGHT; if (!ctx->pushes) { ctx->pushes = apr_array_make(ctx->pool, 5, sizeof(h2_push*)); diff --git a/modules/http2/h2_push.h b/modules/http2/h2_push.h index 546a9928732..b98a2f73e17 100644 --- a/modules/http2/h2_push.h +++ b/modules/http2/h2_push.h @@ -19,17 +19,10 @@ struct h2_request; struct h2_response; struct h2_ngheader; -typedef enum { - H2_PUSH_DEP_AFTER, - H2_PUSH_DEP_INTERLEAVED, - H2_PUSH_DEP_BEFORE, -} h2_push_dep_t; - typedef struct h2_push { - int initiating_id; + int initiating_id; const struct h2_request *req; - h2_push_dep_t dep_pref; - int weight; + h2_priority prio; } h2_push; diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c index 9212e2af8f2..73cdac952c3 100644 --- a/modules/http2/h2_session.c +++ b/modules/http2/h2_session.c @@ -1167,6 +1167,7 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream) nghttp2_data_provider provider; h2_response *response = stream->response; h2_ngheader *ngh; + h2_priority *prio; memset(&provider, 0, sizeof(provider)); provider.source.fd = stream->id; @@ -1176,6 +1177,12 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream) "h2_stream(%ld-%d): submit response %d", session->id, stream->id, response->http_status); + prio = h2_stream_get_priority(stream); + if (prio) { + h2_session_set_prio(session, stream, prio); + /* no showstopper if that fails for some reason */ + } + ngh = h2_util_ngheader_make_res(stream->pool, response->http_status, response->headers); rv = nghttp2_submit_response(session->ngh2, response->stream_id, @@ -1227,13 +1234,6 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream) return status; } -static int valid_weight(float f) -{ - int w = floor(f); - return (w < NGHTTP2_MIN_WEIGHT? NGHTTP2_MIN_WEIGHT : - (w > NGHTTP2_MAX_WEIGHT)? NGHTTP2_MAX_WEIGHT : w); -} - struct h2_stream *h2_session_push(h2_session *session, h2_stream *is, h2_push *push) { @@ -1259,95 +1259,10 @@ struct h2_stream *h2_session_push(h2_session *session, h2_stream *is, session->id, push->initiating_id, nid, push->req->method, push->req->path); -#ifdef H2_NG2_CHANGE_PRIO - /* If different than default, change the priority of the pushed stream - * as specified in the h2_push: - */ - if (push->weight != NGHTTP2_DEFAULT_WEIGHT || push->dep_pref != H2_PUSH_DEP_AFTER) { - nghttp2_stream *s_init, *s_dep, *s_push; - int id_init = push->initiating_id; - - s_push = nghttp2_session_find_stream(session->ngh2, nid); - if (!s_push) { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, - "h2_stream(%ld-%d): lookup of PUSHed stream failed", - session->id, nid); - } - s_init = nghttp2_session_find_stream(session->ngh2, id_init); - if (s_push && s_init) { - nghttp2_priority_spec ps; - int id_dep, w_init, w, rv = 0; - - switch (push->dep_pref) { - case H2_PUSH_DEP_INTERLEAVED: - /* PUSHed stream is to be interleaved with initiating stream. - * It is made a sibling of the initiating stream and gets a - * proportional weight [1, MAX_WEIGHT] of the initiaing - * stream weight. - */ - s_dep = nghttp2_stream_get_parent(s_init); - if (s_dep) { - id_dep = nghttp2_stream_get_stream_id(s_dep); - w_init = nghttp2_stream_get_weight(s_init); - w = valid_weight(w_init * ((float)NGHTTP2_MAX_WEIGHT / push->weight)); - nghttp2_priority_spec_init(&ps, id_dep, w, 0); - rv = nghttp2_session_change_stream_priority(session->ngh2, nid, &ps); - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, - "h2_stream(%ld-%d): PUSH INTERLEAVE, weight=%d, " - "depends=%d, returned=%d", - session->id, nid, w, id_dep, rv); - } - break; - case H2_PUSH_DEP_BEFORE: - /* PUSHed stream os to be sent BEFORE the initiating stream. - * It gets the same weight as the initiating stream, replaces - * that stream in the dependency tree and has the initiating - * stream as child with MAX_WEIGHT. - */ - s_dep = nghttp2_stream_get_parent(s_init); - if (s_dep) { - id_dep = nghttp2_stream_get_stream_id(s_dep); - w_init = nghttp2_stream_get_weight(s_init); - nghttp2_priority_spec_init(&ps, id_dep, valid_weight(w_init), 0); - rv = nghttp2_session_change_stream_priority(session->ngh2, nid, &ps); - if (!rv) { - nghttp2_priority_spec_init(&ps, nid, NGHTTP2_MAX_WEIGHT, 0); - rv = nghttp2_session_change_stream_priority(session->ngh2, id_init, &ps); - if (rv < 0) { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, - "h2_stream(%ld-%d): PUSH BEFORE2, weight=%d, " - "depends=%d, returned=%d", - session->id, id_init, ps.weight, ps.stream_id, rv); - } - } - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, - "h2_stream(%ld-%d): PUSH BEFORE, weight=%d, " - "depends=%d, before=%d, returned=%d", - session->id, nid, w_init, id_dep, id_init, rv); - } - break; - case H2_PUSH_DEP_AFTER: - /* The PUSHed stream is to be sent after the initiating stream. - * Give if the specified weight and let it depend on the intiating - * stream. - */ - /* fall through, it's the default */ - default: - nghttp2_priority_spec_init(&ps, id_init, valid_weight(push->weight), 0); - rv = nghttp2_session_change_stream_priority(session->ngh2, nid, &ps); - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, - "h2_stream(%ld-%d): PUSH AFTER, weight=%d, " - "depends=%d, returned=%d", - session->id, nid, ps.weight, ps.stream_id, rv); - break; - } - } - } -#endif - stream = h2_session_open_stream(session, nid); if (stream) { h2_stream_set_h2_request(stream, is->id, push->req); + h2_stream_set_priority(stream, &push->prio); status = stream_schedule(session, stream, 1); if (status != APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, session->c, @@ -1372,6 +1287,108 @@ struct h2_stream *h2_session_push(h2_session *session, h2_stream *is, return stream; } +static int valid_weight(float f) +{ + int w = floor(f); + return (w < NGHTTP2_MIN_WEIGHT? NGHTTP2_MIN_WEIGHT : + (w > NGHTTP2_MAX_WEIGHT)? NGHTTP2_MAX_WEIGHT : w); +} + +apr_status_t h2_session_set_prio(h2_session *session, h2_stream *stream, + h2_priority *prio) +{ + apr_status_t status = APR_SUCCESS; +#ifdef H2_NG2_CHANGE_PRIO + nghttp2_stream *s_grandpa, *s_parent, *s; + + s = nghttp2_session_find_stream(session->ngh2, stream->id); + if (!s) { + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, + "h2_stream(%ld-%d): lookup of nghttp2_stream failed", + session->id, stream->id); + return APR_EINVAL; + } + + s_parent = nghttp2_stream_get_parent(s); + if (s_parent) { + nghttp2_priority_spec ps; + int id_parent, id_grandpa, w_parent, w, rv = 0; + char *ptype = "AFTER"; + h2_dependency dep = prio->dependency; + + id_parent = nghttp2_stream_get_stream_id(s_parent); + s_grandpa = nghttp2_stream_get_parent(s_parent); + if (s_grandpa) { + id_grandpa = nghttp2_stream_get_stream_id(s_grandpa); + } + else { + /* parent of parent does not exist, + * only possible if parent == root */ + dep = H2_DEPENDANT_AFTER; + } + + switch (dep) { + case H2_DEPENDANT_INTERLEAVED: + /* PUSHed stream is to be interleaved with initiating stream. + * It is made a sibling of the initiating stream and gets a + * proportional weight [1, MAX_WEIGHT] of the initiaing + * stream weight. + */ + ptype = "INTERLEAVED"; + w_parent = nghttp2_stream_get_weight(s_parent); + w = valid_weight(w_parent * ((float)NGHTTP2_MAX_WEIGHT / prio->weight)); + nghttp2_priority_spec_init(&ps, id_grandpa, w, 0); + break; + + case H2_DEPENDANT_BEFORE: + /* PUSHed stream os to be sent BEFORE the initiating stream. + * It gets the same weight as the initiating stream, replaces + * that stream in the dependency tree and has the initiating + * stream as child with MAX_WEIGHT. + */ + ptype = "BEFORE"; + nghttp2_priority_spec_init(&ps, stream->id, NGHTTP2_MAX_WEIGHT, 0); + rv = nghttp2_session_change_stream_priority(session->ngh2, id_parent, &ps); + if (rv < 0) { + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, + "h2_stream(%ld-%d): PUSH BEFORE2, weight=%d, " + "depends=%d, returned=%d", + session->id, id_parent, ps.weight, ps.stream_id, rv); + return APR_EGENERAL; + } + id_grandpa = nghttp2_stream_get_stream_id(s_grandpa); + w_parent = nghttp2_stream_get_weight(s_parent); + nghttp2_priority_spec_init(&ps, id_grandpa, valid_weight(w_parent), 0); + break; + + case H2_DEPENDANT_AFTER: + /* The PUSHed stream is to be sent after the initiating stream. + * Give if the specified weight and let it depend on the intiating + * stream. + */ + /* fall through, it's the default */ + default: + nghttp2_priority_spec_init(&ps, id_parent, valid_weight(prio->weight), 0); + break; + } + + + rv = nghttp2_session_change_stream_priority(session->ngh2, stream->id, &ps); + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, + "h2_stream(%ld-%d): PUSH %s, weight=%d, " + "depends=%d, returned=%d", + session->id, stream->id, ptype, + ps.weight, ps.stream_id, rv); + status = (rv < 0)? APR_EGENERAL : APR_SUCCESS; + } +#else + (void)session; + (void)stream; + (void)prio; +#endif + return status; +} + apr_status_t h2_session_stream_destroy(h2_session *session, h2_stream *stream) { apr_pool_t *pool = h2_stream_detach_pool(stream); diff --git a/modules/http2/h2_session.h b/modules/http2/h2_session.h index 5c3be0a53be..16767fb7859 100644 --- a/modules/http2/h2_session.h +++ b/modules/http2/h2_session.h @@ -41,6 +41,7 @@ struct apr_thread_mutext_t; struct apr_thread_cond_t; struct h2_config; struct h2_mplx; +struct h2_priority; struct h2_push; struct h2_response; struct h2_session; @@ -195,4 +196,9 @@ apr_status_t h2_session_stream_destroy(h2_session *session, struct h2_stream *h2_session_push(h2_session *session, struct h2_stream *is, struct h2_push *push); +apr_status_t h2_session_set_prio(h2_session *session, + struct h2_stream *stream, + struct h2_priority *prio); + + #endif /* defined(__mod_h2__h2_session__) */ diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c index a091e4258b8..c9f88a27b6a 100644 --- a/modules/http2/h2_stream.c +++ b/modules/http2/h2_stream.c @@ -668,3 +668,15 @@ apr_table_t *h2_stream_get_trailers(h2_stream *stream) { return stream->response? stream->response->trailers : NULL; } + +void h2_stream_set_priority(h2_stream *stream, h2_priority *prio) +{ + stream->prio = apr_pcalloc(stream->pool, sizeof(*prio)); + memcpy(stream->prio, prio, sizeof(*prio)); +} + +h2_priority *h2_stream_get_priority(h2_stream *stream) +{ + return stream->prio; +} + diff --git a/modules/http2/h2_stream.h b/modules/http2/h2_stream.h index 79801722f4a..8de3ecbacfc 100644 --- a/modules/http2/h2_stream.h +++ b/modules/http2/h2_stream.h @@ -41,6 +41,7 @@ typedef enum { } h2_stream_state_t; struct h2_mplx; +struct h2_priority; struct h2_request; struct h2_response; struct h2_session; @@ -69,6 +70,8 @@ struct h2_stream { apr_bucket_brigade *bbout; /* output DATA */ apr_off_t data_frames_sent; /* # of DATA frames sent out for this stream */ + + struct h2_priority *prio; /* priority information to set before submit */ }; @@ -300,4 +303,16 @@ apr_status_t h2_stream_submit_pushes(h2_stream *stream); */ apr_table_t *h2_stream_get_trailers(h2_stream *stream); +/** + * Get priority information set for this stream. + */ +struct h2_priority *h2_stream_get_priority(h2_stream *stream); + +/** + * Set the priority information to use on the submit of the stream. + * @param stream the stream to set priority on + * @param prio the priority information + */ +void h2_stream_set_priority(h2_stream *stream, struct h2_priority *prio); + #endif /* defined(__mod_h2__h2_stream__) */