]> granicus.if.org Git - apache/blob - server/util.c
Add an END flag to RewriteRule that acts like L=LAST but also prevents
[apache] / server / util.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * util.c: string utility things
19  *
20  * 3/21/93 Rob McCool
21  * 1995-96 Many changes by the Apache Software Foundation
22  *
23  */
24
25 /* Debugging aid:
26  * #define DEBUG            to trace all cfg_open*()/cfg_closefile() calls
27  * #define DEBUG_CFG_LINES  to trace every line read from the config files
28  */
29
30 #include "apr.h"
31 #include "apr_strings.h"
32 #include "apr_lib.h"
33
34 #define APR_WANT_STDIO
35 #define APR_WANT_STRFUNC
36 #include "apr_want.h"
37
38 #if APR_HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 #if APR_HAVE_PROCESS_H
42 #include <process.h>            /* for getpid() on Win32 */
43 #endif
44 #if APR_HAVE_NETDB_H
45 #include <netdb.h>              /* for gethostbyname() */
46 #endif
47
48 #include "ap_config.h"
49 #include "apr_base64.h"
50 #include "httpd.h"
51 #include "http_main.h"
52 #include "http_log.h"
53 #include "http_protocol.h"
54 #include "http_config.h"
55 #include "util_ebcdic.h"
56
57 #ifdef HAVE_PWD_H
58 #include <pwd.h>
59 #endif
60 #ifdef HAVE_GRP_H
61 #include <grp.h>
62 #endif
63
64 /* A bunch of functions in util.c scan strings looking for certain characters.
65  * To make that more efficient we encode a lookup table.  The test_char_table
66  * is generated automatically by gen_test_char.c.
67  */
68 #include "test_char.h"
69
70 /* we assume the folks using this ensure 0 <= c < 256... which means
71  * you need a cast to (unsigned char) first, you can't just plug a
72  * char in here and get it to work, because if char is signed then it
73  * will first be sign extended.
74  */
75 #define TEST_CHAR(c, f)        (test_char_table[(unsigned)(c)] & (f))
76
77 /* Win32/NetWare/OS2 need to check for both forward and back slashes
78  * in ap_getparents() and ap_escape_url.
79  */
80 #ifdef CASE_BLIND_FILESYSTEM
81 #define IS_SLASH(s) ((s == '/') || (s == '\\'))
82 #else
83 #define IS_SLASH(s) (s == '/')
84 #endif
85
86 APLOG_USE_MODULE(core);
87
88
89 /*
90  * Examine a field value (such as a media-/content-type) string and return
91  * it sans any parameters; e.g., strip off any ';charset=foo' and the like.
92  */
93 AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype)
94 {
95     const char *semi;
96
97     if (intype == NULL) return NULL;
98
99     semi = ap_strchr_c(intype, ';');
100     if (semi == NULL) {
101         return apr_pstrdup(p, intype);
102     }
103     else {
104         while ((semi > intype) && apr_isspace(semi[-1])) {
105             semi--;
106         }
107         return apr_pstrndup(p, intype, semi - intype);
108     }
109 }
110
111 AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt,
112                               int gmt)
113 {
114     apr_size_t retcode;
115     char ts[MAX_STRING_LEN];
116     char tf[MAX_STRING_LEN];
117     apr_time_exp_t xt;
118
119     if (gmt) {
120         const char *f;
121         char *strp;
122
123         apr_time_exp_gmt(&xt, t);
124         /* Convert %Z to "GMT" and %z to "+0000";
125          * on hosts that do not have a time zone string in struct tm,
126          * strftime must assume its argument is local time.
127          */
128         for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f)
129             ; f++, strp++) {
130             if (*f != '%') continue;
131             switch (f[1]) {
132             case '%':
133                 *++strp = *++f;
134                 break;
135             case 'Z':
136                 *strp++ = 'G';
137                 *strp++ = 'M';
138                 *strp = 'T';
139                 f++;
140                 break;
141             case 'z': /* common extension */
142                 *strp++ = '+';
143                 *strp++ = '0';
144                 *strp++ = '0';
145                 *strp++ = '0';
146                 *strp = '0';
147                 f++;
148                 break;
149             }
150         }
151         *strp = '\0';
152         fmt = tf;
153     }
154     else {
155         apr_time_exp_lt(&xt, t);
156     }
157
158     /* check return code? */
159     apr_strftime(ts, &retcode, MAX_STRING_LEN, fmt, &xt);
160     ts[MAX_STRING_LEN - 1] = '\0';
161     return apr_pstrdup(p, ts);
162 }
163
164 /* Roy owes Rob beer. */
165 /* Rob owes Roy dinner. */
166
167 /* These legacy comments would make a lot more sense if Roy hadn't
168  * replaced the old later_than() routine with util_date.c.
169  *
170  * Well, okay, they still wouldn't make any sense.
171  */
172
173 /* Match = 0, NoMatch = 1, Abort = -1
174  * Based loosely on sections of wildmat.c by Rich Salz
175  * Hmmm... shouldn't this really go component by component?
176  */
177 AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected)
178 {
179     int x, y;
180
181     for (x = 0, y = 0; expected[y]; ++y, ++x) {
182         if ((!str[x]) && (expected[y] != '*'))
183             return -1;
184         if (expected[y] == '*') {
185             while (expected[++y] == '*');
186             if (!expected[y])
187                 return 0;
188             while (str[x]) {
189                 int ret;
190                 if ((ret = ap_strcmp_match(&str[x++], &expected[y])) != 1)
191                     return ret;
192             }
193             return -1;
194         }
195         else if ((expected[y] != '?') && (str[x] != expected[y]))
196             return 1;
197     }
198     return (str[x] != '\0');
199 }
200
201 AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
202 {
203     int x, y;
204
205     for (x = 0, y = 0; expected[y]; ++y, ++x) {
206         if (!str[x] && expected[y] != '*')
207             return -1;
208         if (expected[y] == '*') {
209             while (expected[++y] == '*');
210             if (!expected[y])
211                 return 0;
212             while (str[x]) {
213                 int ret;
214                 if ((ret = ap_strcasecmp_match(&str[x++], &expected[y])) != 1)
215                     return ret;
216             }
217             return -1;
218         }
219         else if (expected[y] != '?'
220                  && apr_tolower(str[x]) != apr_tolower(expected[y]))
221             return 1;
222     }
223     return (str[x] != '\0');
224 }
225
226 /* We actually compare the canonical root to this root, (but we don't
227  * waste time checking the case), since every use of this function in
228  * httpd-2.1 tests if the path is 'proper', meaning we've already passed
229  * it through apr_filepath_merge, or we haven't.
230  */
231 AP_DECLARE(int) ap_os_is_path_absolute(apr_pool_t *p, const char *dir)
232 {
233     const char *newpath;
234     const char *ourdir = dir;
235     if (apr_filepath_root(&newpath, &dir, 0, p) != APR_SUCCESS
236             || strncmp(newpath, ourdir, strlen(newpath)) != 0) {
237         return 0;
238     }
239     return 1;
240 }
241
242 AP_DECLARE(int) ap_is_matchexp(const char *str)
243 {
244     register int x;
245
246     for (x = 0; str[x]; x++)
247         if ((str[x] == '*') || (str[x] == '?'))
248             return 1;
249     return 0;
250 }
251
252 /*
253  * Here's a pool-based interface to the POSIX-esque ap_regcomp().
254  * Note that we return ap_regex_t instead of being passed one.
255  * The reason is that if you use an already-used ap_regex_t structure,
256  * the memory that you've already allocated gets forgotten, and
257  * regfree() doesn't clear it. So we don't allow it.
258  */
259
260 static apr_status_t regex_cleanup(void *preg)
261 {
262     ap_regfree((ap_regex_t *) preg);
263     return APR_SUCCESS;
264 }
265
266 AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
267                                      int cflags)
268 {
269     ap_regex_t *preg = apr_palloc(p, sizeof *preg);
270
271     if (ap_regcomp(preg, pattern, cflags)) {
272         return NULL;
273     }
274
275     apr_pool_cleanup_register(p, (void *) preg, regex_cleanup,
276                               apr_pool_cleanup_null);
277
278     return preg;
279 }
280
281 AP_DECLARE(void) ap_pregfree(apr_pool_t *p, ap_regex_t *reg)
282 {
283     ap_regfree(reg);
284     apr_pool_cleanup_kill(p, (void *) reg, regex_cleanup);
285 }
286
287 /*
288  * Similar to standard strstr() but we ignore case in this version.
289  * Based on the strstr() implementation further below.
290  */
291 AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2)
292 {
293     char *p1, *p2;
294     if (*s2 == '\0') {
295         /* an empty s2 */
296         return((char *)s1);
297     }
298     while(1) {
299         for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
300         if (*s1 == '\0') {
301             return(NULL);
302         }
303         /* found first character of s2, see if the rest matches */
304         p1 = (char *)s1;
305         p2 = (char *)s2;
306         for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) {
307             if (*p1 == '\0') {
308                 /* both strings ended together */
309                 return((char *)s1);
310             }
311         }
312         if (*p2 == '\0') {
313             /* second string ended, a match */
314             break;
315         }
316         /* didn't find a match here, try starting at next character in s1 */
317         s1++;
318     }
319     return((char *)s1);
320 }
321
322 /*
323  * Returns an offsetted pointer in bigstring immediately after
324  * prefix. Returns bigstring if bigstring doesn't start with
325  * prefix or if prefix is longer than bigstring while still matching.
326  * NOTE: pointer returned is relative to bigstring, so we
327  * can use standard pointer comparisons in the calling function
328  * (eg: test if ap_stripprefix(a,b) == a)
329  */
330 AP_DECLARE(const char *) ap_stripprefix(const char *bigstring,
331                                         const char *prefix)
332 {
333     const char *p1;
334
335     if (*prefix == '\0')
336         return bigstring;
337
338     p1 = bigstring;
339     while (*p1 && *prefix) {
340         if (*p1++ != *prefix++)
341             return bigstring;
342     }
343     if (*prefix == '\0')
344         return p1;
345
346     /* hit the end of bigstring! */
347     return bigstring;
348 }
349
350 /* This function substitutes for $0-$9, filling in regular expression
351  * submatches. Pass it the same nmatch and pmatch arguments that you
352  * passed ap_regexec(). pmatch should not be greater than the maximum number
353  * of subexpressions - i.e. one more than the re_nsub member of ap_regex_t.
354  *
355  * input should be the string with the $-expressions, source should be the
356  * string that was matched against.
357  *
358  * It returns the substituted string, or NULL on error.
359  *
360  * Parts of this code are based on Henry Spencer's regsub(), from his
361  * AT&T V8 regexp package.
362  */
363
364 AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
365                               const char *source, size_t nmatch,
366                               ap_regmatch_t pmatch[])
367 {
368     const char *src = input;
369     char *dest, *dst;
370     char c;
371     size_t no;
372     int len;
373
374     if (!source)
375         return NULL;
376     if (!nmatch)
377         return apr_pstrdup(p, src);
378
379     /* First pass, find the size */
380
381     len = 0;
382
383     while ((c = *src++) != '\0') {
384         if (c == '$' && apr_isdigit(*src))
385             no = *src++ - '0';
386         else
387             no = 10;
388
389         if (no > 9) {                /* Ordinary character. */
390             if (c == '\\' && *src)
391                 src++;
392             len++;
393         }
394         else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
395             len += pmatch[no].rm_eo - pmatch[no].rm_so;
396         }
397
398     }
399
400     dest = dst = apr_pcalloc(p, len + 1);
401
402     /* Now actually fill in the string */
403
404     src = input;
405
406     while ((c = *src++) != '\0') {
407         if (c == '&')
408             no = 0;
409         else if (c == '$' && apr_isdigit(*src))
410             no = *src++ - '0';
411         else
412             no = 10;
413
414         if (no > 9) {                /* Ordinary character. */
415             if (c == '\\' && (*src == '$' || *src == '&'))
416                 c = *src++;
417             *dst++ = c;
418         }
419         else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
420             len = pmatch[no].rm_eo - pmatch[no].rm_so;
421             memcpy(dst, source + pmatch[no].rm_so, len);
422             dst += len;
423         }
424
425     }
426     *dst = '\0';
427
428     return dest;
429 }
430
431 /*
432  * Parse .. so we don't compromise security
433  */
434 AP_DECLARE(void) ap_getparents(char *name)
435 {
436     char *next;
437     int l, w, first_dot;
438
439     /* Four paseses, as per RFC 1808 */
440     /* a) remove ./ path segments */
441     for (next = name; *next && (*next != '.'); next++) {
442     }
443
444     l = w = first_dot = next - name;
445     while (name[l] != '\0') {
446         if (name[l] == '.' && IS_SLASH(name[l + 1])
447             && (l == 0 || IS_SLASH(name[l - 1])))
448             l += 2;
449         else
450             name[w++] = name[l++];
451     }
452
453     /* b) remove trailing . path, segment */
454     if (w == 1 && name[0] == '.')
455         w--;
456     else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2]))
457         w--;
458     name[w] = '\0';
459
460     /* c) remove all xx/../ segments. (including leading ../ and /../) */
461     l = first_dot;
462
463     while (name[l] != '\0') {
464         if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2])
465             && (l == 0 || IS_SLASH(name[l - 1]))) {
466             register int m = l + 3, n;
467
468             l = l - 2;
469             if (l >= 0) {
470                 while (l >= 0 && !IS_SLASH(name[l]))
471                     l--;
472                 l++;
473             }
474             else
475                 l = 0;
476             n = l;
477             while ((name[n] = name[m]))
478                 (++n, ++m);
479         }
480         else
481             ++l;
482     }
483
484     /* d) remove trailing xx/.. segment. */
485     if (l == 2 && name[0] == '.' && name[1] == '.')
486         name[0] = '\0';
487     else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
488              && IS_SLASH(name[l - 3])) {
489         l = l - 4;
490         if (l >= 0) {
491             while (l >= 0 && !IS_SLASH(name[l]))
492                 l--;
493             l++;
494         }
495         else
496             l = 0;
497         name[l] = '\0';
498     }
499 }
500
501 AP_DECLARE(void) ap_no2slash(char *name)
502 {
503     char *d, *s;
504
505     s = d = name;
506
507 #ifdef HAVE_UNC_PATHS
508     /* Check for UNC names.  Leave leading two slashes. */
509     if (s[0] == '/' && s[1] == '/')
510         *d++ = *s++;
511 #endif
512
513     while (*s) {
514         if ((*d++ = *s) == '/') {
515             do {
516                 ++s;
517             } while (*s == '/');
518         }
519         else {
520             ++s;
521         }
522     }
523     *d = '\0';
524 }
525
526
527 /*
528  * copy at most n leading directories of s into d
529  * d should be at least as large as s plus 1 extra byte
530  * assumes n > 0
531  * the return value is the ever useful pointer to the trailing \0 of d
532  *
533  * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments,
534  * so that if n == 0, "/" is returned in d with n == 1
535  * and s == "e:/test.html", "e:/" is returned in d
536  * *** See also directory_walk in modules/http/http_request.c
537
538  * examples:
539  *    /a/b, 0  ==> /  (true for all platforms)
540  *    /a/b, 1  ==> /
541  *    /a/b, 2  ==> /a/
542  *    /a/b, 3  ==> /a/b/
543  *    /a/b, 4  ==> /a/b/
544  *
545  *    c:/a/b 0 ==> /
546  *    c:/a/b 1 ==> c:/
547  *    c:/a/b 2 ==> c:/a/
548  *    c:/a/b 3 ==> c:/a/b
549  *    c:/a/b 4 ==> c:/a/b
550  */
551 AP_DECLARE(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
552 {
553     if (n < 1) {
554         *d = '/';
555         *++d = '\0';
556         return (d);
557     }
558
559     for (;;) {
560         if (*s == '\0' || (*s == '/' && (--n) == 0)) {
561             *d = '/';
562             break;
563         }
564         *d++ = *s++;
565     }
566     *++d = 0;
567     return (d);
568 }
569
570
571 /*
572  * return the parent directory name including trailing / of the file s
573  */
574 AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s)
575 {
576     const char *last_slash = ap_strrchr_c(s, '/');
577     char *d;
578     int l;
579
580     if (last_slash == NULL) {
581         return apr_pstrdup(p, "");
582     }
583     l = (last_slash - s) + 1;
584     d = apr_pstrmemdup(p, s, l);
585
586     return (d);
587 }
588
589
590 AP_DECLARE(int) ap_count_dirs(const char *path)
591 {
592     register int x, n;
593
594     for (x = 0, n = 0; path[x]; x++)
595         if (path[x] == '/')
596             n++;
597     return n;
598 }
599
600 AP_DECLARE(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop)
601 {
602     return ap_getword(atrans, (const char **) line, stop);
603 }
604
605 AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop)
606 {
607     const char *pos = *line;
608     int len;
609     char *res;
610
611     while ((*pos != stop) && *pos) {
612         ++pos;
613     }
614
615     len = pos - *line;
616     res = apr_pstrmemdup(atrans, *line, len);
617
618     if (stop) {
619         while (*pos == stop) {
620             ++pos;
621         }
622     }
623     *line = pos;
624
625     return res;
626 }
627
628 AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
629 {
630     return ap_getword_white(atrans, (const char **) line);
631 }
632
633 AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
634 {
635     const char *pos = *line;
636     int len;
637     char *res;
638
639     while (!apr_isspace(*pos) && *pos) {
640         ++pos;
641     }
642
643     len = pos - *line;
644     res = apr_pstrmemdup(atrans, *line, len);
645
646     while (apr_isspace(*pos)) {
647         ++pos;
648     }
649
650     *line = pos;
651
652     return res;
653 }
654
655 AP_DECLARE(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line,
656                                        char stop)
657 {
658     return ap_getword_nulls(atrans, (const char **) line, stop);
659 }
660
661 AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line,
662                                     char stop)
663 {
664     const char *pos = ap_strchr_c(*line, stop);
665     char *res;
666
667     if (!pos) {
668         res = apr_pstrdup(atrans, *line);
669         *line += strlen(*line);
670         return res;
671     }
672
673     res = apr_pstrndup(atrans, *line, pos - *line);
674
675     ++pos;
676
677     *line = pos;
678
679     return res;
680 }
681
682 /* Get a word, (new) config-file style --- quoted strings and backslashes
683  * all honored
684  */
685
686 static char *substring_conf(apr_pool_t *p, const char *start, int len,
687                             char quote)
688 {
689     char *result = apr_palloc(p, len + 2);
690     char *resp = result;
691     int i;
692
693     for (i = 0; i < len; ++i) {
694         if (start[i] == '\\' && (start[i + 1] == '\\'
695                                  || (quote && start[i + 1] == quote)))
696             *resp++ = start[++i];
697         else
698             *resp++ = start[i];
699     }
700
701     *resp++ = '\0';
702 #if RESOLVE_ENV_PER_TOKEN
703     return (char *)ap_resolve_env(p,result);
704 #else
705     return result;
706 #endif
707 }
708
709 AP_DECLARE(char *) ap_getword_conf_nc(apr_pool_t *p, char **line)
710 {
711     return ap_getword_conf(p, (const char **) line);
712 }
713
714 AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line)
715 {
716     const char *str = *line, *strend;
717     char *res;
718     char quote;
719
720     while (*str && apr_isspace(*str))
721         ++str;
722
723     if (!*str) {
724         *line = str;
725         return "";
726     }
727
728     if ((quote = *str) == '"' || quote == '\'') {
729         strend = str + 1;
730         while (*strend && *strend != quote) {
731             if (*strend == '\\' && strend[1] &&
732                 (strend[1] == quote || strend[1] == '\\')) {
733                 strend += 2;
734             }
735             else {
736                 ++strend;
737             }
738         }
739         res = substring_conf(p, str + 1, strend - str - 1, quote);
740
741         if (*strend == quote)
742             ++strend;
743     }
744     else {
745         strend = str;
746         while (*strend && !apr_isspace(*strend))
747             ++strend;
748
749         res = substring_conf(p, str, strend - str, 0);
750     }
751
752     while (*strend && apr_isspace(*strend))
753         ++strend;
754     *line = strend;
755     return res;
756 }
757
758 /* Check a string for any ${ENV} environment variable
759  * construct and replace each them by the value of
760  * that environment variable, if it exists. If the
761  * environment value does not exist, leave the ${ENV}
762  * construct alone; it means something else.
763  */
764 AP_DECLARE(const char *) ap_resolve_env(apr_pool_t *p, const char * word)
765 {
766 # define SMALL_EXPANSION 5
767     struct sll {
768         struct sll *next;
769         const char *string;
770         apr_size_t len;
771     } *result, *current, sresult[SMALL_EXPANSION];
772     char *res_buf, *cp;
773     const char *s, *e, *ep;
774     unsigned spc;
775     apr_size_t outlen;
776
777     s = ap_strchr_c(word, '$');
778     if (!s) {
779         return word;
780     }
781
782     /* well, actually something to do */
783     ep = word + strlen(word);
784     spc = 0;
785     result = current = &(sresult[spc++]);
786     current->next = NULL;
787     current->string = word;
788     current->len = s - word;
789     outlen = current->len;
790
791     do {
792         /* prepare next entry */
793         if (current->len) {
794             current->next = (spc < SMALL_EXPANSION)
795                             ? &(sresult[spc++])
796                             : (struct sll *)apr_palloc(p,
797                                                        sizeof(*current->next));
798             current = current->next;
799             current->next = NULL;
800             current->len = 0;
801         }
802
803         if (*s == '$') {
804             if (s[1] == '{' && (e = ap_strchr_c(s, '}'))) {
805                 word = getenv(apr_pstrndup(p, s+2, e-s-2));
806                 if (word) {
807                     current->string = word;
808                     current->len = strlen(word);
809                     outlen += current->len;
810                 }
811                 else {
812                     current->string = s;
813                     current->len = e - s + 1;
814                     outlen += current->len;
815                 }
816                 s = e + 1;
817             }
818             else {
819                 current->string = s++;
820                 current->len = 1;
821                 ++outlen;
822             }
823         }
824         else {
825             word = s;
826             s = ap_strchr_c(s, '$');
827             current->string = word;
828             current->len = s ? s - word : ep - word;
829             outlen += current->len;
830         }
831     } while (s && *s);
832
833     /* assemble result */
834     res_buf = cp = apr_palloc(p, outlen + 1);
835     do {
836         if (result->len) {
837             memcpy(cp, result->string, result->len);
838             cp += result->len;
839         }
840         result = result->next;
841     } while (result);
842     res_buf[outlen] = '\0';
843
844     return res_buf;
845 }
846
847 AP_DECLARE(int) ap_cfg_closefile(ap_configfile_t *cfp)
848 {
849 #ifdef DEBUG
850     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
851         "Done with config file %s", cfp->name);
852 #endif
853     return (cfp->close == NULL) ? 0 : cfp->close(cfp->param);
854 }
855
856 static apr_status_t cfg_close(void *param)
857 {
858     apr_file_t *cfp = (apr_file_t *) param;
859     return (apr_file_close(cfp));
860 }
861
862 static int cfg_getch(void *param)
863 {
864     char ch;
865     apr_file_t *cfp = (apr_file_t *) param;
866     if (apr_file_getc(&ch, cfp) == APR_SUCCESS)
867         return ch;
868     return (int)EOF;
869 }
870
871 static void *cfg_getstr(void *buf, size_t bufsiz, void *param)
872 {
873     apr_file_t *cfp = (apr_file_t *) param;
874     apr_status_t rv;
875     rv = apr_file_gets(buf, bufsiz, cfp);
876     if (rv == APR_SUCCESS) {
877         return buf;
878     }
879     return NULL;
880 }
881
882 /* Open a ap_configfile_t as FILE, return open ap_configfile_t struct pointer */
883 AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg,
884                                           apr_pool_t *p, const char *name)
885 {
886     ap_configfile_t *new_cfg;
887     apr_file_t *file = NULL;
888     apr_finfo_t finfo;
889     apr_status_t status;
890 #ifdef DEBUG
891     char buf[120];
892 #endif
893
894     if (name == NULL) {
895         ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
896                "Internal error: pcfg_openfile() called with NULL filename");
897         return APR_EBADF;
898     }
899
900     status = apr_file_open(&file, name, APR_READ | APR_BUFFERED,
901                            APR_OS_DEFAULT, p);
902 #ifdef DEBUG
903     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
904                 "Opening config file %s (%s)",
905                 name, (status != APR_SUCCESS) ?
906                 apr_strerror(status, buf, sizeof(buf)) : "successful");
907 #endif
908     if (status != APR_SUCCESS)
909         return status;
910
911     status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file);
912     if (status != APR_SUCCESS)
913         return status;
914
915     if (finfo.filetype != APR_REG &&
916 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
917         strcasecmp(apr_filepath_name_get(name), "nul") != 0) {
918 #else
919         strcmp(name, "/dev/null") != 0) {
920 #endif /* WIN32 || OS2 */
921         ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
922                      "Access to file %s denied by server: not a regular file",
923                      name);
924         apr_file_close(file);
925         return APR_EBADF;
926     }
927
928 #ifdef WIN32
929     /* Some twisted character [no pun intended] at MS decided that a
930      * zero width joiner as the lead wide character would be ideal for
931      * describing Unicode text files.  This was further convoluted to
932      * another MSism that the same character mapped into utf-8, EF BB BF
933      * would signify utf-8 text files.
934      *
935      * Since MS configuration files are all protecting utf-8 encoded
936      * Unicode path, file and resource names, we already have the correct
937      * WinNT encoding.  But at least eat the stupid three bytes up front.
938      */
939     {
940         unsigned char buf[4];
941         apr_size_t len = 3;
942         status = apr_file_read(file, buf, &len);
943         if ((status != APR_SUCCESS) || (len < 3)
944               || memcmp(buf, "\xEF\xBB\xBF", 3) != 0) {
945             apr_off_t zero = 0;
946             apr_file_seek(file, APR_SET, &zero);
947         }
948     }
949 #endif
950
951     new_cfg = apr_palloc(p, sizeof(*new_cfg));
952     new_cfg->param = file;
953     new_cfg->name = apr_pstrdup(p, name);
954     new_cfg->getch = (int (*)(void *)) cfg_getch;
955     new_cfg->getstr = (void *(*)(void *, size_t, void *)) cfg_getstr;
956     new_cfg->close = (int (*)(void *)) cfg_close;
957     new_cfg->line_number = 0;
958     *ret_cfg = new_cfg;
959     return APR_SUCCESS;
960 }
961
962
963 /* Allocate a ap_configfile_t handle with user defined functions and params */
964 AP_DECLARE(ap_configfile_t *) ap_pcfg_open_custom(apr_pool_t *p,
965                        const char *descr,
966                        void *param,
967                        int(*getch)(void *param),
968                        void *(*getstr) (void *buf, size_t bufsiz, void *param),
969                        int(*close_func)(void *param))
970 {
971     ap_configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg));
972 #ifdef DEBUG
973     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
974                  "Opening config handler %s", descr);
975 #endif
976     new_cfg->param = param;
977     new_cfg->name = descr;
978     new_cfg->getch = getch;
979     new_cfg->getstr = getstr;
980     new_cfg->close = close_func;
981     new_cfg->line_number = 0;
982     return new_cfg;
983 }
984
985 /* Read one character from a configfile_t */
986 AP_DECLARE(int) ap_cfg_getc(ap_configfile_t *cfp)
987 {
988     register int ch = cfp->getch(cfp->param);
989     if (ch == LF)
990         ++cfp->line_number;
991     return ch;
992 }
993
994 /* Read one line from open ap_configfile_t, strip LF, increase line number */
995 /* If custom handler does not define a getstr() function, read char by char */
996 AP_DECLARE(int) ap_cfg_getline(char *buf, size_t bufsize, ap_configfile_t *cfp)
997 {
998     /* If a "get string" function is defined, use it */
999     if (cfp->getstr != NULL) {
1000         char *src, *dst;
1001         char *cp;
1002         char *cbuf = buf;
1003         size_t cbufsize = bufsize;
1004
1005         while (1) {
1006             ++cfp->line_number;
1007             if (cfp->getstr(cbuf, cbufsize, cfp->param) == NULL)
1008                 return 1;
1009
1010             /*
1011              *  check for line continuation,
1012              *  i.e. match [^\\]\\[\r]\n only
1013              */
1014             cp = cbuf;
1015             while (cp < cbuf+cbufsize && *cp != '\0')
1016                 cp++;
1017             if (cp > cbuf && cp[-1] == LF) {
1018                 cp--;
1019                 if (cp > cbuf && cp[-1] == CR)
1020                     cp--;
1021                 if (cp > cbuf && cp[-1] == '\\') {
1022                     cp--;
1023                     if (!(cp > cbuf && cp[-1] == '\\')) {
1024                         /*
1025                          * line continuation requested -
1026                          * then remove backslash and continue
1027                          */
1028                         cbufsize -= (cp-cbuf);
1029                         cbuf = cp;
1030                         continue;
1031                     }
1032                     else {
1033                         /*
1034                          * no real continuation because escaped -
1035                          * then just remove escape character
1036                          */
1037                         for ( ; cp < cbuf+cbufsize && *cp != '\0'; cp++)
1038                             cp[0] = cp[1];
1039                     }
1040                 }
1041             }
1042             break;
1043         }
1044
1045         /*
1046          * Leading and trailing white space is eliminated completely
1047          */
1048         src = buf;
1049         while (apr_isspace(*src))
1050             ++src;
1051         /* blast trailing whitespace */
1052         dst = &src[strlen(src)];
1053         while (--dst >= src && apr_isspace(*dst))
1054             *dst = '\0';
1055         /* Zap leading whitespace by shifting */
1056         if (src != buf)
1057             for (dst = buf; (*dst++ = *src++) != '\0'; )
1058                 ;
1059
1060 #ifdef DEBUG_CFG_LINES
1061         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "Read config: %s", buf);
1062 #endif
1063         return 0;
1064     } else {
1065         /* No "get string" function defined; read character by character */
1066         register int c;
1067         register size_t i = 0;
1068
1069         buf[0] = '\0';
1070         /* skip leading whitespace */
1071         do {
1072             c = cfp->getch(cfp->param);
1073         } while (c == '\t' || c == ' ');
1074
1075         if (c == EOF)
1076             return 1;
1077
1078         if(bufsize < 2) {
1079             /* too small, assume caller is crazy */
1080             return 1;
1081         }
1082
1083         while (1) {
1084             if ((c == '\t') || (c == ' ')) {
1085                 buf[i++] = ' ';
1086                 while ((c == '\t') || (c == ' '))
1087                     c = cfp->getch(cfp->param);
1088             }
1089             if (c == CR) {
1090                 /* silently ignore CR (_assume_ that a LF follows) */
1091                 c = cfp->getch(cfp->param);
1092             }
1093             if (c == LF) {
1094                 /* increase line number and return on LF */
1095                 ++cfp->line_number;
1096             }
1097             if (c == EOF || c == 0x4 || c == LF || i >= (bufsize - 2)) {
1098                 /*
1099                  *  check for line continuation
1100                  */
1101                 if (i > 0 && buf[i-1] == '\\') {
1102                     i--;
1103                     if (!(i > 0 && buf[i-1] == '\\')) {
1104                         /* line is continued */
1105                         c = cfp->getch(cfp->param);
1106                         continue;
1107                     }
1108                     /* else nothing needs be done because
1109                      * then the backslash is escaped and
1110                      * we just strip to a single one
1111                      */
1112                 }
1113                 /* blast trailing whitespace */
1114                 while (i > 0 && apr_isspace(buf[i - 1]))
1115                     --i;
1116                 buf[i] = '\0';
1117 #ifdef DEBUG_CFG_LINES
1118                 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
1119                              "Read config: %s", buf);
1120 #endif
1121                 return 0;
1122             }
1123             buf[i] = c;
1124             ++i;
1125             c = cfp->getch(cfp->param);
1126         }
1127     }
1128 }
1129
1130 /* Size an HTTP header field list item, as separated by a comma.
1131  * The return value is a pointer to the beginning of the non-empty list item
1132  * within the original string (or NULL if there is none) and the address
1133  * of field is shifted to the next non-comma, non-whitespace character.
1134  * len is the length of the item excluding any beginning whitespace.
1135  */
1136 AP_DECLARE(const char *) ap_size_list_item(const char **field, int *len)
1137 {
1138     const unsigned char *ptr = (const unsigned char *)*field;
1139     const unsigned char *token;
1140     int in_qpair, in_qstr, in_com;
1141
1142     /* Find first non-comma, non-whitespace byte */
1143
1144     while (*ptr == ',' || apr_isspace(*ptr))
1145         ++ptr;
1146
1147     token = ptr;
1148
1149     /* Find the end of this item, skipping over dead bits */
1150
1151     for (in_qpair = in_qstr = in_com = 0;
1152          *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1153          ++ptr) {
1154
1155         if (in_qpair) {
1156             in_qpair = 0;
1157         }
1158         else {
1159             switch (*ptr) {
1160                 case '\\': in_qpair = 1;      /* quoted-pair         */
1161                            break;
1162                 case '"' : if (!in_com)       /* quoted string delim */
1163                                in_qstr = !in_qstr;
1164                            break;
1165                 case '(' : if (!in_qstr)      /* comment (may nest)  */
1166                                ++in_com;
1167                            break;
1168                 case ')' : if (in_com)        /* end comment         */
1169                                --in_com;
1170                            break;
1171                 default  : break;
1172             }
1173         }
1174     }
1175
1176     if ((*len = (ptr - token)) == 0) {
1177         *field = (const char *)ptr;
1178         return NULL;
1179     }
1180
1181     /* Advance field pointer to the next non-comma, non-white byte */
1182
1183     while (*ptr == ',' || apr_isspace(*ptr))
1184         ++ptr;
1185
1186     *field = (const char *)ptr;
1187     return (const char *)token;
1188 }
1189
1190 /* Retrieve an HTTP header field list item, as separated by a comma,
1191  * while stripping insignificant whitespace and lowercasing anything not in
1192  * a quoted string or comment.  The return value is a new string containing
1193  * the converted list item (or NULL if none) and the address pointed to by
1194  * field is shifted to the next non-comma, non-whitespace.
1195  */
1196 AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field)
1197 {
1198     const char *tok_start;
1199     const unsigned char *ptr;
1200     unsigned char *pos;
1201     char *token;
1202     int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
1203
1204     /* Find the beginning and maximum length of the list item so that
1205      * we can allocate a buffer for the new string and reset the field.
1206      */
1207     if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
1208         return NULL;
1209     }
1210     token = apr_palloc(p, tok_len + 1);
1211
1212     /* Scan the token again, but this time copy only the good bytes.
1213      * We skip extra whitespace and any whitespace around a '=', '/',
1214      * or ';' and lowercase normal characters not within a comment,
1215      * quoted-string or quoted-pair.
1216      */
1217     for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
1218          *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1219          ++ptr) {
1220
1221         if (in_qpair) {
1222             in_qpair = 0;
1223             *pos++ = *ptr;
1224         }
1225         else {
1226             switch (*ptr) {
1227                 case '\\': in_qpair = 1;
1228                            if (addspace == 1)
1229                                *pos++ = ' ';
1230                            *pos++ = *ptr;
1231                            addspace = 0;
1232                            break;
1233                 case '"' : if (!in_com)
1234                                in_qstr = !in_qstr;
1235                            if (addspace == 1)
1236                                *pos++ = ' ';
1237                            *pos++ = *ptr;
1238                            addspace = 0;
1239                            break;
1240                 case '(' : if (!in_qstr)
1241                                ++in_com;
1242                            if (addspace == 1)
1243                                *pos++ = ' ';
1244                            *pos++ = *ptr;
1245                            addspace = 0;
1246                            break;
1247                 case ')' : if (in_com)
1248                                --in_com;
1249                            *pos++ = *ptr;
1250                            addspace = 0;
1251                            break;
1252                 case ' ' :
1253                 case '\t': if (addspace)
1254                                break;
1255                            if (in_com || in_qstr)
1256                                *pos++ = *ptr;
1257                            else
1258                                addspace = 1;
1259                            break;
1260                 case '=' :
1261                 case '/' :
1262                 case ';' : if (!(in_com || in_qstr))
1263                                addspace = -1;
1264                            *pos++ = *ptr;
1265                            break;
1266                 default  : if (addspace == 1)
1267                                *pos++ = ' ';
1268                            *pos++ = (in_com || in_qstr) ? *ptr
1269                                                         : apr_tolower(*ptr);
1270                            addspace = 0;
1271                            break;
1272             }
1273         }
1274     }
1275     *pos = '\0';
1276
1277     return token;
1278 }
1279
1280 /* Find an item in canonical form (lowercase, no extra spaces) within
1281  * an HTTP field value list.  Returns 1 if found, 0 if not found.
1282  * This would be much more efficient if we stored header fields as
1283  * an array of list items as they are received instead of a plain string.
1284  */
1285 AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line,
1286                                   const char *tok)
1287 {
1288     const unsigned char *pos;
1289     const unsigned char *ptr = (const unsigned char *)line;
1290     int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
1291
1292     if (!line || !tok)
1293         return 0;
1294
1295     do {  /* loop for each item in line's list */
1296
1297         /* Find first non-comma, non-whitespace byte */
1298
1299         while (*ptr == ',' || apr_isspace(*ptr))
1300             ++ptr;
1301
1302         if (*ptr)
1303             good = 1;  /* until proven otherwise for this item */
1304         else
1305             break;     /* no items left and nothing good found */
1306
1307         /* We skip extra whitespace and any whitespace around a '=', '/',
1308          * or ';' and lowercase normal characters not within a comment,
1309          * quoted-string or quoted-pair.
1310          */
1311         for (pos = (const unsigned char *)tok;
1312              *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1313              ++ptr) {
1314
1315             if (in_qpair) {
1316                 in_qpair = 0;
1317                 if (good)
1318                     good = (*pos++ == *ptr);
1319             }
1320             else {
1321                 switch (*ptr) {
1322                     case '\\': in_qpair = 1;
1323                                if (addspace == 1)
1324                                    good = good && (*pos++ == ' ');
1325                                good = good && (*pos++ == *ptr);
1326                                addspace = 0;
1327                                break;
1328                     case '"' : if (!in_com)
1329                                    in_qstr = !in_qstr;
1330                                if (addspace == 1)
1331                                    good = good && (*pos++ == ' ');
1332                                good = good && (*pos++ == *ptr);
1333                                addspace = 0;
1334                                break;
1335                     case '(' : if (!in_qstr)
1336                                    ++in_com;
1337                                if (addspace == 1)
1338                                    good = good && (*pos++ == ' ');
1339                                good = good && (*pos++ == *ptr);
1340                                addspace = 0;
1341                                break;
1342                     case ')' : if (in_com)
1343                                    --in_com;
1344                                good = good && (*pos++ == *ptr);
1345                                addspace = 0;
1346                                break;
1347                     case ' ' :
1348                     case '\t': if (addspace || !good)
1349                                    break;
1350                                if (in_com || in_qstr)
1351                                    good = (*pos++ == *ptr);
1352                                else
1353                                    addspace = 1;
1354                                break;
1355                     case '=' :
1356                     case '/' :
1357                     case ';' : if (!(in_com || in_qstr))
1358                                    addspace = -1;
1359                                good = good && (*pos++ == *ptr);
1360                                break;
1361                     default  : if (!good)
1362                                    break;
1363                                if (addspace == 1)
1364                                    good = (*pos++ == ' ');
1365                                if (in_com || in_qstr)
1366                                    good = good && (*pos++ == *ptr);
1367                                else
1368                                    good = good && (*pos++ == apr_tolower(*ptr));
1369                                addspace = 0;
1370                                break;
1371                 }
1372             }
1373         }
1374         if (good && *pos)
1375             good = 0;          /* not good if only a prefix was matched */
1376
1377     } while (*ptr && !good);
1378
1379     return good;
1380 }
1381
1382
1383 /* Retrieve a token, spacing over it and returning a pointer to
1384  * the first non-white byte afterwards.  Note that these tokens
1385  * are delimited by semis and commas; and can also be delimited
1386  * by whitespace at the caller's option.
1387  */
1388
1389 AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line,
1390                                 int accept_white)
1391 {
1392     const char *ptr = *accept_line;
1393     const char *tok_start;
1394     char *token;
1395     int tok_len;
1396
1397     /* Find first non-white byte */
1398
1399     while (*ptr && apr_isspace(*ptr))
1400         ++ptr;
1401
1402     tok_start = ptr;
1403
1404     /* find token end, skipping over quoted strings.
1405      * (comments are already gone).
1406      */
1407
1408     while (*ptr && (accept_white || !apr_isspace(*ptr))
1409            && *ptr != ';' && *ptr != ',') {
1410         if (*ptr++ == '"')
1411             while (*ptr)
1412                 if (*ptr++ == '"')
1413                     break;
1414     }
1415
1416     tok_len = ptr - tok_start;
1417     token = apr_pstrndup(p, tok_start, tok_len);
1418
1419     /* Advance accept_line pointer to the next non-white byte */
1420
1421     while (*ptr && apr_isspace(*ptr))
1422         ++ptr;
1423
1424     *accept_line = ptr;
1425     return token;
1426 }
1427
1428
1429 /* find http tokens, see the definition of token from RFC2068 */
1430 AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
1431 {
1432     const unsigned char *start_token;
1433     const unsigned char *s;
1434
1435     if (!line)
1436         return 0;
1437
1438     s = (const unsigned char *)line;
1439     for (;;) {
1440         /* find start of token, skip all stop characters, note NUL
1441          * isn't a token stop, so we don't need to test for it
1442          */
1443         while (TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1444             ++s;
1445         }
1446         if (!*s) {
1447             return 0;
1448         }
1449         start_token = s;
1450         /* find end of the token */
1451         while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1452             ++s;
1453         }
1454         if (!strncasecmp((const char *)start_token, (const char *)tok,
1455                          s - start_token)) {
1456             return 1;
1457         }
1458         if (!*s) {
1459             return 0;
1460         }
1461     }
1462 }
1463
1464
1465 AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line,
1466                                    const char *tok)
1467 {
1468     int llen, tlen, lidx;
1469
1470     if (!line)
1471         return 0;
1472
1473     llen = strlen(line);
1474     tlen = strlen(tok);
1475     lidx = llen - tlen;
1476
1477     if (lidx < 0 ||
1478         (lidx > 0 && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1479         return 0;
1480
1481     return (strncasecmp(&line[lidx], tok, tlen) == 0);
1482 }
1483
1484 AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1485 {
1486     char *cmd;
1487     unsigned char *d;
1488     const unsigned char *s;
1489
1490     cmd = apr_palloc(p, 2 * strlen(str) + 1);        /* Be safe */
1491     d = (unsigned char *)cmd;
1492     s = (const unsigned char *)str;
1493     for (; *s; ++s) {
1494
1495 #if defined(OS2) || defined(WIN32)
1496         /*
1497          * Newlines to Win32/OS2 CreateProcess() are ill advised.
1498          * Convert them to spaces since they are effectively white
1499          * space to most applications
1500          */
1501         if (*s == '\r' || *s == '\n') {
1502              *d++ = ' ';
1503              continue;
1504          }
1505 #endif
1506
1507         if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1508             *d++ = '\\';
1509         }
1510         *d++ = *s;
1511     }
1512     *d = '\0';
1513
1514     return cmd;
1515 }
1516
1517 static char x2c(const char *what)
1518 {
1519     register char digit;
1520
1521 #if !APR_CHARSET_EBCDIC
1522     digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
1523              : (what[0] - '0'));
1524     digit *= 16;
1525     digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
1526               : (what[1] - '0'));
1527 #else /*APR_CHARSET_EBCDIC*/
1528     char xstr[5];
1529     xstr[0]='0';
1530     xstr[1]='x';
1531     xstr[2]=what[0];
1532     xstr[3]=what[1];
1533     xstr[4]='\0';
1534     digit = apr_xlate_conv_byte(ap_hdrs_from_ascii,
1535                                 0xFF & strtol(xstr, NULL, 16));
1536 #endif /*APR_CHARSET_EBCDIC*/
1537     return (digit);
1538 }
1539
1540 /*
1541  * Unescapes a URL, leaving reserved characters intact.
1542  * Returns 0 on success, non-zero on error
1543  * Failure is due to
1544  *   bad % escape       returns HTTP_BAD_REQUEST
1545  *
1546  *   decoding %00 or a forbidden character returns HTTP_NOT_FOUND
1547  */
1548
1549 static int unescape_url(char *url, const char *forbid, const char *reserved)
1550 {
1551     register int badesc, badpath;
1552     char *x, *y;
1553
1554     badesc = 0;
1555     badpath = 0;
1556     /* Initial scan for first '%'. Don't bother writing values before
1557      * seeing a '%' */
1558     y = strchr(url, '%');
1559     if (y == NULL) {
1560         return OK;
1561     }
1562     for (x = y; *y; ++x, ++y) {
1563         if (*y != '%') {
1564             *x = *y;
1565         }
1566         else {
1567             if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1568                 badesc = 1;
1569                 *x = '%';
1570             }
1571             else {
1572                 char decoded;
1573                 decoded = x2c(y + 1);
1574                 if ((decoded == '\0')
1575                     || (forbid && ap_strchr_c(forbid, decoded))) {
1576                     badpath = 1;
1577                     *x = decoded;
1578                     y += 2;
1579                 }
1580                 else if (reserved && ap_strchr_c(reserved, decoded)) {
1581                     *x++ = *y++;
1582                     *x++ = *y++;
1583                     *x = *y;
1584                 }
1585                 else {
1586                     *x = decoded;
1587                     y += 2;
1588                 }
1589             }
1590         }
1591     }
1592     *x = '\0';
1593     if (badesc) {
1594         return HTTP_BAD_REQUEST;
1595     }
1596     else if (badpath) {
1597         return HTTP_NOT_FOUND;
1598     }
1599     else {
1600         return OK;
1601     }
1602 }
1603 AP_DECLARE(int) ap_unescape_url(char *url)
1604 {
1605     /* Traditional */
1606 #ifdef CASE_BLIND_FILESYSTEM
1607     return unescape_url(url, "/\\", NULL);
1608 #else
1609     return unescape_url(url, "/", NULL);
1610 #endif
1611 }
1612 AP_DECLARE(int) ap_unescape_url_keep2f(char *url)
1613 {
1614     /* AllowEncodedSlashes (corrected) */
1615     return unescape_url(url, NULL, "/");
1616 }
1617 #ifdef NEW_APIS
1618 /* IFDEF these out until they've been thought through.
1619  * Just a germ of an API extension for now
1620  */
1621 AP_DECLARE(int) ap_unescape_url_proxy(char *url)
1622 {
1623     /* leave RFC1738 reserved characters intact, * so proxied URLs
1624      * don't get mangled.  Where does that leave encoded '&' ?
1625      */
1626     return unescape_url(url, NULL, "/;?");
1627 }
1628 AP_DECLARE(int) ap_unescape_url_reserved(char *url, const char *reserved)
1629 {
1630     return unescape_url(url, NULL, reserved);
1631 }
1632 #endif
1633
1634 AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname,
1635                                        apr_port_t port, const request_rec *r)
1636 {
1637     if (ap_is_default_port(port, r)) {
1638         return apr_pstrdup(p, hostname);
1639     }
1640     else {
1641         return apr_psprintf(p, "%s:%u", hostname, port);
1642     }
1643 }
1644
1645 AP_DECLARE(int) ap_unescape_all(char *url)
1646 {
1647     return unescape_url(url, NULL, NULL);
1648 }
1649
1650 /* c2x takes an unsigned, and expects the caller has guaranteed that
1651  * 0 <= what < 256... which usually means that you have to cast to
1652  * unsigned char first, because (unsigned)(char)(x) first goes through
1653  * signed extension to an int before the unsigned cast.
1654  *
1655  * The reason for this assumption is to assist gcc code generation --
1656  * the unsigned char -> unsigned extension is already done earlier in
1657  * both uses of this code, so there's no need to waste time doing it
1658  * again.
1659  */
1660 static const char c2x_table[] = "0123456789abcdef";
1661
1662 static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
1663                                      unsigned char *where)
1664 {
1665 #if APR_CHARSET_EBCDIC
1666     what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
1667 #endif /*APR_CHARSET_EBCDIC*/
1668     *where++ = prefix;
1669     *where++ = c2x_table[what >> 4];
1670     *where++ = c2x_table[what & 0xf];
1671     return where;
1672 }
1673
1674 /*
1675  * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
1676  * routine is (should be) OS independent.
1677  *
1678  * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
1679  * cases if a ':' occurs before the first '/' in the URL, the URL should be
1680  * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
1681  * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
1682  * efficiency reasons, we don't use escape_path_segment(), which is provided for
1683  * reference. Again, RFC 1808 is where this stuff is defined.
1684  *
1685  * If partial is set, os_escape_path() assumes that the path will be appended to
1686  * something with a '/' in it (and thus does not prefix "./").
1687  */
1688
1689 AP_DECLARE(char *) ap_escape_path_segment_buffer(char *copy, const char *segment)
1690 {
1691     const unsigned char *s = (const unsigned char *)segment;
1692     unsigned char *d = (unsigned char *)copy;
1693     unsigned c;
1694
1695     while ((c = *s)) {
1696         if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
1697             d = c2x(c, '%', d);
1698         }
1699         else {
1700             *d++ = c;
1701         }
1702         ++s;
1703     }
1704     *d = '\0';
1705     return copy;
1706 }
1707
1708 AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
1709 {
1710     return ap_escape_path_segment_buffer(apr_palloc(p, 3 * strlen(segment) + 1), segment);
1711 }
1712
1713 AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
1714 {
1715     char *copy = apr_palloc(p, 3 * strlen(path) + 3);
1716     const unsigned char *s = (const unsigned char *)path;
1717     unsigned char *d = (unsigned char *)copy;
1718     unsigned c;
1719
1720     if (!partial) {
1721         const char *colon = ap_strchr_c(path, ':');
1722         const char *slash = ap_strchr_c(path, '/');
1723
1724         if (colon && (!slash || colon < slash)) {
1725             *d++ = '.';
1726             *d++ = '/';
1727         }
1728     }
1729     while ((c = *s)) {
1730         if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
1731             d = c2x(c, '%', d);
1732         }
1733         else {
1734             *d++ = c;
1735         }
1736         ++s;
1737     }
1738     *d = '\0';
1739     return copy;
1740 }
1741
1742 /* ap_escape_uri is now a macro for os_escape_path */
1743
1744 AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
1745 {
1746     int i, j;
1747     char *x;
1748
1749     /* first, count the number of extra characters */
1750     for (i = 0, j = 0; s[i] != '\0'; i++)
1751         if (s[i] == '<' || s[i] == '>')
1752             j += 3;
1753         else if (s[i] == '&')
1754             j += 4;
1755         else if (s[i] == '"')
1756             j += 5;
1757         else if (toasc && !apr_isascii(s[i]))
1758             j += 5;
1759
1760     if (j == 0)
1761         return apr_pstrmemdup(p, s, i);
1762
1763     x = apr_palloc(p, i + j + 1);
1764     for (i = 0, j = 0; s[i] != '\0'; i++, j++)
1765         if (s[i] == '<') {
1766             memcpy(&x[j], "&lt;", 4);
1767             j += 3;
1768         }
1769         else if (s[i] == '>') {
1770             memcpy(&x[j], "&gt;", 4);
1771             j += 3;
1772         }
1773         else if (s[i] == '&') {
1774             memcpy(&x[j], "&amp;", 5);
1775             j += 4;
1776         }
1777         else if (s[i] == '"') {
1778             memcpy(&x[j], "&quot;", 6);
1779             j += 5;
1780         }
1781         else if (toasc && !apr_isascii(s[i])) {
1782             char *esc = apr_psprintf(p, "&#%3.3d;", (unsigned char)s[i]);
1783             memcpy(&x[j], esc, 6);
1784             j += 5;
1785         }
1786         else
1787             x[j] = s[i];
1788
1789     x[j] = '\0';
1790     return x;
1791 }
1792 AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str)
1793 {
1794     char *ret;
1795     unsigned char *d;
1796     const unsigned char *s;
1797
1798     if (!str) {
1799         return NULL;
1800     }
1801
1802     ret = apr_palloc(p, 4 * strlen(str) + 1); /* Be safe */
1803     d = (unsigned char *)ret;
1804     s = (const unsigned char *)str;
1805     for (; *s; ++s) {
1806
1807         if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
1808             *d++ = '\\';
1809             switch(*s) {
1810             case '\b':
1811                 *d++ = 'b';
1812                 break;
1813             case '\n':
1814                 *d++ = 'n';
1815                 break;
1816             case '\r':
1817                 *d++ = 'r';
1818                 break;
1819             case '\t':
1820                 *d++ = 't';
1821                 break;
1822             case '\v':
1823                 *d++ = 'v';
1824                 break;
1825             case '\\':
1826             case '"':
1827                 *d++ = *s;
1828                 break;
1829             default:
1830                 c2x(*s, 'x', d);
1831                 d += 3;
1832             }
1833         }
1834         else {
1835             *d++ = *s;
1836         }
1837     }
1838     *d = '\0';
1839
1840     return ret;
1841 }
1842
1843 AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
1844                                                apr_size_t buflen)
1845 {
1846     unsigned char *d, *ep;
1847     const unsigned char *s;
1848
1849     if (!source || !buflen) { /* be safe */
1850         return 0;
1851     }
1852
1853     d = (unsigned char *)dest;
1854     s = (const unsigned char *)source;
1855     ep = d + buflen - 1;
1856
1857     for (; d < ep && *s; ++s) {
1858
1859         if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
1860             *d++ = '\\';
1861             if (d >= ep) {
1862                 --d;
1863                 break;
1864             }
1865
1866             switch(*s) {
1867             case '\b':
1868                 *d++ = 'b';
1869                 break;
1870             case '\n':
1871                 *d++ = 'n';
1872                 break;
1873             case '\r':
1874                 *d++ = 'r';
1875                 break;
1876             case '\t':
1877                 *d++ = 't';
1878                 break;
1879             case '\v':
1880                 *d++ = 'v';
1881                 break;
1882             case '\\':
1883                 *d++ = *s;
1884                 break;
1885             case '"': /* no need for this in error log */
1886                 d[-1] = *s;
1887                 break;
1888             default:
1889                 if (d >= ep - 2) {
1890                     ep = --d; /* break the for loop as well */
1891                     break;
1892                 }
1893                 c2x(*s, 'x', d);
1894                 d += 3;
1895             }
1896         }
1897         else {
1898             *d++ = *s;
1899         }
1900     }
1901     *d = '\0';
1902
1903     return (d - (unsigned char *)dest);
1904 }
1905
1906 AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
1907 {
1908     apr_finfo_t finfo;
1909
1910     if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS)
1911         return 0;                /* in error condition, just return no */
1912
1913     return (finfo.filetype == APR_DIR);
1914 }
1915
1916 AP_DECLARE(int) ap_is_rdirectory(apr_pool_t *p, const char *path)
1917 {
1918     apr_finfo_t finfo;
1919
1920     if (apr_stat(&finfo, path, APR_FINFO_LINK | APR_FINFO_TYPE, p) != APR_SUCCESS)
1921         return 0;                /* in error condition, just return no */
1922
1923     return (finfo.filetype == APR_DIR);
1924 }
1925
1926 AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
1927                                   const char *src2)
1928 {
1929     apr_size_t len1, len2;
1930     char *path;
1931
1932     len1 = strlen(src1);
1933     len2 = strlen(src2);
1934      /* allocate +3 for '/' delimiter, trailing NULL and overallocate
1935       * one extra byte to allow the caller to add a trailing '/'
1936       */
1937     path = (char *)apr_palloc(a, len1 + len2 + 3);
1938     if (len1 == 0) {
1939         *path = '/';
1940         memcpy(path + 1, src2, len2 + 1);
1941     }
1942     else {
1943         char *next;
1944         memcpy(path, src1, len1);
1945         next = path + len1;
1946         if (next[-1] != '/') {
1947             *next++ = '/';
1948         }
1949         memcpy(next, src2, len2 + 1);
1950     }
1951     return path;
1952 }
1953
1954 /*
1955  * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
1956  */
1957 AP_DECLARE(int) ap_is_url(const char *u)
1958 {
1959     register int x;
1960
1961     for (x = 0; u[x] != ':'; x++) {
1962         if ((!u[x]) ||
1963             ((!apr_isalpha(u[x])) && (!apr_isdigit(u[x])) &&
1964              (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
1965             return 0;
1966         }
1967     }
1968
1969     return (x ? 1 : 0);                /* If the first character is ':', it's broken, too */
1970 }
1971
1972 AP_DECLARE(int) ap_ind(const char *s, char c)
1973 {
1974     const char *p = ap_strchr_c(s, c);
1975
1976     if (p == NULL)
1977         return -1;
1978     return p - s;
1979 }
1980
1981 AP_DECLARE(int) ap_rind(const char *s, char c)
1982 {
1983     const char *p = ap_strrchr_c(s, c);
1984
1985     if (p == NULL)
1986         return -1;
1987     return p - s;
1988 }
1989
1990 AP_DECLARE(void) ap_str_tolower(char *str)
1991 {
1992     while (*str) {
1993         *str = apr_tolower(*str);
1994         ++str;
1995     }
1996 }
1997
1998 /*
1999  * We must return a FQDN
2000  */
2001 char *ap_get_local_host(apr_pool_t *a)
2002 {
2003 #ifndef MAXHOSTNAMELEN
2004 #define MAXHOSTNAMELEN 256
2005 #endif
2006     char str[MAXHOSTNAMELEN + 1];
2007     char *server_hostname = NULL;
2008     apr_sockaddr_t *sockaddr;
2009     char *hostname;
2010
2011     if (apr_gethostname(str, sizeof(str) - 1, a) != APR_SUCCESS) {
2012         ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a,
2013                      "%s: apr_gethostname() failed to determine ServerName",
2014                      ap_server_argv0);
2015     } else {
2016         str[sizeof(str) - 1] = '\0';
2017         if (apr_sockaddr_info_get(&sockaddr, str, APR_UNSPEC, 0, 0, a) == APR_SUCCESS) {
2018             if ( (apr_getnameinfo(&hostname, sockaddr, 0) == APR_SUCCESS) &&
2019                 (ap_strchr_c(hostname, '.')) ) {
2020                 server_hostname = apr_pstrdup(a, hostname);
2021                 return server_hostname;
2022             } else if (ap_strchr_c(str, '.')) {
2023                 server_hostname = apr_pstrdup(a, str);
2024             } else {
2025                 apr_sockaddr_ip_get(&hostname, sockaddr);
2026                 server_hostname = apr_pstrdup(a, hostname);
2027             }
2028         } else {
2029             ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a,
2030                          "%s: apr_sockaddr_info_get() failed for %s",
2031                          ap_server_argv0, str);
2032         }
2033     }
2034
2035     if (!server_hostname)
2036         server_hostname = apr_pstrdup(a, "127.0.0.1");
2037
2038     ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, a,
2039                  "%s: Could not reliably determine the server's fully qualified "
2040                  "domain name, using %s for ServerName",
2041                  ap_server_argv0, server_hostname);
2042
2043     return server_hostname;
2044 }
2045
2046 /* simple 'pool' alloc()ing glue to apr_base64.c
2047  */
2048 AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
2049 {
2050     char *decoded;
2051     int l;
2052
2053     decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded));
2054     l = apr_base64_decode(decoded, bufcoded);
2055     decoded[l] = '\0'; /* make binary sequence into string */
2056
2057     return decoded;
2058 }
2059
2060 AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
2061 {
2062     char *encoded;
2063     int l = strlen(string);
2064
2065     encoded = (char *) apr_palloc(p, 1 + apr_base64_encode_len(l));
2066     l = apr_base64_encode(encoded, string, l);
2067     encoded[l] = '\0'; /* make binary sequence into string */
2068
2069     return encoded;
2070 }
2071
2072 /* we want to downcase the type/subtype for comparison purposes
2073  * but nothing else because ;parameter=foo values are case sensitive.
2074  * XXX: in truth we want to downcase parameter names... but really,
2075  * apache has never handled parameters and such correctly.  You
2076  * also need to compress spaces and such to be able to compare
2077  * properly. -djg
2078  */
2079 AP_DECLARE(void) ap_content_type_tolower(char *str)
2080 {
2081     char *semi;
2082
2083     semi = strchr(str, ';');
2084     if (semi) {
2085         *semi = '\0';
2086     }
2087
2088     ap_str_tolower(str);
2089
2090     if (semi) {
2091         *semi = ';';
2092     }
2093 }
2094
2095 /*
2096  * Given a string, replace any bare " with \" .
2097  */
2098 AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
2099 {
2100     int newlen = 0;
2101     const char *inchr = instring;
2102     char *outchr, *outstring;
2103
2104     /*
2105      * Look through the input string, jogging the length of the output
2106      * string up by an extra byte each time we find an unescaped ".
2107      */
2108     while (*inchr != '\0') {
2109         newlen++;
2110         if (*inchr == '"') {
2111             newlen++;
2112         }
2113         /*
2114          * If we find a slosh, and it's not the last byte in the string,
2115          * it's escaping something - advance past both bytes.
2116          */
2117         if ((*inchr == '\\') && (inchr[1] != '\0')) {
2118             inchr++;
2119             newlen++;
2120         }
2121         inchr++;
2122     }
2123     outstring = apr_palloc(p, newlen + 1);
2124     inchr = instring;
2125     outchr = outstring;
2126     /*
2127      * Now copy the input string to the output string, inserting a slosh
2128      * in front of every " that doesn't already have one.
2129      */
2130     while (*inchr != '\0') {
2131         if ((*inchr == '\\') && (inchr[1] != '\0')) {
2132             *outchr++ = *inchr++;
2133             *outchr++ = *inchr++;
2134         }
2135         if (*inchr == '"') {
2136             *outchr++ = '\\';
2137         }
2138         if (*inchr != '\0') {
2139             *outchr++ = *inchr++;
2140         }
2141     }
2142     *outchr = '\0';
2143     return outstring;
2144 }
2145
2146 /*
2147  * Given a string, append the PID deliminated by delim.
2148  * Usually used to create a pid-appended filepath name
2149  * (eg: /a/b/foo -> /a/b/foo.6726). A function, and not
2150  * a macro, to avoid unistd.h dependency
2151  */
2152 AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string,
2153                                     const char *delim)
2154 {
2155     return apr_psprintf(p, "%s%s%" APR_PID_T_FMT, string,
2156                         delim, getpid());
2157
2158 }
2159
2160 /**
2161  * Parse a given timeout parameter string into an apr_interval_time_t value.
2162  * The unit of the time interval is given as postfix string to the numeric
2163  * string. Currently the following units are understood:
2164  *
2165  * ms    : milliseconds
2166  * s     : seconds
2167  * mi[n] : minutes
2168  * h     : hours
2169  *
2170  * If no unit is contained in the given timeout parameter the default_time_unit
2171  * will be used instead.
2172  * @param timeout_parameter The string containing the timeout parameter.
2173  * @param timeout The timeout value to be returned.
2174  * @param default_time_unit The default time unit to use if none is specified
2175  * in timeout_parameter.
2176  * @return Status value indicating whether the parsing was successful or not.
2177  */
2178 AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
2179                                                const char *timeout_parameter,
2180                                                apr_interval_time_t *timeout,
2181                                                const char *default_time_unit)
2182 {
2183     char *endp;
2184     const char *time_str;
2185     apr_int64_t tout;
2186
2187     tout = apr_strtoi64(timeout_parameter, &endp, 10);
2188     if (errno) {
2189         return errno;
2190     }
2191     if (!endp || !*endp) {
2192         time_str = default_time_unit;
2193     }
2194     else {
2195         time_str = endp;
2196     }
2197
2198     switch (*time_str) {
2199         /* Time is in seconds */
2200     case 's':
2201         *timeout = (apr_interval_time_t) apr_time_from_sec(tout);
2202         break;
2203     case 'h':
2204         /* Time is in hours */
2205         *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 3600);
2206         break;
2207     case 'm':
2208         switch (*(++time_str)) {
2209         /* Time is in milliseconds */
2210         case 's':
2211             *timeout = (apr_interval_time_t) tout * 1000;
2212             break;
2213         /* Time is in minutes */
2214         case 'i':
2215             *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 60);
2216             break;
2217         default:
2218             return APR_EGENERAL;
2219         }
2220         break;
2221     default:
2222         return APR_EGENERAL;
2223     }
2224     return APR_SUCCESS;
2225 }
2226
2227 /**
2228  * Determine if a request has a request body or not.
2229  *
2230  * @param r the request_rec of the request
2231  * @return truth value
2232  */
2233 AP_DECLARE(int) ap_request_has_body(request_rec *r)
2234 {
2235     apr_off_t cl;
2236     char *estr;
2237     const char *cls;
2238     int has_body;
2239             
2240     has_body = (!r->header_only
2241                 && (r->kept_body
2242                     || apr_table_get(r->headers_in, "Transfer-Encoding")
2243                     || ( (cls = apr_table_get(r->headers_in, "Content-Length"))
2244                         && (apr_strtoff(&cl, cls, &estr, 10) == APR_SUCCESS)
2245                         && (!*estr)
2246                         && (cl > 0) )
2247                     )
2248                 );
2249     return has_body;
2250 }