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, note NUL
1684 * isn't a token stop, so we don't need to test for it
1686 while (TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1693 /* find end of the token */
1694 while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1697 if (!ap_cstr_casecmpn((const char *)start_token, (const char *)tok,
1708 AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line,
1711 int llen, tlen, lidx;
1716 llen = strlen(line);
1721 (lidx > 0 && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1724 return (ap_cstr_casecmpn(&line[lidx], tok, tlen) == 0);
1727 AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1731 const unsigned char *s;
1733 cmd = apr_palloc(p, 2 * strlen(str) + 1); /* Be safe */
1734 d = (unsigned char *)cmd;
1735 s = (const unsigned char *)str;
1738 #if defined(OS2) || defined(WIN32)
1740 * Newlines to Win32/OS2 CreateProcess() are ill advised.
1741 * Convert them to spaces since they are effectively white
1742 * space to most applications
1744 if (*s == '\r' || *s == '\n') {
1750 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1760 static char x2c(const char *what)
1764 #if !APR_CHARSET_EBCDIC
1765 digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
1768 digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
1770 #else /*APR_CHARSET_EBCDIC*/
1777 digit = apr_xlate_conv_byte(ap_hdrs_from_ascii,
1778 0xFF & strtol(xstr, NULL, 16));
1779 #endif /*APR_CHARSET_EBCDIC*/
1784 * Unescapes a URL, leaving reserved characters intact.
1785 * Returns 0 on success, non-zero on error
1787 * bad % escape returns HTTP_BAD_REQUEST
1789 * decoding %00 or a forbidden character returns HTTP_NOT_FOUND
1792 static int unescape_url(char *url, const char *forbid, const char *reserved)
1794 int badesc, badpath;
1799 /* Initial scan for first '%'. Don't bother writing values before
1801 y = strchr(url, '%');
1805 for (x = y; *y; ++x, ++y) {
1810 if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1816 decoded = x2c(y + 1);
1817 if ((decoded == '\0')
1818 || (forbid && ap_strchr_c(forbid, decoded))) {
1823 else if (reserved && ap_strchr_c(reserved, decoded)) {
1837 return HTTP_BAD_REQUEST;
1840 return HTTP_NOT_FOUND;
1846 AP_DECLARE(int) ap_unescape_url(char *url)
1849 return unescape_url(url, SLASHES, NULL);
1851 AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes)
1853 /* AllowEncodedSlashes (corrected) */
1854 if (decode_slashes) {
1855 /* no chars reserved */
1856 return unescape_url(url, NULL, NULL);
1858 /* reserve (do not decode) encoded slashes */
1859 return unescape_url(url, NULL, SLASHES);
1863 /* IFDEF these out until they've been thought through.
1864 * Just a germ of an API extension for now
1866 AP_DECLARE(int) ap_unescape_url_proxy(char *url)
1868 /* leave RFC1738 reserved characters intact, * so proxied URLs
1869 * don't get mangled. Where does that leave encoded '&' ?
1871 return unescape_url(url, NULL, "/;?");
1873 AP_DECLARE(int) ap_unescape_url_reserved(char *url, const char *reserved)
1875 return unescape_url(url, NULL, reserved);
1879 AP_DECLARE(int) ap_unescape_urlencoded(char *query)
1883 /* replace plus with a space */
1885 for (slider = query; *slider; slider++) {
1886 if (*slider == '+') {
1892 /* unescape everything else */
1893 return unescape_url(query, NULL, NULL);
1896 AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname,
1897 apr_port_t port, const request_rec *r)
1899 if (ap_is_default_port(port, r)) {
1900 return apr_pstrdup(p, hostname);
1903 return apr_psprintf(p, "%s:%u", hostname, port);
1907 AP_DECLARE(int) ap_unescape_all(char *url)
1909 return unescape_url(url, NULL, NULL);
1912 /* c2x takes an unsigned, and expects the caller has guaranteed that
1913 * 0 <= what < 256... which usually means that you have to cast to
1914 * unsigned char first, because (unsigned)(char)(x) first goes through
1915 * signed extension to an int before the unsigned cast.
1917 * The reason for this assumption is to assist gcc code generation --
1918 * the unsigned char -> unsigned extension is already done earlier in
1919 * both uses of this code, so there's no need to waste time doing it
1922 static const char c2x_table[] = "0123456789abcdef";
1924 static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
1925 unsigned char *where)
1927 #if APR_CHARSET_EBCDIC
1928 what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
1929 #endif /*APR_CHARSET_EBCDIC*/
1931 *where++ = c2x_table[what >> 4];
1932 *where++ = c2x_table[what & 0xf];
1937 * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
1938 * routine is (should be) OS independent.
1940 * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
1941 * cases if a ':' occurs before the first '/' in the URL, the URL should be
1942 * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
1943 * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
1944 * efficiency reasons, we don't use escape_path_segment(), which is provided for
1945 * reference. Again, RFC 1808 is where this stuff is defined.
1947 * If partial is set, os_escape_path() assumes that the path will be appended to
1948 * something with a '/' in it (and thus does not prefix "./").
1951 AP_DECLARE(char *) ap_escape_path_segment_buffer(char *copy, const char *segment)
1953 const unsigned char *s = (const unsigned char *)segment;
1954 unsigned char *d = (unsigned char *)copy;
1958 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
1970 AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
1972 return ap_escape_path_segment_buffer(apr_palloc(p, 3 * strlen(segment) + 1), segment);
1975 AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
1977 /* Allocate +3 for potential "./" and trailing NULL.
1978 * Allocate another +1 to allow the caller to add a trailing '/' (see
1979 * comment in 'ap_sub_req_lookup_dirent')
1981 char *copy = apr_palloc(p, 3 * strlen(path) + 3 + 1);
1982 const unsigned char *s = (const unsigned char *)path;
1983 unsigned char *d = (unsigned char *)copy;
1987 const char *colon = ap_strchr_c(path, ':');
1988 const char *slash = ap_strchr_c(path, '/');
1990 if (colon && (!slash || colon < slash)) {
1996 if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
2008 AP_DECLARE(char *) ap_escape_urlencoded_buffer(char *copy, const char *buffer)
2010 const unsigned char *s = (const unsigned char *)buffer;
2011 unsigned char *d = (unsigned char *)copy;
2015 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
2018 else if (c == ' ') {
2030 AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
2032 return ap_escape_urlencoded_buffer(apr_palloc(p, 3 * strlen(buffer) + 1), buffer);
2035 /* ap_escape_uri is now a macro for os_escape_path */
2037 AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
2042 /* first, count the number of extra characters */
2043 for (i = 0, j = 0; s[i] != '\0'; i++)
2044 if (s[i] == '<' || s[i] == '>')
2046 else if (s[i] == '&')
2048 else if (s[i] == '"')
2050 else if (toasc && !apr_isascii(s[i]))
2054 return apr_pstrmemdup(p, s, i);
2056 x = apr_palloc(p, i + j + 1);
2057 for (i = 0, j = 0; s[i] != '\0'; i++, j++)
2059 memcpy(&x[j], "<", 4);
2062 else if (s[i] == '>') {
2063 memcpy(&x[j], ">", 4);
2066 else if (s[i] == '&') {
2067 memcpy(&x[j], "&", 5);
2070 else if (s[i] == '"') {
2071 memcpy(&x[j], """, 6);
2074 else if (toasc && !apr_isascii(s[i])) {
2075 char *esc = apr_psprintf(p, "&#%3.3d;", (unsigned char)s[i]);
2076 memcpy(&x[j], esc, 6);
2085 AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str)
2089 const unsigned char *s;
2090 apr_size_t length, escapes = 0;
2096 /* Compute how many characters need to be escaped */
2097 s = (const unsigned char *)str;
2099 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2104 /* Compute the length of the input string, including NULL */
2105 length = s - (const unsigned char *)str + 1;
2107 /* Fast path: nothing to escape */
2109 return apr_pmemdup(p, str, length);
2112 /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */
2113 ret = apr_palloc(p, length + 3 * escapes);
2114 d = (unsigned char *)ret;
2115 s = (const unsigned char *)str;
2117 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2153 AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
2156 unsigned char *d, *ep;
2157 const unsigned char *s;
2159 if (!source || !buflen) { /* be safe */
2163 d = (unsigned char *)dest;
2164 s = (const unsigned char *)source;
2165 ep = d + buflen - 1;
2167 for (; d < ep && *s; ++s) {
2169 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2195 case '"': /* no need for this in error log */
2200 ep = --d; /* break the for loop as well */
2213 return (d - (unsigned char *)dest);
2216 AP_DECLARE(void) ap_bin2hex(const void *src, apr_size_t srclen, char *dest)
2218 const unsigned char *in = src;
2221 for (i = 0; i < srclen; i++) {
2222 *dest++ = c2x_table[in[i] >> 4];
2223 *dest++ = c2x_table[in[i] & 0xf];
2228 AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
2232 if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS)
2233 return 0; /* in error condition, just return no */
2235 return (finfo.filetype == APR_DIR);
2238 AP_DECLARE(int) ap_is_rdirectory(apr_pool_t *p, const char *path)
2242 if (apr_stat(&finfo, path, APR_FINFO_LINK | APR_FINFO_TYPE, p) != APR_SUCCESS)
2243 return 0; /* in error condition, just return no */
2245 return (finfo.filetype == APR_DIR);
2248 AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
2251 apr_size_t len1, len2;
2254 len1 = strlen(src1);
2255 len2 = strlen(src2);
2256 /* allocate +3 for '/' delimiter, trailing NULL and overallocate
2257 * one extra byte to allow the caller to add a trailing '/'
2259 path = (char *)apr_palloc(a, len1 + len2 + 3);
2262 memcpy(path + 1, src2, len2 + 1);
2266 memcpy(path, src1, len1);
2268 if (next[-1] != '/') {
2271 memcpy(next, src2, len2 + 1);
2277 * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
2279 AP_DECLARE(int) ap_is_url(const char *u)
2283 for (x = 0; u[x] != ':'; x++) {
2285 ((!apr_isalnum(u[x])) &&
2286 (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
2291 return (x ? 1 : 0); /* If the first character is ':', it's broken, too */
2294 AP_DECLARE(int) ap_ind(const char *s, char c)
2296 const char *p = ap_strchr_c(s, c);
2303 AP_DECLARE(int) ap_rind(const char *s, char c)
2305 const char *p = ap_strrchr_c(s, c);
2312 AP_DECLARE(void) ap_str_tolower(char *str)
2315 *str = apr_tolower(*str);
2320 AP_DECLARE(void) ap_str_toupper(char *str)
2323 *str = apr_toupper(*str);
2329 * We must return a FQDN
2331 char *ap_get_local_host(apr_pool_t *a)
2333 #ifndef MAXHOSTNAMELEN
2334 #define MAXHOSTNAMELEN 256
2336 char str[MAXHOSTNAMELEN + 1];
2337 char *server_hostname = NULL;
2338 apr_sockaddr_t *sockaddr;
2341 if (apr_gethostname(str, sizeof(str) - 1, a) != APR_SUCCESS) {
2342 ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00556)
2343 "%s: apr_gethostname() failed to determine ServerName",
2346 str[sizeof(str) - 1] = '\0';
2347 if (apr_sockaddr_info_get(&sockaddr, str, APR_UNSPEC, 0, 0, a) == APR_SUCCESS) {
2348 if ( (apr_getnameinfo(&hostname, sockaddr, 0) == APR_SUCCESS) &&
2349 (ap_strchr_c(hostname, '.')) ) {
2350 server_hostname = apr_pstrdup(a, hostname);
2351 return server_hostname;
2352 } else if (ap_strchr_c(str, '.')) {
2353 server_hostname = apr_pstrdup(a, str);
2355 apr_sockaddr_ip_get(&hostname, sockaddr);
2356 server_hostname = apr_pstrdup(a, hostname);
2359 ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00557)
2360 "%s: apr_sockaddr_info_get() failed for %s",
2361 ap_server_argv0, str);
2365 if (!server_hostname)
2366 server_hostname = apr_pstrdup(a, "127.0.0.1");
2368 ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, a, APLOGNO(00558)
2369 "%s: Could not reliably determine the server's fully qualified "
2370 "domain name, using %s. Set the 'ServerName' directive globally "
2371 "to suppress this message",
2372 ap_server_argv0, server_hostname);
2374 return server_hostname;
2377 /* simple 'pool' alloc()ing glue to apr_base64.c
2379 AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
2384 decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded));
2385 l = apr_base64_decode(decoded, bufcoded);
2386 decoded[l] = '\0'; /* make binary sequence into string */
2391 AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
2394 int l = strlen(string);
2396 encoded = (char *) apr_palloc(p, 1 + apr_base64_encode_len(l));
2397 l = apr_base64_encode(encoded, string, l);
2398 encoded[l] = '\0'; /* make binary sequence into string */
2403 /* we want to downcase the type/subtype for comparison purposes
2404 * but nothing else because ;parameter=foo values are case sensitive.
2405 * XXX: in truth we want to downcase parameter names... but really,
2406 * apache has never handled parameters and such correctly. You
2407 * also need to compress spaces and such to be able to compare
2410 AP_DECLARE(void) ap_content_type_tolower(char *str)
2414 semi = strchr(str, ';');
2419 ap_str_tolower(str);
2427 * Given a string, replace any bare " with \" .
2429 AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
2432 const char *inchr = instring;
2433 char *outchr, *outstring;
2436 * Look through the input string, jogging the length of the output
2437 * string up by an extra byte each time we find an unescaped ".
2439 while (*inchr != '\0') {
2441 if (*inchr == '"') {
2445 * If we find a slosh, and it's not the last byte in the string,
2446 * it's escaping something - advance past both bytes.
2448 if ((*inchr == '\\') && (inchr[1] != '\0')) {
2454 outstring = apr_palloc(p, newlen + 1);
2458 * Now copy the input string to the output string, inserting a slosh
2459 * in front of every " that doesn't already have one.
2461 while (*inchr != '\0') {
2462 if ((*inchr == '\\') && (inchr[1] != '\0')) {
2463 *outchr++ = *inchr++;
2464 *outchr++ = *inchr++;
2466 if (*inchr == '"') {
2469 if (*inchr != '\0') {
2470 *outchr++ = *inchr++;
2478 * Given a string, append the PID deliminated by delim.
2479 * Usually used to create a pid-appended filepath name
2480 * (eg: /a/b/foo -> /a/b/foo.6726). A function, and not
2481 * a macro, to avoid unistd.h dependency
2483 AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string,
2486 return apr_psprintf(p, "%s%s%" APR_PID_T_FMT, string,
2492 * Parse a given timeout parameter string into an apr_interval_time_t value.
2493 * The unit of the time interval is given as postfix string to the numeric
2494 * string. Currently the following units are understood:
2501 * If no unit is contained in the given timeout parameter the default_time_unit
2502 * will be used instead.
2503 * @param timeout_parameter The string containing the timeout parameter.
2504 * @param timeout The timeout value to be returned.
2505 * @param default_time_unit The default time unit to use if none is specified
2506 * in timeout_parameter.
2507 * @return Status value indicating whether the parsing was successful or not.
2509 AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
2510 const char *timeout_parameter,
2511 apr_interval_time_t *timeout,
2512 const char *default_time_unit)
2515 const char *time_str;
2518 tout = apr_strtoi64(timeout_parameter, &endp, 10);
2522 if (!endp || !*endp) {
2523 time_str = default_time_unit;
2529 switch (*time_str) {
2530 /* Time is in seconds */
2532 *timeout = (apr_interval_time_t) apr_time_from_sec(tout);
2535 /* Time is in hours */
2536 *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 3600);
2539 switch (*(++time_str)) {
2540 /* Time is in milliseconds */
2542 *timeout = (apr_interval_time_t) tout * 1000;
2544 /* Time is in minutes */
2546 *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 60);
2549 return APR_EGENERAL;
2553 return APR_EGENERAL;
2559 * Determine if a request has a request body or not.
2561 * @param r the request_rec of the request
2562 * @return truth value
2564 AP_DECLARE(int) ap_request_has_body(request_rec *r)
2571 has_body = (!r->header_only
2573 || apr_table_get(r->headers_in, "Transfer-Encoding")
2574 || ( (cls = apr_table_get(r->headers_in, "Content-Length"))
2575 && (apr_strtoff(&cl, cls, &estr, 10) == APR_SUCCESS)
2584 * Check whether a request is tainted by exposure to something
2585 * potentially untrusted.
2588 AP_DECLARE(int) ap_request_tainted(request_rec *r, int flags)
2590 /** Potential future: a hook or callback here could serve modules
2591 * like mod_security and ironbee with more complex needs.
2593 return r && ((r->taint&flags)
2594 || ap_request_tainted(r->main, flags)
2595 || ap_request_tainted(r->prev, flags));
2598 AP_DECLARE_NONSTD(apr_status_t) ap_pool_cleanup_set_null(void *data_)
2600 void **ptr = (void **)data_;
2605 AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
2607 for ( ; *src; src++, dest++)
2609 if (!apr_isprint(*src))
2611 else if (!apr_isalnum(*src))
2621 AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
2624 char *new = apr_palloc(p, strlen(src)+1);
2628 return ap_str2_alnum(src, new);
2632 * Read the body and parse any form found, which must be of the
2633 * type application/x-www-form-urlencoded.
2635 * Name/value pairs are returned in an array, with the names as
2636 * strings with a maximum length of HUGE_STRING_LEN, and the
2637 * values as bucket brigades. This allows values to be arbitrarily
2640 * All url-encoding is removed from both the names and the values
2641 * on the fly. The names are interpreted as strings, while the
2642 * values are interpreted as blocks of binary data, that may
2643 * contain the 0 character.
2645 * In order to ensure that resource limits are not exceeded, a
2646 * maximum size must be provided. If the sum of the lengths of
2647 * the names and the values exceed this size, this function
2648 * will return HTTP_REQUEST_ENTITY_TOO_LARGE.
2650 * An optional number of parameters can be provided, if the number
2651 * of parameters provided exceeds this amount, this function will
2652 * return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
2653 * no limit is imposed, and the number of parameters is in turn
2654 * constrained by the size parameter above.
2656 * This function honours any kept_body configuration, and the
2657 * original raw request body will be saved to the kept_body brigade
2658 * if so configured, just as ap_discard_request_body does.
2660 * NOTE: File upload is not yet supported, but can be without change
2661 * to the function call.
2664 /* form parsing stuff */
2675 AP_DECLARE(int) ap_parse_form_data(request_rec *r, ap_filter_t *f,
2676 apr_array_header_t **ptr,
2677 apr_size_t num, apr_size_t usize)
2679 apr_bucket_brigade *bb = NULL;
2681 char buffer[HUGE_STRING_LEN + 1];
2683 apr_size_t offset = 0;
2685 ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
2686 ap_form_pair_t *pair = NULL;
2687 apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
2694 /* sanity check - we only support forms for now */
2695 ct = apr_table_get(r->headers_in, "Content-Type");
2696 if (!ct || ap_cstr_casecmpn("application/x-www-form-urlencoded", ct, 33)) {
2697 return ap_discard_request_body(r);
2700 if (usize > APR_SIZE_MAX >> 1)
2701 size = APR_SIZE_MAX >> 1;
2706 f = r->input_filters;
2709 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2711 apr_bucket *bucket = NULL, *last = NULL;
2713 int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
2714 APR_BLOCK_READ, HUGE_STRING_LEN);
2715 if (rv != APR_SUCCESS) {
2716 apr_brigade_destroy(bb);
2717 return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
2720 for (bucket = APR_BRIGADE_FIRST(bb);
2721 bucket != APR_BRIGADE_SENTINEL(bb);
2722 last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
2724 apr_size_t len, slide;
2727 apr_bucket_delete(last);
2729 if (APR_BUCKET_IS_EOS(bucket)) {
2733 if (bucket->length == 0) {
2737 rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
2738 if (rv != APR_SUCCESS) {
2739 apr_brigade_destroy(bb);
2740 return HTTP_BAD_REQUEST;
2744 while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
2749 else if ('&' == c) {
2753 percent = FORM_PERCENTA;
2756 if (FORM_PERCENTA == percent) {
2760 else if (c >= 'A') {
2763 else if (c >= '0') {
2767 percent = FORM_PERCENTB;
2770 if (FORM_PERCENTB == percent) {
2774 else if (c >= 'A') {
2777 else if (c >= '0') {
2781 percent = FORM_NORMAL;
2786 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2787 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2788 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2796 if (offset < HUGE_STRING_LEN) {
2800 pair = (ap_form_pair_t *) apr_array_push(pairs);
2801 pair->name = apr_pstrdup(r->pool, buffer);
2802 pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2806 buffer[offset++] = c;
2815 if (offset >= HUGE_STRING_LEN) {
2816 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2817 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2818 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2821 buffer[offset++] = c;
2831 apr_brigade_cleanup(bb);
2832 } while (!seen_eos);
2834 if (FORM_ABORT == state || size < 0 || num == 0) {
2835 return HTTP_REQUEST_ENTITY_TOO_LARGE;
2837 else if (FORM_VALUE == state && pair && offset > 0) {
2838 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2839 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2840 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2847 #define VARBUF_SMALL_SIZE 2048
2848 #define VARBUF_MAX_SIZE (APR_SIZE_MAX - 1 - \
2849 APR_ALIGN_DEFAULT(sizeof(struct ap_varbuf_info)))
2851 struct ap_varbuf_info {
2852 struct apr_memnode_t *node;
2853 apr_allocator_t *allocator;
2856 static apr_status_t varbuf_cleanup(void *info_)
2858 struct ap_varbuf_info *info = info_;
2859 info->node->next = NULL;
2860 apr_allocator_free(info->allocator, info->node);
2864 const char nul = '\0';
2865 static char * const varbuf_empty = (char *)&nul;
2867 AP_DECLARE(void) ap_varbuf_init(apr_pool_t *p, struct ap_varbuf *vb,
2868 apr_size_t init_size)
2870 vb->buf = varbuf_empty;
2872 vb->strlen = AP_VARBUF_UNKNOWN;
2876 ap_varbuf_grow(vb, init_size);
2879 AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
2881 apr_memnode_t *new_node = NULL;
2882 apr_allocator_t *allocator;
2883 struct ap_varbuf_info *new_info;
2886 AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN || vb->avail >= vb->strlen);
2888 if (new_len <= vb->avail)
2891 if (new_len < 2 * vb->avail && vb->avail < VARBUF_MAX_SIZE/2) {
2892 /* at least double the size, to avoid repeated reallocations */
2893 new_len = 2 * vb->avail;
2895 else if (new_len > VARBUF_MAX_SIZE) {
2896 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2897 ap_assert(abort_fn != NULL);
2898 abort_fn(APR_ENOMEM);
2902 new_len++; /* add space for trailing \0 */
2903 if (new_len <= VARBUF_SMALL_SIZE) {
2904 new_len = APR_ALIGN_DEFAULT(new_len);
2905 new = apr_palloc(vb->pool, new_len);
2906 if (vb->avail && vb->strlen != 0) {
2907 AP_DEBUG_ASSERT(vb->buf != NULL);
2908 AP_DEBUG_ASSERT(vb->buf != varbuf_empty);
2909 if (new == vb->buf + vb->avail + 1) {
2910 /* We are lucky: the new memory lies directly after our old
2911 * buffer, we can now use both.
2913 vb->avail += new_len;
2917 /* copy up to vb->strlen + 1 bytes */
2918 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2919 vb->avail + 1 : vb->strlen + 1);
2925 vb->avail = new_len - 1;
2930 /* The required block is rather larger. Use allocator directly so that
2931 * the memory can be freed independently from the pool. */
2932 allocator = apr_pool_allocator_get(vb->pool);
2933 if (new_len <= VARBUF_MAX_SIZE)
2934 new_node = apr_allocator_alloc(allocator,
2935 new_len + APR_ALIGN_DEFAULT(sizeof(*new_info)));
2937 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2938 ap_assert(abort_fn != NULL);
2939 abort_fn(APR_ENOMEM);
2942 new_info = (struct ap_varbuf_info *)new_node->first_avail;
2943 new_node->first_avail += APR_ALIGN_DEFAULT(sizeof(*new_info));
2944 new_info->node = new_node;
2945 new_info->allocator = allocator;
2946 new = new_node->first_avail;
2947 AP_DEBUG_ASSERT(new_node->endp - new_node->first_avail >= new_len);
2948 new_len = new_node->endp - new_node->first_avail;
2950 if (vb->avail && vb->strlen != 0)
2951 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2952 vb->avail + 1 : vb->strlen + 1);
2956 apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
2957 apr_pool_cleanup_register(vb->pool, new_info, varbuf_cleanup,
2958 apr_pool_cleanup_null);
2959 vb->info = new_info;
2961 vb->avail = new_len - 1;
2964 AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
2970 ap_varbuf_grow(vb, len);
2971 memcpy(vb->buf, str, len);
2972 vb->buf[len] = '\0';
2976 if (vb->strlen == AP_VARBUF_UNKNOWN)
2977 vb->strlen = strlen(vb->buf);
2978 ap_varbuf_grow(vb, vb->strlen + len);
2979 memcpy(vb->buf + vb->strlen, str, len);
2981 vb->buf[vb->strlen] = '\0';
2984 AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb)
2987 apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
2993 AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *buf,
2994 const char *prepend, apr_size_t prepend_len,
2995 const char *append, apr_size_t append_len,
2996 apr_size_t *new_len)
2999 struct iovec vec[3];
3002 vec[i].iov_base = (void *)prepend;
3003 vec[i].iov_len = prepend_len;
3006 if (buf->avail && buf->strlen) {
3007 if (buf->strlen == AP_VARBUF_UNKNOWN)
3008 buf->strlen = strlen(buf->buf);
3009 vec[i].iov_base = (void *)buf->buf;
3010 vec[i].iov_len = buf->strlen;
3014 vec[i].iov_base = (void *)append;
3015 vec[i].iov_len = append_len;
3019 return apr_pstrcatv(p, vec, i, new_len);
3026 AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb,
3030 ap_regmatch_t pmatch[],
3033 return regsub_core(NULL, NULL, vb, input, source, nmatch, pmatch, maxlen);
3036 static const char * const oom_message = "[crit] Memory allocation failed, "
3037 "aborting process." APR_EOL_STR;
3039 AP_DECLARE(void) ap_abort_on_oom()
3041 int written, count = strlen(oom_message);
3042 const char *buf = oom_message;
3044 written = write(STDERR_FILENO, buf, count);
3045 if (written == count)
3051 } while (written >= 0 || errno == EINTR);
3055 AP_DECLARE(void *) ap_malloc(size_t size)
3057 void *p = malloc(size);
3058 if (p == NULL && size != 0)
3063 AP_DECLARE(void *) ap_calloc(size_t nelem, size_t size)
3065 void *p = calloc(nelem, size);
3066 if (p == NULL && nelem != 0 && size != 0)
3071 AP_DECLARE(void *) ap_realloc(void *ptr, size_t size)
3073 void *p = realloc(ptr, size);
3074 if (p == NULL && size != 0)
3079 AP_DECLARE(void) ap_get_sload(ap_sload_t *ld)
3081 int i, j, server_limit, thread_limit;
3085 ap_generation_t mpm_generation;
3087 /* preload errored fields, we overwrite */
3090 ld->bytes_served = 0;
3091 ld->access_count = 0;
3093 ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
3094 ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
3095 ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
3097 for (i = 0; i < server_limit; i++) {
3099 ps = ap_get_scoreboard_process(i);
3101 for (j = 0; j < thread_limit; j++) {
3103 worker_score *ws = NULL;
3104 ws = &ap_scoreboard_image->servers[i][j];
3107 if (!ps->quiescing && ps->pid) {
3108 if (res == SERVER_READY && ps->generation == mpm_generation) {
3111 else if (res != SERVER_DEAD &&
3112 res != SERVER_STARTING && res != SERVER_IDLE_KILL &&
3113 ps->generation == mpm_generation) {
3118 if (ap_extended_status && !ps->quiescing && ps->pid) {
3119 if (ws->access_count != 0
3120 || (res != SERVER_READY && res != SERVER_DEAD)) {
3121 ld->access_count += ws->access_count;
3122 ld->bytes_served += ws->bytes_served;
3127 total = busy + ready;
3129 ld->idle = ready * 100 / total;
3130 ld->busy = busy * 100 / total;
3134 AP_DECLARE(void) ap_get_loadavg(ap_loadavg_t *ld)
3136 /* preload errored fields, we overwrite */
3138 ld->loadavg5 = -1.0;
3139 ld->loadavg15 = -1.0;
3146 num = getloadavg(la, 3);
3148 ld->loadavg = (float)la[0];
3151 ld->loadavg5 = (float)la[1];
3154 ld->loadavg15 = (float)la[2];
3160 static const char * const pw_cache_note_name = "conn_cache_note";
3162 /* varbuf contains concatenated password and hash */
3163 struct ap_varbuf vb;
3165 apr_status_t result;
3168 AP_DECLARE(apr_status_t) ap_password_validate(request_rec *r,
3169 const char *username,
3173 struct pw_cache *cache;
3176 cache = (struct pw_cache *)apr_table_get(r->connection->notes, pw_cache_note_name);
3177 if (cache != NULL) {
3178 if (strncmp(passwd, cache->vb.buf, cache->pwlen) == 0
3179 && strcmp(hash, cache->vb.buf + cache->pwlen) == 0) {
3180 return cache->result;
3182 /* make ap_varbuf_grow below not copy the old data */
3183 cache->vb.strlen = 0;
3186 cache = apr_palloc(r->connection->pool, sizeof(struct pw_cache));
3187 ap_varbuf_init(r->connection->pool, &cache->vb, 0);
3188 apr_table_setn(r->connection->notes, pw_cache_note_name, (void *)cache);
3190 cache->pwlen = strlen(passwd);
3191 hashlen = strlen(hash);
3192 ap_varbuf_grow(&cache->vb, cache->pwlen + hashlen + 1);
3193 memcpy(cache->vb.buf, passwd, cache->pwlen);
3194 memcpy(cache->vb.buf + cache->pwlen, hash, hashlen + 1);
3195 cache->result = apr_password_validate(passwd, hash);
3196 return cache->result;
3199 AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p,
3201 const char * const * argv)
3203 char buf[MAX_STRING_LEN];
3204 apr_procattr_t *procattr;
3207 apr_size_t nbytes = 1;
3211 if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
3213 if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
3214 APR_FULL_BLOCK) != APR_SUCCESS)
3216 if (apr_procattr_dir_set(procattr,
3217 ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
3219 if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
3221 proc = apr_pcalloc(p, sizeof(apr_proc_t));
3222 if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
3228 /* XXX: we are reading 1 byte at a time here */
3229 for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
3230 && nbytes == 1 && (k < MAX_STRING_LEN-1) ; ) {
3231 if (c == '\n' || c == '\r')
3238 return apr_pstrndup(p, buf, k);
3241 AP_DECLARE(int) ap_array_str_index(const apr_array_header_t *array,
3248 for (i = start; i < array->nelts; i++) {
3249 const char *p = APR_ARRAY_IDX(array, i, const char *);
3250 if (!strcmp(p, s)) {
3259 AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array,
3262 return (ap_array_str_index(array, s, 0) >= 0);
3265 #if !APR_CHARSET_EBCDIC
3267 * Our own known-fast translation table for casecmp by character.
3268 * Only ASCII alpha characters 41-5A are folded to 61-7A, other
3269 * octets (such as extended latin alphabetics) are never case-folded.
3270 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3272 static const short ucharmap[] = {
3273 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
3274 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
3275 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3276 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3277 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3278 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3279 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3280 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3281 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3282 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3283 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3284 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3285 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3286 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3287 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3288 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3289 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3290 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3291 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3292 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3293 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3294 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3295 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3296 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3297 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3298 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3299 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3300 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3301 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3302 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3303 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3304 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3306 #else /* APR_CHARSET_EBCDIC */
3308 * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison,
3309 * provides unique identity of every char value (strict ISO-646
3310 * conformance, arbitrary election of an ISO-8859-1 ordering, and
3311 * very arbitrary control code assignments into C1 to achieve
3312 * identity and a reversible mapping of code points),
3313 * then folding the equivalences of ASCII 41-5A into 61-7A,
3314 * presenting comparison results in a somewhat ISO/IEC 10646
3315 * (ASCII-like) order, depending on the EBCDIC code page in use.
3317 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3319 static const short ucharmap[] = {
3320 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
3321 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
3322 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
3323 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
3324 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
3325 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
3326 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
3327 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
3328 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,
3329 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
3330 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,
3331 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
3332 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,
3333 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
3334 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,
3335 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
3336 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3337 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,
3338 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3339 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,
3340 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3341 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE,
3342 0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,
3343 0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7,
3344 0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3345 0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,
3346 0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3347 0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,
3348 0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3349 0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,
3350 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3351 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F
3355 AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2)
3357 const unsigned char *str1 = (const unsigned char *)s1;
3358 const unsigned char *str2 = (const unsigned char *)s2;
3361 const int c1 = (int)(*str1);
3362 const int c2 = (int)(*str2);
3363 const int cmp = ucharmap[c1] - ucharmap[c2];
3364 /* Not necessary to test for !c2, this is caught by cmp */
3372 AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
3374 const unsigned char *str1 = (const unsigned char *)s1;
3375 const unsigned char *str2 = (const unsigned char *)s2;
3378 const int c1 = (int)(*str1);
3379 const int c2 = (int)(*str2);
3380 const int cmp = ucharmap[c1] - ucharmap[c2];
3381 /* Not necessary to test for !c2, this is caught by cmp */