]> granicus.if.org Git - apache/commitdiff
Use the new connection pool for AJP.
authorWilliam A. Rowe Jr <wrowe@apache.org>
Wed, 11 Aug 2004 22:45:51 +0000 (22:45 +0000)
committerWilliam A. Rowe Jr <wrowe@apache.org>
Wed, 11 Aug 2004 22:45:51 +0000 (22:45 +0000)
Submitted by: mturk

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

modules/proxy/proxy_ajp.c

index 3992efbb895e9722453ebb68278f9477bba7e411..bed82af5bf259b91d54fbe1756836223d4b6cf8c 100644 (file)
 
 module AP_MODULE_DECLARE_DATA proxy_ajp_module;
 
-int ap_proxy_ajp_canon(request_rec *r, char *url);
-int ap_proxy_ajp_handler(request_rec *r, proxy_server_conf *conf,
-                          char *url, const char *proxyname, 
-                          apr_port_t proxyport);
-
-typedef struct {
-    const char     *name;
-    apr_port_t      port;
-    apr_sockaddr_t *addr;
-    apr_socket_t   *sock;
-    int             close;
-    void           *data;  /* To store ajp data */
-} proxy_ajp_conn_t;
-
-static apr_status_t ap_proxy_ajp_cleanup(request_rec *r,
-                                          proxy_ajp_conn_t *p_conn,
-                                          proxy_conn_rec *backend);
-
 /*
  * Canonicalise http-like URLs.
  *  scheme is the scheme for the URL
@@ -115,231 +97,10 @@ int ap_proxy_ajp_canon(request_rec *r, char *url)
     return OK;
 }
  
-static
-apr_status_t ap_proxy_http_determine_connection(apr_pool_t *p, request_rec *r,
-                                                proxy_ajp_conn_t *p_conn,
-                                                conn_rec *c,
-                                                proxy_server_conf *conf,
-                                                apr_uri_t *uri,
-                                                char **url,
-                                                const char *proxyname,
-                                                apr_port_t proxyport,
-                                                char *server_portstr,
-                                                int server_portstr_size) {
-    int server_port;
-    apr_status_t err;
-    apr_sockaddr_t *uri_addr;
-    /*
-     * Break up the URL to determine the host to connect to
-     */
-
-    /* we break the URL into host, port, uri */
-    if (APR_SUCCESS != apr_uri_parse(p, *url, uri)) {
-        return ap_proxyerror(r, HTTP_BAD_REQUEST,
-                             apr_pstrcat(p,"URI cannot be parsed: ", *url,
-                                         NULL));
-    }
-    if (!uri->port) {
-        uri->port = apr_uri_port_of_scheme(uri->scheme);
-    }
-
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                 "proxy: AJP connecting %s to %s:%d", *url, uri->hostname,
-                 uri->port);
-
-    /* do a DNS lookup for the destination host */
-    /* see memory note above */
-    err = apr_sockaddr_info_get(&uri_addr, apr_pstrdup(c->pool, uri->hostname),
-                                APR_UNSPEC, uri->port, 0, c->pool);
-
-    /* allocate these out of the connection pool - the check on
-     * r->connection->id makes sure that this string does not get accessed
-     * past the connection lifetime */
-    /* are we connecting directly, or via a proxy? */
-    if (proxyname) {
-        p_conn->name = apr_pstrdup(c->pool, proxyname);
-        p_conn->port = proxyport;
-        /* see memory note above */
-        err = apr_sockaddr_info_get(&p_conn->addr, p_conn->name, APR_UNSPEC,
-                                    p_conn->port, 0, c->pool);
-    } else {
-        p_conn->name = apr_pstrdup(c->pool, uri->hostname);
-        p_conn->port = uri->port;
-        p_conn->addr = uri_addr;
-        *url = apr_pstrcat(p, uri->path, uri->query ? "?" : "",
-                           uri->query ? uri->query : "",
-                           uri->fragment ? "#" : "",
-                           uri->fragment ? uri->fragment : "", NULL);
-    }
-
-    if (err != APR_SUCCESS) {
-        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
-                             apr_pstrcat(p, "DNS lookup failure for: ",
-                                         p_conn->name, NULL));
-    }
-
-    /* Get the server port for the Via headers */
-    {
-        server_port = ap_get_server_port(r);
-        if (ap_is_default_port(server_port, r)) {
-            strcpy(server_portstr,"");
-        } else {
-            apr_snprintf(server_portstr, server_portstr_size, ":%d",
-                         server_port);
-        }
-    }
-
-    /* check if ProxyBlock directive on this host */
-    if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) {
-        return ap_proxyerror(r, HTTP_FORBIDDEN,
-                             "Connect to remote machine blocked");
-    }
-    return OK;
-}
-
-static
-apr_status_t ap_proxy_http_create_connection(apr_pool_t *p, request_rec *r,
-                                             proxy_ajp_conn_t *p_conn,
-                                             conn_rec *c, conn_rec **origin,
-                                             proxy_conn_rec *backend,
-                                             proxy_server_conf *conf,
-                                             const char *proxyname) {
-    int failed = 0, new_conn = 0;
-    apr_socket_t *client_socket = NULL;
-
-    /* We have determined who to connect to. Now make the connection, supporting
-     * a KeepAlive connection.
-     */
-
-    /* get all the possible IP addresses for the destname and loop through them
-     * until we get a successful connection
-     */
-
-    /* if a keepalive socket is already open, check whether it must stay
-     * open, or whether it should be closed and a new socket created.
-     */
-    /* see memory note above */
-    if (backend->connection) {
-        client_socket = ap_get_module_config(backend->connection->conn_config, &core_module);
-        if ((backend->connection->id == c->id) &&
-            (backend->port == p_conn->port) &&
-            (backend->hostname) &&
-            (!apr_strnatcasecmp(backend->hostname, p_conn->name))) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                         "proxy: keepalive address match (keep original socket)");
-        } else {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                         "proxy: keepalive address mismatch / connection has"
-                         " changed (close old socket (%s/%s, %d/%d))", 
-                         p_conn->name, backend->hostname, p_conn->port,
-                         backend->port);
-            apr_socket_close(client_socket);
-            backend->connection = NULL;
-        }
-    }
-
-    /* get a socket - either a keepalive one, or a new one */
-    new_conn = 1;
-    if ((backend->connection) && (backend->connection->id == c->id)) {
-        apr_size_t buffer_len = 1;
-        char test_buffer[1]; 
-        apr_status_t socket_status;
-        apr_interval_time_t current_timeout;
-
-        /* use previous keepalive socket */
-        *origin = backend->connection;
-        p_conn->sock = client_socket;
-        new_conn = 0;
-
-        /* save timeout */
-        apr_socket_timeout_get(p_conn->sock, &current_timeout);
-        /* set no timeout */
-        apr_socket_timeout_set(p_conn->sock, 0);
-        socket_status = apr_socket_recv(p_conn->sock, test_buffer, &buffer_len);
-        /* put back old timeout */
-        apr_socket_timeout_set(p_conn->sock, current_timeout);
-        if ( APR_STATUS_IS_EOF(socket_status) ) {
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
-                         "proxy: AJP: previous connection is closed");
-            new_conn = 1;
-        }
-    }
-    if (new_conn) {
-
-        /* create a new socket */
-        backend->connection = NULL;
-
-        /*
-         * At this point we have a list of one or more IP addresses of
-         * the machine to connect to. If configured, reorder this
-         * list so that the "best candidate" is first try. "best
-         * candidate" could mean the least loaded server, the fastest
-         * responding server, whatever.
-         *
-         * For now we do nothing, ie we get DNS round robin.
-         * XXX FIXME
-         */
-        failed = ap_proxy_connect_to_backend(&p_conn->sock, "AJP",
-                                             p_conn->addr, p_conn->name,
-                                             conf, r->server, c->pool);
-
-        /* handle a permanent error on the connect */
-        if (failed) {
-            if (proxyname) {
-                return DECLINED;
-            } else {
-                return HTTP_BAD_GATEWAY;
-            }
-        }
-
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                     "proxy: socket is connected");
-
-        /* the socket is now open, create a new backend server connection */
-        *origin = ap_run_create_connection(c->pool, r->server, p_conn->sock,
-                                           r->connection->id,
-                                           r->connection->sbh, c->bucket_alloc);
-        if (!*origin) {
-        /* the peer reset the connection already; ap_run_create_connection() 
-         * closed the socket
-         */
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0,
-                         r->server, "proxy: an error occurred creating a "
-                         "new connection to %pI (%s)", p_conn->addr,
-                         p_conn->name);
-            apr_socket_close(p_conn->sock);
-            return HTTP_INTERNAL_SERVER_ERROR;
-        }
-        backend->connection = *origin;
-        backend->hostname = apr_pstrdup(c->pool, p_conn->name);
-        backend->port = p_conn->port;
-
-        if (backend->is_ssl) {
-            if (!ap_proxy_ssl_enable(backend->connection)) {
-                ap_log_error(APLOG_MARK, APLOG_ERR, 0,
-                             r->server, "proxy: failed to enable ssl support "
-                             "for %pI (%s)", p_conn->addr, p_conn->name);
-                return HTTP_INTERNAL_SERVER_ERROR;
-            }
-        }
-        else {
-            ap_proxy_ssl_disable(backend->connection);
-        }
-
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                     "proxy: connection complete to %pI (%s)",
-                     p_conn->addr, p_conn->name);
-
-        /* set up the connection filters */
-        ap_run_pre_connection(*origin, p_conn->sock);
-    }
-    return OK;
-}
-
-
 static
 apr_status_t ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
