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