You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2015/12/18 15:45:18 UTC
svn commit: r1720801 - in /httpd/httpd/trunk: ./ docs/manual/mod/
modules/http2/
Author: icing
Date: Fri Dec 18 14:45:18 2015
New Revision: 1720801
URL: http://svn.apache.org/viewvc?rev=1720801&view=rev
Log:
3 new timeout configuration directives for mod_http2
Modified:
httpd/httpd/trunk/CHANGES
httpd/httpd/trunk/docs/manual/mod/mod_http2.xml
httpd/httpd/trunk/modules/http2/h2_config.c
httpd/httpd/trunk/modules/http2/h2_config.h
httpd/httpd/trunk/modules/http2/h2_conn.c
httpd/httpd/trunk/modules/http2/h2_filter.c
httpd/httpd/trunk/modules/http2/h2_filter.h
httpd/httpd/trunk/modules/http2/h2_io.c
httpd/httpd/trunk/modules/http2/h2_io.h
httpd/httpd/trunk/modules/http2/h2_mplx.c
httpd/httpd/trunk/modules/http2/h2_mplx.h
httpd/httpd/trunk/modules/http2/h2_session.c
httpd/httpd/trunk/modules/http2/h2_session.h
httpd/httpd/trunk/modules/http2/h2_version.h
Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1720801&r1=1720800&r2=1720801&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Fri Dec 18 14:45:18 2015
@@ -1,9 +1,14 @@
-*- coding: utf-8 -*-
Changes with Apache 2.5.0
+ *) mod_http2: adding new config directives and the implementation behind
+ them: H2Timeout, H2KeepAliveTimeout, H2StreamTimeout. Documentation in
+ the http2 manual.
+ [Stefan Eissing]
+
*) mod_http2: when running in async mpm processing, mod_http2 will cease
processing on idle connections (e.g. no open streams) back to the mpm.
- [Stefan Eissing]
+ [Stefan Eissing]
*) mod_http2: fixed bug in input window size calculation by moving chunked
request body encoding into later stage of processing.
Modified: httpd/httpd/trunk/docs/manual/mod/mod_http2.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_http2.xml?rev=1720801&r1=1720800&r2=1720801&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_http2.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_http2.xml Fri Dec 18 14:45:18 2015
@@ -709,4 +709,98 @@ H2PushPriority text/css interleaved
</usage>
</directivesynopsis>
+ <directivesynopsis>
+ <name>H2Timeout</name>
+ <description>Timeout (in seconds) for HTTP/2 connections</description>
+ <syntax>H2Timeout seconds</syntax>
+ <default>H2Timeout 5</default>
+ <contextlist>
+ <context>server config</context>
+ <context>virtual host</context>
+ </contextlist>
+ <compatibility>Available in version 2.4.19 and later.</compatibility>
+
+ <usage>
+ <p>
+ This directive sets the timeout for read/write operations on
+ connections where HTTP/2 is negotiated. This can be used server wide or for specific
+ <directive module="core" type="section">VirtualHost</directive>s.
+ </p>
+ <p>
+ This directive is similar to the
+ <directive module="core" type="section">Timeout</directive>, but
+ applies only to HTTP/2 connections.
+ </p>
+ <p>
+ A value of 0 enforces no timeout.
+ </p>
+ </usage>
+ </directivesynopsis>
+
+ <directivesynopsis>
+ <name>H2KeepAliveTimeout</name>
+ <description>Timeout (in seconds) for idle HTTP/2 connections</description>
+ <syntax>H2KeepAliveTimeout seconds</syntax>
+ <default>H2KeepAliveTimeout 300</default>
+ <contextlist>
+ <context>server config</context>
+ <context>virtual host</context>
+ </contextlist>
+ <compatibility>Available in version 2.4.19 and later.</compatibility>
+
+ <usage>
+ <p>
+ This directive sets the timeout for read/write operations on
+ idle connections where HTTP/2 is negotiated. This can be used server wide or for specific
+ <directive module="core" type="section">VirtualHost</directive>s.
+ </p>
+ <p>
+ This directive is similar to the
+ <directive module="core" type="section">KeepAliveTimeout</directive>, but
+ applies only to HTTP/2 connections. A HTTP/2 connection is considered
+ idle when no streams are open, e.g. no requests are ongoing.
+ </p>
+ <p>
+ A value of 0 enforces no timeout.
+ </p>
+ </usage>
+ </directivesynopsis>
+
+ <directivesynopsis>
+ <name>H2StreamTimeout</name>
+ <description>Timeout (in seconds) for idle HTTP/2 connections</description>
+ <syntax>H2StreamTimeout seconds</syntax>
+ <default>H2StreamTimeout 120</default>
+ <contextlist>
+ <context>server config</context>
+ <context>virtual host</context>
+ </contextlist>
+ <compatibility>Available in version 2.4.19 and later.</compatibility>
+
+ <usage>
+ <p>
+ This directive sets the timeout for read/write operations on
+ HTTP/2 streams, e.g. individual requests. This can be used server wide or for specific
+ <directive module="core" type="section">VirtualHost</directive>s.
+ </p>
+ <p>
+ Due to the nature of HTTP/2, which sends multiple requests over a single
+ connection and has priority scheduling, individual streams might not
+ see input for much longer times than HTTP/1.1 requests would.
+ </p>
+ <p>
+ A value of 0 enforces no timeout, so could wait on chances to receive
+ input or write data indefinitely. This expose a server to
+ risks of thread exhaustion.
+ </p>
+ <p>
+ Depending on your handling of pushed streams,
+ priorities and general responsiveness, a site might need to increase
+ this value. For example, if you PUSH a large resource <em>before</em>
+ the requested one, the initial stream will not write until the
+ pushed resource is fully sent.
+ </p>
+ </usage>
+ </directivesynopsis>
+
</modulesynopsis>
Modified: httpd/httpd/trunk/modules/http2/h2_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_config.c?rev=1720801&r1=1720800&r2=1720801&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_config.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_config.c Fri Dec 18 14:45:18 2015
@@ -59,6 +59,9 @@ static h2_config defconf = {
1, /* TLS cooldown secs */
1, /* HTTP/2 server push enabled */
NULL, /* map of content-type to priorities */
+ 5, /* normal connection timeout */
+ 5*60, /* idle connection timeout */
+ 2*60, /* stream timeout */
};
static int files_per_session;
@@ -122,6 +125,9 @@ static void *h2_config_create(apr_pool_t
conf->tls_cooldown_secs = DEF_VAL;
conf->h2_push = DEF_VAL;
conf->priorities = NULL;
+ conf->h2_timeout = DEF_VAL;
+ conf->h2_keepalive = DEF_VAL;
+ conf->h2_stream_timeout = DEF_VAL;
return conf;
}
@@ -167,6 +173,9 @@ void *h2_config_merge(apr_pool_t *pool,
else {
n->priorities = add->priorities? add->priorities : base->priorities;
}
+ n->h2_timeout = H2_CONFIG_GET(add, base, h2_timeout);
+ n->h2_keepalive = H2_CONFIG_GET(add, base, h2_keepalive);
+ n->h2_stream_timeout = H2_CONFIG_GET(add, base, h2_stream_timeout);
return n;
}
@@ -214,6 +223,12 @@ apr_int64_t h2_config_geti64(const h2_co
return H2_CONFIG_GET(conf, &defconf, tls_cooldown_secs);
case H2_CONF_PUSH:
return H2_CONFIG_GET(conf, &defconf, h2_push);
+ case H2_CONF_TIMEOUT_SECS:
+ return H2_CONFIG_GET(conf, &defconf, h2_timeout);
+ case H2_CONF_KEEPALIVE_SECS:
+ return H2_CONFIG_GET(conf, &defconf, h2_keepalive);
+ case H2_CONF_STREAM_TIMEOUT_SECS:
+ return H2_CONFIG_GET(conf, &defconf, h2_stream_timeout);
default:
return DEF_VAL;
}
@@ -511,6 +526,42 @@ static const char *h2_conf_set_tls_coold
return NULL;
}
+static const char *h2_conf_set_timeout(cmd_parms *parms,
+ void *arg, const char *value)
+{
+ h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
+ (void)arg;
+ cfg->h2_timeout = (int)apr_atoi64(value);
+ if (cfg->h2_timeout < 0) {
+ return "value must be >= 0";
+ }
+ return NULL;
+}
+
+static const char *h2_conf_set_keepalive(cmd_parms *parms,
+ void *arg, const char *value)
+{
+ h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
+ (void)arg;
+ cfg->h2_keepalive = (int)apr_atoi64(value);
+ if (cfg->h2_keepalive < 0) {
+ return "value must be >= 0";
+ }
+ return NULL;
+}
+
+static const char *h2_conf_set_stream_timeout(cmd_parms *parms,
+ void *arg, const char *value)
+{
+ h2_config *cfg = (h2_config *)h2_config_sget(parms->server);
+ (void)arg;
+ cfg->h2_stream_timeout = (int)apr_atoi64(value);
+ if (cfg->h2_stream_timeout < 0) {
+ return "value must be >= 0";
+ }
+ return NULL;
+}
+
#define AP_END_CMD AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)
@@ -549,6 +600,12 @@ const command_rec h2_cmds[] = {
RSRC_CONF, "off to disable HTTP/2 server push"),
AP_INIT_TAKE23("H2PushPriority", h2_conf_add_push_priority, NULL,
RSRC_CONF, "define priority of PUSHed resources per content type"),
+ AP_INIT_TAKE1("H2Timeout", h2_conf_set_timeout, NULL,
+ RSRC_CONF, "read/write timeout (seconds) for HTTP/2 connections"),
+ AP_INIT_TAKE1("H2KeepAliveTimeout", h2_conf_set_keepalive, NULL,
+ RSRC_CONF, "timeout (seconds) for idle HTTP/2 connections, no streams open"),
+ AP_INIT_TAKE1("H2StreamTimeout", h2_conf_set_stream_timeout, NULL,
+ RSRC_CONF, "read/write timeout (seconds) for HTTP/2 streams"),
AP_END_CMD
};
Modified: httpd/httpd/trunk/modules/http2/h2_config.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_config.h?rev=1720801&r1=1720800&r2=1720801&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_config.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_config.h Fri Dec 18 14:45:18 2015
@@ -39,6 +39,9 @@ typedef enum {
H2_CONF_TLS_WARMUP_SIZE,
H2_CONF_TLS_COOLDOWN_SECS,
H2_CONF_PUSH,
+ H2_CONF_TIMEOUT_SECS,
+ H2_CONF_KEEPALIVE_SECS,
+ H2_CONF_STREAM_TIMEOUT_SECS,
} h2_config_var_t;
struct apr_hash_t;
@@ -65,6 +68,10 @@ typedef struct h2_config {
int tls_cooldown_secs; /* Seconds of idle time before going back to small TLS records */
int h2_push; /* if HTTP/2 server push is enabled */
struct apr_hash_t *priorities;/* map of content-type to h2_priority records */
+
+ int h2_timeout; /* timeout for http/2 connections */
+ int h2_keepalive; /* timeout for idle connections, no streams */
+ int h2_stream_timeout; /* timeout for http/2 streams, slave connections */
} h2_config;
Modified: httpd/httpd/trunk/modules/http2/h2_conn.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_conn.c?rev=1720801&r1=1720800&r2=1720801&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_conn.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_conn.c Fri Dec 18 14:45:18 2015
@@ -132,7 +132,6 @@ static module *h2_conn_mpm_module(void)
apr_status_t h2_conn_setup(h2_ctx *ctx, conn_rec *c, request_rec *r)
{
h2_session *session;
- h2_filter_core_in *in;
if (!workers) {
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02911)
@@ -149,10 +148,6 @@ apr_status_t h2_conn_setup(h2_ctx *ctx,
h2_ctx_session_set(ctx, session);
- in = apr_pcalloc(session->pool, sizeof(*in));
- in->session = session;
- ap_add_input_filter("H2_IN", in, r, c);
-
ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c);
return APR_SUCCESS;
Modified: httpd/httpd/trunk/modules/http2/h2_filter.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_filter.c?rev=1720801&r1=1720800&r2=1720801&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_filter.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_filter.c Fri Dec 18 14:45:18 2015
@@ -22,14 +22,15 @@
#include <scoreboard.h>
#include "h2_private.h"
-#include "h2_session.h"
#include "h2_conn_io.h"
#include "h2_util.h"
#include "h2_filter.h"
+#define UNSET -1
+#define H2MIN(x,y) ((x) < (y) ? (x) : (y))
-static apr_status_t consume_brigade(h2_filter_core_in *in,
+static apr_status_t consume_brigade(h2_filter_cin *cin,
apr_bucket_brigade *bb,
apr_read_type_e block)
{
@@ -51,13 +52,13 @@ static apr_status_t consume_brigade(h2_f
if (status == APR_SUCCESS && bucket_length > 0) {
apr_size_t consumed = 0;
- status = h2_session_receive(in->session, bucket_data,
- bucket_length, &consumed);
+ status = cin->cb(cin->cb_ctx, bucket_data, bucket_length, &consumed);
if (status == APR_SUCCESS && bucket_length > consumed) {
/* We have data left in the bucket. Split it. */
status = apr_bucket_split(bucket, consumed);
}
readlen += consumed;
+ cin->last_read = apr_time_now();
}
}
apr_bucket_delete(bucket);
@@ -69,6 +70,38 @@ static apr_status_t consume_brigade(h2_f
return status;
}
+static apr_status_t check_time_left(h2_filter_cin *cin,
+ apr_time_t *ptime_left)
+{
+ if (cin->timeout_secs > 0) {
+ *ptime_left = (cin->last_read + apr_time_from_sec(cin->timeout_secs)
+ - apr_time_now());
+ if (*ptime_left <= 0)
+ return APR_TIMEUP;
+
+ if (*ptime_left < apr_time_from_sec(1)) {
+ *ptime_left = apr_time_from_sec(1);
+ }
+ }
+ return APR_SUCCESS;
+}
+
+h2_filter_cin *h2_filter_cin_create(apr_pool_t *p, h2_filter_cin_cb *cb, void *ctx)
+{
+ h2_filter_cin *cin;
+
+ cin = apr_pcalloc(p, sizeof(*cin));
+ cin->pool = p;
+ cin->cb = cb;
+ cin->cb_ctx = ctx;
+ cin->last_read = UNSET;
+ return cin;
+}
+
+void h2_filter_cin_timeout_set(h2_filter_cin *cin, int timeout_secs)
+{
+ cin->timeout_secs = timeout_secs;
+}
apr_status_t h2_filter_core_input(ap_filter_t* f,
apr_bucket_brigade* brigade,
@@ -76,10 +109,12 @@ apr_status_t h2_filter_core_input(ap_fil
apr_read_type_e block,
apr_off_t readbytes)
{
- h2_filter_core_in *in = f->ctx;
+ h2_filter_cin *cin = f->ctx;
apr_status_t status = APR_SUCCESS;
+ apr_time_t saved_timeout = UNSET;
+ apr_time_t time_left = UNSET;
- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, f->c,
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
"core_input: read, block=%d, mode=%d, readbytes=%ld",
block, mode, (long)readbytes);
@@ -91,32 +126,54 @@ apr_status_t h2_filter_core_input(ap_fil
return (block == APR_BLOCK_READ)? APR_SUCCESS : APR_EAGAIN;
}
- if (!f->bb) {
- f->bb = apr_brigade_create(in->session->pool, f->c->bucket_alloc);
+ if (!cin->bb) {
+ cin->bb = apr_brigade_create(cin->pool, f->c->bucket_alloc);
+ }
+
+ if (!cin->socket) {
+ cin->socket = ap_get_conn_socket(f->c);
+ cin->last_read = apr_time_now(); /* first call */
}
- if (APR_BRIGADE_EMPTY(f->bb)) {
+ if (APR_BRIGADE_EMPTY(cin->bb)) {
/* We only do a blocking read when we have no streams to process. So,
* in httpd scoreboard lingo, we are in a KEEPALIVE connection state.
* When reading non-blocking, we do have streams to process and update
* child with NULL request. That way, any current request information
* in the scoreboard is preserved.
*/
+ status = check_time_left(cin, &time_left);
+ if (status != APR_SUCCESS)
+ goto out;
+
if (block == APR_BLOCK_READ) {
ap_update_child_status_from_conn(f->c->sbh,
SERVER_BUSY_KEEPALIVE, f->c);
+ if (time_left > 0) {
+ status = apr_socket_timeout_get(cin->socket, &saved_timeout);
+ AP_DEBUG_ASSERT(status == APR_SUCCESS);
+ status = apr_socket_timeout_set(cin->socket, H2MIN(time_left, saved_timeout));
+ AP_DEBUG_ASSERT(status == APR_SUCCESS);
+ }
}
else {
ap_update_child_status(f->c->sbh, SERVER_BUSY_READ, NULL);
}
- status = ap_get_brigade(f->next, f->bb, AP_MODE_READBYTES,
+ status = ap_get_brigade(f->next, cin->bb, AP_MODE_READBYTES,
block, readbytes);
}
+out:
switch (status) {
case APR_SUCCESS:
- return consume_brigade(in, f->bb, block);
+ if (saved_timeout != UNSET) {
+ apr_socket_timeout_set(cin->socket, saved_timeout);
+ }
+ status = consume_brigade(cin, cin->bb, block);
+ if (status == APR_SUCCESS) {
+ status = check_time_left(cin, &time_left);
+ }
case APR_EOF:
case APR_EAGAIN:
break;
Modified: httpd/httpd/trunk/modules/http2/h2_filter.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_filter.h?rev=1720801&r1=1720800&r2=1720801&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_filter.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_filter.h Fri Dec 18 14:45:18 2015
@@ -18,9 +18,23 @@
struct h2_session;
-typedef struct {
- struct h2_session *session;
-} h2_filter_core_in;
+typedef apr_status_t h2_filter_cin_cb(void *ctx,
+ const char *data, apr_size_t len,
+ apr_size_t *readlen);
+
+typedef struct h2_filter_cin {
+ apr_pool_t *pool;
+ apr_bucket_brigade *bb;
+ h2_filter_cin_cb *cb;
+ void *cb_ctx;
+ apr_socket_t *socket;
+ int timeout_secs;
+ apr_time_t last_read;
+} h2_filter_cin;
+
+h2_filter_cin *h2_filter_cin_create(apr_pool_t *p, h2_filter_cin_cb *cb, void *ctx);
+
+void h2_filter_cin_timeout_set(h2_filter_cin *cin, int timeout_secs);
apr_status_t h2_filter_core_input(ap_filter_t* filter,
apr_bucket_brigade* brigade,
Modified: httpd/httpd/trunk/modules/http2/h2_io.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_io.c?rev=1720801&r1=1720800&r2=1720801&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_io.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_io.c Fri Dec 18 14:45:18 2015
@@ -15,13 +15,18 @@
#include <assert.h>
+#include <apr_thread_mutex.h>
+#include <apr_thread_cond.h>
+
#include <httpd.h>
#include <http_core.h>
#include <http_log.h>
#include <http_connection.h>
#include "h2_private.h"
+#include "h2_h2.h"
#include "h2_io.h"
+#include "h2_mplx.h"
#include "h2_response.h"
#include "h2_request.h"
#include "h2_task.h"
@@ -95,6 +100,66 @@ apr_status_t h2_io_in_shutdown(h2_io *io
return h2_io_in_close(io);
}
+
+void h2_io_signal_init(h2_io *io, h2_io_op op, int timeout_secs, apr_thread_cond_t *cond)
+{
+ io->timed_op = op;
+ io->timed_cond = cond;
+ if (timeout_secs > 0) {
+ io->timeout_at = apr_time_now() + apr_time_from_sec(timeout_secs);
+ }
+ else {
+ io->timeout_at = 0;
+ }
+}
+
+void h2_io_signal_exit(h2_io *io)
+{
+ io->timed_cond = NULL;
+ io->timeout_at = 0;
+}
+
+apr_status_t h2_io_signal_wait(h2_mplx *m, h2_io *io)
+{
+ apr_status_t status;
+
+ if (io->timeout_at != 0) {
+ status = apr_thread_cond_timedwait(io->timed_cond, m->lock, io->timeout_at);
+ if (APR_STATUS_IS_TIMEUP(status)) {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, m->c,
+ "h2_mplx(%ld-%d): stream timeout expired: %s",
+ m->id, io->id,
+ (io->timed_op == H2_IO_READ)? "read" : "write");
+ h2_io_rst(io, H2_ERR_CANCEL);
+ }
+ }
+ else {
+ apr_thread_cond_wait(io->timed_cond, m->lock);
+ status = APR_SUCCESS;
+ }
+ if (io->orphaned && status == APR_SUCCESS) {
+ return APR_ECONNABORTED;
+ }
+ return status;
+}
+
+void h2_io_signal(h2_io *io, h2_io_op op)
+{
+ if (io->timed_cond && (io->timed_op == op || H2_IO_ANY == op)) {
+ apr_thread_cond_signal(io->timed_cond);
+ }
+}
+
+void h2_io_make_orphaned(h2_io *io, int error)
+{
+ io->orphaned = 1;
+ if (error) {
+ h2_io_rst(io, error);
+ }
+ /* if someone is waiting, wake him up */
+ h2_io_signal(io, H2_IO_ANY);
+}
+
static int add_trailer(void *ctx, const char *key, const char *value)
{
apr_bucket_brigade *bb = ctx;
Modified: httpd/httpd/trunk/modules/http2/h2_io.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_io.h?rev=1720801&r1=1720800&r2=1720801&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_io.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_io.h Fri Dec 18 14:45:18 2015
@@ -18,6 +18,7 @@
struct h2_response;
struct apr_thread_cond_t;
+struct h2_mplx;
struct h2_request;
@@ -25,6 +26,12 @@ typedef apr_status_t h2_io_data_cb(void
typedef int h2_stream_pri_cmp(int stream_id1, int stream_id2, void *ctx);
+typedef enum {
+ H2_IO_READ,
+ H2_IO_WRITE,
+ H2_IO_ANY,
+}
+h2_io_op;
typedef struct h2_io h2_io;
@@ -39,16 +46,18 @@ struct h2_io {
struct h2_response *response;/* response for submit, once created */
int rst_error;
+ h2_io_op timed_op; /* which operation is waited on */
+ struct apr_thread_cond_t *timed_cond; /* condition to wait on */
+ apr_time_t timeout_at; /* when IO wait will time out */
+
int eos_in;
int eos_in_written;
apr_bucket_brigade *bbin; /* input data for stream */
- struct apr_thread_cond_t *input_arrived; /* block on reading */
apr_size_t input_consumed; /* how many bytes have been read */
int eos_out;
apr_bucket_brigade *bbout; /* output data from stream */
apr_bucket_alloc_t *bucket_alloc;
- struct apr_thread_cond_t *output_drained; /* block on writing */
int files_handles_owned;
apr_bucket_brigade *tmp; /* temporary data for chunking */
@@ -88,6 +97,14 @@ int h2_io_in_has_eos_for(h2_io *io);
*/
int h2_io_out_has_data(h2_io *io);
+void h2_io_signal(h2_io *io, h2_io_op op);
+void h2_io_signal_init(h2_io *io, h2_io_op op, int timeout_secs,
+ struct apr_thread_cond_t *cond);
+void h2_io_signal_exit(h2_io *io);
+apr_status_t h2_io_signal_wait(struct h2_mplx *m, h2_io *io);
+
+void h2_io_make_orphaned(h2_io *io, int error);
+
/*******************************************************************************
* Input handling of streams.
******************************************************************************/
Modified: httpd/httpd/trunk/modules/http2/h2_mplx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_mplx.c?rev=1720801&r1=1720800&r2=1720801&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_mplx.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_mplx.c Fri Dec 18 14:45:18 2015
@@ -145,6 +145,7 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr
m->workers = workers;
m->file_handles_allowed = h2_config_geti(conf, H2_CONF_SESSION_FILES);
+ m->stream_timeout_secs = h2_config_geti(conf, H2_CONF_STREAM_TIMEOUT_SECS);
}
return m;
}
@@ -248,10 +249,7 @@ static int io_stream_done(h2_mplx *m, h2
}
else {
/* cleanup once task is done */
- io->orphaned = 1;
- if (rst_error) {
- h2_io_rst(io, rst_error);
- }
+ h2_io_make_orphaned(io, rst_error);
return 1;
}
}
@@ -283,9 +281,9 @@ apr_status_t h2_mplx_release_and_join(h2
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c,
"h2_mplx(%ld): release_join -> destroy, (#ios=%ld)",
m->id, (long)h2_io_set_size(m->stream_ios));
+ apr_thread_mutex_unlock(m->lock);
h2_mplx_destroy(m);
/* all gone */
- /*apr_thread_mutex_unlock(m->lock);*/
}
return status;
}
@@ -356,8 +354,9 @@ apr_status_t h2_mplx_in_read(h2_mplx *m,
if (APR_SUCCESS == status) {
h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
if (io && !io->orphaned) {
- io->input_arrived = iowait;
H2_MPLX_IO_IN(APLOG_TRACE2, m, io, "h2_mplx_in_read_pre");
+
+ h2_io_signal_init(io, H2_IO_READ, m->stream_timeout_secs, iowait);
status = h2_io_in_read(io, bb, -1, trailers);
while (APR_STATUS_IS_EAGAIN(status)
&& !is_aborted(m, &status)
@@ -365,11 +364,13 @@ apr_status_t h2_mplx_in_read(h2_mplx *m,
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, m->c,
"h2_mplx(%ld-%d): wait on in data (BLOCK_READ)",
m->id, stream_id);
- apr_thread_cond_wait(io->input_arrived, m->lock);
- status = h2_io_in_read(io, bb, -1, trailers);
+ status = h2_io_signal_wait(m, io);
+ if (status == APR_SUCCESS) {
+ status = h2_io_in_read(io, bb, -1, trailers);
+ }
}
H2_MPLX_IO_IN(APLOG_TRACE2, m, io, "h2_mplx_in_read_post");
- io->input_arrived = NULL;
+ h2_io_signal_exit(io);
}
else {
status = APR_EOF;
@@ -394,9 +395,7 @@ apr_status_t h2_mplx_in_write(h2_mplx *m
H2_MPLX_IO_IN(APLOG_TRACE2, m, io, "h2_mplx_in_write_pre");
status = h2_io_in_write(io, bb);
H2_MPLX_IO_IN(APLOG_TRACE2, m, io, "h2_mplx_in_write_post");
- if (io->input_arrived) {
- apr_thread_cond_signal(io->input_arrived);
- }
+ h2_io_signal(io, H2_IO_READ);
io_process_events(m, io);
}
else {
@@ -420,9 +419,7 @@ apr_status_t h2_mplx_in_close(h2_mplx *m
if (io && !io->orphaned) {
status = h2_io_in_close(io);
H2_MPLX_IO_IN(APLOG_TRACE2, m, io, "h2_mplx_in_close");
- if (io->input_arrived) {
- apr_thread_cond_signal(io->input_arrived);
- }
+ h2_io_signal(io, H2_IO_READ);
io_process_events(m, io);
}
else {
@@ -496,8 +493,8 @@ apr_status_t h2_mplx_out_readx(h2_mplx *
status = h2_io_out_readx(io, cb, ctx, plen, peos);
H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_readx_post");
- if (status == APR_SUCCESS && cb && io->output_drained) {
- apr_thread_cond_signal(io->output_drained);
+ if (status == APR_SUCCESS && cb) {
+ h2_io_signal(io, H2_IO_WRITE);
}
}
else {
@@ -529,8 +526,8 @@ apr_status_t h2_mplx_out_read_to(h2_mplx
status = h2_io_out_read_to(io, bb, plen, peos);
H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_read_to_post");
- if (status == APR_SUCCESS && io->output_drained) {
- apr_thread_cond_signal(io->output_drained);
+ if (status == APR_SUCCESS) {
+ h2_io_signal(io, H2_IO_WRITE);
}
}
else {
@@ -576,7 +573,7 @@ h2_stream *h2_mplx_next_submit(h2_mplx *
"h2_mplx(%ld): stream for response %d closed, "
"resetting io to close request processing",
m->id, io->id);
- io->orphaned = 1;
+ h2_io_make_orphaned(io, H2_ERR_STREAM_CLOSED);
if (io->task_done) {
io_destroy(m, io, 1);
}
@@ -585,14 +582,11 @@ h2_stream *h2_mplx_next_submit(h2_mplx *
* shutdown input and send out any events (e.g. window
* updates) asap. */
h2_io_in_shutdown(io);
- h2_io_rst(io, H2_ERR_STREAM_CLOSED);
io_process_events(m, io);
}
}
- if (io->output_drained) {
- apr_thread_cond_signal(io->output_drained);
- }
+ h2_io_signal(io, H2_IO_WRITE);
}
apr_thread_mutex_unlock(m->lock);
}
@@ -610,28 +604,29 @@ static apr_status_t out_write(h2_mplx *m
* We will not split buckets to enforce the limit to the last
* byte. After all, the bucket is already in memory.
*/
- while (!APR_BRIGADE_EMPTY(bb)
- && (status == APR_SUCCESS)
+ while (status == APR_SUCCESS
+ && !APR_BRIGADE_EMPTY(bb)
&& !is_aborted(m, &status)) {
status = h2_io_out_write(io, bb, m->stream_max_mem, trailers,
&m->file_handles_allowed);
- /* Wait for data to drain until there is room again */
- while (!APR_BRIGADE_EMPTY(bb)
+ /* Wait for data to drain until there is room again or
+ * stream timeout expires */
+ h2_io_signal_init(io, H2_IO_WRITE, m->stream_timeout_secs, iowait);
+ while (status == APR_SUCCESS
+ && !APR_BRIGADE_EMPTY(bb)
&& iowait
- && status == APR_SUCCESS
&& (m->stream_max_mem <= h2_io_out_length(io))
&& !is_aborted(m, &status)) {
trailers = NULL;
- io->output_drained = iowait;
if (f) {
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c,
"h2_mplx(%ld-%d): waiting for out drain",
m->id, io->id);
}
- apr_thread_cond_wait(io->output_drained, m->lock);
- io->output_drained = NULL;
+ status = h2_io_signal_wait(m, io);
}
+ h2_io_signal_exit(io);
}
apr_brigade_cleanup(bb);
@@ -793,9 +788,7 @@ apr_status_t h2_mplx_out_rst(h2_mplx *m,
H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_rst");
have_out_data_for(m, stream_id);
- if (io->output_drained) {
- apr_thread_cond_signal(io->output_drained);
- }
+ h2_io_signal(io, H2_IO_WRITE);
}
else {
status = APR_ECONNABORTED;
Modified: httpd/httpd/trunk/modules/http2/h2_mplx.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_mplx.h?rev=1720801&r1=1720800&r2=1720801&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_mplx.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_mplx.h Fri Dec 18 14:45:18 2015
@@ -77,6 +77,7 @@ struct h2_mplx {
int aborted;
apr_size_t stream_max_mem;
+ int stream_timeout_secs;
apr_pool_t *spare_pool; /* spare pool, ready for next io */
struct h2_workers *workers;
Modified: httpd/httpd/trunk/modules/http2/h2_session.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_session.c?rev=1720801&r1=1720800&r2=1720801&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_session.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_session.c Fri Dec 18 14:45:18 2015
@@ -27,6 +27,7 @@
#include "h2_bucket_eos.h"
#include "h2_config.h"
#include "h2_ctx.h"
+#include "h2_filter.h"
#include "h2_h2.h"
#include "h2_mplx.h"
#include "h2_push.h"
@@ -66,6 +67,9 @@ static void update_window(void *ctx, int
session->id, stream_id, (long)bytes_read);
}
+static apr_status_t h2_session_receive(void *ctx,
+ const char *data, apr_size_t len,
+ apr_size_t *readlen);
h2_stream *h2_session_open_stream(h2_session *session, int stream_id)
{
@@ -708,7 +712,9 @@ static h2_session *h2_session_create_int
session->max_stream_count = h2_config_geti(session->config, H2_CONF_MAX_STREAMS);
session->max_stream_mem = h2_config_geti(session->config, H2_CONF_STREAM_MAX_MEM);
-
+ session->timeout_secs = h2_config_geti(session->config, H2_CONF_TIMEOUT_SECS);
+ session->keepalive_secs = h2_config_geti(session->config, H2_CONF_KEEPALIVE_SECS);
+
status = apr_thread_cond_create(&session->iowait, session->pool);
if (status != APR_SUCCESS) {
return NULL;
@@ -721,6 +727,11 @@ static h2_session *h2_session_create_int
h2_mplx_set_consumed_cb(session->mplx, update_window, session);
+ /* Install the connection input filter that feeds the session */
+ session->cin = h2_filter_cin_create(session->pool, h2_session_receive, session);
+ h2_filter_cin_timeout_set(session->cin, session->timeout_secs);
+ ap_add_input_filter("H2_IN", session->cin, r, c);
+
h2_conn_io_init(&session->io, c, session->config, session->pool);
session->bbtmp = apr_brigade_create(session->pool, c->bucket_alloc);
@@ -1557,10 +1568,10 @@ static apr_status_t h2_session_send(h2_s
return APR_SUCCESS;
}
-apr_status_t h2_session_receive(h2_session *session,
- const char *data, apr_size_t len,
- apr_size_t *readlen)
+static apr_status_t h2_session_receive(void *ctx, const char *data,
+ apr_size_t len, apr_size_t *readlen)
{
+ h2_session *session = ctx;
if (len > 0) {
ssize_t n = nghttp2_session_mem_recv(session->ngh2,
(const uint8_t *)data, len);
@@ -1713,7 +1724,8 @@ apr_status_t h2_session_process(h2_sessi
|| idle
|| (!h2_stream_set_has_unsubmitted(session->streams)
&& !h2_stream_set_has_suspended(session->streams)));
-
+
+ h2_filter_cin_timeout_set(session->cin, idle? session->keepalive_secs : session->timeout_secs);
status = h2_session_read(session, may_block && !async);
ap_log_cerror( APLOG_MARK, APLOG_TRACE1, status, session->c,
Modified: httpd/httpd/trunk/modules/http2/h2_session.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_session.h?rev=1720801&r1=1720800&r2=1720801&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_session.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_session.h Fri Dec 18 14:45:18 2015
@@ -41,6 +41,7 @@ struct apr_thread_mutext_t;
struct apr_thread_cond_t;
struct h2_ctx;
struct h2_config;
+struct h2_filter_cin;
struct h2_mplx;
struct h2_priority;
struct h2_push;
@@ -83,6 +84,10 @@ struct h2_session {
apr_bucket_brigade *bbtmp; /* brigade for keeping temporary data */
struct apr_thread_cond_t *iowait; /* our cond when trywaiting for data */
+ int timeout_secs; /* connection timeout (seconds) */
+ int keepalive_secs; /* connection idle timeout (seconds) */
+
+ struct h2_filter_cin *cin; /* connection input filter context */
h2_conn_io io; /* io on httpd conn filters */
struct h2_mplx *mplx; /* multiplexer for stream data */
@@ -123,14 +128,6 @@ h2_session *h2_session_rcreate(request_r
struct h2_workers *workers);
/**
- * Recieve len bytes of raw HTTP/2 input data. Return the amount
- * consumed and if the session is done.
- */
-apr_status_t h2_session_receive(h2_session *session,
- const char *data, apr_size_t len,
- apr_size_t *readlen);
-
-/**
* Process the given HTTP/2 session until it is ended or a fatal
* error occured.
*
Modified: httpd/httpd/trunk/modules/http2/h2_version.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_version.h?rev=1720801&r1=1720800&r2=1720801&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_version.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_version.h Fri Dec 18 14:45:18 2015
@@ -20,7 +20,7 @@
* @macro
* Version number of the h2 module as c string
*/
-#define MOD_HTTP2_VERSION "1.0.12-DEV"
+#define MOD_HTTP2_VERSION "1.0.12-DEVd"
/**
* @macro