-                                   proxy_ajp_conn_t *p_conn, conn_rec *origin, 
+                                   proxy_conn_rec *conn, 
+                                   conn_rec *origin, 
                                    proxy_server_conf *conf,
                                    apr_uri_t *uri,
                                    char *url, char *server_portstr)
@@ -353,11 +114,13 @@ apr_status_t ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
      */
 
     /* send request headers */
-    status = ajp_send_header(p_conn->sock,r);
+    status = ajp_send_header(conn->sock, r);
     if (status != APR_SUCCESS) {
+        conn->close++;
         ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
                      "proxy: request failed to %pI (%s)",
-                     p_conn->addr, p_conn->name);
+                     conn->worker->cp->addr,
+                     conn->worker->hostname);
         return status;
     }
 
@@ -402,32 +165,35 @@ apr_status_t ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                      "proxy: got %d byte of data", bufsiz);
         if (bufsiz > 0) {
-            status = ajp_send_data_msg(p_conn->sock, r, msg, bufsiz);
+            status = ajp_send_data_msg(conn->sock, r, msg, bufsiz);
             if (status != APR_SUCCESS) {
                 ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
                              "proxy: request failed to %pI (%s)",
-                             p_conn->addr, p_conn->name);
+                             conn->worker->cp->addr,
+                             conn->worker->hostname);
                 return status;
             }
         }
     }
 
     /* read the response */
