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