diff --git a/docs/manual/mod/mod_proxy_wstunnel.html.en b/docs/manual/mod/mod_proxy_wstunnel.html.en
index 21ffbe2..16e1628 100644
--- a/docs/manual/mod/mod_proxy_wstunnel.html.en
+++ b/docs/manual/mod/mod_proxy_wstunnel.html.en
@@ -60,14 +60,33 @@ NONE means you bypass the check for the header but still upgrade to WebSocket.
ANY means that Upgrade
will read in the request headers and use
in the response Upgrade
This module provides no - directives.
+ProxyWebsocketIdleTimeout num[ms]
ProxyWebsocketIdleTimeout 0
This directive imposes a maximum amount of time for the tunnel to be + left open while idle. The timeout is considered in seconds by default, but + it is possible to increase the time resolution to milliseconds + adding the ms suffix.
+ +Available Languages: en | diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c index 4aadbab..ca3ed3a 100644 --- a/modules/proxy/mod_proxy_wstunnel.c +++ b/modules/proxy/mod_proxy_wstunnel.c @@ -18,6 +18,10 @@ module AP_MODULE_DECLARE_DATA proxy_wstunnel_module; +typedef struct { + apr_time_t idle_timeout; +} proxyws_dir_conf; + /* * Canonicalise http-like URLs. * scheme is the scheme for the URL @@ -108,6 +112,8 @@ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r, conn_rec *c = r->connection; apr_socket_t *sock = conn->sock; conn_rec *backconn = conn->connection; + proxyws_dir_conf *dconf = ap_get_module_config(r->per_dir_config, + &proxy_wstunnel_module); char *buf; apr_bucket_brigade *header_brigade; apr_bucket *e; @@ -185,10 +191,13 @@ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r, c->keepalive = AP_CONN_CLOSE; do { /* Loop until done (one side closes the connection, or an error) */ - rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled); + rv = apr_pollset_poll(pollset, dconf->idle_timeout, &pollcnt, &signalled); if (rv != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(rv)) { continue; + } else if(APR_STATUS_IS_TIMEUP(rv)){ + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "RH: the connection has timed out"); + return HTTP_REQUEST_TIME_OUT; } ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02444) "error apr_poll()"); return HTTP_INTERNAL_SERVER_ERROR; @@ -366,6 +375,38 @@ cleanup: return status; } +static const char * proxyws_set_idle(cmd_parms *cmd, void *conf, const char *val) +{ + proxyws_dir_conf *dconf = conf; + if (ap_timeout_parameter_parse(val, &(dconf->idle_timeout), "s") != APR_SUCCESS) + return "ProxyWebsocketIdleTimeout timeout has wrong format"; + + if (dconf->idle_timeout < 0) + return "ProxyWebsocketIdleTimeout timeout has to be a non-negative number"; + + if (!dconf->idle_timeout) dconf->idle_timeout = -1; /* loop indefinitely */ + + return NULL; +} + +static void *create_proxyws_dir_config(apr_pool_t *p, char *dummy) +{ + proxyws_dir_conf *new = + (proxyws_dir_conf *) apr_pcalloc(p, sizeof(proxyws_dir_conf)); + + new->idle_timeout = -1; /* no timeout */ + + return (void *) new; +} + +static const command_rec ws_proxy_cmds[] = +{ + AP_INIT_TAKE1("ProxyWebsocketIdleTimeout", proxyws_set_idle, NULL, RSRC_CONF|ACCESS_CONF, + "timeout for activity in either direction, unlimited by default."), + + {NULL} +}; + static void ap_proxy_http_register_hook(apr_pool_t *p) { proxy_hook_scheme_handler(proxy_wstunnel_handler, NULL, NULL, APR_HOOK_FIRST); @@ -374,10 +415,10 @@ static void ap_proxy_http_register_hook(apr_pool_t *p) AP_DECLARE_MODULE(proxy_wstunnel) = { STANDARD20_MODULE_STUFF, - NULL, /* create per-directory config structure */ + create_proxyws_dir_config, /* create per-directory config structure */ NULL, /* merge per-directory config structures */ NULL, /* create per-server config structure */ NULL, /* merge per-server config structures */ - NULL, /* command apr_table_t */ + ws_proxy_cmds, /* command apr_table_t */ ap_proxy_http_register_hook /* register hooks */ };