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