-    status = ajp_read_header(p_conn->sock, r,
-                             (ajp_msg_t **)&(p_conn->data));
+    status = ajp_read_header(conn->sock, r,
+                             (ajp_msg_t **)&(conn->data));
     if (status != APR_SUCCESS) {
         ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
                      "proxy: request failed to %pI (%s)",
-                     p_conn->addr, p_conn->name);
+                     conn->worker->cp->addr,
+                     conn->worker->hostname);
         return status;
     }
 
     /* parse the reponse */
-    result = ajp_parse_type(r, p_conn->data);
+    result = ajp_parse_type(r, conn->data);
     if (result == CMD_AJP13_SEND_HEADERS) {
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                      "proxy: got response from %pI (%s)",
-                     p_conn->addr, p_conn->name);
+                     conn->worker->cp->addr,
+                     conn->worker->hostname);
         return APR_SUCCESS;
     }
 
@@ -450,7 +216,6 @@ apr_status_t ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
  */
 static
 apr_status_t ap_proxy_ajp_process_response(apr_pool_t * p, request_rec *r,
-                                            proxy_ajp_conn_t *p_conn,
                                             conn_rec *origin,
                                             proxy_conn_rec *backend,
                                             proxy_server_conf *conf,
@@ -464,39 +229,43 @@ apr_status_t ap_proxy_ajp_process_response(apr_pool_t * p, request_rec *r,
 
     bb = apr_brigade_create(p, c->bucket_alloc);
     
-    type = ajp_parse_type(r, p_conn->data);
+    type = ajp_parse_type(r, backend->data);
     status = APR_SUCCESS;
     while (type != CMD_AJP13_END_RESPONSE) {
         if (type == CMD_AJP13_SEND_HEADERS) {
             /* AJP13_SEND_HEADERS: process them */
-            status = ajp_parse_header(r, p_conn->data); 
+            status = ajp_parse_header(r, backend->data); 
             if (status != APR_SUCCESS) {
                 break;
             }
-        } else if  (type == CMD_AJP13_SEND_BODY_CHUNK) {
+        } 
+        else if  (type == CMD_AJP13_SEND_BODY_CHUNK) {
             /* AJP13_SEND_BODY_CHUNK: piece of data */
             apr_uint16_t size;
             char *buff;
 
-            status = ajp_parse_data(r, p_conn->data, &size, &buff);
+            status = ajp_parse_data(r, backend->data, &size, &buff);
             e = apr_bucket_transient_create(buff, size, c->bucket_alloc);
             APR_BRIGADE_INSERT_TAIL(bb, e);
-        } else {
+        } 
+        else {
             status = APR_EGENERAL;
             break;
         }
         /* Read the next message */
-        status = ajp_read_header(p_conn->sock, r,
-                                 (ajp_msg_t **)&(p_conn->data));
+        status = ajp_read_header(backend->sock, r,
+                                 (ajp_msg_t **)&(backend->data));
         if (status != APR_SUCCESS) {
             break;
         }
-        type = ajp_parse_type(r, p_conn->data);
+        type = ajp_parse_type(r, backend->data);
     }
     if (status != APR_SUCCESS) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                       "proxy: error reading headers from remote "
-                      "server %s:%d", p_conn->name, p_conn->port);
+                      "server %s:%d",
+                      backend->worker->cp->addr,
+                      backend->worker->hostname);
         return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                              "Error reading from remote server");
     }
