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"
51 #include "apr_fnmatch.h"
53 #include "http_main.h"
55 #include "http_protocol.h"
56 #include "http_config.h"
57 #include "http_core.h"
58 #include "util_ebcdic.h"
59 #include "util_varbuf.h"
67 #ifdef HAVE_SYS_LOADAVG_H
68 #include <sys/loadavg.h>
73 /* A bunch of functions in util.c scan strings looking for certain characters.
74 * To make that more efficient we encode a lookup table. The test_char_table
75 * is generated automatically by gen_test_char.c.
77 #include "test_char.h"
79 /* Win32/NetWare/OS2 need to check for both forward and back slashes
80 * in ap_getparents() and ap_escape_url.
82 #ifdef CASE_BLIND_FILESYSTEM
83 #define IS_SLASH(s) ((s == '/') || (s == '\\'))
86 #define IS_SLASH(s) (s == '/')
90 /* we know core's module_index is 0 */
91 #undef APLOG_MODULE_INDEX
92 #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
94 /* maximum nesting level for config directories */
95 #ifndef AP_MAX_FNMATCH_DIR_DEPTH
96 #define AP_MAX_FNMATCH_DIR_DEPTH (128)
100 * Examine a field value (such as a media-/content-type) string and return
101 * it sans any parameters; e.g., strip off any ';charset=foo' and the like.
103 AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype)
107 if (intype == NULL) return NULL;
109 semi = ap_strchr_c(intype, ';');
111 return apr_pstrdup(p, intype);
114 while ((semi > intype) && apr_isspace(semi[-1])) {
117 return apr_pstrmemdup(p, intype, semi - intype);
121 AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt,
125 char ts[MAX_STRING_LEN];
126 char tf[MAX_STRING_LEN];
133 apr_time_exp_gmt(&xt, t);
134 /* Convert %Z to "GMT" and %z to "+0000";
135 * on hosts that do not have a time zone string in struct tm,
136 * strftime must assume its argument is local time.
138 for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f)
140 if (*f != '%') continue;
151 case 'z': /* common extension */
165 apr_time_exp_lt(&xt, t);
168 /* check return code? */
169 apr_strftime(ts, &retcode, MAX_STRING_LEN, fmt, &xt);
170 ts[MAX_STRING_LEN - 1] = '\0';
171 return apr_pstrdup(p, ts);
174 /* Roy owes Rob beer. */
175 /* Rob owes Roy dinner. */
177 /* These legacy comments would make a lot more sense if Roy hadn't
178 * replaced the old later_than() routine with util_date.c.
180 * Well, okay, they still wouldn't make any sense.
183 /* Match = 0, NoMatch = 1, Abort = -1
184 * Based loosely on sections of wildmat.c by Rich Salz
185 * Hmmm... shouldn't this really go component by component?
187 AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected)
191 for (x = 0, y = 0; expected[y]; ++y, ++x) {
192 if (expected[y] == '*') {
193 while (expected[++y] == '*');
198 if ((ret = ap_strcmp_match(&str[x++], &expected[y])) != 1)
205 else if ((expected[y] != '?') && (str[x] != expected[y]))
208 return (str[x] != '\0');
211 AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
215 for (x = 0, y = 0; expected[y]; ++y, ++x) {
216 if (!str[x] && expected[y] != '*')
218 if (expected[y] == '*') {
219 while (expected[++y] == '*');
224 if ((ret = ap_strcasecmp_match(&str[x++], &expected[y])) != 1)
229 else if (expected[y] != '?'
230 && apr_tolower(str[x]) != apr_tolower(expected[y]))
233 return (str[x] != '\0');
236 /* We actually compare the canonical root to this root, (but we don't
237 * waste time checking the case), since every use of this function in
238 * httpd-2.1 tests if the path is 'proper', meaning we've already passed
239 * it through apr_filepath_merge, or we haven't.
241 AP_DECLARE(int) ap_os_is_path_absolute(apr_pool_t *p, const char *dir)
244 const char *ourdir = dir;
245 if (apr_filepath_root(&newpath, &dir, 0, p) != APR_SUCCESS
246 || strncmp(newpath, ourdir, strlen(newpath)) != 0) {
252 AP_DECLARE(int) ap_is_matchexp(const char *str)
256 for (x = 0; str[x]; x++)
257 if ((str[x] == '*') || (str[x] == '?'))
263 * Here's a pool-based interface to the POSIX-esque ap_regcomp().
264 * Note that we return ap_regex_t instead of being passed one.
265 * The reason is that if you use an already-used ap_regex_t structure,
266 * the memory that you've already allocated gets forgotten, and
267 * regfree() doesn't clear it. So we don't allow it.
270 static apr_status_t regex_cleanup(void *preg)
272 ap_regfree((ap_regex_t *) preg);
276 AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
279 ap_regex_t *preg = apr_palloc(p, sizeof *preg);
280 int err = ap_regcomp(preg, pattern, cflags);
282 if (err == AP_REG_ESPACE)
287 apr_pool_cleanup_register(p, (void *) preg, regex_cleanup,
288 apr_pool_cleanup_null);
293 AP_DECLARE(void) ap_pregfree(apr_pool_t *p, ap_regex_t *reg)
296 apr_pool_cleanup_kill(p, (void *) reg, regex_cleanup);
300 * Similar to standard strstr() but we ignore case in this version.
301 * Based on the strstr() implementation further below.
303 AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2)
311 for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
315 /* found first character of s2, see if the rest matches */
318 for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) {
320 /* both strings ended together */
325 /* second string ended, a match */
328 /* didn't find a match here, try starting at next character in s1 */
335 * Returns an offsetted pointer in bigstring immediately after
336 * prefix. Returns bigstring if bigstring doesn't start with
337 * prefix or if prefix is longer than bigstring while still matching.
338 * NOTE: pointer returned is relative to bigstring, so we
339 * can use standard pointer comparisons in the calling function
340 * (eg: test if ap_stripprefix(a,b) == a)
342 AP_DECLARE(const char *) ap_stripprefix(const char *bigstring,
351 while (*p1 && *prefix) {
352 if (*p1++ != *prefix++)
358 /* hit the end of bigstring! */
362 /* This function substitutes for $0-$9, filling in regular expression
363 * submatches. Pass it the same nmatch and pmatch arguments that you
364 * passed ap_regexec(). pmatch should not be greater than the maximum number
365 * of subexpressions - i.e. one more than the re_nsub member of ap_regex_t.
367 * nmatch must be <=AP_MAX_REG_MATCH (10).
369 * input should be the string with the $-expressions, source should be the
370 * string that was matched against.
372 * It returns the substituted string, or NULL if a vbuf is used.
373 * On errors, returns the orig string.
375 * Parts of this code are based on Henry Spencer's regsub(), from his
376 * AT&T V8 regexp package.
379 static apr_status_t regsub_core(apr_pool_t *p, char **result,
380 struct ap_varbuf *vb, const char *input,
381 const char *source, apr_size_t nmatch,
382 ap_regmatch_t pmatch[], apr_size_t maxlen)
384 const char *src = input;
390 AP_DEBUG_ASSERT((result && p && !vb) || (vb && !p && !result));
391 if (!source || nmatch>AP_MAX_REG_MATCH)
395 if (maxlen > 0 && len >= maxlen)
398 *result = apr_pstrmemdup(p, src, len);
402 ap_varbuf_strmemcat(vb, src, len);
407 /* First pass, find the size */
408 while ((c = *src++) != '\0') {
409 if (c == '$' && apr_isdigit(*src))
412 no = AP_MAX_REG_MATCH;
414 if (no >= AP_MAX_REG_MATCH) { /* Ordinary character. */
415 if (c == '\\' && *src)
419 else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
420 if (APR_SIZE_MAX - len <= pmatch[no].rm_eo - pmatch[no].rm_so)
422 len += pmatch[no].rm_eo - pmatch[no].rm_so;
427 if (len >= maxlen && maxlen > 0)
431 *result = dst = apr_palloc(p, len + 1);
434 if (vb->strlen == AP_VARBUF_UNKNOWN)
435 vb->strlen = strlen(vb->buf);
436 ap_varbuf_grow(vb, vb->strlen + len);
437 dst = vb->buf + vb->strlen;
441 /* Now actually fill in the string */
445 while ((c = *src++) != '\0') {
446 if (c == '$' && apr_isdigit(*src))
449 no = AP_MAX_REG_MATCH;
451 if (no >= AP_MAX_REG_MATCH) { /* Ordinary character. */
452 if (c == '\\' && *src)
456 else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
457 len = pmatch[no].rm_eo - pmatch[no].rm_so;
458 memcpy(dst, source + pmatch[no].rm_so, len);
468 #ifndef AP_PREGSUB_MAXLEN
469 #define AP_PREGSUB_MAXLEN (HUGE_STRING_LEN * 8)
471 AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
472 const char *source, apr_size_t nmatch,
473 ap_regmatch_t pmatch[])
476 apr_status_t rc = regsub_core(p, &result, NULL, input, source, nmatch,
477 pmatch, AP_PREGSUB_MAXLEN);
478 if (rc != APR_SUCCESS)
483 AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result,
484 const char *input, const char *source,
485 apr_size_t nmatch, ap_regmatch_t pmatch[],
488 apr_status_t rc = regsub_core(p, result, NULL, input, source, nmatch,
490 if (rc != APR_SUCCESS)
496 * Parse .. so we don't compromise security
498 AP_DECLARE(void) ap_getparents(char *name)
503 /* Four paseses, as per RFC 1808 */
504 /* a) remove ./ path segments */
505 for (next = name; *next && (*next != '.'); next++) {
508 l = w = first_dot = next - name;
509 while (name[l] != '\0') {
510 if (name[l] == '.' && IS_SLASH(name[l + 1])
511 && (l == 0 || IS_SLASH(name[l - 1])))
514 name[w++] = name[l++];
517 /* b) remove trailing . path, segment */
518 if (w == 1 && name[0] == '.')
520 else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2]))
524 /* c) remove all xx/../ segments. (including leading ../ and /../) */
527 while (name[l] != '\0') {
528 if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2])
529 && (l == 0 || IS_SLASH(name[l - 1]))) {
534 while (l >= 0 && !IS_SLASH(name[l]))
541 while ((name[n] = name[m]))
548 /* d) remove trailing xx/.. segment. */
549 if (l == 2 && name[0] == '.' && name[1] == '.')
551 else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
552 && IS_SLASH(name[l - 3])) {
555 while (l >= 0 && !IS_SLASH(name[l]))
564 AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path)
575 #ifdef HAVE_UNC_PATHS
576 /* Check for UNC names. Leave leading two slashes. */
577 if (is_fs_path && s[0] == '/' && s[1] == '/')
582 if ((*d++ = *s) == '/') {
594 AP_DECLARE(void) ap_no2slash(char *name)
596 ap_no2slash_ex(name, 1);
600 * copy at most n leading directories of s into d
601 * d should be at least as large as s plus 1 extra byte
603 * the return value is the ever useful pointer to the trailing \0 of d
605 * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments,
606 * so that if n == 0, "/" is returned in d with n == 1
607 * and s == "e:/test.html", "e:/" is returned in d
608 * *** See also ap_directory_walk in server/request.c
611 * /a/b, 0 ==> / (true for all platforms)
620 * c:/a/b 3 ==> c:/a/b
621 * c:/a/b 4 ==> c:/a/b
623 AP_DECLARE(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
632 if (*s == '\0' || (*s == '/' && (--n) == 0)) {
644 * return the parent directory name including trailing / of the file s
646 AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s)
648 const char *last_slash = ap_strrchr_c(s, '/');
652 if (last_slash == NULL) {
653 return apr_pstrdup(p, "");
655 l = (last_slash - s) + 1;
656 d = apr_pstrmemdup(p, s, l);
662 AP_DECLARE(int) ap_count_dirs(const char *path)
666 for (x = 0, n = 0; path[x]; x++)
672 AP_DECLARE(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop)
674 return ap_getword(atrans, (const char **) line, stop);
677 AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop)
679 const char *pos = *line;
683 while ((*pos != stop) && *pos) {
688 res = apr_pstrmemdup(atrans, *line, len);
691 while (*pos == stop) {
700 AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
702 return ap_getword_white(atrans, (const char **) line);
705 AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
707 const char *pos = *line;
711 while (!apr_isspace(*pos) && *pos) {
716 res = apr_pstrmemdup(atrans, *line, len);
718 while (apr_isspace(*pos)) {
727 AP_DECLARE(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line,
730 return ap_getword_nulls(atrans, (const char **) line, stop);
733 AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line,
736 const char *pos = ap_strchr_c(*line, stop);
740 apr_size_t len = strlen(*line);
741 res = apr_pstrmemdup(atrans, *line, len);
746 res = apr_pstrmemdup(atrans, *line, pos - *line);
755 /* Get a word, (new) config-file style --- quoted strings and backslashes
759 static char *substring_conf(apr_pool_t *p, const char *start, int len,
762 char *result = apr_palloc(p, len + 1);
766 for (i = 0; i < len; ++i) {
767 if (start[i] == '\\' && (start[i + 1] == '\\'
768 || (quote && start[i + 1] == quote)))
769 *resp++ = start[++i];
775 #if RESOLVE_ENV_PER_TOKEN
776 return (char *)ap_resolve_env(p,result);
782 AP_DECLARE(char *) ap_getword_conf_nc(apr_pool_t *p, char **line)
784 return ap_getword_conf(p, (const char **) line);
787 AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line)
789 const char *str = *line, *strend;
793 while (apr_isspace(*str))
801 if ((quote = *str) == '"' || quote == '\'') {
803 while (*strend && *strend != quote) {
804 if (*strend == '\\' && strend[1] &&
805 (strend[1] == quote || strend[1] == '\\')) {
812 res = substring_conf(p, str + 1, strend - str - 1, quote);
814 if (*strend == quote)
819 while (*strend && !apr_isspace(*strend))
822 res = substring_conf(p, str, strend - str, 0);
825 while (apr_isspace(*strend))
831 AP_DECLARE(char *) ap_getword_conf2_nc(apr_pool_t *p, char **line)
833 return ap_getword_conf2(p, (const char **) line);
836 AP_DECLARE(char *) ap_getword_conf2(apr_pool_t *p, const char **line)
838 const char *str = *line, *strend;
843 while (apr_isspace(*str))
851 if ((quote = *str) == '"' || quote == '\'')
852 return ap_getword_conf(p, line);
857 if (*strend == '}' && !--count)
861 if (*strend == '\\' && strend[1] == '\\') {
866 res = substring_conf(p, str + 1, strend - str - 1, 0);
873 while (*strend && !apr_isspace(*strend))
876 res = substring_conf(p, str, strend - str, 0);
879 while (apr_isspace(*strend))
885 AP_DECLARE(int) ap_cfg_closefile(ap_configfile_t *cfp)
888 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00551)
889 "Done with config file %s", cfp->name);
891 return (cfp->close == NULL) ? 0 : cfp->close(cfp->param);
894 /* we can't use apr_file_* directly because of linking issues on Windows */
895 static apr_status_t cfg_close(void *param)
897 return apr_file_close(param);
900 static apr_status_t cfg_getch(char *ch, void *param)
902 return apr_file_getc(ch, param);
905 static apr_status_t cfg_getstr(void *buf, apr_size_t bufsiz, void *param)
907 return apr_file_gets(buf, bufsiz, param);
910 /* Open a ap_configfile_t as FILE, return open ap_configfile_t struct pointer */
911 AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg,
912 apr_pool_t *p, const char *name)
914 ap_configfile_t *new_cfg;
915 apr_file_t *file = NULL;
923 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00552)
924 "Internal error: pcfg_openfile() called with NULL filename");
928 status = apr_file_open(&file, name, APR_READ | APR_BUFFERED,
931 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00553)
932 "Opening config file %s (%s)",
933 name, (status != APR_SUCCESS) ?
934 apr_strerror(status, buf, sizeof(buf)) : "successful");
936 if (status != APR_SUCCESS)
939 status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file);
940 if (status != APR_SUCCESS)
943 if (finfo.filetype != APR_REG &&
944 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
945 ap_cstr_casecmp(apr_filepath_name_get(name), "nul") != 0) {
947 strcmp(name, "/dev/null") != 0) {
948 #endif /* WIN32 || OS2 */
949 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00554)
950 "Access to file %s denied by server: not a regular file",
952 apr_file_close(file);
957 /* Some twisted character [no pun intended] at MS decided that a
958 * zero width joiner as the lead wide character would be ideal for
959 * describing Unicode text files. This was further convoluted to
960 * another MSism that the same character mapped into utf-8, EF BB BF
961 * would signify utf-8 text files.
963 * Since MS configuration files are all protecting utf-8 encoded
964 * Unicode path, file and resource names, we already have the correct
965 * WinNT encoding. But at least eat the stupid three bytes up front.
968 unsigned char buf[4];
970 status = apr_file_read(file, buf, &len);
971 if ((status != APR_SUCCESS) || (len < 3)
972 || memcmp(buf, "\xEF\xBB\xBF", 3) != 0) {
974 apr_file_seek(file, APR_SET, &zero);
979 new_cfg = apr_palloc(p, sizeof(*new_cfg));
980 new_cfg->param = file;
981 new_cfg->name = apr_pstrdup(p, name);
982 new_cfg->getch = cfg_getch;
983 new_cfg->getstr = cfg_getstr;
984 new_cfg->close = cfg_close;
985 new_cfg->line_number = 0;
991 /* Allocate a ap_configfile_t handle with user defined functions and params */
992 AP_DECLARE(ap_configfile_t *) ap_pcfg_open_custom(
993 apr_pool_t *p, const char *descr, void *param,
994 apr_status_t (*getc_func) (char *ch, void *param),
995 apr_status_t (*gets_func) (void *buf, apr_size_t bufsize, void *param),
996 apr_status_t (*close_func) (void *param))
998 ap_configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg));
999 new_cfg->param = param;
1000 new_cfg->name = descr;
1001 new_cfg->getch = getc_func;
1002 new_cfg->getstr = gets_func;
1003 new_cfg->close = close_func;
1004 new_cfg->line_number = 0;
1008 /* Read one character from a configfile_t */
1009 AP_DECLARE(apr_status_t) ap_cfg_getc(char *ch, ap_configfile_t *cfp)
1011 apr_status_t rc = cfp->getch(ch, cfp->param);
1012 if (rc == APR_SUCCESS && *ch == LF)
1017 AP_DECLARE(const char *) ap_pcfg_strerror(apr_pool_t *p, ap_configfile_t *cfp,
1020 if (rc == APR_SUCCESS)
1023 if (rc == APR_ENOSPC)
1024 return apr_psprintf(p, "Error reading %s at line %d: Line too long",
1025 cfp->name, cfp->line_number);
1027 return apr_psprintf(p, "Error reading %s at line %d: %pm",
1028 cfp->name, cfp->line_number, &rc);
1031 /* Read one line from open ap_configfile_t, strip LF, increase line number */
1032 /* If custom handler does not define a getstr() function, read char by char */
1033 static apr_status_t ap_cfg_getline_core(char *buf, apr_size_t bufsize,
1034 apr_size_t offset, ap_configfile_t *cfp)
1037 /* If a "get string" function is defined, use it */
1038 if (cfp->getstr != NULL) {
1040 char *cbuf = buf + offset;
1041 apr_size_t cbufsize = bufsize - offset;
1045 rc = cfp->getstr(cbuf, cbufsize, cfp->param);
1046 if (rc == APR_EOF) {
1047 if (cbuf != buf + offset) {
1055 if (rc != APR_SUCCESS) {
1060 * check for line continuation,
1061 * i.e. match [^\\]\\[\r]\n only
1065 if (cp > buf && cp[-1] == LF) {
1067 if (cp > buf && cp[-1] == CR)
1069 if (cp > buf && cp[-1] == '\\') {
1072 * line continuation requested -
1073 * then remove backslash and continue
1075 cbufsize -= (cp-cbuf);
1080 else if (cp - buf >= bufsize - 1) {
1086 /* No "get string" function defined; read character by character */
1087 apr_size_t i = offset;
1090 /* too small, assume caller is crazy */
1097 rc = cfp->getch(&c, cfp->param);
1098 if (rc == APR_EOF) {
1104 if (rc != APR_SUCCESS)
1108 /* check for line continuation */
1109 if (i > 0 && buf[i-1] == '\\') {
1119 if (i >= bufsize - 1) {
1128 static int cfg_trim_line(char *buf)
1132 * Leading and trailing white space is eliminated completely
1135 while (apr_isspace(*start))
1137 /* blast trailing whitespace */
1138 end = &start[strlen(start)];
1139 while (--end >= start && apr_isspace(*end))
1141 /* Zap leading whitespace by shifting */
1143 memmove(buf, start, end - start + 2);
1144 #ifdef DEBUG_CFG_LINES
1145 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, APLOGNO(00555) "Read config: '%s'", buf);
1147 return end - start + 1;
1150 /* Read one line from open ap_configfile_t, strip LF, increase line number */
1151 /* If custom handler does not define a getstr() function, read char by char */
1152 AP_DECLARE(apr_status_t) ap_cfg_getline(char *buf, apr_size_t bufsize,
1153 ap_configfile_t *cfp)
1155 apr_status_t rc = ap_cfg_getline_core(buf, bufsize, 0, cfp);
1156 if (rc == APR_SUCCESS)
1161 AP_DECLARE(apr_status_t) ap_varbuf_cfg_getline(struct ap_varbuf *vb,
1162 ap_configfile_t *cfp,
1170 if (vb->strlen == AP_VARBUF_UNKNOWN)
1171 vb->strlen = strlen(vb->buf);
1172 if (vb->avail - vb->strlen < 3) {
1173 new_len = vb->avail * 2;
1174 if (new_len > max_len)
1176 else if (new_len < 3)
1178 ap_varbuf_grow(vb, new_len);
1182 rc = ap_cfg_getline_core(vb->buf, vb->avail, vb->strlen, cfp);
1183 if (rc == APR_ENOSPC || rc == APR_SUCCESS)
1184 vb->strlen += strlen(vb->buf + vb->strlen);
1185 if (rc != APR_ENOSPC)
1187 if (vb->avail >= max_len)
1189 new_len = vb->avail * 2;
1190 if (new_len > max_len)
1192 ap_varbuf_grow(vb, new_len);
1195 if (vb->strlen > max_len)
1197 if (rc == APR_SUCCESS)
1198 vb->strlen = cfg_trim_line(vb->buf);
1202 /* Size an HTTP header field list item, as separated by a comma.
1203 * The return value is a pointer to the beginning of the non-empty list item
1204 * within the original string (or NULL if there is none) and the address
1205 * of field is shifted to the next non-comma, non-whitespace character.
1206 * len is the length of the item excluding any beginning whitespace.
1208 AP_DECLARE(const char *) ap_size_list_item(const char **field, int *len)
1210 const unsigned char *ptr = (const unsigned char *)*field;
1211 const unsigned char *token;
1212 int in_qpair, in_qstr, in_com;
1214 /* Find first non-comma, non-whitespace byte */
1216 while (*ptr == ',' || apr_isspace(*ptr))
1221 /* Find the end of this item, skipping over dead bits */
1223 for (in_qpair = in_qstr = in_com = 0;
1224 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1232 case '\\': in_qpair = 1; /* quoted-pair */
1234 case '"' : if (!in_com) /* quoted string delim */
1237 case '(' : if (!in_qstr) /* comment (may nest) */
1240 case ')' : if (in_com) /* end comment */
1248 if ((*len = (ptr - token)) == 0) {
1249 *field = (const char *)ptr;
1253 /* Advance field pointer to the next non-comma, non-white byte */
1255 while (*ptr == ',' || apr_isspace(*ptr))
1258 *field = (const char *)ptr;
1259 return (const char *)token;
1262 /* Retrieve an HTTP header field list item, as separated by a comma,
1263 * while stripping insignificant whitespace and lowercasing anything not in
1264 * a quoted string or comment. The return value is a new string containing
1265 * the converted list item (or NULL if none) and the address pointed to by
1266 * field is shifted to the next non-comma, non-whitespace.
1268 AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field)
1270 const char *tok_start;
1271 const unsigned char *ptr;
1274 int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
1276 /* Find the beginning and maximum length of the list item so that
1277 * we can allocate a buffer for the new string and reset the field.
1279 if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
1282 token = apr_palloc(p, tok_len + 1);
1284 /* Scan the token again, but this time copy only the good bytes.
1285 * We skip extra whitespace and any whitespace around a '=', '/',
1286 * or ';' and lowercase normal characters not within a comment,
1287 * quoted-string or quoted-pair.
1289 for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
1290 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1299 case '\\': in_qpair = 1;
1305 case '"' : if (!in_com)
1312 case '(' : if (!in_qstr)
1319 case ')' : if (in_com)
1325 case '\t': if (addspace)
1327 if (in_com || in_qstr)
1334 case ';' : if (!(in_com || in_qstr))
1338 default : if (addspace == 1)
1340 *pos++ = (in_com || in_qstr) ? *ptr
1341 : apr_tolower(*ptr);
1352 typedef enum ap_etag_e {
1358 /* Find an item in canonical form (lowercase, no extra spaces) within
1359 * an HTTP field value list. Returns 1 if found, 0 if not found.
1360 * This would be much more efficient if we stored header fields as
1361 * an array of list items as they are received instead of a plain string.
1363 static int find_list_item(apr_pool_t *p, const char *line,
1364 const char *tok, ap_etag_e type)
1366 const unsigned char *pos;
1367 const unsigned char *ptr = (const unsigned char *)line;
1368 int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
1370 if (!line || !tok) {
1373 if (type == AP_ETAG_STRONG && *tok != '\"') {
1376 if (type == AP_ETAG_WEAK) {
1377 if (*tok == 'W' && (*(tok+1)) == '/' && (*(tok+2)) == '\"') {
1380 else if (*tok != '\"') {
1385 do { /* loop for each item in line's list */
1387 /* Find first non-comma, non-whitespace byte */
1388 while (*ptr == ',' || apr_isspace(*ptr)) {
1392 /* Account for strong or weak Etags, depending on our search */
1393 if (type == AP_ETAG_STRONG && *ptr != '\"') {
1396 if (type == AP_ETAG_WEAK) {
1397 if (*ptr == 'W' && (*(ptr+1)) == '/' && (*(ptr+2)) == '\"') {
1400 else if (*ptr != '\"') {
1406 good = 1; /* until proven otherwise for this item */
1408 break; /* no items left and nothing good found */
1410 /* We skip extra whitespace and any whitespace around a '=', '/',
1411 * or ';' and lowercase normal characters not within a comment,
1412 * quoted-string or quoted-pair.
1414 for (pos = (const unsigned char *)tok;
1415 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1421 good = (*pos++ == *ptr);
1425 case '\\': in_qpair = 1;
1427 good = good && (*pos++ == ' ');
1428 good = good && (*pos++ == *ptr);
1431 case '"' : if (!in_com)
1434 good = good && (*pos++ == ' ');
1435 good = good && (*pos++ == *ptr);
1438 case '(' : if (!in_qstr)
1441 good = good && (*pos++ == ' ');
1442 good = good && (*pos++ == *ptr);
1445 case ')' : if (in_com)
1447 good = good && (*pos++ == *ptr);
1451 case '\t': if (addspace || !good)
1453 if (in_com || in_qstr)
1454 good = (*pos++ == *ptr);
1460 case ';' : if (!(in_com || in_qstr))
1462 good = good && (*pos++ == *ptr);
1464 default : if (!good)
1467 good = (*pos++ == ' ');
1468 if (in_com || in_qstr)
1469 good = good && (*pos++ == *ptr);
1472 && (apr_tolower(*pos++) == apr_tolower(*ptr));
1479 good = 0; /* not good if only a prefix was matched */
1481 } while (*ptr && !good);
1486 /* Find an item in canonical form (lowercase, no extra spaces) within
1487 * an HTTP field value list. Returns 1 if found, 0 if not found.
1488 * This would be much more efficient if we stored header fields as
1489 * an array of list items as they are received instead of a plain string.
1491 AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line,
1494 return find_list_item(p, line, tok, AP_ETAG_NONE);
1497 /* Find a strong Etag in canonical form (lowercase, no extra spaces) within
1498 * an HTTP field value list. Returns 1 if found, 0 if not found.
1500 AP_DECLARE(int) ap_find_etag_strong(apr_pool_t *p, const char *line,
1503 return find_list_item(p, line, tok, AP_ETAG_STRONG);
1506 /* Find a weak ETag in canonical form (lowercase, no extra spaces) within
1507 * an HTTP field value list. Returns 1 if found, 0 if not found.
1509 AP_DECLARE(int) ap_find_etag_weak(apr_pool_t *p, const char *line,
1512 return find_list_item(p, line, tok, AP_ETAG_WEAK);
1515 /* Grab a list of tokens of the format 1#token (from RFC7230) */
1516 AP_DECLARE(const char *) ap_parse_token_list_strict(apr_pool_t *p,
1518 apr_array_header_t **tokens,
1521 int in_leading_space = 1;
1522 int in_trailing_space = 0;
1524 const char *tok_begin;
1531 tok_begin = cur = str_in;
1533 while (!string_end) {
1534 const unsigned char c = (unsigned char)*cur;
1536 if (!TEST_CHAR(c, T_HTTP_TOKEN_STOP)) {
1537 /* Non-separator character; we are finished with leading
1538 * whitespace. We must never have encountered any trailing
1539 * whitespace before the delimiter (comma) */
1540 in_leading_space = 0;
1541 if (in_trailing_space) {
1542 return "Encountered illegal whitespace in token";
1545 else if (c == ' ' || c == '\t') {
1546 /* "Linear whitespace" only includes ASCII CRLF, space, and tab;
1547 * we can't get a CRLF since headers are split on them already,
1548 * so only look for a space or a tab */
1549 if (in_leading_space) {
1550 /* We're still in leading whitespace */
1554 /* We must be in trailing whitespace */
1555 ++in_trailing_space;
1558 else if (c == ',' || c == '\0') {
1559 if (!in_leading_space) {
1560 /* If we're out of the leading space, we know we've read some
1561 * characters of a token */
1562 if (*tokens == NULL) {
1563 *tokens = apr_array_make(p, 4, sizeof(char *));
1565 APR_ARRAY_PUSH(*tokens, char *) =
1566 apr_pstrmemdup((*tokens)->pool, tok_begin,
1567 (cur - tok_begin) - in_trailing_space);
1569 /* We're allowed to have null elements, just don't add them to the
1572 tok_begin = cur + 1;
1573 in_leading_space = 1;
1574 in_trailing_space = 0;
1575 string_end = (c == '\0');
1578 /* Encountered illegal separator char */
1580 /* Skip to the next separator */
1582 temp = ap_strchr_c(cur, ',');
1584 temp = ap_strchr_c(cur, '\0');
1587 /* Act like we haven't seen a token so we reset */
1589 in_leading_space = 1;
1590 in_trailing_space = 0;
1593 return apr_psprintf(p, "Encountered illegal separator "
1594 "'\\x%.2x'", (unsigned int)c);
1604 /* Scan a string for HTTP VCHAR/obs-text characters including HT and SP
1605 * (as used in header values, for example, in RFC 7230 section 3.2)
1606 * returning the pointer to the first non-HT ASCII ctrl character.
1608 AP_DECLARE(const char *) ap_scan_http_field_content(const char *ptr)
1610 for ( ; !TEST_CHAR(*ptr, T_HTTP_CTRLS); ++ptr) ;
1615 /* Scan a string for HTTP token characters, returning the pointer to
1616 * the first non-token character.
1618 AP_DECLARE(const char *) ap_scan_http_token(const char *ptr)
1620 for ( ; !TEST_CHAR(*ptr, T_HTTP_TOKEN_STOP); ++ptr) ;
1625 /* Scan a string for visible ASCII (0x21-0x7E) or obstext (0x80+)
1626 * and return a pointer to the first ctrl/space character encountered.
1628 AP_DECLARE(const char *) ap_scan_vchar_obstext(const char *ptr)
1630 for ( ; TEST_CHAR(*ptr, T_VCHAR_OBSTEXT); ++ptr) ;
1635 /* Retrieve a token, spacing over it and returning a pointer to
1636 * the first non-white byte afterwards. Note that these tokens
1637 * are delimited by semis and commas; and can also be delimited
1638 * by whitespace at the caller's option.
1641 AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line,
1644 const char *ptr = *accept_line;
1645 const char *tok_start;
1648 /* Find first non-white byte */
1650 while (apr_isspace(*ptr))
1655 /* find token end, skipping over quoted strings.
1656 * (comments are already gone).
1659 while (*ptr && (accept_white || !apr_isspace(*ptr))
1660 && *ptr != ';' && *ptr != ',') {
1667 token = apr_pstrmemdup(p, tok_start, ptr - tok_start);
1669 /* Advance accept_line pointer to the next non-white byte */
1671 while (apr_isspace(*ptr))
1679 /* find http tokens, see the definition of token from RFC2068 */
1680 AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
1682 const unsigned char *start_token;
1683 const unsigned char *s;
1688 s = (const unsigned char *)line;
1690 /* find start of token, skip all stop characters */
1691 while (*s && TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1698 /* find end of the token */
1699 while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1702 if (!ap_cstr_casecmpn((const char *)start_token, (const char *)tok,
1713 AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line,
1716 int llen, tlen, lidx;
1721 llen = strlen(line);
1726 (lidx > 0 && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1729 return (ap_cstr_casecmpn(&line[lidx], tok, tlen) == 0);
1732 AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1736 const unsigned char *s;
1738 cmd = apr_palloc(p, 2 * strlen(str) + 1); /* Be safe */
1739 d = (unsigned char *)cmd;
1740 s = (const unsigned char *)str;
1743 #if defined(OS2) || defined(WIN32)
1745 * Newlines to Win32/OS2 CreateProcess() are ill advised.
1746 * Convert them to spaces since they are effectively white
1747 * space to most applications
1749 if (*s == '\r' || *s == '\n') {
1755 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1765 static char x2c(const char *what)
1769 #if !APR_CHARSET_EBCDIC
1770 digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
1773 digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
1775 #else /*APR_CHARSET_EBCDIC*/
1782 digit = apr_xlate_conv_byte(ap_hdrs_from_ascii,
1783 0xFF & strtol(xstr, NULL, 16));
1784 #endif /*APR_CHARSET_EBCDIC*/
1789 * Unescapes a URL, leaving reserved characters intact.
1790 * Returns 0 on success, non-zero on error
1792 * bad % escape returns HTTP_BAD_REQUEST
1794 * decoding %00 or a forbidden character returns HTTP_NOT_FOUND
1797 static int unescape_url(char *url, const char *forbid, const char *reserved)
1799 int badesc, badpath;
1808 /* Initial scan for first '%'. Don't bother writing values before
1810 y = strchr(url, '%');
1814 for (x = y; *y; ++x, ++y) {
1819 if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1825 decoded = x2c(y + 1);
1826 if ((decoded == '\0')
1827 || (forbid && ap_strchr_c(forbid, decoded))) {
1832 else if (reserved && ap_strchr_c(reserved, decoded)) {
1846 return HTTP_BAD_REQUEST;
1849 return HTTP_NOT_FOUND;
1855 AP_DECLARE(int) ap_unescape_url(char *url)
1858 return unescape_url(url, SLASHES, NULL);
1860 AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes)
1862 /* AllowEncodedSlashes (corrected) */
1863 if (decode_slashes) {
1864 /* no chars reserved */
1865 return unescape_url(url, NULL, NULL);
1867 /* reserve (do not decode) encoded slashes */
1868 return unescape_url(url, NULL, SLASHES);
1872 /* IFDEF these out until they've been thought through.
1873 * Just a germ of an API extension for now
1875 AP_DECLARE(int) ap_unescape_url_proxy(char *url)
1877 /* leave RFC1738 reserved characters intact, * so proxied URLs
1878 * don't get mangled. Where does that leave encoded '&' ?
1880 return unescape_url(url, NULL, "/;?");
1882 AP_DECLARE(int) ap_unescape_url_reserved(char *url, const char *reserved)
1884 return unescape_url(url, NULL, reserved);
1888 AP_DECLARE(int) ap_unescape_urlencoded(char *query)
1892 /* replace plus with a space */
1894 for (slider = query; *slider; slider++) {
1895 if (*slider == '+') {
1901 /* unescape everything else */
1902 return unescape_url(query, NULL, NULL);
1905 AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname,
1906 apr_port_t port, const request_rec *r)
1908 if (ap_is_default_port(port, r)) {
1909 return apr_pstrdup(p, hostname);
1912 return apr_psprintf(p, "%s:%u", hostname, port);
1916 AP_DECLARE(int) ap_unescape_all(char *url)
1918 return unescape_url(url, NULL, NULL);
1921 /* c2x takes an unsigned, and expects the caller has guaranteed that
1922 * 0 <= what < 256... which usually means that you have to cast to
1923 * unsigned char first, because (unsigned)(char)(x) first goes through
1924 * signed extension to an int before the unsigned cast.
1926 * The reason for this assumption is to assist gcc code generation --
1927 * the unsigned char -> unsigned extension is already done earlier in
1928 * both uses of this code, so there's no need to waste time doing it
1931 static const char c2x_table[] = "0123456789abcdef";
1933 static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
1934 unsigned char *where)
1936 #if APR_CHARSET_EBCDIC
1937 what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
1938 #endif /*APR_CHARSET_EBCDIC*/
1940 *where++ = c2x_table[what >> 4];
1941 *where++ = c2x_table[what & 0xf];
1946 * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
1947 * routine is (should be) OS independent.
1949 * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
1950 * cases if a ':' occurs before the first '/' in the URL, the URL should be
1951 * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
1952 * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
1953 * efficiency reasons, we don't use escape_path_segment(), which is provided for
1954 * reference. Again, RFC 1808 is where this stuff is defined.
1956 * If partial is set, os_escape_path() assumes that the path will be appended to
1957 * something with a '/' in it (and thus does not prefix "./").
1960 AP_DECLARE(char *) ap_escape_path_segment_buffer(char *copy, const char *segment)
1962 const unsigned char *s = (const unsigned char *)segment;
1963 unsigned char *d = (unsigned char *)copy;
1967 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
1979 AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
1981 return ap_escape_path_segment_buffer(apr_palloc(p, 3 * strlen(segment) + 1), segment);
1984 AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
1986 /* Allocate +3 for potential "./" and trailing NULL.
1987 * Allocate another +1 to allow the caller to add a trailing '/' (see
1988 * comment in 'ap_sub_req_lookup_dirent')
1990 char *copy = apr_palloc(p, 3 * strlen(path) + 3 + 1);
1991 const unsigned char *s = (const unsigned char *)path;
1992 unsigned char *d = (unsigned char *)copy;
1996 const char *colon = ap_strchr_c(path, ':');
1997 const char *slash = ap_strchr_c(path, '/');
1999 if (colon && (!slash || colon < slash)) {
2005 if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
2017 AP_DECLARE(char *) ap_escape_urlencoded_buffer(char *copy, const char *buffer)
2019 const unsigned char *s = (const unsigned char *)buffer;
2020 unsigned char *d = (unsigned char *)copy;
2024 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
2027 else if (c == ' ') {
2039 AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
2041 return ap_escape_urlencoded_buffer(apr_palloc(p, 3 * strlen(buffer) + 1), buffer);
2044 /* ap_escape_uri is now a macro for os_escape_path */
2046 AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
2051 /* first, count the number of extra characters */
2052 for (i = 0, j = 0; s[i] != '\0'; i++)
2053 if (s[i] == '<' || s[i] == '>')
2055 else if (s[i] == '&')
2057 else if (s[i] == '"')
2059 else if (toasc && !apr_isascii(s[i]))
2063 return apr_pstrmemdup(p, s, i);
2065 x = apr_palloc(p, i + j + 1);
2066 for (i = 0, j = 0; s[i] != '\0'; i++, j++)
2068 memcpy(&x[j], "<", 4);
2071 else if (s[i] == '>') {
2072 memcpy(&x[j], ">", 4);
2075 else if (s[i] == '&') {
2076 memcpy(&x[j], "&", 5);
2079 else if (s[i] == '"') {
2080 memcpy(&x[j], """, 6);
2083 else if (toasc && !apr_isascii(s[i])) {
2084 char *esc = apr_psprintf(p, "&#%3.3d;", (unsigned char)s[i]);
2085 memcpy(&x[j], esc, 6);
2094 AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str)
2098 const unsigned char *s;
2099 apr_size_t length, escapes = 0;
2105 /* Compute how many characters need to be escaped */
2106 s = (const unsigned char *)str;
2108 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2113 /* Compute the length of the input string, including NULL */
2114 length = s - (const unsigned char *)str + 1;
2116 /* Fast path: nothing to escape */
2118 return apr_pmemdup(p, str, length);
2121 /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */
2122 ret = apr_palloc(p, length + 3 * escapes);
2123 d = (unsigned char *)ret;
2124 s = (const unsigned char *)str;
2126 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2162 AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
2165 unsigned char *d, *ep;
2166 const unsigned char *s;
2168 if (!source || !buflen) { /* be safe */
2172 d = (unsigned char *)dest;
2173 s = (const unsigned char *)source;
2174 ep = d + buflen - 1;
2176 for (; d < ep && *s; ++s) {
2178 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2204 case '"': /* no need for this in error log */
2209 ep = --d; /* break the for loop as well */
2222 return (d - (unsigned char *)dest);
2225 AP_DECLARE(void) ap_bin2hex(const void *src, apr_size_t srclen, char *dest)
2227 const unsigned char *in = src;
2230 for (i = 0; i < srclen; i++) {
2231 *dest++ = c2x_table[in[i] >> 4];
2232 *dest++ = c2x_table[in[i] & 0xf];
2237 AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
2241 if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS)
2242 return 0; /* in error condition, just return no */
2244 return (finfo.filetype == APR_DIR);
2247 AP_DECLARE(int) ap_is_rdirectory(apr_pool_t *p, const char *path)
2251 if (apr_stat(&finfo, path, APR_FINFO_LINK | APR_FINFO_TYPE, p) != APR_SUCCESS)
2252 return 0; /* in error condition, just return no */
2254 return (finfo.filetype == APR_DIR);
2257 AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
2260 apr_size_t len1, len2;
2263 len1 = strlen(src1);
2264 len2 = strlen(src2);
2265 /* allocate +3 for '/' delimiter, trailing NULL and overallocate
2266 * one extra byte to allow the caller to add a trailing '/'
2268 path = (char *)apr_palloc(a, len1 + len2 + 3);
2271 memcpy(path + 1, src2, len2 + 1);
2275 memcpy(path, src1, len1);
2277 if (next[-1] != '/') {
2280 memcpy(next, src2, len2 + 1);
2286 * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
2288 AP_DECLARE(int) ap_is_url(const char *u)
2292 for (x = 0; u[x] != ':'; x++) {
2294 ((!apr_isalnum(u[x])) &&
2295 (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
2300 return (x ? 1 : 0); /* If the first character is ':', it's broken, too */
2303 AP_DECLARE(int) ap_ind(const char *s, char c)
2305 const char *p = ap_strchr_c(s, c);
2312 AP_DECLARE(int) ap_rind(const char *s, char c)
2314 const char *p = ap_strrchr_c(s, c);
2321 AP_DECLARE(void) ap_str_tolower(char *str)
2324 *str = apr_tolower(*str);
2329 AP_DECLARE(void) ap_str_toupper(char *str)
2332 *str = apr_toupper(*str);
2338 * We must return a FQDN
2340 char *ap_get_local_host(apr_pool_t *a)
2342 #ifndef MAXHOSTNAMELEN
2343 #define MAXHOSTNAMELEN 256
2345 char str[MAXHOSTNAMELEN + 1];
2346 char *server_hostname = NULL;
2347 apr_sockaddr_t *sockaddr;
2350 if (apr_gethostname(str, sizeof(str) - 1, a) != APR_SUCCESS) {
2351 ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00556)
2352 "%s: apr_gethostname() failed to determine ServerName",
2355 str[sizeof(str) - 1] = '\0';
2356 if (apr_sockaddr_info_get(&sockaddr, str, APR_UNSPEC, 0, 0, a) == APR_SUCCESS) {
2357 if ( (apr_getnameinfo(&hostname, sockaddr, 0) == APR_SUCCESS) &&
2358 (ap_strchr_c(hostname, '.')) ) {
2359 server_hostname = apr_pstrdup(a, hostname);
2360 return server_hostname;
2361 } else if (ap_strchr_c(str, '.')) {
2362 server_hostname = apr_pstrdup(a, str);
2364 apr_sockaddr_ip_get(&hostname, sockaddr);
2365 server_hostname = apr_pstrdup(a, hostname);
2368 ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00557)
2369 "%s: apr_sockaddr_info_get() failed for %s",
2370 ap_server_argv0, str);
2374 if (!server_hostname)
2375 server_hostname = apr_pstrdup(a, "127.0.0.1");
2377 ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, a, APLOGNO(00558)
2378 "%s: Could not reliably determine the server's fully qualified "
2379 "domain name, using %s. Set the 'ServerName' directive globally "
2380 "to suppress this message",
2381 ap_server_argv0, server_hostname);
2383 return server_hostname;
2386 /* simple 'pool' alloc()ing glue to apr_base64.c
2388 AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
2393 decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded));
2394 l = apr_base64_decode(decoded, bufcoded);
2395 decoded[l] = '\0'; /* make binary sequence into string */
2400 /* a stringent version of ap_pbase64decode() */
2401 AP_DECLARE(apr_status_t) ap_pbase64decode_strict(apr_pool_t *p,
2402 const char *encoded,
2406 apr_size_t end_index;
2411 * TODO: this would be a lot more efficient if we had access to the lookup
2412 * table used by APR. If that gets pulled in at any point, make use of it.
2414 end_index = strspn(encoded, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2415 "abcdefghijklmnopqrstuvwxyz"
2418 last_group_len = end_index % 4;
2419 end = encoded + end_index;
2421 /* The only non-alphabet character allowed is the padding character '=' at
2422 * the end of the string. There are two allowable padding cases for the last
2423 * group of four: "xY==" or "xyZ=". We require the final (non-padding)
2424 * character to have been zero-padded during encoding, which limits the
2425 * character choices.
2427 if (last_group_len == 1) {
2428 /* This isn't ever valid. */
2431 else if (last_group_len == 2) {
2433 if (*end != '=' || end[1] != '=') {
2436 else if (!ap_strchr("AQgw", end[-1])) {
2437 /* Correctly zero-padded input data will result in a final character
2438 * that is one of the four above. */
2444 else if (last_group_len == 3) {
2449 else if (!ap_strchr("AEIMQUYcgkosw048", end[-1])) {
2450 /* Correctly zero-padded input data will result in a final character
2451 * that is one of the sixteen above. */
2458 /* At this point, if the encoded buffer is correct, we should be at the end
2464 *decoded = apr_palloc(p, apr_base64_decode_len(encoded));
2465 *len = apr_base64_decode(*decoded, encoded);
2470 AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
2473 int l = strlen(string);
2475 encoded = (char *) apr_palloc(p, 1 + apr_base64_encode_len(l));
2476 l = apr_base64_encode(encoded, string, l);
2477 encoded[l] = '\0'; /* make binary sequence into string */
2482 /* we want to downcase the type/subtype for comparison purposes
2483 * but nothing else because ;parameter=foo values are case sensitive.
2484 * XXX: in truth we want to downcase parameter names... but really,
2485 * apache has never handled parameters and such correctly. You
2486 * also need to compress spaces and such to be able to compare
2489 AP_DECLARE(void) ap_content_type_tolower(char *str)
2493 semi = strchr(str, ';');
2498 ap_str_tolower(str);
2506 * Given a string, replace any bare " with \" .
2508 AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
2511 const char *inchr = instring;
2512 char *outchr, *outstring;
2515 * Look through the input string, jogging the length of the output
2516 * string up by an extra byte each time we find an unescaped ".
2518 while (*inchr != '\0') {
2520 if (*inchr == '"') {
2524 * If we find a slosh, and it's not the last byte in the string,
2525 * it's escaping something - advance past both bytes.
2527 if ((*inchr == '\\') && (inchr[1] != '\0')) {
2533 outstring = apr_palloc(p, newlen + 1);
2537 * Now copy the input string to the output string, inserting a slosh
2538 * in front of every " that doesn't already have one.
2540 while (*inchr != '\0') {
2541 if ((*inchr == '\\') && (inchr[1] != '\0')) {
2542 *outchr++ = *inchr++;
2543 *outchr++ = *inchr++;
2545 if (*inchr == '"') {
2548 if (*inchr != '\0') {
2549 *outchr++ = *inchr++;
2557 * Given a string, append the PID deliminated by delim.
2558 * Usually used to create a pid-appended filepath name
2559 * (eg: /a/b/foo -> /a/b/foo.6726). A function, and not
2560 * a macro, to avoid unistd.h dependency
2562 AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string,
2565 return apr_psprintf(p, "%s%s%" APR_PID_T_FMT, string,
2571 * Parse a given timeout parameter string into an apr_interval_time_t value.
2572 * The unit of the time interval is given as postfix string to the numeric
2573 * string. Currently the following units are understood (case insensitive):
2580 * If no unit is contained in the given timeout parameter the default_time_unit
2581 * will be used instead.
2582 * @param timeout_parameter The string containing the timeout parameter.
2583 * @param timeout The timeout value to be returned.
2584 * @param default_time_unit The default time unit to use if none is specified
2585 * in timeout_parameter.
2586 * @return Status value indicating whether the parsing was successful or not.
2588 AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
2589 const char *timeout_parameter,
2590 apr_interval_time_t *timeout,
2591 const char *default_time_unit)
2594 const char *time_str;
2597 tout = apr_strtoi64(timeout_parameter, &endp, 10);
2601 if (!endp || !*endp) {
2602 time_str = default_time_unit;
2608 switch (*time_str) {
2609 /* Time is in seconds */
2612 *timeout = (apr_interval_time_t) apr_time_from_sec(tout);
2616 /* Time is in hours */
2617 *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 3600);
2621 switch (*(++time_str)) {
2622 /* Time is in milliseconds */
2625 *timeout = (apr_interval_time_t) tout * 1000;
2627 /* Time is in minutes */
2630 *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 60);
2633 return APR_EGENERAL;
2637 return APR_EGENERAL;
2643 * Determine if a request has a request body or not.
2645 * @param r the request_rec of the request
2646 * @return truth value
2648 AP_DECLARE(int) ap_request_has_body(request_rec *r)
2655 has_body = (!r->header_only
2657 || apr_table_get(r->headers_in, "Transfer-Encoding")
2658 || ( (cls = apr_table_get(r->headers_in, "Content-Length"))
2659 && (apr_strtoff(&cl, cls, &estr, 10) == APR_SUCCESS)
2668 * Check whether a request is tainted by exposure to something
2669 * potentially untrusted.
2672 AP_DECLARE(int) ap_request_tainted(request_rec *r, int flags)
2674 /** Potential future: a hook or callback here could serve modules
2675 * like mod_security and ironbee with more complex needs.
2677 return r && ((r->taint&flags)
2678 || ap_request_tainted(r->main, flags)
2679 || ap_request_tainted(r->prev, flags));
2682 AP_DECLARE_NONSTD(apr_status_t) ap_pool_cleanup_set_null(void *data_)
2684 void **ptr = (void **)data_;
2689 AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
2691 for ( ; *src; src++, dest++)
2693 if (!apr_isprint(*src))
2695 else if (!apr_isalnum(*src))
2705 AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
2708 char *new = apr_palloc(p, strlen(src)+1);
2712 return ap_str2_alnum(src, new);
2716 * Read the body and parse any form found, which must be of the
2717 * type application/x-www-form-urlencoded.
2719 * Name/value pairs are returned in an array, with the names as
2720 * strings with a maximum length of HUGE_STRING_LEN, and the
2721 * values as bucket brigades. This allows values to be arbitrarily
2724 * All url-encoding is removed from both the names and the values
2725 * on the fly. The names are interpreted as strings, while the
2726 * values are interpreted as blocks of binary data, that may
2727 * contain the 0 character.
2729 * In order to ensure that resource limits are not exceeded, a
2730 * maximum size must be provided. If the sum of the lengths of
2731 * the names and the values exceed this size, this function
2732 * will return HTTP_REQUEST_ENTITY_TOO_LARGE.
2734 * An optional number of parameters can be provided, if the number
2735 * of parameters provided exceeds this amount, this function will
2736 * return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
2737 * no limit is imposed, and the number of parameters is in turn
2738 * constrained by the size parameter above.
2740 * This function honours any kept_body configuration, and the
2741 * original raw request body will be saved to the kept_body brigade
2742 * if so configured, just as ap_discard_request_body does.
2744 * NOTE: File upload is not yet supported, but can be without change
2745 * to the function call.
2748 /* form parsing stuff */
2759 AP_DECLARE(int) ap_parse_form_data(request_rec *r, ap_filter_t *f,
2760 apr_array_header_t **ptr,
2761 apr_size_t num, apr_size_t usize)
2763 apr_bucket_brigade *bb = NULL;
2765 char buffer[HUGE_STRING_LEN + 1];
2767 apr_size_t offset = 0;
2769 ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
2770 ap_form_pair_t *pair = NULL;
2771 apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
2772 char escaped_char[2] = { 0 };
2776 /* sanity check - we only support forms for now */
2777 ct = apr_table_get(r->headers_in, "Content-Type");
2778 if (!ct || ap_cstr_casecmpn("application/x-www-form-urlencoded", ct, 33)) {
2779 return ap_discard_request_body(r);
2782 if (usize > APR_SIZE_MAX >> 1)
2783 size = APR_SIZE_MAX >> 1;
2788 f = r->input_filters;
2791 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2793 apr_bucket *bucket = NULL, *last = NULL;
2795 int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
2796 APR_BLOCK_READ, HUGE_STRING_LEN);
2797 if (rv != APR_SUCCESS) {
2798 apr_brigade_destroy(bb);
2799 return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
2802 for (bucket = APR_BRIGADE_FIRST(bb);
2803 bucket != APR_BRIGADE_SENTINEL(bb);
2804 last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
2806 apr_size_t len, slide;
2809 apr_bucket_delete(last);
2811 if (APR_BUCKET_IS_EOS(bucket)) {
2815 if (bucket->length == 0) {
2819 rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
2820 if (rv != APR_SUCCESS) {
2821 apr_brigade_destroy(bb);
2822 return HTTP_BAD_REQUEST;
2826 while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
2831 else if ('&' == c) {
2835 percent = FORM_PERCENTA;
2838 if (FORM_PERCENTA == percent) {
2839 escaped_char[0] = c;
2840 percent = FORM_PERCENTB;
2843 if (FORM_PERCENTB == percent) {
2844 escaped_char[1] = c;
2845 c = x2c(escaped_char);
2846 percent = FORM_NORMAL;
2851 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2852 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2853 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2861 if (offset < HUGE_STRING_LEN) {
2863 pair = (ap_form_pair_t *) apr_array_push(pairs);
2864 pair->name = apr_pstrmemdup(r->pool, buffer, offset);
2865 pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2870 buffer[offset++] = c;
2879 if (offset >= HUGE_STRING_LEN) {
2880 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2881 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2882 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2885 buffer[offset++] = c;
2895 apr_brigade_cleanup(bb);
2896 } while (!seen_eos);
2898 if (FORM_ABORT == state || size < 0 || num == 0) {
2899 return HTTP_REQUEST_ENTITY_TOO_LARGE;
2901 else if (FORM_VALUE == state && pair && offset > 0) {
2902 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2903 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2904 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2911 #define VARBUF_SMALL_SIZE 2048
2912 #define VARBUF_MAX_SIZE (APR_SIZE_MAX - 1 - \
2913 APR_ALIGN_DEFAULT(sizeof(struct ap_varbuf_info)))
2915 struct ap_varbuf_info {
2916 struct apr_memnode_t *node;
2917 apr_allocator_t *allocator;
2920 static apr_status_t varbuf_cleanup(void *info_)
2922 struct ap_varbuf_info *info = info_;
2923 info->node->next = NULL;
2924 apr_allocator_free(info->allocator, info->node);
2928 static const char nul = '\0';
2929 static char * const varbuf_empty = (char *)&nul;
2931 AP_DECLARE(void) ap_varbuf_init(apr_pool_t *p, struct ap_varbuf *vb,
2932 apr_size_t init_size)
2934 vb->buf = varbuf_empty;
2936 vb->strlen = AP_VARBUF_UNKNOWN;
2940 ap_varbuf_grow(vb, init_size);
2943 AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
2945 apr_memnode_t *new_node = NULL;
2946 apr_allocator_t *allocator;
2947 struct ap_varbuf_info *new_info;
2950 AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN || vb->avail >= vb->strlen);
2952 if (new_len <= vb->avail)
2955 if (new_len < 2 * vb->avail && vb->avail < VARBUF_MAX_SIZE/2) {
2956 /* at least double the size, to avoid repeated reallocations */
2957 new_len = 2 * vb->avail;
2959 else if (new_len > VARBUF_MAX_SIZE) {
2960 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2961 ap_assert(abort_fn != NULL);
2962 abort_fn(APR_ENOMEM);
2966 new_len++; /* add space for trailing \0 */
2967 if (new_len <= VARBUF_SMALL_SIZE) {
2968 new_len = APR_ALIGN_DEFAULT(new_len);
2969 new = apr_palloc(vb->pool, new_len);
2970 if (vb->avail && vb->strlen != 0) {
2971 AP_DEBUG_ASSERT(vb->buf != NULL);
2972 AP_DEBUG_ASSERT(vb->buf != varbuf_empty);
2973 if (new == vb->buf + vb->avail + 1) {
2974 /* We are lucky: the new memory lies directly after our old
2975 * buffer, we can now use both.
2977 vb->avail += new_len;
2981 /* copy up to vb->strlen + 1 bytes */
2982 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2983 vb->avail + 1 : vb->strlen + 1);
2989 vb->avail = new_len - 1;
2994 /* The required block is rather larger. Use allocator directly so that
2995 * the memory can be freed independently from the pool. */
2996 allocator = apr_pool_allocator_get(vb->pool);
2997 /* Happens if APR was compiled with APR_POOL_DEBUG */
2998 if (allocator == NULL) {
2999 apr_allocator_create(&allocator);
3000 ap_assert(allocator != NULL);
3002 if (new_len <= VARBUF_MAX_SIZE)
3003 new_node = apr_allocator_alloc(allocator,
3004 new_len + APR_ALIGN_DEFAULT(sizeof(*new_info)));
3006 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
3007 ap_assert(abort_fn != NULL);
3008 abort_fn(APR_ENOMEM);
3011 new_info = (struct ap_varbuf_info *)new_node->first_avail;
3012 new_node->first_avail += APR_ALIGN_DEFAULT(sizeof(*new_info));
3013 new_info->node = new_node;
3014 new_info->allocator = allocator;
3015 new = new_node->first_avail;
3016 AP_DEBUG_ASSERT(new_node->endp - new_node->first_avail >= new_len);
3017 new_len = new_node->endp - new_node->first_avail;
3019 if (vb->avail && vb->strlen != 0)
3020 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
3021 vb->avail + 1 : vb->strlen + 1);
3025 apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
3026 apr_pool_cleanup_register(vb->pool, new_info, varbuf_cleanup,
3027 apr_pool_cleanup_null);
3028 vb->info = new_info;
3030 vb->avail = new_len - 1;
3033 AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
3039 ap_varbuf_grow(vb, len);
3040 memcpy(vb->buf, str, len);
3041 vb->buf[len] = '\0';
3045 if (vb->strlen == AP_VARBUF_UNKNOWN)
3046 vb->strlen = strlen(vb->buf);
3047 ap_varbuf_grow(vb, vb->strlen + len);
3048 memcpy(vb->buf + vb->strlen, str, len);
3050 vb->buf[vb->strlen] = '\0';
3053 AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb)
3056 apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
3062 AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *buf,
3063 const char *prepend, apr_size_t prepend_len,
3064 const char *append, apr_size_t append_len,
3065 apr_size_t *new_len)
3068 struct iovec vec[3];
3071 vec[i].iov_base = (void *)prepend;
3072 vec[i].iov_len = prepend_len;
3075 if (buf->avail && buf->strlen) {
3076 if (buf->strlen == AP_VARBUF_UNKNOWN)
3077 buf->strlen = strlen(buf->buf);
3078 vec[i].iov_base = (void *)buf->buf;
3079 vec[i].iov_len = buf->strlen;
3083 vec[i].iov_base = (void *)append;
3084 vec[i].iov_len = append_len;
3088 return apr_pstrcatv(p, vec, i, new_len);
3095 AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb,
3099 ap_regmatch_t pmatch[],
3102 return regsub_core(NULL, NULL, vb, input, source, nmatch, pmatch, maxlen);
3105 static const char * const oom_message = "[crit] Memory allocation failed, "
3106 "aborting process." APR_EOL_STR;
3108 AP_DECLARE(void) ap_abort_on_oom()
3110 int written, count = strlen(oom_message);
3111 const char *buf = oom_message;
3113 written = write(STDERR_FILENO, buf, count);
3114 if (written == count)
3120 } while (written >= 0 || errno == EINTR);
3124 AP_DECLARE(void *) ap_malloc(size_t size)
3126 void *p = malloc(size);
3127 if (p == NULL && size != 0)
3132 AP_DECLARE(void *) ap_calloc(size_t nelem, size_t size)
3134 void *p = calloc(nelem, size);
3135 if (p == NULL && nelem != 0 && size != 0)
3140 AP_DECLARE(void *) ap_realloc(void *ptr, size_t size)
3142 void *p = realloc(ptr, size);
3143 if (p == NULL && size != 0)
3148 AP_DECLARE(void) ap_get_sload(ap_sload_t *ld)
3150 int i, j, server_limit, thread_limit;
3154 ap_generation_t mpm_generation;
3156 /* preload errored fields, we overwrite */
3159 ld->bytes_served = 0;
3160 ld->access_count = 0;
3162 ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
3163 ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
3164 ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
3166 for (i = 0; i < server_limit; i++) {
3168 ps = ap_get_scoreboard_process(i);
3170 for (j = 0; j < thread_limit; j++) {
3172 worker_score *ws = NULL;
3173 ws = &ap_scoreboard_image->servers[i][j];
3176 if (!ps->quiescing && ps->pid) {
3177 if (res == SERVER_READY && ps->generation == mpm_generation) {
3180 else if (res != SERVER_DEAD &&
3181 res != SERVER_STARTING && res != SERVER_IDLE_KILL &&
3182 ps->generation == mpm_generation) {
3187 if (ap_extended_status && !ps->quiescing && ps->pid) {
3188 if (ws->access_count != 0
3189 || (res != SERVER_READY && res != SERVER_DEAD)) {
3190 ld->access_count += ws->access_count;
3191 ld->bytes_served += ws->bytes_served;
3196 total = busy + ready;
3198 ld->idle = ready * 100 / total;
3199 ld->busy = busy * 100 / total;
3203 AP_DECLARE(void) ap_get_loadavg(ap_loadavg_t *ld)
3205 /* preload errored fields, we overwrite */
3207 ld->loadavg5 = -1.0;
3208 ld->loadavg15 = -1.0;
3215 num = getloadavg(la, 3);
3217 ld->loadavg = (float)la[0];
3220 ld->loadavg5 = (float)la[1];
3223 ld->loadavg15 = (float)la[2];
3229 static const char * const pw_cache_note_name = "conn_cache_note";
3231 /* varbuf contains concatenated password and hash */
3232 struct ap_varbuf vb;
3234 apr_status_t result;
3237 AP_DECLARE(apr_status_t) ap_password_validate(request_rec *r,
3238 const char *username,
3242 struct pw_cache *cache;
3245 cache = (struct pw_cache *)apr_table_get(r->connection->notes, pw_cache_note_name);
3246 if (cache != NULL) {
3247 if (strncmp(passwd, cache->vb.buf, cache->pwlen) == 0
3248 && strcmp(hash, cache->vb.buf + cache->pwlen) == 0) {
3249 return cache->result;
3251 /* make ap_varbuf_grow below not copy the old data */
3252 cache->vb.strlen = 0;
3255 cache = apr_palloc(r->connection->pool, sizeof(struct pw_cache));
3256 ap_varbuf_init(r->connection->pool, &cache->vb, 0);
3257 apr_table_setn(r->connection->notes, pw_cache_note_name, (void *)cache);
3259 cache->pwlen = strlen(passwd);
3260 hashlen = strlen(hash);
3261 ap_varbuf_grow(&cache->vb, cache->pwlen + hashlen + 1);
3262 memcpy(cache->vb.buf, passwd, cache->pwlen);
3263 memcpy(cache->vb.buf + cache->pwlen, hash, hashlen + 1);
3264 cache->result = apr_password_validate(passwd, hash);
3265 return cache->result;
3268 AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p,
3270 const char * const * argv)
3272 char buf[MAX_STRING_LEN];
3273 apr_procattr_t *procattr;
3276 apr_size_t nbytes = 1;
3280 if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
3282 if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
3283 APR_FULL_BLOCK) != APR_SUCCESS)
3285 if (apr_procattr_dir_set(procattr,
3286 ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
3288 if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
3290 proc = apr_pcalloc(p, sizeof(apr_proc_t));
3291 if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
3297 /* XXX: we are reading 1 byte at a time here */
3298 for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
3299 && nbytes == 1 && (k < MAX_STRING_LEN-1) ; ) {
3300 if (c == '\n' || c == '\r')
3307 return apr_pstrndup(p, buf, k);
3310 AP_DECLARE(int) ap_array_str_index(const apr_array_header_t *array,
3317 for (i = start; i < array->nelts; i++) {
3318 const char *p = APR_ARRAY_IDX(array, i, const char *);
3319 if (!strcmp(p, s)) {
3328 AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array,
3331 return (ap_array_str_index(array, s, 0) >= 0);
3334 #if !APR_CHARSET_EBCDIC
3336 * Our own known-fast translation table for casecmp by character.
3337 * Only ASCII alpha characters 41-5A are folded to 61-7A, other
3338 * octets (such as extended latin alphabetics) are never case-folded.
3339 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3341 static const short ucharmap[] = {
3342 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
3343 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
3344 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3345 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3346 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3347 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3348 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3349 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3350 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3351 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3352 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3353 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3354 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3355 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3356 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3357 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3358 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3359 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3360 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3361 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3362 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3363 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3364 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3365 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3366 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3367 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3368 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3369 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3370 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3371 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3372 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3373 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3375 #else /* APR_CHARSET_EBCDIC */
3377 * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison,
3378 * provides unique identity of every char value (strict ISO-646
3379 * conformance, arbitrary election of an ISO-8859-1 ordering, and
3380 * very arbitrary control code assignments into C1 to achieve
3381 * identity and a reversible mapping of code points),
3382 * then folding the equivalences of ASCII 41-5A into 61-7A,
3383 * presenting comparison results in a somewhat ISO/IEC 10646
3384 * (ASCII-like) order, depending on the EBCDIC code page in use.
3386 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3388 static const short ucharmap[] = {
3389 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
3390 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
3391 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
3392 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
3393 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
3394 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
3395 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
3396 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
3397 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,
3398 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
3399 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,
3400 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
3401 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,
3402 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
3403 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,
3404 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
3405 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3406 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,
3407 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3408 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,
3409 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3410 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE,
3411 0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,
3412 0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7,
3413 0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3414 0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,
3415 0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3416 0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,
3417 0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3418 0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,
3419 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3420 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F
3424 AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2)
3426 const unsigned char *str1 = (const unsigned char *)s1;
3427 const unsigned char *str2 = (const unsigned char *)s2;
3430 const int c1 = (int)(*str1);
3431 const int c2 = (int)(*str2);
3432 const int cmp = ucharmap[c1] - ucharmap[c2];
3433 /* Not necessary to test for !c2, this is caught by cmp */
3441 AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
3443 const unsigned char *str1 = (const unsigned char *)s1;
3444 const unsigned char *str2 = (const unsigned char *)s2;
3447 const int c1 = (int)(*str1);
3448 const int c2 = (int)(*str2);
3449 const int cmp = ucharmap[c1] - ucharmap[c2];
3450 /* Not necessary to test for !c2, this is caught by cmp */
3463 static int fname_alphasort(const void *fn1, const void *fn2)
3465 const fnames *f1 = fn1;
3466 const fnames *f2 = fn2;
3468 return strcmp(f1->fname, f2->fname);
3471 AP_DECLARE(ap_dir_match_t *)ap_dir_cfgmatch(cmd_parms *cmd, int flags,
3472 const char *(*cb)(ap_dir_match_t *w, const char *fname), void *ctx)
3474 ap_dir_match_t *w = apr_palloc(cmd->temp_pool, sizeof(*w));
3476 w->prefix = apr_pstrcat(cmd->pool, cmd->cmd->name, ": ", NULL);
3478 w->ptemp = cmd->temp_pool;
3487 AP_DECLARE(const char *)ap_dir_nofnmatch(ap_dir_match_t *w, const char *fname)
3492 if ((w->flags & AP_DIR_FLAG_RECURSIVE) && ap_is_directory(w->ptemp, fname)) {
3496 apr_array_header_t *candidates = NULL;
3498 char *path = apr_pstrdup(w->ptemp, fname);
3500 if (++w->depth > AP_MAX_FNMATCH_DIR_DEPTH) {
3501 return apr_psprintf(w->p, "%sDirectory '%s' exceeds the maximum include "
3502 "directory nesting level of %u. You have "
3503 "probably a recursion somewhere.", w->prefix ? w->prefix : "", path,
3504 AP_MAX_FNMATCH_DIR_DEPTH);
3508 * first course of business is to grok all the directory
3509 * entries here and store 'em away. Recall we need full pathnames
3512 rv = apr_dir_open(&dirp, path, w->ptemp);
3513 if (rv != APR_SUCCESS) {
3514 return apr_psprintf(w->p, "%sCould not open directory %s: %pm",
3515 w->prefix ? w->prefix : "", path, &rv);
3518 candidates = apr_array_make(w->ptemp, 1, sizeof(fnames));
3519 while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) {
3520 /* strip out '.' and '..' */
3521 if (strcmp(dirent.name, ".")
3522 && strcmp(dirent.name, "..")) {
3523 fnew = (fnames *) apr_array_push(candidates);
3524 fnew->fname = ap_make_full_path(w->ptemp, path, dirent.name);
3528 apr_dir_close(dirp);
3529 if (candidates->nelts != 0) {
3530 qsort((void *) candidates->elts, candidates->nelts,
3531 sizeof(fnames), fname_alphasort);
3534 * Now recurse these... we handle errors and subdirectories
3535 * via the recursion, which is nice
3537 for (current = 0; current < candidates->nelts; ++current) {
3538 fnew = &((fnames *) candidates->elts)[current];
3539 error = ap_dir_nofnmatch(w, fnew->fname);
3550 else if (w->flags & AP_DIR_FLAG_OPTIONAL) {
3551 /* If the optional flag is set (like for IncludeOptional) we can
3552 * tolerate that no file or directory is present and bail out.
3555 if (apr_stat(&finfo, fname, APR_FINFO_TYPE, w->ptemp) != APR_SUCCESS
3556 || finfo.filetype == APR_NOFILE)
3560 return w->cb(w, fname);
3563 AP_DECLARE(const char *)ap_dir_fnmatch(ap_dir_match_t *w, const char *path,
3570 apr_array_header_t *candidates = NULL;
3574 /* find the first part of the filename */
3575 rest = ap_strchr_c(fname, '/');
3577 fname = apr_pstrmemdup(w->ptemp, fname, rest - fname);
3581 /* optimisation - if the filename isn't a wildcard, process it directly */
3582 if (!apr_fnmatch_test(fname)) {
3583 path = path ? ap_make_full_path(w->ptemp, path, fname) : fname;
3585 return ap_dir_nofnmatch(w, path);
3588 return ap_dir_fnmatch(w, path, rest);
3593 * first course of business is to grok all the directory
3594 * entries here and store 'em away. Recall we need full pathnames
3597 rv = apr_dir_open(&dirp, path, w->ptemp);
3598 if (rv != APR_SUCCESS) {
3599 /* If the directory doesn't exist and the optional flag is set
3600 * there is no need to return an error.
3602 if (rv == APR_ENOENT && (w->flags & AP_DIR_FLAG_OPTIONAL)) {
3605 return apr_psprintf(w->p, "%sCould not open directory %s: %pm",
3606 w->prefix ? w->prefix : "", path, &rv);
3609 candidates = apr_array_make(w->ptemp, 1, sizeof(fnames));
3610 while (apr_dir_read(&dirent, APR_FINFO_DIRENT | APR_FINFO_TYPE, dirp) == APR_SUCCESS) {
3611 /* strip out '.' and '..' */
3612 if (strcmp(dirent.name, ".")
3613 && strcmp(dirent.name, "..")
3614 && (apr_fnmatch(fname, dirent.name,
3615 APR_FNM_PERIOD) == APR_SUCCESS)) {
3616 const char *full_path = ap_make_full_path(w->ptemp, path, dirent.name);
3617 /* If matching internal to path, and we happen to match something
3618 * other than a directory, skip it
3620 if (rest && (dirent.filetype != APR_DIR)) {
3623 fnew = (fnames *) apr_array_push(candidates);
3624 fnew->fname = full_path;
3628 apr_dir_close(dirp);
3629 if (candidates->nelts != 0) {
3632 qsort((void *) candidates->elts, candidates->nelts,
3633 sizeof(fnames), fname_alphasort);
3636 * Now recurse these... we handle errors and subdirectories
3637 * via the recursion, which is nice
3639 for (current = 0; current < candidates->nelts; ++current) {
3640 fnew = &((fnames *) candidates->elts)[current];
3642 error = ap_dir_nofnmatch(w, fnew->fname);
3645 error = ap_dir_fnmatch(w, fnew->fname, rest);
3654 if (!(w->flags & AP_DIR_FLAG_OPTIONAL)) {
3655 return apr_psprintf(w->p, "%sNo matches for the wildcard '%s' in '%s', failing",
3656 w->prefix ? w->prefix : "", fname, path);