/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.
*/
/* * Opaque structure containing infos for CONNECT-ing an origin server through a * remote (forward) proxy. Saved in the (opaque) proxy_conn_rec::forward pointer * field for backend connections kept alive, allowing for reuse when subsequent * requests should be routed through the same remote proxy.
*/ typedefstruct { constchar *proxy_auth; /* Proxy authorization */ constchar *target_host; /* Target/origin hostname */
apr_port_t target_port; /* Target/origin port */
} remote_connect_info;
/* * Opaque structure containing a refcounted and TTL'ed address.
*/ typedefstruct proxy_address {
apr_sockaddr_t *addr; /* Remote address info */ constchar *hostname; /* Remote host name */
apr_port_t hostport; /* Remote host port */
apr_uint32_t refcount; /* Number of conns and/or worker using it */
apr_uint32_t expiry; /* Expiry timestamp (seconds to proxy_start_time) */
} proxy_address;
/* special case handling */ if (!dlen) { /* XXX: APR_ENOSPACE would be better */ return APR_EGENERAL;
} if (!src) {
*dst = '\0'; return APR_SUCCESS;
}
thenil = apr_cpystrn(dst, src, dlen);
thelen = thenil - dst; if (src[thelen] == '\0') { return APR_SUCCESS;
} return APR_EGENERAL;
}
/* already called in the knowledge that the characters are hex digits */
PROXY_DECLARE(int) ap_proxy_hex2c(constchar *x)
{ int i;
#if !APR_CHARSET_EBCDIC int ch = x[0];
if (apr_isdigit(ch)) {
i = ch - '0';
} elseif (apr_isupper(ch)) {
i = ch - ('A' - 10);
} else {
i = ch - ('a' - 10);
}
i <<= 4;
ch = x[1]; if (apr_isdigit(ch)) {
i += ch - '0';
} elseif (apr_isupper(ch)) {
i += ch - ('A' - 10);
} else {
i += ch - ('a' - 10);
} return i; #else/*APR_CHARSET_EBCDIC*/ /* * we assume that the hex value refers to an ASCII character * so convert to EBCDIC so that it makes sense locally; * * example: * * client specifies %20 in URL to refer to a space char; * at this point we're called with EBCDIC "20"; after turning * EBCDIC "20" into binary 0x20, we then need to assume that 0x20 * represents an ASCII char and convert 0x20 to EBCDIC, yielding * 0x40
*/ char buf[1];
/* * Convert a URL-encoded string to canonical form. * It decodes characters which need not be encoded, * and encodes those which must be encoded, and does not touch * those which must not be touched.
*/
PROXY_DECLARE(char *)ap_proxy_canonenc_ex(apr_pool_t *p, constchar *x, int len, enum enctype t, int flags, int proxyreq)
{ int i, j, ch; char *y; char *allowed; /* characters which should not be encoded */ char *reserved; /* characters which much not be en/de-coded */ int forcedec = flags & PROXY_CANONENC_FORCEDEC; int noencslashesenc = flags & PROXY_CANONENC_NOENCODEDSLASHENCODING;
/* * N.B. in addition to :@&=, this allows ';' in an http path * and '?' in an ftp path -- this may be revised * * Also, it makes a '+' character in a search string reserved, as * it may be form-encoded. (Although RFC 1738 doesn't allow this - * it only permits ; / ? : @ = & as reserved chars.)
*/ if (t == enc_path) {
allowed = "~$-_.+!*'(),;:@&=";
} elseif (t == enc_search) {
allowed = "$-_.!*'(),;:@&=";
} elseif (t == enc_user) {
allowed = "$-_.+!*'(),;@&=";
} elseif (t == enc_fpath) {
allowed = "$-_.+!*'(),?:@&=";
} else { /* if (t == enc_parm) */
allowed = "$-_.+!*'(),?/:@&=";
}
for (i = 0, j = 0; i < len; i++, j++) { /* always handle '/' first */
ch = x[i]; if (strchr(reserved, ch)) {
y[j] = ch; continue;
} /* * decode it if not already done. do not decode reverse proxied URLs * unless specifically forced
*/ if ((forcedec || noencslashesenc
|| (proxyreq && proxyreq != PROXYREQ_REVERSE)) && ch == '%') { if (!apr_isxdigit(x[i + 1]) || !apr_isxdigit(x[i + 2])) { return NULL;
}
ch = ap_proxy_hex2c(&x[i + 1]); if (ch != 0 && strchr(reserved, ch)) { /* keep it encoded */
y[j++] = x[i++];
y[j++] = x[i++];
y[j] = x[i]; continue;
} if (noencslashesenc && !forcedec && (proxyreq == PROXYREQ_REVERSE)) { /* * In the reverse proxy case when we only want to keep encoded * slashes untouched revert back to '%' which will cause * '%' to be encoded in the following.
*/
ch = '%';
} else {
i += 2;
}
} /* recode it, if necessary */ if (!apr_isalnum(ch) && !strchr(allowed, ch)) {
ap_proxy_c2hex(ch, &y[j]);
j += 2;
} else {
y[j] = ch;
}
}
y[j] = '\0'; return y;
}
/* * Convert a URL-encoded string to canonical form. * It decodes characters which need not be encoded, * and encodes those which must be encoded, and does not touch * those which must not be touched.
*/
PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, constchar *x, int len, enum enctype t, int forcedec, int proxyreq)
{ int flags;
/* * Parses network-location. * urlp on input the URL; on output the path, after the leading / * user NULL if no user/password permitted * password holder for password * host holder for host * port port number; only set if one is supplied. * * Returns an error string.
*/
PROXY_DECLARE(char *)
ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp, char **passwordp, char **hostp, apr_port_t *port)
{ char *addr, *scope_id, *strp, *host, *url = *urlp; char *user = NULL, *password = NULL;
apr_port_t tmp_port;
apr_status_t rv;
user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1, 0); if (user == NULL) { return"Bad %-escape in URL (username)";
}
} if (userp != NULL) {
*userp = user;
} if (passwordp != NULL) {
*passwordp = password;
}
/* * Parse the host string to separate host portion from optional port. * Perform range checking on port.
*/
rv = apr_parse_addr_port(&addr, &scope_id, &tmp_port, host, p); if (rv != APR_SUCCESS || addr == NULL || scope_id != NULL) { return"Invalid host/port";
} if (tmp_port != 0) { /* only update caller's port if port was specified */
*port = tmp_port;
}
ap_str_tolower(addr); /* DNS names are case-insensitive */
*urlp = url;
*hostp = addr;
return NULL;
}
staticint proxyerror_core(request_rec *r, int statuscode, constchar *message,
apr_status_t rv)
{
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00898) "%s returned by %s", message, r->uri);
apr_table_setn(r->notes, "error-notes",
apr_pstrcat(r->pool, "The proxy server could not handle the request
return host; /* ought to return the port, too */
}
/* Return TRUE if addr represents an IP address (or an IP network address) */
PROXY_DECLARE(int) ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p)
{ constchar *addr = This->name; long ip_addr[4]; int i, quads; long bits;
/* * if the address is given with an explicit netmask, use that * Due to a deficiency in apr_inet_addr(), it is impossible to parse * "partial" addresses (with less than 4 quads) correctly, i.e. * 192.168.123 is parsed as 192.168.0.123, which is not what I want. * I therefore have to parse the IP address manually: * if (proxy_readmask(This->name, &This->addr.s_addr, &This->mask.s_addr) == 0) * addr and mask were set by proxy_readmask() * return 1;
*/
/* * Parse IP addr manually, optionally allowing * abbreviated net addresses like 192.168.
*/
/* Iterate over up to 4 (dotted) quads. */ for (quads = 0; quads < 4 && *addr != '\0'; ++quads) { char *tmp;
/* Return TRUE if addr represents an IP address (or an IP network address) */ staticint proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r)
{ int i, ip_addr[4]; struct in_addr addr, *ip; constchar *host = proxy_get_host_of_request(r);
/* Try to deal with multiple IP addr's for a host */ /* FIXME: This needs to be able to deal with IPv6 */ while (reqaddr) {
ip = (struct in_addr *) reqaddr->ipaddr_ptr; if (This->addr.s_addr == (ip->s_addr & This->mask.s_addr)) { #if DEBUGGING
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00910) "3)IP-Match: %s[%s] <-> ", host, inet_ntoa(*ip));
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00911) "%s/", inet_ntoa(This->addr));
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00912) "%s", inet_ntoa(This->mask)); #endif return 1;
} #if DEBUGGING else {
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00913) "3)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(*ip));
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00914) "%s/", inet_ntoa(This->addr));
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00915) "%s", inet_ntoa(This->mask));
} #endif
reqaddr = reqaddr->next;
}
}
return 0;
}
/* Return TRUE if addr represents a domain name */
PROXY_DECLARE(int) ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p)
{ char *addr = This->name; int i;
/* Domain name must start with a '.' */ if (addr[0] != '.') { return 0;
}
/* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */ for (i = 0; apr_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i) { continue;
}
#if 0 if (addr[i] == ':') {
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(03234) "@@@@ handle optional port in proxy_is_domainname()"); /* @@@@ handle optional port */
} #endif
if (addr[i] != '\0') { return 0;
}
/* Strip trailing dots */ for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i) {
addr[i] = '\0';
}
/* Return TRUE if host "host" is in domain "domain" */ staticint proxy_match_domainname(struct dirconn_entry *This, request_rec *r)
{ constchar *host = proxy_get_host_of_request(r); int d_len = strlen(This->name), h_len;
if (host == NULL) { /* some error was logged already */ return 0;
}
h_len = strlen(host);
/* @@@ do this within the setup? */ /* Ignore trailing dots in domain comparison: */ while (d_len > 0 && This->name[d_len - 1] == '.') {
--d_len;
} while (h_len > 0 && host[h_len - 1] == '.') {
--h_len;
} return h_len > d_len
&& strncasecmp(&host[h_len - d_len], This->name, d_len) == 0;
}
/* Return TRUE if host represents a host name */
PROXY_DECLARE(int) ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p)
{ struct apr_sockaddr_t *addr; char *host = This->name; int i;
/* Host names must not start with a '.' */ if (host[0] == '.') { return 0;
} /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */ for (i = 0; apr_isalnum(host[i]) || host[i] == '-' || host[i] == '.'; ++i);
/* Return TRUE if addr is to be matched as a word */
PROXY_DECLARE(int) ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p)
{
This->matcher = proxy_match_word; return 1;
}
/* XXX FIXME: conf->noproxies->elts is part of an opaque structure */ for (j = 0; j < conf->noproxies->nelts; j++) { struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts; struct apr_sockaddr_t *conf_addr;
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "checking remote machine [%s] against [%s]",
hostname, npent[j].name); if (ap_strstr_c(hostname, npent[j].name) || npent[j].name[0] == '*') {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(00916) "connect to remote machine %s blocked: name %s " "matched", hostname, npent[j].name); return HTTP_FORBIDDEN;
}
/* No IP address checks if no IP address was passed in, * i.e. the forward address proxy case, where this server does
* not resolve the hostname. */ if (!addr) continue;
/* * XXX FIXME: Make sure this handled the ambiguous case of the :<PORT> * after the hostname * XXX FIXME: Ensure the /uri component is a case sensitive match
*/ if (r->proxyreq != PROXYREQ_REVERSE) { return url;
}
l1_orig = strlen(url); if (conf->interpolate_env == 1) {
rconf = ap_get_module_config(r->request_config, &proxy_module);
ent = (struct proxy_alias *)rconf->raliases->elts;
} else {
ent = (struct proxy_alias *)conf->raliases->elts;
} for (i = 0; i < conf->raliases->nelts; i++) {
proxy_server_conf *sconf = (proxy_server_conf *)
ap_get_module_config(r->server->module_config, &proxy_module);
proxy_balancer *balancer; constchar *real = ent[i].real;
/* Restore the url length, if it had been changed by the code below */
l1 = l1_orig;
/* * First check if mapping against a balancer and see * if we have such a entity. If so, then we need to * find the particulars of the actual worker which may * or may not be the right one... basically, we need * to find which member actually handled this request.
*/ if (ap_proxy_valid_balancer_name((char *)real, 0) &&
(balancer = ap_proxy_get_balancer(r->pool, sconf, real, 1))) { int n, l3 = 0;
proxy_worker **worker = (proxy_worker **)balancer->workers->elts; constchar *urlpart = ap_strchr_c(real + sizeof(BALANCER_PREFIX) - 1, '/'); if (urlpart) { if (!urlpart[1])
urlpart = NULL; else
l3 = strlen(urlpart);
} /* The balancer comparison is a bit trickier. Given the context * BalancerMember balancer://alias http://example.com/foo * ProxyPassReverse /bash balancer://alias/bar * translate url http://example.com/foo/bar/that to /bash/that
*/ for (n = 0; n < balancer->workers->nelts; n++) {
l2 = strlen((*worker)->s->name_ex); if (urlpart) { /* urlpart (l3) assuredly starts with its own '/' */ if ((*worker)->s->name_ex[l2 - 1] == '/')
--l2; if (l1 >= l2 + l3
&& strncasecmp((*worker)->s->name_ex, url, l2) == 0
&& strncmp(urlpart, url + l2, l3) == 0) {
u = apr_pstrcat(r->pool, ent[i].fake, &url[l2 + l3],
NULL); return ap_is_url(u) ? u : ap_construct_url(r->pool, u, r);
}
} elseif (l1 >= l2 && strncasecmp((*worker)->s->name_ex, url, l2) == 0) { /* edge case where fake is just "/"... avoid double slash */ if ((ent[i].fake[0] == '/') && (ent[i].fake[1] == 0) && (url[l2] == '/')) {
u = apr_pstrdup(r->pool, &url[l2]);
} else {
u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
} return ap_is_url(u) ? u : ap_construct_url(r->pool, u, r);
}
worker++;
}
} else { constchar *part = url;
l2 = strlen(real); if (real[0] == '/') {
part = ap_strstr_c(url, "://"); if (part) {
part = ap_strchr_c(part+3, '/'); if (part) {
l1 = strlen(part);
} else {
part = url;
}
} else {
part = url;
}
} if (l2 > 0 && l1 >= l2 && strncasecmp(real, part, l2) == 0) {
u = apr_pstrcat(r->pool, ent[i].fake, &part[l2], NULL); return ap_is_url(u) ? u : 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.
*/
PROXY_DECLARE(constchar *) ap_proxy_cookie_reverse_map(request_rec *r,
proxy_dir_conf *conf, constchar *str)
{
proxy_req_conf *rconf = ap_get_module_config(r->request_config,
&proxy_module); struct proxy_alias *ent;
apr_size_t len = strlen(str); constchar *newpath = NULL; constchar *newdomain = NULL; constchar *pathp; constchar *domainp; constchar *pathe = NULL; constchar *domaine = NULL;
apr_size_t l1, l2, poffs = 0, doffs = 0; int i; int ddiff = 0; int pdiff = 0; char *tmpstr, *tmpstr_orig, *token, *last, *ret;
if (r->proxyreq != PROXYREQ_REVERSE) { return str;
}
/* * Find the match and replacement, but save replacing until we've done * both path and domain so we know the new strlen
*/
tmpstr_orig = tmpstr = apr_pstrdup(r->pool, str); while ((token = apr_strtok(tmpstr, ";", &last))) { /* skip leading spaces */ while (apr_isspace(*token)) {
++token;
}
/* * verifies that the balancer name conforms to standards.
*/
PROXY_DECLARE(int) ap_proxy_valid_balancer_name(char *name, int i)
{ if (!i)
i = sizeof(BALANCER_PREFIX)-1; return (!ap_cstr_casecmpn(name, BALANCER_PREFIX, i));
}
/* * NOTE: The default method is byrequests - if it doesn't * exist, that's OK at this time. We check when we share and sync
*/
lbmethod = ap_lookup_provider(PROXY_LBMETHOD, "byrequests", "0");
(*balancer)->lbmethod = lbmethod;
/* Generate a pseudo-UUID from the PRNG to use as a nonce for * the lifetime of the process. uuid.data is a char array so
* this is an adequate substitute for apr_uuid_get(). */
ap_random_insecure_bytes(uuid.data, sizeof uuid.data);
apr_uuid_format(nonce, &uuid);
rv = PROXY_STRNCPY(balancer->s->nonce, nonce);
} return rv;
}
if (!storage) {
ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, APLOGNO(00918) "no provider for %s", balancer->s->name); return APR_EGENERAL;
} /* * for each balancer we need to init the global * mutex and then attach to the shared worker shm
*/ if (!balancer->gmutex) {
ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, APLOGNO(00919) "no mutex %s", balancer->s->name); return APR_EGENERAL;
}
/* Re-open the mutex for the child. */
rv = apr_global_mutex_child_init(&(balancer->gmutex),
apr_global_mutex_lockfile(balancer->gmutex),
p); if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(00920) "Failed to reopen mutex %s in child",
balancer->s->name); return rv;
}
/* Process lbsets in order, only replacing unusable workers in a given lbset * with available spares from the same lbset. Hot standbys will be used as a * last resort when all other workers and spares are unavailable.
*/ for (cur_lbset = 0; !best_worker && (cur_lbset <= max_lbset); cur_lbset++) {
unusable_workers = 0;
apr_array_clear(spares);
apr_array_clear(standbys);
for (i = 0; i < balancer->workers->nelts; i++) {
worker = APR_ARRAY_IDX(balancer->workers, i, proxy_worker *);
if (worker->s->lbset > max_lbset) {
max_lbset = worker->s->lbset;
}
if (worker->s->lbset != cur_lbset) { continue;
}
/* A draining worker that is neither a spare nor a standby should be * considered unusable to be replaced by spares.
*/ if (PROXY_WORKER_IS_DRAINING(worker)) { if (!PROXY_WORKER_IS_SPARE(worker) && !PROXY_WORKER_IS_STANDBY(worker)) {
unusable_workers++;
}
continue;
}
/* If the worker is in error state run retry on that worker. It will * be marked as operational if the retry timeout is elapsed. The * worker might still be unusable, but we try anyway.
*/ if (!PROXY_WORKER_IS_USABLE(worker)) {
ap_proxy_retry_worker("BALANCER", worker, r->server);
}
/* Check if any spares are best. */ for (i = 0; (i < spares->nelts) && (i < unusable_workers); i++) {
worker = APR_ARRAY_IDX(spares, i, proxy_worker *);
if (is_best(worker, best_worker, baton)) {
best_worker = worker;
}
}
/* If no workers are available, use the standbys. */ if (!best_worker) { for (i = 0; i < standbys->nelts; i++) {
worker = APR_ARRAY_IDX(standbys, i, proxy_worker *);
static apr_status_t conn_pool_cleanup(void *theworker)
{ /* Signal that the child is exiting */
((proxy_worker *)theworker)->cp = NULL; return APR_SUCCESS;
}
/* * Alloc from the same pool as worker. * proxy_conn_pool is permanently attached to the worker.
*/
cp = (proxy_conn_pool *)apr_pcalloc(p, sizeof(proxy_conn_pool));
worker->cp = cp;
/* * We need a first pool (cp->pool) to maintain the connections attached to * the worker and a second one (cp->dns_pool) to maintain the DNS addresses * in use (TTL'ed, refcounted). New connections are created as/on a subpool * of cp->pool and new addresses as/on a subpool of cp->dns_pool, such that * both leaks (the subpools can be destroyed when the connections and/or * addresses are over) and race conditions (the creation/destruction of * subpools is protected by the parent pool's mutex) can be avoided. * * cp->dns_pool is created before cp->pool because when a connection on the * latter is destroyed it might destroy an address on the former, so when * the base pools are destroyed (e.g. child exit) we thusly make sure that * cp->dns_pool and its subpools are still alive when cp->pool gets killed. * * Both cp->dns_pool and cp->pool have their own allocator/mutex too since * acquiring connections and addresses don't need to contend.
*/
cp->dns_pool = make_conn_subpool(p, "proxy_worker_dns", s);
cp->pool = make_conn_subpool(p, "proxy_worker_cp", s);
/* When p is cleaning up the child is exiting, signal that to e.g. avoid * destroying the subpools explicitely in connection_destructor() when * they have been destroyed already by the reslist cleanup.
*/
apr_pool_pre_cleanup_register(p, worker, conn_pool_cleanup);
}
/* * Create another subpool that manages the data for the * socket and the connection member of the proxy_conn_rec struct as we * destroy this data more frequently than other data in the proxy_conn_rec * struct like hostname and addr (at least in the case where we have * keepalive connections that timed out). * * XXX: this is really needed only when worker->s->is_address_reusable, * otherwise conn->scpool = conn->pool would be fine. For now we * can't change it since it's (kind of) part of the API.
*/
apr_pool_create(&conn->scpool, p);
apr_pool_tag(conn->scpool, "proxy_conn_scpool");
/* Sanity check: Did we already return the pooled connection? */ if (conn->inreslist) {
ap_log_perror(APLOG_MARK, APLOG_ERR, 0, conn->pool, APLOGNO(00923) "Pooled connection 0x%pp for worker %s has been" " already returned to the connection pool.", conn,
ap_proxy_worker_name(conn->pool, worker)); return;
}
if (conn->r) {
apr_pool_destroy(conn->r->pool);
conn->r = NULL;
}
/* determine if the connection should be cleared, closed or reused */ if (!worker->s->is_address_reusable) {
apr_pool_t *p = conn->pool;
apr_pool_clear(p);
conn = connection_make(p, worker);
} elseif (!conn->sock
|| (conn->connection
&& conn->connection->keepalive == AP_CONN_CLOSE)
|| !ap_proxy_connection_reusable(conn)) {
socket_cleanup(conn);
} elseif (conn->is_ssl) { /* The current ssl section/dir config of the conn is not necessarily * the one it will be reused for, so while the conn is in the reslist * reset its ssl config to the worker's, until a new user sets its own * ssl config eventually in proxy_connection_create() and so on.
*/
ap_proxy_ssl_engine(conn->connection, worker->section_config, 1);
}
/* * If we have an existing SSL connection it might be possible that the * server sent some SSL message we have not read so far (e.g. an SSL * shutdown message if the server closed the keepalive connection while * the connection was held unused in our pool). * So ensure that if present (=> APR_NONBLOCK_READ) it is read and * processed. We don't expect any data to be in the returned brigade.
*/ if (conn->sock && conn->connection) {
rv = ap_get_brigade(conn->connection->input_filters, conn->tmp_bb,
AP_MODE_READBYTES, APR_NONBLOCK_READ,
HUGE_STRING_LEN); if (!APR_BRIGADE_EMPTY(conn->tmp_bb)) {
apr_off_t len;
/* * Create a subpool for each connection * This keeps the memory consumption constant * when it's recycled or destroyed.
*/
apr_pool_create(&p, pool);
apr_pool_tag(p, "proxy_conn_pool");
conn = connection_make(p, worker);
conn->inreslist = 1;
/* Compare to the provided default (if any) */ return (dflt && ap_cstr_casecmp(dflt, upgrade) == 0);
}
/* * Taken from ap_strcmp_match() : * Match = 0, NoMatch = 1, Abort = -1, Inval = -2 * Based loosely on sections of wildmat.c by Rich Salz * Hmmm... shouldn't this really go component by component? * * Adds handling of the "\<any>" => "<any>" unescaping.
*/ staticint ap_proxy_strcmp_ematch(constchar *str, constchar *expected)
{
apr_size_t x, y;
for (x = 0, y = 0; expected[y]; ++y, ++x) { if (expected[y] == '$' && apr_isdigit(expected[y + 1])) { do {
y += 2;
} while (expected[y] == '$' && apr_isdigit(expected[y + 1])); if (!expected[y]) return 0; while (str[x]) { int ret; if ((ret = ap_proxy_strcmp_ematch(&str[x++], &expected[y])) != 1) return ret;
} return -1;
} elseif (!str[x]) { return -1;
} elseif (expected[y] == '\\' && !expected[++y]) { /* NUL is an invalid char! */ return -2;
} if (str[x] != expected[y]) return 1;
} /* We got all the way through the worker path without a difference */ return 0;
}
staticint worker_matches(proxy_worker *worker, constchar *url, apr_size_t url_len,
apr_size_t min_match, apr_size_t *max_match, unsignedint mask)
{
apr_size_t name_len = strlen(worker->s->name_ex); if (name_len <= url_len
&& name_len > *max_match /* min_match is the length of the scheme://host part only of url, * so it's used as a fast path to avoid the match when url is too * small, but it's irrelevant when the worker host contains globs * (i.e. ->is_host_matchable).
*/
&& (worker->s->is_name_matchable
? ((mask & AP_PROXY_WORKER_IS_MATCH)
&& (worker->s->is_host_matchable || name_len >= min_match)
&& !ap_proxy_strcmp_ematch(url, worker->s->name_ex))
: ((mask & AP_PROXY_WORKER_IS_PREFIX)
&& (name_len >= min_match)
&& !strncmp(url, worker->s->name_ex, name_len)))) {
*max_match = name_len; return 1;
} return 0;
}
/* Default to lookup for both _PREFIX and _MATCH workers */ if (!(mask & (AP_PROXY_WORKER_IS_PREFIX | AP_PROXY_WORKER_IS_MATCH))) {
mask |= AP_PROXY_WORKER_IS_PREFIX | AP_PROXY_WORKER_IS_MATCH;
}
/* * We need to find the start of the path and * therefore we know the length of the scheme://hostname/ * part to we can force-lowercase everything up to * the start of the path.
*/
c = ap_strchr_c(c+3, '/'); if (c) { char *pathstart;
pathstart = url_copy + (c - url);
*pathstart = '\0';
ap_str_tolower(url_copy);
min_match = strlen(url_copy);
*pathstart = '/';
} else {
ap_str_tolower(url_copy);
min_match = strlen(url_copy);
}
/* * Do a "longest match" on the worker name to find the worker that * fits best to the URL, but keep in mind that we must have at least * a minimum matching of length min_match such that * scheme://hostname[:port] matches between worker and url.
*/ if (balancer) {
proxy_worker **worker = (proxy_worker **)balancer->workers->elts; for (i = 0; i < balancer->workers->nelts; i++, worker++) { if (worker_matches(*worker, url_copy, url_len,
min_match, &max_match, mask)) {
max_worker = *worker;
}
}
} else {
proxy_worker *worker = (proxy_worker *)conf->workers->elts; for (i = 0; i < conf->workers->nelts; i++, worker++) { if (worker_matches(worker, url_copy, url_len,
min_match, &max_match, mask)) {
max_worker = worker;
}
}
}
/* * To create a worker from scratch first we define the * specifics of the worker; this is all local data. * We then allocate space for it if data needs to be * shared. This allows for dynamic addition during * config and runtime.
*/
PROXY_DECLARE(char *) ap_proxy_define_worker_ex(apr_pool_t *p,
proxy_worker **worker,
proxy_balancer *balancer,
proxy_server_conf *conf, constchar *url, unsignedint mask)
{
apr_status_t rv;
proxy_worker_shared *wshared; constchar *ptr = NULL, *sockpath = NULL, *pdollars = NULL;
apr_port_t port_of_scheme; int address_not_reusable = 0;
apr_uri_t uri;
/* * Look to see if we are using UDS:
--> --------------------
--> maximum size reached
--> --------------------
¤ Dauer der Verarbeitung: 0.24 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.