httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cove...@apache.org
Subject svn commit: r1587075 - in /httpd/httpd/trunk: CHANGES docs/manual/mod/mod_proxy_wstunnel.xml modules/proxy/mod_proxy_wstunnel.c
Date Sun, 13 Apr 2014 18:41:06 GMT
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. 
+     [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 */
 };



Mime
View raw message