httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j..@apache.org
Subject svn commit: r986090 - in /httpd/httpd/trunk: CHANGES docs/manual/mod/mod_proxy.xml modules/proxy/mod_proxy_http.c
Date Mon, 16 Aug 2010 18:36:19 GMT
Author: jim
Date: Mon Aug 16 18:36:19 2010
New Revision: 986090

URL: http://svn.apache.org/viewvc?rev=986090&view=rev
Log:
For backends which are HTTP/1.1, do a quick test (ping)
of the "connection" via 100-Continue for reverse
proxies...

ACO and Filip Hanik also helped out with the idea...

Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml
    httpd/httpd/trunk/modules/proxy/mod_proxy_http.c

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=986090&r1=986089&r2=986090&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Mon Aug 16 18:36:19 2010
@@ -6,6 +6,10 @@ Changes with Apache 2.3.7
      mod_dav, mod_cache, mod_session: Fix Handling of requests without a path 
      segment. PR: 49246 [Mark Drayton, Jeff Trawick]
 
+  *) mod_proxy_http: Support the 'ping' property for backend HTTP/1.1 servers
+     via leveraging 100-Continue as the initial "request".
+     [Jim Jagielski]
+
   *) core/mod_authz_core: Introduce new access_checker_ex hook that enables
      mod_authz_core to bypass authentication if access should be allowed by
      IP address/env var/... [Stefan Fritsch]

Modified: httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml?rev=986090&r1=986089&r2=986090&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml Mon Aug 16 18:36:19 2010
@@ -743,17 +743,20 @@ expressions</description>
     </td></tr>
     <tr><td>ping</td>
         <td>0</td>
-        <td>Ping property tells webserver to send a <code>CPING</code>
-        request on ajp13 connection before forwarding a request.
-        The parameter is the delay in seconds to wait for the
-        <code>CPONG</code> reply.
-        This features has been added to avoid problem with hung and
-        busy Tomcat's and require ajp13 ping/pong support which has
-        been implemented on Tomcat 3.3.2+, 4.1.28+ and 5.0.13+.
+        <td>Ping property tells the webserver to "test" the connection to
+        the backend before forwarding the request. For AJP, it causes
+        <module>mod_proxy_ajp</module>to send a <code>CPING</code>
+        request on the ajp13 connection (implemented on Tomcat 3.3.2+, 4.1.28+
+        and 5.0.13+). For HTTP, it causes <module>mod_proxy_http</module>
+        to send a <code>100-Continue</code> to the backend (only valid for
+        HTTP/1.1 - for non HTTP/1.1 backends, this property has no
+        effect). In both cases the parameter is the delay in seconds to wait
+        for the reply.
+        This feature has been added to avoid problems with hung and
+        busy backends.
         This will increase the network traffic during the normal operation
         which could be an issue, but it will lower the
         traffic in case some of the cluster nodes are down or busy.
-        Currently this has an effect only for AJP.
         By adding a postfix of ms the delay can be also set in
         milliseconds.
     </td></tr>