@@ -514,28 +283,6 @@ apr_status_t ap_proxy_ajp_process_response(apr_pool_t * p, request_rec *r,
     return OK;
 }
 
-static
-apr_status_t ap_proxy_ajp_cleanup(request_rec *r, proxy_ajp_conn_t *p_conn,
-                                   proxy_conn_rec *backend) {
-    /* If the connection has been signalled
-     * to close, close the socket and clean up
-     */
-
-    /* if the connection is < HTTP/1.1, or Connection: close,
-     * we close the socket, otherwise we leave it open for KeepAlive support
-     */
-    if (p_conn->close) {
-        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
-                      "ap_proxy_ajp_cleanup closing");
-        if (p_conn->sock) {
-            apr_socket_close(p_conn->sock);
-            p_conn->sock = NULL;
-            backend->connection = NULL;
-        }
-    }
-    return OK;
-}
-
 /*
  * This handles http:// URLs, and other URLs using a remote proxy over http
  * If proxyhost is NULL, then contact the server directly, otherwise
@@ -545,15 +292,17 @@ apr_status_t ap_proxy_ajp_cleanup(request_rec *r, proxy_ajp_conn_t *p_conn,
  * we return DECLINED so that we can try another proxy. (Or the direct
  * route.)
  */
-int ap_proxy_ajp_handler(request_rec *r, proxy_server_conf *conf,
-                          char *url, const char *proxyname, 
-                          apr_port_t proxyport)
+int ap_proxy_ajp_handler(request_rec *r, proxy_worker *worker,
+                         proxy_server_conf *conf,
+                         char *url, const char *proxyname, 
+                         apr_port_t proxyport)
 {
     int status;
     char server_portstr[32];
     conn_rec *origin = NULL;
     proxy_conn_rec *backend = NULL;
     int is_ssl = 0;
+    const char *scheme = "ajp";
 
     /* Note: Memory pool allocation.
      * A downstream keepalive connection is always connected to the existence
@@ -571,28 +320,8 @@ int ap_proxy_ajp_handler(request_rec *r, proxy_server_conf *conf,
     apr_pool_t *p = r->connection->pool;
     conn_rec *c = r->connection;
     apr_uri_t *uri = apr_palloc(r->connection->pool, sizeof(*uri));
-    proxy_ajp_conn_t *p_conn = apr_pcalloc(r->connection->pool,
-                                           sizeof(*p_conn));
 
     
-    /* only use stored info for top-level pages. Sub requests don't share 
-     * in keepalives
-     */
-    if (!r->main) {
-        backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config,
-                                                      &proxy_ajp_module);
-    }
-    /* create space for state information */
-    if (!backend) {
-        backend = apr_pcalloc(c->pool, sizeof(proxy_conn_rec));
-        backend->connection = NULL;
-        backend->hostname = NULL;
-        backend->port = 0;
-        if (!r->main) {
-            ap_set_module_config(c->conn_config, &proxy_ajp_module, backend);
-        }
-    }
-
     if (strncasecmp(url, "ajp:", 4) != 0) {
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                      "proxy: AJP: declining URL %s", url);
@@ -601,7 +330,7 @@ int ap_proxy_ajp_handler(request_rec *r, proxy_server_conf *conf,
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
              "proxy: AJP: serving URL %s", url);
     
