You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Jeff Trawick <tr...@gmail.com> on 2014/04/14 01:55:43 UTC

Re: svn commit: r1587075 - in /httpd/httpd/trunk: CHANGES docs/manual/mod/mod_proxy_wstunnel.xml modules/proxy/mod_proxy_wstunnel.c

On Sun, Apr 13, 2014 at 2:41 PM, <co...@apache.org> 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/

Re: svn commit: r1587075 - in /httpd/httpd/trunk: CHANGES docs/manual/mod/mod_proxy_wstunnel.xml modules/proxy/mod_proxy_wstunnel.c

Posted by Eric Covener <co...@gmail.com>.
On Sun, Apr 13, 2014 at 7:55 PM, Jeff Trawick <tr...@gmail.com> wrote:
> Should be "Async" instead of "Asynch" IMO...  the latter form is rather
> uncommon...


thanks, r1587126.