]> granicus.if.org Git - apache/blob - server/util.c
Introduce request taint-checking concept.
[apache] / server / 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 /*
18  * util.c: string utility things
19  *
20  * 3/21/93 Rob McCool
21  * 1995-96 Many changes by the Apache Software Foundation
22  *
23  */
24
25 /* Debugging aid:
26  * #define DEBUG            to trace all cfg_open*()/cfg_closefile() calls
27  * #define DEBUG_CFG_LINES  to trace every line read from the config files
28  */
29
30 #include "apr.h"
31 #include "apr_strings.h"
32 #include "apr_lib.h"
33 #include "apr_md5.h"            /* for apr_password_validate */
34
35 #define APR_WANT_STDIO
36 #define APR_WANT_STRFUNC
37 #include "apr_want.h"
38
39 #if APR_HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42 #if APR_HAVE_PROCESS_H
43 #include <process.h>            /* for getpid() on Win32 */
44 #endif
45 #if APR_HAVE_NETDB_H
46 #include <netdb.h>              /* for gethostbyname() */
47 #endif
48
49 #include "ap_config.h"
50 #include "apr_base64.h"
51 #include "httpd.h"
52 #include "http_main.h"
53 #include "http_log.h"
54 #include "http_protocol.h"
55 #include "http_config.h"
56 #include "http_core.h"
57 #include "util_ebcdic.h"
58 #include "util_varbuf.h"
59
60 #ifdef HAVE_PWD_H
61 #include <pwd.h>
62 #endif
63 #ifdef HAVE_GRP_H
64 #include <grp.h>
65 #endif
66 #ifdef HAVE_SYS_LOADAVG_H
67 #include <sys/loadavg.h>
68 #endif
69
70 #include "ap_mpm.h"
71
72 /* A bunch of functions in util.c scan strings looking for certain characters.
73  * To make that more efficient we encode a lookup table.  The test_char_table
74  * is generated automatically by gen_test_char.c.
75  */
76 #include "test_char.h"
77
78 /* we assume the folks using this ensure 0 <= c < 256... which means
79  * you need a cast to (unsigned char) first, you can't just plug a
80  * char in here and get it to work, because if char is signed then it
81  * will first be sign extended.
82  */
83 #define TEST_CHAR(c, f)        (test_char_table[(unsigned char)(c)] & (f))
84
85 /* Win32/NetWare/OS2 need to check for both forward and back slashes
86  * in ap_getparents() and ap_escape_url.
87  */
88 #ifdef CASE_BLIND_FILESYSTEM
89 #define IS_SLASH(s) ((s == '/') || (s == '\\'))
90 #define SLASHES "/\\"
91 #else
92 #define IS_SLASH(s) (s == '/')
93 #define SLASHES "/"
94 #endif
95
96 /* we know core's module_index is 0 */
97 #undef APLOG_MODULE_INDEX
98 #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
99
100 /*
101  * Examine a field value (such as a media-/content-type) string and return
102  * it sans any parameters; e.g., strip off any ';charset=foo' and the like.
103  */
104 AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype)
105 {
106     const char *semi;
107
108     if (intype == NULL) return NULL;
109
110     semi = ap_strchr_c(intype, ';');
111     if (semi == NULL) {
112         return apr_pstrdup(p, intype);
113     }
114     else {
115         while ((semi > intype) && apr_isspace(semi[-1])) {
116             semi--;
117         }
118         return apr_pstrmemdup(p, intype, semi - intype);
119     }
120 }
121
122 AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt,
123                               int gmt)
124 {
125     apr_size_t retcode;
126     char ts[MAX_STRING_LEN];
127     char tf[MAX_STRING_LEN];
128     apr_time_exp_t xt;
129
130     if (gmt) {
131         const char *f;
132         char *strp;
133
134         apr_time_exp_gmt(&xt, t);
135         /* Convert %Z to "GMT" and %z to "+0000";
136          * on hosts that do not have a time zone string in struct tm,
137          * strftime must assume its argument is local time.
138          */
139         for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f)
140             ; f++, strp++) {
141             if (*f != '%') continue;
142             switch (f[1]) {
143             case '%':
144                 *++strp = *++f;
145                 break;
146             case 'Z':
147                 *strp++ = 'G';
148                 *strp++ = 'M';
149                 *strp = 'T';
150                 f++;
151                 break;
152             case 'z': /* common extension */
153                 *strp++ = '+';
154                 *strp++ = '0';
155                 *strp++ = '0';
156                 *strp++ = '0';
157                 *strp = '0';
158                 f++;
159                 break;
160             }
161         }
162         *strp = '\0';
163         fmt = tf;
164     }
165     else {
166         apr_time_exp_lt(&xt, t);
167     }
168
169     /* check return code? */
170     apr_strftime(ts, &retcode, MAX_STRING_LEN, fmt, &xt);
171     ts[MAX_STRING_LEN - 1] = '\0';
172     return apr_pstrdup(p, ts);
173 }
174
175 /* Roy owes Rob beer. */
176 /* Rob owes Roy dinner. */
177
178 /* These legacy comments would make a lot more sense if Roy hadn't
179  * replaced the old later_than() routine with util_date.c.
180  *
181  * Well, okay, they still wouldn't make any sense.
182  */
183
184 /* Match = 0, NoMatch = 1, Abort = -1
185  * Based loosely on sections of wildmat.c by Rich Salz
186  * Hmmm... shouldn't this really go component by component?
187  */
188 AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected)
189 {
190     int x, y;
191
192     for (x = 0, y = 0; expected[y]; ++y, ++x) {
193         if ((!str[x]) && (expected[y] != '*'))
194             return -1;
195         if (expected[y] == '*') {
196             while (expected[++y] == '*');
197             if (!expected[y])
198                 return 0;
199             while (str[x]) {
200                 int ret;
201                 if ((ret = ap_strcmp_match(&str[x++], &expected[y])) != 1)
202                     return ret;
203             }
204             return -1;
205         }
206         else if ((expected[y] != '?') && (str[x] != expected[y]))
207             return 1;
208     }
209     return (str[x] != '\0');
210 }
211
212 AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
213 {
214     int x, y;
215
216     for (x = 0, y = 0; expected[y]; ++y, ++x) {
217         if (!str[x] && expected[y] != '*')
218             return -1;
219         if (expected[y] == '*') {
220             while (expected[++y] == '*');
221             if (!expected[y])
222                 return 0;
223             while (str[x]) {
224                 int ret;
225                 if ((ret = ap_strcasecmp_match(&str[x++], &expected[y])) != 1)
226                     return ret;
227             }
228             return -1;
229         }
230         else if (expected[y] != '?'
231                  && apr_tolower(str[x]) != apr_tolower(expected[y]))
232             return 1;
233     }
234     return (str[x] != '\0');
235 }
236
237 /* We actually compare the canonical root to this root, (but we don't
238  * waste time checking the case), since every use of this function in
239  * httpd-2.1 tests if the path is 'proper', meaning we've already passed
240  * it through apr_filepath_merge, or we haven't.
241  */
242 AP_DECLARE(int) ap_os_is_path_absolute(apr_pool_t *p, const char *dir)
243 {
244     const char *newpath;
245     const char *ourdir = dir;
246     if (apr_filepath_root(&newpath, &dir, 0, p) != APR_SUCCESS
247             || strncmp(newpath, ourdir, strlen(newpath)) != 0) {
248         return 0;
249     }
250     return 1;
251 }
252
253 AP_DECLARE(int) ap_is_matchexp(const char *str)
254 {
255     int x;
256
257     for (x = 0; str[x]; x++)
258         if ((str[x] == '*') || (str[x] == '?'))
259             return 1;
260     return 0;
261 }
262
263 /*
264  * Here's a pool-based interface to the POSIX-esque ap_regcomp().
265  * Note that we return ap_regex_t instead of being passed one.
266  * The reason is that if you use an already-used ap_regex_t structure,
267  * the memory that you've already allocated gets forgotten, and
268  * regfree() doesn't clear it. So we don't allow it.
269  */
270
271 static apr_status_t regex_cleanup(void *preg)
272 {
273     ap_regfree((ap_regex_t *) preg);
274     return APR_SUCCESS;
275 }
276
277 AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
278                                      int cflags)
279 {
280     ap_regex_t *preg = apr_palloc(p, sizeof *preg);
281     int err = ap_regcomp(preg, pattern, cflags);
282     if (err) {
283         if (err == AP_REG_ESPACE)
284             ap_abort_on_oom();
285         return NULL;
286     }
287
288     apr_pool_cleanup_register(p, (void *) preg, regex_cleanup,
289                               apr_pool_cleanup_null);
290
291     return preg;
292 }
293
294 AP_DECLARE(void) ap_pregfree(apr_pool_t *p, ap_regex_t *reg)
295 {
296     ap_regfree(reg);
297     apr_pool_cleanup_kill(p, (void *) reg, regex_cleanup);
298 }
299
300 /*
301  * Similar to standard strstr() but we ignore case in this version.
302  * Based on the strstr() implementation further below.
303  */
304 AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2)
305 {
306     char *p1, *p2;
307     if (*s2 == '\0') {
308         /* an empty s2 */
309         return((char *)s1);
310     }
311     while(1) {
312         for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
313         if (*s1 == '\0') {
314             return(NULL);
315         }
316         /* found first character of s2, see if the rest matches */
317         p1 = (char *)s1;
318         p2 = (char *)s2;
319         for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) {
320             if (*p1 == '\0') {
321                 /* both strings ended together */
322                 return((char *)s1);
323             }
324         }
325         if (*p2 == '\0') {
326             /* second string ended, a match */
327             break;
328         }
329         /* didn't find a match here, try starting at next character in s1 */
330         s1++;
331     }
332     return((char *)s1);
333 }
334
335 /*
336  * Returns an offsetted pointer in bigstring immediately after
337  * prefix. Returns bigstring if bigstring doesn't start with
338  * prefix or if prefix is longer than bigstring while still matching.
339  * NOTE: pointer returned is relative to bigstring, so we
340  * can use standard pointer comparisons in the calling function
341  * (eg: test if ap_stripprefix(a,b) == a)
342  */
343 AP_DECLARE(const char *) ap_stripprefix(const char *bigstring,
344                                         const char *prefix)
345 {
346     const char *p1;
347
348     if (*prefix == '\0')
349         return bigstring;
350
351     p1 = bigstring;
352     while (*p1 && *prefix) {
353         if (*p1++ != *prefix++)
354             return bigstring;
355     }
356     if (*prefix == '\0')
357         return p1;
358
359     /* hit the end of bigstring! */
360     return bigstring;
361 }
362
363 /* This function substitutes for $0-$9, filling in regular expression
364  * submatches. Pass it the same nmatch and pmatch arguments that you
365  * passed ap_regexec(). pmatch should not be greater than the maximum number
366  * of subexpressions - i.e. one more than the re_nsub member of ap_regex_t.
367  *
368  * nmatch must be <=AP_MAX_REG_MATCH (10).
369  *
370  * input should be the string with the $-expressions, source should be the
371  * string that was matched against.
372  *
373  * It returns the substituted string, or NULL if a vbuf is used.
374  * On errors, returns the orig string.
375  *
376  * Parts of this code are based on Henry Spencer's regsub(), from his
377  * AT&T V8 regexp package.
378  */
379
380 static apr_status_t regsub_core(apr_pool_t *p, char **result,
381                                 struct ap_varbuf *vb, const char *input,
382                                 const char *source, apr_size_t nmatch,
383                                 ap_regmatch_t pmatch[], apr_size_t maxlen)
384 {
385     const char *src = input;
386     char *dst;
387     char c;
388     apr_size_t no;
389     apr_size_t len = 0;
390
391     AP_DEBUG_ASSERT((result && p && !vb) || (vb && !p && !result));
392     if (!source || nmatch>AP_MAX_REG_MATCH)
393         return APR_EINVAL;
394     if (!nmatch) {
395         len = strlen(src);
396         if (maxlen > 0 && len >= maxlen)
397             return APR_ENOMEM;
398         if (!vb) {
399             *result = apr_pstrmemdup(p, src, len);
400             return APR_SUCCESS;
401         }
402         else {
403             ap_varbuf_strmemcat(vb, src, len);
404             return APR_SUCCESS;
405         }
406     }
407
408     /* First pass, find the size */
409     while ((c = *src++) != '\0') {
410         if (c == '$' && apr_isdigit(*src))
411             no = *src++ - '0';
412         else
413             no = AP_MAX_REG_MATCH;
414
415         if (no >= AP_MAX_REG_MATCH) {  /* Ordinary character. */
416             if (c == '\\' && *src)
417                 src++;
418             len++;
419         }
420         else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
421             if (APR_SIZE_MAX - len <= pmatch[no].rm_eo - pmatch[no].rm_so)
422                 return APR_ENOMEM;
423             len += pmatch[no].rm_eo - pmatch[no].rm_so;
424         }
425
426     }
427
428     if (len >= maxlen && maxlen > 0)
429         return APR_ENOMEM;
430
431     if (!vb) {
432         *result = dst = apr_palloc(p, len + 1);
433     }
434     else {
435         if (vb->strlen == AP_VARBUF_UNKNOWN)
436             vb->strlen = strlen(vb->buf);
437         ap_varbuf_grow(vb, vb->strlen + len);
438         dst = vb->buf + vb->strlen;
439         vb->strlen += len;
440     }
441
442     /* Now actually fill in the string */
443
444     src = input;
445
446     while ((c = *src++) != '\0') {
447         if (c == '$' && apr_isdigit(*src))
448             no = *src++ - '0';
449         else
450             no = AP_MAX_REG_MATCH;
451
452         if (no >= AP_MAX_REG_MATCH) {  /* Ordinary character. */
453             if (c == '\\' && *src)
454                 c = *src++;
455             *dst++ = c;
456         }
457         else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
458             len = pmatch[no].rm_eo - pmatch[no].rm_so;
459             memcpy(dst, source + pmatch[no].rm_so, len);
460             dst += len;
461         }
462
463     }
464     *dst = '\0';
465
466     return APR_SUCCESS;
467 }
468
469 #ifndef AP_PREGSUB_MAXLEN
470 #define AP_PREGSUB_MAXLEN   (HUGE_STRING_LEN * 8)
471 #endif
472 AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
473                               const char *source, apr_size_t nmatch,
474                               ap_regmatch_t pmatch[])
475 {
476     char *result;
477     apr_status_t rc = regsub_core(p, &result, NULL, input, source, nmatch,
478                                   pmatch, AP_PREGSUB_MAXLEN);
479     if (rc != APR_SUCCESS)
480         result = NULL;
481     return result;
482 }
483
484 AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result,
485                                        const char *input, const char *source,
486                                        apr_size_t nmatch, ap_regmatch_t pmatch[],
487                                        apr_size_t maxlen)
488 {
489     apr_status_t rc = regsub_core(p, result, NULL, input, source, nmatch,
490                                   pmatch, maxlen);
491     if (rc != APR_SUCCESS)
492         *result = NULL;
493     return rc;
494 }
495
496 /*
497  * Parse .. so we don't compromise security
498  */
499 AP_DECLARE(void) ap_getparents(char *name)
500 {
501     char *next;
502     int l, w, first_dot;
503
504     /* Four paseses, as per RFC 1808 */
505     /* a) remove ./ path segments */
506     for (next = name; *next && (*next != '.'); next++) {
507     }
508
509     l = w = first_dot = next - name;
510     while (name[l] != '\0') {
511         if (name[l] == '.' && IS_SLASH(name[l + 1])
512             && (l == 0 || IS_SLASH(name[l - 1])))
513             l += 2;
514         else
515             name[w++] = name[l++];
516     }
517
518     /* b) remove trailing . path, segment */
519     if (w == 1 && name[0] == '.')
520         w--;
521     else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2]))
522         w--;
523     name[w] = '\0';
524
525     /* c) remove all xx/../ segments. (including leading ../ and /../) */
526     l = first_dot;
527
528     while (name[l] != '\0') {
529         if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2])
530             && (l == 0 || IS_SLASH(name[l - 1]))) {
531             int m = l + 3, n;
532
533             l = l - 2;
534             if (l >= 0) {
535                 while (l >= 0 && !IS_SLASH(name[l]))
536                     l--;
537                 l++;
538             }
539             else
540                 l = 0;
541             n = l;
542             while ((name[n] = name[m]))
543                 (++n, ++m);
544         }
545         else
546             ++l;
547     }
548
549     /* d) remove trailing xx/.. segment. */
550     if (l == 2 && name[0] == '.' && name[1] == '.')
551         name[0] = '\0';
552     else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
553              && IS_SLASH(name[l - 3])) {
554         l = l - 4;
555         if (l >= 0) {
556             while (l >= 0 && !IS_SLASH(name[l]))
557                 l--;
558             l++;
559         }
560         else
561             l = 0;
562         name[l] = '\0';
563     }
564 }
565
566 AP_DECLARE(void) ap_no2slash(char *name)
567 {
568     char *d, *s;
569
570     s = d = name;
571
572 #ifdef HAVE_UNC_PATHS
573     /* Check for UNC names.  Leave leading two slashes. */
574     if (s[0] == '/' && s[1] == '/')
575         *d++ = *s++;
576 #endif
577
578     while (*s) {
579         if ((*d++ = *s) == '/') {
580             do {
581                 ++s;
582             } while (*s == '/');
583         }
584         else {
585             ++s;
586         }
587     }
588     *d = '\0';
589 }
590
591
592 /*
593  * copy at most n leading directories of s into d
594  * d should be at least as large as s plus 1 extra byte
595  * assumes n > 0
596  * the return value is the ever useful pointer to the trailing \0 of d
597  *
598  * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments,
599  * so that if n == 0, "/" is returned in d with n == 1
600  * and s == "e:/test.html", "e:/" is returned in d
601  * *** See also directory_walk in modules/http/http_request.c
602
603  * examples:
604  *    /a/b, 0  ==> /  (true for all platforms)
605  *    /a/b, 1  ==> /
606  *    /a/b, 2  ==> /a/
607  *    /a/b, 3  ==> /a/b/
608  *    /a/b, 4  ==> /a/b/
609  *
610  *    c:/a/b 0 ==> /
611  *    c:/a/b 1 ==> c:/
612  *    c:/a/b 2 ==> c:/a/
613  *    c:/a/b 3 ==> c:/a/b
614  *    c:/a/b 4 ==> c:/a/b
615  */
616 AP_DECLARE(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
617 {
618     if (n < 1) {
619         *d = '/';
620         *++d = '\0';
621         return (d);
622     }
623
624     for (;;) {
625         if (*s == '\0' || (*s == '/' && (--n) == 0)) {
626             *d = '/';
627             break;
628         }
629         *d++ = *s++;
630     }
631     *++d = 0;
632     return (d);
633 }
634
635
636 /*
637  * return the parent directory name including trailing / of the file s
638  */
639 AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s)
640 {
641     const char *last_slash = ap_strrchr_c(s, '/');
642     char *d;
643     int l;
644
645     if (last_slash == NULL) {
646         return apr_pstrdup(p, "");
647     }
648     l = (last_slash - s) + 1;
649     d = apr_pstrmemdup(p, s, l);
650
651     return (d);
652 }
653
654
655 AP_DECLARE(int) ap_count_dirs(const char *path)
656 {
657     int x, n;
658
659     for (x = 0, n = 0; path[x]; x++)
660         if (path[x] == '/')
661             n++;
662     return n;
663 }
664
665 AP_DECLARE(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop)
666 {
667     return ap_getword(atrans, (const char **) line, stop);
668 }
669
670 AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop)
671 {
672     const char *pos = *line;
673     int len;
674     char *res;
675
676     while ((*pos != stop) && *pos) {
677         ++pos;
678     }
679
680     len = pos - *line;
681     res = apr_pstrmemdup(atrans, *line, len);
682
683     if (stop) {
684         while (*pos == stop) {
685             ++pos;
686         }
687     }
688     *line = pos;
689
690     return res;
691 }
692
693 AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
694 {
695     return ap_getword_white(atrans, (const char **) line);
696 }
697
698 AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
699 {
700     const char *pos = *line;
701     int len;
702     char *res;
703
704     while (!apr_isspace(*pos) && *pos) {
705         ++pos;
706     }
707
708     len = pos - *line;
709     res = apr_pstrmemdup(atrans, *line, len);
710
711     while (apr_isspace(*pos)) {
712         ++pos;
713     }
714
715     *line = pos;
716
717     return res;
718 }
719
720 AP_DECLARE(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line,
721                                        char stop)
722 {
723     return ap_getword_nulls(atrans, (const char **) line, stop);
724 }
725
726 AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line,
727                                     char stop)
728 {
729     const char *pos = ap_strchr_c(*line, stop);
730     char *res;
731
732     if (!pos) {
733         apr_size_t len = strlen(*line);
734         res = apr_pstrmemdup(atrans, *line, len);
735         *line += len;
736         return res;
737     }
738
739     res = apr_pstrmemdup(atrans, *line, pos - *line);
740
741     ++pos;
742
743     *line = pos;
744
745     return res;
746 }
747
748 /* Get a word, (new) config-file style --- quoted strings and backslashes
749  * all honored
750  */
751
752 static char *substring_conf(apr_pool_t *p, const char *start, int len,
753                             char quote)
754 {
755     char *result = apr_palloc(p, len + 1);
756     char *resp = result;
757     int i;
758
759     for (i = 0; i < len; ++i) {
760         if (start[i] == '\\' && (start[i + 1] == '\\'
761                                  || (quote && start[i + 1] == quote)))
762             *resp++ = start[++i];
763         else
764             *resp++ = start[i];
765     }
766
767     *resp++ = '\0';
768 #if RESOLVE_ENV_PER_TOKEN
769     return (char *)ap_resolve_env(p,result);
770 #else
771     return result;
772 #endif
773 }
774
775 AP_DECLARE(char *) ap_getword_conf_nc(apr_pool_t *p, char **line)
776 {
777     return ap_getword_conf(p, (const char **) line);
778 }
779
780 AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line)
781 {
782     const char *str = *line, *strend;
783     char *res;
784     char quote;
785
786     while (apr_isspace(*str))
787         ++str;
788
789     if (!*str) {
790         *line = str;
791         return "";
792     }
793
794     if ((quote = *str) == '"' || quote == '\'') {
795         strend = str + 1;
796         while (*strend && *strend != quote) {
797             if (*strend == '\\' && strend[1] &&
798                 (strend[1] == quote || strend[1] == '\\')) {
799                 strend += 2;
800             }
801             else {
802                 ++strend;
803             }
804         }
805         res = substring_conf(p, str + 1, strend - str - 1, quote);
806
807         if (*strend == quote)
808             ++strend;
809     }
810     else {
811         strend = str;
812         while (*strend && !apr_isspace(*strend))
813             ++strend;
814
815         res = substring_conf(p, str, strend - str, 0);
816     }
817
818     while (apr_isspace(*strend))
819         ++strend;
820     *line = strend;
821     return res;
822 }
823
824 AP_DECLARE(char *) ap_getword_conf2_nc(apr_pool_t *p, char **line)
825 {
826     return ap_getword_conf2(p, (const char **) line);
827 }
828
829 AP_DECLARE(char *) ap_getword_conf2(apr_pool_t *p, const char **line)
830 {
831     const char *str = *line, *strend;
832     char *res;
833     char quote;
834     int count = 1;
835
836     while (apr_isspace(*str))
837         ++str;
838
839     if (!*str) {
840         *line = str;
841         return "";
842     }
843
844     if ((quote = *str) == '"' || quote == '\'')
845         return ap_getword_conf(p, line);
846
847     if (quote == '{') {
848         strend = str + 1;
849         while (*strend) {
850             if (*strend == '}' && !--count)
851                 break;
852             if (*strend == '{')
853                 ++count;
854             if (*strend == '\\' && strend[1] && strend[1] == '\\') {
855                 ++strend;
856             }
857             ++strend;
858         }
859         res = substring_conf(p, str + 1, strend - str - 1, 0);
860
861         if (*strend == '}')
862             ++strend;
863     }
864     else {
865         strend = str;
866         while (*strend && !apr_isspace(*strend))
867             ++strend;
868
869         res = substring_conf(p, str, strend - str, 0);
870     }
871
872     while (apr_isspace(*strend))
873         ++strend;
874     *line = strend;
875     return res;
876 }
877
878 AP_DECLARE(int) ap_cfg_closefile(ap_configfile_t *cfp)
879 {
880 #ifdef DEBUG
881     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00551)
882         "Done with config file %s", cfp->name);
883 #endif
884     return (cfp->close == NULL) ? 0 : cfp->close(cfp->param);
885 }
886
887 /* we can't use apr_file_* directly because of linking issues on Windows */
888 static apr_status_t cfg_close(void *param)
889 {
890     return apr_file_close(param);
891 }
892
893 static apr_status_t cfg_getch(char *ch, void *param)
894 {
895     return apr_file_getc(ch, param);
896 }
897
898 static apr_status_t cfg_getstr(void *buf, apr_size_t bufsiz, void *param)
899 {
900     return apr_file_gets(buf, bufsiz, param);
901 }
902
903 /* Open a ap_configfile_t as FILE, return open ap_configfile_t struct pointer */
904 AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg,
905                                           apr_pool_t *p, const char *name)
906 {
907     ap_configfile_t *new_cfg;
908     apr_file_t *file = NULL;
909     apr_finfo_t finfo;
910     apr_status_t status;
911 #ifdef DEBUG
912     char buf[120];
913 #endif
914
915     if (name == NULL) {
916         ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00552)
917                "Internal error: pcfg_openfile() called with NULL filename");
918         return APR_EBADF;
919     }
920
921     status = apr_file_open(&file, name, APR_READ | APR_BUFFERED,
922                            APR_OS_DEFAULT, p);
923 #ifdef DEBUG
924     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00553)
925                 "Opening config file %s (%s)",
926                 name, (status != APR_SUCCESS) ?
927                 apr_strerror(status, buf, sizeof(buf)) : "successful");
928 #endif
929     if (status != APR_SUCCESS)
930         return status;
931
932     status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file);
933     if (status != APR_SUCCESS)
934         return status;
935
936     if (finfo.filetype != APR_REG &&
937 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
938         ap_cstr_casecmp(apr_filepath_name_get(name), "nul") != 0) {
939 #else
940         strcmp(name, "/dev/null") != 0) {
941 #endif /* WIN32 || OS2 */
942         ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00554)
943                      "Access to file %s denied by server: not a regular file",
944                      name);
945         apr_file_close(file);
946         return APR_EBADF;
947     }
948
949 #ifdef WIN32
950     /* Some twisted character [no pun intended] at MS decided that a
951      * zero width joiner as the lead wide character would be ideal for
952      * describing Unicode text files.  This was further convoluted to
953      * another MSism that the same character mapped into utf-8, EF BB BF
954      * would signify utf-8 text files.
955      *
956      * Since MS configuration files are all protecting utf-8 encoded
957      * Unicode path, file and resource names, we already have the correct
958      * WinNT encoding.  But at least eat the stupid three bytes up front.
959      */
960     {
961         unsigned char buf[4];
962         apr_size_t len = 3;
963         status = apr_file_read(file, buf, &len);
964         if ((status != APR_SUCCESS) || (len < 3)
965               || memcmp(buf, "\xEF\xBB\xBF", 3) != 0) {
966             apr_off_t zero = 0;
967             apr_file_seek(file, APR_SET, &zero);
968         }
969     }
970 #endif
971
972     new_cfg = apr_palloc(p, sizeof(*new_cfg));
973     new_cfg->param = file;
974     new_cfg->name = apr_pstrdup(p, name);
975     new_cfg->getch = cfg_getch;
976     new_cfg->getstr = cfg_getstr;
977     new_cfg->close = cfg_close;
978     new_cfg->line_number = 0;
979     *ret_cfg = new_cfg;
980     return APR_SUCCESS;
981 }
982
983
984 /* Allocate a ap_configfile_t handle with user defined functions and params */
985 AP_DECLARE(ap_configfile_t *) ap_pcfg_open_custom(
986             apr_pool_t *p, const char *descr, void *param,
987             apr_status_t (*getc_func) (char *ch, void *param),
988             apr_status_t (*gets_func) (void *buf, apr_size_t bufsize, void *param),
989             apr_status_t (*close_func) (void *param))
990 {
991     ap_configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg));
992     new_cfg->param = param;
993     new_cfg->name = descr;
994     new_cfg->getch = getc_func;
995     new_cfg->getstr = gets_func;
996     new_cfg->close = close_func;
997     new_cfg->line_number = 0;
998     return new_cfg;
999 }
1000
1001 /* Read one character from a configfile_t */
1002 AP_DECLARE(apr_status_t) ap_cfg_getc(char *ch, ap_configfile_t *cfp)
1003 {
1004     apr_status_t rc = cfp->getch(ch, cfp->param);
1005     if (rc == APR_SUCCESS && *ch == LF)
1006         ++cfp->line_number;
1007     return rc;
1008 }
1009
1010 AP_DECLARE(const char *) ap_pcfg_strerror(apr_pool_t *p, ap_configfile_t *cfp,
1011                                           apr_status_t rc)
1012 {
1013     if (rc == APR_SUCCESS)
1014         return NULL;
1015
1016     if (rc == APR_ENOSPC)
1017         return apr_psprintf(p, "Error reading %s at line %d: Line too long",
1018                             cfp->name, cfp->line_number);
1019
1020     return apr_psprintf(p, "Error reading %s at line %d: %pm",
1021                         cfp->name, cfp->line_number, &rc);
1022 }
1023
1024 /* Read one line from open ap_configfile_t, strip LF, increase line number */
1025 /* If custom handler does not define a getstr() function, read char by char */
1026 static apr_status_t ap_cfg_getline_core(char *buf, apr_size_t bufsize,
1027                                         apr_size_t offset, ap_configfile_t *cfp)
1028 {
1029     apr_status_t rc;
1030     /* If a "get string" function is defined, use it */
1031     if (cfp->getstr != NULL) {
1032         char *cp;
1033         char *cbuf = buf + offset;
1034         apr_size_t cbufsize = bufsize - offset;
1035
1036         while (1) {
1037             ++cfp->line_number;
1038             rc = cfp->getstr(cbuf, cbufsize, cfp->param);
1039             if (rc == APR_EOF) {
1040                 if (cbuf != buf + offset) {
1041                     *cbuf = '\0';
1042                     break;
1043                 }
1044                 else {
1045                     return APR_EOF;
1046                 }
1047             }
1048             if (rc != APR_SUCCESS) {
1049                 return rc;
1050             }
1051
1052             /*
1053              *  check for line continuation,
1054              *  i.e. match [^\\]\\[\r]\n only
1055              */
1056             cp = cbuf;
1057             cp += strlen(cp);
1058             if (cp > buf && cp[-1] == LF) {
1059                 cp--;
1060                 if (cp > buf && cp[-1] == CR)
1061                     cp--;
1062                 if (cp > buf && cp[-1] == '\\') {
1063                     cp--;
1064                     /*
1065                      * line continuation requested -
1066                      * then remove backslash and continue
1067                      */
1068                     cbufsize -= (cp-cbuf);
1069                     cbuf = cp;
1070                     continue;
1071                 }
1072             }
1073             else if (cp - buf >= bufsize - 1) {
1074                 return APR_ENOSPC;
1075             }
1076             break;
1077         }
1078     } else {
1079         /* No "get string" function defined; read character by character */
1080         apr_size_t i = offset;
1081
1082         if (bufsize < 2) {
1083             /* too small, assume caller is crazy */
1084             return APR_EINVAL;
1085         }
1086         buf[offset] = '\0';
1087
1088         while (1) {
1089             char c;
1090             rc = cfp->getch(&c, cfp->param);
1091             if (rc == APR_EOF) {
1092                 if (i > offset)
1093                     break;
1094                 else
1095                     return APR_EOF;
1096             }
1097             if (rc != APR_SUCCESS)
1098                 return rc;
1099             if (c == LF) {
1100                 ++cfp->line_number;
1101                 /* check for line continuation */
1102                 if (i > 0 && buf[i-1] == '\\') {
1103                     i--;
1104                     continue;
1105                 }
1106                 else {
1107                     break;
1108                 }
1109             }
1110             buf[i] = c;
1111             ++i;
1112             if (i >= bufsize - 1) {
1113                 return APR_ENOSPC;
1114             }
1115         }
1116         buf[i] = '\0';
1117     }
1118     return APR_SUCCESS;
1119 }
1120
1121 static int cfg_trim_line(char *buf)
1122 {
1123     char *start, *end;
1124     /*
1125      * Leading and trailing white space is eliminated completely
1126      */
1127     start = buf;
1128     while (apr_isspace(*start))
1129         ++start;
1130     /* blast trailing whitespace */
1131     end = &start[strlen(start)];
1132     while (--end >= start && apr_isspace(*end))
1133         *end = '\0';
1134     /* Zap leading whitespace by shifting */
1135     if (start != buf)
1136         memmove(buf, start, end - start + 2);
1137 #ifdef DEBUG_CFG_LINES
1138     ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, APLOGNO(00555) "Read config: '%s'", buf);
1139 #endif
1140     return end - start + 1;
1141 }
1142
1143 /* Read one line from open ap_configfile_t, strip LF, increase line number */
1144 /* If custom handler does not define a getstr() function, read char by char */
1145 AP_DECLARE(apr_status_t) ap_cfg_getline(char *buf, apr_size_t bufsize,
1146                                         ap_configfile_t *cfp)
1147 {
1148     apr_status_t rc = ap_cfg_getline_core(buf, bufsize, 0, cfp);
1149     if (rc == APR_SUCCESS)
1150         cfg_trim_line(buf);
1151     return rc;
1152 }
1153
1154 AP_DECLARE(apr_status_t) ap_varbuf_cfg_getline(struct ap_varbuf *vb,
1155                                                ap_configfile_t *cfp,
1156                                                apr_size_t max_len)
1157 {
1158     apr_status_t rc;
1159     apr_size_t new_len;
1160     vb->strlen = 0;
1161     *vb->buf = '\0';
1162
1163     if (vb->strlen == AP_VARBUF_UNKNOWN)
1164         vb->strlen = strlen(vb->buf);
1165     if (vb->avail - vb->strlen < 3) {
1166         new_len = vb->avail * 2;
1167         if (new_len > max_len)
1168             new_len = max_len;
1169         else if (new_len < 3)
1170             new_len = 3;
1171         ap_varbuf_grow(vb, new_len);
1172     }
1173
1174     for (;;) {
1175         rc = ap_cfg_getline_core(vb->buf, vb->avail, vb->strlen, cfp);
1176         if (rc == APR_ENOSPC || rc == APR_SUCCESS)
1177             vb->strlen += strlen(vb->buf + vb->strlen);
1178         if (rc != APR_ENOSPC)
1179             break;
1180         if (vb->avail >= max_len)
1181             return APR_ENOSPC;
1182         new_len = vb->avail * 2;
1183         if (new_len > max_len)
1184             new_len = max_len;
1185         ap_varbuf_grow(vb, new_len);
1186         --cfp->line_number;
1187     }
1188     if (vb->strlen > max_len)
1189         return APR_ENOSPC;
1190     if (rc == APR_SUCCESS)
1191         vb->strlen = cfg_trim_line(vb->buf);
1192     return rc;
1193 }
1194
1195 /* Size an HTTP header field list item, as separated by a comma.
1196  * The return value is a pointer to the beginning of the non-empty list item
1197  * within the original string (or NULL if there is none) and the address
1198  * of field is shifted to the next non-comma, non-whitespace character.
1199  * len is the length of the item excluding any beginning whitespace.
1200  */
1201 AP_DECLARE(const char *) ap_size_list_item(const char **field, int *len)
1202 {
1203     const unsigned char *ptr = (const unsigned char *)*field;
1204     const unsigned char *token;
1205     int in_qpair, in_qstr, in_com;
1206
1207     /* Find first non-comma, non-whitespace byte */
1208
1209     while (*ptr == ',' || apr_isspace(*ptr))
1210         ++ptr;
1211
1212     token = ptr;
1213
1214     /* Find the end of this item, skipping over dead bits */
1215
1216     for (in_qpair = in_qstr = in_com = 0;
1217          *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1218          ++ptr) {
1219
1220         if (in_qpair) {
1221             in_qpair = 0;
1222         }
1223         else {
1224             switch (*ptr) {
1225                 case '\\': in_qpair = 1;      /* quoted-pair         */
1226                            break;
1227                 case '"' : if (!in_com)       /* quoted string delim */
1228                                in_qstr = !in_qstr;
1229                            break;
1230                 case '(' : if (!in_qstr)      /* comment (may nest)  */
1231                                ++in_com;
1232                            break;
1233                 case ')' : if (in_com)        /* end comment         */
1234                                --in_com;
1235                            break;
1236                 default  : break;
1237             }
1238         }
1239     }
1240
1241     if ((*len = (ptr - token)) == 0) {
1242         *field = (const char *)ptr;
1243         return NULL;
1244     }
1245
1246     /* Advance field pointer to the next non-comma, non-white byte */
1247
1248     while (*ptr == ',' || apr_isspace(*ptr))
1249         ++ptr;
1250
1251     *field = (const char *)ptr;
1252     return (const char *)token;
1253 }
1254
1255 /* Retrieve an HTTP header field list item, as separated by a comma,
1256  * while stripping insignificant whitespace and lowercasing anything not in
1257  * a quoted string or comment.  The return value is a new string containing
1258  * the converted list item (or NULL if none) and the address pointed to by
1259  * field is shifted to the next non-comma, non-whitespace.
1260  */
1261 AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field)
1262 {
1263     const char *tok_start;
1264     const unsigned char *ptr;
1265     unsigned char *pos;
1266     char *token;
1267     int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
1268
1269     /* Find the beginning and maximum length of the list item so that
1270      * we can allocate a buffer for the new string and reset the field.
1271      */
1272     if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
1273         return NULL;
1274     }
1275     token = apr_palloc(p, tok_len + 1);
1276
1277     /* Scan the token again, but this time copy only the good bytes.
1278      * We skip extra whitespace and any whitespace around a '=', '/',
1279      * or ';' and lowercase normal characters not within a comment,
1280      * quoted-string or quoted-pair.
1281      */
1282     for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
1283          *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1284          ++ptr) {
1285
1286         if (in_qpair) {
1287             in_qpair = 0;
1288             *pos++ = *ptr;
1289         }
1290         else {
1291             switch (*ptr) {
1292                 case '\\': in_qpair = 1;
1293                            if (addspace == 1)
1294                                *pos++ = ' ';
1295                            *pos++ = *ptr;
1296                            addspace = 0;
1297                            break;
1298                 case '"' : if (!in_com)
1299                                in_qstr = !in_qstr;
1300                            if (addspace == 1)
1301                                *pos++ = ' ';
1302                            *pos++ = *ptr;
1303                            addspace = 0;
1304                            break;
1305                 case '(' : if (!in_qstr)
1306                                ++in_com;
1307                            if (addspace == 1)
1308                                *pos++ = ' ';
1309                            *pos++ = *ptr;
1310                            addspace = 0;
1311                            break;
1312                 case ')' : if (in_com)
1313                                --in_com;
1314                            *pos++ = *ptr;
1315                            addspace = 0;
1316                            break;
1317                 case ' ' :
1318                 case '\t': if (addspace)
1319                                break;
1320                            if (in_com || in_qstr)
1321                                *pos++ = *ptr;
1322                            else
1323                                addspace = 1;
1324                            break;
1325                 case '=' :
1326                 case '/' :
1327                 case ';' : if (!(in_com || in_qstr))
1328                                addspace = -1;
1329                            *pos++ = *ptr;
1330                            break;
1331                 default  : if (addspace == 1)
1332                                *pos++ = ' ';
1333                            *pos++ = (in_com || in_qstr) ? *ptr
1334                                                         : apr_tolower(*ptr);
1335                            addspace = 0;
1336                            break;
1337             }
1338         }
1339     }
1340     *pos = '\0';
1341
1342     return token;
1343 }
1344
1345 typedef enum ap_etag_e {
1346     AP_ETAG_NONE,
1347     AP_ETAG_WEAK,
1348     AP_ETAG_STRONG
1349 } ap_etag_e;
1350
1351 /* Find an item in canonical form (lowercase, no extra spaces) within
1352  * an HTTP field value list.  Returns 1 if found, 0 if not found.
1353  * This would be much more efficient if we stored header fields as
1354  * an array of list items as they are received instead of a plain string.
1355  */
1356 static int find_list_item(apr_pool_t *p, const char *line,
1357                                   const char *tok, ap_etag_e type)
1358 {
1359     const unsigned char *pos;
1360     const unsigned char *ptr = (const unsigned char *)line;
1361     int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
1362
1363     if (!line || !tok) {
1364         return 0;
1365     }
1366     if (type == AP_ETAG_STRONG && *tok != '\"') {
1367         return 0;
1368     }
1369     if (type == AP_ETAG_WEAK) {
1370         if (*tok == 'W' && (*(tok+1)) == '/' && (*(tok+2)) == '\"') {
1371             tok += 2;
1372         }
1373         else if (*tok != '\"') {
1374             return 0;
1375         }
1376     }
1377
1378     do {  /* loop for each item in line's list */
1379
1380         /* Find first non-comma, non-whitespace byte */
1381         while (*ptr == ',' || apr_isspace(*ptr)) {
1382             ++ptr;
1383         }
1384
1385         /* Account for strong or weak Etags, depending on our search */
1386         if (type == AP_ETAG_STRONG && *ptr != '\"') {
1387             break;
1388         }
1389         if (type == AP_ETAG_WEAK) {
1390             if (*ptr == 'W' && (*(ptr+1)) == '/' && (*(ptr+2)) == '\"') {
1391                 ptr += 2;
1392             }
1393             else if (*ptr != '\"') {
1394                 break;
1395             }
1396         }
1397
1398         if (*ptr)
1399             good = 1;  /* until proven otherwise for this item */
1400         else
1401             break;     /* no items left and nothing good found */
1402
1403         /* We skip extra whitespace and any whitespace around a '=', '/',
1404          * or ';' and lowercase normal characters not within a comment,
1405          * quoted-string or quoted-pair.
1406          */
1407         for (pos = (const unsigned char *)tok;
1408              *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1409              ++ptr) {
1410
1411             if (in_qpair) {
1412                 in_qpair = 0;
1413                 if (good)
1414                     good = (*pos++ == *ptr);
1415             }
1416             else {
1417                 switch (*ptr) {
1418                     case '\\': in_qpair = 1;
1419                                if (addspace == 1)
1420                                    good = good && (*pos++ == ' ');
1421                                good = good && (*pos++ == *ptr);
1422                                addspace = 0;
1423                                break;
1424                     case '"' : if (!in_com)
1425                                    in_qstr = !in_qstr;
1426                                if (addspace == 1)
1427                                    good = good && (*pos++ == ' ');
1428                                good = good && (*pos++ == *ptr);
1429                                addspace = 0;
1430                                break;
1431                     case '(' : if (!in_qstr)
1432                                    ++in_com;
1433                                if (addspace == 1)
1434                                    good = good && (*pos++ == ' ');
1435                                good = good && (*pos++ == *ptr);
1436                                addspace = 0;
1437                                break;
1438                     case ')' : if (in_com)
1439                                    --in_com;
1440                                good = good && (*pos++ == *ptr);
1441                                addspace = 0;
1442                                break;
1443                     case ' ' :
1444                     case '\t': if (addspace || !good)
1445                                    break;
1446                                if (in_com || in_qstr)
1447                                    good = (*pos++ == *ptr);
1448                                else
1449                                    addspace = 1;
1450                                break;
1451                     case '=' :
1452                     case '/' :
1453                     case ';' : if (!(in_com || in_qstr))
1454                                    addspace = -1;
1455                                good = good && (*pos++ == *ptr);
1456                                break;
1457                     default  : if (!good)
1458                                    break;
1459                                if (addspace == 1)
1460                                    good = (*pos++ == ' ');
1461                                if (in_com || in_qstr)
1462                                    good = good && (*pos++ == *ptr);
1463                                else
1464                                    good = good
1465                                        && (apr_tolower(*pos++) == apr_tolower(*ptr));
1466                                addspace = 0;
1467                                break;
1468                 }
1469             }
1470         }
1471         if (good && *pos)
1472             good = 0;          /* not good if only a prefix was matched */
1473
1474     } while (*ptr && !good);
1475
1476     return good;
1477 }
1478
1479 /* Find an item in canonical form (lowercase, no extra spaces) within
1480  * an HTTP field value list.  Returns 1 if found, 0 if not found.
1481  * This would be much more efficient if we stored header fields as
1482  * an array of list items as they are received instead of a plain string.
1483  */
1484 AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line,
1485                                   const char *tok)
1486 {
1487     return find_list_item(p, line, tok, AP_ETAG_NONE);
1488 }
1489
1490 /* Find a strong Etag in canonical form (lowercase, no extra spaces) within
1491  * an HTTP field value list.  Returns 1 if found, 0 if not found.
1492  */
1493 AP_DECLARE(int) ap_find_etag_strong(apr_pool_t *p, const char *line,
1494                                     const char *tok)
1495 {
1496     return find_list_item(p, line, tok, AP_ETAG_STRONG);
1497 }
1498
1499 /* Find a weak ETag in canonical form (lowercase, no extra spaces) within
1500  * an HTTP field value list.  Returns 1 if found, 0 if not found.
1501  */
1502 AP_DECLARE(int) ap_find_etag_weak(apr_pool_t *p, const char *line,
1503                                   const char *tok)
1504 {
1505     return find_list_item(p, line, tok, AP_ETAG_WEAK);
1506 }
1507
1508 /* Grab a list of tokens of the format 1#token (from RFC7230) */
1509 AP_DECLARE(const char *) ap_parse_token_list_strict(apr_pool_t *p,
1510                                                 const char *str_in,
1511                                                 apr_array_header_t **tokens,
1512                                                 int skip_invalid)
1513 {
1514     int in_leading_space = 1;
1515     int in_trailing_space = 0;
1516     int string_end = 0;
1517     const char *tok_begin;
1518     const char *cur;
1519
1520     if (!str_in) {
1521         return NULL;
1522     }
1523
1524     tok_begin = cur = str_in;
1525
1526     while (!string_end) {
1527         const unsigned char c = (unsigned char)*cur;
1528
1529         if (!TEST_CHAR(c, T_HTTP_TOKEN_STOP)) {
1530             /* Non-separator character; we are finished with leading
1531              * whitespace. We must never have encountered any trailing
1532              * whitespace before the delimiter (comma) */
1533             in_leading_space = 0;
1534             if (in_trailing_space) {
1535                 return "Encountered illegal whitespace in token";
1536             }
1537         }
1538         else if (c == ' ' || c == '\t') {
1539             /* "Linear whitespace" only includes ASCII CRLF, space, and tab;
1540              * we can't get a CRLF since headers are split on them already,
1541              * so only look for a space or a tab */
1542             if (in_leading_space) {
1543                 /* We're still in leading whitespace */
1544                 ++tok_begin;
1545             }
1546             else {
1547                 /* We must be in trailing whitespace */
1548                 ++in_trailing_space;
1549             }
1550         }
1551         else if (c == ',' || c == '\0') {
1552             if (!in_leading_space) {
1553                 /* If we're out of the leading space, we know we've read some
1554                  * characters of a token */
1555                 if (*tokens == NULL) {
1556                     *tokens = apr_array_make(p, 4, sizeof(char *));
1557                 }
1558                 APR_ARRAY_PUSH(*tokens, char *) =
1559                     apr_pstrmemdup((*tokens)->pool, tok_begin,
1560                                    (cur - tok_begin) - in_trailing_space);
1561             }
1562             /* We're allowed to have null elements, just don't add them to the
1563              * array */
1564
1565             tok_begin = cur + 1;
1566             in_leading_space = 1;
1567             in_trailing_space = 0;
1568             string_end = (c == '\0');
1569         }
1570         else {
1571             /* Encountered illegal separator char */
1572             if (skip_invalid) {
1573                 /* Skip to the next separator */
1574                 const char *temp;
1575                 temp = ap_strchr_c(cur, ',');
1576                 if(!temp) {
1577                     temp = ap_strchr_c(cur, '\0');
1578                 }
1579
1580                 /* Act like we haven't seen a token so we reset */
1581                 cur = temp - 1;
1582                 in_leading_space = 1;
1583                 in_trailing_space = 0;
1584             }
1585             else {
1586                 return apr_psprintf(p, "Encountered illegal separator "
1587                                     "'\\x%.2x'", (unsigned int)c);
1588             }
1589         }
1590
1591         ++cur;
1592     }
1593
1594     return NULL;
1595 }
1596
1597 /* Scan a string for HTTP VCHAR/obs-text characters including HT and SP
1598  * (as used in header values, for example, in RFC 7230 section 3.2)
1599  * returning the pointer to the first non-HT ASCII ctrl character.
1600  */
1601 AP_DECLARE(const char *) ap_scan_http_field_content(const char *ptr)
1602 {
1603     for ( ; !TEST_CHAR(*ptr, T_HTTP_CTRLS); ++ptr) ;
1604
1605     return ptr;
1606 }
1607
1608 /* Scan a string for HTTP token characters, returning the pointer to
1609  * the first non-token character.
1610  */
1611 AP_DECLARE(const char *) ap_scan_http_token(const char *ptr)
1612 {
1613     for ( ; !TEST_CHAR(*ptr, T_HTTP_TOKEN_STOP); ++ptr) ;
1614
1615     return ptr;
1616 }
1617
1618 /* Scan a string for visible ASCII (0x21-0x7E) or obstext (0x80+)
1619  * and return a pointer to the first ctrl/space character encountered.
1620  */
1621 AP_DECLARE(const char *) ap_scan_vchar_obstext(const char *ptr)
1622 {
1623     for ( ; TEST_CHAR(*ptr, T_VCHAR_OBSTEXT); ++ptr) ;
1624
1625     return ptr;
1626 }
1627
1628 /* Retrieve a token, spacing over it and returning a pointer to
1629  * the first non-white byte afterwards.  Note that these tokens
1630  * are delimited by semis and commas; and can also be delimited
1631  * by whitespace at the caller's option.
1632  */
1633
1634 AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line,
1635                                 int accept_white)
1636 {
1637     const char *ptr = *accept_line;
1638     const char *tok_start;
1639     char *token;
1640
1641     /* Find first non-white byte */
1642
1643     while (apr_isspace(*ptr))
1644         ++ptr;
1645
1646     tok_start = ptr;
1647
1648     /* find token end, skipping over quoted strings.
1649      * (comments are already gone).
1650      */
1651
1652     while (*ptr && (accept_white || !apr_isspace(*ptr))
1653            && *ptr != ';' && *ptr != ',') {
1654         if (*ptr++ == '"')
1655             while (*ptr)
1656                 if (*ptr++ == '"')
1657                     break;
1658     }
1659
1660     token = apr_pstrmemdup(p, tok_start, ptr - tok_start);
1661
1662     /* Advance accept_line pointer to the next non-white byte */
1663
1664     while (apr_isspace(*ptr))
1665         ++ptr;
1666
1667     *accept_line = ptr;
1668     return token;
1669 }
1670
1671
1672 /* find http tokens, see the definition of token from RFC2068 */
1673 AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
1674 {
1675     const unsigned char *start_token;
1676     const unsigned char *s;
1677
1678     if (!line)
1679         return 0;
1680
1681     s = (const unsigned char *)line;
1682     for (;;) {
1683         /* find start of token, skip all stop characters, note NUL
1684          * isn't a token stop, so we don't need to test for it
1685          */
1686         while (TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1687             ++s;
1688         }
1689         if (!*s) {
1690             return 0;
1691         }
1692         start_token = s;
1693         /* find end of the token */
1694         while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1695             ++s;
1696         }
1697         if (!ap_cstr_casecmpn((const char *)start_token, (const char *)tok,
1698                          s - start_token)) {
1699             return 1;
1700         }
1701         if (!*s) {
1702             return 0;
1703         }
1704     }
1705 }
1706
1707
1708 AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line,
1709                                    const char *tok)
1710 {
1711     int llen, tlen, lidx;
1712
1713     if (!line)
1714         return 0;
1715
1716     llen = strlen(line);
1717     tlen = strlen(tok);
1718     lidx = llen - tlen;
1719
1720     if (lidx < 0 ||
1721         (lidx > 0 && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1722         return 0;
1723
1724     return (ap_cstr_casecmpn(&line[lidx], tok, tlen) == 0);
1725 }
1726
1727 AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1728 {
1729     char *cmd;
1730     unsigned char *d;
1731     const unsigned char *s;
1732
1733     cmd = apr_palloc(p, 2 * strlen(str) + 1);        /* Be safe */
1734     d = (unsigned char *)cmd;
1735     s = (const unsigned char *)str;
1736     for (; *s; ++s) {
1737
1738 #if defined(OS2) || defined(WIN32)
1739         /*
1740          * Newlines to Win32/OS2 CreateProcess() are ill advised.
1741          * Convert them to spaces since they are effectively white
1742          * space to most applications
1743          */
1744         if (*s == '\r' || *s == '\n') {
1745              *d++ = ' ';
1746              continue;
1747          }
1748 #endif
1749
1750         if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1751             *d++ = '\\';
1752         }
1753         *d++ = *s;
1754     }
1755     *d = '\0';
1756
1757     return cmd;
1758 }
1759
1760 static char x2c(const char *what)
1761 {
1762     char digit;
1763
1764 #if !APR_CHARSET_EBCDIC
1765     digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
1766              : (what[0] - '0'));
1767     digit *= 16;
1768     digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
1769               : (what[1] - '0'));
1770 #else /*APR_CHARSET_EBCDIC*/
1771     char xstr[5];
1772     xstr[0]='0';
1773     xstr[1]='x';
1774     xstr[2]=what[0];
1775     xstr[3]=what[1];
1776     xstr[4]='\0';
1777     digit = apr_xlate_conv_byte(ap_hdrs_from_ascii,
1778                                 0xFF & strtol(xstr, NULL, 16));
1779 #endif /*APR_CHARSET_EBCDIC*/
1780     return (digit);
1781 }
1782
1783 /*
1784  * Unescapes a URL, leaving reserved characters intact.
1785  * Returns 0 on success, non-zero on error
1786  * Failure is due to
1787  *   bad % escape       returns HTTP_BAD_REQUEST
1788  *
1789  *   decoding %00 or a forbidden character returns HTTP_NOT_FOUND
1790  */
1791
1792 static int unescape_url(char *url, const char *forbid, const char *reserved)
1793 {
1794     int badesc, badpath;
1795     char *x, *y;
1796
1797     badesc = 0;
1798     badpath = 0;
1799     /* Initial scan for first '%'. Don't bother writing values before
1800      * seeing a '%' */
1801     y = strchr(url, '%');
1802     if (y == NULL) {
1803         return OK;
1804     }
1805     for (x = y; *y; ++x, ++y) {
1806         if (*y != '%') {
1807             *x = *y;
1808         }
1809         else {
1810             if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1811                 badesc = 1;
1812                 *x = '%';
1813             }
1814             else {
1815                 char decoded;
1816                 decoded = x2c(y + 1);
1817                 if ((decoded == '\0')
1818                     || (forbid && ap_strchr_c(forbid, decoded))) {
1819                     badpath = 1;
1820                     *x = decoded;
1821                     y += 2;
1822                 }
1823                 else if (reserved && ap_strchr_c(reserved, decoded)) {
1824                     *x++ = *y++;
1825                     *x++ = *y++;
1826                     *x = *y;
1827                 }
1828                 else {
1829                     *x = decoded;
1830                     y += 2;
1831                 }
1832             }
1833         }
1834     }
1835     *x = '\0';
1836     if (badesc) {
1837         return HTTP_BAD_REQUEST;
1838     }
1839     else if (badpath) {
1840         return HTTP_NOT_FOUND;
1841     }
1842     else {
1843         return OK;
1844     }
1845 }
1846 AP_DECLARE(int) ap_unescape_url(char *url)
1847 {
1848     /* Traditional */
1849     return unescape_url(url, SLASHES, NULL);
1850 }
1851 AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes)
1852 {
1853     /* AllowEncodedSlashes (corrected) */
1854     if (decode_slashes) {
1855         /* no chars reserved */
1856         return unescape_url(url, NULL, NULL);
1857     } else {
1858         /* reserve (do not decode) encoded slashes */
1859         return unescape_url(url, NULL, SLASHES);
1860     }
1861 }
1862 #ifdef NEW_APIS
1863 /* IFDEF these out until they've been thought through.
1864  * Just a germ of an API extension for now
1865  */
1866 AP_DECLARE(int) ap_unescape_url_proxy(char *url)
1867 {
1868     /* leave RFC1738 reserved characters intact, * so proxied URLs
1869      * don't get mangled.  Where does that leave encoded '&' ?
1870      */
1871     return unescape_url(url, NULL, "/;?");
1872 }
1873 AP_DECLARE(int) ap_unescape_url_reserved(char *url, const char *reserved)
1874 {
1875     return unescape_url(url, NULL, reserved);
1876 }
1877 #endif
1878
1879 AP_DECLARE(int) ap_unescape_urlencoded(char *query)
1880 {
1881     char *slider;
1882
1883     /* replace plus with a space */
1884     if (query) {
1885         for (slider = query; *slider; slider++) {
1886             if (*slider == '+') {
1887                 *slider = ' ';
1888             }
1889         }
1890     }
1891
1892     /* unescape everything else */
1893     return unescape_url(query, NULL, NULL);
1894 }
1895
1896 AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname,
1897                                        apr_port_t port, const request_rec *r)
1898 {
1899     if (ap_is_default_port(port, r)) {
1900         return apr_pstrdup(p, hostname);
1901     }
1902     else {
1903         return apr_psprintf(p, "%s:%u", hostname, port);
1904     }
1905 }
1906
1907 AP_DECLARE(int) ap_unescape_all(char *url)
1908 {
1909     return unescape_url(url, NULL, NULL);
1910 }
1911
1912 /* c2x takes an unsigned, and expects the caller has guaranteed that
1913  * 0 <= what < 256... which usually means that you have to cast to
1914  * unsigned char first, because (unsigned)(char)(x) first goes through
1915  * signed extension to an int before the unsigned cast.
1916  *
1917  * The reason for this assumption is to assist gcc code generation --
1918  * the unsigned char -> unsigned extension is already done earlier in
1919  * both uses of this code, so there's no need to waste time doing it
1920  * again.
1921  */
1922 static const char c2x_table[] = "0123456789abcdef";
1923
1924 static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
1925                                      unsigned char *where)
1926 {
1927 #if APR_CHARSET_EBCDIC
1928     what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
1929 #endif /*APR_CHARSET_EBCDIC*/
1930     *where++ = prefix;
1931     *where++ = c2x_table[what >> 4];
1932     *where++ = c2x_table[what & 0xf];
1933     return where;
1934 }
1935
1936 /*
1937  * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
1938  * routine is (should be) OS independent.
1939  *
1940  * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
1941  * cases if a ':' occurs before the first '/' in the URL, the URL should be
1942  * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
1943  * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
1944  * efficiency reasons, we don't use escape_path_segment(), which is provided for
1945  * reference. Again, RFC 1808 is where this stuff is defined.
1946  *
1947  * If partial is set, os_escape_path() assumes that the path will be appended to
1948  * something with a '/' in it (and thus does not prefix "./").
1949  */
1950
1951 AP_DECLARE(char *) ap_escape_path_segment_buffer(char *copy, const char *segment)
1952 {
1953     const unsigned char *s = (const unsigned char *)segment;
1954     unsigned char *d = (unsigned char *)copy;
1955     unsigned c;
1956
1957     while ((c = *s)) {
1958         if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
1959             d = c2x(c, '%', d);
1960         }
1961         else {
1962             *d++ = c;
1963         }
1964         ++s;
1965     }
1966     *d = '\0';
1967     return copy;
1968 }
1969
1970 AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
1971 {
1972     return ap_escape_path_segment_buffer(apr_palloc(p, 3 * strlen(segment) + 1), segment);
1973 }
1974
1975 AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
1976 {
1977     /* Allocate +3 for potential "./" and trailing NULL.
1978      * Allocate another +1 to allow the caller to add a trailing '/' (see
1979      * comment in 'ap_sub_req_lookup_dirent')
1980      */
1981     char *copy = apr_palloc(p, 3 * strlen(path) + 3 + 1);
1982     const unsigned char *s = (const unsigned char *)path;
1983     unsigned char *d = (unsigned char *)copy;
1984     unsigned c;
1985
1986     if (!partial) {
1987         const char *colon = ap_strchr_c(path, ':');
1988         const char *slash = ap_strchr_c(path, '/');
1989
1990         if (colon && (!slash || colon < slash)) {
1991             *d++ = '.';
1992             *d++ = '/';
1993         }
1994     }
1995     while ((c = *s)) {
1996         if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
1997             d = c2x(c, '%', d);
1998         }
1999         else {
2000             *d++ = c;
2001         }
2002         ++s;
2003     }
2004     *d = '\0';
2005     return copy;
2006 }
2007
2008 AP_DECLARE(char *) ap_escape_urlencoded_buffer(char *copy, const char *buffer)
2009 {
2010     const unsigned char *s = (const unsigned char *)buffer;
2011     unsigned char *d = (unsigned char *)copy;
2012     unsigned c;
2013
2014     while ((c = *s)) {
2015         if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
2016             d = c2x(c, '%', d);
2017         }
2018         else if (c == ' ') {
2019             *d++ = '+';
2020         }
2021         else {
2022             *d++ = c;
2023         }
2024         ++s;
2025     }
2026     *d = '\0';
2027     return copy;
2028 }
2029
2030 AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
2031 {
2032     return ap_escape_urlencoded_buffer(apr_palloc(p, 3 * strlen(buffer) + 1), buffer);
2033 }
2034
2035 /* ap_escape_uri is now a macro for os_escape_path */
2036
2037 AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
2038 {
2039     int i, j;
2040     char *x;
2041
2042     /* first, count the number of extra characters */
2043     for (i = 0, j = 0; s[i] != '\0'; i++)
2044         if (s[i] == '<' || s[i] == '>')
2045             j += 3;
2046         else if (s[i] == '&')
2047             j += 4;
2048         else if (s[i] == '"')
2049             j += 5;
2050         else if (toasc && !apr_isascii(s[i]))
2051             j += 5;
2052
2053     if (j == 0)
2054         return apr_pstrmemdup(p, s, i);
2055
2056     x = apr_palloc(p, i + j + 1);
2057     for (i = 0, j = 0; s[i] != '\0'; i++, j++)
2058         if (s[i] == '<') {
2059             memcpy(&x[j], "&lt;", 4);
2060             j += 3;
2061         }
2062         else if (s[i] == '>') {
2063             memcpy(&x[j], "&gt;", 4);
2064             j += 3;
2065         }
2066         else if (s[i] == '&') {
2067             memcpy(&x[j], "&amp;", 5);
2068             j += 4;
2069         }
2070         else if (s[i] == '"') {
2071             memcpy(&x[j], "&quot;", 6);
2072             j += 5;
2073         }
2074         else if (toasc && !apr_isascii(s[i])) {
2075             char *esc = apr_psprintf(p, "&#%3.3d;", (unsigned char)s[i]);
2076             memcpy(&x[j], esc, 6);
2077             j += 5;
2078         }
2079         else
2080             x[j] = s[i];
2081
2082     x[j] = '\0';
2083     return x;
2084 }
2085 AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str)
2086 {
2087     char *ret;
2088     unsigned char *d;
2089     const unsigned char *s;
2090     apr_size_t length, escapes = 0;
2091
2092     if (!str) {
2093         return NULL;
2094     }
2095
2096     /* Compute how many characters need to be escaped */
2097     s = (const unsigned char *)str;
2098     for (; *s; ++s) {
2099         if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2100             escapes++;
2101         }
2102     }
2103     
2104     /* Compute the length of the input string, including NULL */
2105     length = s - (const unsigned char *)str + 1;
2106     
2107     /* Fast path: nothing to escape */
2108     if (escapes == 0) {
2109         return apr_pmemdup(p, str, length);
2110     }
2111     
2112     /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */
2113     ret = apr_palloc(p, length + 3 * escapes);
2114     d = (unsigned char *)ret;
2115     s = (const unsigned char *)str;
2116     for (; *s; ++s) {
2117         if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2118             *d++ = '\\';
2119             switch(*s) {
2120             case '\b':
2121                 *d++ = 'b';
2122                 break;
2123             case '\n':
2124                 *d++ = 'n';
2125                 break;
2126             case '\r':
2127                 *d++ = 'r';
2128                 break;
2129             case '\t':
2130                 *d++ = 't';
2131                 break;
2132             case '\v':
2133                 *d++ = 'v';
2134                 break;
2135             case '\\':
2136             case '"':
2137                 *d++ = *s;
2138                 break;
2139             default:
2140                 c2x(*s, 'x', d);
2141                 d += 3;
2142             }
2143         }
2144         else {
2145             *d++ = *s;
2146         }
2147     }
2148     *d = '\0';
2149
2150     return ret;
2151 }
2152
2153 AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
2154                                                apr_size_t buflen)
2155 {
2156     unsigned char *d, *ep;
2157     const unsigned char *s;
2158
2159     if (!source || !buflen) { /* be safe */
2160         return 0;
2161     }
2162
2163     d = (unsigned char *)dest;
2164     s = (const unsigned char *)source;
2165     ep = d + buflen - 1;
2166
2167     for (; d < ep && *s; ++s) {
2168
2169         if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2170             *d++ = '\\';
2171             if (d >= ep) {
2172                 --d;
2173                 break;
2174             }
2175
2176             switch(*s) {
2177             case '\b':
2178                 *d++ = 'b';
2179                 break;
2180             case '\n':
2181                 *d++ = 'n';
2182                 break;
2183             case '\r':
2184                 *d++ = 'r';
2185                 break;
2186             case '\t':
2187                 *d++ = 't';
2188                 break;
2189             case '\v':
2190                 *d++ = 'v';
2191                 break;
2192             case '\\':
2193                 *d++ = *s;
2194                 break;
2195             case '"': /* no need for this in error log */
2196                 d[-1] = *s;
2197                 break;
2198             default:
2199                 if (d >= ep - 2) {
2200                     ep = --d; /* break the for loop as well */
2201                     break;
2202                 }
2203                 c2x(*s, 'x', d);
2204                 d += 3;
2205             }
2206         }
2207         else {
2208             *d++ = *s;
2209         }
2210     }
2211     *d = '\0';
2212
2213     return (d - (unsigned char *)dest);
2214 }
2215
2216 AP_DECLARE(void) ap_bin2hex(const void *src, apr_size_t srclen, char *dest)
2217 {
2218     const unsigned char *in = src;
2219     apr_size_t i;
2220
2221     for (i = 0; i < srclen; i++) {
2222         *dest++ = c2x_table[in[i] >> 4];
2223         *dest++ = c2x_table[in[i] & 0xf];
2224     }
2225     *dest = '\0';
2226 }
2227
2228 AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
2229 {
2230     apr_finfo_t finfo;
2231
2232     if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS)
2233         return 0;                /* in error condition, just return no */
2234
2235     return (finfo.filetype == APR_DIR);
2236 }
2237
2238 AP_DECLARE(int) ap_is_rdirectory(apr_pool_t *p, const char *path)
2239 {
2240     apr_finfo_t finfo;
2241
2242     if (apr_stat(&finfo, path, APR_FINFO_LINK | APR_FINFO_TYPE, p) != APR_SUCCESS)
2243         return 0;                /* in error condition, just return no */
2244
2245     return (finfo.filetype == APR_DIR);
2246 }
2247
2248 AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
2249                                   const char *src2)
2250 {
2251     apr_size_t len1, len2;
2252     char *path;
2253
2254     len1 = strlen(src1);
2255     len2 = strlen(src2);
2256      /* allocate +3 for '/' delimiter, trailing NULL and overallocate
2257       * one extra byte to allow the caller to add a trailing '/'
2258       */
2259     path = (char *)apr_palloc(a, len1 + len2 + 3);
2260     if (len1 == 0) {
2261         *path = '/';
2262         memcpy(path + 1, src2, len2 + 1);
2263     }
2264     else {
2265         char *next;
2266         memcpy(path, src1, len1);
2267         next = path + len1;
2268         if (next[-1] != '/') {
2269             *next++ = '/';
2270         }
2271         memcpy(next, src2, len2 + 1);
2272     }
2273     return path;
2274 }
2275
2276 /*
2277  * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
2278  */
2279 AP_DECLARE(int) ap_is_url(const char *u)
2280 {
2281     int x;
2282
2283     for (x = 0; u[x] != ':'; x++) {
2284         if ((!u[x]) ||
2285             ((!apr_isalnum(u[x])) &&
2286              (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
2287             return 0;
2288         }
2289     }
2290
2291     return (x ? 1 : 0);                /* If the first character is ':', it's broken, too */
2292 }
2293
2294 AP_DECLARE(int) ap_ind(const char *s, char c)
2295 {
2296     const char *p = ap_strchr_c(s, c);
2297
2298     if (p == NULL)
2299         return -1;
2300     return p - s;
2301 }
2302
2303 AP_DECLARE(int) ap_rind(const char *s, char c)
2304 {
2305     const char *p = ap_strrchr_c(s, c);
2306
2307     if (p == NULL)
2308         return -1;
2309     return p - s;
2310 }
2311
2312 AP_DECLARE(void) ap_str_tolower(char *str)
2313 {
2314     while (*str) {
2315         *str = apr_tolower(*str);
2316         ++str;
2317     }
2318 }
2319
2320 AP_DECLARE(void) ap_str_toupper(char *str)
2321 {
2322     while (*str) {
2323         *str = apr_toupper(*str);
2324         ++str;
2325     }
2326 }
2327
2328 /*
2329  * We must return a FQDN
2330  */
2331 char *ap_get_local_host(apr_pool_t *a)
2332 {
2333 #ifndef MAXHOSTNAMELEN
2334 #define MAXHOSTNAMELEN 256
2335 #endif
2336     char str[MAXHOSTNAMELEN + 1];
2337     char *server_hostname = NULL;
2338     apr_sockaddr_t *sockaddr;
2339     char *hostname;
2340
2341     if (apr_gethostname(str, sizeof(str) - 1, a) != APR_SUCCESS) {
2342         ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00556)
2343                      "%s: apr_gethostname() failed to determine ServerName",
2344                      ap_server_argv0);
2345     } else {
2346         str[sizeof(str) - 1] = '\0';
2347         if (apr_sockaddr_info_get(&sockaddr, str, APR_UNSPEC, 0, 0, a) == APR_SUCCESS) {
2348             if ( (apr_getnameinfo(&hostname, sockaddr, 0) == APR_SUCCESS) &&
2349                 (ap_strchr_c(hostname, '.')) ) {
2350                 server_hostname = apr_pstrdup(a, hostname);
2351                 return server_hostname;
2352             } else if (ap_strchr_c(str, '.')) {
2353                 server_hostname = apr_pstrdup(a, str);
2354             } else {
2355                 apr_sockaddr_ip_get(&hostname, sockaddr);
2356                 server_hostname = apr_pstrdup(a, hostname);
2357             }
2358         } else {
2359             ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00557)
2360                          "%s: apr_sockaddr_info_get() failed for %s",
2361                          ap_server_argv0, str);
2362         }
2363     }
2364
2365     if (!server_hostname)
2366         server_hostname = apr_pstrdup(a, "127.0.0.1");
2367
2368     ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, a, APLOGNO(00558)
2369                  "%s: Could not reliably determine the server's fully qualified "
2370                  "domain name, using %s. Set the 'ServerName' directive globally "
2371                  "to suppress this message",
2372                  ap_server_argv0, server_hostname);
2373
2374     return server_hostname;
2375 }
2376
2377 /* simple 'pool' alloc()ing glue to apr_base64.c
2378  */
2379 AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
2380 {
2381     char *decoded;
2382     int l;
2383
2384     decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded));
2385     l = apr_base64_decode(decoded, bufcoded);
2386     decoded[l] = '\0'; /* make binary sequence into string */
2387
2388     return decoded;
2389 }
2390
2391 AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
2392 {
2393     char *encoded;
2394     int l = strlen(string);
2395
2396     encoded = (char *) apr_palloc(p, 1 + apr_base64_encode_len(l));
2397     l = apr_base64_encode(encoded, string, l);
2398     encoded[l] = '\0'; /* make binary sequence into string */
2399
2400     return encoded;
2401 }
2402
2403 /* we want to downcase the type/subtype for comparison purposes
2404  * but nothing else because ;parameter=foo values are case sensitive.
2405  * XXX: in truth we want to downcase parameter names... but really,
2406  * apache has never handled parameters and such correctly.  You
2407  * also need to compress spaces and such to be able to compare
2408  * properly. -djg
2409  */
2410 AP_DECLARE(void) ap_content_type_tolower(char *str)
2411 {
2412     char *semi;
2413
2414     semi = strchr(str, ';');
2415     if (semi) {
2416         *semi = '\0';
2417     }
2418
2419     ap_str_tolower(str);
2420
2421     if (semi) {
2422         *semi = ';';
2423     }
2424 }
2425
2426 /*
2427  * Given a string, replace any bare " with \" .
2428  */
2429 AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
2430 {
2431     int newlen = 0;
2432     const char *inchr = instring;
2433     char *outchr, *outstring;
2434
2435     /*
2436      * Look through the input string, jogging the length of the output
2437      * string up by an extra byte each time we find an unescaped ".
2438      */
2439     while (*inchr != '\0') {
2440         newlen++;
2441         if (*inchr == '"') {
2442             newlen++;
2443         }
2444         /*
2445          * If we find a slosh, and it's not the last byte in the string,
2446          * it's escaping something - advance past both bytes.
2447          */
2448         if ((*inchr == '\\') && (inchr[1] != '\0')) {
2449             inchr++;
2450             newlen++;
2451         }
2452         inchr++;
2453     }
2454     outstring = apr_palloc(p, newlen + 1);
2455     inchr = instring;
2456     outchr = outstring;
2457     /*
2458      * Now copy the input string to the output string, inserting a slosh
2459      * in front of every " that doesn't already have one.
2460      */
2461     while (*inchr != '\0') {
2462         if ((*inchr == '\\') && (inchr[1] != '\0')) {
2463             *outchr++ = *inchr++;
2464             *outchr++ = *inchr++;
2465         }
2466         if (*inchr == '"') {
2467             *outchr++ = '\\';
2468         }
2469         if (*inchr != '\0') {
2470             *outchr++ = *inchr++;
2471         }
2472     }
2473     *outchr = '\0';
2474     return outstring;
2475 }
2476
2477 /*
2478  * Given a string, append the PID deliminated by delim.
2479  * Usually used to create a pid-appended filepath name
2480  * (eg: /a/b/foo -> /a/b/foo.6726). A function, and not
2481  * a macro, to avoid unistd.h dependency
2482  */
2483 AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string,
2484                                     const char *delim)
2485 {
2486     return apr_psprintf(p, "%s%s%" APR_PID_T_FMT, string,
2487                         delim, getpid());
2488
2489 }
2490
2491 /**
2492  * Parse a given timeout parameter string into an apr_interval_time_t value.
2493  * The unit of the time interval is given as postfix string to the numeric
2494  * string. Currently the following units are understood:
2495  *
2496  * ms    : milliseconds
2497  * s     : seconds
2498  * mi[n] : minutes
2499  * h     : hours
2500  *
2501  * If no unit is contained in the given timeout parameter the default_time_unit
2502  * will be used instead.
2503  * @param timeout_parameter The string containing the timeout parameter.
2504  * @param timeout The timeout value to be returned.
2505  * @param default_time_unit The default time unit to use if none is specified
2506  * in timeout_parameter.
2507  * @return Status value indicating whether the parsing was successful or not.
2508  */
2509 AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
2510                                                const char *timeout_parameter,
2511                                                apr_interval_time_t *timeout,
2512                                                const char *default_time_unit)
2513 {
2514     char *endp;
2515     const char *time_str;
2516     apr_int64_t tout;
2517
2518     tout = apr_strtoi64(timeout_parameter, &endp, 10);
2519     if (errno) {
2520         return errno;
2521     }
2522     if (!endp || !*endp) {
2523         time_str = default_time_unit;
2524     }
2525     else {
2526         time_str = endp;
2527     }
2528
2529     switch (*time_str) {
2530         /* Time is in seconds */
2531     case 's':
2532         *timeout = (apr_interval_time_t) apr_time_from_sec(tout);
2533         break;
2534     case 'h':
2535         /* Time is in hours */
2536         *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 3600);
2537         break;
2538     case 'm':
2539         switch (*(++time_str)) {
2540         /* Time is in milliseconds */
2541         case 's':
2542             *timeout = (apr_interval_time_t) tout * 1000;
2543             break;
2544         /* Time is in minutes */
2545         case 'i':
2546             *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 60);
2547             break;
2548         default:
2549             return APR_EGENERAL;
2550         }
2551         break;
2552     default:
2553         return APR_EGENERAL;
2554     }
2555     return APR_SUCCESS;
2556 }
2557
2558 /**
2559  * Determine if a request has a request body or not.
2560  *
2561  * @param r the request_rec of the request
2562  * @return truth value
2563  */
2564 AP_DECLARE(int) ap_request_has_body(request_rec *r)
2565 {
2566     apr_off_t cl;
2567     char *estr;
2568     const char *cls;
2569     int has_body;
2570
2571     has_body = (!r->header_only
2572                 && (r->kept_body
2573                     || apr_table_get(r->headers_in, "Transfer-Encoding")
2574                     || ( (cls = apr_table_get(r->headers_in, "Content-Length"))
2575                         && (apr_strtoff(&cl, cls, &estr, 10) == APR_SUCCESS)
2576                         && (!*estr)
2577                         && (cl > 0) )
2578                     )
2579                 );
2580     return has_body;
2581 }
2582
2583 /**
2584  * Check whether a request is tainted by exposure to something
2585  * potentially untrusted.  
2586  *
2587  */
2588 AP_DECLARE(int) ap_request_tainted(request_rec *r, int flags)
2589 {
2590     /** Potential future: a hook or callback here could serve modules
2591      *  like mod_security and ironbee with more complex needs.
2592      */
2593     return r && ((r->taint&flags)
2594                  || ap_request_tainted(r->main, flags)
2595                  || ap_request_tainted(r->prev, flags));
2596 }
2597
2598 AP_DECLARE_NONSTD(apr_status_t) ap_pool_cleanup_set_null(void *data_)
2599 {
2600     void **ptr = (void **)data_;
2601     *ptr = NULL;
2602     return APR_SUCCESS;
2603 }
2604
2605 AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
2606
2607     for ( ; *src; src++, dest++)
2608     {
2609         if (!apr_isprint(*src))
2610             *dest = 'x';
2611         else if (!apr_isalnum(*src))
2612             *dest = '_';
2613         else
2614             *dest = (char)*src;
2615     }
2616     *dest = '\0';
2617     return APR_SUCCESS;
2618
2619 }
2620
2621 AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
2622                                         const char **dest)
2623 {
2624     char *new = apr_palloc(p, strlen(src)+1);
2625     if (!new)
2626         return APR_ENOMEM;
2627     *dest = new;
2628     return ap_str2_alnum(src, new);
2629 }
2630
2631 /**
2632  * Read the body and parse any form found, which must be of the
2633  * type application/x-www-form-urlencoded.
2634  *
2635  * Name/value pairs are returned in an array, with the names as
2636  * strings with a maximum length of HUGE_STRING_LEN, and the
2637  * values as bucket brigades. This allows values to be arbitrarily
2638  * large.
2639  *
2640  * All url-encoding is removed from both the names and the values
2641  * on the fly. The names are interpreted as strings, while the
2642  * values are interpreted as blocks of binary data, that may
2643  * contain the 0 character.
2644  *
2645  * In order to ensure that resource limits are not exceeded, a
2646  * maximum size must be provided. If the sum of the lengths of
2647  * the names and the values exceed this size, this function
2648  * will return HTTP_REQUEST_ENTITY_TOO_LARGE.
2649  *
2650  * An optional number of parameters can be provided, if the number
2651  * of parameters provided exceeds this amount, this function will
2652  * return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
2653  * no limit is imposed, and the number of parameters is in turn
2654  * constrained by the size parameter above.
2655  *
2656  * This function honours any kept_body configuration, and the
2657  * original raw request body will be saved to the kept_body brigade
2658  * if so configured, just as ap_discard_request_body does.
2659  *
2660  * NOTE: File upload is not yet supported, but can be without change
2661  * to the function call.
2662  */
2663
2664 /* form parsing stuff */
2665 typedef enum {
2666     FORM_NORMAL,
2667     FORM_AMP,
2668     FORM_NAME,
2669     FORM_VALUE,
2670     FORM_PERCENTA,
2671     FORM_PERCENTB,
2672     FORM_ABORT
2673 } ap_form_type_t;
2674
2675 AP_DECLARE(int) ap_parse_form_data(request_rec *r, ap_filter_t *f,
2676                                    apr_array_header_t **ptr,
2677                                    apr_size_t num, apr_size_t usize)
2678 {
2679     apr_bucket_brigade *bb = NULL;
2680     int seen_eos = 0;
2681     char buffer[HUGE_STRING_LEN + 1];
2682     const char *ct;
2683     apr_size_t offset = 0;
2684     apr_ssize_t size;
2685     ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
2686     ap_form_pair_t *pair = NULL;
2687     apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
2688
2689     char hi = 0;
2690     char low = 0;
2691
2692     *ptr = pairs;
2693
2694     /* sanity check - we only support forms for now */
2695     ct = apr_table_get(r->headers_in, "Content-Type");
2696     if (!ct || ap_cstr_casecmpn("application/x-www-form-urlencoded", ct, 33)) {
2697         return ap_discard_request_body(r);
2698     }
2699
2700     if (usize > APR_SIZE_MAX >> 1)
2701         size = APR_SIZE_MAX >> 1;
2702     else
2703         size = usize;
2704
2705     if (!f) {
2706         f = r->input_filters;
2707     }
2708
2709     bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2710     do {
2711         apr_bucket *bucket = NULL, *last = NULL;
2712
2713         int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
2714                                 APR_BLOCK_READ, HUGE_STRING_LEN);
2715         if (rv != APR_SUCCESS) {
2716             apr_brigade_destroy(bb);
2717             return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
2718         }
2719
2720         for (bucket = APR_BRIGADE_FIRST(bb);
2721              bucket != APR_BRIGADE_SENTINEL(bb);
2722              last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
2723             const char *data;
2724             apr_size_t len, slide;
2725
2726             if (last) {
2727                 apr_bucket_delete(last);
2728             }
2729             if (APR_BUCKET_IS_EOS(bucket)) {
2730                 seen_eos = 1;
2731                 break;
2732             }
2733             if (bucket->length == 0) {
2734                 continue;
2735             }
2736
2737             rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
2738             if (rv != APR_SUCCESS) {
2739                 apr_brigade_destroy(bb);
2740                 return HTTP_BAD_REQUEST;
2741             }
2742
2743             slide = len;
2744             while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
2745                 char c = *data++;
2746                 if ('+' == c) {
2747                     c = ' ';
2748                 }
2749                 else if ('&' == c) {
2750                     state = FORM_AMP;
2751                 }
2752                 if ('%' == c) {
2753                     percent = FORM_PERCENTA;
2754                     continue;
2755                 }
2756                 if (FORM_PERCENTA == percent) {
2757                     if (c >= 'a') {
2758                         hi = c - 'a' + 10;
2759                     }
2760                     else if (c >= 'A') {
2761                         hi = c - 'A' + 10;
2762                     }
2763                     else if (c >= '0') {
2764                         hi = c - '0';
2765                     }
2766                     hi = hi << 4;
2767                     percent = FORM_PERCENTB;
2768                     continue;
2769                 }
2770                 if (FORM_PERCENTB == percent) {
2771                     if (c >= 'a') {
2772                         low = c - 'a' + 10;
2773                     }
2774                     else if (c >= 'A') {
2775                         low = c - 'A' + 10;
2776                     }
2777                     else if (c >= '0') {
2778                         low = c - '0';
2779                     }
2780                     c = low | hi;
2781                     percent = FORM_NORMAL;
2782                 }
2783                 switch (state) {
2784                     case FORM_AMP:
2785                         if (pair) {
2786                             const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2787                             apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2788                             APR_BRIGADE_INSERT_TAIL(pair->value, b);
2789                         }
2790                         state = FORM_NAME;
2791                         pair = NULL;
2792                         offset = 0;
2793                         num--;
2794                         break;
2795                     case FORM_NAME:
2796                         if (offset < HUGE_STRING_LEN) {
2797                             if ('=' == c) {
2798                                 buffer[offset] = 0;
2799                                 offset = 0;
2800                                 pair = (ap_form_pair_t *) apr_array_push(pairs);
2801                                 pair->name = apr_pstrdup(r->pool, buffer);
2802                                 pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2803                                 state = FORM_VALUE;
2804                             }
2805                             else {
2806                                 buffer[offset++] = c;
2807                                 size--;
2808                             }
2809                         }
2810                         else {
2811                             state = FORM_ABORT;
2812                         }
2813                         break;
2814                     case FORM_VALUE:
2815                         if (offset >= HUGE_STRING_LEN) {
2816                             const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2817                             apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2818                             APR_BRIGADE_INSERT_TAIL(pair->value, b);
2819                             offset = 0;
2820                         }
2821                         buffer[offset++] = c;
2822                         size--;
2823                         break;
2824                     default:
2825                         break;
2826                 }
2827             }
2828
2829         }
2830
2831         apr_brigade_cleanup(bb);
2832     } while (!seen_eos);
2833
2834     if (FORM_ABORT == state || size < 0 || num == 0) {
2835         return HTTP_REQUEST_ENTITY_TOO_LARGE;
2836     }
2837     else if (FORM_VALUE == state && pair && offset > 0) {
2838         const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2839         apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2840         APR_BRIGADE_INSERT_TAIL(pair->value, b);
2841     }
2842
2843     return OK;
2844
2845 }
2846
2847 #define VARBUF_SMALL_SIZE 2048
2848 #define VARBUF_MAX_SIZE   (APR_SIZE_MAX - 1 -                                \
2849                            APR_ALIGN_DEFAULT(sizeof(struct ap_varbuf_info)))
2850
2851 struct ap_varbuf_info {
2852     struct apr_memnode_t *node;
2853     apr_allocator_t *allocator;
2854 };
2855
2856 static apr_status_t varbuf_cleanup(void *info_)
2857 {
2858     struct ap_varbuf_info *info = info_;
2859     info->node->next = NULL;
2860     apr_allocator_free(info->allocator, info->node);
2861     return APR_SUCCESS;
2862 }
2863
2864 const char nul = '\0';
2865 static char * const varbuf_empty = (char *)&nul;
2866
2867 AP_DECLARE(void) ap_varbuf_init(apr_pool_t *p, struct ap_varbuf *vb,
2868                                 apr_size_t init_size)
2869 {
2870     vb->buf = varbuf_empty;
2871     vb->avail = 0;
2872     vb->strlen = AP_VARBUF_UNKNOWN;
2873     vb->pool = p;
2874     vb->info = NULL;
2875
2876     ap_varbuf_grow(vb, init_size);
2877 }
2878
2879 AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
2880 {
2881     apr_memnode_t *new_node = NULL;
2882     apr_allocator_t *allocator;
2883     struct ap_varbuf_info *new_info;
2884     char *new;
2885
2886     AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN || vb->avail >= vb->strlen);
2887
2888     if (new_len <= vb->avail)
2889         return;
2890
2891     if (new_len < 2 * vb->avail && vb->avail < VARBUF_MAX_SIZE/2) {
2892         /* at least double the size, to avoid repeated reallocations */
2893         new_len = 2 * vb->avail;
2894     }
2895     else if (new_len > VARBUF_MAX_SIZE) {
2896         apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2897         ap_assert(abort_fn != NULL);
2898         abort_fn(APR_ENOMEM);
2899         return;
2900     }
2901
2902     new_len++;  /* add space for trailing \0 */
2903     if (new_len <= VARBUF_SMALL_SIZE) {
2904         new_len = APR_ALIGN_DEFAULT(new_len);
2905         new = apr_palloc(vb->pool, new_len);
2906         if (vb->avail && vb->strlen != 0) {
2907             AP_DEBUG_ASSERT(vb->buf != NULL);
2908             AP_DEBUG_ASSERT(vb->buf != varbuf_empty);
2909             if (new == vb->buf + vb->avail + 1) {
2910                 /* We are lucky: the new memory lies directly after our old
2911                  * buffer, we can now use both.
2912                  */
2913                 vb->avail += new_len;
2914                 return;
2915             }
2916             else {
2917                 /* copy up to vb->strlen + 1 bytes */
2918                 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2919                                      vb->avail + 1 : vb->strlen + 1);
2920             }
2921         }
2922         else {
2923             *new = '\0';
2924         }
2925         vb->avail = new_len - 1;
2926         vb->buf = new;
2927         return;
2928     }
2929
2930     /* The required block is rather larger. Use allocator directly so that
2931      * the memory can be freed independently from the pool. */
2932     allocator = apr_pool_allocator_get(vb->pool);
2933     if (new_len <= VARBUF_MAX_SIZE)
2934         new_node = apr_allocator_alloc(allocator,
2935                                        new_len + APR_ALIGN_DEFAULT(sizeof(*new_info)));
2936     if (!new_node) {
2937         apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2938         ap_assert(abort_fn != NULL);
2939         abort_fn(APR_ENOMEM);
2940         return;
2941     }
2942     new_info = (struct ap_varbuf_info *)new_node->first_avail;
2943     new_node->first_avail += APR_ALIGN_DEFAULT(sizeof(*new_info));
2944     new_info->node = new_node;
2945     new_info->allocator = allocator;
2946     new = new_node->first_avail;
2947     AP_DEBUG_ASSERT(new_node->endp - new_node->first_avail >= new_len);
2948     new_len = new_node->endp - new_node->first_avail;
2949
2950     if (vb->avail && vb->strlen != 0)
2951         memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2952                              vb->avail + 1 : vb->strlen + 1);
2953     else
2954         *new = '\0';
2955     if (vb->info)
2956         apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
2957     apr_pool_cleanup_register(vb->pool, new_info, varbuf_cleanup,
2958                               apr_pool_cleanup_null);
2959     vb->info = new_info;
2960     vb->buf = new;
2961     vb->avail = new_len - 1;
2962 }
2963
2964 AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
2965                                      int len)
2966 {
2967     if (len == 0)
2968         return;
2969     if (!vb->avail) {
2970         ap_varbuf_grow(vb, len);
2971         memcpy(vb->buf, str, len);
2972         vb->buf[len] = '\0';
2973         vb->strlen = len;
2974         return;
2975     }
2976     if (vb->strlen == AP_VARBUF_UNKNOWN)
2977         vb->strlen = strlen(vb->buf);
2978     ap_varbuf_grow(vb, vb->strlen + len);
2979     memcpy(vb->buf + vb->strlen, str, len);
2980     vb->strlen += len;
2981     vb->buf[vb->strlen] = '\0';
2982 }
2983
2984 AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb)
2985 {
2986     if (vb->info) {
2987         apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
2988         vb->info = NULL;
2989     }
2990     vb->buf = NULL;
2991 }
2992
2993 AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *buf,
2994                                   const char *prepend, apr_size_t prepend_len,
2995                                   const char *append, apr_size_t append_len,
2996                                   apr_size_t *new_len)
2997 {
2998     apr_size_t i = 0;
2999     struct iovec vec[3];
3000
3001     if (prepend) {
3002         vec[i].iov_base = (void *)prepend;
3003         vec[i].iov_len = prepend_len;
3004         i++;
3005     }
3006     if (buf->avail && buf->strlen) {
3007         if (buf->strlen == AP_VARBUF_UNKNOWN)
3008             buf->strlen = strlen(buf->buf);
3009         vec[i].iov_base = (void *)buf->buf;
3010         vec[i].iov_len = buf->strlen;
3011         i++;
3012     }
3013     if (append) {
3014         vec[i].iov_base = (void *)append;
3015         vec[i].iov_len = append_len;
3016         i++;
3017     }
3018     if (i)
3019         return apr_pstrcatv(p, vec, i, new_len);
3020
3021     if (new_len)
3022         *new_len = 0;
3023     return "";
3024 }
3025
3026 AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb,
3027                                           const char *input,
3028                                           const char *source,
3029                                           apr_size_t nmatch,
3030                                           ap_regmatch_t pmatch[],
3031                                           apr_size_t maxlen)
3032 {
3033     return regsub_core(NULL, NULL, vb, input, source, nmatch, pmatch, maxlen);
3034 }
3035
3036 static const char * const oom_message = "[crit] Memory allocation failed, "
3037                                         "aborting process." APR_EOL_STR;
3038
3039 AP_DECLARE(void) ap_abort_on_oom()
3040 {
3041     int written, count = strlen(oom_message);
3042     const char *buf = oom_message;
3043     do {
3044         written = write(STDERR_FILENO, buf, count);
3045         if (written == count)
3046             break;
3047         if (written > 0) {
3048             buf += written;
3049             count -= written;
3050         }
3051     } while (written >= 0 || errno == EINTR);
3052     abort();
3053 }
3054
3055 AP_DECLARE(void *) ap_malloc(size_t size)
3056 {
3057     void *p = malloc(size);
3058     if (p == NULL && size != 0)
3059         ap_abort_on_oom();
3060     return p;
3061 }
3062
3063 AP_DECLARE(void *) ap_calloc(size_t nelem, size_t size)
3064 {
3065     void *p = calloc(nelem, size);
3066     if (p == NULL && nelem != 0 && size != 0)
3067         ap_abort_on_oom();
3068     return p;
3069 }
3070
3071 AP_DECLARE(void *) ap_realloc(void *ptr, size_t size)
3072 {
3073     void *p = realloc(ptr, size);
3074     if (p == NULL && size != 0)
3075         ap_abort_on_oom();
3076     return p;
3077 }
3078
3079 AP_DECLARE(void) ap_get_sload(ap_sload_t *ld)
3080 {
3081     int i, j, server_limit, thread_limit;
3082     int ready = 0;
3083     int busy = 0;
3084     int total;
3085     ap_generation_t mpm_generation;
3086
3087     /* preload errored fields, we overwrite */
3088     ld->idle = -1;
3089     ld->busy = -1;
3090     ld->bytes_served = 0;
3091     ld->access_count = 0;
3092
3093     ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
3094     ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
3095     ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
3096
3097     for (i = 0; i < server_limit; i++) {
3098         process_score *ps;
3099         ps = ap_get_scoreboard_process(i);
3100
3101         for (j = 0; j < thread_limit; j++) {
3102             int res;
3103             worker_score *ws = NULL;
3104             ws = &ap_scoreboard_image->servers[i][j];
3105             res = ws->status;
3106
3107             if (!ps->quiescing && ps->pid) {
3108                 if (res == SERVER_READY && ps->generation == mpm_generation) {
3109                     ready++;
3110                 }
3111                 else if (res != SERVER_DEAD &&
3112                          res != SERVER_STARTING && res != SERVER_IDLE_KILL &&
3113                          ps->generation == mpm_generation) {
3114                     busy++;
3115                 }   
3116             }
3117
3118             if (ap_extended_status && !ps->quiescing && ps->pid) {
3119                 if (ws->access_count != 0 
3120                     || (res != SERVER_READY && res != SERVER_DEAD)) {
3121                     ld->access_count += ws->access_count;
3122                     ld->bytes_served += ws->bytes_served;
3123                 }
3124             }
3125         }
3126     }
3127     total = busy + ready;
3128     if (total) {
3129         ld->idle = ready * 100 / total;
3130         ld->busy = busy * 100 / total;
3131     }
3132 }
3133
3134 AP_DECLARE(void) ap_get_loadavg(ap_loadavg_t *ld)
3135 {
3136     /* preload errored fields, we overwrite */
3137     ld->loadavg = -1.0;
3138     ld->loadavg5 = -1.0;
3139     ld->loadavg15 = -1.0;
3140
3141 #if HAVE_GETLOADAVG
3142     {
3143         double la[3];
3144         int num;
3145
3146         num = getloadavg(la, 3);
3147         if (num > 0) {
3148             ld->loadavg = (float)la[0];
3149         }
3150         if (num > 1) {
3151             ld->loadavg5 = (float)la[1];
3152         }
3153         if (num > 2) {
3154             ld->loadavg15 = (float)la[2];
3155         }
3156     }
3157 #endif
3158 }
3159
3160 static const char * const pw_cache_note_name = "conn_cache_note";
3161 struct pw_cache {
3162     /* varbuf contains concatenated password and hash */
3163     struct ap_varbuf vb;
3164     apr_size_t pwlen;
3165     apr_status_t result;
3166 };
3167
3168 AP_DECLARE(apr_status_t) ap_password_validate(request_rec *r,
3169                                               const char *username,
3170                                               const char *passwd,
3171                                               const char *hash)
3172 {
3173     struct pw_cache *cache;
3174     apr_size_t hashlen;
3175
3176     cache = (struct pw_cache *)apr_table_get(r->connection->notes, pw_cache_note_name);
3177     if (cache != NULL) {
3178         if (strncmp(passwd, cache->vb.buf, cache->pwlen) == 0
3179             && strcmp(hash, cache->vb.buf + cache->pwlen) == 0) {
3180             return cache->result;
3181         }
3182         /* make ap_varbuf_grow below not copy the old data */
3183         cache->vb.strlen = 0;
3184     }
3185     else {
3186         cache = apr_palloc(r->connection->pool, sizeof(struct pw_cache));
3187         ap_varbuf_init(r->connection->pool, &cache->vb, 0);
3188         apr_table_setn(r->connection->notes, pw_cache_note_name, (void *)cache);
3189     }
3190     cache->pwlen = strlen(passwd);
3191     hashlen = strlen(hash);
3192     ap_varbuf_grow(&cache->vb, cache->pwlen + hashlen + 1);
3193     memcpy(cache->vb.buf, passwd, cache->pwlen);
3194     memcpy(cache->vb.buf + cache->pwlen, hash, hashlen + 1);
3195     cache->result = apr_password_validate(passwd, hash);
3196     return cache->result;
3197 }
3198
3199 AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p,
3200                                     const char *cmd,
3201                                     const char * const * argv)
3202 {
3203     char buf[MAX_STRING_LEN];
3204     apr_procattr_t *procattr;
3205     apr_proc_t *proc;
3206     apr_file_t *fp;
3207     apr_size_t nbytes = 1;
3208     char c;
3209     int k;
3210
3211     if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
3212         return NULL;
3213     if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
3214                             APR_FULL_BLOCK) != APR_SUCCESS)
3215         return NULL;
3216     if (apr_procattr_dir_set(procattr,
3217                              ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
3218         return NULL;
3219     if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
3220         return NULL;
3221     proc = apr_pcalloc(p, sizeof(apr_proc_t));
3222     if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
3223         return NULL;
3224     fp = proc->out;
3225
3226     if (fp == NULL)
3227         return NULL;
3228     /* XXX: we are reading 1 byte at a time here */
3229     for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
3230                 && nbytes == 1 && (k < MAX_STRING_LEN-1)     ; ) {
3231         if (c == '\n' || c == '\r')
3232             break;
3233         buf[k++] = c;
3234     }
3235     buf[k] = '\0'; 
3236     apr_file_close(fp);
3237
3238     return apr_pstrndup(p, buf, k);
3239 }
3240
3241 AP_DECLARE(int) ap_array_str_index(const apr_array_header_t *array, 
3242                                    const char *s,
3243                                    int start)
3244 {
3245     if (start >= 0) {
3246         int i;
3247         
3248         for (i = start; i < array->nelts; i++) {
3249             const char *p = APR_ARRAY_IDX(array, i, const char *);
3250             if (!strcmp(p, s)) {
3251                 return i;
3252             }
3253         }
3254     }
3255     
3256     return -1;
3257 }
3258
3259 AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array, 
3260                                       const char *s)
3261 {
3262     return (ap_array_str_index(array, s, 0) >= 0);
3263 }
3264
3265 #if !APR_CHARSET_EBCDIC
3266 /*
3267  * Our own known-fast translation table for casecmp by character.
3268  * Only ASCII alpha characters 41-5A are folded to 61-7A, other
3269  * octets (such as extended latin alphabetics) are never case-folded.
3270  * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3271  */
3272 static const short ucharmap[] = {
3273     0x0,  0x1,  0x2,  0x3,  0x4,  0x5,  0x6,  0x7,
3274     0x8,  0x9,  0xa,  0xb,  0xc,  0xd,  0xe,  0xf,
3275     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3276     0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3277     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3278     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3279     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3280     0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3281     0x40,  'a',  'b',  'c',  'd',  'e',  'f',  'g',
3282      'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
3283      'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
3284      'x',  'y',  'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3285     0x60,  'a',  'b',  'c',  'd',  'e',  'f',  'g',
3286      'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
3287      'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
3288      'x',  'y',  'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3289     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3290     0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3291     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3292     0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3293     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3294     0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3295     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3296     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3297     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3298     0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3299     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3300     0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3301     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3302     0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3303     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3304     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3305 };
3306 #else /* APR_CHARSET_EBCDIC */
3307 /*
3308  * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison,
3309  * provides unique identity of every char value (strict ISO-646
3310  * conformance, arbitrary election of an ISO-8859-1 ordering, and
3311  * very arbitrary control code assignments into C1 to achieve
3312  * identity and a reversible mapping of code points),
3313  * then folding the equivalences of ASCII 41-5A into 61-7A, 
3314  * presenting comparison results in a somewhat ISO/IEC 10646
3315  * (ASCII-like) order, depending on the EBCDIC code page in use.
3316  *
3317  * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3318  */
3319 static const short ucharmap[] = {
3320     0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
3321     0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
3322     0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
3323     0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
3324     0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
3325     0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
3326     0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
3327     0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
3328     0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,
3329     0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
3330     0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,
3331     0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
3332     0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,
3333     0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
3334     0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,
3335     0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
3336     0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3337     0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,
3338     0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3339     0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,
3340     0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3341     0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE,
3342     0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,
3343     0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7,
3344     0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3345     0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,
3346     0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3347     0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,
3348     0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3349     0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,
3350     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3351     0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F
3352 };
3353 #endif
3354
3355 AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2)
3356 {
3357     const unsigned char *str1 = (const unsigned char *)s1;
3358     const unsigned char *str2 = (const unsigned char *)s2;
3359     for (;;)
3360     {
3361         const int c1 = (int)(*str1);
3362         const int c2 = (int)(*str2);
3363         const int cmp = ucharmap[c1] - ucharmap[c2];
3364         /* Not necessary to test for !c2, this is caught by cmp */
3365         if (cmp || !c1)
3366             return cmp;
3367         str1++;
3368         str2++;
3369     }
3370 }
3371
3372 AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
3373 {
3374     const unsigned char *str1 = (const unsigned char *)s1;
3375     const unsigned char *str2 = (const unsigned char *)s2;
3376     while (n--)
3377     {
3378         const int c1 = (int)(*str1);
3379         const int c2 = (int)(*str2);
3380         const int cmp = ucharmap[c1] - ucharmap[c2];
3381         /* Not necessary to test for !c2, this is caught by cmp */
3382         if (cmp || !c1)
3383             return cmp;
3384         str1++;
3385         str2++;
3386     }
3387     return 0;
3388 }
3389