From abfd8529a373972837364d4f210c8e67bcedf013 Mon Sep 17 00:00:00 2001 From: "William A. Rowe Jr" Date: Wed, 11 Aug 2004 22:45:51 +0000 Subject: [PATCH] Use the new connection pool for AJP. 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 | 423 +++++++------------------------------- 1 file changed, 76 insertions(+), 347 deletions(-) diff --git a/modules/proxy/proxy_ajp.c b/modules/proxy/proxy_ajp.c index 3992efbb89..bed82af5bf 100644 --- a/modules/proxy/proxy_ajp.c +++ b/modules/proxy/proxy_ajp.c @@ -20,24 +20,6 @@ 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, ¤t_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) -- 2.40.0