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