On Sun, Apr 13, 2014 at 2:41 PM, <[email protected]> wrote: > Author: covener > Date: Sun Apr 13 18:41:05 2014 > New Revision: 1587075 > > URL: http://svn.apache.org/r1587075 > Log: > several related mod_proxy_wstunnel changes that are tough to pull apart: > > * make async websockets tunnel opt-in > * add config for how long we block a thread in asynch mode > * add config for a cap on the synchronous path > * avoid sending error responses down the upgraded tunnel > > > Modified: > httpd/httpd/trunk/CHANGES > httpd/httpd/trunk/docs/manual/mod/mod_proxy_wstunnel.xml > httpd/httpd/trunk/modules/proxy/mod_proxy_wstunnel.c > > Modified: httpd/httpd/trunk/CHANGES > URL: > http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1587075&r1=1587074&r2=1587075&view=diff > > ============================================================================== > --- httpd/httpd/trunk/CHANGES [utf-8] (original) > +++ httpd/httpd/trunk/CHANGES [utf-8] Sun Apr 13 18:41:05 2014 > @@ -1,6 +1,17 @@ > -*- coding: > utf-8 -*- > Changes with Apache 2.5.0 > > + *) mod_proxy_wstunnel: Avoid sending error responses down an upgraded > + websockets connection as it is being close down. [Eric Covener] > + > + *) mod_proxy_wstunnel: Allow the administrator to cap the amount > + of time a synchronous websockets connection stays idle with > + ProxyWebsocketIdleTimeout. [Eric Covener] > + > + *) mod_proxy_wstunnel: Change to opt-in for asynchronous support, adding > + directives ProxyWebsocketAsynch and ProxyWebsocketAsynchDelay. >
Should be "Async" instead of "Asynch" IMO... the latter form is rather uncommon... > + [Eric Covener] > + > *) mod_proxy_wstunnel: Stop leaking websockets backend connections under > event MPMi (trunk-only). [Eric Covener] > > > Modified: httpd/httpd/trunk/docs/manual/mod/mod_proxy_wstunnel.xml > URL: > http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_proxy_wstunnel.xml?rev=1587075&r1=1587074&r2=1587075&view=diff > > ============================================================================== > --- httpd/httpd/trunk/docs/manual/mod/mod_proxy_wstunnel.xml (original) > +++ httpd/httpd/trunk/docs/manual/mod/mod_proxy_wstunnel.xml Sun Apr 13 > 18:41:05 2014 > @@ -52,4 +52,50 @@ ProxyPass /wss2/ wss://echo.websocket.or > </summary> > > <seealso><module>mod_proxy</module></seealso> > + > +<directivesynopsis> > +<name>ProxyWebsocketAsynch</name> > +<description>Instructs this module to try to create an asynchronous > tunnel</description> > +<syntax>ProxyWebsocketAsynch ON|OFF</syntax> > +<contextlist><context>server config</context> > +<context>virtual host</context> > +</contextlist> > + > +<usage> > + <p>This directive instructs the server to try to create an > asynchronous tunnel. > + If the current MPM does not support the necessary features, a > synchronous > + tunnel is used.</p> > +</usage> > +</directivesynopsis> > + > +<directivesynopsis> > +<name>ProxyWebsocketIdleTimeout</name> > +<description>Sets the maximum amount of time to wait for data on the > websockets tunnel</description> > +<syntax>ProxyWebsocketIdleTimeout <var>num</var>[ms]</syntax> > +<default>ProxyWebsocketIdleTimeout 0</default> > +<contextlist><context>server config</context> > +<context>virtual host</context> > +</contextlist> > + > +<usage> > + <p>This directive imposes a maximum amount of time for the tunnel to > be > + left open while idle. This directive is ignored if > <directive>ProxyWebsocketAsynch</directive> > + is enabled and the running MPM supports the necessary features</p> > +</usage> > +</directivesynopsis> > + > +<directivesynopsis> > +<name>ProxyWebsocketAsynchDelay</name> > +<description>Sets the amount of time the tunnel waits synchronously for > data</description> > +<syntax>ProxyWebsocketAsynchDelay <var>num</var>[ms]</syntax> > +<default>ProxyWebsocketAsynchDelay 0</default> > +<contextlist><context>server config</context> > +<context>virtual host</context> > +</contextlist> > + > +<usage> > + <p>If <directive>ProxyWebsocketAsynch</directive> is enabled, this > directive > + controls how long the server synchronously waits for more data.</p> > +</usage> > +</directivesynopsis> > </modulesynopsis> > > Modified: httpd/httpd/trunk/modules/proxy/mod_proxy_wstunnel.c > URL: > http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy_wstunnel.c?rev=1587075&r1=1587074&r2=1587075&view=diff > > ============================================================================== > --- httpd/httpd/trunk/modules/proxy/mod_proxy_wstunnel.c (original) > +++ httpd/httpd/trunk/modules/proxy/mod_proxy_wstunnel.c Sun Apr 13 > 18:41:05 2014 > @@ -19,6 +19,12 @@ > > module AP_MODULE_DECLARE_DATA proxy_wstunnel_module; > > +typedef struct { > + signed char is_async; > + apr_time_t idle_timeout; > + apr_time_t async_delay; > +} proxyws_dir_conf; > + > typedef struct ws_baton_t { > request_rec *r; > proxy_conn_rec *proxy_connrec; > @@ -34,7 +40,7 @@ typedef struct ws_baton_t { > static int proxy_wstunnel_transfer(request_rec *r, conn_rec *c_i, > conn_rec *c_o, > apr_bucket_brigade *bb, char *name); > > -static int proxy_wstunnel_pump(ws_baton_t *baton, apr_time_t timeout) { > +static int proxy_wstunnel_pump(ws_baton_t *baton, apr_time_t timeout, int > try_async) { > request_rec *r = baton->r; > conn_rec *c = r->connection; > proxy_conn_rec *conn = baton->proxy_connrec; > @@ -49,14 +55,20 @@ static int proxy_wstunnel_pump(ws_baton_ > apr_bucket_brigade *bb = baton->bb; > > while(1) { > + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "poll timeout is > %"APR_TIME_T_FMT"ms %s", apr_time_as_msec(timeout), try_async ? "async" : > "sync"); > if ((rv = apr_pollset_poll(pollset, timeout, &pollcnt, > &signalled)) > != APR_SUCCESS) { > if (APR_STATUS_IS_EINTR(rv)) { > continue; > } > else if (APR_STATUS_IS_TIMEUP(rv)) { > - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, > APLOGNO(02542) "Attempting to go asynch"); > - return SUSPENDED; > + if (try_async) { > + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, > APLOGNO(02542) "Attempting to go asynch"); > + return SUSPENDED; > + } > + else { > + return HTTP_REQUEST_TIME_OUT; > + } > } > else { > ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, > APLOGNO(02444) "error apr_poll()"); > @@ -128,10 +140,12 @@ static int proxy_wstunnel_pump(ws_baton_ > static void proxy_wstunnel_callback(void *b) { > int status; > ws_baton_t *baton = (ws_baton_t*)b; > + proxyws_dir_conf *dconf = > ap_get_module_config(baton->r->per_dir_config, &proxy_wstunnel_module); > + > apr_socket_t *sockets[3] = {NULL, NULL, NULL}; > apr_thread_mutex_lock(baton->r->invoke_mtx); > apr_pool_clear(baton->subpool); > - status = proxy_wstunnel_pump(baton, apr_time_from_sec(5)); > + status = proxy_wstunnel_pump(baton, dconf->async_delay, > dconf->is_async); > sockets[0] = baton->client_soc; > sockets[1] = baton->server_soc; > if (status == SUSPENDED) { > @@ -317,6 +331,7 @@ static int ap_proxy_wstunnel_request(apr > ws_baton_t *baton = apr_pcalloc(r->pool, sizeof(ws_baton_t)); > apr_socket_t *sockets[3] = {NULL, NULL, NULL}; > int status; > + proxyws_dir_conf *dconf = ap_get_module_config(r->per_dir_config, > &proxy_wstunnel_module); > > header_brigade = apr_brigade_create(p, backconn->bucket_alloc); > > @@ -374,7 +389,6 @@ static int ap_proxy_wstunnel_request(apr > * nothing else is attempted on the connection after returning. */ > c->keepalive = AP_CONN_CLOSE; > > - > baton->r = r; > baton->pollset = pollset; > baton->client_soc = client_socket; > @@ -384,25 +398,37 @@ static int ap_proxy_wstunnel_request(apr > baton->scheme = scheme; > apr_pool_create(&baton->subpool, r->pool); > > - status = proxy_wstunnel_pump(baton, apr_time_from_sec(5)); > - if (status == SUSPENDED) { > - sockets[0] = baton->client_soc; > - sockets[1] = baton->server_soc; > - status = ap_mpm_register_socket_callback(sockets, baton->subpool, > 1, proxy_wstunnel_callback, baton); > - if (status == APR_SUCCESS) { > - return SUSPENDED; > - } > - else if (status == APR_ENOTIMPL) { > - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02544) > "No asynch support"); > - status = proxy_wstunnel_pump(baton, -1); > - } > - else { > - ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, > - APLOGNO(02543) "error creating websockets > tunnel"); > - return HTTP_INTERNAL_SERVER_ERROR; > + if (!dconf->is_async) { > + status = proxy_wstunnel_pump(baton, dconf->idle_timeout, > dconf->is_async); > + } > + else { > + status = proxy_wstunnel_pump(baton, dconf->async_delay, > dconf->is_async); > + if (status == SUSPENDED) { > + sockets[0] = baton->client_soc; > + sockets[1] = baton->server_soc; > + status = ap_mpm_register_socket_callback(sockets, > baton->subpool, 1, proxy_wstunnel_callback, baton); > + if (status == APR_SUCCESS) { > + return SUSPENDED; > + } > + else if (status == APR_ENOTIMPL) { > + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, > APLOGNO(02544) "No asynch support"); > + status = proxy_wstunnel_pump(baton, dconf->idle_timeout, > 0); /* force no async */ > + } > + else { > + ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, > + APLOGNO(02543) "error creating websockets > tunnel"); > + return HTTP_INTERNAL_SERVER_ERROR; > + } > } > } > > + if (status != OK) { > + /* Avoid sending error pages down an upgraded connection */ > + if (status != HTTP_REQUEST_TIME_OUT) { > + r->status = status; > + } > + status = OK; > + } > return status; > } > > @@ -490,6 +516,45 @@ static int proxy_wstunnel_handler(reques > return status; > } > > +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 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"; > + return NULL; > +} > +static const char * proxyws_set_aysnch_delay(cmd_parms *cmd, void *conf, > const char *val) > +{ > + proxyws_dir_conf *dconf = conf; > + if (ap_timeout_parameter_parse(val, &(dconf->async_delay), "s") != > APR_SUCCESS) > + return "ProxyWebsocketAsynchDelay timeout has wrong format"; > + return NULL; > +} > + > +static const command_rec ws_proxy_cmds[] = > +{ > + AP_INIT_FLAG("ProxyWebsocketAsynch", ap_set_flag_slot_char, > (void*)APR_OFFSETOF(proxyws_dir_conf, is_async), > + RSRC_CONF|ACCESS_CONF, > + "on if idle websockets connections should be monitored > asynchronously"), > + > + AP_INIT_TAKE1("ProxyWebsocketIdleTimeout", proxyws_set_idle, NULL, > RSRC_CONF|ACCESS_CONF, > + "timeout for activity in either direction, unlimited by > default. Not currently supported with ProxyWebsocketAsynch"), > + > + AP_INIT_TAKE1("ProxyWebsocketAsynchDelay", proxyws_set_aysnch_delay, > NULL, RSRC_CONF|ACCESS_CONF, > + "amount of time to poll before going asynchronous"), > + {NULL} > +}; > + > static void ap_proxy_http_register_hook(apr_pool_t *p) > { > proxy_hook_scheme_handler(proxy_wstunnel_handler, NULL, NULL, > APR_HOOK_FIRST); > @@ -498,10 +563,10 @@ static void ap_proxy_http_register_hook( > > 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 */ > }; > > > -- Born in Roswell... married an alien... http://emptyhammock.com/ http://edjective.org/
