]> granicus.if.org Git - apache/commitdiff
mod_proxy_{http,ajp,fcgi}}: don't reuse backend connections with data available
authorYann Ylavic <ylavic@apache.org>
Mon, 27 Jun 2016 17:26:12 +0000 (17:26 +0000)
committerYann Ylavic <ylavic@apache.org>
Mon, 27 Jun 2016 17:26:12 +0000 (17:26 +0000)
before the request is sent.  PR 57832.

ap_proxy_check_backend() can be used before ap_proxy_connect_backend() to try
to read available data (including from the filters), and is called by
ap_proxy_connect_backend() to check the socket state only (as before, still
relevant after ap_proxy_check_backend() due to filter data which may not have
triggered a real socket operation).

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1750392 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
docs/log-message-tags/next-number
include/ap_mmn.h
modules/proxy/mod_proxy.h
modules/proxy/mod_proxy_ajp.c
modules/proxy/mod_proxy_fcgi.c
modules/proxy/mod_proxy_http.c
modules/proxy/proxy_util.c

diff --git a/CHANGES b/CHANGES
index 229e85f65184363f7e08f207a021e16c479651fc..22eb092b5a752db809ab959c53e385f77e150136 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.0
 
+  *) mod_proxy_{http,ajp,fcgi}: don't reuse backend connections with data
+     available before the request is sent.  PR 57832.  [Yann Ylavic]
+
   *) mod_sed: Fix 'x' command processing. [Christophe Jaillet]
 
   *) core: Drop an invalid Last-Modified header value coming
index 14879086732b0b7f8a1b3544d48505b5434230c1..46cff15d5b0d0147f61b160475d6fef2d747feef 100644 (file)
@@ -1 +1 @@
-3408
+3409
index c4c4188b01d179718aee237cb4697a9d33b2c87f..1d3b07a72d8b3c5e12baf1e1e11391a3a8cbd44e 100644 (file)
  *                         dav_success_proppatch.
  * 20160608.4 (2.5.0-dev)  Add dav_acl_provider, dav_acl_provider_register
  *                         dav_get_acl_providers.
+ * 20160608.5 (2.5.0-dev)  Add ap_proxy_check_backend(), and tmp_bb to struct
+ *                         proxy_conn_rec.
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20160608
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 4                 /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 5                 /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a
index 467984dfa8c299a70daee5bf2ce9f02b8c2458b5..21043e401a9e2e4f1327d865a541d1a355942e20 100644 (file)
@@ -271,6 +271,7 @@ typedef struct {
     unsigned int inreslist:1;  /* connection in apr_reslist? */
     const char   *uds_path;    /* Unix domain socket path */
     const char   *ssl_hostname;/* Hostname (SNI) in use by SSL connection */
+    apr_bucket_brigade *tmp_bb;
 } proxy_conn_rec;
 
 typedef struct {
@@ -972,6 +973,20 @@ PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function,
 PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function,
                                                proxy_conn_rec *conn,
                                                server_rec *s);
+/**
+ * Check a connection to the backend
+ * @param proxy_function calling proxy scheme (http, ajp, ...)
+ * @param conn    acquired connection
+ * @param s       current server record
+ * @param expect_empty whether to check for empty (no data available) or not
+ * @return        APR_SUCCESS or error status (APR_ENOTEMPTY if expect_empty
+ *                is set but the connection is not empty)
+ */
+PROXY_DECLARE(apr_status_t) ap_proxy_check_backend(const char *proxy_function,
+                                                   proxy_conn_rec *conn,
+                                                   server_rec *s,
+                                                   int expect_empty);
+
 /**
  * Make a connection to the backend
  * @param proxy_function calling proxy scheme (http, ajp, ...)
index 42f6eb66905fd58c58fcc6eddde38d8285e7db4e..63bafe0216e26d242e97fc209a185b7e8c3e1ef1 100644 (file)
@@ -783,6 +783,7 @@ static int proxy_ajp_handler(request_rec *r, proxy_worker *worker,
             break;
 
         /* Step Two: Make the Connection */
+        ap_proxy_check_backend(scheme, backend, r->server, 1);
         if (ap_proxy_connect_backend(scheme, backend, worker, r->server)) {
             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00896)
                           "failed to make connection to backend: %s",
index 930424a216ba2d38ac33eb28b52a7041bc05a732..cc22804bd6289cc15dbf4db4844b85d28e76f505 100644 (file)
@@ -935,6 +935,7 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker,
      */  
     backend->close = 1;
     if (worker->s->disablereuse_set && !worker->s->disablereuse) { 
+        ap_proxy_check_backend(FCGI_SCHEME, backend, r->server, 1);
         backend->close = 0;
     }
 
