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], "<", 4);
2170 j += 3;
2171 }
2172 else if (s[i] == '>') {
2173 memcpy(&x[j], ">", 4);
2174 j += 3;
2175 }
2176 else if (s[i] == '&') {
2177 memcpy(&x[j], "&", 5);
2178 j += 4;
2179 }
2180 else if (s[i] == '"') {
2181 memcpy(&x[j], """, 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