Modified: httpd/httpd/trunk/modules/proxy/mod_proxy_http.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy_http.c?rev=986090&r1=986089&r2=986090&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/mod_proxy_http.c (original)
+++ httpd/httpd/trunk/modules/proxy/mod_proxy_http.c Mon Aug 16 18:36:19 2010
@@ -669,7 +669,7 @@ static int spool_reqbody_cl(apr_pool_t *
 
 static
 int ap_proxy_http_request(apr_pool_t *p, request_rec *r,
-                                   proxy_conn_rec *p_conn, conn_rec *origin,
+                                   proxy_conn_rec *p_conn, proxy_worker *worker,
                                    proxy_server_conf *conf,
                                    apr_uri_t *uri,
                                    char *url, char *server_portstr)
@@ -694,6 +694,8 @@ int ap_proxy_http_request(apr_pool_t *p,
     int force10, rv;
     apr_table_t *headers_in_copy;
     proxy_dir_conf *dconf;
+    conn_rec *origin = p_conn->connection;
+    int do_100_continue;
 
     dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
     header_brigade = apr_brigade_create(p, origin->bucket_alloc);
@@ -702,6 +704,11 @@ int ap_proxy_http_request(apr_pool_t *p,
      * Send the HTTP/1.1 request to the remote server
      */
 
+    do_100_continue = (worker->ping_timeout_set
+                       && !r->header_only
+                       && (PROXYREQ_REVERSE == r->proxyreq)
+                       && !(apr_table_get(r->subprocess_env, "force-proxy-request-1.0")));
+    
     if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) {
         /*
          * According to RFC 2616 8.2.3 we are not allowed to forward an
@@ -791,6 +798,14 @@ int ap_proxy_http_request(apr_pool_t *p,
         );
     }
 
+    /* Use HTTP/1.1 100-Continue as quick "HTTP ping" test
+     * to backend
+     */
+    if (do_100_continue) {
+		apr_table_mergen(r->headers_in, "Expect", "100-Continue");
+        r->expecting_100 = 1;
+    }
+
     /* X-Forwarded-*: handling
      *
      * XXX Privacy Note:
@@ -1350,7 +1365,7 @@ apr_status_t ap_proxygetline(apr_bucket_
 static
 apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
                                             proxy_conn_rec *backend,
-                                            conn_rec *origin,
+                                            proxy_worker *worker,
                                             proxy_server_conf *conf,
                                             char *server_portstr) {
     conn_rec *c = r->connection;
@@ -1375,9 +1390,32 @@ apr_status_t ap_proxy_http_process_respo
     int proxy_status = OK;
     const char *original_status_line = r->status_line;
     const char *proxy_status_line = NULL;
+    conn_rec *origin = backend->connection;
+    apr_interval_time_t old_timeout = 0;
 
+    int do_100_continue;
+    
+    do_100_continue = (worker->ping_timeout_set
+                       && !r->header_only
+                       && (PROXYREQ_REVERSE == r->proxyreq)
+                       && !(apr_table_get(r->subprocess_env, "force-proxy-request-1.0")));
+    
+    
     bb = apr_brigade_create(p, c->bucket_alloc);
     pass_bb = apr_brigade_create(p, c->bucket_alloc);
+    
+    /* Setup for 100-Continue timeout if appropriate */
+    if (do_100_continue) {
+        apr_socket_timeout_get(backend->sock, &old_timeout);
+        if (worker->ping_timeout != old_timeout) {
+            apr_status_t rc;
+        	rc = apr_socket_timeout_set(backend->sock, worker->ping_timeout);
+        	if (rc != APR_SUCCESS) {
+            	ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server,
+                          "proxy: could not set 100-Continue timeout");
+        	}
+        }
+    }
 
     /* Get response from the remote server, and pass it up the
      * filter chain
@@ -1406,6 +1444,9 @@ apr_status_t ap_proxy_http_process_respo
             if (APR_STATUS_IS_TIMEUP(rc)) {
                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
                               "proxy: read timeout");
+                if (do_100_continue) {
+                    return ap_proxyerror(r, HTTP_SERVICE_UNAVAILABLE, "Timeout on 100-Continue");
+                }
             }
             /*
              * If we are a reverse proxy request shutdown the connection
@@ -1641,6 +1682,12 @@ apr_status_t ap_proxy_http_process_respo
 
         if (ap_is_HTTP_INFO(proxy_status)) {
             interim_response++;
+            /* Reset to old timeout iff we've adjusted it */
+            if (do_100_continue
+                && (r->status == HTTP_CONTINUE)
+                && (worker->ping_timeout != old_timeout)) {
+                    apr_socket_timeout_set(backend->sock, old_timeout);
+            }
         }
         else {
             interim_response = 0;
@@ -1923,6 +1970,7 @@ static int proxy_http_handler(request_re
     proxy_conn_rec *backend = NULL;
     int is_ssl = 0;
     conn_rec *c = r->connection;
+    int retry = 0;
     /*
      * Use a shorter-lived pool to reduce memory usage
      * and avoid a memory leak
@@ -1990,48 +2038,68 @@ static int proxy_http_handler(request_re
         backend->close = 1;
     }
 
-    /* Step One: Determine Who To Connect To */
-    if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend,
-                                                uri, &url, proxyname,
+    while (retry < 2) {
+        char *locurl = url;
+
+    	/* Step One: Determine Who To Connect To */
+		if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend,
+                                                uri, &locurl, proxyname,
                                                 proxyport, server_portstr,
                                                 sizeof(server_portstr))) != OK)
-        goto cleanup;
-
-    /* Step Two: Make the Connection */
-    if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) {
-        status = HTTP_SERVICE_UNAVAILABLE;
-        goto cleanup;
-    }
+        	break;
 
