jfclere 2004/07/29 08:13:59 Added: ajp/proxy proxy_ajp.c Log: First try to get proxy using ajp (Note that is for httpd-2.1). Revision Changes Path 1.1 jakarta-tomcat-connectors/ajp/proxy/proxy_ajp.c Index: proxy_ajp.c =================================================================== /* Copyright 1999-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* HTTP routines for Apache proxy */ #include "mod_proxy.h" 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_http_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 * url is the URL starting with the first '/' * def_port is the default port for this scheme. */ int ap_proxy_ajp_canon(request_rec *r, char *url) { char *host, *path, *search, sport[7]; const char *err; const char *scheme; apr_port_t port, def_port; ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "proxy: HTTP: canonicalising URL %s", url); /* ap_port_of_scheme() */ if (strncasecmp(url, "http:", 5) == 0) { url += 5; scheme = "http"; } else if (strncasecmp(url, "https:", 6) == 0) { url += 6; scheme = "https"; } else { return DECLINED; } def_port = apr_uri_port_of_scheme(scheme); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: HTTP: canonicalising URL %s", url); /* do syntatic check. * We break the URL into host, port, path, search */ port = def_port; err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port); if (err) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "error parsing URL %s: %s", url, err); return HTTP_BAD_REQUEST; } /* now parse path/search args, according to rfc1738 */ /* N.B. if this isn't a true proxy request, then the URL _path_ * has already been decoded. True proxy requests have r->uri * == r->unparsed_uri, and no others have that property. */ if (r->uri == r->unparsed_uri) { search = strchr(url, '?'); if (search != NULL) *(search++) = '\0'; } else search = r->args; /* process path */ path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq); if (path == NULL) return HTTP_BAD_REQUEST; if (port != def_port) apr_snprintf(sport, sizeof(sport), ":%d", port); else sport[0] = '\0'; if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */ host = apr_pstrcat(r->pool, "[", host, "]", NULL); } r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport, "/", path, (search) ? "?" : "", (search) ? search : "", NULL); return OK; } static const char *ap_proxy_location_reverse_map(request_rec *r, proxy_server_conf *conf, const char *url) { struct proxy_alias *ent; int i, l1, l2; char *u; /* XXX FIXME: Make sure this handled the ambiguous case of the :80 * after the hostname */ l1 = strlen(url); ent = (struct proxy_alias *)conf->raliases->elts; for (i = 0; i < conf->raliases->nelts; i++) { l2 = strlen(ent[i].real); if (l1 >= l2 && strncasecmp(ent[i].real, url, l2) == 0) { u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL); return ap_construct_url(r->pool, u, r); } } return url; } /* cookies are a bit trickier to match: we've got two substrings to worry * about, and we can't just find them with strstr 'cos of case. Regexp * matching would be an easy fix, but for better consistency with all the * other matches we'll refrain and use apr_strmatch to find path=/domain= * and stick to plain strings for the config values. */ static const char *proxy_cookie_reverse_map(request_rec *r, proxy_server_conf *conf, const char *str) { struct proxy_alias *ent; size_t len = strlen(str); const char* newpath = NULL ; const char* newdomain = NULL ; const char* pathp ; const char* domainp ; const char* pathe = NULL; const char* domaine = NULL; size_t l1, l2, i, poffs = 0, doffs = 0 ; int ddiff = 0 ; int pdiff = 0 ; char* ret ; /* find the match and replacement, but save replacing until we've done both path and domain so we know the new strlen */ if ( pathp = apr_strmatch(conf->cookie_path_str, str, len) , pathp ) { pathp += 5 ; poffs = pathp - str ; pathe = ap_strchr_c(pathp, ';') ; l1 = pathe ? (pathe-pathp) : strlen(pathp) ; pathe = pathp + l1 ; ent = (struct proxy_alias *)conf->cookie_paths->elts; for (i = 0; i < conf->cookie_paths->nelts; i++) { l2 = strlen(ent[i].fake); if (l1 >= l2 && strncmp(ent[i].fake, pathp, l2) == 0) { newpath = ent[i].real ; pdiff = strlen(newpath) - l1 ; break ; } } } if ( domainp = apr_strmatch(conf->cookie_domain_str, str, len) , domainp ) { domainp += 7 ; doffs = domainp - str ; domaine = ap_strchr_c(domainp, ';') ; l1 = domaine ? (domaine-domainp) : strlen(domainp) ; domaine = domainp + l1 ; ent = (struct proxy_alias *)conf->cookie_domains->elts; for (i = 0; i < conf->cookie_domains->nelts; i++) { l2 = strlen(ent[i].fake); if (l1 >= l2 && strncasecmp(ent[i].fake, domainp, l2) == 0) { newdomain = ent[i].real ; ddiff = strlen(newdomain) - l1 ; break ; } } } if ( newpath ) { ret = apr_palloc(r->pool, len+pdiff+ddiff+1) ; l1 = strlen(newpath) ; if ( newdomain ) { l2 = strlen(newdomain) ; if ( doffs > poffs ) { memcpy(ret, str, poffs) ; memcpy(ret+poffs, newpath, l1) ; memcpy(ret+poffs+l1, pathe, domainp-pathe) ; memcpy(ret+doffs+pdiff, newdomain, l2) ; strcpy(ret+doffs+pdiff+l2, domaine) ; } else { memcpy(ret, str, doffs) ; memcpy(ret+doffs, newdomain, l2) ; memcpy(ret+doffs+l2, domaine, pathp-domaine) ; memcpy(ret+poffs+ddiff, newpath, l1) ; strcpy(ret+poffs+ddiff+l1, pathe) ; } } else { memcpy(ret, str, poffs) ; memcpy(ret+poffs, newpath, l1) ; strcpy(ret+poffs+l1, pathe) ; } } else { if ( newdomain ) { ret = apr_palloc(r->pool, len+pdiff+ddiff+1) ; l2 = strlen(newdomain) ; memcpy(ret, str, doffs) ; memcpy(ret+doffs, newdomain, l2) ; strcpy(ret+doffs+l2, domaine) ; } else { ret = (char*) str ; /* no change */ } } return ret ; } /* Clear all connection-based headers from the incoming headers table */ static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers) { const char *name; char *next = apr_pstrdup(p, apr_table_get(headers, "Connection")); apr_table_unset(headers, "Proxy-Connection"); if (!next) return; while (*next) { name = next; while (*next && !apr_isspace(*next) && (*next != ',')) { ++next; } while (*next && (apr_isspace(*next) || (*next == ','))) { *next = '\0'; ++next; } apr_table_unset(headers, name); } apr_table_unset(headers, "Connection"); } 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: HTTP 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=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 = 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 = 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: HTTP: previous connection is closed"); new = 1; } } if (new) { /* 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, "HTTP", 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_DEBUG, 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_server_conf *conf, apr_uri_t *uri, char *url, char *server_portstr) { apr_status_t status; int result; /* * Send the AJP request to the remote server */ /* send request headers */ status = ajp_send_header(p_conn->sock,r); 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); return status; } /* read the response */ status = ajp_read_header(p_conn->sock,r,&(p_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); return status; } /* parse the reponse */ result = ajp_parse_type(r,p_conn->data); if (result == 4) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: got response from %pI (%s)", p_conn->addr, p_conn->name); return APR_SUCCESS; } /* send data via brigade or not??? */ /* status = ajp_send_data(p_conn->sock,r); 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); return status; } */ return APR_SUCCESS; } static void process_proxy_header(request_rec* r, proxy_server_conf* c, const char* key, const char* value) { static const char* date_hdrs[] = { "Date", "Expires", "Last-Modified", NULL } ; static const struct { const char* name ; const char* (*func)(request_rec*, proxy_server_conf*, const char*) ; } transform_hdrs[] = { { "Location", ap_proxy_location_reverse_map } , { "Content-Location", ap_proxy_location_reverse_map } , { "URI", ap_proxy_location_reverse_map } , { "Set-Cookie", proxy_cookie_reverse_map } , { NULL, NULL } } ; int i ; for ( i = 0 ; date_hdrs[i] ; ++i ) { if ( !strcasecmp(date_hdrs[i], key) ) { apr_table_add(r->headers_out, key, ap_proxy_date_canon(r->pool, value)) ; return ; } } for ( i = 0 ; transform_hdrs[i].name ; ++i ) { if ( !strcasecmp(transform_hdrs[i].name, key) ) { apr_table_add(r->headers_out, key, (*transform_hdrs[i].func)(r, c, value)) ; return ; } } apr_table_add(r->headers_out, key, value) ; return ; } static void ap_proxy_read_headers(request_rec *r, request_rec *rr, char *buffer, int size, conn_rec *c) { int len; char *value, *end; char field[MAX_STRING_LEN]; int saw_headers = 0; void *sconf = r->server->module_config; proxy_server_conf *psc; psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); r->headers_out = apr_table_make(r->pool, 20); /* * Read header lines until we get the empty separator line, a read error, * the connection closes (EOF), or we timeout. */ while ((len = ap_getline(buffer, size, rr, 1)) > 0) { if (!(value = strchr(buffer, ':'))) { /* Find the colon separator */ /* We may encounter invalid headers, usually from buggy * MS IIS servers, so we need to determine just how to handle * them. We can either ignore them, assume that they mark the * start-of-body (eg: a missing CRLF) or (the default) mark * the headers as totally bogus and return a 500. The sole * exception is an extra "HTTP/1.0 200, OK" line sprinkled * in between the usual MIME headers, which is a favorite * IIS bug. */ /* XXX: The mask check is buggy if we ever see an HTTP/1.10 */ if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) { if (psc->badopt == bad_error) { /* Nope, it wasn't even an extra HTTP header. Give up. */ return ; } else if (psc->badopt == bad_body) { /* if we've already started loading headers_out, then * return what we've accumulated so far, in the hopes * that they are useful. Otherwise, we completely bail. */ /* FIXME: We've already scarfed the supposed 1st line of * the body, so the actual content may end up being bogus * as well. If the content is HTML, we may be lucky. */ if (saw_headers) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "proxy: Starting body due to bogus non-header in headers " "returned by %s (%s)", r->uri, r->method); return ; } else { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "proxy: No HTTP headers " "returned by %s (%s)", r->uri, r->method); return ; } } } /* this is the psc->badopt == bad_ignore case */ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "proxy: Ignoring bogus HTTP header " "returned by %s (%s)", r->uri, r->method); continue; } *value = '\0'; ++value; /* XXX: RFC2068 defines only SP and HT as whitespace, this test is * wrong... and so are many others probably. */ while (apr_isspace(*value)) ++value; /* Skip to start of value */ /* should strip trailing whitespace as well */ for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); -- end) *end = '\0'; /* make sure we add so as not to destroy duplicated headers * Modify headers requiring canonicalisation and/or affected * by ProxyPassReverse and family with process_proxy_header */ process_proxy_header(r, psc, buffer, value) ; saw_headers = 1; /* the header was too long; at the least we should skip extra data */ if (len >= size - 1) { while ((len = ap_getline(field, MAX_STRING_LEN, rr, 1)) >= MAX_STRING_LEN - 1) { /* soak up the extra data */ } if (len == 0) /* time to exit the larger loop as well */ break; } } } static int addit_dammit(void *v, const char *key, const char *val) { apr_table_addn(v, key, val); return 1; } /* * Process the AJP response, data already contains the first part of it. */ 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, char *server_portstr) { conn_rec *c = r->connection; apr_bucket *e; apr_bucket_brigade *bb; int type; apr_status_t status; // bb = apr_brigade_create(p, c->bucket_alloc); type = ajp_parse_type(r, p_conn->data); status = APR_SUCCESS; while (type != 5) { if (type == 4) { /* AJP13_SEND_HEADERS: process them */ status = ajp_parse_headers(r, p_conn->data); if (status != APR_SUCCESS) { break; } } else if (type == 3) { /* AJP13_SEND_BODY_CHUNK: piece of data */ apr_size_t size; char *buff; status = ajp_parse_data(r, p_conn->data, &size, &buff); ap_rflush(r); ap_rwrite(buff,size,r); // e = apr_bucket_transient_create(buff, size, c->bucket_alloc); // APR_BRIGADE_INSERT_TAIL(bb, e); } else { status = APR_EGENERAL; break; } /* Read the next message */ status = ajp_read_header(p_conn->sock, r, &(p_conn->data)); if (status != APR_SUCCESS) { break; } type = ajp_parse_type(r, p_conn->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); return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server"); } return ap_rflush(r); /* The page is ready give it to the rest of the logic */ e = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, e); if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "proxy: error processing body"); return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server"); } return OK; } static apr_status_t ap_proxy_http_cleanup(request_rec *r, proxy_ajp_conn_t *p_conn, proxy_conn_rec *backend) { /* If there are no KeepAlives, or 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 || (r->proto_num < HTTP_VERSION(1,1))) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "ap_proxy_http_cleanup closing %d %d %d %s", p_conn->sock, p_conn->close, r->proto_num, apr_table_get(r->headers_out, "Connection")); 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 * go via the proxy. * Note that if a proxy is used, then URLs other than http: can be accessed, * also, if we have trouble which is clearly specific to the proxy, then * 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 status; char server_portstr[32]; conn_rec *origin = NULL; proxy_conn_rec *backend = NULL; int is_ssl = 0; /* Note: Memory pool allocation. * A downstream keepalive connection is always connected to the existence * (or not) of an upstream keepalive connection. If this is not done then * load balancing against multiple backend servers breaks (one backend * server ends up taking 100% of the load), and the risk is run of * downstream keepalive connections being kept open unnecessarily. This * keeps webservers busy and ties up resources. * * As a result, we allocate all sockets out of the upstream connection * pool, and when we want to reuse a socket, we check first whether the * connection ID of the current upstream connection is the same as that * of the connection when the socket was opened. */ 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); return DECLINED; } 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 */ 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); } } backend->is_ssl = is_ssl; /* 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; } /* 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; } /* Step Three: Send the Request */ status = ap_proxy_ajp_request(p, r, p_conn, origin, conf, uri, url, server_portstr); if ( status != OK ) { return status; } /* Step Four: Receive the Response */ status = ap_proxy_ajp_process_response(p, r, p_conn, origin, backend, conf, server_portstr); if ( status != OK ) { /* clean up even if there is an error */ ap_proxy_http_cleanup(r, p_conn, backend); return status; } /* Step Five: Clean Up */ status = ap_proxy_http_cleanup(r, p_conn, backend); if ( status != OK ) { return status; } return OK; } static void ap_proxy_http_register_hook(apr_pool_t *p) { proxy_hook_scheme_handler(ap_proxy_ajp_handler, NULL, NULL, APR_HOOK_FIRST); proxy_hook_canon_handler(ap_proxy_ajp_canon, NULL, NULL, APR_HOOK_FIRST); } module AP_MODULE_DECLARE_DATA proxy_ajp_module = { STANDARD20_MODULE_STUFF, NULL, /* 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 */ ap_proxy_http_register_hook/* register hooks */ };
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]