-    
+
     /* only use stored info for top-level pages. Sub requests don't share 
      * in keepalives
      */
@@ -611,59 +340,59 @@ int ap_proxy_ajp_handler(request_rec *r, proxy_server_conf *conf,
     }
     /* create space for state information */
     if (!backend) {
-        backend = apr_pcalloc(c->pool, sizeof(proxy_conn_rec));
-        backend->connection = NULL;
-        backend->hostname = NULL;
-        backend->port = 0;
+        status = ap_proxy_acquire_connection(scheme, &backend, worker, r->server);
+        if (status != OK) {
+            if (backend) {
+                backend->close_on_recycle = 1;
+                ap_proxy_release_connection(scheme, backend, r->server);
+            }
+            return status;
+        }
         if (!r->main) {
             ap_set_module_config(c->conn_config, &proxy_ajp_module, backend);
         }
     }
 
-    backend->is_ssl = is_ssl;
+    backend->is_ssl = 0;
+    backend->close_on_recycle = 0;
 
     /* Step One: Determine Who To Connect To */
-    status = ap_proxy_http_determine_connection(p, r, p_conn, c, conf, uri,
-                                                &url, proxyname, proxyport,
-                                                server_portstr,
-                                                sizeof(server_portstr));
-    if ( status != OK ) {
-        return status;
-    }
+    status = ap_proxy_determine_connection(p, r, conf, worker, backend, c->pool,
+                                           uri, &url, proxyname, proxyport,
+                                           server_portstr,
+                                           sizeof(server_portstr));
+
+    if (status != OK)
+        goto cleanup;
 
     /* Step Two: Make the Connection */
-    status = ap_proxy_http_create_connection(p, r, p_conn, c, &origin, backend,
-                                             conf, proxyname);
-    if ( status != OK ) {
-        return status;
+    status = ap_proxy_connect_backend(scheme, backend, worker, r->server);
+    if (status != OK)
+        goto cleanup;
+
+    /* Step Three: Create conn_rec */
+    if (!backend->connection) {
+        status = ap_proxy_connection_create(scheme, backend, c, r->server);
+        if (status != OK)
+            goto cleanup;
     }
    
-    /* Step Three: Send the Request */
-    status = ap_proxy_ajp_request(p, r, p_conn, origin, conf, uri, url,
-                                   server_portstr);
-    if ( status != OK ) {
-        p_conn->close++;
-        ap_proxy_ajp_cleanup(r, p_conn, backend);
-        return status;
-    }
-
-    /* Step Four: Receive the Response */
-    status = ap_proxy_ajp_process_response(p, r, p_conn, origin, backend,
+   
+    /* Step Four: Send the Request */
+    status = ap_proxy_ajp_request(p, r, backend, origin, conf, uri, url,
+                                  server_portstr);
+    if (status != OK)
+        goto cleanup;
+
+    /* Step Five: Receive the Response */
+    status = ap_proxy_ajp_process_response(p, r, origin, backend,
                                            conf, server_portstr);
-    if ( status != OK ) {
-        /* clean up even if there is an error */
-        p_conn->close++;
-        ap_proxy_ajp_cleanup(r, p_conn, backend);
-        return status;
-    }
-
-    /* Step Five: Clean Up */
-    status = ap_proxy_ajp_cleanup(r, p_conn, backend);
-    if ( status != OK ) {
-        return status;
-    }
-
-    return OK;
+cleanup:
+    /* Clear the module config */
+    ap_set_module_config(c->conn_config, &proxy_ajp_module, NULL);
+    /* Do not close the socket */
+    ap_proxy_release_connection(scheme, backend, r->server);
+    return status;
 }
 
 static void ap_proxy_http_register_hook(apr_pool_t *p)