-    /* Step Three: Create conn_rec */
-    if (!backend->connection) {
-        if ((status = ap_proxy_connection_create(proxy_function, backend,
-                                                 c, r->server)) != OK)
-            goto cleanup;
-        /*
-         * On SSL connections set a note on the connection what CN is
-         * requested, such that mod_ssl can check if it is requested to do
-         * so.
+    	/* Step Two: Make the Connection */
+    	if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                         "proxy: HTTP: failed to make connection to backend: %s",
+                         backend->hostname);
+        	status = HTTP_SERVICE_UNAVAILABLE;
+        	break;
+    	}
+
+    	/* Step Three: Create conn_rec */
+    	if (!backend->connection) {
+			if ((status = ap_proxy_connection_create(proxy_function, backend,
+                                                     c, r->server)) != OK)
+				break;
+			/*
+             * On SSL connections set a note on the connection what CN is
+         	 * requested, such that mod_ssl can check if it is requested to do
+         	 * so.
+         	 */
+			if (is_ssl) {
+				apr_table_set(backend->connection->notes, "proxy-request-hostname",
+                          	  uri->hostname);
+			}
+    	}
+
+    	/* Step Four: Send the Request
+         * On the off-chance that we forced a 100-Continue as a
+         * kinda HTTP ping test, allow for retries
          */
-        if (is_ssl) {
-            apr_table_set(backend->connection->notes, "proxy-request-hostname",
-                          uri->hostname);
+    	if ((status = ap_proxy_http_request(p, r, backend, worker,
+                                        conf, uri, locurl, server_portstr)) != OK) {
+            if ((status == HTTP_SERVICE_UNAVAILABLE) && worker->ping_timeout_set)
{
+            	backend->close = 1;
+        		ap_log_error(APLOG_MARK, APLOG_INFO, status, r->server,
+                     	     "proxy: HTTP: 100-Continue failed to %pI (%s)",
+                     	     worker->cp->addr, worker->hostname);
+        		retry++;
+        		continue;
+            } else {
+                break;
+            }
+
         }
-    }
 
-    /* Step Four: Send the Request */
-    if ((status = ap_proxy_http_request(p, r, backend, backend->connection,
-                                        conf, uri, url, server_portstr)) != OK)
-        goto cleanup;
+    	/* Step Five: Receive the Response... Fall thru to cleanup */
+    	status = ap_proxy_http_process_response(p, r, backend, worker,
+                                                conf, server_portstr);
 
-    /* Step Five: Receive the Response */
-    if ((status = ap_proxy_http_process_response(p, r, backend,
-                                                 backend->connection,
-                                                 conf, server_portstr)) != OK)
-        goto cleanup;
+        break;
+    }
 
     /* Step Six: Clean Up */
-
 cleanup:
     if (backend) {
         if (status != OK)



Mime
View raw message