proxy_util.c revision 2df9fb666776a6f6c7a84391609c4e41d87c350b
842ae4bd224140319ae7feec1872b93dfd491143fielding/* Copyright 1999-2006 The Apache Software Foundation or its licensors, as
842ae4bd224140319ae7feec1872b93dfd491143fielding * applicable.
842ae4bd224140319ae7feec1872b93dfd491143fielding * Licensed under the Apache License, Version 2.0 (the "License");
842ae4bd224140319ae7feec1872b93dfd491143fielding * you may not use this file except in compliance with the License.
842ae4bd224140319ae7feec1872b93dfd491143fielding * You may obtain a copy of the License at
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Unless required by applicable law or agreed to in writing, software
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * distributed under the License is distributed on an "AS IS" BASIS,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * See the License for the specific language governing permissions and
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * limitations under the License.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* Utility routines for Apache proxy */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* Global balancer counter */
5c0419d51818eb02045cf923a9fe456127a44c60wrowestatic int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int proxy_match_domainname(struct dirconn_entry *This, request_rec *r);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int proxy_match_hostname(struct dirconn_entry *This, request_rec *r);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int proxy_match_word(struct dirconn_entry *This, request_rec *r);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesAPR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, create_req,
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes/* already called in the knowledge that the characters are hex digits */
a81c0c1ae464b2063a21b45f80c9da8d89bb840ecovener#else /*APR_CHARSET_EBCDIC*/
43997561b2302d13dee973998e77743a3ddd2374trawick * we assume that the hex value refers to an ASCII character
fa123db15501821e36e513afa78e839775ad2800covener * so convert to EBCDIC so that it makes sense locally;
0568280364eb026393be492ebc732795c4934643jorton * client specifies %20 in URL to refer to a space char;
0568280364eb026393be492ebc732795c4934643jorton * at this point we're called with EBCDIC "20"; after turning
0568280364eb026393be492ebc732795c4934643jorton * EBCDIC "20" into binary 0x20, we then need to assume that 0x20
0568280364eb026393be492ebc732795c4934643jorton * represents an ASCII char and convert 0x20 to EBCDIC, yielding
796e4a7141265d8ed7036e4628161c6eafb2a789jorton#endif /*APR_CHARSET_EBCDIC*/
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesPROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (i >= 10)
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe if (i >= 10)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#else /*APR_CHARSET_EBCDIC*/
95b6fe1346805e1731e6e97c15d569c73be22cf7minfrin x[0] = '%';
713a2b68bac4aeb1e9c48785006c0732451039depquerna#endif /*APR_CHARSET_EBCDIC*/
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * canonicalise a URL-encoded string
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Convert a URL-encoded string to canonical form.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * It decodes characters which need not be encoded,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and encodes those which must be encoded, and does not touch
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * those which must not be touched.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesPROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char *allowed; /* characters which should not be encoded */
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes char *reserved; /* characters which much not be en/de-coded */
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe * N.B. in addition to :@&=, this allows ';' in an http path
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and '?' in an ftp path -- this may be revised
fa123db15501821e36e513afa78e839775ad2800covener * Also, it makes a '+' character in a search string reserved, as
fa123db15501821e36e513afa78e839775ad2800covener * it may be form-encoded. (Although RFC 1738 doesn't allow this -
fa123db15501821e36e513afa78e839775ad2800covener * it only permits ; / ? : @ = & as reserved chars.)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener else if (t == enc_search)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener else if (t == enc_user)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (t == enc_fpath)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else /* if (t == enc_parm) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (t == enc_search)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (i = 0, j = 0; i < len; i++, j++) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* always handle '/' first */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * decode it if not already done. do not decode reverse proxied URLs
fa123db15501821e36e513afa78e839775ad2800covener * unless specifically forced
cceddc0b6c0fdaed0c73abda39975bb1d388243acovener if ((forcedec || (proxyreq && proxyreq != PROXYREQ_REVERSE)) && ch == '%') {
fa123db15501821e36e513afa78e839775ad2800covener if (!apr_isxdigit(x[i + 1]) || !apr_isxdigit(x[i + 2]))
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener if (ch != 0 && strchr(reserved, ch)) { /* keep it encoded */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener/* recode it, if necessary */
6683642c1e0032eeeed5f99e8c14880692ef84c5sf y[j] = '\0';
6683642c1e0032eeeed5f99e8c14880692ef84c5sf * Parses network-location.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * urlp on input the URL; on output the path, after the leading /
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * user NULL if no user/password permitted
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * password holder for password
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * host holder for host
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * port port number; only set if one is supplied.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * Returns an error string.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return "Malformed URL";
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* find _last_ '@' since it might occur in user/password part */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener/* find password */
60215f303c7e1ce8b6d272acb5bfa5b3d99dfd34covener password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1, 0);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return "Bad %-escape in URL (password)";
b08925593f214f621161742925dcf074a8047e0acovener user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1, 0);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return "Bad %-escape in URL (username)";
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * Parse the host string to separate host portion from optional port.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * Perform range checking on port.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes rv = apr_parse_addr_port(&addr, &scope_id, &tmp_port, host, p);
ebe5305f8b22507374358f32b74d12fb50c05a25covener if (rv != APR_SUCCESS || addr == NULL || scope_id != NULL) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return "Invalid host/port";
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (tmp_port != 0) { /* only update caller's port if port was specified */
513b324e774c559b579896df131fd7c8471ed529rederpj ap_str_tolower(addr); /* DNS names are case-insensitive */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If the date is a valid RFC 850 date or asctime() date, then it
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * is converted to the RFC 1123 format, otherwise it is not modified.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * This routine is not very fast at doing conversions, as it uses
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * sscanf and sprintf. However, if the date is already correctly
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * formatted, then it exits very quickly.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ap_proxy_date_canon(apr_pool_t *p, const char *x1)
707f6d077f73cc948deead8df5b40ea42c1eaa78covener /* check for RFC 850 date */
707f6d077f73cc948deead8df5b40ea42c1eaa78covener return x; /* not a valid date */
707f6d077f73cc948deead8df5b40ea42c1eaa78covener if (q[4] != '-' || q[8] != '-' || q[11] != ' ' || q[14] != ':' ||
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (sscanf(q + 2, "%u-%3s-%u %u:%u:%u %3s", &mday, month, &year,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes/* check for acstime() date */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (x[3] != ' ' || x[7] != ' ' || x[10] != ' ' || x[13] != ':' ||
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes/* check date */
9ad7b260be233be7d7b5576979825cac72e15498rederpj apr_snprintf(q, 30, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", apr_day_snames[wk],
707f6d077f73cc948deead8df5b40ea42c1eaa78covenerPROXY_DECLARE(request_rec *)ap_proxy_make_fake_req(conn_rec *c, request_rec *r)
707f6d077f73cc948deead8df5b40ea42c1eaa78covener rp->request_config = ap_create_request_config(c->pool);
707f6d077f73cc948deead8df5b40ea42c1eaa78covener * list is a comma-separated list of case-insensitive tokens, with
707f6d077f73cc948deead8df5b40ea42c1eaa78covener * optional whitespace around the tokens.
707f6d077f73cc948deead8df5b40ea42c1eaa78covener * The return returns 1 if the token val is found in the list, or 0
9ad7b260be233be7d7b5576979825cac72e15498rederpj * otherwise.
9ad7b260be233be7d7b5576979825cac72e15498rederpjPROXY_DECLARE(int) ap_proxy_liststr(const char *list, const char *val)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem const char *p;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * list is a comma-separated list of case-insensitive tokens, with
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * optional whitespace around the tokens.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * if val appears on the list of tokens, it is removed from the list,
e8f95a682820a599fe41b22977010636be5c2717jim * and the new list is returned.
ebe5305f8b22507374358f32b74d12fb50c05a25covenerPROXY_DECLARE(char *)ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes const char *p;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (p != NULL) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf while (apr_isspace(*p));
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* do nothing */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf new = apr_pstrcat(pool, new, ",", apr_pstrndup(pool, list, i), NULL);
7dbf29be626018bc389ef94c1846aeac4b72633bsf * Converts 8 hex digits to a time integer
7dbf29be626018bc389ef94c1846aeac4b72633bsf unsigned int j;
7dbf29be626018bc389ef94c1846aeac4b72633bsf for (i = 0, j = 0; i < 8; i++) {
7dbf29be626018bc389ef94c1846aeac4b72633bsf if (j == 0xffffffff)
7dbf29be626018bc389ef94c1846aeac4b72633bsf * Converts a time integer to 8 hex digits
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes unsigned int j = t;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes for (i = 7; i >= 0; i--) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesPROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes "The proxy server could not handle the request "
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ap_escape_html(r->pool, r->uri), "</a></em>.<p>\n"
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes "Reason: <strong>",
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* Allow "error-notes" string to be printed by ap_send_error_response() */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes apr_table_setn(r->notes, "verbose-error-to", apr_pstrdup(r->pool, "*"));
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes r->status_line = apr_psprintf(r->pool, "%3.3u Proxy Error", statuscode);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic const char *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char *url, *user = NULL, *password = NULL, *err, *host;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* Set url to the first char after "scheme://" */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes url = apr_pstrdup(r->pool, &url[1]); /* make it point to "//", which is what proxy_canon_netloc expects */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);
9c63a05713cb83a44a1590b4af33edeebf39f118sf/* Return TRUE if addr represents an IP address (or an IP network address) */
9c63a05713cb83a44a1590b4af33edeebf39f118sfPROXY_DECLARE(int) ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p)
9c63a05713cb83a44a1590b4af33edeebf39f118sf * if the address is given with an explicit netmask, use that
9c63a05713cb83a44a1590b4af33edeebf39f118sf * Due to a deficiency in apr_inet_addr(), it is impossible to parse
9c63a05713cb83a44a1590b4af33edeebf39f118sf * "partial" addresses (with less than 4 quads) correctly, i.e.
9c63a05713cb83a44a1590b4af33edeebf39f118sf * 192.168.123 is parsed as 192.168.0.123, which is not what I want.
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * I therefore have to parse the IP address manually:
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * if (proxy_readmask(This->name, &This->addr.s_addr, &This->mask.s_addr) == 0)
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * addr and mask were set by proxy_readmask()
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * return 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Parse IP addr manually, optionally allowing
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * abbreviated net addresses like 192.168.
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Iterate over up to 4 (dotted) quads. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (quads = 0; quads < 4 && *addr != '\0'; ++quads) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (*addr == '/' && quads > 0) /* netmask starts here. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return 0; /* no digit at start of quad */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (tmp == addr) /* expected a digit, found something else */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* invalid octet */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ++addr; /* after the 4th quad, a dot would be illegal */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (addr[0] == '/' && apr_isdigit(addr[1])) { /* net mask follows: */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (tmp == addr) /* expected a digit, found something else */
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener if (bits < 0 || bits > 32) /* netmask must be between 0 and 32 */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * Determine (i.e., "guess") netmask by counting the
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * number of trailing .0's; reduce #quads appropriately
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * (so that 192.168.0.0 is equivalent to 192.168.)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* every zero-byte counts as 8 zero-bits */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if (bits != 32) /* no warning for fully qualified IP address */
e8f95a682820a599fe41b22977010636be5c2717jim "Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld",
f0f6f1b90ab582896f8a7d56d85bd62a55e57d90covener This->mask.s_addr = htonl(APR_INADDR_NONE << (32 - bits));
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (*addr == '\0' && (This->addr.s_addr & ~This->mask.s_addr) != 0) {
a81c0c1ae464b2063a21b45f80c9da8d89bb840ecovener "Warning: NetMask and IP-Addr disagree in %s/%ld",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes " Set to %s/%ld",
560fd0658902ab57754616c172d8953e69fc4722bnicholes return (*addr == '\0'); /* okay iff we've parsed the whole string */
560fd0658902ab57754616c172d8953e69fc4722bnicholes/* Return TRUE if addr represents an IP address (or an IP network address) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r)
e8f95a682820a599fe41b22977010636be5c2717jim if (4 == sscanf(host, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3])) {
7a55c294da84865fe13262ed66ffd0c5841a9da5covener if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "1)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(addr));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (apr_sockaddr_info_get(&reqaddr, host, APR_UNSPEC, 0, 0, r->pool)
e8f95a682820a599fe41b22977010636be5c2717jim "2)IP-NoMatch: hostname=%s msg=Host not found",
fa123db15501821e36e513afa78e839775ad2800covener /* Try to deal with multiple IP addr's for a host */
fa123db15501821e36e513afa78e839775ad2800covener /* FIXME: This needs to be able to deal with IPv6 */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (This->addr.s_addr == (ip->s_addr & This->mask.s_addr)) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener/* Return TRUE if addr represents a domain name */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerPROXY_DECLARE(int) ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* Domain name must start with a '.' */
0e05808dc59a321566303084c84b9826a4353cefrederpj /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (i = 0; apr_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "@@@@ handle optional port in proxy_is_domainname()");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* @@@@ handle optional port */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Strip trailing dots */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* Return TRUE if host "host" is in domain "domain" */
a81c0c1ae464b2063a21b45f80c9da8d89bb840ecovenerstatic int proxy_match_domainname(struct dirconn_entry *This, request_rec *r)
fa123db15501821e36e513afa78e839775ad2800covener if (host == NULL) /* some error was logged already */
fa123db15501821e36e513afa78e839775ad2800covener /* @@@ do this within the setup? */
fa123db15501821e36e513afa78e839775ad2800covener /* Ignore trailing dots in domain comparison: */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes && strncasecmp(&host[h_len - d_len], This->name, d_len) == 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* Return TRUE if host represents a host name */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesPROXY_DECLARE(int) ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Host names must not start with a '.' */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe for (i = 0; apr_isalnum(host[i]) || host[i] == '-' || host[i] == '.'; ++i);
e8f95a682820a599fe41b22977010636be5c2717jim if (host[i] != '\0' || apr_sockaddr_info_get(&addr, host, APR_UNSPEC, 0, 0, p) != APR_SUCCESS)
e8f95a682820a599fe41b22977010636be5c2717jim /* Strip trailing dots */
e8f95a682820a599fe41b22977010636be5c2717jim for (i = strlen(host) - 1; i > 0 && host[i] == '.'; --i)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* Return TRUE if host "host" is equal to host2 "host2" */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int proxy_match_hostname(struct dirconn_entry *This, request_rec *r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return 0; /* oops! */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Try to deal with multiple IP addr's for a host */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (addr->ipaddr_ptr == ? ? ? ? ? ? ? ? ? ? ? ? ?)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Ignore trailing dots in host2 comparison: */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* Return TRUE if addr is to be matched as a word */
e8f95a682820a599fe41b22977010636be5c2717jimPROXY_DECLARE(int) ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* Return TRUE if string "str2" occurs literally in "str1" */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int proxy_match_word(struct dirconn_entry *This, request_rec *r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return host != NULL && ap_strstr_c(host, This->name) != NULL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* checks whether a host in uri_addr matches proxyblock */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesPROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* XXX FIXME: conf->noproxies->elts is part of an opaque structure */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "proxy: checking remote machine [%s] against [%s]", uri_addr->hostname, npent[j].name);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((npent[j].name && ap_strstr_c(uri_addr->hostname, npent[j].name))
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener "proxy: connect to remote machine %s blocked: name %s matched", uri_addr->hostname, npent[j].name);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "proxy: ProxyBlock comparing %s and %s", conf_ip, uri_ip);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "proxy: connect to remote machine %s blocked: IP %s matched", uri_addr->hostname, conf_ip);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* set up the minimal filter set */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesPROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * converts a series of buckets into a string
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * XXX: BillS says this function performs essentially the same function as
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ap_rgetline() in protocol.c. Deprecate this function and use ap_rgetline()
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * instead? I think ap_proxy_string_read() will not work properly on non ASCII
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * (EBCDIC) machines either.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesPROXY_DECLARE(apr_status_t) ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* start with an empty string */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* loop through each brigade */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* get brigade from network one line at a time */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (APR_SUCCESS != (rv = ap_get_brigade(c->input_filters, bb,
e8f95a682820a599fe41b22977010636be5c2717jim /* loop through each bucket */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* The connection aborted or timed out */
e8f95a682820a599fe41b22977010636be5c2717jim if (APR_SUCCESS != apr_bucket_read(e, (const char **)&response, &len, APR_BLOCK_READ)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * is string LF terminated?
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * XXX: This check can be made more efficient by simply checking
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * if the last character in the 'response' buffer is an ASCII_LF.
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * See ap_rgetline() for an example.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* concat strings until buff is full - then throw the data away */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* unmerge an element in the table */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpjPROXY_DECLARE(void) ap_proxy_table_unmerge(apr_pool_t *p, apr_table_t *t, char *key)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* get the value to unmerge */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* remove the value from the headers */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* find each comma */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpjPROXY_DECLARE(const char *) ap_proxy_location_reverse_map(request_rec *r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * XXX FIXME: Make sure this handled the ambiguous case of the :<PORT>
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * after the hostname
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes if (l1 >= l2 && strncasecmp(ent[i].real, url, l2) == 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Cookies are a bit trickier to match: we've got two substrings to worry
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * about, and we can't just find them with strstr 'cos of case. Regexp
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes * matching would be an easy fix, but for better consistency with all the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * other matches we'll refrain and use apr_strmatch to find path=/domain=
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and stick to plain strings for the config values.
4be9c459920a7c1cfe62d654327dae5c4bb6b284sfPROXY_DECLARE(const char *) ap_proxy_cookie_reverse_map(request_rec *r,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf const char *pathp;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *domainp;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj * Find the match and replacement, but save replacing until we've done
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj * both path and domain so we know the new strlen
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if ((pathp = apr_strmatch(conf->cookie_path_str, str, len)) != NULL) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if (l1 >= l2 && strncmp(ent[i].fake, pathp, l2) == 0) {
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if ((domainp = apr_strmatch(conf->cookie_domain_str, str, len)) != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes l1 = domaine ? (domaine - domainp) : strlen(domainp);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ent = (struct proxy_alias *)conf->cookie_domains->elts;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (i = 0; i < conf->cookie_domains->nelts; i++) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (l1 >= l2 && strncasecmp(ent[i].fake, domainp, l2) == 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ret = apr_palloc(r->pool, len + pdiff + ddiff + 1);
8869662bb1a4078297020e94ae5e928626d877c6rederpjPROXY_DECLARE(proxy_balancer *) ap_proxy_get_balancer(apr_pool_t *p,
8869662bb1a4078297020e94ae5e928626d877c6rederpj const char *url)
8869662bb1a4078297020e94ae5e928626d877c6rederpj if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* remove path from uri */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf *c = '\0';
8869662bb1a4078297020e94ae5e928626d877c6rederpjPROXY_DECLARE(const char *) ap_proxy_add_balancer(proxy_balancer **balancer,
8869662bb1a4078297020e94ae5e928626d877c6rederpj const char *url)
8869662bb1a4078297020e94ae5e928626d877c6rederpj if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
8869662bb1a4078297020e94ae5e928626d877c6rederpj return "Bad syntax for a balancer name";
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* remove path from uri */
8869662bb1a4078297020e94ae5e928626d877c6rederpj * NOTE: The default method is byrequests, which we assume
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem lbmethod = ap_lookup_provider(PROXY_LBMETHOD, "byrequests", "0");
8869662bb1a4078297020e94ae5e928626d877c6rederpj return "Can't find 'byrequests' lb method";
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem (*balancer)->workers = apr_array_make(p, 5, sizeof(proxy_worker));
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* XXX Is this a right place to create mutex */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* XXX: Do we need to log something here */
8869662bb1a4078297020e94ae5e928626d877c6rederpj return "can not create thread mutex";
8869662bb1a4078297020e94ae5e928626d877c6rederpjPROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
8869662bb1a4078297020e94ae5e928626d877c6rederpj const char *url)
8869662bb1a4078297020e94ae5e928626d877c6rederpj const char *c;
8869662bb1a4078297020e94ae5e928626d877c6rederpj if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
8869662bb1a4078297020e94ae5e928626d877c6rederpj * We need to find the start of the path and
8869662bb1a4078297020e94ae5e928626d877c6rederpj * therefore we know the length of the scheme://hostname/
8869662bb1a4078297020e94ae5e928626d877c6rederpj * part to we can force-lowercase everything up to
8869662bb1a4078297020e94ae5e928626d877c6rederpj * the start of the path.
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * Do a "longest match" on the worker name to find the worker that
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * fits best to the URL.
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if ( ((worker_name_length = strlen(worker->name)) <= url_length)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem && (strncmp(url_copy, worker->name, worker_name_length) == 0) ) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemstatic apr_status_t conn_pool_cleanup(void *theworker)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemstatic void init_conn_pool(apr_pool_t *p, proxy_worker *worker)
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj * Create a connection pool's subpool.
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * This pool is used for connection recycling.
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * Once the worker is added it is never removed but
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * it can be disabled.
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj * Alloc from the same pool as worker.
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj * proxy_conn_pool is permanently attached to the worker.
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj cp = (proxy_conn_pool *)apr_pcalloc(p, sizeof(proxy_conn_pool));
11ca38a20ab9b2d00258f745620e2724838e7e21rederpjPROXY_DECLARE(const char *) ap_proxy_add_worker(proxy_worker **worker,
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj const char *url)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return "Unable to parse URL";
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj return "URL must be absolute!";
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem (*worker)->name = apr_uri_unparse(p, &uri, APR_URI_UNP_REVEALPASSWORD);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* Increase the total worker count */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* XXX: Do we need to log something here */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return "can not create thread mutex";
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpjPROXY_DECLARE(proxy_worker *) ap_proxy_create_worker(apr_pool_t *p)
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj worker = (proxy_worker *)apr_pcalloc(p, sizeof(proxy_worker));
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* Increase the total worker count */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemap_proxy_add_worker_to_balancer(apr_pool_t *pool, proxy_balancer *balancer,
0e05808dc59a321566303084c84b9826a4353cefrederpj /* Increase the total runtime count */
0e05808dc59a321566303084c84b9826a4353cefrederpjPROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
0e05808dc59a321566303084c84b9826a4353cefrederpj access_status = proxy_run_pre_request(worker, balancer, r, conf, url);
0e05808dc59a321566303084c84b9826a4353cefrederpj if (access_status == DECLINED && *balancer == NULL) {
0e05808dc59a321566303084c84b9826a4353cefrederpj "proxy: %s: found worker %s for %s",
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj "proxy: *: found forward proxy worker for %s",
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sf "proxy: *: found reverse proxy worker for %s",
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj else if (access_status == DECLINED && *balancer != NULL) {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* All the workers are busy */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj "proxy: all workers are busy. Unable to serve %s",
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpjPROXY_DECLARE(int) ap_proxy_post_request(proxy_worker *worker,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem access_status = proxy_run_post_request(worker, balancer, r, conf);
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sf/* DEPRECATED */
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sfPROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **newsock,
0e05808dc59a321566303084c84b9826a4353cefrederpj if ((rv = apr_socket_create(newsock, backend_addr->family,
0e05808dc59a321566303084c84b9826a4353cefrederpj loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
0e05808dc59a321566303084c84b9826a4353cefrederpj "proxy: %s: error creating fam %d socket for target %s",
0e05808dc59a321566303084c84b9826a4353cefrederpj * this could be an IPv6 address from the DNS but the
0e05808dc59a321566303084c84b9826a4353cefrederpj * local machine won't give us an IPv6 socket; hopefully the
0e05808dc59a321566303084c84b9826a4353cefrederpj * DNS returned an additional address to try
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj "apr_socket_opt_set(SO_RCVBUF): Failed to set "
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj "ProxyReceiveBufferSize, using default");
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* Set a timeout on the socket */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj "proxy: %s: fam %d socket created to connect to %s",
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj proxy_function, backend_addr->family, backend_name);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* make the connection out of the socket */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* if an error occurred, loop round and try again */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "proxy: %s: attempt to connect to %pI (%s) failed",
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * If the connection pool is NULL the worker
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * cleanup has been run. Just return.
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* Sanity check: Did we already return the pooled connection? */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj "proxy: Pooled connection 0x%pp for worker %s has been"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* determine if the connection need to be closed */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_reslist_release(worker->cp->res, (void *)conn);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Allways return the SUCCESS */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* reslist constructor */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_status_t connection_constructor(void **resource, void *params,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * Create the subpool for each connection
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes * This keeps the memory consumption constant
e8f95a682820a599fe41b22977010636be5c2717jim * when disconnecting from backend.
e8f95a682820a599fe41b22977010636be5c2717jim#if APR_HAS_THREADS /* only needed when threads are used */
e8f95a682820a599fe41b22977010636be5c2717jim/* reslist destructor */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowestatic apr_status_t connection_destructor(void *resource, void *params,
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener /* Destroy the pool only if not called from reslist_destroy */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ap_proxy_initialize_worker_share() concerns itself
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * with initializing those parts of worker which
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * are, or could be, shared. Basically worker->s
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesPROXY_DECLARE(void) ap_proxy_initialize_worker_share(proxy_server_conf *conf,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (worker->s && PROXY_WORKER_IS_INITIALIZED(worker)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* The worker share is already initialized */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "proxy: worker %s already initialized",
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener /* Get scoreboard slot */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "proxy: ap_get_scoreboard_lb(%d) failed in child %" APR_PID_T_FMT " for worker %s",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "proxy: grabbed scoreboard slot %d in child %" APR_PID_T_FMT " for worker %s",
e8f95a682820a599fe41b22977010636be5c2717jim score = apr_pcalloc(conf->pool, sizeof(proxy_worker_stat));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "proxy: initialized plain memory in child %" APR_PID_T_FMT " for worker %s",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * recheck to see if we've already been here. Possible
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * if proxy is using scoreboard to hold shared stats
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* The worker share is already initialized */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "proxy: worker %s already initialized",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes worker->s->status |= (worker->status | PROXY_WORKER_INITIALIZED);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholesPROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, server_rec *s)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* The worker is already initialized */
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* Set default parameters */
7dbf29be626018bc389ef94c1846aeac4b72633bsf worker->retry = apr_time_from_sec(PROXY_WORKER_DEFAULT_RETRY);
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* By default address is reusable */
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes /* Set hard max to no more then mpm_threads */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (worker->hmax == 0 || worker->hmax > mpm_threads)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (worker->smax == 0 || worker->smax > worker->hmax)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Set min to be lower then smax */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* This will supress the apr_reslist creation */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_pool_cleanup_register(worker->cp->pool, (void *)worker,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "proxy: initialized worker %d in child %" APR_PID_T_FMT " for (%s) min=%d max=%d smax=%d",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes worker->id, getpid(), worker->hostname, worker->min,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Set the acquire timeout */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_reslist_timeout_set(worker->cp->res, worker->acquire);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes rv = connection_constructor(&conn, worker, worker->cp->pool);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "proxy: initialized single connection worker %d in child %" APR_PID_T_FMT " for (%s)",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesPROXY_DECLARE(int) ap_proxy_retry_worker(const char *proxy_function,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "proxy: %s: retrying the worker for (%s)",
e8f95a682820a599fe41b22977010636be5c2717jim if (apr_time_now() > worker->s->error_time + worker->retry) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe "proxy: %s: worker for (%s) has been marked for retry",
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholesPROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Retry the worker */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "proxy: %s: disabled connection for (%s)",
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes rv = apr_reslist_acquire(worker->cp->res, (void **)conn);
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe /* create the new connection if the previous was destroyed */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes connection_constructor((void **)conn, worker, worker->cp->pool);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "proxy: %s: failed to acquire connection for (%s)",
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "proxy: %s: has acquired connection for (%s)",
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholesPROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function,
e8f95a682820a599fe41b22977010636be5c2717jim "proxy: %s: has released connection for (%s)",
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* If there is a connection kill it's cleanup */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes apr_pool_cleanup_kill(conn->connection->pool, conn, connection_cleanup);
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covenerap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener const char *proxyname,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes * Break up the URL to determine the host to connect to
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* we break the URL into host, port, uri */
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "proxy: connecting %s to %s:%d", *url, uri->hostname,
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener * allocate these out of the specified connection pool
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener * The scheme handler decides if this is permanent or
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener * short living pool.
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener /* are we connecting directly, or via a proxy? */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes *url = apr_pstrcat(p, uri->path, uri->query ? "?" : "",
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes * Make sure that we pick the the correct and valid worker.
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes * If a single keepalive connection triggers different workers,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes * then we have a problem (we don't select the correct one).
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes * Do an expensive check in this case, where we compare the
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes * the hostnames associated between the two.
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes * TODO: Handle this much better...
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (!conn->hostname || !worker->is_address_reusable ||
e8f95a682820a599fe41b22977010636be5c2717jim (r->proxyreq == PROXYREQ_PROXY || r->proxyreq == PROXYREQ_REVERSE) &&
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes (strcasecmp(conn->hostname, uri->hostname) != 0) ) ) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes conn->hostname = apr_pstrdup(conn->pool, proxyname);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe conn->hostname = apr_pstrdup(conn->pool, uri->hostname);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes apr_pool_cleanup_kill(conn->connection->pool, conn, connection_cleanup);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "proxy: lock");
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes * Worker can have the single constant backend adress.
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes * The single DNS lookup is used once per worker.
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes * If dynamic change is needed then set the addr to NULL
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes * inside dynamic config to force the lookup.
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* Get the server port for the Via headers */
e8f95a682820a599fe41b22977010636be5c2717jim apr_snprintf(server_portstr, server_portstr_size, ":%d",
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* check if ProxyBlock directive on this host */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if (OK != ap_proxy_checkproxyblock(r, conf, conn->addr)) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "Connect to remote machine blocked");
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "proxy: connected %s to %s:%d", *url, conn->hostname,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* save timeout */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* set no timeout */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes socket_status = apr_socket_recv(sock, test_buffer, &buffer_len);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes /* put back old timeout */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesPROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * This increases the connection pool size
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * but the number of dropped connections is
e8f95a682820a599fe41b22977010636be5c2717jim * relatively small compared to connection lifetime
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((rv = apr_socket_create(&newsock, backend_addr->family,
e8f95a682820a599fe41b22977010636be5c2717jim loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sf "proxy: %s: error creating fam %d socket for target %s",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * this could be an IPv6 address from the DNS but the
e8f95a682820a599fe41b22977010636be5c2717jim * local machine won't give us an IPv6 socket; hopefully the
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * DNS returned an additional address to try
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "apr_socket_opt_set(SO_RCVBUF): Failed to set "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "ProxyReceiveBufferSize, using default");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Set a timeout on the socket */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Set a keepalive option */
e8f95a682820a599fe41b22977010636be5c2717jim "apr_socket_opt_set(SO_KEEPALIVE): Failed to set"
e8f95a682820a599fe41b22977010636be5c2717jim " Keepalive");
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes "proxy: %s: fam %d socket created to connect to %s",
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes proxy_function, backend_addr->family, worker->hostname);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* make the connection out of the socket */
e8f95a682820a599fe41b22977010636be5c2717jim /* if an error occurred, loop round and try again */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "proxy: %s: attempt to connect to %pI (%s) failed",
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes * Put the entire worker to error state if
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the PROXY_WORKER_IGNORE_ERRORS flag is not set.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Altrough some connections may be alive
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * no further connections to the worker could be made
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!connected && PROXY_WORKER_IS_USABLE(worker) &&
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes !(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "ap_proxy_connect_backend disabling worker for (%s)",
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholesPROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function,
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sf * The socket is now open, create a new backend server connection
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes conn->connection = ap_run_create_connection(c->pool, s, conn->sock,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the peer reset the connection already; ap_run_create_connection()
e8f95a682820a599fe41b22977010636be5c2717jim * closed the socket
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes s, "proxy: %s: an error occurred creating a "
3effb85eb3124c6f02cd89e22ffed0fc9afaddb9bnicholes /* XXX: Will be closed when proxy_conn is closed */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * register the connection cleanup to client connection
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * so that the connection can be closed or reused
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* For ssl connection to backend */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin s, "proxy: %s: failed to enable ssl support "
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* TODO: See if this will break FTP */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "proxy: %s: connection complete to %pI (%s)",
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* set up the connection filters */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin rc = ap_run_pre_connection(conn->connection, conn->sock);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin "proxy: %s: pre_connection setup failed (%d)",
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * Since we can't resize the scoreboard when reconfiguring, we
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * have to impose a limit on the number of workers, we are
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * able to reconfigure to.
54d22ed1c429b903b029bbd62621f11a9e286137minfrin lb_workers_limit = proxy_lb_workers + PROXY_DYNAMIC_BALANCER_LIMIT;
09338db7fdcf82ecc189195347da3a3ed5d0287abnicholesPROXY_DECLARE(void) ap_proxy_backend_broke(request_rec *r,
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * If this is a subrequest, then prevent also caching of the main