]> granicus.if.org Git - apache/blob - server/util.c
With NUL as a TOKEN_STOP, this code is more efficient
[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 ((!str[x]) && (expected[y] != '*'))
194             return -1;
195         if (expected[y] == '*') {
196             while (expected[++y] == '*');
197             if (!expected[y])
198                 return 0;
199             while (str[x]) {
200                 int ret;
201                 if ((ret = ap_strcmp_match(&str[x++], &expected[y])) != 1)
202                     return ret;
203             }
204             return -1;
205         }
206         else if ((expected[y] != '?') && (str[x] != expected[y]))
207             return 1;
208     }
209     return (str[x] != '\0');
210 }
211
212 AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
213 {
214     int x, y;
215
216     for (x = 0, y = 0; expected[y]; ++y, ++x) {
217         if (!str[x] && expected[y] != '*')
218             return -1;
219         if (expected[y] == '*') {
220             while (expected[++y] == '*');
221             if (!expected[y])
222                 return 0;
223             while (str[x]) {
224                 int ret;
225                 if ((ret = ap_strcasecmp_match(&str[x++], &expected[y])) != 1)
226                     return ret;
227             }
228             return -1;
229         }
230         else if (expected[y] != '?'
231                  && apr_tolower(str[x]) != apr_tolower(expected[y]))
232             return 1;
233     }
234     return (str[x] != '\0');
235 }
236
237 /* We actually compare the canonical root to this root, (but we don't
238  * waste time checking the case), since every use of this function in
239  * httpd-2.1 tests if the path is 'proper', meaning we've already passed
240  * it through apr_filepath_merge, or we haven't.
241  */
242 AP_DECLARE(int) ap_os_is_path_absolute(apr_pool_t *p, const char *dir)
243 {
244     const char *newpath;
245     const char *ourdir = dir;
246     if (apr_filepath_root(&newpath, &dir, 0, p) != APR_SUCCESS
247             || strncmp(newpath, ourdir, strlen(newpath)) != 0) {
248         return 0;
249     }
250     return 1;
251 }
252
253 AP_DECLARE(int) ap_is_matchexp(const char *str)
254 {
255     int x;
256
257     for (x = 0; str[x]; x++)
258         if ((str[x] == '*') || (str[x] == '?'))
259             return 1;
260     return 0;
261 }
262
263 /*
264  * Here's a pool-based interface to the POSIX-esque ap_regcomp().
265  * Note that we return ap_regex_t instead of being passed one.
266  * The reason is that if you use an already-used ap_regex_t structure,
267  * the memory that you've already allocated gets forgotten, and
268  * regfree() doesn't clear it. So we don't allow it.
269  */
270
271 static apr_status_t regex_cleanup(void *preg)
272 {
273     ap_regfree((ap_regex_t *) preg);
274     return APR_SUCCESS;
275 }
276
277 AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
278                                      int cflags)
279 {
280     ap_regex_t *preg = apr_palloc(p, sizeof *preg);
281     int err = ap_regcomp(preg, pattern, cflags);
282     if (err) {
283         if (err == AP_REG_ESPACE)
284             ap_abort_on_oom();
285         return NULL;
286     }
287
288     apr_pool_cleanup_register(p, (void *) preg, regex_cleanup,
289                               apr_pool_cleanup_null);
290
291     return preg;
292 }
293
294 AP_DECLARE(void) ap_pregfree(apr_pool_t *p, ap_regex_t *reg)
295 {
296     ap_regfree(reg);
297     apr_pool_cleanup_kill(p, (void *) reg, regex_cleanup);
298 }
299
300 /*
301  * Similar to standard strstr() but we ignore case in this version.
302  * Based on the strstr() implementation further below.
303  */
304 AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2)
305 {
306     char *p1, *p2;
307     if (*s2 == '\0') {
308         /* an empty s2 */
309         return((char *)s1);
310     }
311     while(1) {
312         for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
313         if (*s1 == '\0') {
314             return(NULL);
315         }
316         /* found first character of s2, see if the rest matches */
317         p1 = (char *)s1;
318         p2 = (char *)s2;
319         for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) {
320             if (*p1 == '\0') {
321                 /* both strings ended together */
322                 return((char *)s1);
323             }
324         }
325         if (*p2 == '\0') {
326             /* second string ended, a match */
327             break;
328         }
329         /* didn't find a match here, try starting at next character in s1 */
330         s1++;
331     }
332     return((char *)s1);
333 }
334
335 /*
336  * Returns an offsetted pointer in bigstring immediately after
337  * prefix. Returns bigstring if bigstring doesn't start with
338  * prefix or if prefix is longer than bigstring while still matching.
339  * NOTE: pointer returned is relative to bigstring, so we
340  * can use standard pointer comparisons in the calling function
341  * (eg: test if ap_stripprefix(a,b) == a)
342  */
343 AP_DECLARE(const char *) ap_stripprefix(const char *bigstring,
344                                         const char *prefix)
345 {
346     const char *p1;
347
348     if (*prefix == '\0')
349         return bigstring;
350
351     p1 = bigstring;
352     while (*p1 && *prefix) {
353         if (*p1++ != *prefix++)
354             return bigstring;
355     }
356     if (*prefix == '\0')
357         return p1;
358
359     /* hit the end of bigstring! */
360     return bigstring;
361 }
362
363 /* This function substitutes for $0-$9, filling in regular expression
364  * submatches. Pass it the same nmatch and pmatch arguments that you
365  * passed ap_regexec(). pmatch should not be greater than the maximum number
366  * of subexpressions - i.e. one more than the re_nsub member of ap_regex_t.
367  *
368  * nmatch must be <=AP_MAX_REG_MATCH (10).
369  *
370  * input should be the string with the $-expressions, source should be the
371  * string that was matched against.
372  *
373  * It returns the substituted string, or NULL if a vbuf is used.
374  * On errors, returns the orig string.
375  *
376  * Parts of this code are based on Henry Spencer's regsub(), from his
377  * AT&T V8 regexp package.
378  */
379
380 static apr_status_t regsub_core(apr_pool_t *p, char **result,
381                                 struct ap_varbuf *vb, const char *input,
382                                 const char *source, apr_size_t nmatch,
383                                 ap_regmatch_t pmatch[], apr_size_t maxlen)
384 {
385     const char *src = input;
386     char *dst;
387     char c;
388     apr_size_t no;
389     apr_size_t len = 0;
390
391     AP_DEBUG_ASSERT((result && p && !vb) || (vb && !p && !result));
392     if (!source || nmatch>AP_MAX_REG_MATCH)
393         return APR_EINVAL;
394     if (!nmatch) {
395         len = strlen(src);
396         if (maxlen > 0 && len >= maxlen)
397             return APR_ENOMEM;
398         if (!vb) {
399             *result = apr_pstrmemdup(p, src, len);
400             return APR_SUCCESS;
401         }
402         else {
403             ap_varbuf_strmemcat(vb, src, len);
404             return APR_SUCCESS;
405         }
406     }
407
408     /* First pass, find the size */
409     while ((c = *src++) != '\0') {
410         if (c == '$' && apr_isdigit(*src))
411             no = *src++ - '0';
412         else
413             no = AP_MAX_REG_MATCH;
414
415         if (no >= AP_MAX_REG_MATCH) {  /* Ordinary character. */
416             if (c == '\\' && *src)
417                 src++;
418             len++;
419         }
420         else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
421             if (APR_SIZE_MAX - len <= pmatch[no].rm_eo - pmatch[no].rm_so)
422                 return APR_ENOMEM;
423             len += pmatch[no].rm_eo - pmatch[no].rm_so;
424         }
425
426     }
427
428     if (len >= maxlen && maxlen > 0)
429         return APR_ENOMEM;
430
431     if (!vb) {
432         *result = dst = apr_palloc(p, len + 1);
433     }
434     else {
435         if (vb->strlen == AP_VARBUF_UNKNOWN)
436             vb->strlen = strlen(vb->buf);
437         ap_varbuf_grow(vb, vb->strlen + len);
438         dst = vb->buf + vb->strlen;
439         vb->strlen += len;
440     }
441
442     /* Now actually fill in the string */
443
444     src = input;
445
446     while ((c = *src++) != '\0') {
447         if (c == '$' && apr_isdigit(*src))
448             no = *src++ - '0';
449         else
450             no = AP_MAX_REG_MATCH;
451
452         if (no >= AP_MAX_REG_MATCH) {  /* Ordinary character. */
453             if (c == '\\' && *src)
454                 c = *src++;
455             *dst++ = c;
456         }
457         else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
458             len = pmatch[no].rm_eo - pmatch[no].rm_so;
459             memcpy(dst, source + pmatch[no].rm_so, len);
460             dst += len;
461         }
462
463     }
464     *dst = '\0';
465
466     return APR_SUCCESS;
467 }
468
469 #ifndef AP_PREGSUB_MAXLEN
470 #define AP_PREGSUB_MAXLEN   (HUGE_STRING_LEN * 8)
471 #endif
472 AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
473                               const char *source, apr_size_t nmatch,
474                               ap_regmatch_t pmatch[])
475 {
476     char *result;
477     apr_status_t rc = regsub_core(p, &result, NULL, input, source, nmatch,
478                                   pmatch, AP_PREGSUB_MAXLEN);
479     if (rc != APR_SUCCESS)
480         result = NULL;
481     return result;
482 }
483
484 AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result,
485                                        const char *input, const char *source,
486                                        apr_size_t nmatch, ap_regmatch_t pmatch[],
487                                        apr_size_t maxlen)
488 {
489     apr_status_t rc = regsub_core(p, result, NULL, input, source, nmatch,
490                                   pmatch, maxlen);
491     if (rc != APR_SUCCESS)
492         *result = NULL;
493     return rc;
494 }
495
496 /*
497  * Parse .. so we don't compromise security
498  */
499 AP_DECLARE(void) ap_getparents(char *name)
500 {
501     char *next;
502     int l, w, first_dot;
503
504     /* Four paseses, as per RFC 1808 */
505     /* a) remove ./ path segments */
506     for (next = name; *next && (*next != '.'); next++) {
507     }
508
509     l = w = first_dot = next - name;
510     while (name[l] != '\0') {
511         if (name[l] == '.' && IS_SLASH(name[l + 1])
512             && (l == 0 || IS_SLASH(name[l - 1])))
513             l += 2;
514         else
515             name[w++] = name[l++];
516     }
517
518     /* b) remove trailing . path, segment */
519     if (w == 1 && name[0] == '.')
520         w--;
521     else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2]))
522         w--;
523     name[w] = '\0';
524
525     /* c) remove all xx/../ segments. (including leading ../ and /../) */
526     l = first_dot;
527
528     while (name[l] != '\0') {
529         if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2])
530             && (l == 0 || IS_SLASH(name[l - 1]))) {
531             int m = l + 3, n;
532
533             l = l - 2;
534             if (l >= 0) {
535                 while (l >= 0 && !IS_SLASH(name[l]))
536                     l--;
537                 l++;
538             }
539             else
540                 l = 0;
541             n = l;
542             while ((name[n] = name[m]))
543                 (++n, ++m);
544         }
545         else
546             ++l;
547     }
548
549     /* d) remove trailing xx/.. segment. */
550     if (l == 2 && name[0] == '.' && name[1] == '.')
551         name[0] = '\0';
552     else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
553              && IS_SLASH(name[l - 3])) {
554         l = l - 4;
555         if (l >= 0) {
556             while (l >= 0 && !IS_SLASH(name[l]))
557                 l--;
558             l++;
559         }
560         else
561             l = 0;
562         name[l] = '\0';
563     }
564 }
565
566 AP_DECLARE(void) ap_no2slash(char *name)
567 {
568     char *d, *s;
569
570     s = d = name;
571
572 #ifdef HAVE_UNC_PATHS
573     /* Check for UNC names.  Leave leading two slashes. */
574     if (s[0] == '/' && s[1] == '/')
575         *d++ = *s++;
576 #endif
577
578     while (*s) {
579         if ((*d++ = *s) == '/') {
580             do {
581                 ++s;
582             } while (*s == '/');
583         }
584         else {
585             ++s;
586         }
587     }
588     *d = '\0';
589 }
590
591
592 /*
593  * copy at most n leading directories of s into d
594  * d should be at least as large as s plus 1 extra byte
595  * assumes n > 0
596  * the return value is the ever useful pointer to the trailing \0 of d
597  *
598  * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments,
599  * so that if n == 0, "/" is returned in d with n == 1
600  * and s == "e:/test.html", "e:/" is returned in d
601  * *** See also directory_walk in modules/http/http_request.c
602
603  * examples:
604  *    /a/b, 0  ==> /  (true for all platforms)
605  *    /a/b, 1  ==> /
606  *    /a/b, 2  ==> /a/
607  *    /a/b, 3  ==> /a/b/
608  *    /a/b, 4  ==> /a/b/
609  *
610  *    c:/a/b 0 ==> /
611  *    c:/a/b 1 ==> c:/
612  *    c:/a/b 2 ==> c:/a/
613  *    c:/a/b 3 ==> c:/a/b
614  *    c:/a/b 4 ==> c:/a/b
615  */
616 AP_DECLARE(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
617 {
618     if (n < 1) {
619         *d = '/';
620         *++d = '\0';
621         return (d);
622     }
623
624     for (;;) {
625         if (*s == '\0' || (*s == '/' && (--n) == 0)) {
626             *d = '/';
627             break;
628         }
629         *d++ = *s++;
630     }
631     *++d = 0;
632     return (d);
633 }
634
635
636 /*
637  * return the parent directory name including trailing / of the file s
638  */
639 AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s)
640 {
641     const char *last_slash = ap_strrchr_c(s, '/');
642     char *d;
643     int l;
644
645     if (last_slash == NULL) {
646         return apr_pstrdup(p, "");
647     }
648     l = (last_slash - s) + 1;
649     d = apr_pstrmemdup(p, s, l);
650
651     return (d);
652 }
653
654
655 AP_DECLARE(int) ap_count_dirs(const char *path)
656 {
657     int x, n;
658
659     for (x = 0, n = 0; path[x]; x++)
660         if (path[x] == '/')
661             n++;
662     return n;
663 }
664
665 AP_DECLARE(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop)
666 {
667     return ap_getword(atrans, (const char **) line, stop);
668 }
669
670 AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop)
671 {
672     const char *pos = *line;
673     int len;
674     char *res;
675
676     while ((*pos != stop) && *pos) {
677         ++pos;
678     }
679
680     len = pos - *line;
681     res = apr_pstrmemdup(atrans, *line, len);
682
683     if (stop) {
684         while (*pos == stop) {
685             ++pos;
686         }
687     }
688     *line = pos;
689
690     return res;
691 }
692
693 AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
694 {
695     return ap_getword_white(atrans, (const char **) line);
696 }
697
698 AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
699 {
700     const char *pos = *line;
701     int len;
702     char *res;
703
704     while (!apr_isspace(*pos) && *pos) {
705         ++pos;
706     }
707
708     len = pos - *line;
709     res = apr_pstrmemdup(atrans, *line, len);
710
711     while (apr_isspace(*pos)) {
712         ++pos;
713     }
714
715     *line = pos;
716
717     return res;
718 }
719
720 AP_DECLARE(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line,
721                                        char stop)
722 {
723     return ap_getword_nulls(atrans, (const char **) line, stop);
724 }
725
726 AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line,
727                                     char stop)
728 {
729     const char *pos = ap_strchr_c(*line, stop);
730     char *res;
731
732     if (!pos) {
733         apr_size_t len = strlen(*line);
734         res = apr_pstrmemdup(atrans, *line, len);
735         *line += len;
736         return res;
737     }
738
739     res = apr_pstrmemdup(atrans, *line, pos - *line);
740
741     ++pos;
742
743     *line = pos;
744
745     return res;
746 }
747
748 /* Get a word, (new) config-file style --- quoted strings and backslashes
749  * all honored
750  */
751
752 static char *substring_conf(apr_pool_t *p, const char *start, int len,
753                             char quote)
754 {
755     char *result = apr_palloc(p, len + 1);
756     char *resp = result;
757     int i;
758
759     for (i = 0; i < len; ++i) {
760         if (start[i] == '\\' && (start[i + 1] == '\\'
761                                  || (quote && start[i + 1] == quote)))
762             *resp++ = start[++i];
763         else
764             *resp++ = start[i];
765     }
766
767     *resp++ = '\0';
768 #if RESOLVE_ENV_PER_TOKEN
769     return (char *)ap_resolve_env(p,result);
770 #else
771     return result;
772 #endif
773 }
774
775 AP_DECLARE(char *) ap_getword_conf_nc(apr_pool_t *p, char **line)
776 {
777     return ap_getword_conf(p, (const char **) line);
778 }
779
780 AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line)
781 {
782     const char *str = *line, *strend;
783     char *res;
784     char quote;
785
786     while (apr_isspace(*str))
787         ++str;
788
789     if (!*str) {
790         *line = str;
791         return "";
792     }
793
794     if ((quote = *str) == '"' || quote == '\'') {
795         strend = str + 1;
796         while (*strend && *strend != quote) {
797             if (*strend == '\\' && strend[1] &&
798                 (strend[1] == quote || strend[1] == '\\')) {
799                 strend += 2;
800             }
801             else {
802                 ++strend;
803             }
804         }
805         res = substring_conf(p, str + 1, strend - str - 1, quote);
806
807         if (*strend == quote)
808             ++strend;
809     }
810     else {
811         strend = str;
812         while (*strend && !apr_isspace(*strend))
813             ++strend;
814
815         res = substring_conf(p, str, strend - str, 0);
816     }
817
818     while (apr_isspace(*strend))
819         ++strend;
820     *line = strend;
821     return res;
822 }
823
824 AP_DECLARE(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 /* Retrieve a token, advancing the pointer to the first non-token character
1619  * and returning a copy of the token string.
1620  * The caller must handle whitespace and determine the meaning of the
1621  * terminating character. Returns NULL if the character at **ptr is not
1622  * a valid token character.
1623  */
1624 AP_DECLARE(char *) ap_get_http_token(apr_pool_t *p, const char **ptr)
1625 {
1626     const char *tok_end = ap_scan_http_token(*ptr);
1627     char *tok;
1628
1629     if (tok_end == *ptr)
1630         return NULL;
1631
1632     tok = apr_pstrmemdup(p, *ptr, tok_end - *ptr);
1633     *ptr = tok_end;
1634     return tok;
1635 }
1636
1637 /* Retrieve a token, spacing over it and returning a pointer to
1638  * the first non-white byte afterwards.  Note that these tokens
1639  * are delimited by semis and commas; and can also be delimited
1640  * by whitespace at the caller's option.
1641  */
1642
1643 AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line,
1644                                 int accept_white)
1645 {
1646     const char *ptr = *accept_line;
1647     const char *tok_start;
1648     char *token;
1649
1650     /* Find first non-white byte */
1651
1652     while (apr_isspace(*ptr))
1653         ++ptr;
1654
1655     tok_start = ptr;
1656
1657     /* find token end, skipping over quoted strings.
1658      * (comments are already gone).
1659      */
1660
1661     while (*ptr && (accept_white || !apr_isspace(*ptr))
1662            && *ptr != ';' && *ptr != ',') {
1663         if (*ptr++ == '"')
1664             while (*ptr)
1665                 if (*ptr++ == '"')
1666                     break;
1667     }
1668
1669     token = apr_pstrmemdup(p, tok_start, ptr - tok_start);
1670
1671     /* Advance accept_line pointer to the next non-white byte */
1672
1673     while (apr_isspace(*ptr))
1674         ++ptr;
1675
1676     *accept_line = ptr;
1677     return token;
1678 }
1679
1680
1681 /* find http tokens, see the definition of token from RFC2068 */
1682 AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
1683 {
1684     const unsigned char *start_token;
1685     const unsigned char *s;
1686
1687     if (!line)
1688         return 0;
1689
1690     s = (const unsigned char *)line;
1691     for (;;) {
1692         /* find start of token, skip all stop characters, note NUL
1693          * isn't a token stop, so we don't need to test for it
1694          */
1695         while (TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1696             ++s;
1697         }
1698         if (!*s) {
1699             return 0;
1700         }
1701         start_token = s;
1702         /* find end of the token */
1703         while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1704             ++s;
1705         }
1706         if (!ap_cstr_casecmpn((const char *)start_token, (const char *)tok,
1707                          s - start_token)) {
1708             return 1;
1709         }
1710         if (!*s) {
1711             return 0;
1712         }
1713     }
1714 }
1715
1716
1717 AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line,
1718                                    const char *tok)
1719 {
1720     int llen, tlen, lidx;
1721
1722     if (!line)
1723         return 0;
1724
1725     llen = strlen(line);
1726     tlen = strlen(tok);
1727     lidx = llen - tlen;
1728
1729     if (lidx < 0 ||
1730         (lidx > 0 && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1731         return 0;
1732
1733     return (ap_cstr_casecmpn(&line[lidx], tok, tlen) == 0);
1734 }
1735
1736 AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1737 {
1738     char *cmd;
1739     unsigned char *d;
1740     const unsigned char *s;
1741
1742     cmd = apr_palloc(p, 2 * strlen(str) + 1);        /* Be safe */
1743     d = (unsigned char *)cmd;
1744     s = (const unsigned char *)str;
1745     for (; *s; ++s) {
1746
1747 #if defined(OS2) || defined(WIN32)
1748         /*
1749          * Newlines to Win32/OS2 CreateProcess() are ill advised.
1750          * Convert them to spaces since they are effectively white
1751          * space to most applications
1752          */
1753         if (*s == '\r' || *s == '\n') {
1754              *d++ = ' ';
1755              continue;
1756          }
1757 #endif
1758
1759         if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1760             *d++ = '\\';
1761         }
1762         *d++ = *s;
1763     }
1764     *d = '\0';
1765
1766     return cmd;
1767 }
1768
1769 static char x2c(const char *what)
1770 {
1771     char digit;
1772
1773 #if !APR_CHARSET_EBCDIC
1774     digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
1775              : (what[0] - '0'));
1776     digit *= 16;
1777     digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
1778               : (what[1] - '0'));
1779 #else /*APR_CHARSET_EBCDIC*/
1780     char xstr[5];
1781     xstr[0]='0';
1782     xstr[1]='x';
1783     xstr[2]=what[0];
1784     xstr[3]=what[1];
1785     xstr[4]='\0';
1786     digit = apr_xlate_conv_byte(ap_hdrs_from_ascii,
1787                                 0xFF & strtol(xstr, NULL, 16));
1788 #endif /*APR_CHARSET_EBCDIC*/
1789     return (digit);
1790 }
1791
1792 /*
1793  * Unescapes a URL, leaving reserved characters intact.
1794  * Returns 0 on success, non-zero on error
1795  * Failure is due to
1796  *   bad % escape       returns HTTP_BAD_REQUEST
1797  *
1798  *   decoding %00 or a forbidden character returns HTTP_NOT_FOUND
1799  */
1800
1801 static int unescape_url(char *url, const char *forbid, const char *reserved)
1802 {
1803     int badesc, badpath;
1804     char *x, *y;
1805
1806     badesc = 0;
1807     badpath = 0;
1808     /* Initial scan for first '%'. Don't bother writing values before
1809      * seeing a '%' */
1810     y = strchr(url, '%');
1811     if (y == NULL) {
1812         return OK;
1813     }
1814     for (x = y; *y; ++x, ++y) {
1815         if (*y != '%') {
1816             *x = *y;
1817         }
1818         else {
1819             if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1820                 badesc = 1;
1821                 *x = '%';
1822             }
1823             else {
1824                 char decoded;
1825                 decoded = x2c(y + 1);
1826                 if ((decoded == '\0')
1827                     || (forbid && ap_strchr_c(forbid, decoded))) {
1828                     badpath = 1;
1829                     *x = decoded;
1830                     y += 2;
1831                 }
1832                 else if (reserved && ap_strchr_c(reserved, decoded)) {
1833                     *x++ = *y++;
1834                     *x++ = *y++;
1835                     *x = *y;
1836                 }
1837                 else {
1838                     *x = decoded;
1839                     y += 2;
1840                 }
1841             }
1842         }
1843     }
1844     *x = '\0';
1845     if (badesc) {
1846         return HTTP_BAD_REQUEST;
1847     }
1848     else if (badpath) {
1849         return HTTP_NOT_FOUND;
1850     }
1851     else {
1852         return OK;
1853     }
1854 }
1855 AP_DECLARE(int) ap_unescape_url(char *url)
1856 {
1857     /* Traditional */
1858     return unescape_url(url, SLASHES, NULL);
1859 }
1860 AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes)
1861 {
1862     /* AllowEncodedSlashes (corrected) */
1863     if (decode_slashes) {
1864         /* no chars reserved */
1865         return unescape_url(url, NULL, NULL);
1866     } else {
1867         /* reserve (do not decode) encoded slashes */
1868         return unescape_url(url, NULL, SLASHES);
1869     }
1870 }
1871 #ifdef NEW_APIS
1872 /* IFDEF these out until they've been thought through.
1873  * Just a germ of an API extension for now
1874  */
1875 AP_DECLARE(int) ap_unescape_url_proxy(char *url)
1876 {
1877     /* leave RFC1738 reserved characters intact, * so proxied URLs
1878      * don't get mangled.  Where does that leave encoded '&' ?
1879      */
1880     return unescape_url(url, NULL, "/;?");
1881 }
1882 AP_DECLARE(int) ap_unescape_url_reserved(char *url, const char *reserved)
1883 {
1884     return unescape_url(url, NULL, reserved);
1885 }
1886 #endif
1887
1888 AP_DECLARE(int) ap_unescape_urlencoded(char *query)
1889 {
1890     char *slider;
1891
1892     /* replace plus with a space */
1893     if (query) {
1894         for (slider = query; *slider; slider++) {
1895             if (*slider == '+') {
1896                 *slider = ' ';
1897             }
1898         }
1899     }
1900
1901     /* unescape everything else */
1902     return unescape_url(query, NULL, NULL);
1903 }
1904
1905 AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname,
1906                                        apr_port_t port, const request_rec *r)
1907 {
1908     if (ap_is_default_port(port, r)) {
1909         return apr_pstrdup(p, hostname);
1910     }
1911     else {
1912         return apr_psprintf(p, "%s:%u", hostname, port);
1913     }
1914 }
1915
1916 AP_DECLARE(int) ap_unescape_all(char *url)
1917 {
1918     return unescape_url(url, NULL, NULL);
1919 }
1920
1921 /* c2x takes an unsigned, and expects the caller has guaranteed that
1922  * 0 <= what < 256... which usually means that you have to cast to
1923  * unsigned char first, because (unsigned)(char)(x) first goes through
1924  * signed extension to an int before the unsigned cast.
1925  *
1926  * The reason for this assumption is to assist gcc code generation --
1927  * the unsigned char -> unsigned extension is already done earlier in
1928  * both uses of this code, so there's no need to waste time doing it
1929  * again.
1930  */
1931 static const char c2x_table[] = "0123456789abcdef";
1932
1933 static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
1934                                      unsigned char *where)
1935 {
1936 #if APR_CHARSET_EBCDIC
1937     what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
1938 #endif /*APR_CHARSET_EBCDIC*/
1939     *where++ = prefix;
1940     *where++ = c2x_table[what >> 4];
1941     *where++ = c2x_table[what & 0xf];
1942     return where;
1943 }
1944
1945 /*
1946  * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
1947  * routine is (should be) OS independent.
1948  *
1949  * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
1950  * cases if a ':' occurs before the first '/' in the URL, the URL should be
1951  * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
1952  * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
1953  * efficiency reasons, we don't use escape_path_segment(), which is provided for
1954  * reference. Again, RFC 1808 is where this stuff is defined.
1955  *
1956  * If partial is set, os_escape_path() assumes that the path will be appended to
1957  * something with a '/' in it (and thus does not prefix "./").
1958  */
1959
1960 AP_DECLARE(char *) ap_escape_path_segment_buffer(char *copy, const char *segment)
1961 {
1962     const unsigned char *s = (const unsigned char *)segment;
1963     unsigned char *d = (unsigned char *)copy;
1964     unsigned c;
1965
1966     while ((c = *s)) {
1967         if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
1968             d = c2x(c, '%', d);
1969         }
1970         else {
1971             *d++ = c;
1972         }
1973         ++s;
1974     }
1975     *d = '\0';
1976     return copy;
1977 }
1978
1979 AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
1980 {
1981     return ap_escape_path_segment_buffer(apr_palloc(p, 3 * strlen(segment) + 1), segment);
1982 }
1983
1984 AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
1985 {
1986     /* Allocate +3 for potential "./" and trailing NULL.
1987      * Allocate another +1 to allow the caller to add a trailing '/' (see
1988      * comment in 'ap_sub_req_lookup_dirent')
1989      */
1990     char *copy = apr_palloc(p, 3 * strlen(path) + 3 + 1);
1991     const unsigned char *s = (const unsigned char *)path;
1992     unsigned char *d = (unsigned char *)copy;
1993     unsigned c;
1994
1995     if (!partial) {
1996         const char *colon = ap_strchr_c(path, ':');
1997         const char *slash = ap_strchr_c(path, '/');
1998
1999         if (colon && (!slash || colon < slash)) {
2000             *d++ = '.';
2001             *d++ = '/';
2002         }
2003     }
2004     while ((c = *s)) {
2005         if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
2006             d = c2x(c, '%', d);
2007         }
2008         else {
2009             *d++ = c;
2010         }
2011         ++s;
2012     }
2013     *d = '\0';
2014     return copy;
2015 }
2016
2017 AP_DECLARE(char *) ap_escape_urlencoded_buffer(char *copy, const char *buffer)
2018 {
2019     const unsigned char *s = (const unsigned char *)buffer;
2020     unsigned char *d = (unsigned char *)copy;
2021     unsigned c;
2022
2023     while ((c = *s)) {
2024         if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
2025             d = c2x(c, '%', d);
2026         }
2027         else if (c == ' ') {
2028             *d++ = '+';
2029         }
2030         else {
2031             *d++ = c;
2032         }
2033         ++s;
2034     }
2035     *d = '\0';
2036     return copy;
2037 }
2038
2039 AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
2040 {
2041     return ap_escape_urlencoded_buffer(apr_palloc(p, 3 * strlen(buffer) + 1), buffer);
2042 }
2043
2044 /* ap_escape_uri is now a macro for os_escape_path */
2045
2046 AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
2047 {
2048     int i, j;
2049     char *x;
2050
2051     /* first, count the number of extra characters */
2052     for (i = 0, j = 0; s[i] != '\0'; i++)
2053         if (s[i] == '<' || s[i] == '>')
2054             j += 3;
2055         else if (s[i] == '&')
2056             j += 4;
2057         else if (s[i] == '"')
2058             j += 5;
2059         else if (toasc && !apr_isascii(s[i]))
2060             j += 5;
2061
2062     if (j == 0)
2063         return apr_pstrmemdup(p, s, i);
2064
2065     x = apr_palloc(p, i + j + 1);
2066     for (i = 0, j = 0; s[i] != '\0'; i++, j++)
2067         if (s[i] == '<') {
2068             memcpy(&x[j], "&lt;", 4);
2069             j += 3;
2070         }
2071         else if (s[i] == '>') {
2072             memcpy(&x[j], "&gt;", 4);
2073             j += 3;
2074         }
2075         else if (s[i] == '&') {
2076             memcpy(&x[j], "&amp;", 5);
2077             j += 4;
2078         }
2079         else if (s[i] == '"') {
2080             memcpy(&x[j], "&quot;", 6);
2081             j += 5;
2082         }
2083         else if (toasc && !apr_isascii(s[i])) {
2084             char *esc = apr_psprintf(p, "&#%3.3d;", (unsigned char)s[i]);
2085             memcpy(&x[j], esc, 6);
2086             j += 5;
2087         }
2088         else
2089             x[j] = s[i];
2090
2091     x[j] = '\0';
2092     return x;
2093 }
2094 AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str)
2095 {
2096     char *ret;
2097     unsigned char *d;
2098     const unsigned char *s;
2099     apr_size_t length, escapes = 0;
2100
2101     if (!str) {
2102         return NULL;
2103     }
2104
2105     /* Compute how many characters need to be escaped */
2106     s = (const unsigned char *)str;
2107     for (; *s; ++s) {
2108         if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2109             escapes++;
2110         }
2111     }
2112     
2113     /* Compute the length of the input string, including NULL */
2114     length = s - (const unsigned char *)str + 1;
2115     
2116     /* Fast path: nothing to escape */
2117     if (escapes == 0) {
2118         return apr_pmemdup(p, str, length);
2119     }
2120     
2121     /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */
2122     ret = apr_palloc(p, length + 3 * escapes);
2123     d = (unsigned char *)ret;
2124     s = (const unsigned char *)str;
2125     for (; *s; ++s) {
2126         if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2127             *d++ = '\\';
2128             switch(*s) {
2129             case '\b':
2130                 *d++ = 'b';
2131                 break;
2132             case '\n':
2133                 *d++ = 'n';
2134                 break;
2135             case '\r':
2136                 *d++ = 'r';
2137                 break;
2138             case '\t':
2139                 *d++ = 't';
2140                 break;
2141             case '\v':
2142                 *d++ = 'v';
2143                 break;
2144             case '\\':
2145             case '"':
2146                 *d++ = *s;
2147                 break;
2148             default:
2149                 c2x(*s, 'x', d);
2150                 d += 3;
2151             }
2152         }
2153         else {
2154             *d++ = *s;
2155         }
2156     }
2157     *d = '\0';
2158
2159     return ret;
2160 }
2161
2162 AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
2163                                                apr_size_t buflen)
2164 {
2165     unsigned char *d, *ep;
2166     const unsigned char *s;
2167
2168     if (!source || !buflen) { /* be safe */
2169         return 0;
2170     }
2171
2172     d = (unsigned char *)dest;
2173     s = (const unsigned char *)source;
2174     ep = d + buflen - 1;
2175
2176     for (; d < ep && *s; ++s) {
2177
2178         if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2179             *d++ = '\\';
2180             if (d >= ep) {
2181                 --d;
2182                 break;
2183             }
2184
2185             switch(*s) {
2186             case '\b':
2187                 *d++ = 'b';
2188                 break;
2189             case '\n':
2190                 *d++ = 'n';
2191                 break;
2192             case '\r':
2193                 *d++ = 'r';
2194                 break;
2195             case '\t':
2196                 *d++ = 't';
2197                 break;
2198             case '\v':
2199                 *d++ = 'v';
2200                 break;
2201             case '\\':
2202                 *d++ = *s;
2203                 break;
2204             case '"': /* no need for this in error log */
2205                 d[-1] = *s;
2206                 break;
2207             default:
2208                 if (d >= ep - 2) {
2209                     ep = --d; /* break the for loop as well */
2210                     break;
2211                 }
2212                 c2x(*s, 'x', d);
2213                 d += 3;
2214             }
2215         }
2216         else {
2217             *d++ = *s;
2218         }
2219     }
2220     *d = '\0';
2221
2222     return (d - (unsigned char *)dest);
2223 }
2224
2225 AP_DECLARE(void) ap_bin2hex(const void *src, apr_size_t srclen, char *dest)
2226 {
2227     const unsigned char *in = src;
2228     apr_size_t i;
2229
2230     for (i = 0; i < srclen; i++) {
2231         *dest++ = c2x_table[in[i] >> 4];
2232         *dest++ = c2x_table[in[i] & 0xf];
2233     }
2234     *dest = '\0';
2235 }
2236
2237 AP_DECLARE(int) ap_has_cntrl(const char *str)
2238 {
2239     while (*str) {
2240         if (apr_iscntrl(*str))
2241             return 1;
2242         str++;
2243     }
2244     return 0;
2245 }
2246
2247 AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
2248 {
2249     apr_finfo_t finfo;
2250
2251     if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS)
2252         return 0;                /* in error condition, just return no */
2253
2254     return (finfo.filetype == APR_DIR);
2255 }
2256
2257 AP_DECLARE(int) ap_is_rdirectory(apr_pool_t *p, const char *path)
2258 {
2259     apr_finfo_t finfo;
2260
2261     if (apr_stat(&finfo, path, APR_FINFO_LINK | APR_FINFO_TYPE, p) != APR_SUCCESS)
2262         return 0;                /* in error condition, just return no */
2263
2264     return (finfo.filetype == APR_DIR);
2265 }
2266
2267 AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
2268                                   const char *src2)
2269 {
2270     apr_size_t len1, len2;
2271     char *path;
2272
2273     len1 = strlen(src1);
2274     len2 = strlen(src2);
2275      /* allocate +3 for '/' delimiter, trailing NULL and overallocate
2276       * one extra byte to allow the caller to add a trailing '/'
2277       */
2278     path = (char *)apr_palloc(a, len1 + len2 + 3);
2279     if (len1 == 0) {
2280         *path = '/';
2281         memcpy(path + 1, src2, len2 + 1);
2282     }
2283     else {
2284         char *next;
2285         memcpy(path, src1, len1);
2286         next = path + len1;
2287         if (next[-1] != '/') {
2288             *next++ = '/';
2289         }
2290         memcpy(next, src2, len2 + 1);
2291     }
2292     return path;
2293 }
2294
2295 /*
2296  * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
2297  */
2298 AP_DECLARE(int) ap_is_url(const char *u)
2299 {
2300     int x;
2301
2302     for (x = 0; u[x] != ':'; x++) {
2303         if ((!u[x]) ||
2304             ((!apr_isalnum(u[x])) &&
2305              (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
2306             return 0;
2307         }
2308     }
2309
2310     return (x ? 1 : 0);                /* If the first character is ':', it's broken, too */
2311 }
2312
2313 AP_DECLARE(int) ap_ind(const char *s, char c)
2314 {
2315     const char *p = ap_strchr_c(s, c);
2316
2317     if (p == NULL)
2318         return -1;
2319     return p - s;
2320 }
2321
2322 AP_DECLARE(int) ap_rind(const char *s, char c)
2323 {
2324     const char *p = ap_strrchr_c(s, c);
2325
2326     if (p == NULL)
2327         return -1;
2328     return p - s;
2329 }
2330
2331 AP_DECLARE(void) ap_str_tolower(char *str)
2332 {
2333     while (*str) {
2334         *str = apr_tolower(*str);
2335         ++str;
2336     }
2337 }
2338
2339 AP_DECLARE(void) ap_str_toupper(char *str)
2340 {
2341     while (*str) {
2342         *str = apr_toupper(*str);
2343         ++str;
2344     }
2345 }
2346
2347 /*
2348  * We must return a FQDN
2349  */
2350 char *ap_get_local_host(apr_pool_t *a)
2351 {
2352 #ifndef MAXHOSTNAMELEN
2353 #define MAXHOSTNAMELEN 256
2354 #endif
2355     char str[MAXHOSTNAMELEN + 1];
2356     char *server_hostname = NULL;
2357     apr_sockaddr_t *sockaddr;
2358     char *hostname;
2359
2360     if (apr_gethostname(str, sizeof(str) - 1, a) != APR_SUCCESS) {
2361         ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00556)
2362                      "%s: apr_gethostname() failed to determine ServerName",
2363                      ap_server_argv0);
2364     } else {
2365         str[sizeof(str) - 1] = '\0';
2366         if (apr_sockaddr_info_get(&sockaddr, str, APR_UNSPEC, 0, 0, a) == APR_SUCCESS) {
2367             if ( (apr_getnameinfo(&hostname, sockaddr, 0) == APR_SUCCESS) &&
2368                 (ap_strchr_c(hostname, '.')) ) {
2369                 server_hostname = apr_pstrdup(a, hostname);
2370                 return server_hostname;
2371             } else if (ap_strchr_c(str, '.')) {
2372                 server_hostname = apr_pstrdup(a, str);
2373             } else {
2374                 apr_sockaddr_ip_get(&hostname, sockaddr);
2375                 server_hostname = apr_pstrdup(a, hostname);
2376             }
2377         } else {
2378             ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00557)
2379                          "%s: apr_sockaddr_info_get() failed for %s",
2380                          ap_server_argv0, str);
2381         }
2382     }
2383
2384     if (!server_hostname)
2385         server_hostname = apr_pstrdup(a, "127.0.0.1");
2386
2387     ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, a, APLOGNO(00558)
2388                  "%s: Could not reliably determine the server's fully qualified "
2389                  "domain name, using %s. Set the 'ServerName' directive globally "
2390                  "to suppress this message",
2391                  ap_server_argv0, server_hostname);
2392
2393     return server_hostname;
2394 }
2395
2396 /* simple 'pool' alloc()ing glue to apr_base64.c
2397  */
2398 AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
2399 {
2400     char *decoded;
2401     int l;
2402
2403     decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded));
2404     l = apr_base64_decode(decoded, bufcoded);
2405     decoded[l] = '\0'; /* make binary sequence into string */
2406
2407     return decoded;
2408 }
2409
2410 AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
2411 {
2412     char *encoded;
2413     int l = strlen(string);
2414
2415     encoded = (char *) apr_palloc(p, 1 + apr_base64_encode_len(l));
2416     l = apr_base64_encode(encoded, string, l);
2417     encoded[l] = '\0'; /* make binary sequence into string */
2418
2419     return encoded;
2420 }
2421
2422 /* we want to downcase the type/subtype for comparison purposes
2423  * but nothing else because ;parameter=foo values are case sensitive.
2424  * XXX: in truth we want to downcase parameter names... but really,
2425  * apache has never handled parameters and such correctly.  You
2426  * also need to compress spaces and such to be able to compare
2427  * properly. -djg
2428  */
2429 AP_DECLARE(void) ap_content_type_tolower(char *str)
2430 {
2431     char *semi;
2432
2433     semi = strchr(str, ';');
2434     if (semi) {
2435         *semi = '\0';
2436     }
2437
2438     ap_str_tolower(str);
2439
2440     if (semi) {
2441         *semi = ';';
2442     }
2443 }
2444
2445 /*
2446  * Given a string, replace any bare " with \" .
2447  */
2448 AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
2449 {
2450     int newlen = 0;
2451     const char *inchr = instring;
2452     char *outchr, *outstring;
2453
2454     /*
2455      * Look through the input string, jogging the length of the output
2456      * string up by an extra byte each time we find an unescaped ".
2457      */
2458     while (*inchr != '\0') {
2459         newlen++;
2460         if (*inchr == '"') {
2461             newlen++;
2462         }
2463         /*
2464          * If we find a slosh, and it's not the last byte in the string,
2465          * it's escaping something - advance past both bytes.
2466          */
2467         if ((*inchr == '\\') && (inchr[1] != '\0')) {
2468             inchr++;
2469             newlen++;
2470         }
2471         inchr++;
2472     }
2473     outstring = apr_palloc(p, newlen + 1);
2474     inchr = instring;
2475     outchr = outstring;
2476     /*
2477      * Now copy the input string to the output string, inserting a slosh
2478      * in front of every " that doesn't already have one.
2479      */
2480     while (*inchr != '\0') {
2481         if ((*inchr == '\\') && (inchr[1] != '\0')) {
2482             *outchr++ = *inchr++;
2483             *outchr++ = *inchr++;
2484         }
2485         if (*inchr == '"') {
2486             *outchr++ = '\\';
2487         }
2488         if (*inchr != '\0') {
2489             *outchr++ = *inchr++;
2490         }
2491     }
2492     *outchr = '\0';
2493     return outstring;
2494 }
2495
2496 /*
2497  * Given a string, append the PID deliminated by delim.
2498  * Usually used to create a pid-appended filepath name
2499  * (eg: /a/b/foo -> /a/b/foo.6726). A function, and not
2500  * a macro, to avoid unistd.h dependency
2501  */
2502 AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string,
2503                                     const char *delim)
2504 {
2505     return apr_psprintf(p, "%s%s%" APR_PID_T_FMT, string,
2506                         delim, getpid());
2507
2508 }
2509
2510 /**
2511  * Parse a given timeout parameter string into an apr_interval_time_t value.
2512  * The unit of the time interval is given as postfix string to the numeric
2513  * string. Currently the following units are understood:
2514  *
2515  * ms    : milliseconds
2516  * s     : seconds
2517  * mi[n] : minutes
2518  * h     : hours
2519  *
2520  * If no unit is contained in the given timeout parameter the default_time_unit
2521  * will be used instead.
2522  * @param timeout_parameter The string containing the timeout parameter.
2523  * @param timeout The timeout value to be returned.
2524  * @param default_time_unit The default time unit to use if none is specified
2525  * in timeout_parameter.
2526  * @return Status value indicating whether the parsing was successful or not.
2527  */
2528 AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
2529                                                const char *timeout_parameter,
2530                                                apr_interval_time_t *timeout,
2531                                                const char *default_time_unit)
2532 {
2533     char *endp;
2534     const char *time_str;
2535     apr_int64_t tout;
2536
2537     tout = apr_strtoi64(timeout_parameter, &endp, 10);
2538     if (errno) {
2539         return errno;
2540     }
2541     if (!endp || !*endp) {
2542         time_str = default_time_unit;
2543     }
2544     else {
2545         time_str = endp;
2546     }
2547
2548     switch (*time_str) {
2549         /* Time is in seconds */
2550     case 's':
2551         *timeout = (apr_interval_time_t) apr_time_from_sec(tout);
2552         break;
2553     case 'h':
2554         /* Time is in hours */
2555         *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 3600);
2556         break;
2557     case 'm':
2558         switch (*(++time_str)) {
2559         /* Time is in milliseconds */
2560         case 's':
2561             *timeout = (apr_interval_time_t) tout * 1000;
2562             break;
2563         /* Time is in minutes */
2564         case 'i':
2565             *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 60);
2566             break;
2567         default:
2568             return APR_EGENERAL;
2569         }
2570         break;
2571     default:
2572         return APR_EGENERAL;
2573     }
2574     return APR_SUCCESS;
2575 }
2576
2577 /**
2578  * Determine if a request has a request body or not.
2579  *
2580  * @param r the request_rec of the request
2581  * @return truth value
2582  */
2583 AP_DECLARE(int) ap_request_has_body(request_rec *r)
2584 {
2585     apr_off_t cl;
2586     char *estr;
2587     const char *cls;
2588     int has_body;
2589
2590     has_body = (!r->header_only
2591                 && (r->kept_body
2592                     || apr_table_get(r->headers_in, "Transfer-Encoding")
2593                     || ( (cls = apr_table_get(r->headers_in, "Content-Length"))
2594                         && (apr_strtoff(&cl, cls, &estr, 10) == APR_SUCCESS)
2595                         && (!*estr)
2596                         && (cl > 0) )
2597                     )
2598                 );
2599     return has_body;
2600 }
2601
2602 AP_DECLARE_NONSTD(apr_status_t) ap_pool_cleanup_set_null(void *data_)
2603 {
2604     void **ptr = (void **)data_;
2605     *ptr = NULL;
2606     return APR_SUCCESS;
2607 }
2608
2609 AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
2610
2611     for ( ; *src; src++, dest++)
2612     {
2613         if (!apr_isprint(*src))
2614             *dest = 'x';
2615         else if (!apr_isalnum(*src))
2616             *dest = '_';
2617         else
2618             *dest = (char)*src;
2619     }
2620     *dest = '\0';
2621     return APR_SUCCESS;
2622
2623 }
2624
2625 AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
2626                                         const char **dest)
2627 {
2628     char *new = apr_palloc(p, strlen(src)+1);
2629     if (!new)
2630         return APR_ENOMEM;
2631     *dest = new;
2632     return ap_str2_alnum(src, new);
2633 }
2634
2635 /**
2636  * Read the body and parse any form found, which must be of the
2637  * type application/x-www-form-urlencoded.
2638  *
2639  * Name/value pairs are returned in an array, with the names as
2640  * strings with a maximum length of HUGE_STRING_LEN, and the
2641  * values as bucket brigades. This allows values to be arbitrarily
2642  * large.
2643  *
2644  * All url-encoding is removed from both the names and the values
2645  * on the fly. The names are interpreted as strings, while the
2646  * values are interpreted as blocks of binary data, that may
2647  * contain the 0 character.
2648  *
2649  * In order to ensure that resource limits are not exceeded, a
2650  * maximum size must be provided. If the sum of the lengths of
2651  * the names and the values exceed this size, this function
2652  * will return HTTP_REQUEST_ENTITY_TOO_LARGE.
2653  *
2654  * An optional number of parameters can be provided, if the number
2655  * of parameters provided exceeds this amount, this function will
2656  * return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
2657  * no limit is imposed, and the number of parameters is in turn
2658  * constrained by the size parameter above.
2659  *
2660  * This function honours any kept_body configuration, and the
2661  * original raw request body will be saved to the kept_body brigade
2662  * if so configured, just as ap_discard_request_body does.
2663  *
2664  * NOTE: File upload is not yet supported, but can be without change
2665  * to the function call.
2666  */
2667
2668 /* form parsing stuff */
2669 typedef enum {
2670     FORM_NORMAL,
2671     FORM_AMP,
2672     FORM_NAME,
2673     FORM_VALUE,
2674     FORM_PERCENTA,
2675     FORM_PERCENTB,
2676     FORM_ABORT
2677 } ap_form_type_t;
2678
2679 AP_DECLARE(int) ap_parse_form_data(request_rec *r, ap_filter_t *f,
2680                                    apr_array_header_t **ptr,
2681                                    apr_size_t num, apr_size_t usize)
2682 {
2683     apr_bucket_brigade *bb = NULL;
2684     int seen_eos = 0;
2685     char buffer[HUGE_STRING_LEN + 1];
2686     const char *ct;
2687     apr_size_t offset = 0;
2688     apr_ssize_t size;
2689     ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
2690     ap_form_pair_t *pair = NULL;
2691     apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
2692
2693     char hi = 0;
2694     char low = 0;
2695
2696     *ptr = pairs;
2697
2698     /* sanity check - we only support forms for now */
2699     ct = apr_table_get(r->headers_in, "Content-Type");
2700     if (!ct || ap_cstr_casecmpn("application/x-www-form-urlencoded", ct, 33)) {
2701         return ap_discard_request_body(r);
2702     }
2703
2704     if (usize > APR_SIZE_MAX >> 1)
2705         size = APR_SIZE_MAX >> 1;
2706     else
2707         size = usize;
2708
2709     if (!f) {
2710         f = r->input_filters;
2711     }
2712
2713     bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2714     do {
2715         apr_bucket *bucket = NULL, *last = NULL;
2716
2717         int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
2718                                 APR_BLOCK_READ, HUGE_STRING_LEN);
2719         if (rv != APR_SUCCESS) {
2720             apr_brigade_destroy(bb);
2721             return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
2722         }
2723
2724         for (bucket = APR_BRIGADE_FIRST(bb);
2725              bucket != APR_BRIGADE_SENTINEL(bb);
2726              last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
2727             const char *data;
2728             apr_size_t len, slide;
2729
2730             if (last) {
2731                 apr_bucket_delete(last);
2732             }
2733             if (APR_BUCKET_IS_EOS(bucket)) {
2734                 seen_eos = 1;
2735                 break;
2736             }
2737             if (bucket->length == 0) {
2738                 continue;
2739             }
2740
2741             rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
2742             if (rv != APR_SUCCESS) {
2743                 apr_brigade_destroy(bb);
2744                 return HTTP_BAD_REQUEST;
2745             }
2746
2747             slide = len;
2748             while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
2749                 char c = *data++;
2750                 if ('+' == c) {
2751                     c = ' ';
2752                 }
2753                 else if ('&' == c) {
2754                     state = FORM_AMP;
2755                 }
2756                 if ('%' == c) {
2757                     percent = FORM_PERCENTA;
2758                     continue;
2759                 }
2760                 if (FORM_PERCENTA == percent) {
2761                     if (c >= 'a') {
2762                         hi = c - 'a' + 10;
2763                     }
2764                     else if (c >= 'A') {
2765                         hi = c - 'A' + 10;
2766                     }
2767                     else if (c >= '0') {
2768                         hi = c - '0';
2769                     }
2770                     hi = hi << 4;
2771                     percent = FORM_PERCENTB;
2772                     continue;
2773                 }
2774                 if (FORM_PERCENTB == percent) {
2775                     if (c >= 'a') {
2776                         low = c - 'a' + 10;
2777                     }
2778                     else if (c >= 'A') {
2779                         low = c - 'A' + 10;
2780                     }
2781                     else if (c >= '0') {
2782                         low = c - '0';
2783                     }
2784                     c = low | hi;
2785                     percent = FORM_NORMAL;
2786                 }
2787                 switch (state) {
2788                     case FORM_AMP:
2789                         if (pair) {
2790                             const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2791                             apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2792                             APR_BRIGADE_INSERT_TAIL(pair->value, b);
2793                         }
2794                         state = FORM_NAME;
2795                         pair = NULL;
2796                         offset = 0;
2797                         num--;
2798                         break;
2799                     case FORM_NAME:
2800                         if (offset < HUGE_STRING_LEN) {
2801                             if ('=' == c) {
2802                                 buffer[offset] = 0;
2803                                 offset = 0;
2804                                 pair = (ap_form_pair_t *) apr_array_push(pairs);
2805                                 pair->name = apr_pstrdup(r->pool, buffer);
2806                                 pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2807                                 state = FORM_VALUE;
2808                             }
2809                             else {
2810                                 buffer[offset++] = c;
2811                                 size--;
2812                             }
2813                         }
2814                         else {
2815                             state = FORM_ABORT;
2816                         }
2817                         break;
2818                     case FORM_VALUE:
2819                         if (offset >= HUGE_STRING_LEN) {
2820                             const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2821                             apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2822                             APR_BRIGADE_INSERT_TAIL(pair->value, b);
2823                             offset = 0;
2824                         }
2825                         buffer[offset++] = c;
2826                         size--;
2827                         break;
2828                     default:
2829                         break;
2830                 }
2831             }
2832
2833         }
2834
2835         apr_brigade_cleanup(bb);
2836     } while (!seen_eos);
2837
2838     if (FORM_ABORT == state || size < 0 || num == 0) {
2839         return HTTP_REQUEST_ENTITY_TOO_LARGE;
2840     }
2841     else if (FORM_VALUE == state && pair && offset > 0) {
2842         const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2843         apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2844         APR_BRIGADE_INSERT_TAIL(pair->value, b);
2845     }
2846
2847     return OK;
2848
2849 }
2850
2851 #define VARBUF_SMALL_SIZE 2048
2852 #define VARBUF_MAX_SIZE   (APR_SIZE_MAX - 1 -                                \
2853                            APR_ALIGN_DEFAULT(sizeof(struct ap_varbuf_info)))
2854
2855 struct ap_varbuf_info {
2856     struct apr_memnode_t *node;
2857     apr_allocator_t *allocator;
2858 };
2859
2860 static apr_status_t varbuf_cleanup(void *info_)
2861 {
2862     struct ap_varbuf_info *info = info_;
2863     info->node->next = NULL;
2864     apr_allocator_free(info->allocator, info->node);
2865     return APR_SUCCESS;
2866 }
2867
2868 const char nul = '\0';
2869 static char * const varbuf_empty = (char *)&nul;
2870
2871 AP_DECLARE(void) ap_varbuf_init(apr_pool_t *p, struct ap_varbuf *vb,
2872                                 apr_size_t init_size)
2873 {
2874     vb->buf = varbuf_empty;
2875     vb->avail = 0;
2876     vb->strlen = AP_VARBUF_UNKNOWN;
2877     vb->pool = p;
2878     vb->info = NULL;
2879
2880     ap_varbuf_grow(vb, init_size);
2881 }
2882
2883 AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
2884 {
2885     apr_memnode_t *new_node = NULL;
2886     apr_allocator_t *allocator;
2887     struct ap_varbuf_info *new_info;
2888     char *new;
2889
2890     AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN || vb->avail >= vb->strlen);
2891
2892     if (new_len <= vb->avail)
2893         return;
2894
2895     if (new_len < 2 * vb->avail && vb->avail < VARBUF_MAX_SIZE/2) {
2896         /* at least double the size, to avoid repeated reallocations */
2897         new_len = 2 * vb->avail;
2898     }
2899     else if (new_len > VARBUF_MAX_SIZE) {
2900         apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2901         ap_assert(abort_fn != NULL);
2902         abort_fn(APR_ENOMEM);
2903         return;
2904     }
2905
2906     new_len++;  /* add space for trailing \0 */
2907     if (new_len <= VARBUF_SMALL_SIZE) {
2908         new_len = APR_ALIGN_DEFAULT(new_len);
2909         new = apr_palloc(vb->pool, new_len);
2910         if (vb->avail && vb->strlen != 0) {
2911             AP_DEBUG_ASSERT(vb->buf != NULL);
2912             AP_DEBUG_ASSERT(vb->buf != varbuf_empty);
2913             if (new == vb->buf + vb->avail + 1) {
2914                 /* We are lucky: the new memory lies directly after our old
2915                  * buffer, we can now use both.
2916                  */
2917                 vb->avail += new_len;
2918                 return;
2919             }
2920             else {
2921                 /* copy up to vb->strlen + 1 bytes */
2922                 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2923                                      vb->avail + 1 : vb->strlen + 1);
2924             }
2925         }
2926         else {
2927             *new = '\0';
2928         }
2929         vb->avail = new_len - 1;
2930         vb->buf = new;
2931         return;
2932     }
2933
2934     /* The required block is rather larger. Use allocator directly so that
2935      * the memory can be freed independently from the pool. */
2936     allocator = apr_pool_allocator_get(vb->pool);
2937     if (new_len <= VARBUF_MAX_SIZE)
2938         new_node = apr_allocator_alloc(allocator,
2939                                        new_len + APR_ALIGN_DEFAULT(sizeof(*new_info)));
2940     if (!new_node) {
2941         apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2942         ap_assert(abort_fn != NULL);
2943         abort_fn(APR_ENOMEM);
2944         return;
2945     }
2946     new_info = (struct ap_varbuf_info *)new_node->first_avail;
2947     new_node->first_avail += APR_ALIGN_DEFAULT(sizeof(*new_info));
2948     new_info->node = new_node;
2949     new_info->allocator = allocator;
2950     new = new_node->first_avail;
2951     AP_DEBUG_ASSERT(new_node->endp - new_node->first_avail >= new_len);
2952     new_len = new_node->endp - new_node->first_avail;
2953
2954     if (vb->avail && vb->strlen != 0)
2955         memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2956                              vb->avail + 1 : vb->strlen + 1);
2957     else
2958         *new = '\0';
2959     if (vb->info)
2960         apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
2961     apr_pool_cleanup_register(vb->pool, new_info, varbuf_cleanup,
2962                               apr_pool_cleanup_null);
2963     vb->info = new_info;
2964     vb->buf = new;
2965     vb->avail = new_len - 1;
2966 }
2967
2968 AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
2969                                      int len)
2970 {
2971     if (len == 0)
2972         return;
2973     if (!vb->avail) {
2974         ap_varbuf_grow(vb, len);
2975         memcpy(vb->buf, str, len);
2976         vb->buf[len] = '\0';
2977         vb->strlen = len;
2978         return;
2979     }
2980     if (vb->strlen == AP_VARBUF_UNKNOWN)
2981         vb->strlen = strlen(vb->buf);
2982     ap_varbuf_grow(vb, vb->strlen + len);
2983     memcpy(vb->buf + vb->strlen, str, len);
2984     vb->strlen += len;
2985     vb->buf[vb->strlen] = '\0';
2986 }
2987
2988 AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb)
2989 {
2990     if (vb->info) {
2991         apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
2992         vb->info = NULL;
2993     }
2994     vb->buf = NULL;
2995 }
2996
2997 AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *buf,
2998                                   const char *prepend, apr_size_t prepend_len,
2999                                   const char *append, apr_size_t append_len,
3000                                   apr_size_t *new_len)
3001 {
3002     apr_size_t i = 0;
3003     struct iovec vec[3];
3004
3005     if (prepend) {
3006         vec[i].iov_base = (void *)prepend;
3007         vec[i].iov_len = prepend_len;
3008         i++;
3009     }
3010     if (buf->avail && buf->strlen) {
3011         if (buf->strlen == AP_VARBUF_UNKNOWN)
3012             buf->strlen = strlen(buf->buf);
3013         vec[i].iov_base = (void *)buf->buf;
3014         vec[i].iov_len = buf->strlen;
3015         i++;
3016     }
3017     if (append) {
3018         vec[i].iov_base = (void *)append;
3019         vec[i].iov_len = append_len;
3020         i++;
3021     }
3022     if (i)
3023         return apr_pstrcatv(p, vec, i, new_len);
3024
3025     if (new_len)
3026         *new_len = 0;
3027     return "";
3028 }
3029
3030 AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb,
3031                                           const char *input,
3032                                           const char *source,
3033                                           apr_size_t nmatch,
3034                                           ap_regmatch_t pmatch[],
3035                                           apr_size_t maxlen)
3036 {
3037     return regsub_core(NULL, NULL, vb, input, source, nmatch, pmatch, maxlen);
3038 }
3039
3040 static const char * const oom_message = "[crit] Memory allocation failed, "
3041                                         "aborting process." APR_EOL_STR;
3042
3043 AP_DECLARE(void) ap_abort_on_oom()
3044 {
3045     int written, count = strlen(oom_message);
3046     const char *buf = oom_message;
3047     do {
3048         written = write(STDERR_FILENO, buf, count);
3049         if (written == count)
3050             break;
3051         if (written > 0) {
3052             buf += written;
3053             count -= written;
3054         }
3055     } while (written >= 0 || errno == EINTR);
3056     abort();
3057 }
3058
3059 AP_DECLARE(void *) ap_malloc(size_t size)
3060 {
3061     void *p = malloc(size);
3062     if (p == NULL && size != 0)
3063         ap_abort_on_oom();
3064     return p;
3065 }
3066
3067 AP_DECLARE(void *) ap_calloc(size_t nelem, size_t size)
3068 {
3069     void *p = calloc(nelem, size);
3070     if (p == NULL && nelem != 0 && size != 0)
3071         ap_abort_on_oom();
3072     return p;
3073 }
3074
3075 AP_DECLARE(void *) ap_realloc(void *ptr, size_t size)
3076 {
3077     void *p = realloc(ptr, size);
3078     if (p == NULL && size != 0)
3079         ap_abort_on_oom();
3080     return p;
3081 }
3082
3083 AP_DECLARE(void) ap_get_sload(ap_sload_t *ld)
3084 {
3085     int i, j, server_limit, thread_limit;
3086     int ready = 0;
3087     int busy = 0;
3088     int total;
3089     ap_generation_t mpm_generation;
3090
3091     /* preload errored fields, we overwrite */
3092     ld->idle = -1;
3093     ld->busy = -1;
3094     ld->bytes_served = 0;
3095     ld->access_count = 0;
3096
3097     ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
3098     ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
3099     ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
3100
3101     for (i = 0; i < server_limit; i++) {
3102         process_score *ps;
3103         ps = ap_get_scoreboard_process(i);
3104
3105         for (j = 0; j < thread_limit; j++) {
3106             int res;
3107             worker_score *ws = NULL;
3108             ws = &ap_scoreboard_image->servers[i][j];
3109             res = ws->status;
3110
3111             if (!ps->quiescing && ps->pid) {
3112                 if (res == SERVER_READY && ps->generation == mpm_generation) {
3113                     ready++;
3114                 }
3115                 else if (res != SERVER_DEAD &&
3116                          res != SERVER_STARTING && res != SERVER_IDLE_KILL &&
3117                          ps->generation == mpm_generation) {
3118                     busy++;
3119                 }   
3120             }
3121
3122             if (ap_extended_status && !ps->quiescing && ps->pid) {
3123                 if (ws->access_count != 0 
3124                     || (res != SERVER_READY && res != SERVER_DEAD)) {
3125                     ld->access_count += ws->access_count;
3126                     ld->bytes_served += ws->bytes_served;
3127                 }
3128             }
3129         }
3130     }
3131     total = busy + ready;
3132     if (total) {
3133         ld->idle = ready * 100 / total;
3134         ld->busy = busy * 100 / total;
3135     }
3136 }
3137
3138 AP_DECLARE(void) ap_get_loadavg(ap_loadavg_t *ld)
3139 {
3140     /* preload errored fields, we overwrite */
3141     ld->loadavg = -1.0;
3142     ld->loadavg5 = -1.0;
3143     ld->loadavg15 = -1.0;
3144
3145 #if HAVE_GETLOADAVG
3146     {
3147         double la[3];
3148         int num;
3149
3150         num = getloadavg(la, 3);
3151         if (num > 0) {
3152             ld->loadavg = (float)la[0];
3153         }
3154         if (num > 1) {
3155             ld->loadavg5 = (float)la[1];
3156         }
3157         if (num > 2) {
3158             ld->loadavg15 = (float)la[2];
3159         }
3160     }
3161 #endif
3162 }
3163
3164 static const char * const pw_cache_note_name = "conn_cache_note";
3165 struct pw_cache {
3166     /* varbuf contains concatenated password and hash */
3167     struct ap_varbuf vb;
3168     apr_size_t pwlen;
3169     apr_status_t result;
3170 };
3171
3172 AP_DECLARE(apr_status_t) ap_password_validate(request_rec *r,
3173                                               const char *username,
3174                                               const char *passwd,
3175                                               const char *hash)
3176 {
3177     struct pw_cache *cache;
3178     apr_size_t hashlen;
3179
3180     cache = (struct pw_cache *)apr_table_get(r->connection->notes, pw_cache_note_name);
3181     if (cache != NULL) {
3182         if (strncmp(passwd, cache->vb.buf, cache->pwlen) == 0
3183             && strcmp(hash, cache->vb.buf + cache->pwlen) == 0) {
3184             return cache->result;
3185         }
3186         /* make ap_varbuf_grow below not copy the old data */
3187         cache->vb.strlen = 0;
3188     }
3189     else {
3190         cache = apr_palloc(r->connection->pool, sizeof(struct pw_cache));
3191         ap_varbuf_init(r->connection->pool, &cache->vb, 0);
3192         apr_table_setn(r->connection->notes, pw_cache_note_name, (void *)cache);
3193     }
3194     cache->pwlen = strlen(passwd);
3195     hashlen = strlen(hash);
3196     ap_varbuf_grow(&cache->vb, cache->pwlen + hashlen + 1);
3197     memcpy(cache->vb.buf, passwd, cache->pwlen);
3198     memcpy(cache->vb.buf + cache->pwlen, hash, hashlen + 1);
3199     cache->result = apr_password_validate(passwd, hash);
3200     return cache->result;
3201 }
3202
3203 AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p,
3204                                     const char *cmd,
3205                                     const char * const * argv)
3206 {
3207     char buf[MAX_STRING_LEN];
3208     apr_procattr_t *procattr;
3209     apr_proc_t *proc;
3210     apr_file_t *fp;
3211     apr_size_t nbytes = 1;
3212     char c;
3213     int k;
3214
3215     if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
3216         return NULL;
3217     if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
3218                             APR_FULL_BLOCK) != APR_SUCCESS)
3219         return NULL;
3220     if (apr_procattr_dir_set(procattr,
3221                              ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
3222         return NULL;
3223     if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
3224         return NULL;
3225     proc = apr_pcalloc(p, sizeof(apr_proc_t));
3226     if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
3227         return NULL;
3228     fp = proc->out;
3229
3230     if (fp == NULL)
3231         return NULL;
3232     /* XXX: we are reading 1 byte at a time here */
3233     for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
3234                 && nbytes == 1 && (k < MAX_STRING_LEN-1)     ; ) {
3235         if (c == '\n' || c == '\r')
3236             break;
3237         buf[k++] = c;
3238     }
3239     buf[k] = '\0'; 
3240     apr_file_close(fp);
3241
3242     return apr_pstrndup(p, buf, k);
3243 }
3244
3245 AP_DECLARE(int) ap_array_str_index(const apr_array_header_t *array, 
3246                                    const char *s,
3247                                    int start)
3248 {
3249     if (start >= 0) {
3250         int i;
3251         
3252         for (i = start; i < array->nelts; i++) {
3253             const char *p = APR_ARRAY_IDX(array, i, const char *);
3254             if (!strcmp(p, s)) {
3255                 return i;
3256             }
3257         }
3258     }
3259     
3260     return -1;
3261 }
3262
3263 AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array, 
3264                                       const char *s)
3265 {
3266     return (ap_array_str_index(array, s, 0) >= 0);
3267 }
3268
3269 #if !APR_CHARSET_EBCDIC
3270 /*
3271  * Our own known-fast translation table for casecmp by character.
3272  * Only ASCII alpha characters 41-5A are folded to 61-7A, other
3273  * octets (such as extended latin alphabetics) are never case-folded.
3274  * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3275  */
3276 static const short ucharmap[] = {
3277     0x0,  0x1,  0x2,  0x3,  0x4,  0x5,  0x6,  0x7,
3278     0x8,  0x9,  0xa,  0xb,  0xc,  0xd,  0xe,  0xf,
3279     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3280     0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3281     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3282     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3283     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3284     0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3285     0x40,  'a',  'b',  'c',  'd',  'e',  'f',  'g',
3286      'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
3287      'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
3288      'x',  'y',  'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3289     0x60,  'a',  'b',  'c',  'd',  'e',  'f',  'g',
3290      'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
3291      'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
3292      'x',  'y',  'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3293     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3294     0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3295     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3296     0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3297     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3298     0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3299     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3300     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3301     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3302     0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3303     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3304     0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3305     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3306     0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3307     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3308     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3309 };
3310 #else /* APR_CHARSET_EBCDIC */
3311 /*
3312  * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison,
3313  * provides unique identity of every char value (strict ISO-646
3314  * conformance, arbitrary election of an ISO-8859-1 ordering, and
3315  * very arbitrary control code assignments into C1 to achieve
3316  * identity and a reversible mapping of code points),
3317  * then folding the equivalences of ASCII 41-5A into 61-7A, 
3318  * presenting comparison results in a somewhat ISO/IEC 10646
3319  * (ASCII-like) order, depending on the EBCDIC code page in use.
3320  *
3321  * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3322  */
3323 static const short ucharmap[] = {
3324     0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
3325     0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
3326     0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
3327     0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
3328     0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
3329     0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
3330     0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
3331     0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
3332     0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,
3333     0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
3334     0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,
3335     0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
3336     0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,
3337     0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
3338     0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,
3339     0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
3340     0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3341     0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,
3342     0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3343     0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,
3344     0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3345     0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE,
3346     0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,
3347     0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7,
3348     0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3349     0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,
3350     0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3351     0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,
3352     0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3353     0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,
3354     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3355     0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F
3356 };
3357 #endif
3358
3359 AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2)
3360 {
3361     const unsigned char *str1 = (const unsigned char *)s1;
3362     const unsigned char *str2 = (const unsigned char *)s2;
3363     for (;;)
3364     {
3365         const int c1 = (int)(*str1);
3366         const int c2 = (int)(*str2);
3367         const int cmp = ucharmap[c1] - ucharmap[c2];
3368         /* Not necessary to test for !c2, this is caught by cmp */
3369         if (cmp || !c1)
3370             return cmp;
3371         str1++;
3372         str2++;
3373     }
3374 }
3375
3376 AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
3377 {
3378     const unsigned char *str1 = (const unsigned char *)s1;
3379     const unsigned char *str2 = (const unsigned char *)s2;
3380     while (n--)
3381     {
3382         const int c1 = (int)(*str1);
3383         const int c2 = (int)(*str2);
3384         const int cmp = ucharmap[c1] - ucharmap[c2];
3385         /* Not necessary to test for !c2, this is caught by cmp */
3386         if (cmp || !c1)
3387             return cmp;
3388         str1++;
3389         str2++;
3390     }
3391     return 0;
3392 }
3393