]> granicus.if.org Git - apache/blob - modules/proxy/proxy_util.c
follow-up to r1530603: fix typo/syntax error
[apache] / modules / proxy / proxy_util.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* Utility routines for Apache proxy */
18 #include "mod_proxy.h"
19 #include "ap_mpm.h"
20 #include "scoreboard.h"
21 #include "apr_version.h"
22 #include "apr_hash.h"
23 #include "proxy_util.h"
24
25 #if APR_HAVE_UNISTD_H
26 #include <unistd.h>         /* for getpid() */
27 #endif
28
29 #if (APR_MAJOR_VERSION < 1)
30 #undef apr_socket_create
31 #define apr_socket_create apr_socket_create_ex
32 #endif
33
34 #if APR_HAVE_SYS_UN_H
35 #include <sys/un.h>
36 #endif
37 #if (APR_MAJOR_VERSION < 2)
38 #include "apr_support.h"        /* for apr_wait_for_io_or_timeout() */
39 #endif
40
41 APLOG_USE_MODULE(proxy);
42
43 #define UDS_SOCKET_STRING "uds="
44 /*
45  * Opaque structure containing target server info when
46  * using a forward proxy.
47  * Up to now only used in combination with HTTP CONNECT.
48  */
49 typedef struct {
50     int          use_http_connect; /* Use SSL Tunneling via HTTP CONNECT */
51     const char   *target_host;     /* Target hostname */
52     apr_port_t   target_port;      /* Target port */
53     const char   *proxy_auth;      /* Proxy authorization */
54 } forward_info;
55
56 /* Keep synced with mod_proxy.h! */
57 static struct wstat {
58     unsigned int bit;
59     char flag;
60     const char *name;
61 } wstat_tbl[] = {
62     {PROXY_WORKER_INITIALIZED,   PROXY_WORKER_INITIALIZED_FLAG,   "Init "},
63     {PROXY_WORKER_IGNORE_ERRORS, PROXY_WORKER_IGNORE_ERRORS_FLAG, "Ign "},
64     {PROXY_WORKER_DRAIN,         PROXY_WORKER_DRAIN_FLAG,         "Drn "},
65     {PROXY_WORKER_IN_SHUTDOWN,   PROXY_WORKER_IN_SHUTDOWN_FLAG,   "Shut "},
66     {PROXY_WORKER_DISABLED,      PROXY_WORKER_DISABLED_FLAG,      "Dis "},
67     {PROXY_WORKER_STOPPED,       PROXY_WORKER_STOPPED_FLAG,       "Stop "},
68     {PROXY_WORKER_IN_ERROR,      PROXY_WORKER_IN_ERROR_FLAG,      "Err "},
69     {PROXY_WORKER_HOT_STANDBY,   PROXY_WORKER_HOT_STANDBY_FLAG,   "Stby "},
70     {PROXY_WORKER_FREE,          PROXY_WORKER_FREE_FLAG,          "Free "},
71     {0x0, '\0', NULL}
72 };
73
74 /* Global balancer counter */
75 int PROXY_DECLARE_DATA proxy_lb_workers = 0;
76 static int lb_workers_limit = 0;
77 const apr_strmatch_pattern PROXY_DECLARE_DATA *ap_proxy_strmatch_path;
78 const apr_strmatch_pattern PROXY_DECLARE_DATA *ap_proxy_strmatch_domain;
79
80 extern apr_global_mutex_t *proxy_mutex;
81
82 static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r);
83 static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r);
84 static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r);
85 static int proxy_match_word(struct dirconn_entry *This, request_rec *r);
86
87 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, create_req,
88                                    (request_rec *r, request_rec *pr), (r, pr),
89                                    OK, DECLINED)
90
91 PROXY_DECLARE(apr_status_t) ap_proxy_strncpy(char *dst, const char *src,
92                                              apr_size_t dlen)
93 {
94     char *thenil;
95     apr_size_t thelen;
96
97     thenil = apr_cpystrn(dst, src, dlen);
98     thelen = thenil - dst;
99     /* Assume the typical case is smaller copying into bigger
100        so we have a fast return */
101     if ((thelen < dlen-1) || ((strlen(src)) == thelen)) {
102         return APR_SUCCESS;
103     }
104     /* XXX: APR_ENOSPACE would be better */
105     return APR_EGENERAL;
106 }
107
108 /* already called in the knowledge that the characters are hex digits */
109 PROXY_DECLARE(int) ap_proxy_hex2c(const char *x)
110 {
111     int i;
112
113 #if !APR_CHARSET_EBCDIC
114     int ch = x[0];
115
116     if (apr_isdigit(ch)) {
117         i = ch - '0';
118     }
119     else if (apr_isupper(ch)) {
120         i = ch - ('A' - 10);
121     }
122     else {
123         i = ch - ('a' - 10);
124     }
125     i <<= 4;
126
127     ch = x[1];
128     if (apr_isdigit(ch)) {
129         i += ch - '0';
130     }
131     else if (apr_isupper(ch)) {
132         i += ch - ('A' - 10);
133     }
134     else {
135         i += ch - ('a' - 10);
136     }
137     return i;
138 #else /*APR_CHARSET_EBCDIC*/
139     /*
140      * we assume that the hex value refers to an ASCII character
141      * so convert to EBCDIC so that it makes sense locally;
142      *
143      * example:
144      *
145      * client specifies %20 in URL to refer to a space char;
146      * at this point we're called with EBCDIC "20"; after turning
147      * EBCDIC "20" into binary 0x20, we then need to assume that 0x20
148      * represents an ASCII char and convert 0x20 to EBCDIC, yielding
149      * 0x40
150      */
151     char buf[1];
152
153     if (1 == sscanf(x, "%2x", &i)) {
154         buf[0] = i & 0xFF;
155         ap_xlate_proto_from_ascii(buf, 1);
156         return buf[0];
157     }
158     else {
159         return 0;
160     }
161 #endif /*APR_CHARSET_EBCDIC*/
162 }
163
164 PROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x)
165 {
166 #if !APR_CHARSET_EBCDIC
167     int i;
168
169     x[0] = '%';
170     i = (ch & 0xF0) >> 4;
171     if (i >= 10) {
172         x[1] = ('A' - 10) + i;
173     }
174     else {
175         x[1] = '0' + i;
176     }
177
178     i = ch & 0x0F;
179     if (i >= 10) {
180         x[2] = ('A' - 10) + i;
181     }
182     else {
183         x[2] = '0' + i;
184     }
185 #else /*APR_CHARSET_EBCDIC*/
186     static const char ntoa[] = { "0123456789ABCDEF" };
187     char buf[1];
188
189     ch &= 0xFF;
190
191     buf[0] = ch;
192     ap_xlate_proto_to_ascii(buf, 1);
193
194     x[0] = '%';
195     x[1] = ntoa[(buf[0] >> 4) & 0x0F];
196     x[2] = ntoa[buf[0] & 0x0F];
197     x[3] = '\0';
198 #endif /*APR_CHARSET_EBCDIC*/
199 }
200
201 /*
202  * canonicalise a URL-encoded string
203  */
204
205 /*
206  * Convert a URL-encoded string to canonical form.
207  * It decodes characters which need not be encoded,
208  * and encodes those which must be encoded, and does not touch
209  * those which must not be touched.
210  */
211 PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len,
212                                        enum enctype t, int forcedec,
213                                        int proxyreq)
214 {
215     int i, j, ch;
216     char *y;
217     char *allowed;  /* characters which should not be encoded */
218     char *reserved; /* characters which much not be en/de-coded */
219
220 /*
221  * N.B. in addition to :@&=, this allows ';' in an http path
222  * and '?' in an ftp path -- this may be revised
223  *
224  * Also, it makes a '+' character in a search string reserved, as
225  * it may be form-encoded. (Although RFC 1738 doesn't allow this -
226  * it only permits ; / ? : @ = & as reserved chars.)
227  */
228     if (t == enc_path) {
229         allowed = "~$-_.+!*'(),;:@&=";
230     }
231     else if (t == enc_search) {
232         allowed = "$-_.!*'(),;:@&=";
233     }
234     else if (t == enc_user) {
235         allowed = "$-_.+!*'(),;@&=";
236     }
237     else if (t == enc_fpath) {
238         allowed = "$-_.+!*'(),?:@&=";
239     }
240     else {            /* if (t == enc_parm) */
241         allowed = "$-_.+!*'(),?/:@&=";
242     }
243
244     if (t == enc_path) {
245         reserved = "/";
246     }
247     else if (t == enc_search) {
248         reserved = "+";
249     }
250     else {
251         reserved = "";
252     }
253
254     y = apr_palloc(p, 3 * len + 1);
255
256     for (i = 0, j = 0; i < len; i++, j++) {
257 /* always handle '/' first */
258         ch = x[i];
259         if (strchr(reserved, ch)) {
260             y[j] = ch;
261             continue;
262         }
263 /*
264  * decode it if not already done. do not decode reverse proxied URLs
265  * unless specifically forced
266  */
267         if ((forcedec || (proxyreq && proxyreq != PROXYREQ_REVERSE)) && ch == '%') {
268             if (!apr_isxdigit(x[i + 1]) || !apr_isxdigit(x[i + 2])) {
269                 return NULL;
270             }
271             ch = ap_proxy_hex2c(&x[i + 1]);
272             i += 2;
273             if (ch != 0 && strchr(reserved, ch)) {  /* keep it encoded */
274                 ap_proxy_c2hex(ch, &y[j]);
275                 j += 2;
276                 continue;
277             }
278         }
279 /* recode it, if necessary */
280         if (!apr_isalnum(ch) && !strchr(allowed, ch)) {
281             ap_proxy_c2hex(ch, &y[j]);
282             j += 2;
283         }
284         else {
285             y[j] = ch;
286         }
287     }
288     y[j] = '\0';
289     return y;
290 }
291
292 /*
293  * Parses network-location.
294  *    urlp           on input the URL; on output the path, after the leading /
295  *    user           NULL if no user/password permitted
296  *    password       holder for password
297  *    host           holder for host
298  *    port           port number; only set if one is supplied.
299  *
300  * Returns an error string.
301  */
302 PROXY_DECLARE(char *)
303      ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp,
304             char **passwordp, char **hostp, apr_port_t *port)
305 {
306     char *addr, *scope_id, *strp, *host, *url = *urlp;
307     char *user = NULL, *password = NULL;
308     apr_port_t tmp_port;
309     apr_status_t rv;
310
311     if (url[0] != '/' || url[1] != '/') {
312         return "Malformed URL";
313     }
314     host = url + 2;
315     url = strchr(host, '/');
316     if (url == NULL) {
317         url = "";
318     }
319     else {
320         *(url++) = '\0';    /* skip separating '/' */
321     }
322
323     /* find _last_ '@' since it might occur in user/password part */
324     strp = strrchr(host, '@');
325
326     if (strp != NULL) {
327         *strp = '\0';
328         user = host;
329         host = strp + 1;
330
331 /* find password */
332         strp = strchr(user, ':');
333         if (strp != NULL) {
334             *strp = '\0';
335             password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1, 0);
336             if (password == NULL) {
337                 return "Bad %-escape in URL (password)";
338             }
339         }
340
341         user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1, 0);
342         if (user == NULL) {
343             return "Bad %-escape in URL (username)";
344         }
345     }
346     if (userp != NULL) {
347         *userp = user;
348     }
349     if (passwordp != NULL) {
350         *passwordp = password;
351     }
352
353     /*
354      * Parse the host string to separate host portion from optional port.
355      * Perform range checking on port.
356      */
357     rv = apr_parse_addr_port(&addr, &scope_id, &tmp_port, host, p);
358     if (rv != APR_SUCCESS || addr == NULL || scope_id != NULL) {
359         return "Invalid host/port";
360     }
361     if (tmp_port != 0) { /* only update caller's port if port was specified */
362         *port = tmp_port;
363     }
364
365     ap_str_tolower(addr); /* DNS names are case-insensitive */
366
367     *urlp = url;
368     *hostp = addr;
369
370     return NULL;
371 }
372
373 PROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message)
374 {
375     const char *uri = ap_escape_html(r->pool, r->uri);
376     apr_table_setn(r->notes, "error-notes",
377         apr_pstrcat(r->pool,
378             "The proxy server could not handle the request <em><a href=\"",
379             uri, "\">", ap_escape_html(r->pool, r->method), "&nbsp;", uri,
380             "</a></em>.<p>\n"
381             "Reason: <strong>", ap_escape_html(r->pool, message),
382             "</strong></p>",
383             NULL));
384
385     /* Allow "error-notes" string to be printed by ap_send_error_response() */
386     apr_table_setn(r->notes, "verbose-error-to", "*");
387
388     r->status_line = apr_psprintf(r->pool, "%3.3u Proxy Error", statuscode);
389     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00898) "%s returned by %s", message,
390                   r->uri);
391     return statuscode;
392 }
393
394 static const char *
395      proxy_get_host_of_request(request_rec *r)
396 {
397     char *url, *user = NULL, *password = NULL, *err, *host = NULL;
398     apr_port_t port;
399
400     if (r->hostname != NULL) {
401         return r->hostname;
402     }
403
404     /* Set url to the first char after "scheme://" */
405     if ((url = strchr(r->uri, ':')) == NULL || url[1] != '/' || url[2] != '/') {
406         return NULL;
407     }
408
409     url = apr_pstrdup(r->pool, &url[1]);    /* make it point to "//", which is what proxy_canon_netloc expects */
410
411     err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);
412
413     if (err != NULL) {
414         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00899) "%s", err);
415     }
416
417     r->hostname = host;
418
419     return host;        /* ought to return the port, too */
420 }
421
422 /* Return TRUE if addr represents an IP address (or an IP network address) */
423 PROXY_DECLARE(int) ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p)
424 {
425     const char *addr = This->name;
426     long ip_addr[4];
427     int i, quads;
428     long bits;
429
430     /*
431      * if the address is given with an explicit netmask, use that
432      * Due to a deficiency in apr_inet_addr(), it is impossible to parse
433      * "partial" addresses (with less than 4 quads) correctly, i.e.
434      * 192.168.123 is parsed as 192.168.0.123, which is not what I want.
435      * I therefore have to parse the IP address manually:
436      * if (proxy_readmask(This->name, &This->addr.s_addr, &This->mask.s_addr) == 0)
437      * addr and mask were set by proxy_readmask()
438      * return 1;
439      */
440
441     /*
442      * Parse IP addr manually, optionally allowing
443      * abbreviated net addresses like 192.168.
444      */
445
446     /* Iterate over up to 4 (dotted) quads. */
447     for (quads = 0; quads < 4 && *addr != '\0'; ++quads) {
448         char *tmp;
449
450         if (*addr == '/' && quads > 0) {  /* netmask starts here. */
451             break;
452         }
453
454         if (!apr_isdigit(*addr)) {
455             return 0;       /* no digit at start of quad */
456         }
457
458         ip_addr[quads] = strtol(addr, &tmp, 0);
459
460         if (tmp == addr) {  /* expected a digit, found something else */
461             return 0;
462         }
463
464         if (ip_addr[quads] < 0 || ip_addr[quads] > 255) {
465             /* invalid octet */
466             return 0;
467         }
468
469         addr = tmp;
470
471         if (*addr == '.' && quads != 3) {
472             ++addr;     /* after the 4th quad, a dot would be illegal */
473         }
474     }
475
476     for (This->addr.s_addr = 0, i = 0; i < quads; ++i) {
477         This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
478     }
479
480     if (addr[0] == '/' && apr_isdigit(addr[1])) {   /* net mask follows: */
481         char *tmp;
482
483         ++addr;
484
485         bits = strtol(addr, &tmp, 0);
486
487         if (tmp == addr) {   /* expected a digit, found something else */
488             return 0;
489         }
490
491         addr = tmp;
492
493         if (bits < 0 || bits > 32) { /* netmask must be between 0 and 32 */
494             return 0;
495         }
496
497     }
498     else {
499         /*
500          * Determine (i.e., "guess") netmask by counting the
501          * number of trailing .0's; reduce #quads appropriately
502          * (so that 192.168.0.0 is equivalent to 192.168.)
503          */
504         while (quads > 0 && ip_addr[quads - 1] == 0) {
505             --quads;
506         }
507
508         /* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
509         if (quads < 1) {
510             return 0;
511         }
512
513         /* every zero-byte counts as 8 zero-bits */
514         bits = 8 * quads;
515
516         if (bits != 32) {     /* no warning for fully qualified IP address */
517             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00900)
518                          "Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld",
519                          inet_ntoa(This->addr), bits);
520         }
521     }
522
523     This->mask.s_addr = htonl(APR_INADDR_NONE << (32 - bits));
524
525     if (*addr == '\0' && (This->addr.s_addr & ~This->mask.s_addr) != 0) {
526         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00901)
527                      "Warning: NetMask and IP-Addr disagree in %s/%ld",
528                      inet_ntoa(This->addr), bits);
529         This->addr.s_addr &= This->mask.s_addr;
530         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00902)
531                      "         Set to %s/%ld", inet_ntoa(This->addr), bits);
532     }
533
534     if (*addr == '\0') {
535         This->matcher = proxy_match_ipaddr;
536         return 1;
537     }
538     else {
539         return (*addr == '\0'); /* okay iff we've parsed the whole string */
540     }
541 }
542
543 /* Return TRUE if addr represents an IP address (or an IP network address) */
544 static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r)
545 {
546     int i, ip_addr[4];
547     struct in_addr addr, *ip;
548     const char *host = proxy_get_host_of_request(r);
549
550     if (host == NULL) {   /* oops! */
551        return 0;
552     }
553
554     memset(&addr, '\0', sizeof addr);
555     memset(ip_addr, '\0', sizeof ip_addr);
556
557     if (4 == sscanf(host, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3])) {
558         for (addr.s_addr = 0, i = 0; i < 4; ++i) {
559             /* ap_proxy_is_ipaddr() already confirmed that we have
560              * a valid octet in ip_addr[i]
561              */
562             addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
563         }
564
565         if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {
566 #if DEBUGGING
567             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00903)
568                          "1)IP-Match: %s[%s] <-> ", host, inet_ntoa(addr));
569             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00904)
570                          "%s/", inet_ntoa(This->addr));
571             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00905)
572                          "%s", inet_ntoa(This->mask));
573 #endif
574             return 1;
575         }
576 #if DEBUGGING
577         else {
578             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00906)
579                          "1)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(addr));
580             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00907)
581                          "%s/", inet_ntoa(This->addr));
582             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00908)
583                          "%s", inet_ntoa(This->mask));
584         }
585 #endif
586     }
587     else {
588         struct apr_sockaddr_t *reqaddr;
589
590         if (apr_sockaddr_info_get(&reqaddr, host, APR_UNSPEC, 0, 0, r->pool)
591             != APR_SUCCESS) {
592 #if DEBUGGING
593             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00909)
594              "2)IP-NoMatch: hostname=%s msg=Host not found", host);
595 #endif
596             return 0;
597         }
598
599         /* Try to deal with multiple IP addr's for a host */
600         /* FIXME: This needs to be able to deal with IPv6 */
601         while (reqaddr) {
602             ip = (struct in_addr *) reqaddr->ipaddr_ptr;
603             if (This->addr.s_addr == (ip->s_addr & This->mask.s_addr)) {
604 #if DEBUGGING
605                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00910)
606                              "3)IP-Match: %s[%s] <-> ", host, inet_ntoa(*ip));
607                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00911)
608                              "%s/", inet_ntoa(This->addr));
609                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00912)
610                              "%s", inet_ntoa(This->mask));
611 #endif
612                 return 1;
613             }
614 #if DEBUGGING
615             else {
616                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00913)
617                              "3)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(*ip));
618                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00914)
619                              "%s/", inet_ntoa(This->addr));
620                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00915)
621                              "%s", inet_ntoa(This->mask));
622             }
623 #endif
624             reqaddr = reqaddr->next;
625         }
626     }
627
628     return 0;
629 }
630
631 /* Return TRUE if addr represents a domain name */
632 PROXY_DECLARE(int) ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p)
633 {
634     char *addr = This->name;
635     int i;
636
637     /* Domain name must start with a '.' */
638     if (addr[0] != '.') {
639         return 0;
640     }
641
642     /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
643     for (i = 0; apr_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i) {
644         continue;
645     }
646
647 #if 0
648     if (addr[i] == ':') {
649     ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
650                      "@@@@ handle optional port in proxy_is_domainname()");
651     /* @@@@ handle optional port */
652     }
653 #endif
654
655     if (addr[i] != '\0') {
656         return 0;
657     }
658
659     /* Strip trailing dots */
660     for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i) {
661         addr[i] = '\0';
662     }
663
664     This->matcher = proxy_match_domainname;
665     return 1;
666 }
667
668 /* Return TRUE if host "host" is in domain "domain" */
669 static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r)
670 {
671     const char *host = proxy_get_host_of_request(r);
672     int d_len = strlen(This->name), h_len;
673
674     if (host == NULL) {      /* some error was logged already */
675         return 0;
676     }
677
678     h_len = strlen(host);
679
680     /* @@@ do this within the setup? */
681     /* Ignore trailing dots in domain comparison: */
682     while (d_len > 0 && This->name[d_len - 1] == '.') {
683         --d_len;
684     }
685     while (h_len > 0 && host[h_len - 1] == '.') {
686         --h_len;
687     }
688     return h_len > d_len
689         && strncasecmp(&host[h_len - d_len], This->name, d_len) == 0;
690 }
691
692 /* Return TRUE if host represents a host name */
693 PROXY_DECLARE(int) ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p)
694 {
695     struct apr_sockaddr_t *addr;
696     char *host = This->name;
697     int i;
698
699     /* Host names must not start with a '.' */
700     if (host[0] == '.') {
701         return 0;
702     }
703     /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
704     for (i = 0; apr_isalnum(host[i]) || host[i] == '-' || host[i] == '.'; ++i);
705
706     if (host[i] != '\0' || apr_sockaddr_info_get(&addr, host, APR_UNSPEC, 0, 0, p) != APR_SUCCESS) {
707         return 0;
708     }
709
710     This->hostaddr = addr;
711
712     /* Strip trailing dots */
713     for (i = strlen(host) - 1; i > 0 && host[i] == '.'; --i) {
714         host[i] = '\0';
715     }
716
717     This->matcher = proxy_match_hostname;
718     return 1;
719 }
720
721 /* Return TRUE if host "host" is equal to host2 "host2" */
722 static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r)
723 {
724     char *host = This->name;
725     const char *host2 = proxy_get_host_of_request(r);
726     int h2_len;
727     int h1_len;
728
729     if (host == NULL || host2 == NULL) {
730         return 0; /* oops! */
731     }
732
733     h2_len = strlen(host2);
734     h1_len = strlen(host);
735
736 #if 0
737     struct apr_sockaddr_t *addr = *This->hostaddr;
738
739     /* Try to deal with multiple IP addr's for a host */
740     while (addr) {
741         if (addr->ipaddr_ptr == ? ? ? ? ? ? ? ? ? ? ? ? ?)
742             return 1;
743         addr = addr->next;
744     }
745 #endif
746
747     /* Ignore trailing dots in host2 comparison: */
748     while (h2_len > 0 && host2[h2_len - 1] == '.') {
749         --h2_len;
750     }
751     while (h1_len > 0 && host[h1_len - 1] == '.') {
752         --h1_len;
753     }
754     return h1_len == h2_len
755         && strncasecmp(host, host2, h1_len) == 0;
756 }
757
758 /* Return TRUE if addr is to be matched as a word */
759 PROXY_DECLARE(int) ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p)
760 {
761     This->matcher = proxy_match_word;
762     return 1;
763 }
764
765 /* Return TRUE if string "str2" occurs literally in "str1" */
766 static int proxy_match_word(struct dirconn_entry *This, request_rec *r)
767 {
768     const char *host = proxy_get_host_of_request(r);
769     return host != NULL && ap_strstr_c(host, This->name) != NULL;
770 }
771
772 #define MAX_IP_STR_LEN (46)
773
774 PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf,
775                                             const char *hostname, apr_sockaddr_t *addr)
776 {
777     int j;
778
779     /* XXX FIXME: conf->noproxies->elts is part of an opaque structure */
780     for (j = 0; j < conf->noproxies->nelts; j++) {
781         struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
782         struct apr_sockaddr_t *conf_addr;
783
784         ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
785                       "checking remote machine [%s] against [%s]",
786                       hostname, npent[j].name);
787         if (ap_strstr_c(hostname, npent[j].name) || npent[j].name[0] == '*') {
788             ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(00916)
789                           "connect to remote machine %s blocked: name %s "
790                           "matched", hostname, npent[j].name);
791             return HTTP_FORBIDDEN;
792         }
793
794         /* No IP address checks if no IP address was passed in,
795          * i.e. the forward address proxy case, where this server does
796          * not resolve the hostname.  */
797         if (!addr)
798             continue;
799
800         for (conf_addr = npent[j].addr; conf_addr; conf_addr = conf_addr->next) {
801             char caddr[MAX_IP_STR_LEN], uaddr[MAX_IP_STR_LEN];
802             apr_sockaddr_t *uri_addr;
803
804             if (apr_sockaddr_ip_getbuf(caddr, sizeof caddr, conf_addr))
805                 continue;
806
807             for (uri_addr = addr; uri_addr; uri_addr = uri_addr->next) {
808                 if (apr_sockaddr_ip_getbuf(uaddr, sizeof uaddr, uri_addr))
809                     continue;
810                 ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
811                               "ProxyBlock comparing %s and %s", caddr, uaddr);
812                 if (!strcmp(caddr, uaddr)) {
813                     ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(00917)
814                                   "connect to remote machine %s blocked: "
815                                   "IP %s matched", hostname, caddr);
816                     return HTTP_FORBIDDEN;
817                 }
818             }
819         }
820     }
821
822     return OK;
823 }
824
825 /* set up the minimal filter set */
826 PROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r)
827 {
828     ap_add_input_filter("HTTP_IN", NULL, r, c);
829     return OK;
830 }
831
832 PROXY_DECLARE(const char *) ap_proxy_location_reverse_map(request_rec *r,
833                               proxy_dir_conf *conf, const char *url)
834 {
835     proxy_req_conf *rconf;
836     struct proxy_alias *ent;
837     int i, l1, l2;
838     char *u;
839
840     /*
841      * XXX FIXME: Make sure this handled the ambiguous case of the :<PORT>
842      * after the hostname
843      * XXX FIXME: Ensure the /uri component is a case sensitive match
844      */
845     if (r->proxyreq != PROXYREQ_REVERSE) {
846         return url;
847     }
848
849     l1 = strlen(url);
850     if (conf->interpolate_env == 1) {
851         rconf = ap_get_module_config(r->request_config, &proxy_module);
852         ent = (struct proxy_alias *)rconf->raliases->elts;
853     }
854     else {
855         ent = (struct proxy_alias *)conf->raliases->elts;
856     }
857     for (i = 0; i < conf->raliases->nelts; i++) {
858         proxy_server_conf *sconf = (proxy_server_conf *)
859             ap_get_module_config(r->server->module_config, &proxy_module);
860         proxy_balancer *balancer;
861         const char *real = ent[i].real;
862         /*
863          * First check if mapping against a balancer and see
864          * if we have such a entity. If so, then we need to
865          * find the particulars of the actual worker which may
866          * or may not be the right one... basically, we need
867          * to find which member actually handled this request.
868          */
869         if (ap_proxy_valid_balancer_name((char *)real, 0) &&
870             (balancer = ap_proxy_get_balancer(r->pool, sconf, real, 1))) {
871             int n, l3 = 0;
872             proxy_worker **worker = (proxy_worker **)balancer->workers->elts;
873             const char *urlpart = ap_strchr_c(real + sizeof(BALANCER_PREFIX) - 1, '/');
874             if (urlpart) {
875                 if (!urlpart[1])
876                     urlpart = NULL;
877                 else
878                     l3 = strlen(urlpart);
879             }
880             /* The balancer comparison is a bit trickier.  Given the context
881              *   BalancerMember balancer://alias http://example.com/foo
882              *   ProxyPassReverse /bash balancer://alias/bar
883              * translate url http://example.com/foo/bar/that to /bash/that
884              */
885             for (n = 0; n < balancer->workers->nelts; n++) {
886                 l2 = strlen((*worker)->s->name);
887                 if (urlpart) {
888                     /* urlpart (l3) assuredly starts with its own '/' */
889                     if ((*worker)->s->name[l2 - 1] == '/')
890                         --l2;
891                     if (l1 >= l2 + l3
892                             && strncasecmp((*worker)->s->name, url, l2) == 0
893                             && strncmp(urlpart, url + l2, l3) == 0) {
894                         u = apr_pstrcat(r->pool, ent[i].fake, &url[l2 + l3],
895                                         NULL);
896                         return ap_is_url(u) ? u : ap_construct_url(r->pool, u, r);
897                     }
898                 }
899                 else if (l1 >= l2 && strncasecmp((*worker)->s->name, url, l2) == 0) {
900                     /* edge case where fake is just "/"... avoid double slash */
901                     if ((ent[i].fake[0] == '/') && (ent[i].fake[1] == 0) && (url[l2] == '/')) {
902                         u = apr_pstrdup(r->pool, &url[l2]);
903                     } else {
904                         u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
905                     }
906                     return ap_is_url(u) ? u : ap_construct_url(r->pool, u, r);
907                 }
908                 worker++;
909             }
910         }
911         else {
912             const char *part = url;
913             l2 = strlen(real);
914             if (real[0] == '/') {
915                 part = ap_strstr_c(url, "://");
916                 if (part) {
917                     part = ap_strchr_c(part+3, '/');
918                     if (part) {
919                         l1 = strlen(part);
920                     }
921                     else {
922                         part = url;
923                     }
924                 }
925                 else {
926                     part = url;
927                 }
928             }
929             if (l1 >= l2 && strncasecmp(real, part, l2) == 0) {
930                 u = apr_pstrcat(r->pool, ent[i].fake, &part[l2], NULL);
931                 return ap_is_url(u) ? u : ap_construct_url(r->pool, u, r);
932             }
933         }
934     }
935
936     return url;
937 }
938
939 /*
940  * Cookies are a bit trickier to match: we've got two substrings to worry
941  * about, and we can't just find them with strstr 'cos of case.  Regexp
942  * matching would be an easy fix, but for better consistency with all the
943  * other matches we'll refrain and use apr_strmatch to find path=/domain=
944  * and stick to plain strings for the config values.
945  */
946 PROXY_DECLARE(const char *) ap_proxy_cookie_reverse_map(request_rec *r,
947                               proxy_dir_conf *conf, const char *str)
948 {
949     proxy_req_conf *rconf = ap_get_module_config(r->request_config,
950                                                  &proxy_module);
951     struct proxy_alias *ent;
952     apr_size_t len = strlen(str);
953     const char *newpath = NULL;
954     const char *newdomain = NULL;
955     const char *pathp;
956     const char *domainp;
957     const char *pathe = NULL;
958     const char *domaine = NULL;
959     apr_size_t l1, l2, poffs = 0, doffs = 0;
960     int i;
961     int ddiff = 0;
962     int pdiff = 0;
963     char *ret;
964
965     if (r->proxyreq != PROXYREQ_REVERSE) {
966         return str;
967     }
968
969    /*
970     * Find the match and replacement, but save replacing until we've done
971     * both path and domain so we know the new strlen
972     */
973     if ((pathp = apr_strmatch(ap_proxy_strmatch_path, str, len)) != NULL) {
974         pathp += 5;
975         poffs = pathp - str;
976         pathe = ap_strchr_c(pathp, ';');
977         l1 = pathe ? (pathe - pathp) : strlen(pathp);
978         pathe = pathp + l1 ;
979         if (conf->interpolate_env == 1) {
980             ent = (struct proxy_alias *)rconf->cookie_paths->elts;
981         }
982         else {
983             ent = (struct proxy_alias *)conf->cookie_paths->elts;
984         }
985         for (i = 0; i < conf->cookie_paths->nelts; i++) {
986             l2 = strlen(ent[i].fake);
987             if (l1 >= l2 && strncmp(ent[i].fake, pathp, l2) == 0) {
988                 newpath = ent[i].real;
989                 pdiff = strlen(newpath) - l1;
990                 break;
991             }
992         }
993     }
994
995     if ((domainp = apr_strmatch(ap_proxy_strmatch_domain, str, len)) != NULL) {
996         domainp += 7;
997         doffs = domainp - str;
998         domaine = ap_strchr_c(domainp, ';');
999         l1 = domaine ? (domaine - domainp) : strlen(domainp);
1000         domaine = domainp + l1;
1001         if (conf->interpolate_env == 1) {
1002             ent = (struct proxy_alias *)rconf->cookie_domains->elts;
1003         }
1004         else {
1005             ent = (struct proxy_alias *)conf->cookie_domains->elts;
1006         }
1007         for (i = 0; i < conf->cookie_domains->nelts; i++) {
1008             l2 = strlen(ent[i].fake);
1009             if (l1 >= l2 && strncasecmp(ent[i].fake, domainp, l2) == 0) {
1010                 newdomain = ent[i].real;
1011                 ddiff = strlen(newdomain) - l1;
1012                 break;
1013             }
1014         }
1015     }
1016
1017     if (newpath) {
1018         ret = apr_palloc(r->pool, len + pdiff + ddiff + 1);
1019         l1 = strlen(newpath);
1020         if (newdomain) {
1021             l2 = strlen(newdomain);
1022             if (doffs > poffs) {
1023                 memcpy(ret, str, poffs);
1024                 memcpy(ret + poffs, newpath, l1);
1025                 memcpy(ret + poffs + l1, pathe, domainp - pathe);
1026                 memcpy(ret + doffs + pdiff, newdomain, l2);
1027                 strcpy(ret + doffs + pdiff + l2, domaine);
1028             }
1029             else {
1030                 memcpy(ret, str, doffs) ;
1031                 memcpy(ret + doffs, newdomain, l2);
1032                 memcpy(ret + doffs + l2, domaine, pathp - domaine);
1033                 memcpy(ret + poffs + ddiff, newpath, l1);
1034                 strcpy(ret + poffs + ddiff + l1, pathe);
1035             }
1036         }
1037         else {
1038             memcpy(ret, str, poffs);
1039             memcpy(ret + poffs, newpath, l1);
1040             strcpy(ret + poffs + l1, pathe);
1041         }
1042     }
1043     else {
1044         if (newdomain) {
1045             ret = apr_palloc(r->pool, len + pdiff + ddiff + 1);
1046             l2 = strlen(newdomain);
1047             memcpy(ret, str, doffs);
1048             memcpy(ret + doffs, newdomain, l2);
1049             strcpy(ret + doffs+l2, domaine);
1050         }
1051         else {
1052             ret = (char *)str; /* no change */
1053         }
1054     }
1055
1056     return ret;
1057 }
1058
1059 /*
1060  * BALANCER related...
1061  */
1062
1063 /*
1064  * verifies that the balancer name conforms to standards.
1065  */
1066 PROXY_DECLARE(int) ap_proxy_valid_balancer_name(char *name, int i)
1067 {
1068     if (!i)
1069         i = sizeof(BALANCER_PREFIX)-1;
1070     return (!strncasecmp(name, BALANCER_PREFIX, i));
1071 }
1072
1073
1074 PROXY_DECLARE(proxy_balancer *) ap_proxy_get_balancer(apr_pool_t *p,
1075                                                       proxy_server_conf *conf,
1076                                                       const char *url,
1077                                                       int care)
1078 {
1079     proxy_balancer *balancer;
1080     char *c, *uri = apr_pstrdup(p, url);
1081     int i;
1082     proxy_hashes hash;
1083
1084     c = strchr(uri, ':');
1085     if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') {
1086         return NULL;
1087     }
1088     /* remove path from uri */
1089     if ((c = strchr(c + 3, '/'))) {
1090         *c = '\0';
1091     }
1092     ap_str_tolower(uri);
1093     hash.def = ap_proxy_hashfunc(uri, PROXY_HASHFUNC_DEFAULT);
1094     hash.fnv = ap_proxy_hashfunc(uri, PROXY_HASHFUNC_FNV);
1095     balancer = (proxy_balancer *)conf->balancers->elts;
1096     for (i = 0; i < conf->balancers->nelts; i++) {
1097         if (balancer->hash.def == hash.def && balancer->hash.fnv == hash.fnv) {
1098             if (!care || !balancer->s->inactive) {
1099                 return balancer;
1100             }
1101         }
1102         balancer++;
1103     }
1104     return NULL;
1105 }
1106
1107
1108 PROXY_DECLARE(char *) ap_proxy_update_balancer(apr_pool_t *p,
1109                                                 proxy_balancer *balancer,
1110                                                 const char *url)
1111 {
1112     apr_uri_t puri;
1113     if (apr_uri_parse(p, url, &puri) != APR_SUCCESS) {
1114         return apr_psprintf(p, "unable to parse: %s", url);
1115     }
1116     if (puri.path && PROXY_STRNCPY(balancer->s->vpath, puri.path) != APR_SUCCESS) {
1117         return apr_psprintf(p, "balancer %s front-end virtual-path (%s) too long",
1118                             balancer->s->name, puri.path);
1119     }
1120     if (puri.hostname && PROXY_STRNCPY(balancer->s->vhost, puri.hostname) != APR_SUCCESS) {
1121         return apr_psprintf(p, "balancer %s front-end vhost name (%s) too long",
1122                             balancer->s->name, puri.hostname);
1123     }
1124     return NULL;
1125 }
1126
1127 #define PROXY_UNSET_NONCE '\n'
1128
1129 PROXY_DECLARE(char *) ap_proxy_define_balancer(apr_pool_t *p,
1130                                                proxy_balancer **balancer,
1131                                                proxy_server_conf *conf,
1132                                                const char *url,
1133                                                const char *alias,
1134                                                int do_malloc)
1135 {
1136     proxy_balancer_method *lbmethod;
1137     proxy_balancer_shared *bshared;
1138     char *c, *q, *uri = apr_pstrdup(p, url);
1139     const char *sname;
1140
1141     /* We should never get here without a valid BALANCER_PREFIX... */
1142
1143     c = strchr(uri, ':');
1144     if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
1145         return "Bad syntax for a balancer name";
1146     /* remove path from uri */
1147     if ((q = strchr(c + 3, '/')))
1148         *q = '\0';
1149
1150     ap_str_tolower(uri);
1151     *balancer = apr_array_push(conf->balancers);
1152     memset(*balancer, 0, sizeof(proxy_balancer));
1153
1154     /*
1155      * NOTE: The default method is byrequests - if it doesn't
1156      * exist, that's OK at this time. We check when we share and sync
1157      */
1158     lbmethod = ap_lookup_provider(PROXY_LBMETHOD, "byrequests", "0");
1159
1160     (*balancer)->workers = apr_array_make(p, 5, sizeof(proxy_worker *));
1161     (*balancer)->gmutex = NULL;
1162     (*balancer)->tmutex = NULL;
1163     (*balancer)->lbmethod = lbmethod;
1164
1165     if (do_malloc)
1166         bshared = ap_malloc(sizeof(proxy_balancer_shared));
1167     else
1168         bshared = apr_palloc(p, sizeof(proxy_balancer_shared));
1169
1170     memset(bshared, 0, sizeof(proxy_balancer_shared));
1171
1172     bshared->was_malloced = (do_malloc != 0);
1173     PROXY_STRNCPY(bshared->lbpname, "byrequests");
1174     if (PROXY_STRNCPY(bshared->name, uri) != APR_SUCCESS) {
1175         return apr_psprintf(p, "balancer name (%s) too long", uri);
1176     }
1177     /*
1178      * We do the below for verification. The real sname will be
1179      * done post_config
1180      */
1181     ap_pstr2_alnum(p, bshared->name + sizeof(BALANCER_PREFIX) - 1,
1182                    &sname);
1183     sname = apr_pstrcat(p, conf->id, "_", sname, NULL);
1184     if (PROXY_STRNCPY(bshared->sname, sname) != APR_SUCCESS) {
1185         return apr_psprintf(p, "balancer safe-name (%s) too long", sname);
1186     }
1187     bshared->hash.def = ap_proxy_hashfunc(bshared->name, PROXY_HASHFUNC_DEFAULT);
1188     bshared->hash.fnv = ap_proxy_hashfunc(bshared->name, PROXY_HASHFUNC_FNV);
1189     (*balancer)->hash = bshared->hash;
1190
1191     bshared->forcerecovery = 1;
1192     bshared->sticky_separator = '.';
1193     *bshared->nonce = PROXY_UNSET_NONCE;  /* impossible valid input */
1194
1195     (*balancer)->s = bshared;
1196     (*balancer)->sconf = conf;
1197
1198     return ap_proxy_update_balancer(p, *balancer, alias);
1199 }
1200
1201 /*
1202  * Create an already defined balancer and free up memory.
1203  */
1204 PROXY_DECLARE(apr_status_t) ap_proxy_share_balancer(proxy_balancer *balancer,
1205                                                     proxy_balancer_shared *shm,
1206                                                     int i)
1207 {
1208     apr_status_t rv = APR_SUCCESS;
1209     proxy_balancer_method *lbmethod;
1210     char *action = "copying";
1211     if (!shm || !balancer->s)
1212         return APR_EINVAL;
1213
1214     if ((balancer->s->hash.def != shm->hash.def) ||
1215         (balancer->s->hash.fnv != shm->hash.fnv)) {
1216         memcpy(shm, balancer->s, sizeof(proxy_balancer_shared));
1217         if (balancer->s->was_malloced)
1218             free(balancer->s);
1219     } else {
1220         action = "re-using";
1221     }
1222     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02337)
1223                  "%s shm[%d] (0x%pp) for %s", action, i, (void *)shm,
1224                  balancer->s->name);
1225     balancer->s = shm;
1226     balancer->s->index = i;
1227     /* the below should always succeed */
1228     lbmethod = ap_lookup_provider(PROXY_LBMETHOD, balancer->s->lbpname, "0");
1229     if (lbmethod) {
1230         balancer->lbmethod = lbmethod;
1231     } else {
1232         ap_log_error(APLOG_MARK, APLOG_CRIT, 0, ap_server_conf, APLOGNO(02432)
1233                      "Cannot find LB Method: %s", balancer->s->lbpname);
1234         return APR_EINVAL;
1235     }
1236     if (*balancer->s->nonce == PROXY_UNSET_NONCE) {
1237         char nonce[APR_UUID_FORMATTED_LENGTH + 1];
1238         apr_uuid_t uuid;
1239         /* Retrieve a UUID and store the nonce for the lifetime of
1240          * the process.
1241          */
1242         apr_uuid_get(&uuid);
1243         apr_uuid_format(nonce, &uuid);
1244         rv = PROXY_STRNCPY(balancer->s->nonce, nonce);
1245     }
1246     return rv;
1247 }
1248
1249 PROXY_DECLARE(apr_status_t) ap_proxy_initialize_balancer(proxy_balancer *balancer, server_rec *s, apr_pool_t *p)
1250 {
1251     apr_status_t rv = APR_SUCCESS;
1252     ap_slotmem_provider_t *storage = balancer->storage;
1253     apr_size_t size;
1254     unsigned int num;
1255
1256     if (!storage) {
1257         ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, APLOGNO(00918)
1258                      "no provider for %s", balancer->s->name);
1259         return APR_EGENERAL;
1260     }
1261     /*
1262      * for each balancer we need to init the global
1263      * mutex and then attach to the shared worker shm
1264      */
1265     if (!balancer->gmutex) {
1266         ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, APLOGNO(00919)
1267                      "no mutex %s", balancer->s->name);
1268         return APR_EGENERAL;
1269     }
1270
1271     /* Re-open the mutex for the child. */
1272     rv = apr_global_mutex_child_init(&(balancer->gmutex),
1273                                      apr_global_mutex_lockfile(balancer->gmutex),
1274                                      p);
1275     if (rv != APR_SUCCESS) {
1276         ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(00920)
1277                      "Failed to reopen mutex %s in child",
1278                      balancer->s->name);
1279         return rv;
1280     }
1281
1282     /* now attach */
1283     storage->attach(&(balancer->wslot), balancer->s->sname, &size, &num, p);
1284     if (!balancer->wslot) {
1285         ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, APLOGNO(00921) "slotmem_attach failed");
1286         return APR_EGENERAL;
1287     }
1288     if (balancer->lbmethod && balancer->lbmethod->reset)
1289         balancer->lbmethod->reset(balancer, s);
1290
1291     if (balancer->tmutex == NULL) {
1292         rv = apr_thread_mutex_create(&(balancer->tmutex), APR_THREAD_MUTEX_DEFAULT, p);
1293         if (rv != APR_SUCCESS) {
1294             ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, APLOGNO(00922)
1295                          "can not create balancer thread mutex");
1296             return rv;
1297         }
1298     }
1299     return APR_SUCCESS;
1300 }
1301
1302 /*
1303  * CONNECTION related...
1304  */
1305
1306 static apr_status_t conn_pool_cleanup(void *theworker)
1307 {
1308     proxy_worker *worker = (proxy_worker *)theworker;
1309     if (worker->cp->res) {
1310         worker->cp->pool = NULL;
1311     }
1312     return APR_SUCCESS;
1313 }
1314
1315 static void init_conn_pool(apr_pool_t *p, proxy_worker *worker)
1316 {
1317     apr_pool_t *pool;
1318     proxy_conn_pool *cp;
1319
1320     /*
1321      * Create a connection pool's subpool.
1322      * This pool is used for connection recycling.
1323      * Once the worker is added it is never removed but
1324      * it can be disabled.
1325      */
1326     apr_pool_create(&pool, p);
1327     apr_pool_tag(pool, "proxy_worker_cp");
1328     /*
1329      * Alloc from the same pool as worker.
1330      * proxy_conn_pool is permanently attached to the worker.
1331      */
1332     cp = (proxy_conn_pool *)apr_pcalloc(p, sizeof(proxy_conn_pool));
1333     cp->pool = pool;
1334     worker->cp = cp;
1335 }
1336
1337 PROXY_DECLARE(int) ap_proxy_connection_reusable(proxy_conn_rec *conn)
1338 {
1339     proxy_worker *worker = conn->worker;
1340
1341     return ! (conn->close || !worker->s->is_address_reusable || worker->s->disablereuse);
1342 }
1343
1344 static apr_status_t connection_cleanup(void *theconn)
1345 {
1346     proxy_conn_rec *conn = (proxy_conn_rec *)theconn;
1347     proxy_worker *worker = conn->worker;
1348
1349     /*
1350      * If the connection pool is NULL the worker
1351      * cleanup has been run. Just return.
1352      */
1353     if (!worker->cp) {
1354         return APR_SUCCESS;
1355     }
1356
1357     if (conn->r) {
1358         apr_pool_destroy(conn->r->pool);
1359         conn->r = NULL;
1360     }
1361
1362     /* Sanity check: Did we already return the pooled connection? */
1363     if (conn->inreslist) {
1364         ap_log_perror(APLOG_MARK, APLOG_ERR, 0, conn->pool, APLOGNO(00923)
1365                       "Pooled connection 0x%pp for worker %s has been"
1366                       " already returned to the connection pool.", conn,
1367                       worker->s->name);
1368         return APR_SUCCESS;
1369     }
1370
1371     /* determine if the connection need to be closed */
1372     if (!ap_proxy_connection_reusable(conn)) {
1373         apr_pool_t *p = conn->pool;
1374         apr_pool_clear(p);
1375         conn = apr_pcalloc(p, sizeof(proxy_conn_rec));
1376         conn->pool = p;
1377         conn->worker = worker;
1378         apr_pool_create(&(conn->scpool), p);
1379         apr_pool_tag(conn->scpool, "proxy_conn_scpool");
1380     }
1381
1382     if (worker->s->hmax && worker->cp->res) {
1383         conn->inreslist = 1;
1384         apr_reslist_release(worker->cp->res, (void *)conn);
1385     }
1386     else
1387     {
1388         worker->cp->conn = conn;
1389     }
1390
1391     /* Always return the SUCCESS */
1392     return APR_SUCCESS;
1393 }
1394
1395 static void socket_cleanup(proxy_conn_rec *conn)
1396 {
1397     conn->sock = NULL;
1398     conn->connection = NULL;
1399     apr_pool_clear(conn->scpool);
1400 }
1401
1402 PROXY_DECLARE(apr_status_t) ap_proxy_ssl_connection_cleanup(proxy_conn_rec *conn,
1403                                                             request_rec *r)
1404 {
1405     apr_bucket_brigade *bb;
1406     apr_status_t rv;
1407
1408     /*
1409      * If we have an existing SSL connection it might be possible that the
1410      * server sent some SSL message we have not read so far (e.g. an SSL
1411      * shutdown message if the server closed the keepalive connection while
1412      * the connection was held unused in our pool).
1413      * So ensure that if present (=> APR_NONBLOCK_READ) it is read and
1414      * processed. We don't expect any data to be in the returned brigade.
1415      */
1416     if (conn->sock && conn->connection) {
1417         bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
1418         rv = ap_get_brigade(conn->connection->input_filters, bb,
1419                             AP_MODE_READBYTES, APR_NONBLOCK_READ,
1420                             HUGE_STRING_LEN);
1421         if ((rv != APR_SUCCESS) && !APR_STATUS_IS_EAGAIN(rv)) {
1422             socket_cleanup(conn);
1423         }
1424         if (!APR_BRIGADE_EMPTY(bb)) {
1425             apr_off_t len;
1426
1427             rv = apr_brigade_length(bb, 0, &len);
1428             ap_log_rerror(APLOG_MARK, APLOG_TRACE3, rv, r,
1429                           "SSL cleanup brigade contained %"
1430                           APR_OFF_T_FMT " bytes of data.", len);
1431         }
1432         apr_brigade_destroy(bb);
1433     }
1434     return APR_SUCCESS;
1435 }
1436
1437 /* reslist constructor */
1438 static apr_status_t connection_constructor(void **resource, void *params,
1439                                            apr_pool_t *pool)
1440 {
1441     apr_pool_t *ctx;
1442     apr_pool_t *scpool;
1443     proxy_conn_rec *conn;
1444     proxy_worker *worker = (proxy_worker *)params;
1445
1446     /*
1447      * Create the subpool for each connection
1448      * This keeps the memory consumption constant
1449      * when disconnecting from backend.
1450      */
1451     apr_pool_create(&ctx, pool);
1452     apr_pool_tag(ctx, "proxy_conn_pool");
1453     /*
1454      * Create another subpool that manages the data for the
1455      * socket and the connection member of the proxy_conn_rec struct as we
1456      * destroy this data more frequently than other data in the proxy_conn_rec
1457      * struct like hostname and addr (at least in the case where we have
1458      * keepalive connections that timed out).
1459      */
1460     apr_pool_create(&scpool, ctx);
1461     apr_pool_tag(scpool, "proxy_conn_scpool");
1462     conn = apr_pcalloc(ctx, sizeof(proxy_conn_rec));
1463
1464     conn->pool   = ctx;
1465     conn->scpool = scpool;
1466     conn->worker = worker;
1467     conn->inreslist = 1;
1468     *resource = conn;
1469
1470     return APR_SUCCESS;
1471 }
1472
1473 /* reslist destructor */
1474 static apr_status_t connection_destructor(void *resource, void *params,
1475                                           apr_pool_t *pool)
1476 {
1477     proxy_conn_rec *conn = (proxy_conn_rec *)resource;
1478
1479     /* Destroy the pool only if not called from reslist_destroy */
1480     if (conn->worker->cp->pool) {
1481         apr_pool_destroy(conn->pool);
1482     }
1483
1484     return APR_SUCCESS;
1485 }
1486
1487 /*
1488  * WORKER related...
1489  */
1490
1491 PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
1492                                                   proxy_balancer *balancer,
1493                                                   proxy_server_conf *conf,
1494                                                   const char *url)
1495 {
1496     proxy_worker *worker;
1497     proxy_worker *max_worker = NULL;
1498     int max_match = 0;
1499     int url_length;
1500     int min_match;
1501     int worker_name_length;
1502     const char *c;
1503     char *url_copy;
1504     int i;
1505
1506     c = ap_strchr_c(url, ':');
1507     if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') {
1508         return NULL;
1509     }
1510
1511     url_length = strlen(url);
1512     url_copy = apr_pstrmemdup(p, url, url_length);
1513
1514     /*
1515      * We need to find the start of the path and
1516      * therefore we know the length of the scheme://hostname/
1517      * part to we can force-lowercase everything up to
1518      * the start of the path.
1519      */
1520     c = ap_strchr_c(c+3, '/');
1521     if (c) {
1522         char *pathstart;
1523         pathstart = url_copy + (c - url);
1524         *pathstart = '\0';
1525         ap_str_tolower(url_copy);
1526         min_match = strlen(url_copy);
1527         *pathstart = '/';
1528     }
1529     else {
1530         ap_str_tolower(url_copy);
1531         min_match = strlen(url_copy);
1532     }
1533     /*
1534      * Do a "longest match" on the worker name to find the worker that
1535      * fits best to the URL, but keep in mind that we must have at least
1536      * a minimum matching of length min_match such that
1537      * scheme://hostname[:port] matches between worker and url.
1538      */
1539
1540     if (balancer) {
1541         proxy_worker **workers = (proxy_worker **)balancer->workers->elts;
1542         for (i = 0; i < balancer->workers->nelts; i++, workers++) {
1543             worker = *workers;
1544             if ( ((worker_name_length = strlen(worker->s->name)) <= url_length)
1545                 && (worker_name_length >= min_match)
1546                 && (worker_name_length > max_match)
1547                 && (strncmp(url_copy, worker->s->name, worker_name_length) == 0) ) {
1548                 max_worker = worker;
1549                 max_match = worker_name_length;
1550             }
1551
1552         }
1553     } else {
1554         worker = (proxy_worker *)conf->workers->elts;
1555         for (i = 0; i < conf->workers->nelts; i++, worker++) {
1556             if ( ((worker_name_length = strlen(worker->s->name)) <= url_length)
1557                 && (worker_name_length >= min_match)
1558                 && (worker_name_length > max_match)
1559                 && (strncmp(url_copy, worker->s->name, worker_name_length) == 0) ) {
1560                 max_worker = worker;
1561                 max_match = worker_name_length;
1562             }
1563         }
1564     }
1565
1566     return max_worker;
1567 }
1568
1569 /*
1570  * To create a worker from scratch first we define the
1571  * specifics of the worker; this is all local data.
1572  * We then allocate space for it if data needs to be
1573  * shared. This allows for dynamic addition during
1574  * config and runtime.
1575  */
1576 PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p,
1577                                              proxy_worker **worker,
1578                                              proxy_balancer *balancer,
1579                                              proxy_server_conf *conf,
1580                                              const char *url,
1581                                              int do_malloc)
1582 {
1583     int rv;
1584     apr_uri_t uri;
1585     proxy_worker_shared *wshared;
1586     char *ptr;
1587
1588     rv = apr_uri_parse(p, url, &uri);
1589
1590     if (rv != APR_SUCCESS) {
1591         return "Unable to parse URL";
1592     }
1593     if (!uri.hostname || !uri.scheme) {
1594         return "URL must be absolute!";
1595     }
1596
1597     ap_str_tolower(uri.hostname);
1598     ap_str_tolower(uri.scheme);
1599     /*
1600      * Workers can be associated w/ balancers or on their
1601      * own; ie: the generic reverse-proxy or a worker
1602      * in a simple ProxyPass statement. eg:
1603      *
1604      *      ProxyPass / http://www.example.com
1605      *
1606      * in which case the worker goes in the conf slot.
1607      */
1608     if (balancer) {
1609         proxy_worker **runtime;
1610         /* recall that we get a ptr to the ptr here */
1611         runtime = apr_array_push(balancer->workers);
1612         *worker = *runtime = apr_palloc(p, sizeof(proxy_worker));   /* right to left baby */
1613         /* we've updated the list of workers associated with
1614          * this balancer *locally* */
1615         balancer->wupdated = apr_time_now();
1616     } else if (conf) {
1617         *worker = apr_array_push(conf->workers);
1618     } else {
1619         /* we need to allocate space here */
1620         *worker = apr_palloc(p, sizeof(proxy_worker));
1621     }
1622
1623     memset(*worker, 0, sizeof(proxy_worker));
1624     /* right here we just want to tuck away the worker info.
1625      * if called during config, we don't have shm setup yet,
1626      * so just note the info for later. */
1627     if (do_malloc)
1628         wshared = ap_malloc(sizeof(proxy_worker_shared));  /* will be freed ap_proxy_share_worker */
1629     else
1630         wshared = apr_palloc(p, sizeof(proxy_worker_shared));
1631
1632     memset(wshared, 0, sizeof(proxy_worker_shared));
1633
1634     ptr = apr_uri_unparse(p, &uri, APR_URI_UNP_REVEALPASSWORD);
1635     if (PROXY_STRNCPY(wshared->name, ptr) != APR_SUCCESS) {
1636         return apr_psprintf(p, "worker name (%s) too long", ptr);
1637     }
1638     if (PROXY_STRNCPY(wshared->scheme, uri.scheme) != APR_SUCCESS) {
1639         return apr_psprintf(p, "worker scheme (%s) too long", uri.scheme);
1640     }
1641     if (PROXY_STRNCPY(wshared->hostname, uri.hostname) != APR_SUCCESS) {
1642         return apr_psprintf(p, "worker hostname (%s) too long", uri.hostname);
1643     }
1644     wshared->port = uri.port;
1645     wshared->flush_packets = flush_off;
1646     wshared->flush_wait = PROXY_FLUSH_WAIT;
1647     wshared->is_address_reusable = 1;
1648     wshared->lbfactor = 1;
1649     wshared->smax = -1;
1650     wshared->hash.def = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_DEFAULT);
1651     wshared->hash.fnv = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_FNV);
1652     wshared->was_malloced = (do_malloc != 0);
1653
1654     (*worker)->hash = wshared->hash;
1655     (*worker)->context = NULL;
1656     (*worker)->cp = NULL;
1657     (*worker)->balancer = balancer;
1658     (*worker)->s = wshared;
1659
1660     return NULL;
1661 }
1662
1663 /*
1664  * Create an already defined worker and free up memory
1665  */
1666 PROXY_DECLARE(apr_status_t) ap_proxy_share_worker(proxy_worker *worker, proxy_worker_shared *shm,
1667                                                   int i)
1668 {
1669     char *action = "copying";
1670     if (!shm || !worker->s)
1671         return APR_EINVAL;
1672
1673     if ((worker->s->hash.def != shm->hash.def) ||
1674         (worker->s->hash.fnv != shm->hash.fnv)) {
1675         memcpy(shm, worker->s, sizeof(proxy_worker_shared));
1676         if (worker->s->was_malloced)
1677             free(worker->s); /* was malloced in ap_proxy_define_worker */
1678     } else {
1679         action = "re-using";
1680     }
1681     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02338)
1682                  "%s shm[%d] (0x%pp) for worker: %s", action, i, (void *)shm,
1683                  worker->s->name);
1684
1685     worker->s = shm;
1686     worker->s->index = i;
1687     return APR_SUCCESS;
1688 }
1689
1690 PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, server_rec *s, apr_pool_t *p)
1691 {
1692     apr_status_t rv = APR_SUCCESS;
1693     int mpm_threads;
1694
1695     if (worker->s->status & PROXY_WORKER_INITIALIZED) {
1696         /* The worker is already initialized */
1697         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00924)
1698                      "worker %s shared already initialized", worker->s->name);
1699     }
1700     else {
1701         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00925)
1702                      "initializing worker %s shared", worker->s->name);
1703         /* Set default parameters */
1704         if (!worker->s->retry_set) {
1705             worker->s->retry = apr_time_from_sec(PROXY_WORKER_DEFAULT_RETRY);
1706         }
1707         /* By default address is reusable unless DisableReuse is set */
1708         if (worker->s->disablereuse) {
1709             worker->s->is_address_reusable = 0;
1710         }
1711         else {
1712             worker->s->is_address_reusable = 1;
1713         }
1714
1715         ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads);
1716         if (mpm_threads > 1) {
1717             /* Set hard max to no more then mpm_threads */
1718             if (worker->s->hmax == 0 || worker->s->hmax > mpm_threads) {
1719                 worker->s->hmax = mpm_threads;
1720             }
1721             if (worker->s->smax == -1 || worker->s->smax > worker->s->hmax) {
1722                 worker->s->smax = worker->s->hmax;
1723             }
1724             /* Set min to be lower then smax */
1725             if (worker->s->min > worker->s->smax) {
1726                 worker->s->min = worker->s->smax;
1727             }
1728         }
1729         else {
1730             /* This will supress the apr_reslist creation */
1731             worker->s->min = worker->s->smax = worker->s->hmax = 0;
1732         }
1733     }
1734
1735     /* What if local is init'ed and shm isn't?? Even possible? */
1736     if (worker->local_status & PROXY_WORKER_INITIALIZED) {
1737         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00926)
1738                      "worker %s local already initialized", worker->s->name);
1739     }
1740     else {
1741         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00927)
1742                      "initializing worker %s local", worker->s->name);
1743         apr_global_mutex_lock(proxy_mutex);
1744         /* Now init local worker data */
1745         if (worker->tmutex == NULL) {
1746             rv = apr_thread_mutex_create(&(worker->tmutex), APR_THREAD_MUTEX_DEFAULT, p);
1747             if (rv != APR_SUCCESS) {
1748                 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00928)
1749                              "can not create worker thread mutex");
1750                 apr_global_mutex_unlock(proxy_mutex);
1751                 return rv;
1752             }
1753         }
1754         if (worker->cp == NULL)
1755             init_conn_pool(p, worker);
1756         if (worker->cp == NULL) {
1757             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00929)
1758                          "can not create connection pool");
1759             apr_global_mutex_unlock(proxy_mutex);
1760             return APR_EGENERAL;
1761         }
1762
1763         if (worker->s->hmax) {
1764             rv = apr_reslist_create(&(worker->cp->res),
1765                                     worker->s->min, worker->s->smax,
1766                                     worker->s->hmax, worker->s->ttl,
1767                                     connection_constructor, connection_destructor,
1768                                     worker, worker->cp->pool);
1769
1770             apr_pool_cleanup_register(worker->cp->pool, (void *)worker,
1771                                       conn_pool_cleanup,
1772                                       apr_pool_cleanup_null);
1773
1774             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00930)
1775                 "initialized pool in child %" APR_PID_T_FMT " for (%s) min=%d max=%d smax=%d",
1776                  getpid(), worker->s->hostname, worker->s->min,
1777                  worker->s->hmax, worker->s->smax);
1778
1779             /* Set the acquire timeout */
1780             if (rv == APR_SUCCESS && worker->s->acquire_set) {
1781                 apr_reslist_timeout_set(worker->cp->res, worker->s->acquire);
1782             }
1783
1784         }
1785         else {
1786             void *conn;
1787
1788             rv = connection_constructor(&conn, worker, worker->cp->pool);
1789             worker->cp->conn = conn;
1790
1791             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00931)
1792                  "initialized single connection worker in child %" APR_PID_T_FMT " for (%s)",
1793                  getpid(), worker->s->hostname);
1794         }
1795         apr_global_mutex_unlock(proxy_mutex);
1796
1797     }
1798     if (rv == APR_SUCCESS) {
1799         worker->s->status |= (PROXY_WORKER_INITIALIZED);
1800         worker->local_status |= (PROXY_WORKER_INITIALIZED);
1801     }
1802     return rv;
1803 }
1804
1805 static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worker,
1806         server_rec *s)
1807 {
1808     if (worker->s->status & PROXY_WORKER_IN_ERROR) {
1809         if (apr_time_now() > worker->s->error_time + worker->s->retry) {
1810             ++worker->s->retries;
1811             worker->s->status &= ~PROXY_WORKER_IN_ERROR;
1812             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00932)
1813                          "%s: worker for (%s) has been marked for retry",
1814                          proxy_function, worker->s->hostname);
1815             return OK;
1816         }
1817         else {
1818             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00933)
1819                          "%s: too soon to retry worker for (%s)",
1820                          proxy_function, worker->s->hostname);
1821             return DECLINED;
1822         }
1823     }
1824     else {
1825         return OK;
1826     }
1827 }
1828
1829 PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
1830                                         proxy_balancer **balancer,
1831                                         request_rec *r,
1832                                         proxy_server_conf *conf, char **url)
1833 {
1834     int access_status;
1835
1836     access_status = proxy_run_pre_request(worker, balancer, r, conf, url);
1837     if (access_status == DECLINED && *balancer == NULL) {
1838         *worker = ap_proxy_get_worker(r->pool, NULL, conf, *url);
1839         if (*worker) {
1840             ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
1841                           "%s: found worker %s for %s",
1842                           (*worker)->s->scheme, (*worker)->s->name, *url);
1843
1844             *balancer = NULL;
1845             access_status = OK;
1846         }
1847         else if (r->proxyreq == PROXYREQ_PROXY) {
1848             if (conf->forward) {
1849                 ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
1850                               "*: found forward proxy worker for %s", *url);
1851                 *balancer = NULL;
1852                 *worker = conf->forward;
1853                 access_status = OK;
1854                 /*
1855                  * The forward worker does not keep connections alive, so
1856                  * ensure that mod_proxy_http does the correct thing
1857                  * regarding the Connection header in the request.
1858                  */
1859                 apr_table_setn(r->subprocess_env, "proxy-nokeepalive", "1");
1860             }
1861         }
1862         else if (r->proxyreq == PROXYREQ_REVERSE) {
1863             if (conf->reverse) {
1864                 ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
1865                               "*: found reverse proxy worker for %s", *url);
1866                 *balancer = NULL;
1867                 *worker = conf->reverse;
1868                 access_status = OK;
1869                 /*
1870                  * The reverse worker does not keep connections alive, so
1871                  * ensure that mod_proxy_http does the correct thing
1872                  * regarding the Connection header in the request.
1873                  */
1874                 apr_table_setn(r->subprocess_env, "proxy-nokeepalive", "1");
1875             }
1876         }
1877     }
1878     else if (access_status == DECLINED && *balancer != NULL) {
1879         /* All the workers are busy */
1880         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00934)
1881                       "all workers are busy.  Unable to serve %s", *url);
1882         access_status = HTTP_SERVICE_UNAVAILABLE;
1883     }
1884     return access_status;
1885 }
1886
1887 PROXY_DECLARE(int) ap_proxy_post_request(proxy_worker *worker,
1888                                          proxy_balancer *balancer,
1889                                          request_rec *r,
1890                                          proxy_server_conf *conf)
1891 {
1892     int access_status = OK;
1893     if (balancer) {
1894         access_status = proxy_run_post_request(worker, balancer, r, conf);
1895         if (access_status == DECLINED) {
1896             access_status = OK; /* no post_request handler available */
1897             /* TODO: recycle direct worker */
1898         }
1899     }
1900
1901     return access_status;
1902 }
1903
1904 /* DEPRECATED */
1905 PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **newsock,
1906                                                const char *proxy_function,
1907                                                apr_sockaddr_t *backend_addr,
1908                                                const char *backend_name,
1909                                                proxy_server_conf *conf,
1910                                                request_rec *r)
1911 {
1912     apr_status_t rv;
1913     int connected = 0;
1914     int loglevel;
1915
1916     while (backend_addr && !connected) {
1917         if ((rv = apr_socket_create(newsock, backend_addr->family,
1918                                     SOCK_STREAM, 0, r->pool)) != APR_SUCCESS) {
1919             loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
1920             ap_log_rerror(APLOG_MARK, loglevel, rv, r, APLOGNO(00935)
1921                           "%s: error creating fam %d socket for target %s",
1922                           proxy_function, backend_addr->family, backend_name);
1923             /*
1924              * this could be an IPv6 address from the DNS but the
1925              * local machine won't give us an IPv6 socket; hopefully the
1926              * DNS returned an additional address to try
1927              */
1928             backend_addr = backend_addr->next;
1929             continue;
1930         }
1931
1932         if (conf->recv_buffer_size > 0 &&
1933             (rv = apr_socket_opt_set(*newsock, APR_SO_RCVBUF,
1934                                      conf->recv_buffer_size))) {
1935             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00936)
1936                           "apr_socket_opt_set(SO_RCVBUF): Failed to set "
1937                           "ProxyReceiveBufferSize, using default");
1938         }
1939
1940         rv = apr_socket_opt_set(*newsock, APR_TCP_NODELAY, 1);
1941         if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
1942             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00937)
1943                           "apr_socket_opt_set(APR_TCP_NODELAY): "
1944                           "Failed to set");
1945         }
1946
1947         /* Set a timeout on the socket */
1948         if (conf->timeout_set) {
1949             apr_socket_timeout_set(*newsock, conf->timeout);
1950         }
1951         else {
1952             apr_socket_timeout_set(*newsock, r->server->timeout);
1953         }
1954
1955         ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
1956                       "%s: fam %d socket created to connect to %s",
1957                       proxy_function, backend_addr->family, backend_name);
1958
1959         if (conf->source_address) {
1960             rv = apr_socket_bind(*newsock, conf->source_address);
1961             if (rv != APR_SUCCESS) {
1962                 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00938)
1963                               "%s: failed to bind socket to local address",
1964                               proxy_function);
1965             }
1966         }
1967
1968         /* make the connection out of the socket */
1969         rv = apr_socket_connect(*newsock, backend_addr);
1970
1971         /* if an error occurred, loop round and try again */
1972         if (rv != APR_SUCCESS) {
1973             apr_socket_close(*newsock);
1974             loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
1975             ap_log_rerror(APLOG_MARK, loglevel, rv, r, APLOGNO(00939)
1976                           "%s: attempt to connect to %pI (%s) failed",
1977                           proxy_function, backend_addr, backend_name);
1978             backend_addr = backend_addr->next;
1979             continue;
1980         }
1981         connected = 1;
1982     }
1983     return connected ? 0 : 1;
1984 }
1985
1986 PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function,
1987                                                proxy_conn_rec **conn,
1988                                                proxy_worker *worker,
1989                                                server_rec *s)
1990 {
1991     apr_status_t rv;
1992
1993     if (!PROXY_WORKER_IS_USABLE(worker)) {
1994         /* Retry the worker */
1995         ap_proxy_retry_worker(proxy_function, worker, s);
1996
1997         if (!PROXY_WORKER_IS_USABLE(worker)) {
1998             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00940)
1999                          "%s: disabled connection for (%s)",
2000                          proxy_function, worker->s->hostname);
2001             return HTTP_SERVICE_UNAVAILABLE;
2002         }
2003     }
2004
2005     if (worker->s->hmax && worker->cp->res) {
2006         rv = apr_reslist_acquire(worker->cp->res, (void **)conn);
2007     }
2008     else {
2009         /* create the new connection if the previous was destroyed */
2010         if (!worker->cp->conn) {
2011             connection_constructor((void **)conn, worker, worker->cp->pool);
2012         }
2013         else {
2014             *conn = worker->cp->conn;
2015             worker->cp->conn = NULL;
2016         }
2017         rv = APR_SUCCESS;
2018     }
2019
2020     if (rv != APR_SUCCESS) {
2021         ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00941)
2022                      "%s: failed to acquire connection for (%s)",
2023                      proxy_function, worker->s->hostname);
2024         return HTTP_SERVICE_UNAVAILABLE;
2025     }
2026     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00942)
2027                  "%s: has acquired connection for (%s)",
2028                  proxy_function, worker->s->hostname);
2029
2030     (*conn)->worker = worker;
2031     (*conn)->close  = 0;
2032     (*conn)->inreslist = 0;
2033     (*conn)->uds_path = NULL;
2034
2035     return OK;
2036 }
2037
2038 PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function,
2039                                                proxy_conn_rec *conn,
2040                                                server_rec *s)
2041 {
2042     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00943)
2043                 "%s: has released connection for (%s)",
2044                 proxy_function, conn->worker->s->hostname);
2045     connection_cleanup(conn);
2046
2047     return OK;
2048 }
2049
2050 /*
2051  * Decodes a '%' escaped string, and returns the number of characters
2052  */
2053 static int decodeenc(char *x)
2054 {
2055     int i, j, ch;
2056
2057     if (x[0] == '\0') {
2058         /* special case for no characters */
2059         return 0;
2060     }
2061     for (i = 0, j = 0; x[i] != '\0'; i++, j++) {
2062         /* decode it if not already done */
2063         ch = x[i];
2064         if (ch == '%' && apr_isxdigit(x[i + 1]) && apr_isxdigit(x[i + 2])) {
2065             ch = ap_proxy_hex2c(&x[i + 1]);
2066             i += 2;
2067         }
2068         x[j] = ch;
2069     }
2070     x[j] = '\0';
2071     return j;
2072 }
2073
2074 PROXY_DECLARE(int)
2075 ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
2076                               proxy_server_conf *conf,
2077                               proxy_worker *worker,
2078                               proxy_conn_rec *conn,
2079                               apr_uri_t *uri,
2080                               char **url,
2081                               const char *proxyname,
2082                               apr_port_t proxyport,
2083                               char *server_portstr,
2084                               int server_portstr_size)
2085 {
2086     int server_port;
2087     apr_status_t err = APR_SUCCESS;
2088     apr_status_t uerr = APR_SUCCESS;
2089
2090     /*
2091      * Break up the URL to determine the host to connect to
2092      */
2093
2094     /* we break the URL into host, port, uri */
2095     if (APR_SUCCESS != apr_uri_parse(p, *url, uri)) {
2096         return ap_proxyerror(r, HTTP_BAD_REQUEST,
2097                              apr_pstrcat(p,"URI cannot be parsed: ", *url,
2098                                          NULL));
2099     }
2100     if (!uri->port) {
2101         uri->port = apr_uri_port_of_scheme(uri->scheme);
2102     }
2103
2104     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00944)
2105                  "connecting %s to %s:%d", *url, uri->hostname, uri->port);
2106
2107     /*
2108      * allocate these out of the specified connection pool
2109      * The scheme handler decides if this is permanent or
2110      * short living pool.
2111      */
2112     /* are we connecting directly, or via a proxy? */
2113     if (!proxyname) {
2114         *url = apr_pstrcat(p, uri->path, uri->query ? "?" : "",
2115                            uri->query ? uri->query : "",
2116                            uri->fragment ? "#" : "",
2117                            uri->fragment ? uri->fragment : "", NULL);
2118     }
2119     /*
2120      * Figure out if our passed in proxy_conn_rec has a usable
2121      * address cached.
2122      *
2123      * TODO: Handle this much better... 
2124      *
2125      * XXX: If generic workers are ever address-reusable, we need 
2126      *      to check host and port on the conn and be careful about
2127      *      spilling the cached addr from the worker.
2128      */
2129     if (!conn->hostname || !worker->s->is_address_reusable ||
2130         worker->s->disablereuse || strncmp(conn->hostname, UDS_SOCKET_STRING, sizeof(UDS_SOCKET_STRING)-1) == 0) {
2131         if (proxyname) {
2132             conn->hostname = apr_pstrdup(conn->pool, proxyname);
2133             conn->port = proxyport;
2134             /*
2135              * If we have a forward proxy and the protocol is HTTPS,
2136              * then we need to prepend a HTTP CONNECT request before
2137              * sending our actual HTTPS requests.
2138              * Save our real backend data for using it later during HTTP CONNECT.
2139              */
2140             if (conn->is_ssl) {
2141                 const char *proxy_auth;
2142
2143                 forward_info *forward = apr_pcalloc(conn->pool, sizeof(forward_info));
2144                 conn->forward = forward;
2145                 forward->use_http_connect = 1;
2146                 forward->target_host = apr_pstrdup(conn->pool, uri->hostname);
2147                 forward->target_port = uri->port;
2148                 /* Do we want to pass Proxy-Authorization along?
2149                  * If we haven't used it, then YES
2150                  * If we have used it then MAYBE: RFC2616 says we MAY propagate it.
2151                  * So let's make it configurable by env.
2152                  * The logic here is the same used in mod_proxy_http.
2153                  */
2154                 proxy_auth = apr_table_get(r->headers_in, "Proxy-Authorization");
2155                 if (proxy_auth != NULL &&
2156                     proxy_auth[0] != '\0' &&
2157                     r->user == NULL && /* we haven't yet authenticated */
2158                     apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) {
2159                     forward->proxy_auth = apr_pstrdup(conn->pool, proxy_auth);
2160                 }
2161             }
2162         }
2163         else {
2164             conn->hostname = apr_pstrdup(conn->pool, uri->hostname);
2165             conn->port = uri->port;
2166         }
2167         socket_cleanup(conn);
2168         if (strncmp(conn->hostname, UDS_SOCKET_STRING, sizeof(UDS_SOCKET_STRING)-1) == 0) {
2169             char *uds_path = apr_pstrdup(conn->pool, conn->hostname + sizeof(UDS_SOCKET_STRING) - 1);
2170             decodeenc(uds_path);
2171             conn->uds_path = uds_path;
2172         }
2173         else if (!worker->s->is_address_reusable || worker->s->disablereuse) {
2174             /*
2175              * Only do a lookup if we should not reuse the backend address.
2176              * Otherwise we will look it up once for the worker.
2177              */
2178             err = apr_sockaddr_info_get(&(conn->addr),
2179                                         conn->hostname, APR_UNSPEC,
2180                                         conn->port, 0,
2181                                         conn->pool);
2182         }
2183     }
2184     if (worker->s->is_address_reusable && !worker->s->disablereuse) {
2185         /*
2186          * Looking up the backend address for the worker only makes sense if
2187          * we can reuse the address.
2188          */
2189         if (!worker->cp->addr) {
2190             if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) {
2191                 ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(00945) "lock");
2192                 return HTTP_INTERNAL_SERVER_ERROR;
2193             }
2194
2195             /*
2196              * Worker can have the single constant backend adress.
2197              * The single DNS lookup is used once per worker.
2198              * If dynamic change is needed then set the addr to NULL
2199              * inside dynamic config to force the lookup.
2200              */
2201             err = apr_sockaddr_info_get(&(worker->cp->addr),
2202                                         conn->hostname, APR_UNSPEC,
2203                                         conn->port, 0,
2204                                         worker->cp->pool);
2205             conn->addr = worker->cp->addr;
2206             if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) {
2207                 ap_log_rerror(APLOG_MARK, APLOG_ERR, uerr, r, APLOGNO(00946) "unlock");
2208             }
2209         }
2210         else {
2211             conn->addr = worker->cp->addr;
2212         }
2213     }
2214     /* Close a possible existing socket if we are told to do so */
2215     if (conn->close) {
2216         socket_cleanup(conn);
2217         conn->close = 0;
2218     }
2219
2220     if (err != APR_SUCCESS) {
2221         return ap_proxyerror(r, HTTP_GATEWAY_TIME_OUT,
2222                              apr_pstrcat(p, "DNS lookup failure for: ",
2223                                          conn->hostname, NULL));
2224     }
2225
2226     /* Get the server port for the Via headers */
2227     {
2228         server_port = ap_get_server_port(r);
2229         if (ap_is_default_port(server_port, r)) {
2230             strcpy(server_portstr,"");
2231         }
2232         else {
2233             apr_snprintf(server_portstr, server_portstr_size, ":%d",
2234                          server_port);
2235         }
2236     }
2237     /* check if ProxyBlock directive on this host */
2238     if (OK != ap_proxy_checkproxyblock(r, conf, uri->hostname, 
2239                                        proxyname ? NULL : conn->addr)) {
2240         return ap_proxyerror(r, HTTP_FORBIDDEN,
2241                              "Connect to remote machine blocked");
2242     }
2243     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00947)
2244                  "connected %s to %s:%d", *url, conn->hostname, conn->port);
2245     return OK;
2246 }
2247
2248 #define USE_ALTERNATE_IS_CONNECTED 1
2249
2250 #if !defined(APR_MSG_PEEK) && defined(MSG_PEEK)
2251 #define APR_MSG_PEEK MSG_PEEK
2252 #endif
2253
2254 #if USE_ALTERNATE_IS_CONNECTED && defined(APR_MSG_PEEK)
2255 PROXY_DECLARE(int) ap_proxy_is_socket_connected(apr_socket_t *socket)
2256 {
2257     apr_pollfd_t pfds[1];
2258     apr_status_t status;
2259     apr_int32_t  nfds;
2260
2261     pfds[0].reqevents = APR_POLLIN;
2262     pfds[0].desc_type = APR_POLL_SOCKET;
2263     pfds[0].desc.s = socket;
2264
2265     do {
2266         status = apr_poll(&pfds[0], 1, &nfds, 0);
2267     } while (APR_STATUS_IS_EINTR(status));
2268
2269     if (status == APR_SUCCESS && nfds == 1 &&
2270         pfds[0].rtnevents == APR_POLLIN) {
2271         apr_sockaddr_t unused;
2272         apr_size_t len = 1;
2273         char buf[1];
2274         /* The socket might be closed in which case
2275          * the poll will return POLLIN.
2276          * If there is no data available the socket
2277          * is closed.
2278          */
2279         status = apr_socket_recvfrom(&unused, socket, APR_MSG_PEEK,
2280                                      &buf[0], &len);
2281         if (status == APR_SUCCESS && len)
2282             return 1;
2283         else
2284             return 0;
2285     }
2286     else if (APR_STATUS_IS_EAGAIN(status) || APR_STATUS_IS_TIMEUP(status)) {
2287         return 1;
2288     }
2289     return 0;
2290
2291 }
2292 #else
2293 PROXY_DECLARE(int) ap_proxy_is_socket_connected(apr_socket_t *socket)
2294
2295 {
2296     apr_size_t buffer_len = 1;
2297     char test_buffer[1];
2298     apr_status_t socket_status;
2299     apr_interval_time_t current_timeout;
2300
2301     /* save timeout */
2302     apr_socket_timeout_get(sock, &current_timeout);
2303     /* set no timeout */
2304     apr_socket_timeout_set(sock, 0);
2305     socket_status = apr_socket_recv(sock, test_buffer, &buffer_len);
2306     /* put back old timeout */
2307     apr_socket_timeout_set(sock, current_timeout);
2308     if (APR_STATUS_IS_EOF(socket_status)
2309         || APR_STATUS_IS_ECONNRESET(socket_status)) {
2310         return 0;
2311     }
2312     else {
2313         return 1;
2314     }
2315 }
2316 #endif /* USE_ALTERNATE_IS_CONNECTED */
2317
2318
2319 /*
2320  * Send a HTTP CONNECT request to a forward proxy.
2321  * The proxy is given by "backend", the target server
2322  * is contained in the "forward" member of "backend".
2323  */
2324 static apr_status_t send_http_connect(proxy_conn_rec *backend,
2325                                       server_rec *s)
2326 {
2327     int status;
2328     apr_size_t nbytes;
2329     apr_size_t left;
2330     int complete = 0;
2331     char buffer[HUGE_STRING_LEN];
2332     char drain_buffer[HUGE_STRING_LEN];
2333     forward_info *forward = (forward_info *)backend->forward;
2334     int len = 0;
2335
2336     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00948)
2337                  "CONNECT: sending the CONNECT request for %s:%d "
2338                  "to the remote proxy %pI (%s)",
2339                  forward->target_host, forward->target_port,
2340                  backend->addr, backend->hostname);
2341     /* Create the CONNECT request */
2342     nbytes = apr_snprintf(buffer, sizeof(buffer),
2343                           "CONNECT %s:%d HTTP/1.0" CRLF,
2344                           forward->target_host, forward->target_port);
2345     /* Add proxy authorization from the initial request if necessary */
2346     if (forward->proxy_auth != NULL) {
2347         nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
2348                                "Proxy-Authorization: %s" CRLF,
2349                                forward->proxy_auth);
2350     }
2351     /* Set a reasonable agent and send everything */
2352     nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
2353                            "Proxy-agent: %s" CRLF CRLF,
2354                            ap_get_server_banner());
2355     apr_socket_send(backend->sock, buffer, &nbytes);
2356
2357     /* Receive the whole CONNECT response */
2358     left = sizeof(buffer) - 1;
2359     /* Read until we find the end of the headers or run out of buffer */
2360     do {
2361         nbytes = left;
2362         status = apr_socket_recv(backend->sock, buffer + len, &nbytes);
2363         len += nbytes;
2364         left -= nbytes;
2365         buffer[len] = '\0';
2366         if (strstr(buffer + len - nbytes, "\r\n\r\n") != NULL) {
2367             complete = 1;
2368             break;
2369         }
2370     } while (status == APR_SUCCESS && left > 0);
2371     /* Drain what's left */
2372     if (!complete) {
2373         nbytes = sizeof(drain_buffer) - 1;
2374         while (status == APR_SUCCESS && nbytes) {
2375             status = apr_socket_recv(backend->sock, drain_buffer, &nbytes);
2376             drain_buffer[nbytes] = '\0';
2377             nbytes = sizeof(drain_buffer) - 1;
2378             if (strstr(drain_buffer, "\r\n\r\n") != NULL) {
2379                 break;
2380             }
2381         }
2382     }
2383
2384     /* Check for HTTP_OK response status */
2385     if (status == APR_SUCCESS) {
2386         int major, minor;
2387         /* Only scan for three character status code */
2388         char code_str[4];
2389
2390         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00949)
2391                      "send_http_connect: response from the forward proxy: %s",
2392                      buffer);
2393
2394         /* Extract the returned code */
2395         if (sscanf(buffer, "HTTP/%u.%u %3s", &major, &minor, code_str) == 3) {
2396             status = atoi(code_str);
2397             if (status == HTTP_OK) {
2398                 status = APR_SUCCESS;
2399             }
2400             else {
2401                 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00950)
2402                              "send_http_connect: the forward proxy returned code is '%s'",
2403                              code_str);
2404             status = APR_INCOMPLETE;
2405             }
2406         }
2407     }
2408
2409     return(status);
2410 }
2411
2412
2413 #if APR_HAVE_SYS_UN_H
2414 /* lifted from mod_proxy_fdpass.c; tweaked addrlen in connect() call */
2415 static apr_status_t socket_connect_un(apr_socket_t *sock,
2416                                       struct sockaddr_un *sa)
2417 {
2418     apr_status_t rv;
2419     apr_os_sock_t rawsock;
2420     apr_interval_time_t t;
2421
2422     rv = apr_os_sock_get(&rawsock, sock);
2423     if (rv != APR_SUCCESS) {
2424         return rv;
2425     }
2426
2427     rv = apr_socket_timeout_get(sock, &t);
2428     if (rv != APR_SUCCESS) {
2429         return rv;
2430     }
2431
2432     do {
2433         const socklen_t addrlen = APR_OFFSETOF(struct sockaddr_un, sun_path)
2434                                   + strlen(sa->sun_path) + 1;
2435         rv = connect(rawsock, (struct sockaddr*)sa, addrlen);
2436     } while (rv == -1 && errno == EINTR);
2437
2438     if ((rv == -1) && (errno == EINPROGRESS || errno == EALREADY)
2439         && (t > 0)) {
2440 #if APR_MAJOR_VERSION < 2
2441         rv = apr_wait_for_io_or_timeout(NULL, sock, 0);
2442 #else
2443         rv = apr_socket_wait(sock, APR_WAIT_WRITE);
2444 #endif
2445
2446         if (rv != APR_SUCCESS) {
2447             return rv;
2448         }
2449     }
2450
2451     if (rv == -1 && errno != EISCONN) {
2452         return errno;
2453     }
2454
2455     return APR_SUCCESS;
2456 }
2457 #endif
2458
2459 PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
2460                                             proxy_conn_rec *conn,
2461                                             proxy_worker *worker,
2462                                             server_rec *s)
2463 {
2464     apr_status_t rv;
2465     int connected = 0;
2466     int loglevel;
2467     apr_sockaddr_t *backend_addr = conn->addr;
2468     /* the local address to use for the outgoing connection */
2469     apr_sockaddr_t *local_addr;
2470     apr_socket_t *newsock;
2471     void *sconf = s->module_config;
2472     proxy_server_conf *conf =
2473         (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
2474
2475     if (conn->sock) {
2476         if (!(connected = ap_proxy_is_socket_connected(conn->sock))) {
2477             socket_cleanup(conn);
2478             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00951)
2479                          "%s: backend socket is disconnected.",
2480                          proxy_function);
2481         }
2482     }
2483     while ((backend_addr || conn->uds_path) && !connected) {
2484 #if APR_HAVE_SYS_UN_H
2485         if (conn->uds_path)
2486         {
2487             struct sockaddr_un sa;
2488
2489             rv = apr_socket_create(&newsock, AF_UNIX, SOCK_STREAM, 0,
2490                                    conn->scpool);
2491             if (rv != APR_SUCCESS) {
2492                 loglevel = APLOG_ERR;
2493                 ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(02453)
2494                              "%s: error creating Unix domain socket for "
2495                              "target %s",
2496                              proxy_function,
2497                              worker->s->hostname);
2498                 break;
2499             }
2500             conn->connection = NULL;
2501
2502             sa.sun_family = AF_UNIX;
2503             apr_cpystrn(sa.sun_path, conn->uds_path, sizeof(sa.sun_path));
2504
2505             rv = socket_connect_un(newsock, &sa);
2506             if (rv != APR_SUCCESS) {
2507                 apr_socket_close(newsock);
2508                 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(02454)
2509                              "%s: attempt to connect to Unix domain socket "
2510                              "%s (%s) failed",
2511                              proxy_function,
2512                              conn->uds_path,
2513                              worker->s->hostname);
2514                 break;
2515             }
2516         }
2517         else
2518 #endif
2519         {
2520             if ((rv = apr_socket_create(&newsock, backend_addr->family,
2521                                         SOCK_STREAM, APR_PROTO_TCP,
2522                                         conn->scpool)) != APR_SUCCESS) {
2523                 loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
2524                 ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00952)
2525                              "%s: error creating fam %d socket for "
2526                              "target %s",
2527                              proxy_function,
2528                              backend_addr->family,
2529                              worker->s->hostname);
2530                 /*
2531                  * this could be an IPv6 address from the DNS but the
2532                  * local machine won't give us an IPv6 socket; hopefully the
2533                  * DNS returned an additional address to try
2534                  */
2535                 backend_addr = backend_addr->next;
2536                 continue;
2537             }
2538             conn->connection = NULL;
2539
2540             if (worker->s->recv_buffer_size > 0 &&
2541                 (rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF,
2542                                          worker->s->recv_buffer_size))) {
2543                 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00953)
2544                              "apr_socket_opt_set(SO_RCVBUF): Failed to set "
2545                              "ProxyReceiveBufferSize, using default");
2546             }
2547
2548             rv = apr_socket_opt_set(newsock, APR_TCP_NODELAY, 1);
2549             if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
2550                 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00954)
2551                              "apr_socket_opt_set(APR_TCP_NODELAY): "
2552                              "Failed to set");
2553             }
2554
2555             /* Set a timeout for connecting to the backend on the socket */
2556             if (worker->s->conn_timeout_set) {
2557                 apr_socket_timeout_set(newsock, worker->s->conn_timeout);
2558             }
2559             else if (worker->s->timeout_set) {
2560                 apr_socket_timeout_set(newsock, worker->s->timeout);
2561             }
2562             else if (conf->timeout_set) {
2563                 apr_socket_timeout_set(newsock, conf->timeout);
2564             }
2565             else {
2566                 apr_socket_timeout_set(newsock, s->timeout);
2567             }
2568             /* Set a keepalive option */
2569             if (worker->s->keepalive) {
2570                 if ((rv = apr_socket_opt_set(newsock,
2571                                              APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) {
2572                     ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00955)
2573                                  "apr_socket_opt_set(SO_KEEPALIVE): Failed to set"
2574                                  " Keepalive");
2575                 }
2576             }
2577             ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s,
2578                          "%s: fam %d socket created to connect to %s",
2579                          proxy_function, backend_addr->family, worker->s->hostname);
2580
2581             if (conf->source_address_set) {
2582                 local_addr = apr_pmemdup(conn->pool, conf->source_address,
2583                                          sizeof(apr_sockaddr_t));
2584                 local_addr->pool = conn->pool;
2585                 rv = apr_socket_bind(newsock, local_addr);
2586                 if (rv != APR_SUCCESS) {
2587                     ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00956)
2588                                  "%s: failed to bind socket to local address",
2589                                  proxy_function);
2590                 }
2591             }
2592
2593             /* make the connection out of the socket */
2594             rv = apr_socket_connect(newsock, backend_addr);
2595
2596             /* if an error occurred, loop round and try again */
2597             if (rv != APR_SUCCESS) {
2598                 apr_socket_close(newsock);
2599                 loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
2600                 ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00957)
2601                              "%s: attempt to connect to %pI (%s) failed",
2602                              proxy_function,
2603                              backend_addr,
2604                              worker->s->hostname);
2605                 backend_addr = backend_addr->next;
2606                 continue;
2607             }
2608         }
2609
2610         /* Set a timeout on the socket */
2611         if (worker->s->timeout_set) {
2612             apr_socket_timeout_set(newsock, worker->s->timeout);
2613         }
2614         else if (conf->timeout_set) {
2615             apr_socket_timeout_set(newsock, conf->timeout);
2616         }
2617         else {
2618              apr_socket_timeout_set(newsock, s->timeout);
2619         }
2620
2621         conn->sock = newsock;
2622
2623         if (!conn->uds_path && conn->forward) {
2624             forward_info *forward = (forward_info *)conn->forward;
2625             /*
2626              * For HTTP CONNECT we need to prepend CONNECT request before
2627              * sending our actual HTTPS requests.
2628              */
2629             if (forward->use_http_connect) {
2630                 rv = send_http_connect(conn, s);
2631                 /* If an error occurred, loop round and try again */
2632                 if (rv != APR_SUCCESS) {
2633                     conn->sock = NULL;
2634                     apr_socket_close(newsock);
2635                     loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
2636                     ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00958)
2637                                  "%s: attempt to connect to %s:%d "
2638                                  "via http CONNECT through %pI (%s) failed",
2639                                  proxy_function,
2640                                  forward->target_host, forward->target_port,
2641                                  backend_addr, worker->s->hostname);
2642                     backend_addr = backend_addr->next;
2643                     continue;
2644                 }
2645             }
2646         }
2647
2648         connected    = 1;
2649     }
2650     /*
2651      * Put the entire worker to error state if
2652      * the PROXY_WORKER_IGNORE_ERRORS flag is not set.
2653      * Altrough some connections may be alive
2654      * no further connections to the worker could be made
2655      */
2656     if (!connected && PROXY_WORKER_IS_USABLE(worker) &&
2657         !(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) {
2658         worker->s->error_time = apr_time_now();
2659         worker->s->status |= PROXY_WORKER_IN_ERROR;
2660         ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00959)
2661             "ap_proxy_connect_backend disabling worker for (%s) for %"
2662             APR_TIME_T_FMT "s",
2663             worker->s->hostname, apr_time_sec(worker->s->retry));
2664     }
2665     else {
2666         if (worker->s->retries) {
2667             /*
2668              * A worker came back. So here is where we need to
2669              * either reset all params to initial conditions or
2670              * apply some sort of aging
2671              */
2672         }
2673         worker->s->error_time = 0;
2674         worker->s->retries = 0;
2675     }
2676     return connected ? OK : DECLINED;
2677 }
2678
2679 PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function,
2680                                               proxy_conn_rec *conn,
2681                                               conn_rec *c,
2682                                               server_rec *s)
2683 {
2684     apr_sockaddr_t *backend_addr = conn->addr;
2685     int rc;
2686     apr_interval_time_t current_timeout;
2687     apr_bucket_alloc_t *bucket_alloc;
2688
2689     if (conn->connection) {
2690         return OK;
2691     }
2692
2693     bucket_alloc = apr_bucket_alloc_create(conn->scpool);
2694     /*
2695      * The socket is now open, create a new backend server connection
2696      */
2697     conn->connection = ap_run_create_connection(conn->scpool, s, conn->sock,
2698                                                 0, NULL,
2699                                                 bucket_alloc);
2700
2701     if (!conn->connection) {
2702         /*
2703          * the peer reset the connection already; ap_run_create_connection()
2704          * closed the socket
2705          */
2706         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
2707                      s, APLOGNO(00960) "%s: an error occurred creating a "
2708                      "new connection to %pI (%s)", proxy_function,
2709                      backend_addr, conn->hostname);
2710         /* XXX: Will be closed when proxy_conn is closed */
2711         socket_cleanup(conn);
2712         return HTTP_INTERNAL_SERVER_ERROR;
2713     }
2714
2715     /* For ssl connection to backend */
2716     if (conn->is_ssl) {
2717         if (!ap_proxy_ssl_enable(conn->connection)) {
2718             ap_log_error(APLOG_MARK, APLOG_ERR, 0,
2719                          s, APLOGNO(00961) "%s: failed to enable ssl support "
2720                          "for %pI (%s)", proxy_function,
2721                          backend_addr, conn->hostname);
2722             return HTTP_INTERNAL_SERVER_ERROR;
2723         }
2724     }
2725     else {
2726         /* TODO: See if this will break FTP */
2727         ap_proxy_ssl_disable(conn->connection);
2728     }
2729
2730     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00962)
2731                  "%s: connection complete to %pI (%s)",
2732                  proxy_function, backend_addr, conn->hostname);
2733
2734     /*
2735      * save the timeout of the socket because core_pre_connection
2736      * will set it to base_server->timeout
2737      * (core TimeOut directive).
2738      */
2739     apr_socket_timeout_get(conn->sock, &current_timeout);
2740     /* set up the connection filters */
2741     rc = ap_run_pre_connection(conn->connection, conn->sock);
2742     if (rc != OK && rc != DONE) {
2743         conn->connection->aborted = 1;
2744         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00963)
2745                      "%s: pre_connection setup failed (%d)",
2746                      proxy_function, rc);
2747         return rc;
2748     }
2749     apr_socket_timeout_set(conn->sock, current_timeout);
2750
2751     return OK;
2752 }
2753
2754 int ap_proxy_lb_workers(void)
2755 {
2756     /*
2757      * Since we can't resize the scoreboard when reconfiguring, we
2758      * have to impose a limit on the number of workers, we are
2759      * able to reconfigure to.
2760      */
2761     if (!lb_workers_limit)
2762         lb_workers_limit = proxy_lb_workers + PROXY_DYNAMIC_BALANCER_LIMIT;
2763     return lb_workers_limit;
2764 }
2765
2766 /* deprecated - to be removed in v2.6 */
2767 PROXY_DECLARE(void) ap_proxy_backend_broke(request_rec *r,
2768                                            apr_bucket_brigade *brigade)
2769 {
2770     apr_bucket *e;
2771     conn_rec *c = r->connection;
2772
2773     r->no_cache = 1;
2774     /*
2775      * If this is a subrequest, then prevent also caching of the main
2776      * request.
2777      */
2778     if (r->main)
2779         r->main->no_cache = 1;
2780     e = ap_bucket_error_create(HTTP_GATEWAY_TIME_OUT, NULL, c->pool,
2781                                c->bucket_alloc);
2782     APR_BRIGADE_INSERT_TAIL(brigade, e);
2783     e = apr_bucket_eos_create(c->bucket_alloc);
2784     APR_BRIGADE_INSERT_TAIL(brigade, e);
2785 }
2786
2787 /*
2788  * Provide a string hashing function for the proxy.
2789  * We offer 2 methods: one is the APR model but we
2790  * also provide our own, based on either FNV or SDBM.
2791  * The reason is in case we want to use both to ensure no
2792  * collisions.
2793  */
2794 PROXY_DECLARE(unsigned int)
2795 ap_proxy_hashfunc(const char *str, proxy_hash_t method)
2796 {
2797     if (method == PROXY_HASHFUNC_APR) {
2798         apr_ssize_t slen = strlen(str);
2799         return apr_hashfunc_default(str, &slen);
2800     }
2801     else if (method == PROXY_HASHFUNC_FNV) {
2802         /* FNV model */
2803         unsigned int hash;
2804         const unsigned int fnv_prime = 0x811C9DC5;
2805         for (hash = 0; *str; str++) {
2806             hash *= fnv_prime;
2807             hash ^= (*str);
2808         }
2809         return hash;
2810     }
2811     else { /* method == PROXY_HASHFUNC_DEFAULT */
2812         /* SDBM model */
2813         unsigned int hash;
2814         for (hash = 0; *str; str++) {
2815             hash = (*str) + (hash << 6) + (hash << 16) - hash;
2816         }
2817         return hash;
2818     }
2819 }
2820
2821 PROXY_DECLARE(apr_status_t) ap_proxy_set_wstatus(char c, int set, proxy_worker *w)
2822 {
2823     unsigned int *status = &w->s->status;
2824     char flag = toupper(c);
2825     struct wstat *pwt = wstat_tbl;
2826     while (pwt->bit) {
2827         if (flag == pwt->flag) {
2828             if (set)
2829                 *status |= pwt->bit;
2830             else
2831                 *status &= ~(pwt->bit);
2832             return APR_SUCCESS;
2833         }
2834         pwt++;
2835     }
2836     return APR_EINVAL;
2837 }
2838
2839 PROXY_DECLARE(char *) ap_proxy_parse_wstatus(apr_pool_t *p, proxy_worker *w)
2840 {
2841     char *ret = "";
2842     unsigned int status = w->s->status;
2843     struct wstat *pwt = wstat_tbl;
2844     while (pwt->bit) {
2845         if (status & pwt->bit)
2846             ret = apr_pstrcat(p, ret, pwt->name, NULL);
2847         pwt++;
2848     }
2849     if (PROXY_WORKER_IS_USABLE(w))
2850         ret = apr_pstrcat(p, ret, "Ok ", NULL);
2851     return ret;
2852 }
2853
2854 PROXY_DECLARE(apr_status_t) ap_proxy_sync_balancer(proxy_balancer *b, server_rec *s,
2855                                                     proxy_server_conf *conf)
2856 {
2857     proxy_worker **workers;
2858     int i;
2859     int index;
2860     proxy_worker_shared *shm;
2861     proxy_balancer_method *lbmethod;
2862     ap_slotmem_provider_t *storage = b->storage;
2863
2864     if (b->s->wupdated <= b->wupdated)
2865         return APR_SUCCESS;
2866     /* balancer sync */
2867     lbmethod = ap_lookup_provider(PROXY_LBMETHOD, b->s->lbpname, "0");
2868     if (lbmethod) {
2869         b->lbmethod = lbmethod;
2870     } else {
2871         ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, APLOGNO(02433)
2872                      "Cannot find LB Method: %s", b->s->lbpname);
2873         return APR_EINVAL;
2874     }
2875
2876     /* worker sync */
2877
2878     /*
2879      * Look thru the list of workers in shm
2880      * and see which one(s) we are lacking...
2881      * again, the cast to unsigned int is safe
2882      * since our upper limit is always max_workers
2883      * which is int.
2884      */
2885     for (index = 0; index < b->max_workers; index++) {
2886         int found;
2887         apr_status_t rv;
2888         if ((rv = storage->dptr(b->wslot, (unsigned int)index, (void *)&shm)) != APR_SUCCESS) {
2889             ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(00965) "worker slotmem_dptr failed");
2890             return APR_EGENERAL;
2891         }
2892         /* account for possible "holes" in the slotmem
2893          * (eg: slots 0-2 are used, but 3 isn't, but 4-5 is)
2894          */
2895         if (!shm->hash.def || !shm->hash.fnv)
2896             continue;
2897         found = 0;
2898         workers = (proxy_worker **)b->workers->elts;
2899         for (i = 0; i < b->workers->nelts; i++, workers++) {
2900             proxy_worker *worker = *workers;
2901             if (worker->hash.def == shm->hash.def && worker->hash.fnv == shm->hash.fnv) {
2902                 found = 1;
2903                 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02402)
2904                              "re-grabbing shm[%d] (0x%pp) for worker: %s", i, (void *)shm,
2905                              worker->s->name);
2906                 break;
2907             }
2908         }
2909         if (!found) {
2910             proxy_worker **runtime;
2911             apr_global_mutex_lock(proxy_mutex);
2912             runtime = apr_array_push(b->workers);
2913             *runtime = apr_palloc(conf->pool, sizeof(proxy_worker));
2914             apr_global_mutex_unlock(proxy_mutex);
2915             (*runtime)->hash = shm->hash;
2916             (*runtime)->context = NULL;
2917             (*runtime)->cp = NULL;
2918             (*runtime)->balancer = b;
2919             (*runtime)->s = shm;
2920             (*runtime)->tmutex = NULL;
2921             rv = ap_proxy_initialize_worker(*runtime, s, conf->pool);
2922             if (rv != APR_SUCCESS) {
2923                 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(00966) "Cannot init worker");
2924                 return rv;
2925             }
2926             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02403)
2927                          "grabbing shm[%d] (0x%pp) for worker: %s", i, (void *)shm,
2928                          (*runtime)->s->name);
2929         }
2930     }
2931     if (b->s->need_reset) {
2932         if (b->lbmethod && b->lbmethod->reset)
2933             b->lbmethod->reset(b, s);
2934         b->s->need_reset = 0;
2935     }
2936     b->wupdated = b->s->wupdated;
2937     return APR_SUCCESS;
2938 }
2939
2940 PROXY_DECLARE(proxy_worker_shared *) ap_proxy_find_workershm(ap_slotmem_provider_t *storage,
2941                                                                ap_slotmem_instance_t *slot,
2942                                                                proxy_worker *worker,
2943                                                                unsigned int *index)
2944 {
2945     proxy_worker_shared *shm;
2946     unsigned int i, limit;
2947     limit = storage->num_slots(slot);
2948     for (i = 0; i < limit; i++) {
2949         if (storage->dptr(slot, i, (void *)&shm) != APR_SUCCESS) {
2950             return NULL;
2951         }
2952         if ((worker->s->hash.def == shm->hash.def) &&
2953             (worker->s->hash.fnv == shm->hash.fnv)) {
2954             *index = i;
2955             return shm;
2956         }
2957     }
2958     return NULL;
2959 }
2960
2961 PROXY_DECLARE(proxy_balancer_shared *) ap_proxy_find_balancershm(ap_slotmem_provider_t *storage,
2962                                                                  ap_slotmem_instance_t *slot,
2963                                                                  proxy_balancer *balancer,
2964                                                                  unsigned int *index)
2965 {
2966     proxy_balancer_shared *shm;
2967     unsigned int i, limit;
2968     limit = storage->num_slots(slot);
2969     for (i = 0; i < limit; i++) {
2970         if (storage->dptr(slot, i, (void *)&shm) != APR_SUCCESS) {
2971             return NULL;
2972         }
2973         if ((balancer->s->hash.def == shm->hash.def) &&
2974             (balancer->s->hash.fnv == shm->hash.fnv)) {
2975             *index = i;
2976             return shm;
2977         }
2978     }
2979     return NULL;
2980 }
2981
2982 typedef struct header_connection {
2983     apr_pool_t *pool;
2984     apr_array_header_t *array;
2985     const char *first;
2986     unsigned int closed:1;
2987 } header_connection;
2988
2989 static int find_conn_headers(void *data, const char *key, const char *val)
2990 {
2991     header_connection *x = data;
2992     const char *name;
2993
2994     do {
2995         while (*val == ',') {
2996             val++;
2997         }
2998         name = ap_get_token(x->pool, &val, 0);
2999         if (!strcasecmp(name, "close")) {
3000             x->closed = 1;
3001         }
3002         if (!x->first) {
3003             x->first = name;
3004         }
3005         else {
3006             const char **elt;
3007             if (!x->array) {
3008                 x->array = apr_array_make(x->pool, 4, sizeof(char *));
3009             }
3010             elt = apr_array_push(x->array);
3011             *elt = name;
3012         }
3013     } while (*val);
3014
3015     return 1;
3016 }
3017
3018 /**
3019  * Remove all headers referred to by the Connection header.
3020  */
3021 static int ap_proxy_clear_connection(request_rec *r, apr_table_t *headers)
3022 {
3023     const char **name;
3024     header_connection x;
3025
3026     x.pool = r->pool;
3027     x.array = NULL;
3028     x.first = NULL;
3029     x.closed = 0;
3030
3031     apr_table_unset(headers, "Proxy-Connection");
3032
3033     apr_table_do(find_conn_headers, &x, headers, "Connection", NULL);
3034     if (x.first) {
3035         /* fast path - no memory allocated for one header */
3036         apr_table_unset(headers, "Connection");
3037         apr_table_unset(headers, x.first);
3038     }
3039     if (x.array) {
3040         /* two or more headers */
3041         while ((name = apr_array_pop(x.array))) {
3042             apr_table_unset(headers, *name);
3043         }
3044     }
3045
3046     return x.closed;
3047 }
3048
3049 PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
3050                                             apr_bucket_brigade *header_brigade,
3051                                             request_rec *r,
3052                                             proxy_conn_rec *p_conn,
3053                                             proxy_worker *worker,
3054                                             proxy_server_conf *conf,
3055                                             apr_uri_t *uri,
3056                                             char *url, char *server_portstr,
3057                                             char **old_cl_val,
3058                                             char **old_te_val)
3059 {
3060     conn_rec *c = r->connection;
3061     int counter;
3062     char *buf;
3063     const apr_array_header_t *headers_in_array;
3064     const apr_table_entry_t *headers_in;
3065     apr_table_t *headers_in_copy;
3066     apr_bucket *e;
3067     int do_100_continue;
3068     conn_rec *origin = p_conn->connection;
3069     proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
3070
3071     /*
3072      * HTTP "Ping" test? Easiest is 100-Continue. However:
3073      * To be compliant, we only use 100-Continue for requests with bodies.
3074      * We also make sure we won't be talking HTTP/1.0 as well.
3075      */
3076     do_100_continue = (worker->s->ping_timeout_set
3077                        && (worker->s->ping_timeout >= 0)
3078                        && (PROXYREQ_REVERSE == r->proxyreq)
3079                        && !(apr_table_get(r->subprocess_env, "force-proxy-request-1.0"))
3080                        && ap_request_has_body(r));
3081
3082     if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) {
3083         /*
3084          * According to RFC 2616 8.2.3 we are not allowed to forward an
3085          * Expect: 100-continue to an HTTP/1.0 server. Instead we MUST return
3086          * a HTTP_EXPECTATION_FAILED
3087          */
3088         if (r->expecting_100) {
3089             return HTTP_EXPECTATION_FAILED;
3090         }
3091         buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.0" CRLF, NULL);
3092         p_conn->close = 1;
3093     } else {
3094         buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL);
3095     }
3096     if (apr_table_get(r->subprocess_env, "proxy-nokeepalive")) {
3097         origin->keepalive = AP_CONN_CLOSE;
3098         p_conn->close = 1;
3099     }
3100     ap_xlate_proto_to_ascii(buf, strlen(buf));
3101     e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
3102     APR_BRIGADE_INSERT_TAIL(header_brigade, e);
3103     if (dconf->preserve_host == 0) {
3104         if (ap_strchr_c(uri->hostname, ':')) { /* if literal IPv6 address */
3105             if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
3106                 buf = apr_pstrcat(p, "Host: [", uri->hostname, "]:",
3107                                   uri->port_str, CRLF, NULL);
3108             } else {
3109                 buf = apr_pstrcat(p, "Host: [", uri->hostname, "]", CRLF, NULL);
3110             }
3111         } else {
3112             if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
3113                 buf = apr_pstrcat(p, "Host: ", uri->hostname, ":",
3114                                   uri->port_str, CRLF, NULL);
3115             } else {
3116                 buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL);
3117             }
3118         }
3119     }
3120     else {
3121         /* don't want to use r->hostname, as the incoming header might have a
3122          * port attached
3123          */
3124         const char* hostname = apr_table_get(r->headers_in,"Host");
3125         if (!hostname) {
3126             hostname =  r->server->server_hostname;
3127             ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01092)
3128                           "no HTTP 0.9 request (with no host line) "
3129                           "on incoming request and preserve host set "
3130                           "forcing hostname to be %s for uri %s",
3131                           hostname, r->uri);
3132         }
3133         buf = apr_pstrcat(p, "Host: ", hostname, CRLF, NULL);
3134     }
3135     ap_xlate_proto_to_ascii(buf, strlen(buf));
3136     e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
3137     APR_BRIGADE_INSERT_TAIL(header_brigade, e);
3138
3139     /* handle Via */
3140     if (conf->viaopt == via_block) {
3141         /* Block all outgoing Via: headers */
3142         apr_table_unset(r->headers_in, "Via");
3143     } else if (conf->viaopt != via_off) {
3144         const char *server_name = ap_get_server_name(r);
3145         /* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host,
3146          * then the server name returned by ap_get_server_name() is the
3147          * origin server name (which does make too much sense with Via: headers)
3148          * so we use the proxy vhost's name instead.
3149          */
3150         if (server_name == r->hostname)
3151             server_name = r->server->server_hostname;
3152         /* Create a "Via:" request header entry and merge it */
3153         /* Generate outgoing Via: header with/without server comment: */
3154         apr_table_mergen(r->headers_in, "Via",
3155                          (conf->viaopt == via_full)
3156                          ? apr_psprintf(p, "%d.%d %s%s (%s)",
3157                                         HTTP_VERSION_MAJOR(r->proto_num),
3158                                         HTTP_VERSION_MINOR(r->proto_num),
3159                                         server_name, server_portstr,
3160                                         AP_SERVER_BASEVERSION)
3161                          : apr_psprintf(p, "%d.%d %s%s",
3162                                         HTTP_VERSION_MAJOR(r->proto_num),
3163                                         HTTP_VERSION_MINOR(r->proto_num),
3164                                         server_name, server_portstr)
3165                          );
3166     }
3167
3168     /* Use HTTP/1.1 100-Continue as quick "HTTP ping" test
3169      * to backend
3170      */
3171     if (do_100_continue) {
3172         apr_table_mergen(r->headers_in, "Expect", "100-Continue");
3173         r->expecting_100 = 1;
3174     }
3175
3176     /* X-Forwarded-*: handling
3177      *
3178      * XXX Privacy Note:
3179      * -----------------
3180      *
3181      * These request headers are only really useful when the mod_proxy
3182      * is used in a reverse proxy configuration, so that useful info
3183      * about the client can be passed through the reverse proxy and on
3184      * to the backend server, which may require the information to
3185      * function properly.
3186      *
3187      * In a forward proxy situation, these options are a potential
3188      * privacy violation, as information about clients behind the proxy
3189      * are revealed to arbitrary servers out there on the internet.
3190      *
3191      * The HTTP/1.1 Via: header is designed for passing client
3192      * information through proxies to a server, and should be used in
3193      * a forward proxy configuation instead of X-Forwarded-*. See the
3194      * ProxyVia option for details.
3195      */
3196     if (dconf->add_forwarded_headers) {
3197         if (PROXYREQ_REVERSE == r->proxyreq) {
3198             const char *buf;
3199
3200             /* Add X-Forwarded-For: so that the upstream has a chance to
3201              * determine, where the original request came from.
3202              */
3203             apr_table_mergen(r->headers_in, "X-Forwarded-For",
3204                              r->useragent_ip);
3205
3206             /* Add X-Forwarded-Host: so that upstream knows what the
3207              * original request hostname was.
3208              */
3209             if ((buf = apr_table_get(r->headers_in, "Host"))) {
3210                 apr_table_mergen(r->headers_in, "X-Forwarded-Host", buf);
3211             }
3212
3213             /* Add X-Forwarded-Server: so that upstream knows what the
3214              * name of this proxy server is (if there are more than one)
3215              * XXX: This duplicates Via: - do we strictly need it?
3216              */
3217             apr_table_mergen(r->headers_in, "X-Forwarded-Server",
3218                              r->server->server_hostname);
3219         }
3220     }
3221
3222     proxy_run_fixups(r);
3223     /*
3224      * Make a copy of the headers_in table before clearing the connection
3225      * headers as we need the connection headers later in the http output
3226      * filter to prepare the correct response headers.
3227      *
3228      * Note: We need to take r->pool for apr_table_copy as the key / value
3229      * pairs in r->headers_in have been created out of r->pool and
3230      * p might be (and actually is) a longer living pool.
3231      * This would trigger the bad pool ancestry abort in apr_table_copy if
3232      * apr is compiled with APR_POOL_DEBUG.
3233      */
3234     headers_in_copy = apr_table_copy(r->pool, r->headers_in);
3235     ap_proxy_clear_connection(r, headers_in_copy);
3236     /* send request headers */
3237     headers_in_array = apr_table_elts(headers_in_copy);
3238     headers_in = (const apr_table_entry_t *) headers_in_array->elts;
3239     for (counter = 0; counter < headers_in_array->nelts; counter++) {
3240         if (headers_in[counter].key == NULL
3241             || headers_in[counter].val == NULL
3242
3243             /* Already sent */
3244             || !strcasecmp(headers_in[counter].key, "Host")
3245
3246             /* Clear out hop-by-hop request headers not to send
3247              * RFC2616 13.5.1 says we should strip these headers
3248              */
3249             || !strcasecmp(headers_in[counter].key, "Keep-Alive")
3250             || !strcasecmp(headers_in[counter].key, "TE")
3251             || !strcasecmp(headers_in[counter].key, "Trailer")
3252             || !strcasecmp(headers_in[counter].key, "Upgrade")
3253
3254             ) {
3255             continue;
3256         }
3257         /* Do we want to strip Proxy-Authorization ?
3258          * If we haven't used it, then NO
3259          * If we have used it then MAYBE: RFC2616 says we MAY propagate it.
3260          * So let's make it configurable by env.
3261          */
3262         if (!strcasecmp(headers_in[counter].key,"Proxy-Authorization")) {
3263             if (r->user != NULL) { /* we've authenticated */
3264                 if (!apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) {
3265                     continue;
3266                 }
3267             }
3268         }
3269
3270         /* Skip Transfer-Encoding and Content-Length for now.
3271          */
3272         if (!strcasecmp(headers_in[counter].key, "Transfer-Encoding")) {
3273             *old_te_val = headers_in[counter].val;
3274             continue;
3275         }
3276         if (!strcasecmp(headers_in[counter].key, "Content-Length")) {
3277             *old_cl_val = headers_in[counter].val;
3278             continue;
3279         }
3280
3281         /* for sub-requests, ignore freshness/expiry headers */
3282         if (r->main) {
3283             if (    !strcasecmp(headers_in[counter].key, "If-Match")
3284                 || !strcasecmp(headers_in[counter].key, "If-Modified-Since")
3285                 || !strcasecmp(headers_in[counter].key, "If-Range")
3286                 || !strcasecmp(headers_in[counter].key, "If-Unmodified-Since")
3287                 || !strcasecmp(headers_in[counter].key, "If-None-Match")) {
3288                 continue;
3289             }
3290         }
3291
3292         buf = apr_pstrcat(p, headers_in[counter].key, ": ",
3293                           headers_in[counter].val, CRLF,
3294                           NULL);
3295         ap_xlate_proto_to_ascii(buf, strlen(buf));
3296         e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
3297         APR_BRIGADE_INSERT_TAIL(header_brigade, e);
3298     }
3299     return OK;
3300 }
3301
3302 PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc,
3303                                          request_rec *r, proxy_conn_rec *p_conn,
3304                                          conn_rec *origin, apr_bucket_brigade *bb,
3305                                          int flush)
3306 {
3307     apr_status_t status;
3308     apr_off_t transferred;
3309
3310     if (flush) {
3311         apr_bucket *e = apr_bucket_flush_create(bucket_alloc);
3312         APR_BRIGADE_INSERT_TAIL(bb, e);
3313     }
3314     apr_brigade_length(bb, 0, &transferred);
3315     if (transferred != -1)
3316         p_conn->worker->s->transferred += transferred;
3317     status = ap_pass_brigade(origin->output_filters, bb);
3318     if (status != APR_SUCCESS) {
3319         ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01084)
3320                       "pass request body failed to %pI (%s)",
3321                       p_conn->addr, p_conn->hostname);
3322         if (origin->aborted) {
3323             const char *ssl_note;
3324
3325             if (((ssl_note = apr_table_get(origin->notes, "SSL_connect_rv"))
3326                  != NULL) && (strcmp(ssl_note, "err") == 0)) {
3327                 return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR,
3328                                      "Error during SSL Handshake with"
3329                                      " remote server");
3330             }
3331             return HTTP_GATEWAY_TIME_OUT;
3332         }
3333         else {
3334             return HTTP_BAD_REQUEST;
3335         }
3336     }
3337     apr_brigade_cleanup(bb);
3338     return OK;
3339 }
3340
3341 void proxy_util_register_hooks(apr_pool_t *p)
3342 {
3343     APR_REGISTER_OPTIONAL_FN(ap_proxy_retry_worker);
3344     APR_REGISTER_OPTIONAL_FN(ap_proxy_clear_connection);
3345 }