1 /* $MirOS: src/usr.sbin/httpd/src/modules/proxy/proxy_util.c,v 1.8 2014/03/29 00:28:13 tg Exp $ */
2 
3 /* ====================================================================
4  * The Apache Software License, Version 1.1
5  *
6  * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
7  * reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  *
21  * 3. The end-user documentation included with the redistribution,
22  *    if any, must include the following acknowledgment:
23  *       "This product includes software developed by the
24  *        Apache Software Foundation (http://www.apache.org/)."
25  *    Alternately, this acknowledgment may appear in the software itself,
26  *    if and wherever such third-party acknowledgments normally appear.
27  *
28  * 4. The names "Apache" and "Apache Software Foundation" must
29  *    not be used to endorse or promote products derived from this
30  *    software without prior written permission. For written
31  *    permission, please contact apache@apache.org.
32  *
33  * 5. Products derived from this software may not be called "Apache",
34  *    nor may "Apache" appear in their name, without prior written
35  *    permission of the Apache Software Foundation.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals on behalf of the Apache Software Foundation.  For more
53  * information on the Apache Software Foundation, please see
54  * <http://www.apache.org/>.
55  *
56  * Portions of this software are based upon public domain software
57  * originally written at the National Center for Supercomputing Applications,
58  * University of Illinois, Urbana-Champaign.
59  */
60 
61 /* Utility routines for Apache proxy */
62 #include "mod_proxy.h"
63 #include "http_main.h"
64 #include "ap_md5.h"
65 #include "multithread.h"
66 #include "http_log.h"
67 #include "util_uri.h"
68 #include "util_date.h"          /* get ap_checkmask() decl. */
69 #include "sa_len.h"
70 
71 __RCSID("$MirOS: src/usr.sbin/httpd/src/modules/proxy/proxy_util.c,v 1.8 2014/03/29 00:28:13 tg Exp $");
72 
73 static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r);
74 static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r);
75 static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r);
76 static int proxy_match_word(struct dirconn_entry *This, request_rec *r);
77 static struct per_thread_data *get_per_thread_data(void);
78 /* already called in the knowledge that the characters are hex digits */
ap_proxy_hex2c(const char * x)79 int ap_proxy_hex2c(const char *x)
80 {
81     int i;
82     int ch;
83 
84     ch = x[0];
85     if (isdigit((unsigned char)ch))
86         i = ch - '0';
87     else if (ap_isupper(ch))
88         i = ch - ('A' - 10);
89     else
90         i = ch - ('a' - 10);
91     i <<= 4;
92 
93     ch = x[1];
94     if (isdigit((unsigned char)ch))
95         i += ch - '0';
96     else if (ap_isupper(ch))
97         i += ch - ('A' - 10);
98     else
99         i += ch - ('a' - 10);
100     return i;
101 }
102 
ap_proxy_c2hex(int ch,char * x)103 void ap_proxy_c2hex(int ch, char *x)
104 {
105     int i;
106 
107     x[0] = '%';
108     i = (ch & 0xF0) >> 4;
109     if (i >= 10)
110         x[1] = ('A' - 10) + i;
111     else
112         x[1] = '0' + i;
113 
114     i = ch & 0x0F;
115     if (i >= 10)
116         x[2] = ('A' - 10) + i;
117     else
118         x[2] = '0' + i;
119 }
120 
121 /*
122  * canonicalise a URL-encoded string
123  */
124 
125 /*
126  * Convert a URL-encoded string to canonical form.
127  * It decodes characters which need not be encoded,
128  * and encodes those which must be encoded, and does not touch
129  * those which must not be touched.
130  */
ap_proxy_canonenc(pool * p,const char * x,int len,enum enctype t,enum proxyreqtype isenc)131 char *ap_proxy_canonenc(pool *p, const char *x, int len, enum enctype t,
132                              enum proxyreqtype isenc)
133 {
134     int i, j, ch;
135     char *y;
136     const char *allowed;        /* characters which should not be encoded */
137     const char *reserved;       /* characters which much not be en/de-coded */
138 
139 /* N.B. in addition to :@&=, this allows ';' in an http path
140  * and '?' in an ftp path -- this may be revised
141  *
142  * Also, it makes a '+' character in a search string reserved, as
143  * it may be form-encoded. (Although RFC 1738 doesn't allow this -
144  * it only permits ; / ? : @ = & as reserved chars.)
145  */
146     if (t == enc_path)
147         allowed = "$-_.+!*'(),;:@&=";
148     else if (t == enc_search)
149         allowed = "$-_.!*'(),;:@&=";
150     else if (t == enc_user)
151         allowed = "$-_.+!*'(),;@&=";
152     else if (t == enc_fpath)
153         allowed = "$-_.+!*'(),?:@&=";
154     else                        /* if (t == enc_parm) */
155         allowed = "$-_.+!*'(),?/:@&=";
156 
157     if (t == enc_path)
158         reserved = "/";
159     else if (t == enc_search)
160         reserved = "+";
161     else
162         reserved = "";
163 
164     y = ap_palloc(p, 3 * len + 1);
165 
166     for (i = 0, j = 0; i < len; i++, j++) {
167 /* always handle '/' first */
168         ch = x[i];
169         if (strchr(reserved, ch)) {
170             y[j] = ch;
171             continue;
172         }
173 /* decode it if not already done */
174         if (isenc != NOT_PROXY && ch == '%') {
175             if (!ap_isxdigit(x[i + 1]) || !ap_isxdigit(x[i + 2]))
176                 return NULL;
177             ch = ap_proxy_hex2c(&x[i + 1]);
178             i += 2;
179             if (ch != 0 && strchr(reserved, ch)) {      /* keep it encoded */
180                 ap_proxy_c2hex(ch, &y[j]);
181                 j += 2;
182                 continue;
183             }
184         }
185 /* recode it, if necessary */
186         if (!ap_isalnum(ch) && !strchr(allowed, ch)) {
187             ap_proxy_c2hex(ch, &y[j]);
188             j += 2;
189         }
190         else
191             y[j] = ch;
192     }
193     y[j] = '\0';
194     return y;
195 }
196 
197 /*
198  * Parses network-location.
199  *    urlp           on input the URL; on output the path, after the leading /
200  *    user           NULL if no user/password permitted
201  *    password       holder for password
202  *    host           holder for host
203  *    port           port number; only set if one is supplied.
204  *
205  * Returns an error string.
206  */
207 char *
ap_proxy_canon_netloc(pool * p,char ** const urlp,char ** userp,char ** passwordp,char ** hostp,int * port)208      ap_proxy_canon_netloc(pool *p, char **const urlp, char **userp,
209                                 char **passwordp, char **hostp, int *port)
210 {
211     int i;
212     char *strp, *host, *url = *urlp;
213     char *user = NULL, *password = NULL;
214     char *t = NULL, *u = NULL, *v = NULL;
215 
216     if (url[0] != '/' || url[1] != '/')
217         return "Malformed URL";
218     host = url + 2;
219     url = strchr(host, '/');
220     if (url == NULL)
221         url = "";
222     else
223         *(url++) = '\0';        /* skip seperating '/' */
224 
225     /* find _last_ '@' since it might occur in user/password part */
226     strp = strrchr(host, '@');
227 
228     if (strp != NULL) {
229         *strp = '\0';
230         user = host;
231         host = strp + 1;
232 
233 /* find password */
234         strp = strchr(user, ':');
235         if (strp != NULL) {
236             *strp = '\0';
237             password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, STD_PROXY);
238             if (password == NULL)
239                 return "Bad %-escape in URL (password)";
240         }
241 
242         user = ap_proxy_canonenc(p, user, strlen(user), enc_user, STD_PROXY);
243         if (user == NULL)
244             return "Bad %-escape in URL (username)";
245     }
246     if (userp != NULL) {
247         *userp = user;
248     }
249     if (passwordp != NULL) {
250         *passwordp = password;
251     }
252 
253     v = host;
254     if (*host == '['){
255 	u = strrchr(host, ']');
256 	if (u){
257 	    host++;
258 	    *u = '\0';
259 	    v = u + 1;
260 	}
261     }
262     t = strrchr(v, ':');
263     if (t){
264 	*t = '\0';
265 	strp = t + 1;
266     }
267     if (strp){
268 	for (i=0; strp[i] != '\0'; i++)
269 	    if (!ap_isdigit(strp[i]))
270 		break;
271 
272 	/* if (i == 0) the no port was given; keep default */
273 	if (strp[i] != '\0') {
274 	    return "Bad port number in URL";
275 	}
276         else if (i > 0) {
277 	    *port = atoi(strp);
278 	    if (*port > 65535)
279 		return "Port number in URL > 65535";
280 	}
281     }
282     ap_str_tolower(host);       /* DNS names are case-insensitive */
283     if (*host == '\0')
284         return "Missing host in URL";
285 /* check hostname syntax */
286     for (i = 0; host[i] != '\0'; i++)
287 	if (!ap_isxdigit(host[i]) && host[i] != '.' && host[i] != ':')
288 	    break;
289     /* must be an IP address */
290     if (host[i] == '\0') {
291 	struct addrinfo hints, *res0;
292 	int gai;
293 	memset(&hints, 0, sizeof(hints));
294 	hints.ai_family = PF_UNSPEC;
295 	hints.ai_flags = AI_NUMERICHOST;
296 	if ((gai = getaddrinfo(host, NULL, &hints, &res0))) {
297 #if 0
298 	    return gai_strerror(gai);
299 #else
300 	    return "Bad IP address in URL";
301 #endif
302 	}
303 	freeaddrinfo(res0);
304     }
305 
306 /*    if (strchr(host,'.') == NULL && domain != NULL)
307    host = pstrcat(p, host, domain, NULL);
308  */
309     *urlp = url;
310     *hostp = host;
311 
312     return NULL;
313 }
314 
315 static const char *const lwday[7] =
316 {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
317 
318 /*
319  * If the date is a valid RFC 850 date or asctime() date, then it
320  * is converted to the RFC 1123 format, otherwise it is not modified.
321  * This routine is not very fast at doing conversions, as it uses
322  * sscanf and sprintf. However, if the date is already correctly
323  * formatted, then it exits very quickly.
324  */
325 const char *
ap_proxy_date_canon(pool * p,const char * x)326      ap_proxy_date_canon(pool *p, const char *x)
327 {
328     int wk, mday, year, hour, min, sec, mon;
329     char *q, month[4], zone[4], week[4];
330 
331     q = strchr(x, ',');
332     /* check for RFC 850 date */
333     if (q != NULL && q - x > 3 && q[1] == ' ') {
334         *q = '\0';
335         for (wk = 0; wk < 7; wk++)
336             if (strcmp(x, lwday[wk]) == 0)
337                 break;
338         *q = ',';
339         if (wk == 7)
340             return x;           /* not a valid date */
341         if (q[4] != '-' || q[8] != '-' || q[11] != ' ' || q[14] != ':' ||
342             q[17] != ':' || strcmp(&q[20], " GMT") != 0)
343             return x;
344         if (sscanf(q + 2, "%u-%3s-%u %u:%u:%u %3s", &mday, month, &year,
345                    &hour, &min, &sec, zone) != 7)
346             return x;
347         if (year < 70)
348             year += 2000;
349         else
350             year += 1900;
351     }
352     else {
353 /* check for acstime() date */
354         if (x[3] != ' ' || x[7] != ' ' || x[10] != ' ' || x[13] != ':' ||
355             x[16] != ':' || x[19] != ' ' || x[24] != '\0')
356             return x;
357         if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour,
358                    &min, &sec, &year) != 7)
359             return x;
360         for (wk = 0; wk < 7; wk++)
361             if (strcmp(week, ap_day_snames[wk]) == 0)
362                 break;
363         if (wk == 7)
364             return x;
365     }
366 
367 /* check date */
368     for (mon = 0; mon < 12; mon++)
369         if (strcmp(month, ap_month_snames[mon]) == 0)
370             break;
371     if (mon == 12)
372         return x;
373 
374     q = ap_palloc(p, 30);
375     snprintf(q, 30, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", ap_day_snames[wk], mday,
376                 ap_month_snames[mon], year, hour, min, sec);
377     return q;
378 }
379 
380 
381 /*
382  * Reads headers from a buffer and returns an array of headers.
383  * Returns NULL on file error
384  * This routine tries to deal with too long lines and continuation lines.
385  *
386  * Note: Currently the headers are passed through unmerged. This has to be
387  * done so that headers which react badly to merging (such as Set-Cookie
388  * headers, which contain commas within the date field) do not get stuffed
389  * up.
390  */
ap_proxy_read_headers(request_rec * r,char * buffer,int size,BUFF * f)391 table *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f)
392 {
393     table *resp_hdrs;
394     int len;
395     char *value, *end;
396     char field[MAX_STRING_LEN];
397 
398     resp_hdrs = ap_make_table(r->pool, 20);
399 
400     /*
401      * Read header lines until we get the empty separator line, a read error,
402      * the connection closes (EOF), or we timeout.
403      */
404     while ((len = ap_getline(buffer, size, f, 1)) > 0) {
405 
406         if (!(value = strchr(buffer, ':'))) {   /* Find the colon separator */
407 
408             /*
409              * Buggy MS IIS servers sometimes return invalid headers (an
410              * extra "HTTP/1.0 200, OK" line sprinkled in between the usual
411              * MIME headers). Try to deal with it in a sensible way, but log
412              * the fact. XXX: The mask check is buggy if we ever see an
413              * HTTP/1.10
414              */
415 
416             if (!ap_checkmask(buffer, "HTTP/#.# ###*")) {
417                 /* Nope, it wasn't even an extra HTTP header. Give up. */
418                 return NULL;
419             }
420 
421             ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_NOERRNO, r->server,
422                          "proxy: Ignoring duplicate HTTP status line "
423                          "returned by buggy server %s (%s)", r->uri, r->method);
424             continue;
425         }
426 
427         *value = '\0';
428         ++value;
429         /*
430          * XXX: RFC2068 defines only SP and HT as whitespace, this test is
431          * wrong... and so are many others probably.
432          */
433         while (ap_isspace(*value))
434             ++value;            /* Skip to start of value   */
435 
436         /* should strip trailing whitespace as well */
437         for (end = &value[strlen(value) - 1]; end > value && ap_isspace(*end); --end)
438             *end = '\0';
439 
440         /* make sure we add so as not to destroy duplicated headers */
441         ap_table_add(resp_hdrs, buffer, value);
442 
443         /* the header was too long; at the least we should skip extra data */
444         if (len >= size - 1) {
445             while ((len = ap_getline(field, MAX_STRING_LEN, f, 1))
446                    >= MAX_STRING_LEN - 1) {
447                 /* soak up the extra data */
448             }
449             if (len == 0)       /* time to exit the larger loop as well */
450                 break;
451         }
452     }
453     return resp_hdrs;
454 }
455 
456 /* read data from (socket BUFF*) f, write it to:
457  * - c->fp, if it is open
458  * - r->connection->client, if nowrite == 0
459  */
460 
ap_proxy_send_fb(BUFF * f,request_rec * r,cache_req * c,off_t len,int nowrite,int chunked,size_t recv_buffer_size)461 long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c, off_t len, int nowrite, int chunked, size_t recv_buffer_size)
462 {
463     int ok, end_of_chunk;
464     char *buf;
465     size_t buf_size;
466     long remaining = 0;
467     long total_bytes_rcvd;
468     register int n = 0, o, w;
469     conn_rec *con = r->connection;
470     int alternate_timeouts = 1; /* 1 if we alternate between soft & hard
471                                  * timeouts */
472 
473     /* allocate a buffer to store the bytes in */
474     /*
475      * make sure it is at least IOBUFSIZE, as recv_buffer_size may be zero
476      * for system default
477      */
478     buf_size = MAX(recv_buffer_size, IOBUFSIZE);
479     buf = ap_palloc(r->pool, buf_size);
480 
481     total_bytes_rcvd = 0;
482     if (c != NULL)
483         c->written = 0;
484 
485     /*
486      * Since we are reading from one buffer and writing to another, it is
487      * unsafe to do a soft_timeout here, at least until the proxy has its own
488      * timeout handler which can set both buffers to EOUT.
489      */
490 
491     ap_kill_timeout(r);
492 
493     /*
494      * CHECKME! Since hard_timeout won't work in unix on sends with partial
495      * cache completion, we have to alternate between hard_timeout for reads,
496      * and soft_timeout for send.  This is because we need to get a return
497      * from ap_bwrite to be able to continue caching. BUT, if we *can't*
498      * continue anyway, just use hard_timeout. (Also, if no cache file is
499      * written, use hard timeouts)
500      */
501 
502     if (c == NULL || c->len <= 0 || c->cache_completion == 1.0) {
503         ap_hard_timeout("proxy send body", r);
504         alternate_timeouts = 0;
505     }
506 
507     /*
508      * Loop and ap_bread() while we can successfully read and write, or
509      * (after the client aborted) while we can successfully read and finish
510      * the configured cache_completion.
511      */
512     for (end_of_chunk = ok = 1; ok;) {
513         if (alternate_timeouts)
514             ap_hard_timeout("proxy recv body from upstream server", r);
515 
516 
517         /* read a chunked block */
518         if (chunked) {
519             long chunk_start = 0;
520             n = 0;
521 
522             /* start of a new chunk */
523             if (end_of_chunk) {
524                 end_of_chunk = 0;
525                 /* get the chunk size from the stream */
526                 chunk_start = ap_getline(buf, buf_size, f, 0);
527                 if ((chunk_start <= 0) || ((size_t)chunk_start + 1 >= buf_size) || !ap_isxdigit(*buf)) {
528                     n = -1;
529                 }
530                 /* parse the chunk size */
531                 else {
532                     remaining = ap_get_chunk_size(buf);
533                     if (remaining == 0) { /* Last chunk indicated, get footers */
534                         /* as we are a proxy, we discard the footers, as the headers
535                          * have already been sent at this point.
536                          */
537                         if (NULL == ap_proxy_read_headers(r, buf, buf_size, f)) {
538                             n = -1;
539                         }
540                     }
541                     else if (remaining < 0) {
542                         n = -1;
543                         ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,
544                                       "proxy: remote protocol error, invalid chunk size");
545 
546                     }
547                 }
548             }
549 
550             /* read the chunk */
551             if (remaining > 0) {
552                 n = ap_bread(f, buf, MIN((int)buf_size, (int)remaining));
553                 if (n > -1) {
554                     remaining -= n;
555                     end_of_chunk = (remaining == 0);
556                 }
557             }
558 
559             /* soak up trailing CRLF */
560             if (end_of_chunk) {
561                 int ch; /* int because it may hold an EOF */
562                 /*
563                  * For EBCDIC, the proxy has configured the BUFF layer to
564                  * transparently pass the ascii characters thru (also writing
565                  * an ASCII copy to the cache, where appropriate).
566                  * Therefore, we see here an ASCII-CRLF (\015\012),
567                  * not an EBCDIC-CRLF (\r\n).
568                  */
569                 if ((ch = ap_bgetc(f)) == EOF) {
570                     /* Protocol error: EOF detected within chunk */
571                     n = -1;
572                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,
573                                   "proxy: remote protocol error, eof while reading chunked from proxy");
574                 }
575                 else
576                 {
577                     if (ch == '\015') { /* _ASCII_ CR */
578                         ch = ap_bgetc(f);
579                     }
580                     if (ch != '\012') {
581                         n = -1;
582                     }
583                 }
584             }
585         }
586 
587         /* otherwise read block normally */
588         else {
589             if (-1 == len) {
590                 n = ap_bread(f, buf, buf_size);
591             }
592             else {
593                 n = ap_bread(f, buf, MIN((int)buf_size,
594                                          (int)(len - total_bytes_rcvd)));
595             }
596         }
597 
598 
599         if (alternate_timeouts)
600             ap_kill_timeout(r);
601         else
602             ap_reset_timeout(r);
603 
604         if (n == -1) {          /* input error */
605             if (c != NULL) {
606                 ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
607                               "proxy: error reading from %s", c->url);
608                 c = ap_proxy_cache_error(c);
609             }
610             break;
611         }
612         if (n == 0)
613             break;              /* EOF */
614         o = 0;
615         total_bytes_rcvd += n;
616 
617         /* if we've received everything... */
618         /*
619          * in the case of slow frontends and expensive backends, we want to
620          * avoid leaving a backend connection hanging while the frontend
621          * takes it's time to absorb the bytes. so: if we just read the last
622          * block, we close the backend connection now instead of later - it's
623          * no longer needed.
624          */
625         if (total_bytes_rcvd == len) {
626             ap_bclose(f);
627             f = NULL;
628         }
629 
630         /* Write to cache first. */
631         /*
632          * @@@ XXX FIXME: Assuming that writing the cache file won't time
633          * out?!!?
634          */
635         if (c != NULL && c->fp != NULL) {
636             if (ap_bwrite(c->fp, &buf[0], n) != n) {
637                 ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
638                               "proxy: error writing to %s", c->tempfile);
639                 c = ap_proxy_cache_error(c);
640             }
641             else {
642                 c->written += n;
643             }
644         }
645 
646         /* Write the block to the client, detect aborted transfers */
647         while (!nowrite && !con->aborted && n > 0) {
648             if (alternate_timeouts)
649                 ap_soft_timeout("proxy send body", r);
650 
651             w = ap_bwrite(con->client, &buf[o], n);
652 
653             if (alternate_timeouts)
654                 ap_kill_timeout(r);
655             else
656                 ap_reset_timeout(r);
657 
658             if (w <= 0) {
659                 if (c != NULL) {
660                     /*
661                      * when a send failure occurs, we need to decide whether
662                      * to continue loading and caching the document, or to
663                      * abort the whole thing
664                      */
665                     ok = (c->len > 0) &&
666                         (c->cache_completion > 0) &&
667                         (c->len * c->cache_completion < total_bytes_rcvd);
668 
669                     if (!ok) {
670                         if (c->fp != NULL) {
671                             ap_pclosef(c->req->pool, ap_bfileno(c->fp, B_WR));
672                             c->fp = NULL;
673                         }
674                         unlink(c->tempfile);
675                         c = NULL;
676                     }
677                 }
678                 con->aborted = 1;
679                 break;
680             }
681             n -= w;
682             o += w;
683         }                       /* while client alive and more data to send */
684 
685         /* if we've received everything, leave now */
686         if (total_bytes_rcvd == len)
687             break;
688 
689     }                           /* loop and ap_bread while "ok" */
690 
691     /* if the backend connection is still open, close it */
692     if (f) {
693         ap_bclose(f);
694     }
695 
696     if (!con->aborted) {
697         ap_bflush(con->client);
698     }
699 
700     ap_kill_timeout(r);
701 
702     r->bytes_sent += total_bytes_rcvd;
703 
704     return total_bytes_rcvd;
705 }
706 
707 /*
708  * Writes response line and headers to the cache file.
709  *
710  * If respline is NULL, no response line will be written.
711  */
ap_proxy_write_headers(cache_req * c,const char * respline,table * t)712 void ap_proxy_write_headers(cache_req *c, const char *respline, table *t)
713 {
714     /* write status line */
715     if (respline && c->fp != NULL &&
716         ap_bvputs(c->fp, respline, CRLF, NULL) == -1) {
717         ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
718                       "proxy: error writing status line to %s", c->tempfile);
719         c = ap_proxy_cache_error(c);
720         return;
721     }
722 
723     /* write response headers to the cache file */
724     ap_table_do(ap_proxy_send_hdr_line, c, t, NULL);
725 
726     /* write terminating CRLF */
727     if (c->fp != NULL && ap_bputs(CRLF, c->fp) == -1) {
728         ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
729                       "proxy: error writing CRLF to %s", c->tempfile);
730         c = ap_proxy_cache_error(c);
731     }
732 }
733 
734 
735 /*
736  * list is a comma-separated list of case-insensitive tokens, with
737  * optional whitespace around the tokens.
738  * The return returns 1 if the token val is found in the list, or 0
739  * otherwise.
740  */
ap_proxy_liststr(const char * list,const char * key,char ** val)741 int ap_proxy_liststr(const char *list, const char *key, char **val)
742 {
743     int len, i;
744     const char *p;
745     char valbuf[HUGE_STRING_LEN];
746     valbuf[sizeof(valbuf) - 1] = 0;     /* safety terminating zero */
747 
748     len = strlen(key);
749 
750     while (list != NULL) {
751         p = strchr(list, ',');
752         if (p != NULL) {
753             i = p - list;
754             do
755                 p++;
756             while (ap_isspace(*p));
757         }
758         else
759             i = strlen(list);
760 
761         while (i > 0 && ap_isspace(list[i - 1]))
762             i--;
763         if (i == len && strncasecmp(list, key, len) == 0) {
764             if (val) {
765                 p = strchr(list, ',');
766                 while (ap_isspace(*list)) {
767                     list++;
768                 }
769                 if ('=' == list[0])
770                     list++;
771                 while (ap_isspace(*list)) {
772                     list++;
773                 }
774                 strncpy(valbuf, list, MIN(p - list, sizeof(valbuf) - 1));
775                 *val = valbuf;
776             }
777             return 1;
778         }
779         list = p;
780     }
781     return 0;
782 }
783 
ap_proxy_hash(const char * it,char * val,int ndepth,int nlength)784 void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength)
785 {
786     AP_MD5_CTX context;
787     unsigned char digest[16];
788     char tmp[22];
789     int i, k, d;
790     unsigned int x;
791     static const char enc_table[64] =
792     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@";
793 
794     ap_MD5Init(&context);
795     ap_MD5Update(&context, (const unsigned char *)it, strlen(it));
796     ap_MD5Final(digest, &context);
797 
798 /* encode 128 bits as 22 characters, using a modified uuencoding */
799 /* the encoding is 3 bytes -> 4 characters
800  * i.e. 128 bits is 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters
801  */
802     for (i = 0, k = 0; i < 15; i += 3) {
803         x = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2];
804         tmp[k++] = enc_table[x >> 18];
805         tmp[k++] = enc_table[(x >> 12) & 0x3f];
806         tmp[k++] = enc_table[(x >> 6) & 0x3f];
807         tmp[k++] = enc_table[x & 0x3f];
808     }
809 /* one byte left */
810     x = digest[15];
811     tmp[k++] = enc_table[x >> 2];       /* use up 6 bits */
812     tmp[k++] = enc_table[(x << 4) & 0x3f];
813     /* now split into directory levels */
814 
815     for (i = k = d = 0; d < ndepth; ++d) {
816         memcpy(&val[i], &tmp[k], nlength);
817         k += nlength;
818         val[i + nlength] = '/';
819         i += nlength + 1;
820     }
821     memcpy(&val[i], &tmp[k], 22 - k);
822     val[i + 22 - k] = '\0';
823 }
824 
825 /*
826  * Converts 16 hex digits to a time integer
827  */
ap_proxy_hex2sec(const char * x)828 int ap_proxy_hex2sec(const char *x)
829 {
830     int i, ch;
831     unsigned int j;
832 
833     for (i = 0, j = 0; i < 16; i++) {
834         ch = x[i];
835         j <<= 4;
836         if (ap_isdigit(ch))
837             j |= ch - '0';
838         else if (ap_isupper(ch))
839             j |= ch - ('A' - 10);
840         else
841             j |= ch - ('a' - 10);
842     }
843 /* no longer necessary, as the source hex is 8-byte int */
844 /*    if (j == 0xffffffff)*/
845     /*      return -1;*//* so that it works with 8-byte ints */
846 /*    else */
847     return j;
848 }
849 
850 /*
851  * Converts a time integer to 16 hex digits
852  */
ap_proxy_sec2hex(int t,char * y,int len)853 int ap_proxy_sec2hex(int t, char *y, int len)
854 {
855     int i, ch;
856     unsigned int j = t;
857 
858     if (-1 == t) {
859         if (strlcpy(y, "FFFFFFFFFFFFFFFF", len) > len)
860 		return (-1);
861         return (0);
862     }
863 
864     if (len < 17)
865 	return (-1);
866 
867     for (i = 15; i >= 0; i--) {
868         ch = j & 0xF;
869         j >>= 4;
870         if (ch >= 10)
871             y[i] = ch + ('A' - 10);
872         else
873             y[i] = ch + '0';
874     }
875     y[16] = '\0';
876     return (0);
877 }
878 
879 
ap_proxy_cache_error(cache_req * c)880 cache_req *ap_proxy_cache_error(cache_req *c)
881 {
882     if (c != NULL) {
883         if (c->fp != NULL) {
884             ap_pclosef(c->req->pool, ap_bfileno(c->fp, B_WR));
885             c->fp = NULL;
886         }
887         if (c->origfp != NULL) {
888             ap_pclosef(c->req->pool, ap_bfileno(c->origfp, B_WR));
889             c->origfp = NULL;
890         }
891         if (c->tempfile)
892             unlink(c->tempfile);
893     }
894     return NULL;
895 }
896 
ap_proxyerror(request_rec * r,int statuscode,const char * message)897 int ap_proxyerror(request_rec *r, int statuscode, const char *message)
898 {
899     ap_table_setn(r->notes, "error-notes",
900                   ap_pstrcat(r->pool,
901                              "The proxy server could not handle the request "
902                            "<EM><A HREF=\"", ap_escape_uri(r->pool, r->uri),
903                              "\">", ap_escape_html(r->pool, r->method),
904                              "&nbsp;",
905                           ap_escape_html(r->pool, r->uri), "</A></EM>.<P>\n"
906                              "Reason: <STRONG>",
907                              ap_escape_html(r->pool, message),
908                              "</STRONG>", NULL));
909 
910     /* Allow "error-notes" string to be printed by ap_send_error_response() */
911     ap_table_setn(r->notes, "verbose-error-to", ap_pstrdup(r->pool, "*"));
912 
913     r->status_line = ap_psprintf(r->pool, "%3.3u Proxy Error", statuscode);
914     return statuscode;
915 }
916 
917 /*
918  * This routine returns its own error message
919  */
920 const char *
ap_proxy_host2addr(const char * host,struct hostent * reqhp)921      ap_proxy_host2addr(const char *host, struct hostent * reqhp)
922 {
923     int i;
924     struct hostent *hp;
925     struct per_thread_data *ptd = get_per_thread_data();
926 
927     for (i = 0; host[i] != '\0'; i++)
928         if (!isdigit((unsigned char)host[i]) && host[i] != '.')
929             break;
930 
931     if (host[i] != '\0') {
932         hp = gethostbyname(host);
933         if (hp == NULL)
934             return "Host not found";
935     }
936     else {
937         ptd->ipaddr = ap_inet_addr(host);
938         hp = gethostbyaddr((char *)&ptd->ipaddr, sizeof(ptd->ipaddr), AF_INET);
939         if (hp == NULL) {
940             memset(&ptd->hpbuf, 0, sizeof(ptd->hpbuf));
941             ptd->hpbuf.h_name = 0;
942             ptd->hpbuf.h_addrtype = AF_INET;
943             ptd->hpbuf.h_length = sizeof(ptd->ipaddr);
944             ptd->hpbuf.h_addr_list = ptd->charpbuf;
945             ptd->hpbuf.h_addr_list[0] = (char *)&ptd->ipaddr;
946             ptd->hpbuf.h_addr_list[1] = 0;
947             hp = &ptd->hpbuf;
948         }
949     }
950     *reqhp = *hp;
951     return NULL;
952 }
953 
954 static const char *
proxy_get_host_of_request(request_rec * r)955      proxy_get_host_of_request(request_rec *r)
956 {
957     char *url, *user = NULL, *password = NULL, *err, *host;
958     int port = -1;
959 
960     if (r->hostname != NULL)
961         return r->hostname;
962 
963     /* Set url to the first char after "scheme://" */
964     if ((url = strchr(r->uri, ':')) == NULL
965         || url[1] != '/' || url[2] != '/')
966         return NULL;
967 
968     url = ap_pstrdup(r->pool, &url[1]); /* make it point to "//", which is
969                                          * what proxy_canon_netloc expects */
970 
971     err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);
972 
973     if (err != NULL)
974         ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, r,
975                       "%s", err);
976 
977     r->hostname = host;
978 
979     return host;                /* ought to return the port, too */
980 }
981 
982 /* Return TRUE if addr represents an IP address (or an IP network address) */
ap_proxy_is_ipaddr(struct dirconn_entry * This,pool * p)983 int ap_proxy_is_ipaddr(struct dirconn_entry *This, pool *p)
984 {
985     const char *addr = This->name;
986     long ip_addr[4];
987     int i, quads;
988     long bits;
989 
990     /* if the address is given with an explicit netmask, use that */
991     /* Due to a deficiency in ap_inet_addr(), it is impossible to parse */
992     /* "partial" addresses (with less than 4 quads) correctly, i.e.  */
993     /* 192.168.123 is parsed as 192.168.0.123, which is not what I want. */
994     /* I therefore have to parse the IP address manually: */
995     /*
996      * if (proxy_readmask(This->name, &This->addr.s_addr, &This->mask.s_addr)
997      * == 0)
998      */
999     /* addr and mask were set by proxy_readmask() */
1000     /* return 1; */
1001 
1002     /* Parse IP addr manually, optionally allowing */
1003     /* abbreviated net addresses like 192.168. */
1004 
1005     /* Iterate over up to 4 (dotted) quads. */
1006     for (quads = 0; quads < 4 && *addr != '\0'; ++quads) {
1007         char *tmp;
1008 
1009         if (*addr == '/' && quads > 0)  /* netmask starts here. */
1010             break;
1011 
1012         if (!isdigit((unsigned char)*addr))
1013             return 0;           /* no digit at start of quad */
1014 
1015         ip_addr[quads] = ap_strtol(addr, &tmp, 0);
1016 
1017         if (tmp == addr)        /* expected a digit, found something else */
1018             return 0;
1019 
1020         if (ip_addr[quads] < 0 || ip_addr[quads] > 255) {
1021             /* invalid octet */
1022             return 0;
1023         }
1024 
1025         addr = tmp;
1026 
1027         if (*addr == '.' && quads != 3)
1028             ++addr;             /* after the 4th quad, a dot would be illegal */
1029     }
1030 
1031     for (This->addr.s_addr = 0, i = 0; i < quads; ++i)
1032         This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
1033 
1034     if (addr[0] == '/' && isdigit((unsigned char)addr[1])) { /* net mask follows: */
1035         char *tmp;
1036 
1037         ++addr;
1038 
1039         bits = ap_strtol(addr, &tmp, 0);
1040 
1041         if (tmp == addr)        /* expected a digit, found something else */
1042             return 0;
1043 
1044         addr = tmp;
1045 
1046         if (bits < 0 || bits > 32)      /* netmask must be between 0 and 32 */
1047             return 0;
1048 
1049     }
1050     else {
1051         /* Determine (i.e., "guess") netmask by counting the */
1052         /* number of trailing .0's; reduce #quads appropriately */
1053         /* (so that 192.168.0.0 is equivalent to 192.168.)        */
1054         while (quads > 0 && ip_addr[quads - 1] == 0)
1055             --quads;
1056 
1057         /*
1058          * "IP Address should be given in dotted-quad form, optionally
1059          * followed by a netmask (e.g., 192.168.111.0/24)";
1060          */
1061         if (quads < 1)
1062             return 0;
1063 
1064         /* every zero-byte counts as 8 zero-bits */
1065         bits = 8 * quads;
1066 
1067         if (bits != 32)         /* no warning for fully qualified IP address */
1068             fprintf(stderr, "Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld\n",
1069                     inet_ntoa(This->addr), bits);
1070     }
1071 
1072     This->mask.s_addr = htonl(INADDR_NONE << (32 - bits));
1073 
1074     if (*addr == '\0' && (This->addr.s_addr & ~This->mask.s_addr) != 0) {
1075         fprintf(stderr, "Warning: NetMask and IP-Addr disagree in %s/%ld\n",
1076                 inet_ntoa(This->addr), bits);
1077         This->addr.s_addr &= This->mask.s_addr;
1078         fprintf(stderr, "         Set to %s/%ld\n",
1079                 inet_ntoa(This->addr), bits);
1080     }
1081 
1082     if (*addr == '\0') {
1083         This->matcher = proxy_match_ipaddr;
1084         return 1;
1085     }
1086     else
1087         return (*addr == '\0'); /* okay iff we've parsed the whole string */
1088 }
1089 
1090 /* Return TRUE if addr represents an IP address (or an IP network address) */
proxy_match_ipaddr(struct dirconn_entry * This,request_rec * r)1091 static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r)
1092 {
1093     int i;
1094     int ip_addr[4];
1095     struct in_addr addr;
1096     struct in_addr *ip_list;
1097     char **ip_listptr;
1098     const char *found;
1099     const char *host = proxy_get_host_of_request(r);
1100 
1101     if (host == NULL)           /* oops! */
1102         return 0;
1103 
1104     memset(&addr, '\0', sizeof addr);
1105     memset(ip_addr, '\0', sizeof ip_addr);
1106 
1107     if (4 == sscanf(host, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3])) {
1108         for (addr.s_addr = 0, i = 0; i < 4; ++i)
1109             addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
1110 
1111         if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {
1112 #if DEBUGGING
1113             fprintf(stderr, "1)IP-Match: %s[%s] <-> ", host, inet_ntoa(addr));
1114             fprintf(stderr, "%s/", inet_ntoa(This->addr));
1115             fprintf(stderr, "%s\n", inet_ntoa(This->mask));
1116 #endif
1117             return 1;
1118         }
1119 #if DEBUGGING
1120         else {
1121             fprintf(stderr, "1)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(addr));
1122             fprintf(stderr, "%s/", inet_ntoa(This->addr));
1123             fprintf(stderr, "%s\n", inet_ntoa(This->mask));
1124         }
1125 #endif
1126     }
1127     else {
1128         struct hostent the_host;
1129 
1130         memset(&the_host, '\0', sizeof the_host);
1131         found = ap_proxy_host2addr(host, &the_host);
1132 
1133         if (found != NULL) {
1134 #if DEBUGGING
1135             fprintf(stderr, "2)IP-NoMatch: hostname=%s msg=%s\n", host, found);
1136 #endif
1137             return 0;
1138         }
1139 
1140         if (the_host.h_name != NULL)
1141             found = the_host.h_name;
1142         else
1143             found = host;
1144 
1145         /* Try to deal with multiple IP addr's for a host */
1146         for (ip_listptr = the_host.h_addr_list; *ip_listptr; ++ip_listptr) {
1147             ip_list = (struct in_addr *)*ip_listptr;
1148             if (This->addr.s_addr == (ip_list->s_addr & This->mask.s_addr)) {
1149 #if DEBUGGING
1150                 fprintf(stderr, "3)IP-Match: %s[%s] <-> ", found, inet_ntoa(*ip_list));
1151                 fprintf(stderr, "%s/", inet_ntoa(This->addr));
1152                 fprintf(stderr, "%s\n", inet_ntoa(This->mask));
1153 #endif
1154                 return 1;
1155             }
1156 #if DEBUGGING
1157             else {
1158                 fprintf(stderr, "3)IP-NoMatch: %s[%s] <-> ", found, inet_ntoa(*ip_list));
1159                 fprintf(stderr, "%s/", inet_ntoa(This->addr));
1160                 fprintf(stderr, "%s\n", inet_ntoa(This->mask));
1161             }
1162 #endif
1163         }
1164     }
1165 
1166     return 0;
1167 }
1168 
1169 /* Return TRUE if addr represents a domain name */
ap_proxy_is_domainname(struct dirconn_entry * This,pool * p)1170 int ap_proxy_is_domainname(struct dirconn_entry *This, pool *p)
1171 {
1172     char *addr = This->name;
1173     int i;
1174 
1175     /* Domain name must start with a '.' */
1176     if (addr[0] != '.')
1177         return 0;
1178 
1179     /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
1180     for (i = 0; ap_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i)
1181         continue;
1182 
1183     if (addr[i] != '\0')
1184         return 0;
1185 
1186     /* Strip trailing dots */
1187     for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i)
1188         addr[i] = '\0';
1189 
1190     This->matcher = proxy_match_domainname;
1191     return 1;
1192 }
1193 
1194 /* Return TRUE if host "host" is in domain "domain" */
proxy_match_domainname(struct dirconn_entry * This,request_rec * r)1195 static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r)
1196 {
1197     const char *host = proxy_get_host_of_request(r);
1198     int d_len = strlen(This->name), h_len;
1199 
1200     if (host == NULL)           /* some error was logged already */
1201         return 0;
1202 
1203     h_len = strlen(host);
1204 
1205     /* @@@ do this within the setup? */
1206     /* Ignore trailing dots in domain comparison: */
1207     while (d_len > 0 && This->name[d_len - 1] == '.')
1208         --d_len;
1209     while (h_len > 0 && host[h_len - 1] == '.')
1210         --h_len;
1211     return h_len > d_len
1212         && strncasecmp(&host[h_len - d_len], This->name, d_len) == 0;
1213 }
1214 
1215 /* Return TRUE if addr represents a host name */
ap_proxy_is_hostname(struct dirconn_entry * This,pool * p)1216 int ap_proxy_is_hostname(struct dirconn_entry *This, pool *p)
1217 {
1218     struct hostent host;
1219     char *addr = This->name;
1220     int i;
1221 
1222     /* Host names must not start with a '.' */
1223     if (addr[0] == '.')
1224         return 0;
1225 
1226     /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
1227     for (i = 0; ap_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i);
1228 
1229     if (addr[i] != '\0' || ap_proxy_host2addr(addr, &host) != NULL)
1230         return 0;
1231 
1232     This->hostentry = ap_pduphostent(p, &host);
1233 
1234     /* Strip trailing dots */
1235     for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i)
1236         addr[i] = '\0';
1237 
1238     This->matcher = proxy_match_hostname;
1239     return 1;
1240 }
1241 
1242 /* Return TRUE if host "host" is equal to host2 "host2" */
proxy_match_hostname(struct dirconn_entry * This,request_rec * r)1243 static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r)
1244 {
1245     char *host = This->name;
1246     const char *host2 = proxy_get_host_of_request(r);
1247     int h2_len;
1248     int h1_len;
1249 
1250     if (host == NULL || host2 == NULL)
1251         return 0;               /* oops! */
1252 
1253     h2_len = strlen(host2);
1254     h1_len = strlen(host);
1255 
1256     /* Ignore trailing dots in host2 comparison: */
1257     while (h2_len > 0 && host2[h2_len - 1] == '.')
1258         --h2_len;
1259     while (h1_len > 0 && host[h1_len - 1] == '.')
1260         --h1_len;
1261     return h1_len == h2_len
1262         && strncasecmp(host, host2, h1_len) == 0;
1263 }
1264 
1265 /* Return TRUE if addr is to be matched as a word */
ap_proxy_is_word(struct dirconn_entry * This,pool * p)1266 int ap_proxy_is_word(struct dirconn_entry *This, pool *p)
1267 {
1268     This->matcher = proxy_match_word;
1269     return 1;
1270 }
1271 
1272 /* Return TRUE if string "str2" occurs literally in "str1" */
proxy_match_word(struct dirconn_entry * This,request_rec * r)1273 static int proxy_match_word(struct dirconn_entry *This, request_rec *r)
1274 {
1275     const char *host = proxy_get_host_of_request(r);
1276     return host != NULL && strstr(host, This->name) != NULL;
1277 }
1278 
ap_proxy_doconnect(int sock,struct sockaddr * addr,request_rec * r)1279 int ap_proxy_doconnect(int sock, struct sockaddr *addr, request_rec *r)
1280 {
1281     int i;
1282     int salen;
1283     char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
1284 #ifdef NI_WITHSCOPEID
1285     const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID;
1286 #else
1287     const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
1288 #endif
1289 
1290     ap_hard_timeout("proxy connect", r);
1291 #ifdef HAVE_SOCKADDR_LEN
1292     salen = addr->sa_len;
1293 #else
1294     switch (addr->sa_family) {
1295     case AF_INET6:
1296 	salen = sizeof(struct sockaddr_in6);
1297 	break;
1298     default:
1299 	salen = sizeof(struct sockaddr_in);
1300 	break;
1301     }
1302 #endif
1303     do {
1304 	i = connect(sock,  addr, salen);
1305     } while (i == -1 && errno == EINTR);
1306     if (i == -1) {
1307 	if (getnameinfo(addr, salen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1308 		niflags) != 0) {
1309 	    memcpy(hbuf, "?", 2);
1310 	    memcpy(pbuf, "?", 2);
1311 	}
1312         ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
1313                       "proxy connect to %s port %s failed", hbuf, pbuf);
1314     }
1315     ap_kill_timeout(r);
1316 
1317     return i;
1318 }
1319 
1320 /* This function is called by ap_table_do() for all header lines
1321  * (from proxy_http.c and proxy_ftp.c)
1322  * It is passed a cache_req struct pointer and a MIME field and value pair
1323  */
ap_proxy_send_hdr_line(void * p,const char * key,const char * value)1324 int ap_proxy_send_hdr_line(void *p, const char *key, const char *value)
1325 {
1326     cache_req *c = (cache_req *)p;
1327 
1328     if (key == NULL || value == NULL || value[0] == '\0')
1329         return 1;
1330     if (c->fp != NULL &&
1331         ap_bvputs(c->fp, key, ": ", value, CRLF, NULL) == -1) {
1332         ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
1333                       "proxy: error writing header to %s", c->tempfile);
1334         c = ap_proxy_cache_error(c);
1335         return 0;               /* no need to continue, it failed already */
1336     }
1337     return 1;                   /* tell ap_table_do() to continue calling us
1338                                  * for more headers */
1339 }
1340 
1341 /* send a text line to one or two BUFF's; return line length */
ap_proxy_bputs2(const char * data,BUFF * client,cache_req * cache)1342 unsigned ap_proxy_bputs2(const char *data, BUFF *client, cache_req *cache)
1343 {
1344     unsigned len = ap_bputs(data, client);
1345     if (cache != NULL && cache->fp != NULL)
1346         ap_bputs(data, cache->fp);
1347     return len;
1348 }
1349 
1350 /* do a HTTP/1.1 age calculation */
ap_proxy_current_age(cache_req * c,const time_t age_value)1351 time_t ap_proxy_current_age(cache_req *c, const time_t age_value)
1352 {
1353     time_t apparent_age, corrected_received_age, response_delay, corrected_initial_age,
1354            resident_time, current_age;
1355 
1356     /* Perform an HTTP/1.1 age calculation. (RFC2616 13.2.3) */
1357 
1358     apparent_age = MAX(0, c->resp_time - c->date);
1359     corrected_received_age = MAX(apparent_age, age_value);
1360     response_delay = c->resp_time - c->req_time;
1361     corrected_initial_age = corrected_received_age + response_delay;
1362     resident_time = time(NULL) - c->resp_time;
1363     current_age = corrected_initial_age + resident_time;
1364 
1365     return (current_age);
1366 }
1367 
1368 /* open a cache file and return a pointer to a BUFF */
ap_proxy_open_cachefile(request_rec * r,char * filename)1369 BUFF *ap_proxy_open_cachefile(request_rec *r, char *filename)
1370 {
1371     BUFF *cachefp = NULL;
1372     int cfd;
1373 
1374     if (filename != NULL) {
1375         cfd = open(filename, O_RDWR | O_BINARY);
1376         if (cfd != -1) {
1377             ap_note_cleanups_for_fd(r->pool, cfd);
1378             cachefp = ap_bcreate(r->pool, B_RD | B_WR);
1379             ap_bpushfd(cachefp, cfd, cfd);
1380         }
1381         else if (errno != ENOENT)
1382             ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
1383                           "proxy: error opening cache file %s",
1384                           filename);
1385         else
1386             ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server, "File %s not found", filename);
1387 
1388     }
1389     return cachefp;
1390 }
1391 
1392 /* create a cache file and return a pointer to a BUFF */
ap_proxy_create_cachefile(request_rec * r,char * filename)1393 BUFF *ap_proxy_create_cachefile(request_rec *r, char *filename)
1394 {
1395     BUFF *cachefp = NULL;
1396     int cfd;
1397 
1398     if (filename != NULL) {
1399         cfd = open(filename, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0622);
1400         if (cfd != -1) {
1401             ap_note_cleanups_for_fd(r->pool, cfd);
1402             cachefp = ap_bcreate(r->pool, B_WR);
1403             ap_bpushfd(cachefp, -1, cfd);
1404         }
1405         else if (errno != ENOENT)
1406             ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
1407                           "proxy: error creating cache file %s",
1408                           filename);
1409     }
1410     return cachefp;
1411 }
1412 
1413 /* Clear all connection-based headers from headers table */
ap_proxy_clear_connection(pool * p,table * headers)1414 void ap_proxy_clear_connection(pool *p, table *headers)
1415 {
1416     const char *name;
1417     char *next = ap_pstrdup(p, ap_table_get(headers, "Connection"));
1418 
1419     /* Some proxies (Squid, ICS) use the non-standard "Proxy-Connection" header. */
1420     ap_table_unset(headers, "Proxy-Connection");
1421 
1422     if (next != NULL) {
1423         while (*next) {
1424             name = next;
1425             while (*next && !ap_isspace(*next) && (*next != ','))
1426                 ++next;
1427             while (ap_isspace(*next) || (*next == ',')) {
1428                 *next = '\0';
1429                 ++next;
1430             }
1431             ap_table_unset(headers, name);
1432         }
1433         ap_table_unset(headers, "Connection");
1434     }
1435 
1436     /* unset hop-by-hop headers defined in RFC2616 13.5.1 */
1437     ap_table_unset(headers,"Keep-Alive");
1438     /*
1439      * XXX: @@@ FIXME: "Proxy-Authenticate" should IMO *not* be stripped
1440      * because in a chain of proxies some "front" proxy might need
1441      * proxy authentication, while a "back-end" proxy which needs none can
1442      * simply pass the "Proxy-Authenticate" back to the client, and pass
1443      * the client's "Proxy-Authorization" to the front-end proxy.
1444      * (See the note in proxy_http.c for the "Proxy-Authorization" case.)
1445      *
1446      *   MnKr 04/2002
1447      */
1448     ap_table_unset(headers,"Proxy-Authenticate");
1449     ap_table_unset(headers,"TE");
1450     ap_table_unset(headers,"Trailer");
1451     /* it is safe to just chop the transfer-encoding header
1452      * here, because proxy doesn't support any other encodings
1453      * to the backend other than chunked.
1454      */
1455     ap_table_unset(headers,"Transfer-Encoding");
1456     ap_table_unset(headers,"Upgrade");
1457 
1458 }
1459 
1460 /* overlay one table on another
1461  * keys in base will be replaced by keys in overlay
1462  *
1463  * Note: this has to be done in a special way, due
1464  * to some nastiness when it comes to having multiple
1465  * headers in the overlay table. First, we remove all
1466  * the headers in the base table that are found in the
1467  * overlay table, then we simply concatenate the
1468  * tables together.
1469  *
1470  * The base and overlay tables need not be in the same
1471  * pool (and probably won't be).
1472  *
1473  * If the base table is changed in any way through
1474  * being overlayed with the overlay table, this
1475  * function returns a 1.
1476  */
ap_proxy_table_replace(table * base,table * overlay)1477 int ap_proxy_table_replace(table *base, table *overlay)
1478 {
1479     table_entry *elts = (table_entry *)overlay->a.elts;
1480     int i, q = 0;
1481     const char *val;
1482 
1483     /* remove overlay's keys from base */
1484     for (i = 0; i < overlay->a.nelts; ++i) {
1485         val = ap_table_get(base, elts[i].key);
1486         if (!val || strcmp(val, elts[i].val)) {
1487             q = 1;
1488         }
1489         if (val) {
1490             ap_table_unset(base, elts[i].key);
1491         }
1492     }
1493 
1494     /* add overlay to base */
1495     for (i = 0; i < overlay->a.nelts; ++i) {
1496         ap_table_add(base, elts[i].key, elts[i].val);
1497     }
1498 
1499     return q;
1500 }
1501 
1502 /* read the response line
1503  * This function reads a single line of response from the server,
1504  * and returns a status code.
1505  * It also populates the request_rec with the resultant status, and
1506  * returns backasswards status (HTTP/0.9).
1507  */
ap_proxy_read_response_line(BUFF * f,request_rec * r,char * buffer,int size,int * backasswards,int * major,int * minor)1508 int ap_proxy_read_response_line(BUFF *f, request_rec *r, char *buffer, int size, int *backasswards, int *major, int *minor) {
1509 
1510     long len;
1511 
1512     len = ap_getline(buffer, size-1, f, 0);
1513     if (len == -1) {
1514         ap_bclose(f);
1515         ap_kill_timeout(r);
1516         return ap_proxyerror(r, HTTP_BAD_GATEWAY,
1517                              "Error reading from remote server");
1518     }
1519     else if (len == 0) {
1520         ap_bclose(f);
1521         ap_kill_timeout(r);
1522         return ap_proxyerror(r, HTTP_BAD_GATEWAY,
1523                              "Document contains no data");
1524     }
1525 
1526     /*
1527      * Is it an HTTP/1 response? Do some sanity checks on the response. (This
1528      * is buggy if we ever see an HTTP/1.10)
1529      */
1530     if (ap_checkmask(buffer, "HTTP/#.# ###*")) {
1531 
1532         if (2 != sscanf(buffer, "HTTP/%u.%u", major, minor)) {
1533             /* if no response, default to HTTP/1.1 - is this correct? */
1534             *major = 1;
1535             *minor = 1;
1536         }
1537 
1538         /* If not an HTTP/1 message */
1539         if (*major < 1) {
1540             ap_bclose(f);
1541             ap_kill_timeout(r);
1542             return HTTP_BAD_GATEWAY;
1543         }
1544         *backasswards = 0;
1545 
1546         /* there need not be a reason phrase in the response,
1547 	 * and ap_getline() already deleted trailing whitespace.
1548 	 * But RFC2616 requires a SP after the Status-Code. Add one:
1549 	 */
1550 	if (strlen(buffer) < sizeof("HTTP/1.x 200 ")-1)
1551 	  buffer = ap_pstrcat(r->pool, buffer, " ", NULL);
1552         buffer[12] = '\0';
1553         r->status = atoi(&buffer[9]);
1554         buffer[12] = ' ';
1555         r->status_line = ap_pstrdup(r->pool, &buffer[9]);
1556 
1557         /* if the response was 100 continue, soak up any headers */
1558         if (r->status == 100) {
1559             ap_proxy_read_headers(r, buffer, size, f);
1560         }
1561 
1562     }
1563     else {
1564 
1565         /* an http/0.9 response */
1566         *backasswards = 1;
1567         r->status = 200;
1568         r->status_line = "200 OK";
1569         *major = 0;
1570         *minor = 9;
1571 
1572     }
1573 
1574     return OK;
1575 
1576 }
1577 
get_per_thread_data(void)1578 static struct per_thread_data *get_per_thread_data(void)
1579 {
1580     static APACHE_TLS struct per_thread_data sptd;
1581     return &sptd;
1582 }
1583