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 /* Retrieve a token, advancing the pointer to the first non-token character
1619 * and returning a copy of the token string.
1620 * The caller must handle whitespace and determine the meaning of the
1621 * terminating character. Returns NULL if the character at **ptr is not
1622 * a valid token character.
1624 AP_DECLARE(char *) ap_get_http_token(apr_pool_t *p, const char **ptr)
1626 const char *tok_end = ap_scan_http_token(*ptr);
1629 if (tok_end == *ptr)
1632 tok = apr_pstrmemdup(p, *ptr, tok_end - *ptr);
1637 /* Scan a string for visible ASCII (0x21-0x7E) or obstext (0x80+)
1638 * and return a pointer to the first ctrl/space character encountered.
1640 AP_DECLARE(const char *) ap_scan_vchar_obstext(const char *ptr)
1642 for ( ; TEST_CHAR(*ptr, T_VCHAR_OBSTEXT); ++ptr) ;
1647 /* Retrieve a token, spacing over it and returning a pointer to
1648 * the first non-white byte afterwards. Note that these tokens
1649 * are delimited by semis and commas; and can also be delimited
1650 * by whitespace at the caller's option.
1653 AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line,
1656 const char *ptr = *accept_line;
1657 const char *tok_start;
1660 /* Find first non-white byte */
1662 while (apr_isspace(*ptr))
1667 /* find token end, skipping over quoted strings.
1668 * (comments are already gone).
1671 while (*ptr && (accept_white || !apr_isspace(*ptr))
1672 && *ptr != ';' && *ptr != ',') {
1679 token = apr_pstrmemdup(p, tok_start, ptr - tok_start);
1681 /* Advance accept_line pointer to the next non-white byte */
1683 while (apr_isspace(*ptr))
1691 /* find http tokens, see the definition of token from RFC2068 */
1692 AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
1694 const unsigned char *start_token;
1695 const unsigned char *s;
1700 s = (const unsigned char *)line;
1702 /* find start of token, skip all stop characters, note NUL
1703 * isn't a token stop, so we don't need to test for it
1705 while (TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1712 /* find end of the token */
1713 while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1716 if (!ap_cstr_casecmpn((const char *)start_token, (const char *)tok,
1727 AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line,
1730 int llen, tlen, lidx;
1735 llen = strlen(line);
1740 (lidx > 0 && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1743 return (ap_cstr_casecmpn(&line[lidx], tok, tlen) == 0);
1746 AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1750 const unsigned char *s;
1752 cmd = apr_palloc(p, 2 * strlen(str) + 1); /* Be safe */
1753 d = (unsigned char *)cmd;
1754 s = (const unsigned char *)str;
1757 #if defined(OS2) || defined(WIN32)
1759 * Newlines to Win32/OS2 CreateProcess() are ill advised.
1760 * Convert them to spaces since they are effectively white
1761 * space to most applications
1763 if (*s == '\r' || *s == '\n') {
1769 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1779 static char x2c(const char *what)
1783 #if !APR_CHARSET_EBCDIC
1784 digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
1787 digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
1789 #else /*APR_CHARSET_EBCDIC*/
1796 digit = apr_xlate_conv_byte(ap_hdrs_from_ascii,
1797 0xFF & strtol(xstr, NULL, 16));
1798 #endif /*APR_CHARSET_EBCDIC*/
1803 * Unescapes a URL, leaving reserved characters intact.
1804 * Returns 0 on success, non-zero on error
1806 * bad % escape returns HTTP_BAD_REQUEST
1808 * decoding %00 or a forbidden character returns HTTP_NOT_FOUND
1811 static int unescape_url(char *url, const char *forbid, const char *reserved)
1813 int badesc, badpath;
1818 /* Initial scan for first '%'. Don't bother writing values before
1820 y = strchr(url, '%');
1824 for (x = y; *y; ++x, ++y) {
1829 if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1835 decoded = x2c(y + 1);
1836 if ((decoded == '\0')
1837 || (forbid && ap_strchr_c(forbid, decoded))) {
1842 else if (reserved && ap_strchr_c(reserved, decoded)) {
1856 return HTTP_BAD_REQUEST;
1859 return HTTP_NOT_FOUND;
1865 AP_DECLARE(int) ap_unescape_url(char *url)
1868 return unescape_url(url, SLASHES, NULL);
1870 AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes)
1872 /* AllowEncodedSlashes (corrected) */
1873 if (decode_slashes) {
1874 /* no chars reserved */
1875 return unescape_url(url, NULL, NULL);
1877 /* reserve (do not decode) encoded slashes */
1878 return unescape_url(url, NULL, SLASHES);
1882 /* IFDEF these out until they've been thought through.
1883 * Just a germ of an API extension for now
1885 AP_DECLARE(int) ap_unescape_url_proxy(char *url)
1887 /* leave RFC1738 reserved characters intact, * so proxied URLs
1888 * don't get mangled. Where does that leave encoded '&' ?
1890 return unescape_url(url, NULL, "/;?");
1892 AP_DECLARE(int) ap_unescape_url_reserved(char *url, const char *reserved)
1894 return unescape_url(url, NULL, reserved);
1898 AP_DECLARE(int) ap_unescape_urlencoded(char *query)
1902 /* replace plus with a space */
1904 for (slider = query; *slider; slider++) {
1905 if (*slider == '+') {
1911 /* unescape everything else */
1912 return unescape_url(query, NULL, NULL);
1915 AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname,
1916 apr_port_t port, const request_rec *r)
1918 if (ap_is_default_port(port, r)) {
1919 return apr_pstrdup(p, hostname);
1922 return apr_psprintf(p, "%s:%u", hostname, port);
1926 AP_DECLARE(int) ap_unescape_all(char *url)
1928 return unescape_url(url, NULL, NULL);
1931 /* c2x takes an unsigned, and expects the caller has guaranteed that
1932 * 0 <= what < 256... which usually means that you have to cast to
1933 * unsigned char first, because (unsigned)(char)(x) first goes through
1934 * signed extension to an int before the unsigned cast.
1936 * The reason for this assumption is to assist gcc code generation --
1937 * the unsigned char -> unsigned extension is already done earlier in
1938 * both uses of this code, so there's no need to waste time doing it
1941 static const char c2x_table[] = "0123456789abcdef";
1943 static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
1944 unsigned char *where)
1946 #if APR_CHARSET_EBCDIC
1947 what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
1948 #endif /*APR_CHARSET_EBCDIC*/
1950 *where++ = c2x_table[what >> 4];
1951 *where++ = c2x_table[what & 0xf];
1956 * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
1957 * routine is (should be) OS independent.
1959 * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
1960 * cases if a ':' occurs before the first '/' in the URL, the URL should be
1961 * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
1962 * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
1963 * efficiency reasons, we don't use escape_path_segment(), which is provided for
1964 * reference. Again, RFC 1808 is where this stuff is defined.
1966 * If partial is set, os_escape_path() assumes that the path will be appended to
1967 * something with a '/' in it (and thus does not prefix "./").
1970 AP_DECLARE(char *) ap_escape_path_segment_buffer(char *copy, const char *segment)
1972 const unsigned char *s = (const unsigned char *)segment;
1973 unsigned char *d = (unsigned char *)copy;
1977 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
1989 AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
1991 return ap_escape_path_segment_buffer(apr_palloc(p, 3 * strlen(segment) + 1), segment);
1994 AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
1996 /* Allocate +3 for potential "./" and trailing NULL.
1997 * Allocate another +1 to allow the caller to add a trailing '/' (see
1998 * comment in 'ap_sub_req_lookup_dirent')
2000 char *copy = apr_palloc(p, 3 * strlen(path) + 3 + 1);
2001 const unsigned char *s = (const unsigned char *)path;
2002 unsigned char *d = (unsigned char *)copy;
2006 const char *colon = ap_strchr_c(path, ':');
2007 const char *slash = ap_strchr_c(path, '/');
2009 if (colon && (!slash || colon < slash)) {
2015 if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
2027 AP_DECLARE(char *) ap_escape_urlencoded_buffer(char *copy, const char *buffer)
2029 const unsigned char *s = (const unsigned char *)buffer;
2030 unsigned char *d = (unsigned char *)copy;
2034 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
2037 else if (c == ' ') {
2049 AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
2051 return ap_escape_urlencoded_buffer(apr_palloc(p, 3 * strlen(buffer) + 1), buffer);
2054 /* ap_escape_uri is now a macro for os_escape_path */
2056 AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
2061 /* first, count the number of extra characters */
2062 for (i = 0, j = 0; s[i] != '\0'; i++)
2063 if (s[i] == '<' || s[i] == '>')
2065 else if (s[i] == '&')
2067 else if (s[i] == '"')
2069 else if (toasc && !apr_isascii(s[i]))
2073 return apr_pstrmemdup(p, s, i);
2075 x = apr_palloc(p, i + j + 1);
2076 for (i = 0, j = 0; s[i] != '\0'; i++, j++)
2078 memcpy(&x[j], "<", 4);
2081 else if (s[i] == '>') {
2082 memcpy(&x[j], ">", 4);
2085 else if (s[i] == '&') {
2086 memcpy(&x[j], "&", 5);
2089 else if (s[i] == '"') {
2090 memcpy(&x[j], """, 6);
2093 else if (toasc && !apr_isascii(s[i])) {
2094 char *esc = apr_psprintf(p, "&#%3.3d;", (unsigned char)s[i]);
2095 memcpy(&x[j], esc, 6);
2104 AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str)
2108 const unsigned char *s;
2109 apr_size_t length, escapes = 0;
2115 /* Compute how many characters need to be escaped */
2116 s = (const unsigned char *)str;
2118 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2123 /* Compute the length of the input string, including NULL */
2124 length = s - (const unsigned char *)str + 1;
2126 /* Fast path: nothing to escape */
2128 return apr_pmemdup(p, str, length);
2131 /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */
2132 ret = apr_palloc(p, length + 3 * escapes);
2133 d = (unsigned char *)ret;
2134 s = (const unsigned char *)str;
2136 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2172 AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
2175 unsigned char *d, *ep;
2176 const unsigned char *s;
2178 if (!source || !buflen) { /* be safe */
2182 d = (unsigned char *)dest;
2183 s = (const unsigned char *)source;
2184 ep = d + buflen - 1;
2186 for (; d < ep && *s; ++s) {
2188 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2214 case '"': /* no need for this in error log */
2219 ep = --d; /* break the for loop as well */
2232 return (d - (unsigned char *)dest);
2235 AP_DECLARE(void) ap_bin2hex(const void *src, apr_size_t srclen, char *dest)
2237 const unsigned char *in = src;
2240 for (i = 0; i < srclen; i++) {
2241 *dest++ = c2x_table[in[i] >> 4];
2242 *dest++ = c2x_table[in[i] & 0xf];
2247 AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
2251 if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS)
2252 return 0; /* in error condition, just return no */
2254 return (finfo.filetype == APR_DIR);
2257 AP_DECLARE(int) ap_is_rdirectory(apr_pool_t *p, const char *path)
2261 if (apr_stat(&finfo, path, APR_FINFO_LINK | APR_FINFO_TYPE, p) != APR_SUCCESS)
2262 return 0; /* in error condition, just return no */
2264 return (finfo.filetype == APR_DIR);
2267 AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
2270 apr_size_t len1, len2;
2273 len1 = strlen(src1);
2274 len2 = strlen(src2);
2275 /* allocate +3 for '/' delimiter, trailing NULL and overallocate
2276 * one extra byte to allow the caller to add a trailing '/'
2278 path = (char *)apr_palloc(a, len1 + len2 + 3);
2281 memcpy(path + 1, src2, len2 + 1);
2285 memcpy(path, src1, len1);
2287 if (next[-1] != '/') {
2290 memcpy(next, src2, len2 + 1);
2296 * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
2298 AP_DECLARE(int) ap_is_url(const char *u)
2302 for (x = 0; u[x] != ':'; x++) {
2304 ((!apr_isalnum(u[x])) &&
2305 (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
2310 return (x ? 1 : 0); /* If the first character is ':', it's broken, too */
2313 AP_DECLARE(int) ap_ind(const char *s, char c)
2315 const char *p = ap_strchr_c(s, c);
2322 AP_DECLARE(int) ap_rind(const char *s, char c)
2324 const char *p = ap_strrchr_c(s, c);
2331 AP_DECLARE(void) ap_str_tolower(char *str)
2334 *str = apr_tolower(*str);
2339 AP_DECLARE(void) ap_str_toupper(char *str)
2342 *str = apr_toupper(*str);
2348 * We must return a FQDN
2350 char *ap_get_local_host(apr_pool_t *a)
2352 #ifndef MAXHOSTNAMELEN
2353 #define MAXHOSTNAMELEN 256
2355 char str[MAXHOSTNAMELEN + 1];
2356 char *server_hostname = NULL;
2357 apr_sockaddr_t *sockaddr;
2360 if (apr_gethostname(str, sizeof(str) - 1, a) != APR_SUCCESS) {
2361 ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00556)
2362 "%s: apr_gethostname() failed to determine ServerName",
2365 str[sizeof(str) - 1] = '\0';
2366 if (apr_sockaddr_info_get(&sockaddr, str, APR_UNSPEC, 0, 0, a) == APR_SUCCESS) {
2367 if ( (apr_getnameinfo(&hostname, sockaddr, 0) == APR_SUCCESS) &&
2368 (ap_strchr_c(hostname, '.')) ) {
2369 server_hostname = apr_pstrdup(a, hostname);
2370 return server_hostname;
2371 } else if (ap_strchr_c(str, '.')) {
2372 server_hostname = apr_pstrdup(a, str);
2374 apr_sockaddr_ip_get(&hostname, sockaddr);
2375 server_hostname = apr_pstrdup(a, hostname);
2378 ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00557)
2379 "%s: apr_sockaddr_info_get() failed for %s",
2380 ap_server_argv0, str);
2384 if (!server_hostname)
2385 server_hostname = apr_pstrdup(a, "127.0.0.1");
2387 ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, a, APLOGNO(00558)
2388 "%s: Could not reliably determine the server's fully qualified "
2389 "domain name, using %s. Set the 'ServerName' directive globally "
2390 "to suppress this message",
2391 ap_server_argv0, server_hostname);
2393 return server_hostname;
2396 /* simple 'pool' alloc()ing glue to apr_base64.c
2398 AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
2403 decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded));
2404 l = apr_base64_decode(decoded, bufcoded);
2405 decoded[l] = '\0'; /* make binary sequence into string */
2410 AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
2413 int l = strlen(string);
2415 encoded = (char *) apr_palloc(p, 1 + apr_base64_encode_len(l));
2416 l = apr_base64_encode(encoded, string, l);
2417 encoded[l] = '\0'; /* make binary sequence into string */
2422 /* we want to downcase the type/subtype for comparison purposes
2423 * but nothing else because ;parameter=foo values are case sensitive.
2424 * XXX: in truth we want to downcase parameter names... but really,
2425 * apache has never handled parameters and such correctly. You
2426 * also need to compress spaces and such to be able to compare
2429 AP_DECLARE(void) ap_content_type_tolower(char *str)
2433 semi = strchr(str, ';');
2438 ap_str_tolower(str);
2446 * Given a string, replace any bare " with \" .
2448 AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
2451 const char *inchr = instring;
2452 char *outchr, *outstring;
2455 * Look through the input string, jogging the length of the output
2456 * string up by an extra byte each time we find an unescaped ".
2458 while (*inchr != '\0') {
2460 if (*inchr == '"') {
2464 * If we find a slosh, and it's not the last byte in the string,
2465 * it's escaping something - advance past both bytes.
2467 if ((*inchr == '\\') && (inchr[1] != '\0')) {
2473 outstring = apr_palloc(p, newlen + 1);
2477 * Now copy the input string to the output string, inserting a slosh
2478 * in front of every " that doesn't already have one.
2480 while (*inchr != '\0') {
2481 if ((*inchr == '\\') && (inchr[1] != '\0')) {
2482 *outchr++ = *inchr++;
2483 *outchr++ = *inchr++;
2485 if (*inchr == '"') {
2488 if (*inchr != '\0') {
2489 *outchr++ = *inchr++;
2497 * Given a string, append the PID deliminated by delim.
2498 * Usually used to create a pid-appended filepath name
2499 * (eg: /a/b/foo -> /a/b/foo.6726). A function, and not
2500 * a macro, to avoid unistd.h dependency
2502 AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string,
2505 return apr_psprintf(p, "%s%s%" APR_PID_T_FMT, string,
2511 * Parse a given timeout parameter string into an apr_interval_time_t value.
2512 * The unit of the time interval is given as postfix string to the numeric
2513 * string. Currently the following units are understood:
2520 * If no unit is contained in the given timeout parameter the default_time_unit
2521 * will be used instead.
2522 * @param timeout_parameter The string containing the timeout parameter.
2523 * @param timeout The timeout value to be returned.
2524 * @param default_time_unit The default time unit to use if none is specified
2525 * in timeout_parameter.
2526 * @return Status value indicating whether the parsing was successful or not.
2528 AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
2529 const char *timeout_parameter,
2530 apr_interval_time_t *timeout,
2531 const char *default_time_unit)
2534 const char *time_str;
2537 tout = apr_strtoi64(timeout_parameter, &endp, 10);
2541 if (!endp || !*endp) {
2542 time_str = default_time_unit;
2548 switch (*time_str) {
2549 /* Time is in seconds */
2551 *timeout = (apr_interval_time_t) apr_time_from_sec(tout);
2554 /* Time is in hours */
2555 *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 3600);
2558 switch (*(++time_str)) {
2559 /* Time is in milliseconds */
2561 *timeout = (apr_interval_time_t) tout * 1000;
2563 /* Time is in minutes */
2565 *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 60);
2568 return APR_EGENERAL;
2572 return APR_EGENERAL;
2578 * Determine if a request has a request body or not.
2580 * @param r the request_rec of the request
2581 * @return truth value
2583 AP_DECLARE(int) ap_request_has_body(request_rec *r)
2590 has_body = (!r->header_only
2592 || apr_table_get(r->headers_in, "Transfer-Encoding")
2593 || ( (cls = apr_table_get(r->headers_in, "Content-Length"))
2594 && (apr_strtoff(&cl, cls, &estr, 10) == APR_SUCCESS)
2602 AP_DECLARE_NONSTD(apr_status_t) ap_pool_cleanup_set_null(void *data_)
2604 void **ptr = (void **)data_;
2609 AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
2611 for ( ; *src; src++, dest++)
2613 if (!apr_isprint(*src))
2615 else if (!apr_isalnum(*src))
2625 AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
2628 char *new = apr_palloc(p, strlen(src)+1);
2632 return ap_str2_alnum(src, new);
2636 * Read the body and parse any form found, which must be of the
2637 * type application/x-www-form-urlencoded.
2639 * Name/value pairs are returned in an array, with the names as
2640 * strings with a maximum length of HUGE_STRING_LEN, and the
2641 * values as bucket brigades. This allows values to be arbitrarily
2644 * All url-encoding is removed from both the names and the values
2645 * on the fly. The names are interpreted as strings, while the
2646 * values are interpreted as blocks of binary data, that may
2647 * contain the 0 character.
2649 * In order to ensure that resource limits are not exceeded, a
2650 * maximum size must be provided. If the sum of the lengths of
2651 * the names and the values exceed this size, this function
2652 * will return HTTP_REQUEST_ENTITY_TOO_LARGE.
2654 * An optional number of parameters can be provided, if the number
2655 * of parameters provided exceeds this amount, this function will
2656 * return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
2657 * no limit is imposed, and the number of parameters is in turn
2658 * constrained by the size parameter above.
2660 * This function honours any kept_body configuration, and the
2661 * original raw request body will be saved to the kept_body brigade
2662 * if so configured, just as ap_discard_request_body does.
2664 * NOTE: File upload is not yet supported, but can be without change
2665 * to the function call.
2668 /* form parsing stuff */
2679 AP_DECLARE(int) ap_parse_form_data(request_rec *r, ap_filter_t *f,
2680 apr_array_header_t **ptr,
2681 apr_size_t num, apr_size_t usize)
2683 apr_bucket_brigade *bb = NULL;
2685 char buffer[HUGE_STRING_LEN + 1];
2687 apr_size_t offset = 0;
2689 ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
2690 ap_form_pair_t *pair = NULL;
2691 apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
2698 /* sanity check - we only support forms for now */
2699 ct = apr_table_get(r->headers_in, "Content-Type");
2700 if (!ct || ap_cstr_casecmpn("application/x-www-form-urlencoded", ct, 33)) {
2701 return ap_discard_request_body(r);
2704 if (usize > APR_SIZE_MAX >> 1)
2705 size = APR_SIZE_MAX >> 1;
2710 f = r->input_filters;
2713 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2715 apr_bucket *bucket = NULL, *last = NULL;
2717 int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
2718 APR_BLOCK_READ, HUGE_STRING_LEN);
2719 if (rv != APR_SUCCESS) {
2720 apr_brigade_destroy(bb);
2721 return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
2724 for (bucket = APR_BRIGADE_FIRST(bb);
2725 bucket != APR_BRIGADE_SENTINEL(bb);
2726 last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
2728 apr_size_t len, slide;
2731 apr_bucket_delete(last);
2733 if (APR_BUCKET_IS_EOS(bucket)) {
2737 if (bucket->length == 0) {
2741 rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
2742 if (rv != APR_SUCCESS) {
2743 apr_brigade_destroy(bb);
2744 return HTTP_BAD_REQUEST;
2748 while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
2753 else if ('&' == c) {
2757 percent = FORM_PERCENTA;
2760 if (FORM_PERCENTA == percent) {
2764 else if (c >= 'A') {
2767 else if (c >= '0') {
2771 percent = FORM_PERCENTB;
2774 if (FORM_PERCENTB == percent) {
2778 else if (c >= 'A') {
2781 else if (c >= '0') {
2785 percent = FORM_NORMAL;
2790 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2791 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2792 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2800 if (offset < HUGE_STRING_LEN) {
2804 pair = (ap_form_pair_t *) apr_array_push(pairs);
2805 pair->name = apr_pstrdup(r->pool, buffer);
2806 pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2810 buffer[offset++] = c;
2819 if (offset >= HUGE_STRING_LEN) {
2820 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2821 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2822 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2825 buffer[offset++] = c;
2835 apr_brigade_cleanup(bb);
2836 } while (!seen_eos);
2838 if (FORM_ABORT == state || size < 0 || num == 0) {
2839 return HTTP_REQUEST_ENTITY_TOO_LARGE;
2841 else if (FORM_VALUE == state && pair && offset > 0) {
2842 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2843 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2844 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2851 #define VARBUF_SMALL_SIZE 2048
2852 #define VARBUF_MAX_SIZE (APR_SIZE_MAX - 1 - \
2853 APR_ALIGN_DEFAULT(sizeof(struct ap_varbuf_info)))
2855 struct ap_varbuf_info {
2856 struct apr_memnode_t *node;
2857 apr_allocator_t *allocator;
2860 static apr_status_t varbuf_cleanup(void *info_)
2862 struct ap_varbuf_info *info = info_;
2863 info->node->next = NULL;
2864 apr_allocator_free(info->allocator, info->node);
2868 const char nul = '\0';
2869 static char * const varbuf_empty = (char *)&nul;
2871 AP_DECLARE(void) ap_varbuf_init(apr_pool_t *p, struct ap_varbuf *vb,
2872 apr_size_t init_size)
2874 vb->buf = varbuf_empty;
2876 vb->strlen = AP_VARBUF_UNKNOWN;
2880 ap_varbuf_grow(vb, init_size);
2883 AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
2885 apr_memnode_t *new_node = NULL;
2886 apr_allocator_t *allocator;
2887 struct ap_varbuf_info *new_info;
2890 AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN || vb->avail >= vb->strlen);
2892 if (new_len <= vb->avail)
2895 if (new_len < 2 * vb->avail && vb->avail < VARBUF_MAX_SIZE/2) {
2896 /* at least double the size, to avoid repeated reallocations */
2897 new_len = 2 * vb->avail;
2899 else if (new_len > VARBUF_MAX_SIZE) {
2900 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2901 ap_assert(abort_fn != NULL);
2902 abort_fn(APR_ENOMEM);
2906 new_len++; /* add space for trailing \0 */
2907 if (new_len <= VARBUF_SMALL_SIZE) {
2908 new_len = APR_ALIGN_DEFAULT(new_len);
2909 new = apr_palloc(vb->pool, new_len);
2910 if (vb->avail && vb->strlen != 0) {
2911 AP_DEBUG_ASSERT(vb->buf != NULL);
2912 AP_DEBUG_ASSERT(vb->buf != varbuf_empty);
2913 if (new == vb->buf + vb->avail + 1) {
2914 /* We are lucky: the new memory lies directly after our old
2915 * buffer, we can now use both.
2917 vb->avail += new_len;
2921 /* copy up to vb->strlen + 1 bytes */
2922 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2923 vb->avail + 1 : vb->strlen + 1);
2929 vb->avail = new_len - 1;
2934 /* The required block is rather larger. Use allocator directly so that
2935 * the memory can be freed independently from the pool. */
2936 allocator = apr_pool_allocator_get(vb->pool);
2937 if (new_len <= VARBUF_MAX_SIZE)
2938 new_node = apr_allocator_alloc(allocator,
2939 new_len + APR_ALIGN_DEFAULT(sizeof(*new_info)));
2941 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2942 ap_assert(abort_fn != NULL);
2943 abort_fn(APR_ENOMEM);
2946 new_info = (struct ap_varbuf_info *)new_node->first_avail;
2947 new_node->first_avail += APR_ALIGN_DEFAULT(sizeof(*new_info));
2948 new_info->node = new_node;
2949 new_info->allocator = allocator;
2950 new = new_node->first_avail;
2951 AP_DEBUG_ASSERT(new_node->endp - new_node->first_avail >= new_len);
2952 new_len = new_node->endp - new_node->first_avail;
2954 if (vb->avail && vb->strlen != 0)
2955 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2956 vb->avail + 1 : vb->strlen + 1);
2960 apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
2961 apr_pool_cleanup_register(vb->pool, new_info, varbuf_cleanup,
2962 apr_pool_cleanup_null);
2963 vb->info = new_info;
2965 vb->avail = new_len - 1;
2968 AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
2974 ap_varbuf_grow(vb, len);
2975 memcpy(vb->buf, str, len);
2976 vb->buf[len] = '\0';
2980 if (vb->strlen == AP_VARBUF_UNKNOWN)
2981 vb->strlen = strlen(vb->buf);
2982 ap_varbuf_grow(vb, vb->strlen + len);
2983 memcpy(vb->buf + vb->strlen, str, len);
2985 vb->buf[vb->strlen] = '\0';
2988 AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb)
2991 apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
2997 AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *buf,
2998 const char *prepend, apr_size_t prepend_len,
2999 const char *append, apr_size_t append_len,
3000 apr_size_t *new_len)
3003 struct iovec vec[3];
3006 vec[i].iov_base = (void *)prepend;
3007 vec[i].iov_len = prepend_len;
3010 if (buf->avail && buf->strlen) {
3011 if (buf->strlen == AP_VARBUF_UNKNOWN)
3012 buf->strlen = strlen(buf->buf);
3013 vec[i].iov_base = (void *)buf->buf;
3014 vec[i].iov_len = buf->strlen;
3018 vec[i].iov_base = (void *)append;
3019 vec[i].iov_len = append_len;
3023 return apr_pstrcatv(p, vec, i, new_len);
3030 AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb,
3034 ap_regmatch_t pmatch[],
3037 return regsub_core(NULL, NULL, vb, input, source, nmatch, pmatch, maxlen);
3040 static const char * const oom_message = "[crit] Memory allocation failed, "
3041 "aborting process." APR_EOL_STR;
3043 AP_DECLARE(void) ap_abort_on_oom()
3045 int written, count = strlen(oom_message);
3046 const char *buf = oom_message;
3048 written = write(STDERR_FILENO, buf, count);
3049 if (written == count)
3055 } while (written >= 0 || errno == EINTR);
3059 AP_DECLARE(void *) ap_malloc(size_t size)
3061 void *p = malloc(size);
3062 if (p == NULL && size != 0)
3067 AP_DECLARE(void *) ap_calloc(size_t nelem, size_t size)
3069 void *p = calloc(nelem, size);
3070 if (p == NULL && nelem != 0 && size != 0)
3075 AP_DECLARE(void *) ap_realloc(void *ptr, size_t size)
3077 void *p = realloc(ptr, size);
3078 if (p == NULL && size != 0)
3083 AP_DECLARE(void) ap_get_sload(ap_sload_t *ld)
3085 int i, j, server_limit, thread_limit;
3089 ap_generation_t mpm_generation;
3091 /* preload errored fields, we overwrite */
3094 ld->bytes_served = 0;
3095 ld->access_count = 0;
3097 ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
3098 ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
3099 ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
3101 for (i = 0; i < server_limit; i++) {
3103 ps = ap_get_scoreboard_process(i);
3105 for (j = 0; j < thread_limit; j++) {
3107 worker_score *ws = NULL;
3108 ws = &ap_scoreboard_image->servers[i][j];
3111 if (!ps->quiescing && ps->pid) {
3112 if (res == SERVER_READY && ps->generation == mpm_generation) {
3115 else if (res != SERVER_DEAD &&
3116 res != SERVER_STARTING && res != SERVER_IDLE_KILL &&
3117 ps->generation == mpm_generation) {
3122 if (ap_extended_status && !ps->quiescing && ps->pid) {
3123 if (ws->access_count != 0
3124 || (res != SERVER_READY && res != SERVER_DEAD)) {
3125 ld->access_count += ws->access_count;
3126 ld->bytes_served += ws->bytes_served;
3131 total = busy + ready;
3133 ld->idle = ready * 100 / total;
3134 ld->busy = busy * 100 / total;
3138 AP_DECLARE(void) ap_get_loadavg(ap_loadavg_t *ld)
3140 /* preload errored fields, we overwrite */
3142 ld->loadavg5 = -1.0;
3143 ld->loadavg15 = -1.0;
3150 num = getloadavg(la, 3);
3152 ld->loadavg = (float)la[0];
3155 ld->loadavg5 = (float)la[1];
3158 ld->loadavg15 = (float)la[2];
3164 static const char * const pw_cache_note_name = "conn_cache_note";
3166 /* varbuf contains concatenated password and hash */
3167 struct ap_varbuf vb;
3169 apr_status_t result;
3172 AP_DECLARE(apr_status_t) ap_password_validate(request_rec *r,
3173 const char *username,
3177 struct pw_cache *cache;
3180 cache = (struct pw_cache *)apr_table_get(r->connection->notes, pw_cache_note_name);
3181 if (cache != NULL) {
3182 if (strncmp(passwd, cache->vb.buf, cache->pwlen) == 0
3183 && strcmp(hash, cache->vb.buf + cache->pwlen) == 0) {
3184 return cache->result;
3186 /* make ap_varbuf_grow below not copy the old data */
3187 cache->vb.strlen = 0;
3190 cache = apr_palloc(r->connection->pool, sizeof(struct pw_cache));
3191 ap_varbuf_init(r->connection->pool, &cache->vb, 0);
3192 apr_table_setn(r->connection->notes, pw_cache_note_name, (void *)cache);
3194 cache->pwlen = strlen(passwd);
3195 hashlen = strlen(hash);
3196 ap_varbuf_grow(&cache->vb, cache->pwlen + hashlen + 1);
3197 memcpy(cache->vb.buf, passwd, cache->pwlen);
3198 memcpy(cache->vb.buf + cache->pwlen, hash, hashlen + 1);
3199 cache->result = apr_password_validate(passwd, hash);
3200 return cache->result;
3203 AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p,
3205 const char * const * argv)
3207 char buf[MAX_STRING_LEN];
3208 apr_procattr_t *procattr;
3211 apr_size_t nbytes = 1;
3215 if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
3217 if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
3218 APR_FULL_BLOCK) != APR_SUCCESS)
3220 if (apr_procattr_dir_set(procattr,
3221 ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
3223 if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
3225 proc = apr_pcalloc(p, sizeof(apr_proc_t));
3226 if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
3232 /* XXX: we are reading 1 byte at a time here */
3233 for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
3234 && nbytes == 1 && (k < MAX_STRING_LEN-1) ; ) {
3235 if (c == '\n' || c == '\r')
3242 return apr_pstrndup(p, buf, k);
3245 AP_DECLARE(int) ap_array_str_index(const apr_array_header_t *array,
3252 for (i = start; i < array->nelts; i++) {
3253 const char *p = APR_ARRAY_IDX(array, i, const char *);
3254 if (!strcmp(p, s)) {
3263 AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array,
3266 return (ap_array_str_index(array, s, 0) >= 0);
3269 #if !APR_CHARSET_EBCDIC
3271 * Our own known-fast translation table for casecmp by character.
3272 * Only ASCII alpha characters 41-5A are folded to 61-7A, other
3273 * octets (such as extended latin alphabetics) are never case-folded.
3274 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3276 static const short ucharmap[] = {
3277 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
3278 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
3279 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3280 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3281 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3282 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3283 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3284 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3285 0x40, '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', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3289 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3290 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3291 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3292 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3293 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3294 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3295 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3296 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3297 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3298 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3299 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3300 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3301 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3302 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3303 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3304 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3305 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3306 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3307 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3308 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3310 #else /* APR_CHARSET_EBCDIC */
3312 * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison,
3313 * provides unique identity of every char value (strict ISO-646
3314 * conformance, arbitrary election of an ISO-8859-1 ordering, and
3315 * very arbitrary control code assignments into C1 to achieve
3316 * identity and a reversible mapping of code points),
3317 * then folding the equivalences of ASCII 41-5A into 61-7A,
3318 * presenting comparison results in a somewhat ISO/IEC 10646
3319 * (ASCII-like) order, depending on the EBCDIC code page in use.
3321 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3323 static const short ucharmap[] = {
3324 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
3325 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
3326 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
3327 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
3328 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
3329 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
3330 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
3331 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
3332 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,
3333 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
3334 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,
3335 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
3336 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,
3337 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
3338 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,
3339 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
3340 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3341 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,
3342 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3343 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,
3344 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3345 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE,
3346 0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,
3347 0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7,
3348 0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3349 0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,
3350 0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3351 0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,
3352 0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3353 0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,
3354 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3355 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F
3359 AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2)
3361 const unsigned char *str1 = (const unsigned char *)s1;
3362 const unsigned char *str2 = (const unsigned char *)s2;
3365 const int c1 = (int)(*str1);
3366 const int c2 = (int)(*str2);
3367 const int cmp = ucharmap[c1] - ucharmap[c2];
3368 /* Not necessary to test for !c2, this is caught by cmp */
3376 AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
3378 const unsigned char *str1 = (const unsigned char *)s1;
3379 const unsigned char *str2 = (const unsigned char *)s2;
3382 const int c1 = (int)(*str1);
3383 const int c2 = (int)(*str2);
3384 const int cmp = ucharmap[c1] - ucharmap[c2];
3385 /* Not necessary to test for !c2, this is caught by cmp */