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