index ccaa0e634fcd1bcf373603d2353749255363f74f..2684bd136fc2987cd77a4344d4f6ce65a5099ea5 100644 (file)
@@ -2073,6 +2073,7 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
         }
 
         /* Step Two: Make the Connection */
+        ap_proxy_check_backend(proxy_function, backend, r->server, 1);
         if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) {
             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01114)
                           "HTTP: failed to make connection to backend: %s",
index 6fee211e5b93e8d442d081a651dd785a0145cb40..9666c1df610ca506d631e7d8361f20b47979553d 100644 (file)
@@ -2699,13 +2699,81 @@ PROXY_DECLARE(apr_status_t) ap_proxy_connect_uds(apr_socket_t *sock,
 #endif
 }
 
+PROXY_DECLARE(apr_status_t) ap_proxy_check_backend(const char *proxy_function,
+                                                   proxy_conn_rec *conn,
+                                                   server_rec *s,
+                                                   int expect_empty)
+{
+    apr_status_t rv;
+    
+    if (!conn->sock) {
+        return APR_ENOTSOCK;
+    }
+
+    if (conn->connection) {
+        conn_rec *c = conn->connection;
+        if (conn->tmp_bb == NULL) {
+            conn->tmp_bb = apr_brigade_create(c->pool, c->bucket_alloc);
+        }
+        rv = ap_get_brigade(c->input_filters, conn->tmp_bb,
+                            AP_MODE_SPECULATIVE, APR_NONBLOCK_READ, 1);
+        if (rv == APR_SUCCESS && expect_empty) {
+            apr_off_t len = 0;
+            apr_brigade_length(conn->tmp_bb, 0, &len);
+            if (len) {
+                rv = APR_ENOTEMPTY;
+            }
+        }
+        else if (APR_STATUS_IS_EAGAIN(rv)) {
+            rv = APR_SUCCESS;
+        }
+        apr_brigade_cleanup(conn->tmp_bb);
+    }
+    else if (ap_proxy_is_socket_connected(conn->sock)) {
+        rv = APR_SUCCESS;
+    }
+    else {
+        rv = APR_EPIPE;
+    }
+
+    if (rv != APR_SUCCESS) {
+        /* This clears conn->scpool (and associated data), so backup and
+         * restore any ssl_hostname for this connection set earlier by
+         * ap_proxy_determine_connection().
+         */
+        char ssl_hostname[PROXY_WORKER_RFC1035_NAME_SIZE];
+        if (!conn->ssl_hostname || PROXY_STRNCPY(ssl_hostname,
+                                                 conn->ssl_hostname)) {
+            ssl_hostname[0] = '\0';
+        }
+
+        socket_cleanup(conn);
+        if (rv != APR_ENOTEMPTY) {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00951)
+                         "%s: backend socket is disconnected.",
+                         proxy_function);
+        }
+        else {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(03408)
+                         "%s: reusable backend connection is not empty: "
+                         "forcibly closed", proxy_function);
+        }
+
+        if (ssl_hostname[0]) {
+            conn->ssl_hostname = apr_pstrdup(conn->scpool, ssl_hostname);
+        }
+    }
+
+    return rv;
+}
+
 PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
                                             proxy_conn_rec *conn,
                                             proxy_worker *worker,
                                             server_rec *s)
 {
     apr_status_t rv;
-    int connected = 0;
+    int connected;
     int loglevel;
     apr_sockaddr_t *backend_addr = conn->addr;
     /* the local address to use for the outgoing connection */
@@ -2715,28 +2783,8 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
     proxy_server_conf *conf =
         (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
 
-    if (conn->sock) {
-        if (!(connected = ap_proxy_is_socket_connected(conn->sock))) {
-            /* This clears conn->scpool (and associated data), so backup and
-             * restore any ssl_hostname for this connection set earlier by
-             * ap_proxy_determine_connection().
-             */
-            char ssl_hostname[PROXY_WORKER_RFC1035_NAME_SIZE];
-            if (!conn->ssl_hostname || PROXY_STRNCPY(ssl_hostname,
-                                                     conn->ssl_hostname)) {
-                ssl_hostname[0] = '\0';
-            }
-
-            socket_cleanup(conn);
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00951)
-                         "%s: backend socket is disconnected.",
-                         proxy_function);
-
-            if (ssl_hostname[0]) {
-                conn->ssl_hostname = apr_pstrdup(conn->scpool, ssl_hostname);
-            }
-        }
-    }
+    connected = (ap_proxy_check_backend(proxy_function, conn,
+                                        s, 0) == APR_SUCCESS);
     while ((backend_addr || conn->uds_path) && !connected) {
 #if APR_HAVE_SYS_UN_H
         if (conn->uds_path)