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