From 85900b7fd8faf51fad3a2410556bfe71b7c53896 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Sat, 31 Dec 2016 13:11:59 +0000 Subject: On the trunk: mod_http2: adding support for MergeTrailers directive. mod_http2: limiting DATA frame sizes by TLS record sizes in use on the connection. Flushing outgoing frames earlier. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1776735 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 5 +++++ modules/http2/h2_config.c | 16 ++++++++++++++++ modules/http2/h2_config.h | 2 ++ modules/http2/h2_conn.c | 6 ++++++ modules/http2/h2_conn_io.c | 16 +++++++++++++--- modules/http2/h2_conn_io.h | 1 + modules/http2/h2_from_h1.c | 9 ++++++++- modules/http2/h2_session.c | 6 ++---- modules/http2/h2_stream.c | 11 ++++------- 9 files changed, 57 insertions(+), 15 deletions(-) diff --git a/CHANGES b/CHANGES index 40bfa5d52d..bb9b761c61 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,11 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.0 + *) mod_http2: adding support for MergeTrailers directive. [Stefan Eissing] + + *) mod_http2: limiting DATA frame sizes by TLS record sizes in use on the + connection. Flushing outgoing frames earlier. [Stefan Eissing] + *) mod_remoteip: Add support for PROXY protocol (code donated by Cloudzilla). Add ability for PROXY protocol processing to be optional to donated code. See also: http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt diff --git a/modules/http2/h2_config.c b/modules/http2/h2_config.c index 669d20e75c..f91c8c257a 100644 --- a/modules/http2/h2_config.c +++ b/modules/http2/h2_config.c @@ -64,6 +64,7 @@ static h2_config defconf = { 0, /* copy files across threads */ NULL, /* push list */ 0, /* early hints, http status 103 */ + 2, /* TLS records flush count */ }; void h2_config_init(apr_pool_t *pool) @@ -99,6 +100,7 @@ static void *h2_config_create(apr_pool_t *pool, conf->copy_files = DEF_VAL; conf->push_list = NULL; conf->early_hints = DEF_VAL; + conf->tls_flush_count = DEF_VAL; return conf; } @@ -151,6 +153,7 @@ static void *h2_config_merge(apr_pool_t *pool, void *basev, void *addv) n->push_list = add->push_list? add->push_list : base->push_list; } n->early_hints = H2_CONFIG_GET(add, base, early_hints); + n->tls_flush_count = H2_CONFIG_GET(add, base, tls_flush_count); return n; } @@ -208,6 +211,8 @@ apr_int64_t h2_config_geti64(const h2_config *conf, h2_config_var_t var) return H2_CONFIG_GET(conf, &defconf, copy_files); case H2_CONF_EARLY_HINTS: return H2_CONFIG_GET(conf, &defconf, early_hints); + case H2_CONF_TLS_FLUSH_COUNT: + return H2_CONFIG_GET(conf, &defconf, tls_flush_count); default: return DEF_VAL; } @@ -505,6 +510,15 @@ static const char *h2_conf_set_tls_cooldown_secs(cmd_parms *parms, return NULL; } +static const char *h2_conf_set_tls_flush_count(cmd_parms *parms, + void *arg, const char *value) +{ + h2_config *cfg = (h2_config *)h2_config_sget(parms->server); + cfg->tls_flush_count = (int)apr_atoi64(value); + (void)arg; + return NULL; +} + static const char *h2_conf_set_push_diary_size(cmd_parms *parms, void *arg, const char *value) { @@ -643,6 +657,8 @@ const command_rec h2_cmds[] = { RSRC_CONF, "number of bytes on TLS connection before doing max writes"), AP_INIT_TAKE1("H2TLSCoolDownSecs", h2_conf_set_tls_cooldown_secs, NULL, RSRC_CONF, "seconds of idle time on TLS before shrinking writes"), + AP_INIT_TAKE1("H2TLSFlushCount", h2_conf_set_tls_flush_count, NULL, + RSRC_CONF, "number of max TLS records before output is flushed"), AP_INIT_TAKE1("H2Push", h2_conf_set_push, NULL, RSRC_CONF, "off to disable HTTP/2 server push"), AP_INIT_TAKE23("H2PushPriority", h2_conf_add_push_priority, NULL, diff --git a/modules/http2/h2_config.h b/modules/http2/h2_config.h index 1f2fe309d0..60257df427 100644 --- a/modules/http2/h2_config.h +++ b/modules/http2/h2_config.h @@ -42,6 +42,7 @@ typedef enum { H2_CONF_PUSH_DIARY_SIZE, H2_CONF_COPY_FILES, H2_CONF_EARLY_HINTS, + H2_CONF_TLS_FLUSH_COUNT, } h2_config_var_t; struct apr_hash_t; @@ -79,6 +80,7 @@ typedef struct h2_config { int copy_files; /* if files shall be copied vs setaside on output */ apr_array_header_t *push_list;/* list of h2_push_res configurations */ int early_hints; /* support status code 103 */ + int tls_flush_count; /* max # of TLS records until output flushed */ } h2_config; diff --git a/modules/http2/h2_conn.c b/modules/http2/h2_conn.c index 6f3a8cfe8e..81d2b7f5f3 100644 --- a/modules/http2/h2_conn.c +++ b/modules/http2/h2_conn.c @@ -208,7 +208,9 @@ apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c) do { if (c->cs) { c->cs->sense = CONN_SENSE_DEFAULT; + c->cs->state = CONN_STATE_HANDLER; } + status = h2_session_process(h2_ctx_session_get(ctx), async_mpm); if (APR_STATUS_IS_EOF(status)) { @@ -227,6 +229,10 @@ apr_status_t h2_conn_run(struct h2_ctx *ctx, conn_rec *c) && c->keepalive == AP_CONN_KEEPALIVE && mpm_state != AP_MPMQ_STOPPING); + if (c->cs) { + c->cs->state = CONN_STATE_WRITE_COMPLETION; + } + return DONE; } diff --git a/modules/http2/h2_conn_io.c b/modules/http2/h2_conn_io.c index 303860eeb8..13d29913df 100644 --- a/modules/http2/h2_conn_io.c +++ b/modules/http2/h2_conn_io.c @@ -133,6 +133,7 @@ apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c, io->is_tls = h2_h2_is_tls(c); io->buffer_output = io->is_tls; io->pass_threshold = (apr_size_t)h2_config_geti64(cfg, H2_CONF_STREAM_MAX_MEM) / 2; + io->flush_factor = h2_config_geti(cfg, H2_CONF_TLS_FLUSH_COUNT); if (io->is_tls) { /* This is what we start with, @@ -420,9 +421,18 @@ apr_status_t h2_conn_io_pass(h2_conn_io *io, apr_bucket_brigade *bb) if (status == APR_SUCCESS) { if (!APR_BRIGADE_EMPTY(io->output)) { - apr_off_t len = h2_brigade_mem_size(io->output); - if (len >= io->pass_threshold) { - return pass_output(io, 0, NULL); + apr_off_t len; + if (io->buffer_output) { + apr_brigade_length(io->output, 0, &len); + if (len >= (io->flush_factor * io->write_size)) { + return pass_output(io, 1, NULL); + } + } + else { + len = h2_brigade_mem_size(io->output); + if (len >= io->pass_threshold) { + return pass_output(io, 0, NULL); + } } } } diff --git a/modules/http2/h2_conn_io.h b/modules/http2/h2_conn_io.h index 4ccf007086..bda0c8ff6d 100644 --- a/modules/http2/h2_conn_io.h +++ b/modules/http2/h2_conn_io.h @@ -40,6 +40,7 @@ typedef struct { int buffer_output; apr_size_t pass_threshold; + int flush_factor; char *scratch; apr_size_t ssize; diff --git a/modules/http2/h2_from_h1.c b/modules/http2/h2_from_h1.c index 108e318276..64cfb76778 100644 --- a/modules/http2/h2_from_h1.c +++ b/modules/http2/h2_from_h1.c @@ -730,6 +730,9 @@ apr_status_t h2_filter_request_in(ap_filter_t* f, request_rec *r = f->r; apr_status_t status = APR_SUCCESS; apr_bucket *b, *next; + core_server_config *conf = + (core_server_config *) ap_get_module_config(r->server->module_config, + &core_module); ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, f->r, "h2_task(%s): request filter, exp=%d", task->id, r->expecting_100); @@ -744,7 +747,11 @@ apr_status_t h2_filter_request_in(ap_filter_t* f, ap_assert(headers); ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "h2_task(%s): receiving trailers", task->id); - r->trailers_in = apr_table_clone(r->pool, headers->headers); + r->trailers_in = headers->headers; + if (conf && conf->merge_trailers == AP_MERGE_TRAILERS_ENABLE) { + r->headers_in = apr_table_overlay(r->pool, r->headers_in, + r->trailers_in); + } APR_BUCKET_REMOVE(b); apr_bucket_destroy(b); ap_remove_input_filter(f); diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c index 44eed63325..f2db2997f7 100644 --- a/modules/http2/h2_session.c +++ b/modules/http2/h2_session.c @@ -1394,6 +1394,8 @@ static apr_status_t h2_session_send(h2_session *session) apr_socket_timeout_set(socket, session->s->timeout); } + /* This sends one round of frames from every able stream, plus + * settings etc. if accumulated */ rv = nghttp2_session_send(session->ngh2); if (socket) { @@ -2040,10 +2042,6 @@ apr_status_t h2_session_process(h2_session *session, int async) session->id, async); } - if (c->cs) { - c->cs->state = CONN_STATE_WRITE_COMPLETION; - } - while (session->state != H2_SESSION_ST_DONE) { trace = APLOGctrace3(c); session->have_read = session->have_written = 0; diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c index 815b6e313b..6fe5ed46cd 100644 --- a/modules/http2/h2_stream.c +++ b/modules/http2/h2_stream.c @@ -602,7 +602,7 @@ apr_status_t h2_stream_out_prepare(h2_stream *stream, apr_off_t *plen, { conn_rec *c = stream->session->c; apr_status_t status = APR_SUCCESS; - apr_off_t requested; + apr_off_t requested, max_chunk = H2_DATA_CHUNK_SIZE; apr_bucket *b, *e; if (presponse) { @@ -620,13 +620,10 @@ apr_status_t h2_stream_out_prepare(h2_stream *stream, apr_off_t *plen, } prep_output(stream); - if (*plen > 0) { - requested = H2MIN(*plen, H2_DATA_CHUNK_SIZE); + if (stream->session->io.write_size > 0) { + max_chunk = stream->session->io.write_size - 9; /* header bits */ } - else { - requested = H2_DATA_CHUNK_SIZE; - } - *plen = requested; + *plen = requested = (*plen > 0)? H2MIN(*plen, max_chunk) : max_chunk; H2_STREAM_OUT_LOG(APLOG_TRACE2, stream, "h2_stream_out_prepare_pre"); h2_util_bb_avail(stream->out_buffer, plen, peos); -- cgit v1.2.1