-*- 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
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)
conf->copy_files = DEF_VAL;
conf->push_list = NULL;
conf->early_hints = DEF_VAL;
+ conf->tls_flush_count = DEF_VAL;
return conf;
}
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;
}
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;
}
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)
{
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,
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;
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;
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)) {
&& c->keepalive == AP_CONN_KEEPALIVE
&& mpm_state != AP_MPMQ_STOPPING);
+ if (c->cs) {
+ c->cs->state = CONN_STATE_WRITE_COMPLETION;
+ }
+
return DONE;
}
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,
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);
+ }
}
}
}
int buffer_output;
apr_size_t pass_threshold;
+ int flush_factor;
char *scratch;
apr_size_t ssize;
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);
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);
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) {
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;
{
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) {
}
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);