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"
33 #include "apr_md5.h" /* for apr_password_validate */
35 #define APR_WANT_STDIO
36 #define APR_WANT_STRFUNC
42 #if APR_HAVE_PROCESS_H
43 #include <process.h> /* for getpid() on Win32 */
46 #include <netdb.h> /* for gethostbyname() */
49 #include "ap_config.h"
50 #include "apr_base64.h"
52 #include "http_main.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"
66 #ifdef HAVE_SYS_LOADAVG_H
67 #include <sys/loadavg.h>
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.
76 #include "test_char.h"
78 /* we assume the folks using this ensure 0 <= c < 256... which means
79 * you need a cast to (unsigned char) first, you can't just plug a
80 * char in here and get it to work, because if char is signed then it
81 * will first be sign extended.
83 #define TEST_CHAR(c, f) (test_char_table[(unsigned char)(c)] & (f))
85 /* Win32/NetWare/OS2 need to check for both forward and back slashes
86 * in ap_getparents() and ap_escape_url.
88 #ifdef CASE_BLIND_FILESYSTEM
89 #define IS_SLASH(s) ((s == '/') || (s == '\\'))
92 #define IS_SLASH(s) (s == '/')
96 /* we know core's module_index is 0 */
97 #undef APLOG_MODULE_INDEX
98 #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
101 * Examine a field value (such as a media-/content-type) string and return
102 * it sans any parameters; e.g., strip off any ';charset=foo' and the like.
104 AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype)
108 if (intype == NULL) return NULL;
110 semi = ap_strchr_c(intype, ';');
112 return apr_pstrdup(p, intype);
115 while ((semi > intype) && apr_isspace(semi[-1])) {
118 return apr_pstrmemdup(p, intype, semi - intype);
122 AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt,
126 char ts[MAX_STRING_LEN];
127 char tf[MAX_STRING_LEN];
134 apr_time_exp_gmt(&xt, t);
135 /* Convert %Z to "GMT" and %z to "+0000";
136 * on hosts that do not have a time zone string in struct tm,
137 * strftime must assume its argument is local time.
139 for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f)
141 if (*f != '%') continue;
152 case 'z': /* common extension */
166 apr_time_exp_lt(&xt, t);
169 /* check return code? */
170 apr_strftime(ts, &retcode, MAX_STRING_LEN, fmt, &xt);
171 ts[MAX_STRING_LEN - 1] = '\0';
172 return apr_pstrdup(p, ts);
175 /* Roy owes Rob beer. */
176 /* Rob owes Roy dinner. */
178 /* These legacy comments would make a lot more sense if Roy hadn't
179 * replaced the old later_than() routine with util_date.c.
181 * Well, okay, they still wouldn't make any sense.
184 /* Match = 0, NoMatch = 1, Abort = -1
185 * Based loosely on sections of wildmat.c by Rich Salz
186 * Hmmm... shouldn't this really go component by component?
188 AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected)
192 for (x = 0, y = 0; expected[y]; ++y, ++x) {
193 if ((!str[x]) && (expected[y] != '*'))
195 if (expected[y] == '*') {
196 while (expected[++y] == '*');
201 if ((ret = ap_strcmp_match(&str[x++], &expected[y])) != 1)
206 else if ((expected[y] != '?') && (str[x] != expected[y]))
209 return (str[x] != '\0');
212 AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
216 for (x = 0, y = 0; expected[y]; ++y, ++x) {
217 if (!str[x] && expected[y] != '*')
219 if (expected[y] == '*') {
220 while (expected[++y] == '*');
225 if ((ret = ap_strcasecmp_match(&str[x++], &expected[y])) != 1)
230 else if (expected[y] != '?'
231 && apr_tolower(str[x]) != apr_tolower(expected[y]))
234 return (str[x] != '\0');
237 /* We actually compare the canonical root to this root, (but we don't
238 * waste time checking the case), since every use of this function in
239 * httpd-2.1 tests if the path is 'proper', meaning we've already passed
240 * it through apr_filepath_merge, or we haven't.
242 AP_DECLARE(int) ap_os_is_path_absolute(apr_pool_t *p, const char *dir)
245 const char *ourdir = dir;
246 if (apr_filepath_root(&newpath, &dir, 0, p) != APR_SUCCESS
247 || strncmp(newpath, ourdir, strlen(newpath)) != 0) {
253 AP_DECLARE(int) ap_is_matchexp(const char *str)
257 for (x = 0; str[x]; x++)
258 if ((str[x] == '*') || (str[x] == '?'))
264 * Here's a pool-based interface to the POSIX-esque ap_regcomp().
265 * Note that we return ap_regex_t instead of being passed one.
266 * The reason is that if you use an already-used ap_regex_t structure,
267 * the memory that you've already allocated gets forgotten, and
268 * regfree() doesn't clear it. So we don't allow it.
271 static apr_status_t regex_cleanup(void *preg)
273 ap_regfree((ap_regex_t *) preg);
277 AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
280 ap_regex_t *preg = apr_palloc(p, sizeof *preg);
281 int err = ap_regcomp(preg, pattern, cflags);
283 if (err == AP_REG_ESPACE)
288 apr_pool_cleanup_register(p, (void *) preg, regex_cleanup,
289 apr_pool_cleanup_null);
294 AP_DECLARE(void) ap_pregfree(apr_pool_t *p, ap_regex_t *reg)
297 apr_pool_cleanup_kill(p, (void *) reg, regex_cleanup);
301 * Similar to standard strstr() but we ignore case in this version.
302 * Based on the strstr() implementation further below.
304 AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2)
312 for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
316 /* found first character of s2, see if the rest matches */
319 for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) {
321 /* both strings ended together */
326 /* second string ended, a match */
329 /* didn't find a match here, try starting at next character in s1 */
336 * Returns an offsetted pointer in bigstring immediately after
337 * prefix. Returns bigstring if bigstring doesn't start with
338 * prefix or if prefix is longer than bigstring while still matching.
339 * NOTE: pointer returned is relative to bigstring, so we
340 * can use standard pointer comparisons in the calling function
341 * (eg: test if ap_stripprefix(a,b) == a)
343 AP_DECLARE(const char *) ap_stripprefix(const char *bigstring,
352 while (*p1 && *prefix) {
353 if (*p1++ != *prefix++)
359 /* hit the end of bigstring! */
363 /* This function substitutes for $0-$9, filling in regular expression
364 * submatches. Pass it the same nmatch and pmatch arguments that you
365 * passed ap_regexec(). pmatch should not be greater than the maximum number
366 * of subexpressions - i.e. one more than the re_nsub member of ap_regex_t.
368 * nmatch must be <=AP_MAX_REG_MATCH (10).
370 * input should be the string with the $-expressions, source should be the
371 * string that was matched against.
373 * It returns the substituted string, or NULL if a vbuf is used.
374 * On errors, returns the orig string.
376 * Parts of this code are based on Henry Spencer's regsub(), from his
377 * AT&T V8 regexp package.
380 static apr_status_t regsub_core(apr_pool_t *p, char **result,
381 struct ap_varbuf *vb, const char *input,
382 const char *source, apr_size_t nmatch,
383 ap_regmatch_t pmatch[], apr_size_t maxlen)
385 const char *src = input;
391 AP_DEBUG_ASSERT((result && p && !vb) || (vb && !p && !result));
392 if (!source || nmatch>AP_MAX_REG_MATCH)
396 if (maxlen > 0 && len >= maxlen)
399 *result = apr_pstrmemdup(p, src, len);
403 ap_varbuf_strmemcat(vb, src, len);
408 /* First pass, find the size */
409 while ((c = *src++) != '\0') {
410 if (c == '$' && apr_isdigit(*src))
413 no = AP_MAX_REG_MATCH;
415 if (no >= AP_MAX_REG_MATCH) { /* Ordinary character. */
416 if (c == '\\' && *src)
420 else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
421 if (APR_SIZE_MAX - len <= pmatch[no].rm_eo - pmatch[no].rm_so)
423 len += pmatch[no].rm_eo - pmatch[no].rm_so;
428 if (len >= maxlen && maxlen > 0)
432 *result = dst = apr_palloc(p, len + 1);
435 if (vb->strlen == AP_VARBUF_UNKNOWN)
436 vb->strlen = strlen(vb->buf);
437 ap_varbuf_grow(vb, vb->strlen + len);
438 dst = vb->buf + vb->strlen;
442 /* Now actually fill in the string */
446 while ((c = *src++) != '\0') {
447 if (c == '$' && apr_isdigit(*src))
450 no = AP_MAX_REG_MATCH;
452 if (no >= AP_MAX_REG_MATCH) { /* Ordinary character. */
453 if (c == '\\' && *src)
457 else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
458 len = pmatch[no].rm_eo - pmatch[no].rm_so;
459 memcpy(dst, source + pmatch[no].rm_so, len);
469 #ifndef AP_PREGSUB_MAXLEN
470 #define AP_PREGSUB_MAXLEN (HUGE_STRING_LEN * 8)
472 AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
473 const char *source, apr_size_t nmatch,
474 ap_regmatch_t pmatch[])
477 apr_status_t rc = regsub_core(p, &result, NULL, input, source, nmatch,
478 pmatch, AP_PREGSUB_MAXLEN);
479 if (rc != APR_SUCCESS)
484 AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result,
485 const char *input, const char *source,
486 apr_size_t nmatch, ap_regmatch_t pmatch[],
489 apr_status_t rc = regsub_core(p, result, NULL, input, source, nmatch,
491 if (rc != APR_SUCCESS)
497 * Parse .. so we don't compromise security
499 AP_DECLARE(void) ap_getparents(char *name)
504 /* Four paseses, as per RFC 1808 */
505 /* a) remove ./ path segments */
506 for (next = name; *next && (*next != '.'); next++) {
509 l = w = first_dot = next - name;
510 while (name[l] != '\0') {
511 if (name[l] == '.' && IS_SLASH(name[l + 1])
512 && (l == 0 || IS_SLASH(name[l - 1])))
515 name[w++] = name[l++];
518 /* b) remove trailing . path, segment */
519 if (w == 1 && name[0] == '.')
521 else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2]))
525 /* c) remove all xx/../ segments. (including leading ../ and /../) */
528 while (name[l] != '\0') {
529 if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2])
530 && (l == 0 || IS_SLASH(name[l - 1]))) {
535 while (l >= 0 && !IS_SLASH(name[l]))
542 while ((name[n] = name[m]))
549 /* d) remove trailing xx/.. segment. */
550 if (l == 2 && name[0] == '.' && name[1] == '.')
552 else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
553 && IS_SLASH(name[l - 3])) {
556 while (l >= 0 && !IS_SLASH(name[l]))
566 AP_DECLARE(void) ap_no2slash(char *name)
572 #ifdef HAVE_UNC_PATHS
573 /* Check for UNC names. Leave leading two slashes. */
574 if (s[0] == '/' && s[1] == '/')
579 if ((*d++ = *s) == '/') {
593 * copy at most n leading directories of s into d
594 * d should be at least as large as s plus 1 extra byte
596 * the return value is the ever useful pointer to the trailing \0 of d
598 * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments,
599 * so that if n == 0, "/" is returned in d with n == 1
600 * and s == "e:/test.html", "e:/" is returned in d
601 * *** See also directory_walk in modules/http/http_request.c
604 * /a/b, 0 ==> / (true for all platforms)
613 * c:/a/b 3 ==> c:/a/b
614 * c:/a/b 4 ==> c:/a/b
616 AP_DECLARE(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
625 if (*s == '\0' || (*s == '/' && (--n) == 0)) {
637 * return the parent directory name including trailing / of the file s
639 AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s)
641 const char *last_slash = ap_strrchr_c(s, '/');
645 if (last_slash == NULL) {
646 return apr_pstrdup(p, "");
648 l = (last_slash - s) + 1;
649 d = apr_pstrmemdup(p, s, l);
655 AP_DECLARE(int) ap_count_dirs(const char *path)
659 for (x = 0, n = 0; path[x]; x++)
665 AP_DECLARE(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop)
667 return ap_getword(atrans, (const char **) line, stop);
670 AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop)
672 const char *pos = *line;
676 while ((*pos != stop) && *pos) {
681 res = apr_pstrmemdup(atrans, *line, len);
684 while (*pos == stop) {
693 AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
695 return ap_getword_white(atrans, (const char **) line);
698 AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
700 const char *pos = *line;
704 while (!apr_isspace(*pos) && *pos) {
709 res = apr_pstrmemdup(atrans, *line, len);
711 while (apr_isspace(*pos)) {
720 AP_DECLARE(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line,
723 return ap_getword_nulls(atrans, (const char **) line, stop);
726 AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line,
729 const char *pos = ap_strchr_c(*line, stop);
733 apr_size_t len = strlen(*line);
734 res = apr_pstrmemdup(atrans, *line, len);
739 res = apr_pstrmemdup(atrans, *line, pos - *line);
748 /* Get a word, (new) config-file style --- quoted strings and backslashes
752 static char *substring_conf(apr_pool_t *p, const char *start, int len,
755 char *result = apr_palloc(p, len + 1);
759 for (i = 0; i < len; ++i) {
760 if (start[i] == '\\' && (start[i + 1] == '\\'
761 || (quote && start[i + 1] == quote)))
762 *resp++ = start[++i];
768 #if RESOLVE_ENV_PER_TOKEN
769 return (char *)ap_resolve_env(p,result);
775 AP_DECLARE(char *) ap_getword_conf_nc(apr_pool_t *p, char **line)
777 return ap_getword_conf(p, (const char **) line);
780 AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line)
782 const char *str = *line, *strend;
786 while (apr_isspace(*str))
794 if ((quote = *str) == '"' || quote == '\'') {
796 while (*strend && *strend != quote) {
797 if (*strend == '\\' && strend[1] &&
798 (strend[1] == quote || strend[1] == '\\')) {
805 res = substring_conf(p, str + 1, strend - str - 1, quote);
807 if (*strend == quote)
812 while (*strend && !apr_isspace(*strend))
815 res = substring_conf(p, str, strend - str, 0);
818 while (apr_isspace(*strend))
824 AP_DECLARE(char *) ap_getword_conf2_nc(apr_pool_t *p, char **line)
826 return ap_getword_conf2(p, (const char **) line);
829 AP_DECLARE(char *) ap_getword_conf2(apr_pool_t *p, const char **line)
831 const char *str = *line, *strend;
836 while (apr_isspace(*str))
844 if ((quote = *str) == '"' || quote == '\'')
845 return ap_getword_conf(p, line);
850 if (*strend == '}' && !--count)
854 if (*strend == '\\' && strend[1] && strend[1] == '\\') {
859 res = substring_conf(p, str + 1, strend - str - 1, 0);
866 while (*strend && !apr_isspace(*strend))
869 res = substring_conf(p, str, strend - str, 0);
872 while (apr_isspace(*strend))
878 AP_DECLARE(int) ap_cfg_closefile(ap_configfile_t *cfp)
881 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00551)
882 "Done with config file %s", cfp->name);
884 return (cfp->close == NULL) ? 0 : cfp->close(cfp->param);
887 /* we can't use apr_file_* directly because of linking issues on Windows */
888 static apr_status_t cfg_close(void *param)
890 return apr_file_close(param);
893 static apr_status_t cfg_getch(char *ch, void *param)
895 return apr_file_getc(ch, param);
898 static apr_status_t cfg_getstr(void *buf, apr_size_t bufsiz, void *param)
900 return apr_file_gets(buf, bufsiz, param);
903 /* Open a ap_configfile_t as FILE, return open ap_configfile_t struct pointer */
904 AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg,
905 apr_pool_t *p, const char *name)
907 ap_configfile_t *new_cfg;
908 apr_file_t *file = NULL;
916 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00552)
917 "Internal error: pcfg_openfile() called with NULL filename");
921 status = apr_file_open(&file, name, APR_READ | APR_BUFFERED,
924 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00553)
925 "Opening config file %s (%s)",
926 name, (status != APR_SUCCESS) ?
927 apr_strerror(status, buf, sizeof(buf)) : "successful");
929 if (status != APR_SUCCESS)
932 status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file);
933 if (status != APR_SUCCESS)
936 if (finfo.filetype != APR_REG &&
937 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
938 ap_cstr_casecmp(apr_filepath_name_get(name), "nul") != 0) {
940 strcmp(name, "/dev/null") != 0) {
941 #endif /* WIN32 || OS2 */
942 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00554)
943 "Access to file %s denied by server: not a regular file",
945 apr_file_close(file);
950 /* Some twisted character [no pun intended] at MS decided that a
951 * zero width joiner as the lead wide character would be ideal for
952 * describing Unicode text files. This was further convoluted to
953 * another MSism that the same character mapped into utf-8, EF BB BF
954 * would signify utf-8 text files.
956 * Since MS configuration files are all protecting utf-8 encoded
957 * Unicode path, file and resource names, we already have the correct
958 * WinNT encoding. But at least eat the stupid three bytes up front.
961 unsigned char buf[4];
963 status = apr_file_read(file, buf, &len);
964 if ((status != APR_SUCCESS) || (len < 3)
965 || memcmp(buf, "\xEF\xBB\xBF", 3) != 0) {
967 apr_file_seek(file, APR_SET, &zero);
972 new_cfg = apr_palloc(p, sizeof(*new_cfg));
973 new_cfg->param = file;
974 new_cfg->name = apr_pstrdup(p, name);
975 new_cfg->getch = cfg_getch;
976 new_cfg->getstr = cfg_getstr;
977 new_cfg->close = cfg_close;
978 new_cfg->line_number = 0;
984 /* Allocate a ap_configfile_t handle with user defined functions and params */
985 AP_DECLARE(ap_configfile_t *) ap_pcfg_open_custom(
986 apr_pool_t *p, const char *descr, void *param,
987 apr_status_t (*getc_func) (char *ch, void *param),
988 apr_status_t (*gets_func) (void *buf, apr_size_t bufsize, void *param),
989 apr_status_t (*close_func) (void *param))
991 ap_configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg));
992 new_cfg->param = param;
993 new_cfg->name = descr;
994 new_cfg->getch = getc_func;
995 new_cfg->getstr = gets_func;
996 new_cfg->close = close_func;
997 new_cfg->line_number = 0;
1001 /* Read one character from a configfile_t */
1002 AP_DECLARE(apr_status_t) ap_cfg_getc(char *ch, ap_configfile_t *cfp)
1004 apr_status_t rc = cfp->getch(ch, cfp->param);
1005 if (rc == APR_SUCCESS && *ch == LF)
1010 AP_DECLARE(const char *) ap_pcfg_strerror(apr_pool_t *p, ap_configfile_t *cfp,
1013 if (rc == APR_SUCCESS)
1016 if (rc == APR_ENOSPC)
1017 return apr_psprintf(p, "Error reading %s at line %d: Line too long",
1018 cfp->name, cfp->line_number);
1020 return apr_psprintf(p, "Error reading %s at line %d: %pm",
1021 cfp->name, cfp->line_number, &rc);
1024 /* Read one line from open ap_configfile_t, strip LF, increase line number */
1025 /* If custom handler does not define a getstr() function, read char by char */
1026 static apr_status_t ap_cfg_getline_core(char *buf, apr_size_t bufsize,
1027 apr_size_t offset, ap_configfile_t *cfp)
1030 /* If a "get string" function is defined, use it */
1031 if (cfp->getstr != NULL) {
1033 char *cbuf = buf + offset;
1034 apr_size_t cbufsize = bufsize - offset;
1038 rc = cfp->getstr(cbuf, cbufsize, cfp->param);
1039 if (rc == APR_EOF) {
1040 if (cbuf != buf + offset) {
1048 if (rc != APR_SUCCESS) {
1053 * check for line continuation,
1054 * i.e. match [^\\]\\[\r]\n only
1058 if (cp > buf && cp[-1] == LF) {
1060 if (cp > buf && cp[-1] == CR)
1062 if (cp > buf && cp[-1] == '\\') {
1065 * line continuation requested -
1066 * then remove backslash and continue
1068 cbufsize -= (cp-cbuf);
1073 else if (cp - buf >= bufsize - 1) {
1079 /* No "get string" function defined; read character by character */
1080 apr_size_t i = offset;
1083 /* too small, assume caller is crazy */
1090 rc = cfp->getch(&c, cfp->param);
1091 if (rc == APR_EOF) {
1097 if (rc != APR_SUCCESS)
1101 /* check for line continuation */
1102 if (i > 0 && buf[i-1] == '\\') {
1112 if (i >= bufsize - 1) {
1121 static int cfg_trim_line(char *buf)
1125 * Leading and trailing white space is eliminated completely
1128 while (apr_isspace(*start))
1130 /* blast trailing whitespace */
1131 end = &start[strlen(start)];
1132 while (--end >= start && apr_isspace(*end))
1134 /* Zap leading whitespace by shifting */
1136 memmove(buf, start, end - start + 2);
1137 #ifdef DEBUG_CFG_LINES
1138 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, APLOGNO(00555) "Read config: '%s'", buf);
1140 return end - start + 1;
1143 /* Read one line from open ap_configfile_t, strip LF, increase line number */
1144 /* If custom handler does not define a getstr() function, read char by char */
1145 AP_DECLARE(apr_status_t) ap_cfg_getline(char *buf, apr_size_t bufsize,
1146 ap_configfile_t *cfp)
1148 apr_status_t rc = ap_cfg_getline_core(buf, bufsize, 0, cfp);
1149 if (rc == APR_SUCCESS)
1154 AP_DECLARE(apr_status_t) ap_varbuf_cfg_getline(struct ap_varbuf *vb,
1155 ap_configfile_t *cfp,
1163 if (vb->strlen == AP_VARBUF_UNKNOWN)
1164 vb->strlen = strlen(vb->buf);
1165 if (vb->avail - vb->strlen < 3) {
1166 new_len = vb->avail * 2;
1167 if (new_len > max_len)
1169 else if (new_len < 3)
1171 ap_varbuf_grow(vb, new_len);
1175 rc = ap_cfg_getline_core(vb->buf, vb->avail, vb->strlen, cfp);
1176 if (rc == APR_ENOSPC || rc == APR_SUCCESS)
1177 vb->strlen += strlen(vb->buf + vb->strlen);
1178 if (rc != APR_ENOSPC)
1180 if (vb->avail >= max_len)
1182 new_len = vb->avail * 2;
1183 if (new_len > max_len)
1185 ap_varbuf_grow(vb, new_len);
1188 if (vb->strlen > max_len)
1190 if (rc == APR_SUCCESS)
1191 vb->strlen = cfg_trim_line(vb->buf);
1195 /* Size an HTTP header field list item, as separated by a comma.
1196 * The return value is a pointer to the beginning of the non-empty list item
1197 * within the original string (or NULL if there is none) and the address
1198 * of field is shifted to the next non-comma, non-whitespace character.
1199 * len is the length of the item excluding any beginning whitespace.
1201 AP_DECLARE(const char *) ap_size_list_item(const char **field, int *len)
1203 const unsigned char *ptr = (const unsigned char *)*field;
1204 const unsigned char *token;
1205 int in_qpair, in_qstr, in_com;
1207 /* Find first non-comma, non-whitespace byte */
1209 while (*ptr == ',' || apr_isspace(*ptr))
1214 /* Find the end of this item, skipping over dead bits */
1216 for (in_qpair = in_qstr = in_com = 0;
1217 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1225 case '\\': in_qpair = 1; /* quoted-pair */
1227 case '"' : if (!in_com) /* quoted string delim */
1230 case '(' : if (!in_qstr) /* comment (may nest) */
1233 case ')' : if (in_com) /* end comment */
1241 if ((*len = (ptr - token)) == 0) {
1242 *field = (const char *)ptr;
1246 /* Advance field pointer to the next non-comma, non-white byte */
1248 while (*ptr == ',' || apr_isspace(*ptr))
1251 *field = (const char *)ptr;
1252 return (const char *)token;
1255 /* Retrieve an HTTP header field list item, as separated by a comma,
1256 * while stripping insignificant whitespace and lowercasing anything not in
1257 * a quoted string or comment. The return value is a new string containing
1258 * the converted list item (or NULL if none) and the address pointed to by
1259 * field is shifted to the next non-comma, non-whitespace.
1261 AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field)
1263 const char *tok_start;
1264 const unsigned char *ptr;
1267 int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
1269 /* Find the beginning and maximum length of the list item so that
1270 * we can allocate a buffer for the new string and reset the field.
1272 if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
1275 token = apr_palloc(p, tok_len + 1);
1277 /* Scan the token again, but this time copy only the good bytes.
1278 * We skip extra whitespace and any whitespace around a '=', '/',
1279 * or ';' and lowercase normal characters not within a comment,
1280 * quoted-string or quoted-pair.
1282 for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
1283 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1292 case '\\': in_qpair = 1;
1298 case '"' : if (!in_com)
1305 case '(' : if (!in_qstr)
1312 case ')' : if (in_com)
1318 case '\t': if (addspace)
1320 if (in_com || in_qstr)
1327 case ';' : if (!(in_com || in_qstr))
1331 default : if (addspace == 1)
1333 *pos++ = (in_com || in_qstr) ? *ptr
1334 : apr_tolower(*ptr);
1345 typedef enum ap_etag_e {
1351 /* Find an item in canonical form (lowercase, no extra spaces) within
1352 * an HTTP field value list. Returns 1 if found, 0 if not found.
1353 * This would be much more efficient if we stored header fields as
1354 * an array of list items as they are received instead of a plain string.
1356 static int find_list_item(apr_pool_t *p, const char *line,
1357 const char *tok, ap_etag_e type)
1359 const unsigned char *pos;
1360 const unsigned char *ptr = (const unsigned char *)line;
1361 int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
1363 if (!line || !tok) {
1366 if (type == AP_ETAG_STRONG && *tok != '\"') {
1369 if (type == AP_ETAG_WEAK) {
1370 if (*tok == 'W' && (*(tok+1)) == '/' && (*(tok+2)) == '\"') {
1373 else if (*tok != '\"') {
1378 do { /* loop for each item in line's list */
1380 /* Find first non-comma, non-whitespace byte */
1381 while (*ptr == ',' || apr_isspace(*ptr)) {
1385 /* Account for strong or weak Etags, depending on our search */
1386 if (type == AP_ETAG_STRONG && *ptr != '\"') {
1389 if (type == AP_ETAG_WEAK) {
1390 if (*ptr == 'W' && (*(ptr+1)) == '/' && (*(ptr+2)) == '\"') {
1393 else if (*ptr != '\"') {
1399 good = 1; /* until proven otherwise for this item */
1401 break; /* no items left and nothing good found */
1403 /* We skip extra whitespace and any whitespace around a '=', '/',
1404 * or ';' and lowercase normal characters not within a comment,
1405 * quoted-string or quoted-pair.
1407 for (pos = (const unsigned char *)tok;
1408 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1414 good = (*pos++ == *ptr);
1418 case '\\': in_qpair = 1;
1420 good = good && (*pos++ == ' ');
1421 good = good && (*pos++ == *ptr);
1424 case '"' : if (!in_com)
1427 good = good && (*pos++ == ' ');
1428 good = good && (*pos++ == *ptr);
1431 case '(' : if (!in_qstr)
1434 good = good && (*pos++ == ' ');
1435 good = good && (*pos++ == *ptr);
1438 case ')' : if (in_com)
1440 good = good && (*pos++ == *ptr);
1444 case '\t': if (addspace || !good)
1446 if (in_com || in_qstr)
1447 good = (*pos++ == *ptr);
1453 case ';' : if (!(in_com || in_qstr))
1455 good = good && (*pos++ == *ptr);
1457 default : if (!good)
1460 good = (*pos++ == ' ');
1461 if (in_com || in_qstr)
1462 good = good && (*pos++ == *ptr);
1465 && (apr_tolower(*pos++) == apr_tolower(*ptr));
1472 good = 0; /* not good if only a prefix was matched */
1474 } while (*ptr && !good);
1479 /* Find an item in canonical form (lowercase, no extra spaces) within
1480 * an HTTP field value list. Returns 1 if found, 0 if not found.
1481 * This would be much more efficient if we stored header fields as
1482 * an array of list items as they are received instead of a plain string.
1484 AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line,
1487 return find_list_item(p, line, tok, AP_ETAG_NONE);
1490 /* Find a strong Etag in canonical form (lowercase, no extra spaces) within
1491 * an HTTP field value list. Returns 1 if found, 0 if not found.
1493 AP_DECLARE(int) ap_find_etag_strong(apr_pool_t *p, const char *line,
1496 return find_list_item(p, line, tok, AP_ETAG_STRONG);
1499 /* Find a weak ETag in canonical form (lowercase, no extra spaces) within
1500 * an HTTP field value list. Returns 1 if found, 0 if not found.
1502 AP_DECLARE(int) ap_find_etag_weak(apr_pool_t *p, const char *line,
1505 return find_list_item(p, line, tok, AP_ETAG_WEAK);
1508 /* Grab a list of tokens of the format 1#token (from RFC7230) */
1509 AP_DECLARE(const char *) ap_parse_token_list_strict(apr_pool_t *p,
1511 apr_array_header_t **tokens,
1514 int in_leading_space = 1;
1515 int in_trailing_space = 0;
1517 const char *tok_begin;
1524 tok_begin = cur = str_in;
1526 while (!string_end) {
1527 const unsigned char c = (unsigned char)*cur;
1529 if (!TEST_CHAR(c, T_HTTP_TOKEN_STOP)) {
1530 /* Non-separator character; we are finished with leading
1531 * whitespace. We must never have encountered any trailing
1532 * whitespace before the delimiter (comma) */
1533 in_leading_space = 0;
1534 if (in_trailing_space) {
1535 return "Encountered illegal whitespace in token";
1538 else if (c == ' ' || c == '\t') {
1539 /* "Linear whitespace" only includes ASCII CRLF, space, and tab;
1540 * we can't get a CRLF since headers are split on them already,
1541 * so only look for a space or a tab */
1542 if (in_leading_space) {
1543 /* We're still in leading whitespace */
1547 /* We must be in trailing whitespace */
1548 ++in_trailing_space;
1551 else if (c == ',' || c == '\0') {
1552 if (!in_leading_space) {
1553 /* If we're out of the leading space, we know we've read some
1554 * characters of a token */
1555 if (*tokens == NULL) {
1556 *tokens = apr_array_make(p, 4, sizeof(char *));
1558 APR_ARRAY_PUSH(*tokens, char *) =
1559 apr_pstrmemdup((*tokens)->pool, tok_begin,
1560 (cur - tok_begin) - in_trailing_space);
1562 /* We're allowed to have null elements, just don't add them to the
1565 tok_begin = cur + 1;
1566 in_leading_space = 1;
1567 in_trailing_space = 0;
1568 string_end = (c == '\0');
1571 /* Encountered illegal separator char */
1573 /* Skip to the next separator */
1575 temp = ap_strchr_c(cur, ',');
1577 temp = ap_strchr_c(cur, '\0');
1580 /* Act like we haven't seen a token so we reset */
1582 in_leading_space = 1;
1583 in_trailing_space = 0;
1586 return apr_psprintf(p, "Encountered illegal separator "
1587 "'\\x%.2x'", (unsigned int)c);
1597 /* Scan a string for HTTP VCHAR/obs-text characters including HT and SP
1598 * (as used in header values, for example, in RFC 7230 section 3.2)
1599 * returning the pointer to the first non-HT ASCII ctrl character.
1601 AP_DECLARE(const char *) ap_scan_http_field_content(const char *ptr)
1603 for ( ; !TEST_CHAR(*ptr, T_HTTP_CTRLS); ++ptr) ;
1608 /* Scan a string for HTTP token characters, returning the pointer to
1609 * the first non-token character.
1611 AP_DECLARE(const char *) ap_scan_http_token(const char *ptr)
1613 for ( ; !TEST_CHAR(*ptr, T_HTTP_TOKEN_STOP); ++ptr) ;
1618 /* Scan a string for visible ASCII (0x21-0x7E) or obstext (0x80+)
1619 * and return a pointer to the first ctrl/space character encountered.
1621 AP_DECLARE(const char *) ap_scan_vchar_obstext(const char *ptr)
1623 for ( ; TEST_CHAR(*ptr, T_VCHAR_OBSTEXT); ++ptr) ;
1628 /* Retrieve a token, spacing over it and returning a pointer to
1629 * the first non-white byte afterwards. Note that these tokens
1630 * are delimited by semis and commas; and can also be delimited
1631 * by whitespace at the caller's option.
1634 AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line,
1637 const char *ptr = *accept_line;
1638 const char *tok_start;
1641 /* Find first non-white byte */
1643 while (apr_isspace(*ptr))
1648 /* find token end, skipping over quoted strings.
1649 * (comments are already gone).
1652 while (*ptr && (accept_white || !apr_isspace(*ptr))
1653 && *ptr != ';' && *ptr != ',') {
1660 token = apr_pstrmemdup(p, tok_start, ptr - tok_start);
1662 /* Advance accept_line pointer to the next non-white byte */
1664 while (apr_isspace(*ptr))
1672 /* find http tokens, see the definition of token from RFC2068 */
1673 AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
1675 const unsigned char *start_token;
1676 const unsigned char *s;
1681 s = (const unsigned char *)line;
1683 /* find start of token, skip all stop characters */
1684 while (*s && TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1691 /* find end of the token */
1692 while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1695 if (!ap_cstr_casecmpn((const char *)start_token, (const char *)tok,
1706 AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line,
1709 int llen, tlen, lidx;
1714 llen = strlen(line);
1719 (lidx > 0 && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1722 return (ap_cstr_casecmpn(&line[lidx], tok, tlen) == 0);
1725 AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1729 const unsigned char *s;
1731 cmd = apr_palloc(p, 2 * strlen(str) + 1); /* Be safe */
1732 d = (unsigned char *)cmd;
1733 s = (const unsigned char *)str;
1736 #if defined(OS2) || defined(WIN32)
1738 * Newlines to Win32/OS2 CreateProcess() are ill advised.
1739 * Convert them to spaces since they are effectively white
1740 * space to most applications
1742 if (*s == '\r' || *s == '\n') {
1748 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1758 static char x2c(const char *what)
1762 #if !APR_CHARSET_EBCDIC
1763 digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
1766 digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
1768 #else /*APR_CHARSET_EBCDIC*/
1775 digit = apr_xlate_conv_byte(ap_hdrs_from_ascii,
1776 0xFF & strtol(xstr, NULL, 16));
1777 #endif /*APR_CHARSET_EBCDIC*/
1782 * Unescapes a URL, leaving reserved characters intact.
1783 * Returns 0 on success, non-zero on error
1785 * bad % escape returns HTTP_BAD_REQUEST
1787 * decoding %00 or a forbidden character returns HTTP_NOT_FOUND
1790 static int unescape_url(char *url, const char *forbid, const char *reserved)
1792 int badesc, badpath;
1797 /* Initial scan for first '%'. Don't bother writing values before
1799 y = strchr(url, '%');
1803 for (x = y; *y; ++x, ++y) {
1808 if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1814 decoded = x2c(y + 1);
1815 if ((decoded == '\0')
1816 || (forbid && ap_strchr_c(forbid, decoded))) {
1821 else if (reserved && ap_strchr_c(reserved, decoded)) {
1835 return HTTP_BAD_REQUEST;
1838 return HTTP_NOT_FOUND;
1844 AP_DECLARE(int) ap_unescape_url(char *url)
1847 return unescape_url(url, SLASHES, NULL);
1849 AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes)
1851 /* AllowEncodedSlashes (corrected) */
1852 if (decode_slashes) {
1853 /* no chars reserved */
1854 return unescape_url(url, NULL, NULL);
1856 /* reserve (do not decode) encoded slashes */
1857 return unescape_url(url, NULL, SLASHES);
1861 /* IFDEF these out until they've been thought through.
1862 * Just a germ of an API extension for now
1864 AP_DECLARE(int) ap_unescape_url_proxy(char *url)
1866 /* leave RFC1738 reserved characters intact, * so proxied URLs
1867 * don't get mangled. Where does that leave encoded '&' ?
1869 return unescape_url(url, NULL, "/;?");
1871 AP_DECLARE(int) ap_unescape_url_reserved(char *url, const char *reserved)
1873 return unescape_url(url, NULL, reserved);
1877 AP_DECLARE(int) ap_unescape_urlencoded(char *query)
1881 /* replace plus with a space */
1883 for (slider = query; *slider; slider++) {
1884 if (*slider == '+') {
1890 /* unescape everything else */
1891 return unescape_url(query, NULL, NULL);
1894 AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname,
1895 apr_port_t port, const request_rec *r)
1897 if (ap_is_default_port(port, r)) {
1898 return apr_pstrdup(p, hostname);
1901 return apr_psprintf(p, "%s:%u", hostname, port);
1905 AP_DECLARE(int) ap_unescape_all(char *url)
1907 return unescape_url(url, NULL, NULL);
1910 /* c2x takes an unsigned, and expects the caller has guaranteed that
1911 * 0 <= what < 256... which usually means that you have to cast to
1912 * unsigned char first, because (unsigned)(char)(x) first goes through
1913 * signed extension to an int before the unsigned cast.
1915 * The reason for this assumption is to assist gcc code generation --
1916 * the unsigned char -> unsigned extension is already done earlier in
1917 * both uses of this code, so there's no need to waste time doing it
1920 static const char c2x_table[] = "0123456789abcdef";
1922 static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
1923 unsigned char *where)
1925 #if APR_CHARSET_EBCDIC
1926 what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
1927 #endif /*APR_CHARSET_EBCDIC*/
1929 *where++ = c2x_table[what >> 4];
1930 *where++ = c2x_table[what & 0xf];
1935 * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
1936 * routine is (should be) OS independent.
1938 * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
1939 * cases if a ':' occurs before the first '/' in the URL, the URL should be
1940 * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
1941 * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
1942 * efficiency reasons, we don't use escape_path_segment(), which is provided for
1943 * reference. Again, RFC 1808 is where this stuff is defined.
1945 * If partial is set, os_escape_path() assumes that the path will be appended to
1946 * something with a '/' in it (and thus does not prefix "./").
1949 AP_DECLARE(char *) ap_escape_path_segment_buffer(char *copy, const char *segment)
1951 const unsigned char *s = (const unsigned char *)segment;
1952 unsigned char *d = (unsigned char *)copy;
1956 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
1968 AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
1970 return ap_escape_path_segment_buffer(apr_palloc(p, 3 * strlen(segment) + 1), segment);
1973 AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
1975 /* Allocate +3 for potential "./" and trailing NULL.
1976 * Allocate another +1 to allow the caller to add a trailing '/' (see
1977 * comment in 'ap_sub_req_lookup_dirent')
1979 char *copy = apr_palloc(p, 3 * strlen(path) + 3 + 1);
1980 const unsigned char *s = (const unsigned char *)path;
1981 unsigned char *d = (unsigned char *)copy;
1985 const char *colon = ap_strchr_c(path, ':');
1986 const char *slash = ap_strchr_c(path, '/');
1988 if (colon && (!slash || colon < slash)) {
1994 if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
2006 AP_DECLARE(char *) ap_escape_urlencoded_buffer(char *copy, const char *buffer)
2008 const unsigned char *s = (const unsigned char *)buffer;
2009 unsigned char *d = (unsigned char *)copy;
2013 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
2016 else if (c == ' ') {
2028 AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
2030 return ap_escape_urlencoded_buffer(apr_palloc(p, 3 * strlen(buffer) + 1), buffer);
2033 /* ap_escape_uri is now a macro for os_escape_path */
2035 AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
2040 /* first, count the number of extra characters */
2041 for (i = 0, j = 0; s[i] != '\0'; i++)
2042 if (s[i] == '<' || s[i] == '>')
2044 else if (s[i] == '&')
2046 else if (s[i] == '"')
2048 else if (toasc && !apr_isascii(s[i]))
2052 return apr_pstrmemdup(p, s, i);
2054 x = apr_palloc(p, i + j + 1);
2055 for (i = 0, j = 0; s[i] != '\0'; i++, j++)
2057 memcpy(&x[j], "<", 4);
2060 else if (s[i] == '>') {
2061 memcpy(&x[j], ">", 4);
2064 else if (s[i] == '&') {
2065 memcpy(&x[j], "&", 5);
2068 else if (s[i] == '"') {
2069 memcpy(&x[j], """, 6);
2072 else if (toasc && !apr_isascii(s[i])) {
2073 char *esc = apr_psprintf(p, "&#%3.3d;", (unsigned char)s[i]);
2074 memcpy(&x[j], esc, 6);
2083 AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str)
2087 const unsigned char *s;
2088 apr_size_t length, escapes = 0;
2094 /* Compute how many characters need to be escaped */
2095 s = (const unsigned char *)str;
2097 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2102 /* Compute the length of the input string, including NULL */
2103 length = s - (const unsigned char *)str + 1;
2105 /* Fast path: nothing to escape */
2107 return apr_pmemdup(p, str, length);
2110 /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */
2111 ret = apr_palloc(p, length + 3 * escapes);
2112 d = (unsigned char *)ret;
2113 s = (const unsigned char *)str;
2115 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2151 AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
2154 unsigned char *d, *ep;
2155 const unsigned char *s;
2157 if (!source || !buflen) { /* be safe */
2161 d = (unsigned char *)dest;
2162 s = (const unsigned char *)source;
2163 ep = d + buflen - 1;
2165 for (; d < ep && *s; ++s) {
2167 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2193 case '"': /* no need for this in error log */
2198 ep = --d; /* break the for loop as well */
2211 return (d - (unsigned char *)dest);
2214 AP_DECLARE(void) ap_bin2hex(const void *src, apr_size_t srclen, char *dest)
2216 const unsigned char *in = src;
2219 for (i = 0; i < srclen; i++) {
2220 *dest++ = c2x_table[in[i] >> 4];
2221 *dest++ = c2x_table[in[i] & 0xf];
2226 AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
2230 if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS)
2231 return 0; /* in error condition, just return no */
2233 return (finfo.filetype == APR_DIR);
2236 AP_DECLARE(int) ap_is_rdirectory(apr_pool_t *p, const char *path)
2240 if (apr_stat(&finfo, path, APR_FINFO_LINK | APR_FINFO_TYPE, p) != APR_SUCCESS)
2241 return 0; /* in error condition, just return no */
2243 return (finfo.filetype == APR_DIR);
2246 AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
2249 apr_size_t len1, len2;
2252 len1 = strlen(src1);
2253 len2 = strlen(src2);
2254 /* allocate +3 for '/' delimiter, trailing NULL and overallocate
2255 * one extra byte to allow the caller to add a trailing '/'
2257 path = (char *)apr_palloc(a, len1 + len2 + 3);
2260 memcpy(path + 1, src2, len2 + 1);
2264 memcpy(path, src1, len1);
2266 if (next[-1] != '/') {
2269 memcpy(next, src2, len2 + 1);
2275 * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
2277 AP_DECLARE(int) ap_is_url(const char *u)
2281 for (x = 0; u[x] != ':'; x++) {
2283 ((!apr_isalnum(u[x])) &&
2284 (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
2289 return (x ? 1 : 0); /* If the first character is ':', it's broken, too */
2292 AP_DECLARE(int) ap_ind(const char *s, char c)
2294 const char *p = ap_strchr_c(s, c);
2301 AP_DECLARE(int) ap_rind(const char *s, char c)
2303 const char *p = ap_strrchr_c(s, c);
2310 AP_DECLARE(void) ap_str_tolower(char *str)
2313 *str = apr_tolower(*str);
2318 AP_DECLARE(void) ap_str_toupper(char *str)
2321 *str = apr_toupper(*str);
2327 * We must return a FQDN
2329 char *ap_get_local_host(apr_pool_t *a)
2331 #ifndef MAXHOSTNAMELEN
2332 #define MAXHOSTNAMELEN 256
2334 char str[MAXHOSTNAMELEN + 1];
2335 char *server_hostname = NULL;
2336 apr_sockaddr_t *sockaddr;
2339 if (apr_gethostname(str, sizeof(str) - 1, a) != APR_SUCCESS) {
2340 ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00556)
2341 "%s: apr_gethostname() failed to determine ServerName",
2344 str[sizeof(str) - 1] = '\0';
2345 if (apr_sockaddr_info_get(&sockaddr, str, APR_UNSPEC, 0, 0, a) == APR_SUCCESS) {
2346 if ( (apr_getnameinfo(&hostname, sockaddr, 0) == APR_SUCCESS) &&
2347 (ap_strchr_c(hostname, '.')) ) {
2348 server_hostname = apr_pstrdup(a, hostname);
2349 return server_hostname;
2350 } else if (ap_strchr_c(str, '.')) {
2351 server_hostname = apr_pstrdup(a, str);
2353 apr_sockaddr_ip_get(&hostname, sockaddr);
2354 server_hostname = apr_pstrdup(a, hostname);
2357 ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00557)
2358 "%s: apr_sockaddr_info_get() failed for %s",
2359 ap_server_argv0, str);
2363 if (!server_hostname)
2364 server_hostname = apr_pstrdup(a, "127.0.0.1");
2366 ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, a, APLOGNO(00558)
2367 "%s: Could not reliably determine the server's fully qualified "
2368 "domain name, using %s. Set the 'ServerName' directive globally "
2369 "to suppress this message",
2370 ap_server_argv0, server_hostname);
2372 return server_hostname;
2375 /* simple 'pool' alloc()ing glue to apr_base64.c
2377 AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
2382 decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded));
2383 l = apr_base64_decode(decoded, bufcoded);
2384 decoded[l] = '\0'; /* make binary sequence into string */
2389 AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
2392 int l = strlen(string);
2394 encoded = (char *) apr_palloc(p, 1 + apr_base64_encode_len(l));
2395 l = apr_base64_encode(encoded, string, l);
2396 encoded[l] = '\0'; /* make binary sequence into string */
2401 /* we want to downcase the type/subtype for comparison purposes
2402 * but nothing else because ;parameter=foo values are case sensitive.
2403 * XXX: in truth we want to downcase parameter names... but really,
2404 * apache has never handled parameters and such correctly. You
2405 * also need to compress spaces and such to be able to compare
2408 AP_DECLARE(void) ap_content_type_tolower(char *str)
2412 semi = strchr(str, ';');
2417 ap_str_tolower(str);
2425 * Given a string, replace any bare " with \" .
2427 AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
2430 const char *inchr = instring;
2431 char *outchr, *outstring;
2434 * Look through the input string, jogging the length of the output
2435 * string up by an extra byte each time we find an unescaped ".
2437 while (*inchr != '\0') {
2439 if (*inchr == '"') {
2443 * If we find a slosh, and it's not the last byte in the string,
2444 * it's escaping something - advance past both bytes.
2446 if ((*inchr == '\\') && (inchr[1] != '\0')) {
2452 outstring = apr_palloc(p, newlen + 1);
2456 * Now copy the input string to the output string, inserting a slosh
2457 * in front of every " that doesn't already have one.
2459 while (*inchr != '\0') {
2460 if ((*inchr == '\\') && (inchr[1] != '\0')) {
2461 *outchr++ = *inchr++;
2462 *outchr++ = *inchr++;
2464 if (*inchr == '"') {
2467 if (*inchr != '\0') {
2468 *outchr++ = *inchr++;
2476 * Given a string, append the PID deliminated by delim.
2477 * Usually used to create a pid-appended filepath name
2478 * (eg: /a/b/foo -> /a/b/foo.6726). A function, and not
2479 * a macro, to avoid unistd.h dependency
2481 AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string,
2484 return apr_psprintf(p, "%s%s%" APR_PID_T_FMT, string,
2490 * Parse a given timeout parameter string into an apr_interval_time_t value.
2491 * The unit of the time interval is given as postfix string to the numeric
2492 * string. Currently the following units are understood:
2499 * If no unit is contained in the given timeout parameter the default_time_unit
2500 * will be used instead.
2501 * @param timeout_parameter The string containing the timeout parameter.
2502 * @param timeout The timeout value to be returned.
2503 * @param default_time_unit The default time unit to use if none is specified
2504 * in timeout_parameter.
2505 * @return Status value indicating whether the parsing was successful or not.
2507 AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
2508 const char *timeout_parameter,
2509 apr_interval_time_t *timeout,
2510 const char *default_time_unit)
2513 const char *time_str;
2516 tout = apr_strtoi64(timeout_parameter, &endp, 10);
2520 if (!endp || !*endp) {
2521 time_str = default_time_unit;
2527 switch (*time_str) {
2528 /* Time is in seconds */
2530 *timeout = (apr_interval_time_t) apr_time_from_sec(tout);
2533 /* Time is in hours */
2534 *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 3600);
2537 switch (*(++time_str)) {
2538 /* Time is in milliseconds */
2540 *timeout = (apr_interval_time_t) tout * 1000;
2542 /* Time is in minutes */
2544 *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 60);
2547 return APR_EGENERAL;
2551 return APR_EGENERAL;
2557 * Determine if a request has a request body or not.
2559 * @param r the request_rec of the request
2560 * @return truth value
2562 AP_DECLARE(int) ap_request_has_body(request_rec *r)
2569 has_body = (!r->header_only
2571 || apr_table_get(r->headers_in, "Transfer-Encoding")
2572 || ( (cls = apr_table_get(r->headers_in, "Content-Length"))
2573 && (apr_strtoff(&cl, cls, &estr, 10) == APR_SUCCESS)
2582 * Check whether a request is tainted by exposure to something
2583 * potentially untrusted.
2586 AP_DECLARE(int) ap_request_tainted(request_rec *r, int flags)
2588 /** Potential future: a hook or callback here could serve modules
2589 * like mod_security and ironbee with more complex needs.
2591 return r && ((r->taint&flags)
2592 || ap_request_tainted(r->main, flags)
2593 || ap_request_tainted(r->prev, flags));
2596 AP_DECLARE_NONSTD(apr_status_t) ap_pool_cleanup_set_null(void *data_)
2598 void **ptr = (void **)data_;
2603 AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
2605 for ( ; *src; src++, dest++)
2607 if (!apr_isprint(*src))
2609 else if (!apr_isalnum(*src))
2619 AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
2622 char *new = apr_palloc(p, strlen(src)+1);
2626 return ap_str2_alnum(src, new);
2630 * Read the body and parse any form found, which must be of the
2631 * type application/x-www-form-urlencoded.
2633 * Name/value pairs are returned in an array, with the names as
2634 * strings with a maximum length of HUGE_STRING_LEN, and the
2635 * values as bucket brigades. This allows values to be arbitrarily
2638 * All url-encoding is removed from both the names and the values
2639 * on the fly. The names are interpreted as strings, while the
2640 * values are interpreted as blocks of binary data, that may
2641 * contain the 0 character.
2643 * In order to ensure that resource limits are not exceeded, a
2644 * maximum size must be provided. If the sum of the lengths of
2645 * the names and the values exceed this size, this function
2646 * will return HTTP_REQUEST_ENTITY_TOO_LARGE.
2648 * An optional number of parameters can be provided, if the number
2649 * of parameters provided exceeds this amount, this function will
2650 * return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
2651 * no limit is imposed, and the number of parameters is in turn
2652 * constrained by the size parameter above.
2654 * This function honours any kept_body configuration, and the
2655 * original raw request body will be saved to the kept_body brigade
2656 * if so configured, just as ap_discard_request_body does.
2658 * NOTE: File upload is not yet supported, but can be without change
2659 * to the function call.
2662 /* form parsing stuff */
2673 AP_DECLARE(int) ap_parse_form_data(request_rec *r, ap_filter_t *f,
2674 apr_array_header_t **ptr,
2675 apr_size_t num, apr_size_t usize)
2677 apr_bucket_brigade *bb = NULL;
2679 char buffer[HUGE_STRING_LEN + 1];
2681 apr_size_t offset = 0;
2683 ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
2684 ap_form_pair_t *pair = NULL;
2685 apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
2692 /* sanity check - we only support forms for now */
2693 ct = apr_table_get(r->headers_in, "Content-Type");
2694 if (!ct || ap_cstr_casecmpn("application/x-www-form-urlencoded", ct, 33)) {
2695 return ap_discard_request_body(r);
2698 if (usize > APR_SIZE_MAX >> 1)
2699 size = APR_SIZE_MAX >> 1;
2704 f = r->input_filters;
2707 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2709 apr_bucket *bucket = NULL, *last = NULL;
2711 int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
2712 APR_BLOCK_READ, HUGE_STRING_LEN);
2713 if (rv != APR_SUCCESS) {
2714 apr_brigade_destroy(bb);
2715 return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
2718 for (bucket = APR_BRIGADE_FIRST(bb);
2719 bucket != APR_BRIGADE_SENTINEL(bb);
2720 last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
2722 apr_size_t len, slide;
2725 apr_bucket_delete(last);
2727 if (APR_BUCKET_IS_EOS(bucket)) {
2731 if (bucket->length == 0) {
2735 rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
2736 if (rv != APR_SUCCESS) {
2737 apr_brigade_destroy(bb);
2738 return HTTP_BAD_REQUEST;
2742 while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
2747 else if ('&' == c) {
2751 percent = FORM_PERCENTA;
2754 if (FORM_PERCENTA == percent) {
2758 else if (c >= 'A') {
2761 else if (c >= '0') {
2765 percent = FORM_PERCENTB;
2768 if (FORM_PERCENTB == percent) {
2772 else if (c >= 'A') {
2775 else if (c >= '0') {
2779 percent = FORM_NORMAL;
2784 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2785 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2786 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2794 if (offset < HUGE_STRING_LEN) {
2798 pair = (ap_form_pair_t *) apr_array_push(pairs);
2799 pair->name = apr_pstrdup(r->pool, buffer);
2800 pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2804 buffer[offset++] = c;
2813 if (offset >= HUGE_STRING_LEN) {
2814 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2815 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2816 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2819 buffer[offset++] = c;
2829 apr_brigade_cleanup(bb);
2830 } while (!seen_eos);
2832 if (FORM_ABORT == state || size < 0 || num == 0) {
2833 return HTTP_REQUEST_ENTITY_TOO_LARGE;
2835 else if (FORM_VALUE == state && pair && offset > 0) {
2836 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2837 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2838 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2845 #define VARBUF_SMALL_SIZE 2048
2846 #define VARBUF_MAX_SIZE (APR_SIZE_MAX - 1 - \
2847 APR_ALIGN_DEFAULT(sizeof(struct ap_varbuf_info)))
2849 struct ap_varbuf_info {
2850 struct apr_memnode_t *node;
2851 apr_allocator_t *allocator;
2854 static apr_status_t varbuf_cleanup(void *info_)
2856 struct ap_varbuf_info *info = info_;
2857 info->node->next = NULL;
2858 apr_allocator_free(info->allocator, info->node);
2862 const char nul = '\0';
2863 static char * const varbuf_empty = (char *)&nul;
2865 AP_DECLARE(void) ap_varbuf_init(apr_pool_t *p, struct ap_varbuf *vb,
2866 apr_size_t init_size)
2868 vb->buf = varbuf_empty;
2870 vb->strlen = AP_VARBUF_UNKNOWN;
2874 ap_varbuf_grow(vb, init_size);
2877 AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
2879 apr_memnode_t *new_node = NULL;
2880 apr_allocator_t *allocator;
2881 struct ap_varbuf_info *new_info;
2884 AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN || vb->avail >= vb->strlen);
2886 if (new_len <= vb->avail)
2889 if (new_len < 2 * vb->avail && vb->avail < VARBUF_MAX_SIZE/2) {
2890 /* at least double the size, to avoid repeated reallocations */
2891 new_len = 2 * vb->avail;
2893 else if (new_len > VARBUF_MAX_SIZE) {
2894 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2895 ap_assert(abort_fn != NULL);
2896 abort_fn(APR_ENOMEM);
2900 new_len++; /* add space for trailing \0 */
2901 if (new_len <= VARBUF_SMALL_SIZE) {
2902 new_len = APR_ALIGN_DEFAULT(new_len);
2903 new = apr_palloc(vb->pool, new_len);
2904 if (vb->avail && vb->strlen != 0) {
2905 AP_DEBUG_ASSERT(vb->buf != NULL);
2906 AP_DEBUG_ASSERT(vb->buf != varbuf_empty);
2907 if (new == vb->buf + vb->avail + 1) {
2908 /* We are lucky: the new memory lies directly after our old
2909 * buffer, we can now use both.
2911 vb->avail += new_len;
2915 /* copy up to vb->strlen + 1 bytes */
2916 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2917 vb->avail + 1 : vb->strlen + 1);
2923 vb->avail = new_len - 1;
2928 /* The required block is rather larger. Use allocator directly so that
2929 * the memory can be freed independently from the pool. */
2930 allocator = apr_pool_allocator_get(vb->pool);
2931 if (new_len <= VARBUF_MAX_SIZE)
2932 new_node = apr_allocator_alloc(allocator,
2933 new_len + APR_ALIGN_DEFAULT(sizeof(*new_info)));
2935 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2936 ap_assert(abort_fn != NULL);
2937 abort_fn(APR_ENOMEM);
2940 new_info = (struct ap_varbuf_info *)new_node->first_avail;
2941 new_node->first_avail += APR_ALIGN_DEFAULT(sizeof(*new_info));
2942 new_info->node = new_node;
2943 new_info->allocator = allocator;
2944 new = new_node->first_avail;
2945 AP_DEBUG_ASSERT(new_node->endp - new_node->first_avail >= new_len);
2946 new_len = new_node->endp - new_node->first_avail;
2948 if (vb->avail && vb->strlen != 0)
2949 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2950 vb->avail + 1 : vb->strlen + 1);
2954 apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
2955 apr_pool_cleanup_register(vb->pool, new_info, varbuf_cleanup,
2956 apr_pool_cleanup_null);
2957 vb->info = new_info;
2959 vb->avail = new_len - 1;
2962 AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
2968 ap_varbuf_grow(vb, len);
2969 memcpy(vb->buf, str, len);
2970 vb->buf[len] = '\0';
2974 if (vb->strlen == AP_VARBUF_UNKNOWN)
2975 vb->strlen = strlen(vb->buf);
2976 ap_varbuf_grow(vb, vb->strlen + len);
2977 memcpy(vb->buf + vb->strlen, str, len);
2979 vb->buf[vb->strlen] = '\0';
2982 AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb)
2985 apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
2991 AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *buf,
2992 const char *prepend, apr_size_t prepend_len,
2993 const char *append, apr_size_t append_len,
2994 apr_size_t *new_len)
2997 struct iovec vec[3];
3000 vec[i].iov_base = (void *)prepend;
3001 vec[i].iov_len = prepend_len;
3004 if (buf->avail && buf->strlen) {
3005 if (buf->strlen == AP_VARBUF_UNKNOWN)
3006 buf->strlen = strlen(buf->buf);
3007 vec[i].iov_base = (void *)buf->buf;
3008 vec[i].iov_len = buf->strlen;
3012 vec[i].iov_base = (void *)append;
3013 vec[i].iov_len = append_len;
3017 return apr_pstrcatv(p, vec, i, new_len);
3024 AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb,
3028 ap_regmatch_t pmatch[],
3031 return regsub_core(NULL, NULL, vb, input, source, nmatch, pmatch, maxlen);
3034 static const char * const oom_message = "[crit] Memory allocation failed, "
3035 "aborting process." APR_EOL_STR;
3037 AP_DECLARE(void) ap_abort_on_oom()
3039 int written, count = strlen(oom_message);
3040 const char *buf = oom_message;
3042 written = write(STDERR_FILENO, buf, count);
3043 if (written == count)
3049 } while (written >= 0 || errno == EINTR);
3053 AP_DECLARE(void *) ap_malloc(size_t size)
3055 void *p = malloc(size);
3056 if (p == NULL && size != 0)
3061 AP_DECLARE(void *) ap_calloc(size_t nelem, size_t size)
3063 void *p = calloc(nelem, size);
3064 if (p == NULL && nelem != 0 && size != 0)
3069 AP_DECLARE(void *) ap_realloc(void *ptr, size_t size)
3071 void *p = realloc(ptr, size);
3072 if (p == NULL && size != 0)
3077 AP_DECLARE(void) ap_get_sload(ap_sload_t *ld)
3079 int i, j, server_limit, thread_limit;
3083 ap_generation_t mpm_generation;
3085 /* preload errored fields, we overwrite */
3088 ld->bytes_served = 0;
3089 ld->access_count = 0;
3091 ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
3092 ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
3093 ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
3095 for (i = 0; i < server_limit; i++) {
3097 ps = ap_get_scoreboard_process(i);
3099 for (j = 0; j < thread_limit; j++) {
3101 worker_score *ws = NULL;
3102 ws = &ap_scoreboard_image->servers[i][j];
3105 if (!ps->quiescing && ps->pid) {
3106 if (res == SERVER_READY && ps->generation == mpm_generation) {
3109 else if (res != SERVER_DEAD &&
3110 res != SERVER_STARTING && res != SERVER_IDLE_KILL &&
3111 ps->generation == mpm_generation) {
3116 if (ap_extended_status && !ps->quiescing && ps->pid) {
3117 if (ws->access_count != 0
3118 || (res != SERVER_READY && res != SERVER_DEAD)) {
3119 ld->access_count += ws->access_count;
3120 ld->bytes_served += ws->bytes_served;
3125 total = busy + ready;
3127 ld->idle = ready * 100 / total;
3128 ld->busy = busy * 100 / total;
3132 AP_DECLARE(void) ap_get_loadavg(ap_loadavg_t *ld)
3134 /* preload errored fields, we overwrite */
3136 ld->loadavg5 = -1.0;
3137 ld->loadavg15 = -1.0;
3144 num = getloadavg(la, 3);
3146 ld->loadavg = (float)la[0];
3149 ld->loadavg5 = (float)la[1];
3152 ld->loadavg15 = (float)la[2];
3158 static const char * const pw_cache_note_name = "conn_cache_note";
3160 /* varbuf contains concatenated password and hash */
3161 struct ap_varbuf vb;
3163 apr_status_t result;
3166 AP_DECLARE(apr_status_t) ap_password_validate(request_rec *r,
3167 const char *username,
3171 struct pw_cache *cache;
3174 cache = (struct pw_cache *)apr_table_get(r->connection->notes, pw_cache_note_name);
3175 if (cache != NULL) {
3176 if (strncmp(passwd, cache->vb.buf, cache->pwlen) == 0
3177 && strcmp(hash, cache->vb.buf + cache->pwlen) == 0) {
3178 return cache->result;
3180 /* make ap_varbuf_grow below not copy the old data */
3181 cache->vb.strlen = 0;
3184 cache = apr_palloc(r->connection->pool, sizeof(struct pw_cache));
3185 ap_varbuf_init(r->connection->pool, &cache->vb, 0);
3186 apr_table_setn(r->connection->notes, pw_cache_note_name, (void *)cache);
3188 cache->pwlen = strlen(passwd);
3189 hashlen = strlen(hash);
3190 ap_varbuf_grow(&cache->vb, cache->pwlen + hashlen + 1);
3191 memcpy(cache->vb.buf, passwd, cache->pwlen);
3192 memcpy(cache->vb.buf + cache->pwlen, hash, hashlen + 1);
3193 cache->result = apr_password_validate(passwd, hash);
3194 return cache->result;
3197 AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p,
3199 const char * const * argv)
3201 char buf[MAX_STRING_LEN];
3202 apr_procattr_t *procattr;
3205 apr_size_t nbytes = 1;
3209 if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
3211 if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
3212 APR_FULL_BLOCK) != APR_SUCCESS)
3214 if (apr_procattr_dir_set(procattr,
3215 ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
3217 if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
3219 proc = apr_pcalloc(p, sizeof(apr_proc_t));
3220 if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
3226 /* XXX: we are reading 1 byte at a time here */
3227 for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
3228 && nbytes == 1 && (k < MAX_STRING_LEN-1) ; ) {
3229 if (c == '\n' || c == '\r')
3236 return apr_pstrndup(p, buf, k);
3239 AP_DECLARE(int) ap_array_str_index(const apr_array_header_t *array,
3246 for (i = start; i < array->nelts; i++) {
3247 const char *p = APR_ARRAY_IDX(array, i, const char *);
3248 if (!strcmp(p, s)) {
3257 AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array,
3260 return (ap_array_str_index(array, s, 0) >= 0);
3263 #if !APR_CHARSET_EBCDIC
3265 * Our own known-fast translation table for casecmp by character.
3266 * Only ASCII alpha characters 41-5A are folded to 61-7A, other
3267 * octets (such as extended latin alphabetics) are never case-folded.
3268 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3270 static const short ucharmap[] = {
3271 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
3272 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
3273 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3274 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3275 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3276 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3277 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3278 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3279 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3280 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3281 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3282 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3283 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3284 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3285 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3286 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3287 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3288 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3289 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3290 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3291 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3292 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3293 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3294 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3295 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3296 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3297 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3298 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3299 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3300 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3301 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3302 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3304 #else /* APR_CHARSET_EBCDIC */
3306 * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison,
3307 * provides unique identity of every char value (strict ISO-646
3308 * conformance, arbitrary election of an ISO-8859-1 ordering, and
3309 * very arbitrary control code assignments into C1 to achieve
3310 * identity and a reversible mapping of code points),
3311 * then folding the equivalences of ASCII 41-5A into 61-7A,
3312 * presenting comparison results in a somewhat ISO/IEC 10646
3313 * (ASCII-like) order, depending on the EBCDIC code page in use.
3315 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3317 static const short ucharmap[] = {
3318 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
3319 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
3320 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
3321 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
3322 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
3323 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
3324 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
3325 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
3326 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,
3327 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
3328 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,
3329 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
3330 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,
3331 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
3332 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,
3333 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
3334 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3335 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,
3336 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3337 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,
3338 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3339 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE,
3340 0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,
3341 0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7,
3342 0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3343 0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,
3344 0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3345 0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,
3346 0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3347 0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,
3348 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3349 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F
3353 AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2)
3355 const unsigned char *str1 = (const unsigned char *)s1;
3356 const unsigned char *str2 = (const unsigned char *)s2;
3359 const int c1 = (int)(*str1);
3360 const int c2 = (int)(*str2);
3361 const int cmp = ucharmap[c1] - ucharmap[c2];
3362 /* Not necessary to test for !c2, this is caught by cmp */
3370 AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
3372 const unsigned char *str1 = (const unsigned char *)s1;
3373 const unsigned char *str2 = (const unsigned char *)s2;
3376 const int c1 = (int)(*str1);
3377 const int c2 = (int)(*str2);
3378 const int cmp = ucharmap[c1] - ucharmap[c2];
3379 /* Not necessary to test for !c2, this is caught by cmp */