From: Stefan Eissing Date: Wed, 30 Mar 2016 15:35:58 +0000 (+0000) Subject: mod_http2: new vars, keepalive increase, no slave reuse when con->keepalive not set... X-Git-Tag: 2.5.0-alpha~1810 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=42cc4efc74fed396ec6a04140542d6e8d9bb478d;p=apache mod_http2: new vars, keepalive increase, no slave reuse when con->keepalive not set properly git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1737125 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index ea15bb1899..498d145b36 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,12 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.0 + *) mod_http2: incrementing keepalives on each request started so that logging + %k gives increasing numbers per master http2 connection. + New documented variables in env, usable in custom log formats: H2_PUSH, + H2_PUSHED, H2_PUSHED_ON, H2_STREAM_ID and H2_STREAM_TAG. + [Stefan Eissing] + *) core: Do not read .htaccess if AllowOverride and AllowOverrideList are "None". PR 58528. [Michael Schlenker Environment Variables

This module can be configured to provide HTTP/2 related information - as additional environment variables to the SSI and CGI namespace. + as additional environment variables to the SSI and CGI namespace, as well + as in custom log configurations (see %{VAR_NAME}e).

@@ -178,7 +179,12 @@ Protocols h2 h2c http/1.1 - + + + + + +
Description:
HTTP2flagHTTP/2 is being used.
H2PUSHflagHTTP/2 Server Push is enabled for this request and also supported by the client.
H2PUSHflagHTTP/2 Server Push is enabled for this connection and also supported by the client.
H2_PUSHflagalternate name for H2PUSH
H2_PUSHEDstringempty or PUSHED for a request being pushed by the server.
H2_PUSHED_ONnumberHTTP/2 stream number that triggered the push of this request.
H2_STREAM_IDnumberHTTP/2 stream number of this request.
H2_STREAM_TAGstringHTTP/2 process unique stream identifier, consisting of connection id and stream id separated by -.
diff --git a/modules/http2/h2.h b/modules/http2/h2.h index 335d368899..acb79cd2e2 100644 --- a/modules/http2/h2.h +++ b/modules/http2/h2.h @@ -117,7 +117,8 @@ typedef struct h2_request h2_request; struct h2_request { int id; /* stream id */ - + int initiated_on; /* initiating stream id (PUSH) or 0 */ + const char *method; /* pseudo header values, see ch. 8.1.2.3 */ const char *scheme; const char *authority; diff --git a/modules/http2/h2_ctx.c b/modules/http2/h2_ctx.c index e8294fcb2b..8b786b94d9 100644 --- a/modules/http2/h2_ctx.c +++ b/modules/http2/h2_ctx.c @@ -65,7 +65,11 @@ h2_ctx *h2_ctx_rget(const request_rec *r) const char *h2_ctx_protocol_get(const conn_rec *c) { - h2_ctx *ctx = (h2_ctx*)ap_get_module_config(c->conn_config, &http2_module); + h2_ctx *ctx; + if (c->master) { + c = c->master; + } + ctx = (h2_ctx*)ap_get_module_config(c->conn_config, &http2_module); return ctx? ctx->protocol : NULL; } diff --git a/modules/http2/h2_io.c b/modules/http2/h2_io.c index d3c0e6c04d..5bbf09e99b 100644 --- a/modules/http2/h2_io.c +++ b/modules/http2/h2_io.c @@ -108,10 +108,16 @@ void h2_io_set_response(h2_io *io, h2_response *response) AP_DEBUG_ASSERT(io->pool); AP_DEBUG_ASSERT(response); AP_DEBUG_ASSERT(!io->response); - io->response = h2_response_clone(io->pool, response); + /* we used to clone the response into the io->pool. But + * we have much tighter control over the EOR bucket nowadays, + * so just use the instance given */ + io->response = response; if (response->rst_error) { h2_io_rst(io, response->rst_error); } + else if (response->content_length == 0) { + io->eos_out = 1; + } } void h2_io_rst(h2_io *io, int error) @@ -378,16 +384,8 @@ apr_status_t h2_io_out_get_brigade(h2_io *io, apr_bucket_brigade *bb, } } -static void process_trailers(h2_io *io, apr_table_t *trailers) -{ - if (trailers && io->response) { - h2_response_set_trailers(io->response, - apr_table_clone(io->pool, trailers)); - } -} - apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb, - apr_size_t maxlen, apr_table_t *trailers, + apr_size_t maxlen, apr_size_t *pfile_buckets_allowed) { apr_status_t status; @@ -415,8 +413,6 @@ apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb, } } - process_trailers(io, trailers); - /* Let's move the buckets from the request processing in here, so * that the main thread can read them when it has time/capacity. * @@ -439,13 +435,12 @@ apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb, } -apr_status_t h2_io_out_close(h2_io *io, apr_table_t *trailers) +apr_status_t h2_io_out_close(h2_io *io) { if (io->rst_error) { return APR_ECONNABORTED; } if (!io->eos_out_read) { /* EOS has not been read yet */ - process_trailers(io, trailers); if (!io->eos_out) { check_bbout(io); io->eos_out = 1; diff --git a/modules/http2/h2_io.h b/modules/http2/h2_io.h index 7730d7754e..d700f6f322 100644 --- a/modules/http2/h2_io.h +++ b/modules/http2/h2_io.h @@ -37,7 +37,7 @@ typedef struct h2_io h2_io; struct h2_io { int id; /* stream identifier */ - apr_pool_t *pool; /* stream pool */ + apr_pool_t *pool; /* stream pool */ apr_bucket_alloc_t *bucket_alloc; const struct h2_request *request;/* request on this io */ @@ -156,14 +156,14 @@ apr_status_t h2_io_out_get_brigade(h2_io *io, apr_off_t len); apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb, - apr_size_t maxlen, apr_table_t *trailers, + apr_size_t maxlen, apr_size_t *pfile_buckets_allowed); /** * Closes the input. After existing data has been read, APR_EOF will * be returned. */ -apr_status_t h2_io_out_close(h2_io *io, apr_table_t *trailers); +apr_status_t h2_io_out_close(h2_io *io); /** * Gives the overall length of the data that is currently queued for diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c index 3d37990ef6..6513a75415 100644 --- a/modules/http2/h2_mplx.c +++ b/modules/http2/h2_mplx.c @@ -306,12 +306,13 @@ static void io_destroy(h2_mplx *m, h2_io *io, int events) h2_task_destroy(io->task); io->task = NULL; - if (reuse_slave) { + if (reuse_slave && slave->keepalive == AP_CONN_KEEPALIVE) { apr_bucket_delete(io->eor); io->eor = NULL; APR_ARRAY_PUSH(m->spare_slaves, conn_rec*) = slave; } else { + slave->sbh = NULL; h2_slave_destroy(slave, NULL); } } @@ -697,7 +698,6 @@ h2_stream *h2_mplx_next_submit(h2_mplx *m, h2_ihash_t *streams) static apr_status_t out_write(h2_mplx *m, h2_io *io, ap_filter_t* f, int blocking, apr_bucket_brigade *bb, - apr_table_t *trailers, struct apr_thread_cond_t *iowait) { apr_status_t status = APR_SUCCESS; @@ -711,7 +711,7 @@ static apr_status_t out_write(h2_mplx *m, h2_io *io, && !is_aborted(m, &status)) { status = h2_io_out_write(io, bb, blocking? m->stream_max_mem : INT_MAX, - trailers, &m->tx_handles_reserved); + &m->tx_handles_reserved); io_out_consumed_signal(m, io); /* Wait for data to drain until there is room again or @@ -728,7 +728,6 @@ static apr_status_t out_write(h2_mplx *m, h2_io *io, m->id, io->id); return APR_INCOMPLETE; } - trailers = NULL; if (f) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c, "h2_mplx(%ld-%d): waiting for out drain", @@ -766,7 +765,7 @@ static apr_status_t out_open(h2_mplx *m, int stream_id, h2_response *response, check_tx_reservation(m); } if (bb) { - status = out_write(m, io, f, 0, bb, response->trailers, iowait); + status = out_write(m, io, f, 0, bb, iowait); if (status == APR_INCOMPLETE) { /* write will have transferred as much data as possible. caller has to deal with non-empty brigade */ @@ -807,7 +806,6 @@ apr_status_t h2_mplx_out_open(h2_mplx *m, int stream_id, h2_response *response, apr_status_t h2_mplx_out_write(h2_mplx *m, int stream_id, ap_filter_t* f, int blocking, apr_bucket_brigade *bb, - apr_table_t *trailers, struct apr_thread_cond_t *iowait) { apr_status_t status; @@ -817,10 +815,9 @@ apr_status_t h2_mplx_out_write(h2_mplx *m, int stream_id, if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) { h2_io *io = h2_io_set_get(m->stream_ios, stream_id); if (io && !io->orphaned) { - status = out_write(m, io, f, blocking, bb, trailers, iowait); + status = out_write(m, io, f, blocking, bb, iowait); ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, m->c, - "h2_mplx(%ld-%d): write with trailers=%s", - m->id, io->id, trailers? "yes" : "no"); + "h2_mplx(%ld-%d): write", m->id, io->id); H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_write"); have_out_data_for(m, stream_id); @@ -833,7 +830,7 @@ apr_status_t h2_mplx_out_write(h2_mplx *m, int stream_id, return status; } -apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id, apr_table_t *trailers) +apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id) { apr_status_t status; int acquired; @@ -855,10 +852,9 @@ apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id, apr_table_t *trailers) m->id, io->id); } ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, m->c, - "h2_mplx(%ld-%d): close with eor=%s, trailers=%s", - m->id, io->id, io->eor? "yes" : "no", - trailers? "yes" : "no"); - status = h2_io_out_close(io, trailers); + "h2_mplx(%ld-%d): close with eor=%s", + m->id, io->id, io->eor? "yes" : "no"); + status = h2_io_out_close(io); H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_close"); io_out_consumed_signal(m, io); @@ -987,7 +983,8 @@ static h2_io *open_io(h2_mplx *m, int stream_id, const h2_request *request) } -apr_status_t h2_mplx_process(h2_mplx *m, int stream_id, const h2_request *req, +apr_status_t h2_mplx_process(h2_mplx *m, int stream_id, + const h2_request *req, h2_stream_pri_cmp *cmp, void *ctx) { apr_status_t status; @@ -1048,8 +1045,9 @@ static h2_task *pop_task(h2_mplx *m) h2_slave_run_pre_connection(slave, ap_get_conn_socket(slave)); } - ++m->c->keepalives; + slave->sbh = m->c->sbh; io->task = task = h2_task_create(m->id, io->request, slave, m); + m->c->keepalives++; apr_table_setn(slave->notes, H2_TASK_ID_NOTE, task->id); io->worker_started = 1; @@ -1111,7 +1109,7 @@ static void task_done(h2_mplx *m, h2_task *task, h2_req_engine *ngn) /* TODO: this will keep a worker attached to this h2_mplx as * long as it has requests to handle. Might no be fair to * other mplx's. Perhaps leave after n requests? */ - h2_mplx_out_close(m, task->stream_id, NULL); + h2_mplx_out_close(m, task->stream_id); if (ngn && io) { apr_off_t bytes = io->output_consumed + h2_io_out_length(io); diff --git a/modules/http2/h2_mplx.h b/modules/http2/h2_mplx.h index aa1a04f877..4029847678 100644 --- a/modules/http2/h2_mplx.h +++ b/modules/http2/h2_mplx.h @@ -190,7 +190,8 @@ apr_status_t h2_mplx_out_trywait(h2_mplx *m, apr_interval_time_t timeout, * @param cmp the stream priority compare function * @param ctx context data for the compare function */ -apr_status_t h2_mplx_process(h2_mplx *m, int stream_id, const struct h2_request *r, +apr_status_t h2_mplx_process(h2_mplx *m, int stream_id, + const struct h2_request *r, h2_stream_pri_cmp *cmp, void *ctx); /** @@ -289,21 +290,18 @@ apr_status_t h2_mplx_out_open(h2_mplx *mplx, int stream_id, * @param blocking == 0 iff call should return with APR_INCOMPLETE if * the full brigade cannot be written at once * @param bb the bucket brigade to append - * @param trailers optional trailers for response, maybe NULL * @param iowait a conditional used for block/signalling in h2_mplx */ apr_status_t h2_mplx_out_write(h2_mplx *mplx, int stream_id, ap_filter_t* filter, int blocking, apr_bucket_brigade *bb, - apr_table_t *trailers, struct apr_thread_cond_t *iowait); /** - * Closes the output for stream stream_id. Optionally forwards trailers - * fromt the processed stream. + * Closes the output for stream stream_id. */ -apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id, apr_table_t *trailers); +apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id); apr_status_t h2_mplx_out_rst(h2_mplx *m, int stream_id, int error); diff --git a/modules/http2/h2_request.c b/modules/http2/h2_request.c index acd89a684c..6f8016a363 100644 --- a/modules/http2/h2_request.c +++ b/modules/http2/h2_request.c @@ -342,6 +342,7 @@ apr_status_t h2_request_add_trailer(h2_request *req, apr_pool_t *pool, void h2_request_copy(apr_pool_t *p, h2_request *dst, const h2_request *src) { /* keep the dst id */ + dst->initiated_on = src->initiated_on; dst->method = OPT_COPY(p, src->method); dst->scheme = OPT_COPY(p, src->scheme); dst->authority = OPT_COPY(p, src->authority); @@ -350,9 +351,15 @@ void h2_request_copy(apr_pool_t *p, h2_request *dst, const h2_request *src) if (src->trailers) { dst->trailers = apr_table_clone(p, src->trailers); } + else { + dst->trailers = NULL; + } dst->content_length = src->content_length; dst->chunked = src->chunked; dst->eoh = src->eoh; + dst->body = src->body; + dst->serialize = src->serialize; + dst->push_policy = src->push_policy; } h2_request *h2_request_clone(apr_pool_t *p, const h2_request *src) diff --git a/modules/http2/h2_response.c b/modules/http2/h2_response.c index 01bb20b990..eb9043d0db 100644 --- a/modules/http2/h2_response.c +++ b/modules/http2/h2_response.c @@ -70,6 +70,28 @@ static const char *get_sos_filter(apr_table_t *notes) return notes? apr_table_get(notes, H2_RESP_SOS_NOTE) : NULL; } +static void check_clen(h2_response *response, request_rec *r, apr_pool_t *pool) +{ + + if (r && r->header_only) { + response->content_length = 0; + } + else if (response->headers) { + const char *s = apr_table_get(response->headers, "Content-Length"); + if (s) { + char *end; + response->content_length = apr_strtoi64(s, &end, 10); + if (s == end) { + ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, + pool, APLOGNO(02956) + "h2_response: content-length" + " value not parsed: %s", s); + response->content_length = -1; + } + } + } +} + static h2_response *h2_response_create_int(int stream_id, int rst_error, int http_status, @@ -78,7 +100,6 @@ static h2_response *h2_response_create_int(int stream_id, apr_pool_t *pool) { h2_response *response; - const char *s; if (!headers) { return NULL; @@ -96,19 +117,7 @@ static h2_response *h2_response_create_int(int stream_id, response->headers = headers; response->sos_filter = get_sos_filter(notes); - s = apr_table_get(headers, "Content-Length"); - if (s) { - char *end; - - response->content_length = apr_strtoi64(s, &end, 10); - if (s == end) { - ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, - pool, APLOGNO(02956) - "h2_response: content-length" - " value not parsed: %s", s); - response->content_length = -1; - } - } + check_clen(response, NULL, pool); return response; } @@ -138,6 +147,8 @@ h2_response *h2_response_rcreate(int stream_id, request_rec *r, response->headers = header; response->sos_filter = get_sos_filter(r->notes); + check_clen(response, r, pool); + if (response->http_status == HTTP_FORBIDDEN) { const char *cause = apr_table_get(r->notes, "ssl-renegotiate-forbidden"); if (cause) { diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c index fe4c843510..be16ab4415 100644 --- a/modules/http2/h2_session.c +++ b/modules/http2/h2_session.c @@ -491,7 +491,7 @@ static int on_frame_recv_cb(nghttp2_session *ng2s, session->id, (int)frame->hd.stream_id, (int)frame->rst_stream.error_code); stream = h2_session_get_stream(session, frame->hd.stream_id); - if (stream && stream->initiated_on) { + if (stream && stream->request && stream->request->initiated_on) { ++session->pushes_reset; } else { @@ -1270,18 +1270,21 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream) rv = NGHTTP2_PROTOCOL_ERROR; } else if (response && response->headers) { - nghttp2_data_provider provider; + nghttp2_data_provider provider, *pprovider = NULL; h2_ngheader *ngh; const h2_priority *prio; - memset(&provider, 0, sizeof(provider)); - provider.source.fd = stream->id; - provider.read_callback = stream_data_cb; - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03073) "h2_stream(%ld-%d): submit response %d", session->id, stream->id, response->http_status); + if (response->content_length != 0) { + memset(&provider, 0, sizeof(provider)); + provider.source.fd = stream->id; + provider.read_callback = stream_data_cb; + pprovider = &provider; + } + /* If this stream is not a pushed one itself, * and HTTP/2 server push is enabled here, * and the response is in the range 200-299 *), @@ -1297,7 +1300,7 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream) * as the client, having this resource in its cache, might * also have the pushed ones as well. */ - if (!stream->initiated_on + if (stream->request && !stream->request->initiated_on && H2_HTTP_2XX(response->http_status) && h2_session_push_enabled(session)) { @@ -1313,7 +1316,7 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream) ngh = h2_util_ngheader_make_res(stream->pool, response->http_status, response->headers); rv = nghttp2_submit_response(session->ngh2, response->stream_id, - ngh->nv, ngh->nvlen, &provider); + ngh->nv, ngh->nvlen, pprovider); } else { int err = H2_STREAM_RST(stream, H2_ERR_PROTOCOL_ERROR); @@ -1327,7 +1330,7 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream) } stream->submitted = 1; - if (stream->initiated_on) { + if (stream->request && stream->request->initiated_on) { ++session->pushes_submitted; } else { diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c index 0aaed8c42e..0a1dadf9dd 100644 --- a/modules/http2/h2_stream.c +++ b/modules/http2/h2_stream.c @@ -235,7 +235,7 @@ void h2_stream_set_h2_request(h2_stream *stream, int initiated_on, const h2_request *req) { h2_request_copy(stream->pool, stream->request, req); - stream->initiated_on = initiated_on; + stream->request->initiated_on = initiated_on; stream->request->eoh = 0; } @@ -476,7 +476,7 @@ const h2_priority *h2_stream_get_priority(h2_stream *stream) { h2_response *response = h2_stream_get_response(stream); - if (stream->initiated_on && response) { + if (response && stream->request && stream->request->initiated_on) { const char *ctype = apr_table_get(response->headers, "content-type"); if (ctype) { /* FIXME: Not good enough, config needs to come from request->server */ diff --git a/modules/http2/h2_stream.h b/modules/http2/h2_stream.h index a861b894e1..f0cd2167a3 100644 --- a/modules/http2/h2_stream.h +++ b/modules/http2/h2_stream.h @@ -43,7 +43,6 @@ typedef struct h2_stream h2_stream; struct h2_stream { int id; /* http2 stream id */ - int initiated_on; /* http2 stream id this was initiated on or 0 */ h2_stream_state_t state; /* http/2 state of this stream */ struct h2_session *session; /* the session this stream belongs to */ diff --git a/modules/http2/h2_task.c b/modules/http2/h2_task.c index ceb569a52f..e764fcc832 100644 --- a/modules/http2/h2_task.c +++ b/modules/http2/h2_task.c @@ -135,7 +135,7 @@ h2_task *h2_task_create(long session_id, const h2_request *req, ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, c, APLOGNO(02941) "h2_task(%ld-%d): create stream task", session_id, req->id); - h2_mplx_out_close(mplx, req->id, NULL); + h2_mplx_out_close(mplx, req->id); return NULL; } diff --git a/modules/http2/h2_task_output.c b/modules/http2/h2_task_output.c index 959398d1d1..80938d1fcc 100644 --- a/modules/http2/h2_task_output.c +++ b/modules/http2/h2_task_output.c @@ -45,23 +45,6 @@ h2_task_output *h2_task_output_create(h2_task *task, conn_rec *c) return output; } -static apr_table_t *get_trailers(h2_task_output *output) -{ - if (!output->trailers_passed) { - h2_response *response = h2_from_h1_get_response(output->from_h1); - if (response && response->trailers) { - output->trailers_passed = 1; - if (h2_task_logio_add_bytes_out) { - /* counter trailers as if we'd do a HTTP/1.1 serialization */ - h2_task_logio_add_bytes_out(output->task->c, - h2_util_table_bytes(response->trailers, 3)+1); - } - return response->trailers; - } - } - return NULL; -} - static apr_status_t open_response(h2_task_output *output, ap_filter_t *f, apr_bucket_brigade *bb, const char *caller) { @@ -71,7 +54,7 @@ static apr_status_t open_response(h2_task_output *output, ap_filter_t *f, if (f) { /* This happens currently when ap_die(status, r) is invoked * by a read request filter. */ - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, output->task->c, APLOGNO(03204) + ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, output->task->c, APLOGNO(03204) "h2_task_output(%s): write without response by %s " "for %s %s %s", output->task->id, caller, @@ -91,7 +74,6 @@ static apr_status_t open_response(h2_task_output *output, ap_filter_t *f, output->written = h2_util_table_bytes(response->headers, 3)+1; h2_task_logio_add_bytes_out(output->task->c, output->written); } - get_trailers(output); ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, output->task->c, APLOGNO(03348) "h2_task(%s): open response to %s %s %s", output->task->id, output->task->request->method, @@ -113,8 +95,7 @@ static apr_status_t write_brigade_raw(h2_task_output *output, output->task->id, (long)written); status = h2_mplx_out_write(output->task->mplx, output->task->stream_id, - f, output->task->blocking, bb, - get_trailers(output), output->task->io); + f, output->task->blocking, bb, output->task->io); if (status == APR_INCOMPLETE) { apr_brigade_length(bb, 0, &left); written -= left; diff --git a/modules/http2/h2_task_output.h b/modules/http2/h2_task_output.h index ba396f07eb..3135bc459e 100644 --- a/modules/http2/h2_task_output.h +++ b/modules/http2/h2_task_output.h @@ -33,7 +33,6 @@ struct h2_task_output { struct h2_from_h1 *from_h1; unsigned int response_open : 1; - unsigned int trailers_passed : 1; apr_off_t written; apr_bucket_brigade *bb; diff --git a/modules/http2/mod_http2.c b/modules/http2/mod_http2.c index 6450eb9ea0..0d33969161 100644 --- a/modules/http2/mod_http2.c +++ b/modules/http2/mod_http2.c @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -198,36 +199,83 @@ static void h2_hooks(apr_pool_t *pool) ap_hook_handler(h2_filter_h2_status_handler, NULL, NULL, APR_HOOK_MIDDLE); } -static char *value_of_HTTP2(apr_pool_t *p, server_rec *s, - conn_rec *c, request_rec *r) +static const char *val_HTTP2(apr_pool_t *p, server_rec *s, + conn_rec *c, request_rec *r, h2_ctx *ctx) { - return c && http2_is_h2(c)? "on" : "off"; + return ctx? "on" : "off"; } -static char *value_of_H2PUSH(apr_pool_t *p, server_rec *s, - conn_rec *c, request_rec *r) +static const char *val_H2_PUSH(apr_pool_t *p, server_rec *s, + conn_rec *c, request_rec *r, h2_ctx *ctx) { - h2_ctx *ctx; - if (r) { - ctx = h2_ctx_rget(r); - if (ctx) { + if (ctx) { + if (r) { h2_task *task = h2_ctx_get_task(ctx); - return (task && task->request->push_policy != H2_PUSH_NONE)? "on" : "off"; + if (task && task->request->push_policy != H2_PUSH_NONE) { + return "on"; + } + } + else if (c && h2_session_push_enabled(ctx->session)) { + return "on"; } - } - else if (c) { - ctx = h2_ctx_get(c, 0); - return ctx && h2_session_push_enabled(ctx->session)? "on" : "off"; } else if (s) { const h2_config *cfg = h2_config_sget(s); - return cfg && h2_config_geti(cfg, H2_CONF_PUSH)? "on" : "off"; + if (cfg && h2_config_geti(cfg, H2_CONF_PUSH)) { + return "on"; + } } return "off"; } -typedef char *h2_var_lookup(apr_pool_t *p, server_rec *s, - conn_rec *c, request_rec *r); +static const char *val_H2_PUSHED(apr_pool_t *p, server_rec *s, + conn_rec *c, request_rec *r, h2_ctx *ctx) +{ + if (ctx) { + h2_task *task = h2_ctx_get_task(ctx); + if (task && !H2_STREAM_CLIENT_INITIATED(task->stream_id)) { + return "PUSHED"; + } + } + return ""; +} + +static const char *val_H2_PUSHED_ON(apr_pool_t *p, server_rec *s, + conn_rec *c, request_rec *r, h2_ctx *ctx) +{ + if (ctx) { + h2_task *task = h2_ctx_get_task(ctx); + if (task && !H2_STREAM_CLIENT_INITIATED(task->stream_id)) { + return apr_itoa(p, task->request->initiated_on); + } + } + return ""; +} + +static const char *val_H2_STREAM_TAG(apr_pool_t *p, server_rec *s, + conn_rec *c, request_rec *r, h2_ctx *ctx) +{ + if (ctx) { + h2_task *task = h2_ctx_get_task(ctx); + if (task) { + return task->id; + } + } + return ""; +} + +static const char *val_H2_STREAM_ID(apr_pool_t *p, server_rec *s, + conn_rec *c, request_rec *r, h2_ctx *ctx) +{ + const char *cp = val_H2_STREAM_TAG(p, s, c, r, ctx); + if (cp && (cp = ap_strchr_c(cp, '-'))) { + return ++cp; + } + return NULL; +} + +typedef const char *h2_var_lookup(apr_pool_t *p, server_rec *s, + conn_rec *c, request_rec *r, h2_ctx *ctx); typedef struct h2_var_def { const char *name; h2_var_lookup *lookup; @@ -235,8 +283,13 @@ typedef struct h2_var_def { } h2_var_def; static h2_var_def H2_VARS[] = { - { "HTTP2", value_of_HTTP2, 1 }, - { "H2PUSH", value_of_H2PUSH, 1 }, + { "HTTP2", val_HTTP2, 1 }, + { "H2PUSH", val_H2_PUSH, 1 }, + { "H2_PUSH", val_H2_PUSH, 1 }, + { "H2_PUSHED", val_H2_PUSHED, 1 }, + { "H2_PUSHED_ON", val_H2_PUSHED_ON, 1 }, + { "H2_STREAM_ID", val_H2_STREAM_ID, 1 }, + { "H2_STREAM_TAG", val_H2_STREAM_TAG, 1 }, }; #ifndef H2_ALEN @@ -257,7 +310,9 @@ static char *http2_var_lookup(apr_pool_t *p, server_rec *s, for (i = 0; i < H2_ALEN(H2_VARS); ++i) { h2_var_def *vdef = &H2_VARS[i]; if (!strcmp(vdef->name, name)) { - return vdef->lookup(p, s, c, r); + h2_ctx *ctx = (r? h2_ctx_rget(r) : + h2_ctx_get(c->master? c->master : c, 0)); + return (char *)vdef->lookup(p, s, c, r, ctx); } } return ""; @@ -273,7 +328,8 @@ static int h2_h2_fixups(request_rec *r) h2_var_def *vdef = &H2_VARS[i]; if (vdef->subprocess) { apr_table_setn(r->subprocess_env, vdef->name, - vdef->lookup(r->pool, r->server, r->connection, r)); + vdef->lookup(r->pool, r->server, r->connection, + r, ctx)); } } }