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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * util.c: string utility things
21 * 1995-96 Many changes by the Apache Software Foundation
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
31 #include "apr_strings.h"
34 #define APR_WANT_STDIO
35 #define APR_WANT_STRFUNC
41 #if APR_HAVE_PROCESS_H
42 #include <process.h> /* for getpid() on Win32 */
45 #include <netdb.h> /* for gethostbyname() */
48 #include "ap_config.h"
49 #include "apr_base64.h"
51 #include "http_main.h"
53 #include "http_protocol.h"
54 #include "http_config.h"
55 #include "http_core.h"
56 #include "util_ebcdic.h"
57 #include "util_varbuf.h"
65 #ifdef HAVE_SYS_LOADAVG_H
66 #include <sys/loadavg.h>
71 /* A bunch of functions in util.c scan strings looking for certain characters.
72 * To make that more efficient we encode a lookup table. The test_char_table
73 * is generated automatically by gen_test_char.c.
75 #include "test_char.h"
77 /* we assume the folks using this ensure 0 <= c < 256... which means
78 * you need a cast to (unsigned char) first, you can't just plug a
79 * char in here and get it to work, because if char is signed then it
80 * will first be sign extended.
82 #define TEST_CHAR(c, f) (test_char_table[(unsigned)(c)] & (f))
84 /* Win32/NetWare/OS2 need to check for both forward and back slashes
85 * in ap_getparents() and ap_escape_url.
87 #ifdef CASE_BLIND_FILESYSTEM
88 #define IS_SLASH(s) ((s == '/') || (s == '\\'))
91 #define IS_SLASH(s) (s == '/')
95 /* we know core's module_index is 0 */
96 #undef APLOG_MODULE_INDEX
97 #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
100 * Examine a field value (such as a media-/content-type) string and return
101 * it sans any parameters; e.g., strip off any ';charset=foo' and the like.
103 AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype)
107 if (intype == NULL) return NULL;
109 semi = ap_strchr_c(intype, ';');
111 return apr_pstrdup(p, intype);
114 while ((semi > intype) && apr_isspace(semi[-1])) {
117 return apr_pstrmemdup(p, intype, semi - intype);
121 AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt,
125 char ts[MAX_STRING_LEN];
126 char tf[MAX_STRING_LEN];
133 apr_time_exp_gmt(&xt, t);
134 /* Convert %Z to "GMT" and %z to "+0000";
135 * on hosts that do not have a time zone string in struct tm,
136 * strftime must assume its argument is local time.
138 for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f)
140 if (*f != '%') continue;
151 case 'z': /* common extension */
165 apr_time_exp_lt(&xt, t);
168 /* check return code? */
169 apr_strftime(ts, &retcode, MAX_STRING_LEN, fmt, &xt);
170 ts[MAX_STRING_LEN - 1] = '\0';
171 return apr_pstrdup(p, ts);
174 /* Roy owes Rob beer. */
175 /* Rob owes Roy dinner. */
177 /* These legacy comments would make a lot more sense if Roy hadn't
178 * replaced the old later_than() routine with util_date.c.
180 * Well, okay, they still wouldn't make any sense.
183 /* Match = 0, NoMatch = 1, Abort = -1
184 * Based loosely on sections of wildmat.c by Rich Salz
185 * Hmmm... shouldn't this really go component by component?
187 AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected)
191 for (x = 0, y = 0; expected[y]; ++y, ++x) {
192 if ((!str[x]) && (expected[y] != '*'))
194 if (expected[y] == '*') {
195 while (expected[++y] == '*');
200 if ((ret = ap_strcmp_match(&str[x++], &expected[y])) != 1)
205 else if ((expected[y] != '?') && (str[x] != expected[y]))
208 return (str[x] != '\0');
211 AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
215 for (x = 0, y = 0; expected[y]; ++y, ++x) {
216 if (!str[x] && expected[y] != '*')
218 if (expected[y] == '*') {
219 while (expected[++y] == '*');
224 if ((ret = ap_strcasecmp_match(&str[x++], &expected[y])) != 1)
229 else if (expected[y] != '?'
230 && apr_tolower(str[x]) != apr_tolower(expected[y]))
233 return (str[x] != '\0');
236 /* We actually compare the canonical root to this root, (but we don't
237 * waste time checking the case), since every use of this function in
238 * httpd-2.1 tests if the path is 'proper', meaning we've already passed
239 * it through apr_filepath_merge, or we haven't.
241 AP_DECLARE(int) ap_os_is_path_absolute(apr_pool_t *p, const char *dir)
244 const char *ourdir = dir;
245 if (apr_filepath_root(&newpath, &dir, 0, p) != APR_SUCCESS
246 || strncmp(newpath, ourdir, strlen(newpath)) != 0) {
252 AP_DECLARE(int) ap_is_matchexp(const char *str)
256 for (x = 0; str[x]; x++)
257 if ((str[x] == '*') || (str[x] == '?'))
263 * Here's a pool-based interface to the POSIX-esque ap_regcomp().
264 * Note that we return ap_regex_t instead of being passed one.
265 * The reason is that if you use an already-used ap_regex_t structure,
266 * the memory that you've already allocated gets forgotten, and
267 * regfree() doesn't clear it. So we don't allow it.
270 static apr_status_t regex_cleanup(void *preg)
272 ap_regfree((ap_regex_t *) preg);
276 AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
279 ap_regex_t *preg = apr_palloc(p, sizeof *preg);
280 int err = ap_regcomp(preg, pattern, cflags);
282 if (err == AP_REG_ESPACE)
287 apr_pool_cleanup_register(p, (void *) preg, regex_cleanup,
288 apr_pool_cleanup_null);
293 AP_DECLARE(void) ap_pregfree(apr_pool_t *p, ap_regex_t *reg)
296 apr_pool_cleanup_kill(p, (void *) reg, regex_cleanup);
300 * Similar to standard strstr() but we ignore case in this version.
301 * Based on the strstr() implementation further below.
303 AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2)
311 for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
315 /* found first character of s2, see if the rest matches */
318 for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) {
320 /* both strings ended together */
325 /* second string ended, a match */
328 /* didn't find a match here, try starting at next character in s1 */
335 * Returns an offsetted pointer in bigstring immediately after
336 * prefix. Returns bigstring if bigstring doesn't start with
337 * prefix or if prefix is longer than bigstring while still matching.
338 * NOTE: pointer returned is relative to bigstring, so we
339 * can use standard pointer comparisons in the calling function
340 * (eg: test if ap_stripprefix(a,b) == a)
342 AP_DECLARE(const char *) ap_stripprefix(const char *bigstring,
351 while (*p1 && *prefix) {
352 if (*p1++ != *prefix++)
358 /* hit the end of bigstring! */
362 /* This function substitutes for $0-$9, filling in regular expression
363 * submatches. Pass it the same nmatch and pmatch arguments that you
364 * passed ap_regexec(). pmatch should not be greater than the maximum number
365 * of subexpressions - i.e. one more than the re_nsub member of ap_regex_t.
367 * nmatch must be <=AP_MAX_REG_MATCH (10).
369 * input should be the string with the $-expressions, source should be the
370 * string that was matched against.
372 * It returns the substituted string, or NULL if a vbuf is used.
373 * On errors, returns the orig string.
375 * Parts of this code are based on Henry Spencer's regsub(), from his
376 * AT&T V8 regexp package.
379 static apr_status_t regsub_core(apr_pool_t *p, char **result,
380 struct ap_varbuf *vb, const char *input,
381 const char *source, apr_size_t nmatch,
382 ap_regmatch_t pmatch[], apr_size_t maxlen)
384 const char *src = input;
390 AP_DEBUG_ASSERT((result && p && !vb) || (vb && !p && !result));
391 if (!source || nmatch>AP_MAX_REG_MATCH)
395 if (maxlen > 0 && len >= maxlen)
398 *result = apr_pstrmemdup(p, src, len);
402 ap_varbuf_strmemcat(vb, src, len);
407 /* First pass, find the size */
408 while ((c = *src++) != '\0') {
409 if (c == '$' && apr_isdigit(*src))
412 no = AP_MAX_REG_MATCH;
414 if (no >= AP_MAX_REG_MATCH) { /* Ordinary character. */
415 if (c == '\\' && *src)
419 else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
420 if (APR_SIZE_MAX - len <= pmatch[no].rm_eo - pmatch[no].rm_so)
422 len += pmatch[no].rm_eo - pmatch[no].rm_so;
427 if (len >= maxlen && maxlen > 0)
431 *result = dst = apr_palloc(p, len + 1);
434 if (vb->strlen == AP_VARBUF_UNKNOWN)
435 vb->strlen = strlen(vb->buf);
436 ap_varbuf_grow(vb, vb->strlen + len);
437 dst = vb->buf + vb->strlen;
441 /* Now actually fill in the string */
445 while ((c = *src++) != '\0') {
446 if (c == '$' && apr_isdigit(*src))
449 no = AP_MAX_REG_MATCH;
451 if (no >= AP_MAX_REG_MATCH) { /* Ordinary character. */
452 if (c == '\\' && *src)
456 else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
457 len = pmatch[no].rm_eo - pmatch[no].rm_so;
458 memcpy(dst, source + pmatch[no].rm_so, len);
468 #ifndef AP_PREGSUB_MAXLEN
469 #define AP_PREGSUB_MAXLEN (HUGE_STRING_LEN * 8)
471 AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
472 const char *source, apr_size_t nmatch,
473 ap_regmatch_t pmatch[])
476 apr_status_t rc = regsub_core(p, &result, NULL, input, source, nmatch,
477 pmatch, AP_PREGSUB_MAXLEN);
478 if (rc != APR_SUCCESS)
483 AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result,
484 const char *input, const char *source,
485 apr_size_t nmatch, ap_regmatch_t pmatch[],
488 apr_status_t rc = regsub_core(p, result, NULL, input, source, nmatch,
490 if (rc != APR_SUCCESS)
496 * Parse .. so we don't compromise security
498 AP_DECLARE(void) ap_getparents(char *name)
503 /* Four paseses, as per RFC 1808 */
504 /* a) remove ./ path segments */
505 for (next = name; *next && (*next != '.'); next++) {
508 l = w = first_dot = next - name;
509 while (name[l] != '\0') {
510 if (name[l] == '.' && IS_SLASH(name[l + 1])
511 && (l == 0 || IS_SLASH(name[l - 1])))
514 name[w++] = name[l++];
517 /* b) remove trailing . path, segment */
518 if (w == 1 && name[0] == '.')
520 else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2]))
524 /* c) remove all xx/../ segments. (including leading ../ and /../) */
527 while (name[l] != '\0') {
528 if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2])
529 && (l == 0 || IS_SLASH(name[l - 1]))) {
534 while (l >= 0 && !IS_SLASH(name[l]))
541 while ((name[n] = name[m]))
548 /* d) remove trailing xx/.. segment. */
549 if (l == 2 && name[0] == '.' && name[1] == '.')
551 else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
552 && IS_SLASH(name[l - 3])) {
555 while (l >= 0 && !IS_SLASH(name[l]))
565 AP_DECLARE(void) ap_no2slash(char *name)
571 #ifdef HAVE_UNC_PATHS
572 /* Check for UNC names. Leave leading two slashes. */
573 if (s[0] == '/' && s[1] == '/')
578 if ((*d++ = *s) == '/') {
592 * copy at most n leading directories of s into d
593 * d should be at least as large as s plus 1 extra byte
595 * the return value is the ever useful pointer to the trailing \0 of d
597 * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments,
598 * so that if n == 0, "/" is returned in d with n == 1
599 * and s == "e:/test.html", "e:/" is returned in d
600 * *** See also directory_walk in modules/http/http_request.c
603 * /a/b, 0 ==> / (true for all platforms)
612 * c:/a/b 3 ==> c:/a/b
613 * c:/a/b 4 ==> c:/a/b
615 AP_DECLARE(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
624 if (*s == '\0' || (*s == '/' && (--n) == 0)) {
636 * return the parent directory name including trailing / of the file s
638 AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s)
640 const char *last_slash = ap_strrchr_c(s, '/');
644 if (last_slash == NULL) {
645 return apr_pstrdup(p, "");
647 l = (last_slash - s) + 1;
648 d = apr_pstrmemdup(p, s, l);
654 AP_DECLARE(int) ap_count_dirs(const char *path)
658 for (x = 0, n = 0; path[x]; x++)
664 AP_DECLARE(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop)
666 return ap_getword(atrans, (const char **) line, stop);
669 AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop)
671 const char *pos = *line;
675 while ((*pos != stop) && *pos) {
680 res = apr_pstrmemdup(atrans, *line, len);
683 while (*pos == stop) {
692 AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
694 return ap_getword_white(atrans, (const char **) line);
697 AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
699 const char *pos = *line;
703 while (!apr_isspace(*pos) && *pos) {
708 res = apr_pstrmemdup(atrans, *line, len);
710 while (apr_isspace(*pos)) {
719 AP_DECLARE(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line,
722 return ap_getword_nulls(atrans, (const char **) line, stop);
725 AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line,
728 const char *pos = ap_strchr_c(*line, stop);
732 apr_size_t len = strlen(*line);
733 res = apr_pstrmemdup(atrans, *line, len);
738 res = apr_pstrmemdup(atrans, *line, pos - *line);
747 /* Get a word, (new) config-file style --- quoted strings and backslashes
751 static char *substring_conf(apr_pool_t *p, const char *start, int len,
754 char *result = apr_palloc(p, len + 1);
758 for (i = 0; i < len; ++i) {
759 if (start[i] == '\\' && (start[i + 1] == '\\'
760 || (quote && start[i + 1] == quote)))
761 *resp++ = start[++i];
767 #if RESOLVE_ENV_PER_TOKEN
768 return (char *)ap_resolve_env(p,result);
774 AP_DECLARE(char *) ap_getword_conf_nc(apr_pool_t *p, char **line)
776 return ap_getword_conf(p, (const char **) line);
779 AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line)
781 const char *str = *line, *strend;
785 while (apr_isspace(*str))
793 if ((quote = *str) == '"' || quote == '\'') {
795 while (*strend && *strend != quote) {
796 if (*strend == '\\' && strend[1] &&
797 (strend[1] == quote || strend[1] == '\\')) {
804 res = substring_conf(p, str + 1, strend - str - 1, quote);
806 if (*strend == quote)
811 while (*strend && !apr_isspace(*strend))
814 res = substring_conf(p, str, strend - str, 0);
817 while (apr_isspace(*strend))
823 AP_DECLARE(char *) ap_getword_conf2_nc(apr_pool_t *p, char **line)
825 return ap_getword_conf2(p, (const char **) line);
828 AP_DECLARE(char *) ap_getword_conf2(apr_pool_t *p, const char **line)
830 const char *str = *line, *strend;
835 while (apr_isspace(*str))
843 if ((quote = *str) == '"' || quote == '\'')
844 return ap_getword_conf(p, line);
849 if (*strend == '}' && !--count)
853 if (*strend == '\\' && strend[1] && strend[1] == '\\') {
858 res = substring_conf(p, str + 1, strend - str - 1, 0);
865 while (*strend && !apr_isspace(*strend))
868 res = substring_conf(p, str, strend - str, 0);
871 while (apr_isspace(*strend))
877 AP_DECLARE(int) ap_cfg_closefile(ap_configfile_t *cfp)
880 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00551)
881 "Done with config file %s", cfp->name);
883 return (cfp->close == NULL) ? 0 : cfp->close(cfp->param);
886 /* we can't use apr_file_* directly because of linking issues on Windows */
887 static apr_status_t cfg_close(void *param)
889 return apr_file_close(param);
892 static apr_status_t cfg_getch(char *ch, void *param)
894 return apr_file_getc(ch, param);
897 static apr_status_t cfg_getstr(void *buf, apr_size_t bufsiz, void *param)
899 return apr_file_gets(buf, bufsiz, param);
902 /* Open a ap_configfile_t as FILE, return open ap_configfile_t struct pointer */
903 AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg,
904 apr_pool_t *p, const char *name)
906 ap_configfile_t *new_cfg;
907 apr_file_t *file = NULL;
915 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00552)
916 "Internal error: pcfg_openfile() called with NULL filename");
920 status = apr_file_open(&file, name, APR_READ | APR_BUFFERED,
923 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00553)
924 "Opening config file %s (%s)",
925 name, (status != APR_SUCCESS) ?
926 apr_strerror(status, buf, sizeof(buf)) : "successful");
928 if (status != APR_SUCCESS)
931 status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file);
932 if (status != APR_SUCCESS)
935 if (finfo.filetype != APR_REG &&
936 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
937 strcasecmp(apr_filepath_name_get(name), "nul") != 0) {
939 strcmp(name, "/dev/null") != 0) {
940 #endif /* WIN32 || OS2 */
941 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00554)
942 "Access to file %s denied by server: not a regular file",
944 apr_file_close(file);
949 /* Some twisted character [no pun intended] at MS decided that a
950 * zero width joiner as the lead wide character would be ideal for
951 * describing Unicode text files. This was further convoluted to
952 * another MSism that the same character mapped into utf-8, EF BB BF
953 * would signify utf-8 text files.
955 * Since MS configuration files are all protecting utf-8 encoded
956 * Unicode path, file and resource names, we already have the correct
957 * WinNT encoding. But at least eat the stupid three bytes up front.
960 unsigned char buf[4];
962 status = apr_file_read(file, buf, &len);
963 if ((status != APR_SUCCESS) || (len < 3)
964 || memcmp(buf, "\xEF\xBB\xBF", 3) != 0) {
966 apr_file_seek(file, APR_SET, &zero);
971 new_cfg = apr_palloc(p, sizeof(*new_cfg));
972 new_cfg->param = file;
973 new_cfg->name = apr_pstrdup(p, name);
974 new_cfg->getch = cfg_getch;
975 new_cfg->getstr = cfg_getstr;
976 new_cfg->close = cfg_close;
977 new_cfg->line_number = 0;
983 /* Allocate a ap_configfile_t handle with user defined functions and params */
984 AP_DECLARE(ap_configfile_t *) ap_pcfg_open_custom(
985 apr_pool_t *p, const char *descr, void *param,
986 apr_status_t (*getc_func) (char *ch, void *param),
987 apr_status_t (*gets_func) (void *buf, apr_size_t bufsize, void *param),
988 apr_status_t (*close_func) (void *param))
990 ap_configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg));
991 new_cfg->param = param;
992 new_cfg->name = descr;
993 new_cfg->getch = getc_func;
994 new_cfg->getstr = gets_func;
995 new_cfg->close = close_func;
996 new_cfg->line_number = 0;
1000 /* Read one character from a configfile_t */
1001 AP_DECLARE(apr_status_t) ap_cfg_getc(char *ch, ap_configfile_t *cfp)
1003 apr_status_t rc = cfp->getch(ch, cfp->param);
1004 if (rc == APR_SUCCESS && *ch == LF)
1009 AP_DECLARE(const char *) ap_pcfg_strerror(apr_pool_t *p, ap_configfile_t *cfp,
1012 if (rc == APR_SUCCESS)
1015 if (rc == APR_ENOSPC)
1016 return apr_psprintf(p, "Error reading %s at line %d: Line too long",
1017 cfp->name, cfp->line_number);
1019 return apr_psprintf(p, "Error reading %s at line %d: %pm",
1020 cfp->name, cfp->line_number, &rc);
1023 /* Read one line from open ap_configfile_t, strip LF, increase line number */
1024 /* If custom handler does not define a getstr() function, read char by char */
1025 static apr_status_t ap_cfg_getline_core(char *buf, apr_size_t bufsize,
1026 apr_size_t offset, ap_configfile_t *cfp)
1029 /* If a "get string" function is defined, use it */
1030 if (cfp->getstr != NULL) {
1032 char *cbuf = buf + offset;
1033 apr_size_t cbufsize = bufsize - offset;
1037 rc = cfp->getstr(cbuf, cbufsize, cfp->param);
1038 if (rc == APR_EOF) {
1039 if (cbuf != buf + offset) {
1047 if (rc != APR_SUCCESS) {
1052 * check for line continuation,
1053 * i.e. match [^\\]\\[\r]\n only
1057 if (cp > buf && cp[-1] == LF) {
1059 if (cp > buf && cp[-1] == CR)
1061 if (cp > buf && cp[-1] == '\\') {
1064 * line continuation requested -
1065 * then remove backslash and continue
1067 cbufsize -= (cp-cbuf);
1072 else if (cp - buf >= bufsize - 1) {
1078 /* No "get string" function defined; read character by character */
1079 apr_size_t i = offset;
1082 /* too small, assume caller is crazy */
1089 rc = cfp->getch(&c, cfp->param);
1090 if (rc == APR_EOF) {
1096 if (rc != APR_SUCCESS)
1100 /* check for line continuation */
1101 if (i > 0 && buf[i-1] == '\\') {
1111 if (i >= bufsize - 1) {
1120 static int cfg_trim_line(char *buf)
1124 * Leading and trailing white space is eliminated completely
1127 while (apr_isspace(*start))
1129 /* blast trailing whitespace */
1130 end = &start[strlen(start)];
1131 while (--end >= start && apr_isspace(*end))
1133 /* Zap leading whitespace by shifting */
1135 memmove(buf, start, end - start + 2);
1136 #ifdef DEBUG_CFG_LINES
1137 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, APLOGNO(00555) "Read config: '%s'", buf);
1139 return end - start + 1;
1142 /* Read one line from open ap_configfile_t, strip LF, increase line number */
1143 /* If custom handler does not define a getstr() function, read char by char */
1144 AP_DECLARE(apr_status_t) ap_cfg_getline(char *buf, apr_size_t bufsize,
1145 ap_configfile_t *cfp)
1147 apr_status_t rc = ap_cfg_getline_core(buf, bufsize, 0, cfp);
1148 if (rc == APR_SUCCESS)
1153 AP_DECLARE(apr_status_t) ap_varbuf_cfg_getline(struct ap_varbuf *vb,
1154 ap_configfile_t *cfp,
1162 if (vb->strlen == AP_VARBUF_UNKNOWN)
1163 vb->strlen = strlen(vb->buf);
1164 if (vb->avail - vb->strlen < 3) {
1165 new_len = vb->avail * 2;
1166 if (new_len > max_len)
1168 else if (new_len < 3)
1170 ap_varbuf_grow(vb, new_len);
1174 rc = ap_cfg_getline_core(vb->buf, vb->avail, vb->strlen, cfp);
1175 if (rc == APR_ENOSPC || rc == APR_SUCCESS)
1176 vb->strlen += strlen(vb->buf + vb->strlen);
1177 if (rc != APR_ENOSPC)
1179 if (vb->avail >= max_len)
1181 new_len = vb->avail * 2;
1182 if (new_len > max_len)
1184 ap_varbuf_grow(vb, new_len);
1187 if (vb->strlen > max_len)
1189 if (rc == APR_SUCCESS)
1190 vb->strlen = cfg_trim_line(vb->buf);
1194 /* Size an HTTP header field list item, as separated by a comma.
1195 * The return value is a pointer to the beginning of the non-empty list item
1196 * within the original string (or NULL if there is none) and the address
1197 * of field is shifted to the next non-comma, non-whitespace character.
1198 * len is the length of the item excluding any beginning whitespace.
1200 AP_DECLARE(const char *) ap_size_list_item(const char **field, int *len)
1202 const unsigned char *ptr = (const unsigned char *)*field;
1203 const unsigned char *token;
1204 int in_qpair, in_qstr, in_com;
1206 /* Find first non-comma, non-whitespace byte */
1208 while (*ptr == ',' || apr_isspace(*ptr))
1213 /* Find the end of this item, skipping over dead bits */
1215 for (in_qpair = in_qstr = in_com = 0;
1216 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1224 case '\\': in_qpair = 1; /* quoted-pair */
1226 case '"' : if (!in_com) /* quoted string delim */
1229 case '(' : if (!in_qstr) /* comment (may nest) */
1232 case ')' : if (in_com) /* end comment */
1240 if ((*len = (ptr - token)) == 0) {
1241 *field = (const char *)ptr;
1245 /* Advance field pointer to the next non-comma, non-white byte */
1247 while (*ptr == ',' || apr_isspace(*ptr))
1250 *field = (const char *)ptr;
1251 return (const char *)token;
1254 /* Retrieve an HTTP header field list item, as separated by a comma,
1255 * while stripping insignificant whitespace and lowercasing anything not in
1256 * a quoted string or comment. The return value is a new string containing
1257 * the converted list item (or NULL if none) and the address pointed to by
1258 * field is shifted to the next non-comma, non-whitespace.
1260 AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field)
1262 const char *tok_start;
1263 const unsigned char *ptr;
1266 int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
1268 /* Find the beginning and maximum length of the list item so that
1269 * we can allocate a buffer for the new string and reset the field.
1271 if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
1274 token = apr_palloc(p, tok_len + 1);
1276 /* Scan the token again, but this time copy only the good bytes.
1277 * We skip extra whitespace and any whitespace around a '=', '/',
1278 * or ';' and lowercase normal characters not within a comment,
1279 * quoted-string or quoted-pair.
1281 for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
1282 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1291 case '\\': in_qpair = 1;
1297 case '"' : if (!in_com)
1304 case '(' : if (!in_qstr)
1311 case ')' : if (in_com)
1317 case '\t': if (addspace)
1319 if (in_com || in_qstr)
1326 case ';' : if (!(in_com || in_qstr))
1330 default : if (addspace == 1)
1332 *pos++ = (in_com || in_qstr) ? *ptr
1333 : apr_tolower(*ptr);
1344 typedef enum ap_etag_e {
1350 /* Find an item in canonical form (lowercase, no extra spaces) within
1351 * an HTTP field value list. Returns 1 if found, 0 if not found.
1352 * This would be much more efficient if we stored header fields as
1353 * an array of list items as they are received instead of a plain string.
1355 static int find_list_item(apr_pool_t *p, const char *line,
1356 const char *tok, ap_etag_e type)
1358 const unsigned char *pos;
1359 const unsigned char *ptr = (const unsigned char *)line;
1360 int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
1362 if (!line || !tok) {
1365 if (type == AP_ETAG_STRONG && *tok != '\"') {
1368 if (type == AP_ETAG_WEAK) {
1369 if (*tok == 'W' && (*(tok+1)) == '/' && (*(tok+2)) == '\"') {
1372 else if (*tok != '\"') {
1377 do { /* loop for each item in line's list */
1379 /* Find first non-comma, non-whitespace byte */
1380 while (*ptr == ',' || apr_isspace(*ptr)) {
1384 /* Account for strong or weak Etags, depending on our search */
1385 if (type == AP_ETAG_STRONG && *ptr != '\"') {
1388 if (type == AP_ETAG_WEAK) {
1389 if (*ptr == 'W' && (*(ptr+1)) == '/' && (*(ptr+2)) == '\"') {
1392 else if (*ptr != '\"') {
1398 good = 1; /* until proven otherwise for this item */
1400 break; /* no items left and nothing good found */
1402 /* We skip extra whitespace and any whitespace around a '=', '/',
1403 * or ';' and lowercase normal characters not within a comment,
1404 * quoted-string or quoted-pair.
1406 for (pos = (const unsigned char *)tok;
1407 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1413 good = (*pos++ == *ptr);
1417 case '\\': in_qpair = 1;
1419 good = good && (*pos++ == ' ');
1420 good = good && (*pos++ == *ptr);
1423 case '"' : if (!in_com)
1426 good = good && (*pos++ == ' ');
1427 good = good && (*pos++ == *ptr);
1430 case '(' : if (!in_qstr)
1433 good = good && (*pos++ == ' ');
1434 good = good && (*pos++ == *ptr);
1437 case ')' : if (in_com)
1439 good = good && (*pos++ == *ptr);
1443 case '\t': if (addspace || !good)
1445 if (in_com || in_qstr)
1446 good = (*pos++ == *ptr);
1452 case ';' : if (!(in_com || in_qstr))
1454 good = good && (*pos++ == *ptr);
1456 default : if (!good)
1459 good = (*pos++ == ' ');
1460 if (in_com || in_qstr)
1461 good = good && (*pos++ == *ptr);
1464 && (apr_tolower(*pos++) == apr_tolower(*ptr));
1471 good = 0; /* not good if only a prefix was matched */
1473 } while (*ptr && !good);
1478 /* Find an item in canonical form (lowercase, no extra spaces) within
1479 * an HTTP field value list. Returns 1 if found, 0 if not found.
1480 * This would be much more efficient if we stored header fields as
1481 * an array of list items as they are received instead of a plain string.
1483 AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line,
1486 return find_list_item(p, line, tok, AP_ETAG_NONE);
1489 /* Find a strong Etag in canonical form (lowercase, no extra spaces) within
1490 * an HTTP field value list. Returns 1 if found, 0 if not found.
1492 AP_DECLARE(int) ap_find_etag_strong(apr_pool_t *p, const char *line,
1495 return find_list_item(p, line, tok, AP_ETAG_STRONG);
1498 /* Find a weak ETag in canonical form (lowercase, no extra spaces) within
1499 * an HTTP field value list. Returns 1 if found, 0 if not found.
1501 AP_DECLARE(int) ap_find_etag_weak(apr_pool_t *p, const char *line,
1504 return find_list_item(p, line, tok, AP_ETAG_WEAK);
1507 /* Grab a list of tokens of the format 1#token (from RFC7230) */
1508 AP_DECLARE(const char *) ap_parse_token_list_strict(apr_pool_t *p,
1510 apr_array_header_t **tokens,
1513 int in_leading_space = 1;
1514 int in_trailing_space = 0;
1516 const char *tok_begin;
1523 tok_begin = cur = str_in;
1525 while (!string_end) {
1526 const unsigned char c = (unsigned char)*cur;
1528 if (!TEST_CHAR(c, T_HTTP_TOKEN_STOP) && c != '\0') {
1529 /* Non-separator character; we are finished with leading
1530 * whitespace. We must never have encountered any trailing
1531 * whitespace before the delimiter (comma) */
1532 in_leading_space = 0;
1533 if (in_trailing_space) {
1534 return "Encountered illegal whitespace in token";
1537 else if (c == ' ' || c == '\t') {
1538 /* "Linear whitespace" only includes ASCII CRLF, space, and tab;
1539 * we can't get a CRLF since headers are split on them already,
1540 * so only look for a space or a tab */
1541 if (in_leading_space) {
1542 /* We're still in leading whitespace */
1546 /* We must be in trailing whitespace */
1547 ++in_trailing_space;
1550 else if (c == ',' || c == '\0') {
1551 if (!in_leading_space) {
1552 /* If we're out of the leading space, we know we've read some
1553 * characters of a token */
1554 if (*tokens == NULL) {
1555 *tokens = apr_array_make(p, 4, sizeof(char *));
1557 APR_ARRAY_PUSH(*tokens, char *) =
1558 apr_pstrmemdup((*tokens)->pool, tok_begin,
1559 (cur - tok_begin) - in_trailing_space);
1561 /* We're allowed to have null elements, just don't add them to the
1564 tok_begin = cur + 1;
1565 in_leading_space = 1;
1566 in_trailing_space = 0;
1567 string_end = (c == '\0');
1570 /* Encountered illegal separator char */
1572 /* Skip to the next separator */
1574 temp = ap_strchr_c(cur, ',');
1576 temp = ap_strchr_c(cur, '\0');
1579 /* Act like we haven't seen a token so we reset */
1581 in_leading_space = 1;
1582 in_trailing_space = 0;
1585 return apr_psprintf(p, "Encountered illegal separator "
1586 "'\\x%.2x'", (unsigned int)c);
1596 /* Retrieve a token, spacing over it and returning a pointer to
1597 * the first non-white byte afterwards. Note that these tokens
1598 * are delimited by semis and commas; and can also be delimited
1599 * by whitespace at the caller's option.
1602 AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line,
1605 const char *ptr = *accept_line;
1606 const char *tok_start;
1609 /* Find first non-white byte */
1611 while (apr_isspace(*ptr))
1616 /* find token end, skipping over quoted strings.
1617 * (comments are already gone).
1620 while (*ptr && (accept_white || !apr_isspace(*ptr))
1621 && *ptr != ';' && *ptr != ',') {
1628 token = apr_pstrmemdup(p, tok_start, ptr - tok_start);
1630 /* Advance accept_line pointer to the next non-white byte */
1632 while (apr_isspace(*ptr))
1640 /* find http tokens, see the definition of token from RFC2068 */
1641 AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
1643 const unsigned char *start_token;
1644 const unsigned char *s;
1649 s = (const unsigned char *)line;
1651 /* find start of token, skip all stop characters, note NUL
1652 * isn't a token stop, so we don't need to test for it
1654 while (TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1661 /* find end of the token */
1662 while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1665 if (!strncasecmp((const char *)start_token, (const char *)tok,
1676 AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line,
1679 int llen, tlen, lidx;
1684 llen = strlen(line);
1689 (lidx > 0 && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1692 return (strncasecmp(&line[lidx], tok, tlen) == 0);
1695 AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1699 const unsigned char *s;
1701 cmd = apr_palloc(p, 2 * strlen(str) + 1); /* Be safe */
1702 d = (unsigned char *)cmd;
1703 s = (const unsigned char *)str;
1706 #if defined(OS2) || defined(WIN32)
1708 * Newlines to Win32/OS2 CreateProcess() are ill advised.
1709 * Convert them to spaces since they are effectively white
1710 * space to most applications
1712 if (*s == '\r' || *s == '\n') {
1718 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1728 static char x2c(const char *what)
1732 #if !APR_CHARSET_EBCDIC
1733 digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
1736 digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
1738 #else /*APR_CHARSET_EBCDIC*/
1745 digit = apr_xlate_conv_byte(ap_hdrs_from_ascii,
1746 0xFF & strtol(xstr, NULL, 16));
1747 #endif /*APR_CHARSET_EBCDIC*/
1752 * Unescapes a URL, leaving reserved characters intact.
1753 * Returns 0 on success, non-zero on error
1755 * bad % escape returns HTTP_BAD_REQUEST
1757 * decoding %00 or a forbidden character returns HTTP_NOT_FOUND
1760 static int unescape_url(char *url, const char *forbid, const char *reserved)
1762 int badesc, badpath;
1767 /* Initial scan for first '%'. Don't bother writing values before
1769 y = strchr(url, '%');
1773 for (x = y; *y; ++x, ++y) {
1778 if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1784 decoded = x2c(y + 1);
1785 if ((decoded == '\0')
1786 || (forbid && ap_strchr_c(forbid, decoded))) {
1791 else if (reserved && ap_strchr_c(reserved, decoded)) {
1805 return HTTP_BAD_REQUEST;
1808 return HTTP_NOT_FOUND;
1814 AP_DECLARE(int) ap_unescape_url(char *url)
1817 return unescape_url(url, SLASHES, NULL);
1819 AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes)
1821 /* AllowEncodedSlashes (corrected) */
1822 if (decode_slashes) {
1823 /* no chars reserved */
1824 return unescape_url(url, NULL, NULL);
1826 /* reserve (do not decode) encoded slashes */
1827 return unescape_url(url, NULL, SLASHES);
1831 /* IFDEF these out until they've been thought through.
1832 * Just a germ of an API extension for now
1834 AP_DECLARE(int) ap_unescape_url_proxy(char *url)
1836 /* leave RFC1738 reserved characters intact, * so proxied URLs
1837 * don't get mangled. Where does that leave encoded '&' ?
1839 return unescape_url(url, NULL, "/;?");
1841 AP_DECLARE(int) ap_unescape_url_reserved(char *url, const char *reserved)
1843 return unescape_url(url, NULL, reserved);
1847 AP_DECLARE(int) ap_unescape_urlencoded(char *query)
1851 /* replace plus with a space */
1853 for (slider = query; *slider; slider++) {
1854 if (*slider == '+') {
1860 /* unescape everything else */
1861 return unescape_url(query, NULL, NULL);
1864 AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname,
1865 apr_port_t port, const request_rec *r)
1867 if (ap_is_default_port(port, r)) {
1868 return apr_pstrdup(p, hostname);
1871 return apr_psprintf(p, "%s:%u", hostname, port);
1875 AP_DECLARE(int) ap_unescape_all(char *url)
1877 return unescape_url(url, NULL, NULL);
1880 /* c2x takes an unsigned, and expects the caller has guaranteed that
1881 * 0 <= what < 256... which usually means that you have to cast to
1882 * unsigned char first, because (unsigned)(char)(x) first goes through
1883 * signed extension to an int before the unsigned cast.
1885 * The reason for this assumption is to assist gcc code generation --
1886 * the unsigned char -> unsigned extension is already done earlier in
1887 * both uses of this code, so there's no need to waste time doing it
1890 static const char c2x_table[] = "0123456789abcdef";
1892 static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
1893 unsigned char *where)
1895 #if APR_CHARSET_EBCDIC
1896 what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
1897 #endif /*APR_CHARSET_EBCDIC*/
1899 *where++ = c2x_table[what >> 4];
1900 *where++ = c2x_table[what & 0xf];
1905 * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
1906 * routine is (should be) OS independent.
1908 * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
1909 * cases if a ':' occurs before the first '/' in the URL, the URL should be
1910 * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
1911 * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
1912 * efficiency reasons, we don't use escape_path_segment(), which is provided for
1913 * reference. Again, RFC 1808 is where this stuff is defined.
1915 * If partial is set, os_escape_path() assumes that the path will be appended to
1916 * something with a '/' in it (and thus does not prefix "./").
1919 AP_DECLARE(char *) ap_escape_path_segment_buffer(char *copy, const char *segment)
1921 const unsigned char *s = (const unsigned char *)segment;
1922 unsigned char *d = (unsigned char *)copy;
1926 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
1938 AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
1940 return ap_escape_path_segment_buffer(apr_palloc(p, 3 * strlen(segment) + 1), segment);
1943 AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
1945 char *copy = apr_palloc(p, 3 * strlen(path) + 3);
1946 const unsigned char *s = (const unsigned char *)path;
1947 unsigned char *d = (unsigned char *)copy;
1951 const char *colon = ap_strchr_c(path, ':');
1952 const char *slash = ap_strchr_c(path, '/');
1954 if (colon && (!slash || colon < slash)) {
1960 if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
1972 AP_DECLARE(char *) ap_escape_urlencoded_buffer(char *copy, const char *buffer)
1974 const unsigned char *s = (const unsigned char *)buffer;
1975 unsigned char *d = (unsigned char *)copy;
1979 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
1982 else if (c == ' ') {
1994 AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
1996 return ap_escape_urlencoded_buffer(apr_palloc(p, 3 * strlen(buffer) + 1), buffer);
1999 /* ap_escape_uri is now a macro for os_escape_path */
2001 AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
2006 /* first, count the number of extra characters */
2007 for (i = 0, j = 0; s[i] != '\0'; i++)
2008 if (s[i] == '<' || s[i] == '>')
2010 else if (s[i] == '&')
2012 else if (s[i] == '"')
2014 else if (toasc && !apr_isascii(s[i]))
2018 return apr_pstrmemdup(p, s, i);
2020 x = apr_palloc(p, i + j + 1);
2021 for (i = 0, j = 0; s[i] != '\0'; i++, j++)
2023 memcpy(&x[j], "<", 4);
2026 else if (s[i] == '>') {
2027 memcpy(&x[j], ">", 4);
2030 else if (s[i] == '&') {
2031 memcpy(&x[j], "&", 5);
2034 else if (s[i] == '"') {
2035 memcpy(&x[j], """, 6);
2038 else if (toasc && !apr_isascii(s[i])) {
2039 char *esc = apr_psprintf(p, "&#%3.3d;", (unsigned char)s[i]);
2040 memcpy(&x[j], esc, 6);
2049 AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str)
2053 const unsigned char *s;
2054 apr_size_t length, escapes = 0;
2060 /* Compute how many characters need to be escaped */
2061 s = (const unsigned char *)str;
2063 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2068 /* Compute the length of the input string, including NULL */
2069 length = s - (const unsigned char *)str + 1;
2071 /* Fast path: nothing to escape */
2073 return apr_pmemdup(p, str, length);
2076 /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */
2077 ret = apr_palloc(p, length + 3 * escapes);
2078 d = (unsigned char *)ret;
2079 s = (const unsigned char *)str;
2081 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2117 AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
2120 unsigned char *d, *ep;
2121 const unsigned char *s;
2123 if (!source || !buflen) { /* be safe */
2127 d = (unsigned char *)dest;
2128 s = (const unsigned char *)source;
2129 ep = d + buflen - 1;
2131 for (; d < ep && *s; ++s) {
2133 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2159 case '"': /* no need for this in error log */
2164 ep = --d; /* break the for loop as well */
2177 return (d - (unsigned char *)dest);
2180 AP_DECLARE(void) ap_bin2hex(const void *src, apr_size_t srclen, char *dest)
2182 const unsigned char *in = src;
2185 for (i = 0; i < srclen; i++) {
2186 *dest++ = c2x_table[in[i] >> 4];
2187 *dest++ = c2x_table[in[i] & 0xf];
2192 AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
2196 if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS)
2197 return 0; /* in error condition, just return no */
2199 return (finfo.filetype == APR_DIR);
2202 AP_DECLARE(int) ap_is_rdirectory(apr_pool_t *p, const char *path)
2206 if (apr_stat(&finfo, path, APR_FINFO_LINK | APR_FINFO_TYPE, p) != APR_SUCCESS)
2207 return 0; /* in error condition, just return no */
2209 return (finfo.filetype == APR_DIR);
2212 AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
2215 apr_size_t len1, len2;
2218 len1 = strlen(src1);
2219 len2 = strlen(src2);
2220 /* allocate +3 for '/' delimiter, trailing NULL and overallocate
2221 * one extra byte to allow the caller to add a trailing '/'
2223 path = (char *)apr_palloc(a, len1 + len2 + 3);
2226 memcpy(path + 1, src2, len2 + 1);
2230 memcpy(path, src1, len1);
2232 if (next[-1] != '/') {
2235 memcpy(next, src2, len2 + 1);
2241 * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
2243 AP_DECLARE(int) ap_is_url(const char *u)
2247 for (x = 0; u[x] != ':'; x++) {
2249 ((!apr_isalnum(u[x])) &&
2250 (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
2255 return (x ? 1 : 0); /* If the first character is ':', it's broken, too */
2258 AP_DECLARE(int) ap_ind(const char *s, char c)
2260 const char *p = ap_strchr_c(s, c);
2267 AP_DECLARE(int) ap_rind(const char *s, char c)
2269 const char *p = ap_strrchr_c(s, c);
2276 AP_DECLARE(void) ap_str_tolower(char *str)
2279 *str = apr_tolower(*str);
2284 AP_DECLARE(void) ap_str_toupper(char *str)
2287 *str = apr_toupper(*str);
2293 * We must return a FQDN
2295 char *ap_get_local_host(apr_pool_t *a)
2297 #ifndef MAXHOSTNAMELEN
2298 #define MAXHOSTNAMELEN 256
2300 char str[MAXHOSTNAMELEN + 1];
2301 char *server_hostname = NULL;
2302 apr_sockaddr_t *sockaddr;
2305 if (apr_gethostname(str, sizeof(str) - 1, a) != APR_SUCCESS) {
2306 ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00556)
2307 "%s: apr_gethostname() failed to determine ServerName",
2310 str[sizeof(str) - 1] = '\0';
2311 if (apr_sockaddr_info_get(&sockaddr, str, APR_UNSPEC, 0, 0, a) == APR_SUCCESS) {
2312 if ( (apr_getnameinfo(&hostname, sockaddr, 0) == APR_SUCCESS) &&
2313 (ap_strchr_c(hostname, '.')) ) {
2314 server_hostname = apr_pstrdup(a, hostname);
2315 return server_hostname;
2316 } else if (ap_strchr_c(str, '.')) {
2317 server_hostname = apr_pstrdup(a, str);
2319 apr_sockaddr_ip_get(&hostname, sockaddr);
2320 server_hostname = apr_pstrdup(a, hostname);
2323 ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00557)
2324 "%s: apr_sockaddr_info_get() failed for %s",
2325 ap_server_argv0, str);
2329 if (!server_hostname)
2330 server_hostname = apr_pstrdup(a, "127.0.0.1");
2332 ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, a, APLOGNO(00558)
2333 "%s: Could not reliably determine the server's fully qualified "
2334 "domain name, using %s. Set the 'ServerName' directive globally "
2335 "to suppress this message",
2336 ap_server_argv0, server_hostname);
2338 return server_hostname;
2341 /* simple 'pool' alloc()ing glue to apr_base64.c
2343 AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
2348 decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded));
2349 l = apr_base64_decode(decoded, bufcoded);
2350 decoded[l] = '\0'; /* make binary sequence into string */
2355 AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
2358 int l = strlen(string);
2360 encoded = (char *) apr_palloc(p, 1 + apr_base64_encode_len(l));
2361 l = apr_base64_encode(encoded, string, l);
2362 encoded[l] = '\0'; /* make binary sequence into string */
2367 /* we want to downcase the type/subtype for comparison purposes
2368 * but nothing else because ;parameter=foo values are case sensitive.
2369 * XXX: in truth we want to downcase parameter names... but really,
2370 * apache has never handled parameters and such correctly. You
2371 * also need to compress spaces and such to be able to compare
2374 AP_DECLARE(void) ap_content_type_tolower(char *str)
2378 semi = strchr(str, ';');
2383 ap_str_tolower(str);
2391 * Given a string, replace any bare " with \" .
2393 AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
2396 const char *inchr = instring;
2397 char *outchr, *outstring;
2400 * Look through the input string, jogging the length of the output
2401 * string up by an extra byte each time we find an unescaped ".
2403 while (*inchr != '\0') {
2405 if (*inchr == '"') {
2409 * If we find a slosh, and it's not the last byte in the string,
2410 * it's escaping something - advance past both bytes.
2412 if ((*inchr == '\\') && (inchr[1] != '\0')) {
2418 outstring = apr_palloc(p, newlen + 1);
2422 * Now copy the input string to the output string, inserting a slosh
2423 * in front of every " that doesn't already have one.
2425 while (*inchr != '\0') {
2426 if ((*inchr == '\\') && (inchr[1] != '\0')) {
2427 *outchr++ = *inchr++;
2428 *outchr++ = *inchr++;
2430 if (*inchr == '"') {
2433 if (*inchr != '\0') {
2434 *outchr++ = *inchr++;
2442 * Given a string, append the PID deliminated by delim.
2443 * Usually used to create a pid-appended filepath name
2444 * (eg: /a/b/foo -> /a/b/foo.6726). A function, and not
2445 * a macro, to avoid unistd.h dependency
2447 AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string,
2450 return apr_psprintf(p, "%s%s%" APR_PID_T_FMT, string,
2456 * Parse a given timeout parameter string into an apr_interval_time_t value.
2457 * The unit of the time interval is given as postfix string to the numeric
2458 * string. Currently the following units are understood:
2465 * If no unit is contained in the given timeout parameter the default_time_unit
2466 * will be used instead.
2467 * @param timeout_parameter The string containing the timeout parameter.
2468 * @param timeout The timeout value to be returned.
2469 * @param default_time_unit The default time unit to use if none is specified
2470 * in timeout_parameter.
2471 * @return Status value indicating whether the parsing was successful or not.
2473 AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
2474 const char *timeout_parameter,
2475 apr_interval_time_t *timeout,
2476 const char *default_time_unit)
2479 const char *time_str;
2482 tout = apr_strtoi64(timeout_parameter, &endp, 10);
2486 if (!endp || !*endp) {
2487 time_str = default_time_unit;
2493 switch (*time_str) {
2494 /* Time is in seconds */
2496 *timeout = (apr_interval_time_t) apr_time_from_sec(tout);
2499 /* Time is in hours */
2500 *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 3600);
2503 switch (*(++time_str)) {
2504 /* Time is in milliseconds */
2506 *timeout = (apr_interval_time_t) tout * 1000;
2508 /* Time is in minutes */
2510 *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 60);
2513 return APR_EGENERAL;
2517 return APR_EGENERAL;
2523 * Determine if a request has a request body or not.
2525 * @param r the request_rec of the request
2526 * @return truth value
2528 AP_DECLARE(int) ap_request_has_body(request_rec *r)
2535 has_body = (!r->header_only
2537 || apr_table_get(r->headers_in, "Transfer-Encoding")
2538 || ( (cls = apr_table_get(r->headers_in, "Content-Length"))
2539 && (apr_strtoff(&cl, cls, &estr, 10) == APR_SUCCESS)
2547 AP_DECLARE_NONSTD(apr_status_t) ap_pool_cleanup_set_null(void *data_)
2549 void **ptr = (void **)data_;
2554 AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
2556 for ( ; *src; src++, dest++)
2558 if (!apr_isprint(*src))
2560 else if (!apr_isalnum(*src))
2570 AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
2573 char *new = apr_palloc(p, strlen(src)+1);
2577 return ap_str2_alnum(src, new);
2581 * Read the body and parse any form found, which must be of the
2582 * type application/x-www-form-urlencoded.
2584 * Name/value pairs are returned in an array, with the names as
2585 * strings with a maximum length of HUGE_STRING_LEN, and the
2586 * values as bucket brigades. This allows values to be arbitrarily
2589 * All url-encoding is removed from both the names and the values
2590 * on the fly. The names are interpreted as strings, while the
2591 * values are interpreted as blocks of binary data, that may
2592 * contain the 0 character.
2594 * In order to ensure that resource limits are not exceeded, a
2595 * maximum size must be provided. If the sum of the lengths of
2596 * the names and the values exceed this size, this function
2597 * will return HTTP_REQUEST_ENTITY_TOO_LARGE.
2599 * An optional number of parameters can be provided, if the number
2600 * of parameters provided exceeds this amount, this function will
2601 * return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
2602 * no limit is imposed, and the number of parameters is in turn
2603 * constrained by the size parameter above.
2605 * This function honours any kept_body configuration, and the
2606 * original raw request body will be saved to the kept_body brigade
2607 * if so configured, just as ap_discard_request_body does.
2609 * NOTE: File upload is not yet supported, but can be without change
2610 * to the function call.
2613 /* form parsing stuff */
2624 AP_DECLARE(int) ap_parse_form_data(request_rec *r, ap_filter_t *f,
2625 apr_array_header_t **ptr,
2626 apr_size_t num, apr_size_t usize)
2628 apr_bucket_brigade *bb = NULL;
2630 char buffer[HUGE_STRING_LEN + 1];
2632 apr_size_t offset = 0;
2634 ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
2635 ap_form_pair_t *pair = NULL;
2636 apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
2643 /* sanity check - we only support forms for now */
2644 ct = apr_table_get(r->headers_in, "Content-Type");
2645 if (!ct || strncasecmp("application/x-www-form-urlencoded", ct, 33)) {
2646 return ap_discard_request_body(r);
2649 if (usize > APR_SIZE_MAX >> 1)
2650 size = APR_SIZE_MAX >> 1;
2655 f = r->input_filters;
2658 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2660 apr_bucket *bucket = NULL, *last = NULL;
2662 int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
2663 APR_BLOCK_READ, HUGE_STRING_LEN);
2664 if (rv != APR_SUCCESS) {
2665 apr_brigade_destroy(bb);
2666 return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
2669 for (bucket = APR_BRIGADE_FIRST(bb);
2670 bucket != APR_BRIGADE_SENTINEL(bb);
2671 last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
2673 apr_size_t len, slide;
2676 apr_bucket_delete(last);
2678 if (APR_BUCKET_IS_EOS(bucket)) {
2682 if (bucket->length == 0) {
2686 rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
2687 if (rv != APR_SUCCESS) {
2688 apr_brigade_destroy(bb);
2689 return HTTP_BAD_REQUEST;
2693 while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
2698 else if ('&' == c) {
2702 percent = FORM_PERCENTA;
2705 if (FORM_PERCENTA == percent) {
2709 else if (c >= 'A') {
2712 else if (c >= '0') {
2716 percent = FORM_PERCENTB;
2719 if (FORM_PERCENTB == percent) {
2723 else if (c >= 'A') {
2726 else if (c >= '0') {
2730 percent = FORM_NORMAL;
2735 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2736 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2737 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2745 if (offset < HUGE_STRING_LEN) {
2749 pair = (ap_form_pair_t *) apr_array_push(pairs);
2750 pair->name = apr_pstrdup(r->pool, buffer);
2751 pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2755 buffer[offset++] = c;
2764 if (offset >= HUGE_STRING_LEN) {
2765 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2766 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2767 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2770 buffer[offset++] = c;
2780 apr_brigade_cleanup(bb);
2781 } while (!seen_eos);
2783 if (FORM_ABORT == state || size < 0 || num == 0) {
2784 return HTTP_REQUEST_ENTITY_TOO_LARGE;
2786 else if (FORM_VALUE == state && pair && offset > 0) {
2787 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2788 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2789 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2796 #define VARBUF_SMALL_SIZE 2048
2797 #define VARBUF_MAX_SIZE (APR_SIZE_MAX - 1 - \
2798 APR_ALIGN_DEFAULT(sizeof(struct ap_varbuf_info)))
2800 struct ap_varbuf_info {
2801 struct apr_memnode_t *node;
2802 apr_allocator_t *allocator;
2805 static apr_status_t varbuf_cleanup(void *info_)
2807 struct ap_varbuf_info *info = info_;
2808 info->node->next = NULL;
2809 apr_allocator_free(info->allocator, info->node);
2813 const char nul = '\0';
2814 static char * const varbuf_empty = (char *)&nul;
2816 AP_DECLARE(void) ap_varbuf_init(apr_pool_t *p, struct ap_varbuf *vb,
2817 apr_size_t init_size)
2819 vb->buf = varbuf_empty;
2821 vb->strlen = AP_VARBUF_UNKNOWN;
2825 ap_varbuf_grow(vb, init_size);
2828 AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
2830 apr_memnode_t *new_node = NULL;
2831 apr_allocator_t *allocator;
2832 struct ap_varbuf_info *new_info;
2835 AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN || vb->avail >= vb->strlen);
2837 if (new_len <= vb->avail)
2840 if (new_len < 2 * vb->avail && vb->avail < VARBUF_MAX_SIZE/2) {
2841 /* at least double the size, to avoid repeated reallocations */
2842 new_len = 2 * vb->avail;
2844 else if (new_len > VARBUF_MAX_SIZE) {
2845 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2846 ap_assert(abort_fn != NULL);
2847 abort_fn(APR_ENOMEM);
2851 new_len++; /* add space for trailing \0 */
2852 if (new_len <= VARBUF_SMALL_SIZE) {
2853 new_len = APR_ALIGN_DEFAULT(new_len);
2854 new = apr_palloc(vb->pool, new_len);
2855 if (vb->avail && vb->strlen != 0) {
2856 AP_DEBUG_ASSERT(vb->buf != NULL);
2857 AP_DEBUG_ASSERT(vb->buf != varbuf_empty);
2858 if (new == vb->buf + vb->avail + 1) {
2859 /* We are lucky: the new memory lies directly after our old
2860 * buffer, we can now use both.
2862 vb->avail += new_len;
2866 /* copy up to vb->strlen + 1 bytes */
2867 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2868 vb->avail + 1 : vb->strlen + 1);
2874 vb->avail = new_len - 1;
2879 /* The required block is rather larger. Use allocator directly so that
2880 * the memory can be freed independently from the pool. */
2881 allocator = apr_pool_allocator_get(vb->pool);
2882 if (new_len <= VARBUF_MAX_SIZE)
2883 new_node = apr_allocator_alloc(allocator,
2884 new_len + APR_ALIGN_DEFAULT(sizeof(*new_info)));
2886 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2887 ap_assert(abort_fn != NULL);
2888 abort_fn(APR_ENOMEM);
2891 new_info = (struct ap_varbuf_info *)new_node->first_avail;
2892 new_node->first_avail += APR_ALIGN_DEFAULT(sizeof(*new_info));
2893 new_info->node = new_node;
2894 new_info->allocator = allocator;
2895 new = new_node->first_avail;
2896 AP_DEBUG_ASSERT(new_node->endp - new_node->first_avail >= new_len);
2897 new_len = new_node->endp - new_node->first_avail;
2899 if (vb->avail && vb->strlen != 0)
2900 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2901 vb->avail + 1 : vb->strlen + 1);
2905 apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
2906 apr_pool_cleanup_register(vb->pool, new_info, varbuf_cleanup,
2907 apr_pool_cleanup_null);
2908 vb->info = new_info;
2910 vb->avail = new_len - 1;
2913 AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
2919 ap_varbuf_grow(vb, len);
2920 memcpy(vb->buf, str, len);
2921 vb->buf[len] = '\0';
2925 if (vb->strlen == AP_VARBUF_UNKNOWN)
2926 vb->strlen = strlen(vb->buf);
2927 ap_varbuf_grow(vb, vb->strlen + len);
2928 memcpy(vb->buf + vb->strlen, str, len);
2930 vb->buf[vb->strlen] = '\0';
2933 AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb)
2936 apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
2942 AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *buf,
2943 const char *prepend, apr_size_t prepend_len,
2944 const char *append, apr_size_t append_len,
2945 apr_size_t *new_len)
2948 struct iovec vec[3];
2951 vec[i].iov_base = (void *)prepend;
2952 vec[i].iov_len = prepend_len;
2955 if (buf->avail && buf->strlen) {
2956 if (buf->strlen == AP_VARBUF_UNKNOWN)
2957 buf->strlen = strlen(buf->buf);
2958 vec[i].iov_base = (void *)buf->buf;
2959 vec[i].iov_len = buf->strlen;
2963 vec[i].iov_base = (void *)append;
2964 vec[i].iov_len = append_len;
2968 return apr_pstrcatv(p, vec, i, new_len);
2975 AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb,
2979 ap_regmatch_t pmatch[],
2982 return regsub_core(NULL, NULL, vb, input, source, nmatch, pmatch, maxlen);
2985 static const char * const oom_message = "[crit] Memory allocation failed, "
2986 "aborting process." APR_EOL_STR;
2988 AP_DECLARE(void) ap_abort_on_oom()
2990 int written, count = strlen(oom_message);
2991 const char *buf = oom_message;
2993 written = write(STDERR_FILENO, buf, count);
2994 if (written == count)
3000 } while (written >= 0 || errno == EINTR);
3004 AP_DECLARE(void *) ap_malloc(size_t size)
3006 void *p = malloc(size);
3007 if (p == NULL && size != 0)
3012 AP_DECLARE(void *) ap_calloc(size_t nelem, size_t size)
3014 void *p = calloc(nelem, size);
3015 if (p == NULL && nelem != 0 && size != 0)
3020 AP_DECLARE(void *) ap_realloc(void *ptr, size_t size)
3022 void *p = realloc(ptr, size);
3023 if (p == NULL && size != 0)
3028 AP_DECLARE(void) ap_get_sload(ap_sload_t *ld)
3030 int i, j, server_limit, thread_limit;
3034 ap_generation_t mpm_generation;
3036 /* preload errored fields, we overwrite */
3039 ld->bytes_served = 0;
3040 ld->access_count = 0;
3042 ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
3043 ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
3044 ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
3046 for (i = 0; i < server_limit; i++) {
3048 ps = ap_get_scoreboard_process(i);
3050 for (j = 0; j < thread_limit; j++) {
3052 worker_score *ws = NULL;
3053 ws = &ap_scoreboard_image->servers[i][j];
3056 if (!ps->quiescing && ps->pid) {
3057 if (res == SERVER_READY && ps->generation == mpm_generation) {
3060 else if (res != SERVER_DEAD &&
3061 res != SERVER_STARTING && res != SERVER_IDLE_KILL &&
3062 ps->generation == mpm_generation) {
3067 if (ap_extended_status && !ps->quiescing && ps->pid) {
3068 if (ws->access_count != 0
3069 || (res != SERVER_READY && res != SERVER_DEAD)) {
3070 ld->access_count += ws->access_count;
3071 ld->bytes_served += ws->bytes_served;
3076 total = busy + ready;
3078 ld->idle = ready * 100 / total;
3079 ld->busy = busy * 100 / total;
3083 AP_DECLARE(void) ap_get_loadavg(ap_loadavg_t *ld)
3085 /* preload errored fields, we overwrite */
3087 ld->loadavg5 = -1.0;
3088 ld->loadavg15 = -1.0;
3095 num = getloadavg(la, 3);
3097 ld->loadavg = (float)la[0];
3100 ld->loadavg5 = (float)la[1];
3103 ld->loadavg15 = (float)la[2];
3109 AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p,
3111 const char * const * argv)
3113 char buf[MAX_STRING_LEN];
3114 apr_procattr_t *procattr;
3117 apr_size_t nbytes = 1;
3121 if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
3123 if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
3124 APR_FULL_BLOCK) != APR_SUCCESS)
3126 if (apr_procattr_dir_set(procattr,
3127 ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
3129 if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
3131 proc = apr_pcalloc(p, sizeof(apr_proc_t));
3132 if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
3138 /* XXX: we are reading 1 byte at a time here */
3139 for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
3140 && nbytes == 1 && (k < MAX_STRING_LEN-1) ; ) {
3141 if (c == '\n' || c == '\r')
3148 return apr_pstrndup(p, buf, k);
3151 AP_DECLARE(int) ap_array_str_index(const apr_array_header_t *array,
3158 for (i = start; i < array->nelts; i++) {
3159 const char *p = APR_ARRAY_IDX(array, i, const char *);
3160 if (!strcmp(p, s)) {
3169 AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array,
3172 return (ap_array_str_index(array, s, 0) >= 0);
3175 #if !APR_CHARSET_EBCDIC
3177 * Our own known-fast translation table for casecmp by character.
3178 * Only ASCII alpha characters 41-5A are folded to 61-7A, other
3179 * octets (such as extended latin alphabetics) are never case-folded.
3180 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3182 static const short ucharmap[] = {
3183 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
3184 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
3185 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3186 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3187 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3188 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3189 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3190 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3191 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3192 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3193 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3194 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3195 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3196 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3197 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3198 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3199 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3200 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3201 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3202 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3203 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3204 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3205 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3206 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3207 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3208 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3209 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3210 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3211 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3212 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3213 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3214 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3216 #else /* APR_CHARSET_EBCDIC */
3218 * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison,
3219 * provides unique identity of every char value (strict ISO-646
3220 * conformance, arbitrary election of an ISO-8859-1 ordering, and
3221 * very arbitrary control code assignments into C1 to achieve
3222 * identity and a reversible mapping of code points),
3223 * then folding the equivalences of ASCII 41-5A into 61-7A,
3224 * presenting comparison results in a somewhat ISO/IEC 10646
3225 * (ASCII-like) order, depending on the EBCDIC code page in use.
3227 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3229 static const short ucharmap[] = {
3230 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
3231 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
3232 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
3233 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
3234 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
3235 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
3236 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
3237 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
3238 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,
3239 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
3240 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,
3241 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
3242 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,
3243 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
3244 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,
3245 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
3246 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3247 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,
3248 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3249 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,
3250 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3251 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE,
3252 0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,
3253 0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7,
3254 0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3255 0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,
3256 0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3257 0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,
3258 0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3259 0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,
3260 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3261 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F
3265 AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2)
3267 const unsigned char *str1 = (const unsigned char *)s1;
3268 const unsigned char *str2 = (const unsigned char *)s2;
3271 const int c1 = (int)(*str1);
3272 const int c2 = (int)(*str2);
3273 const int cmp = ucharmap[c1] - ucharmap[c2];
3274 /* Not necessary to test for !c2, this is caught by cmp */
3282 AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
3284 const unsigned char *str1 = (const unsigned char *)s1;
3285 const unsigned char *str2 = (const unsigned char *)s2;
3288 const int c1 = (int)(*str1);
3289 const int c2 = (int)(*str2);
3290 const int cmp = ucharmap[c1] - ucharmap[c2];
3291 /* Not necessary to test for !c2, this is caught by cmp */