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 /* we assume the folks using this ensure 0 <= c < 256... which means
80 * you need a cast to (unsigned char) first, you can't just plug a
81 * char in here and get it to work, because if char is signed then it
82 * will first be sign extended.
84 #define TEST_CHAR(c, f) (test_char_table[(unsigned char)(c)] & (f))
86 /* Win32/NetWare/OS2 need to check for both forward and back slashes
87 * in ap_getparents() and ap_escape_url.
89 #ifdef CASE_BLIND_FILESYSTEM
90 #define IS_SLASH(s) ((s == '/') || (s == '\\'))
93 #define IS_SLASH(s) (s == '/')
97 /* we know core's module_index is 0 */
98 #undef APLOG_MODULE_INDEX
99 #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
101 /* maximum nesting level for config directories */
102 #ifndef AP_MAX_FNMATCH_DIR_DEPTH
103 #define AP_MAX_FNMATCH_DIR_DEPTH (128)
107 * Examine a field value (such as a media-/content-type) string and return
108 * it sans any parameters; e.g., strip off any ';charset=foo' and the like.
110 AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype)
114 if (intype == NULL) return NULL;
116 semi = ap_strchr_c(intype, ';');
118 return apr_pstrdup(p, intype);
121 while ((semi > intype) && apr_isspace(semi[-1])) {
124 return apr_pstrmemdup(p, intype, semi - intype);
128 AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt,
132 char ts[MAX_STRING_LEN];
133 char tf[MAX_STRING_LEN];
140 apr_time_exp_gmt(&xt, t);
141 /* Convert %Z to "GMT" and %z to "+0000";
142 * on hosts that do not have a time zone string in struct tm,
143 * strftime must assume its argument is local time.
145 for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f)
147 if (*f != '%') continue;
158 case 'z': /* common extension */
172 apr_time_exp_lt(&xt, t);
175 /* check return code? */
176 apr_strftime(ts, &retcode, MAX_STRING_LEN, fmt, &xt);
177 ts[MAX_STRING_LEN - 1] = '\0';
178 return apr_pstrdup(p, ts);
181 /* Roy owes Rob beer. */
182 /* Rob owes Roy dinner. */
184 /* These legacy comments would make a lot more sense if Roy hadn't
185 * replaced the old later_than() routine with util_date.c.
187 * Well, okay, they still wouldn't make any sense.
190 /* Match = 0, NoMatch = 1, Abort = -1
191 * Based loosely on sections of wildmat.c by Rich Salz
192 * Hmmm... shouldn't this really go component by component?
194 AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected)
198 for (x = 0, y = 0; expected[y]; ++y, ++x) {
199 if (expected[y] == '*') {
200 while (expected[++y] == '*');
205 if ((ret = ap_strcmp_match(&str[x++], &expected[y])) != 1)
212 else if ((expected[y] != '?') && (str[x] != expected[y]))
215 return (str[x] != '\0');
218 AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
222 for (x = 0, y = 0; expected[y]; ++y, ++x) {
223 if (!str[x] && expected[y] != '*')
225 if (expected[y] == '*') {
226 while (expected[++y] == '*');
231 if ((ret = ap_strcasecmp_match(&str[x++], &expected[y])) != 1)
236 else if (expected[y] != '?'
237 && apr_tolower(str[x]) != apr_tolower(expected[y]))
240 return (str[x] != '\0');
243 /* We actually compare the canonical root to this root, (but we don't
244 * waste time checking the case), since every use of this function in
245 * httpd-2.1 tests if the path is 'proper', meaning we've already passed
246 * it through apr_filepath_merge, or we haven't.
248 AP_DECLARE(int) ap_os_is_path_absolute(apr_pool_t *p, const char *dir)
251 const char *ourdir = dir;
252 if (apr_filepath_root(&newpath, &dir, 0, p) != APR_SUCCESS
253 || strncmp(newpath, ourdir, strlen(newpath)) != 0) {
259 AP_DECLARE(int) ap_is_matchexp(const char *str)
263 for (x = 0; str[x]; x++)
264 if ((str[x] == '*') || (str[x] == '?'))
270 * Here's a pool-based interface to the POSIX-esque ap_regcomp().
271 * Note that we return ap_regex_t instead of being passed one.
272 * The reason is that if you use an already-used ap_regex_t structure,
273 * the memory that you've already allocated gets forgotten, and
274 * regfree() doesn't clear it. So we don't allow it.
277 static apr_status_t regex_cleanup(void *preg)
279 ap_regfree((ap_regex_t *) preg);
283 AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
286 ap_regex_t *preg = apr_palloc(p, sizeof *preg);
287 int err = ap_regcomp(preg, pattern, cflags);
289 if (err == AP_REG_ESPACE)
294 apr_pool_cleanup_register(p, (void *) preg, regex_cleanup,
295 apr_pool_cleanup_null);
300 AP_DECLARE(void) ap_pregfree(apr_pool_t *p, ap_regex_t *reg)
303 apr_pool_cleanup_kill(p, (void *) reg, regex_cleanup);
307 * Similar to standard strstr() but we ignore case in this version.
308 * Based on the strstr() implementation further below.
310 AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2)
318 for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
322 /* found first character of s2, see if the rest matches */
325 for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) {
327 /* both strings ended together */
332 /* second string ended, a match */
335 /* didn't find a match here, try starting at next character in s1 */
342 * Returns an offsetted pointer in bigstring immediately after
343 * prefix. Returns bigstring if bigstring doesn't start with
344 * prefix or if prefix is longer than bigstring while still matching.
345 * NOTE: pointer returned is relative to bigstring, so we
346 * can use standard pointer comparisons in the calling function
347 * (eg: test if ap_stripprefix(a,b) == a)
349 AP_DECLARE(const char *) ap_stripprefix(const char *bigstring,
358 while (*p1 && *prefix) {
359 if (*p1++ != *prefix++)
365 /* hit the end of bigstring! */
369 /* This function substitutes for $0-$9, filling in regular expression
370 * submatches. Pass it the same nmatch and pmatch arguments that you
371 * passed ap_regexec(). pmatch should not be greater than the maximum number
372 * of subexpressions - i.e. one more than the re_nsub member of ap_regex_t.
374 * nmatch must be <=AP_MAX_REG_MATCH (10).
376 * input should be the string with the $-expressions, source should be the
377 * string that was matched against.
379 * It returns the substituted string, or NULL if a vbuf is used.
380 * On errors, returns the orig string.
382 * Parts of this code are based on Henry Spencer's regsub(), from his
383 * AT&T V8 regexp package.
386 static apr_status_t regsub_core(apr_pool_t *p, char **result,
387 struct ap_varbuf *vb, const char *input,
388 const char *source, apr_size_t nmatch,
389 ap_regmatch_t pmatch[], apr_size_t maxlen)
391 const char *src = input;
397 AP_DEBUG_ASSERT((result && p && !vb) || (vb && !p && !result));
398 if (!source || nmatch>AP_MAX_REG_MATCH)
402 if (maxlen > 0 && len >= maxlen)
405 *result = apr_pstrmemdup(p, src, len);
409 ap_varbuf_strmemcat(vb, src, len);
414 /* First pass, find the size */
415 while ((c = *src++) != '\0') {
416 if (c == '$' && apr_isdigit(*src))
419 no = AP_MAX_REG_MATCH;
421 if (no >= AP_MAX_REG_MATCH) { /* Ordinary character. */
422 if (c == '\\' && *src)
426 else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
427 if (APR_SIZE_MAX - len <= pmatch[no].rm_eo - pmatch[no].rm_so)
429 len += pmatch[no].rm_eo - pmatch[no].rm_so;
434 if (len >= maxlen && maxlen > 0)
438 *result = dst = apr_palloc(p, len + 1);
441 if (vb->strlen == AP_VARBUF_UNKNOWN)
442 vb->strlen = strlen(vb->buf);
443 ap_varbuf_grow(vb, vb->strlen + len);
444 dst = vb->buf + vb->strlen;
448 /* Now actually fill in the string */
452 while ((c = *src++) != '\0') {
453 if (c == '$' && apr_isdigit(*src))
456 no = AP_MAX_REG_MATCH;
458 if (no >= AP_MAX_REG_MATCH) { /* Ordinary character. */
459 if (c == '\\' && *src)
463 else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
464 len = pmatch[no].rm_eo - pmatch[no].rm_so;
465 memcpy(dst, source + pmatch[no].rm_so, len);
475 #ifndef AP_PREGSUB_MAXLEN
476 #define AP_PREGSUB_MAXLEN (HUGE_STRING_LEN * 8)
478 AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
479 const char *source, apr_size_t nmatch,
480 ap_regmatch_t pmatch[])
483 apr_status_t rc = regsub_core(p, &result, NULL, input, source, nmatch,
484 pmatch, AP_PREGSUB_MAXLEN);
485 if (rc != APR_SUCCESS)
490 AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result,
491 const char *input, const char *source,
492 apr_size_t nmatch, ap_regmatch_t pmatch[],
495 apr_status_t rc = regsub_core(p, result, NULL, input, source, nmatch,
497 if (rc != APR_SUCCESS)
503 * Parse .. so we don't compromise security
505 AP_DECLARE(void) ap_getparents(char *name)
510 /* Four paseses, as per RFC 1808 */
511 /* a) remove ./ path segments */
512 for (next = name; *next && (*next != '.'); next++) {
515 l = w = first_dot = next - name;
516 while (name[l] != '\0') {
517 if (name[l] == '.' && IS_SLASH(name[l + 1])
518 && (l == 0 || IS_SLASH(name[l - 1])))
521 name[w++] = name[l++];
524 /* b) remove trailing . path, segment */
525 if (w == 1 && name[0] == '.')
527 else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2]))
531 /* c) remove all xx/../ segments. (including leading ../ and /../) */
534 while (name[l] != '\0') {
535 if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2])
536 && (l == 0 || IS_SLASH(name[l - 1]))) {
541 while (l >= 0 && !IS_SLASH(name[l]))
548 while ((name[n] = name[m]))
555 /* d) remove trailing xx/.. segment. */
556 if (l == 2 && name[0] == '.' && name[1] == '.')
558 else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
559 && IS_SLASH(name[l - 3])) {
562 while (l >= 0 && !IS_SLASH(name[l]))
572 AP_DECLARE(void) ap_no2slash(char *name)
578 #ifdef HAVE_UNC_PATHS
579 /* Check for UNC names. Leave leading two slashes. */
580 if (s[0] == '/' && s[1] == '/')
585 if ((*d++ = *s) == '/') {
599 * copy at most n leading directories of s into d
600 * d should be at least as large as s plus 1 extra byte
602 * the return value is the ever useful pointer to the trailing \0 of d
604 * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments,
605 * so that if n == 0, "/" is returned in d with n == 1
606 * and s == "e:/test.html", "e:/" is returned in d
607 * *** See also ap_directory_walk in server/request.c
610 * /a/b, 0 ==> / (true for all platforms)
619 * c:/a/b 3 ==> c:/a/b
620 * c:/a/b 4 ==> c:/a/b
622 AP_DECLARE(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
631 if (*s == '\0' || (*s == '/' && (--n) == 0)) {
643 * return the parent directory name including trailing / of the file s
645 AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s)
647 const char *last_slash = ap_strrchr_c(s, '/');
651 if (last_slash == NULL) {
652 return apr_pstrdup(p, "");
654 l = (last_slash - s) + 1;
655 d = apr_pstrmemdup(p, s, l);
661 AP_DECLARE(int) ap_count_dirs(const char *path)
665 for (x = 0, n = 0; path[x]; x++)
671 AP_DECLARE(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop)
673 return ap_getword(atrans, (const char **) line, stop);
676 AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop)
678 const char *pos = *line;
682 while ((*pos != stop) && *pos) {
687 res = apr_pstrmemdup(atrans, *line, len);
690 while (*pos == stop) {
699 AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
701 return ap_getword_white(atrans, (const char **) line);
704 AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
706 const char *pos = *line;
710 while (!apr_isspace(*pos) && *pos) {
715 res = apr_pstrmemdup(atrans, *line, len);
717 while (apr_isspace(*pos)) {
726 AP_DECLARE(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line,
729 return ap_getword_nulls(atrans, (const char **) line, stop);
732 AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line,
735 const char *pos = ap_strchr_c(*line, stop);
739 apr_size_t len = strlen(*line);
740 res = apr_pstrmemdup(atrans, *line, len);
745 res = apr_pstrmemdup(atrans, *line, pos - *line);
754 /* Get a word, (new) config-file style --- quoted strings and backslashes
758 static char *substring_conf(apr_pool_t *p, const char *start, int len,
761 char *result = apr_palloc(p, len + 1);
765 for (i = 0; i < len; ++i) {
766 if (start[i] == '\\' && (start[i + 1] == '\\'
767 || (quote && start[i + 1] == quote)))
768 *resp++ = start[++i];
774 #if RESOLVE_ENV_PER_TOKEN
775 return (char *)ap_resolve_env(p,result);
781 AP_DECLARE(char *) ap_getword_conf_nc(apr_pool_t *p, char **line)
783 return ap_getword_conf(p, (const char **) line);
786 AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line)
788 const char *str = *line, *strend;
792 while (apr_isspace(*str))
800 if ((quote = *str) == '"' || quote == '\'') {
802 while (*strend && *strend != quote) {
803 if (*strend == '\\' && strend[1] &&
804 (strend[1] == quote || strend[1] == '\\')) {
811 res = substring_conf(p, str + 1, strend - str - 1, quote);
813 if (*strend == quote)
818 while (*strend && !apr_isspace(*strend))
821 res = substring_conf(p, str, strend - str, 0);
824 while (apr_isspace(*strend))
830 AP_DECLARE(char *) ap_getword_conf2_nc(apr_pool_t *p, char **line)
832 return ap_getword_conf2(p, (const char **) line);
835 AP_DECLARE(char *) ap_getword_conf2(apr_pool_t *p, const char **line)
837 const char *str = *line, *strend;
842 while (apr_isspace(*str))
850 if ((quote = *str) == '"' || quote == '\'')
851 return ap_getword_conf(p, line);
856 if (*strend == '}' && !--count)
860 if (*strend == '\\' && strend[1] == '\\') {
865 res = substring_conf(p, str + 1, strend - str - 1, 0);
872 while (*strend && !apr_isspace(*strend))
875 res = substring_conf(p, str, strend - str, 0);
878 while (apr_isspace(*strend))
884 AP_DECLARE(int) ap_cfg_closefile(ap_configfile_t *cfp)
887 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00551)
888 "Done with config file %s", cfp->name);
890 return (cfp->close == NULL) ? 0 : cfp->close(cfp->param);
893 /* we can't use apr_file_* directly because of linking issues on Windows */
894 static apr_status_t cfg_close(void *param)
896 return apr_file_close(param);
899 static apr_status_t cfg_getch(char *ch, void *param)
901 return apr_file_getc(ch, param);
904 static apr_status_t cfg_getstr(void *buf, apr_size_t bufsiz, void *param)
906 return apr_file_gets(buf, bufsiz, param);
909 /* Open a ap_configfile_t as FILE, return open ap_configfile_t struct pointer */
910 AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg,
911 apr_pool_t *p, const char *name)
913 ap_configfile_t *new_cfg;
914 apr_file_t *file = NULL;
922 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00552)
923 "Internal error: pcfg_openfile() called with NULL filename");
927 status = apr_file_open(&file, name, APR_READ | APR_BUFFERED,
930 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00553)
931 "Opening config file %s (%s)",
932 name, (status != APR_SUCCESS) ?
933 apr_strerror(status, buf, sizeof(buf)) : "successful");
935 if (status != APR_SUCCESS)
938 status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file);
939 if (status != APR_SUCCESS)
942 if (finfo.filetype != APR_REG &&
943 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
944 ap_cstr_casecmp(apr_filepath_name_get(name), "nul") != 0) {
946 strcmp(name, "/dev/null") != 0) {
947 #endif /* WIN32 || OS2 */
948 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00554)
949 "Access to file %s denied by server: not a regular file",
951 apr_file_close(file);
956 /* Some twisted character [no pun intended] at MS decided that a
957 * zero width joiner as the lead wide character would be ideal for
958 * describing Unicode text files. This was further convoluted to
959 * another MSism that the same character mapped into utf-8, EF BB BF
960 * would signify utf-8 text files.
962 * Since MS configuration files are all protecting utf-8 encoded
963 * Unicode path, file and resource names, we already have the correct
964 * WinNT encoding. But at least eat the stupid three bytes up front.
967 unsigned char buf[4];
969 status = apr_file_read(file, buf, &len);
970 if ((status != APR_SUCCESS) || (len < 3)
971 || memcmp(buf, "\xEF\xBB\xBF", 3) != 0) {
973 apr_file_seek(file, APR_SET, &zero);
978 new_cfg = apr_palloc(p, sizeof(*new_cfg));
979 new_cfg->param = file;
980 new_cfg->name = apr_pstrdup(p, name);
981 new_cfg->getch = cfg_getch;
982 new_cfg->getstr = cfg_getstr;
983 new_cfg->close = cfg_close;
984 new_cfg->line_number = 0;
990 /* Allocate a ap_configfile_t handle with user defined functions and params */
991 AP_DECLARE(ap_configfile_t *) ap_pcfg_open_custom(
992 apr_pool_t *p, const char *descr, void *param,
993 apr_status_t (*getc_func) (char *ch, void *param),
994 apr_status_t (*gets_func) (void *buf, apr_size_t bufsize, void *param),
995 apr_status_t (*close_func) (void *param))
997 ap_configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg));
998 new_cfg->param = param;
999 new_cfg->name = descr;
1000 new_cfg->getch = getc_func;
1001 new_cfg->getstr = gets_func;
1002 new_cfg->close = close_func;
1003 new_cfg->line_number = 0;
1007 /* Read one character from a configfile_t */
1008 AP_DECLARE(apr_status_t) ap_cfg_getc(char *ch, ap_configfile_t *cfp)
1010 apr_status_t rc = cfp->getch(ch, cfp->param);
1011 if (rc == APR_SUCCESS && *ch == LF)
1016 AP_DECLARE(const char *) ap_pcfg_strerror(apr_pool_t *p, ap_configfile_t *cfp,
1019 if (rc == APR_SUCCESS)
1022 if (rc == APR_ENOSPC)
1023 return apr_psprintf(p, "Error reading %s at line %d: Line too long",
1024 cfp->name, cfp->line_number);
1026 return apr_psprintf(p, "Error reading %s at line %d: %pm",
1027 cfp->name, cfp->line_number, &rc);
1030 /* Read one line from open ap_configfile_t, strip LF, increase line number */
1031 /* If custom handler does not define a getstr() function, read char by char */
1032 static apr_status_t ap_cfg_getline_core(char *buf, apr_size_t bufsize,
1033 apr_size_t offset, ap_configfile_t *cfp)
1036 /* If a "get string" function is defined, use it */
1037 if (cfp->getstr != NULL) {
1039 char *cbuf = buf + offset;
1040 apr_size_t cbufsize = bufsize - offset;
1044 rc = cfp->getstr(cbuf, cbufsize, cfp->param);
1045 if (rc == APR_EOF) {
1046 if (cbuf != buf + offset) {
1054 if (rc != APR_SUCCESS) {
1059 * check for line continuation,
1060 * i.e. match [^\\]\\[\r]\n only
1064 if (cp > buf && cp[-1] == LF) {
1066 if (cp > buf && cp[-1] == CR)
1068 if (cp > buf && cp[-1] == '\\') {
1071 * line continuation requested -
1072 * then remove backslash and continue
1074 cbufsize -= (cp-cbuf);
1079 else if (cp - buf >= bufsize - 1) {
1085 /* No "get string" function defined; read character by character */
1086 apr_size_t i = offset;
1089 /* too small, assume caller is crazy */
1096 rc = cfp->getch(&c, cfp->param);
1097 if (rc == APR_EOF) {
1103 if (rc != APR_SUCCESS)
1107 /* check for line continuation */
1108 if (i > 0 && buf[i-1] == '\\') {
1118 if (i >= bufsize - 1) {
1127 static int cfg_trim_line(char *buf)
1131 * Leading and trailing white space is eliminated completely
1134 while (apr_isspace(*start))
1136 /* blast trailing whitespace */
1137 end = &start[strlen(start)];
1138 while (--end >= start && apr_isspace(*end))
1140 /* Zap leading whitespace by shifting */
1142 memmove(buf, start, end - start + 2);
1143 #ifdef DEBUG_CFG_LINES
1144 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, APLOGNO(00555) "Read config: '%s'", buf);
1146 return end - start + 1;
1149 /* Read one line from open ap_configfile_t, strip LF, increase line number */
1150 /* If custom handler does not define a getstr() function, read char by char */
1151 AP_DECLARE(apr_status_t) ap_cfg_getline(char *buf, apr_size_t bufsize,
1152 ap_configfile_t *cfp)
1154 apr_status_t rc = ap_cfg_getline_core(buf, bufsize, 0, cfp);
1155 if (rc == APR_SUCCESS)
1160 AP_DECLARE(apr_status_t) ap_varbuf_cfg_getline(struct ap_varbuf *vb,
1161 ap_configfile_t *cfp,
1169 if (vb->strlen == AP_VARBUF_UNKNOWN)
1170 vb->strlen = strlen(vb->buf);
1171 if (vb->avail - vb->strlen < 3) {
1172 new_len = vb->avail * 2;
1173 if (new_len > max_len)
1175 else if (new_len < 3)
1177 ap_varbuf_grow(vb, new_len);
1181 rc = ap_cfg_getline_core(vb->buf, vb->avail, vb->strlen, cfp);
1182 if (rc == APR_ENOSPC || rc == APR_SUCCESS)
1183 vb->strlen += strlen(vb->buf + vb->strlen);
1184 if (rc != APR_ENOSPC)
1186 if (vb->avail >= max_len)
1188 new_len = vb->avail * 2;
1189 if (new_len > max_len)
1191 ap_varbuf_grow(vb, new_len);
1194 if (vb->strlen > max_len)
1196 if (rc == APR_SUCCESS)
1197 vb->strlen = cfg_trim_line(vb->buf);
1201 /* Size an HTTP header field list item, as separated by a comma.
1202 * The return value is a pointer to the beginning of the non-empty list item
1203 * within the original string (or NULL if there is none) and the address
1204 * of field is shifted to the next non-comma, non-whitespace character.
1205 * len is the length of the item excluding any beginning whitespace.
1207 AP_DECLARE(const char *) ap_size_list_item(const char **field, int *len)
1209 const unsigned char *ptr = (const unsigned char *)*field;
1210 const unsigned char *token;
1211 int in_qpair, in_qstr, in_com;
1213 /* Find first non-comma, non-whitespace byte */
1215 while (*ptr == ',' || apr_isspace(*ptr))
1220 /* Find the end of this item, skipping over dead bits */
1222 for (in_qpair = in_qstr = in_com = 0;
1223 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1231 case '\\': in_qpair = 1; /* quoted-pair */
1233 case '"' : if (!in_com) /* quoted string delim */
1236 case '(' : if (!in_qstr) /* comment (may nest) */
1239 case ')' : if (in_com) /* end comment */
1247 if ((*len = (ptr - token)) == 0) {
1248 *field = (const char *)ptr;
1252 /* Advance field pointer to the next non-comma, non-white byte */
1254 while (*ptr == ',' || apr_isspace(*ptr))
1257 *field = (const char *)ptr;
1258 return (const char *)token;
1261 /* Retrieve an HTTP header field list item, as separated by a comma,
1262 * while stripping insignificant whitespace and lowercasing anything not in
1263 * a quoted string or comment. The return value is a new string containing
1264 * the converted list item (or NULL if none) and the address pointed to by
1265 * field is shifted to the next non-comma, non-whitespace.
1267 AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field)
1269 const char *tok_start;
1270 const unsigned char *ptr;
1273 int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
1275 /* Find the beginning and maximum length of the list item so that
1276 * we can allocate a buffer for the new string and reset the field.
1278 if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
1281 token = apr_palloc(p, tok_len + 1);
1283 /* Scan the token again, but this time copy only the good bytes.
1284 * We skip extra whitespace and any whitespace around a '=', '/',
1285 * or ';' and lowercase normal characters not within a comment,
1286 * quoted-string or quoted-pair.
1288 for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
1289 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1298 case '\\': in_qpair = 1;
1304 case '"' : if (!in_com)
1311 case '(' : if (!in_qstr)
1318 case ')' : if (in_com)
1324 case '\t': if (addspace)
1326 if (in_com || in_qstr)
1333 case ';' : if (!(in_com || in_qstr))
1337 default : if (addspace == 1)
1339 *pos++ = (in_com || in_qstr) ? *ptr
1340 : apr_tolower(*ptr);
1351 typedef enum ap_etag_e {
1357 /* Find an item in canonical form (lowercase, no extra spaces) within
1358 * an HTTP field value list. Returns 1 if found, 0 if not found.
1359 * This would be much more efficient if we stored header fields as
1360 * an array of list items as they are received instead of a plain string.
1362 static int find_list_item(apr_pool_t *p, const char *line,
1363 const char *tok, ap_etag_e type)
1365 const unsigned char *pos;
1366 const unsigned char *ptr = (const unsigned char *)line;
1367 int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
1369 if (!line || !tok) {
1372 if (type == AP_ETAG_STRONG && *tok != '\"') {
1375 if (type == AP_ETAG_WEAK) {
1376 if (*tok == 'W' && (*(tok+1)) == '/' && (*(tok+2)) == '\"') {
1379 else if (*tok != '\"') {
1384 do { /* loop for each item in line's list */
1386 /* Find first non-comma, non-whitespace byte */
1387 while (*ptr == ',' || apr_isspace(*ptr)) {
1391 /* Account for strong or weak Etags, depending on our search */
1392 if (type == AP_ETAG_STRONG && *ptr != '\"') {
1395 if (type == AP_ETAG_WEAK) {
1396 if (*ptr == 'W' && (*(ptr+1)) == '/' && (*(ptr+2)) == '\"') {
1399 else if (*ptr != '\"') {
1405 good = 1; /* until proven otherwise for this item */
1407 break; /* no items left and nothing good found */
1409 /* We skip extra whitespace and any whitespace around a '=', '/',
1410 * or ';' and lowercase normal characters not within a comment,
1411 * quoted-string or quoted-pair.
1413 for (pos = (const unsigned char *)tok;
1414 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1420 good = (*pos++ == *ptr);
1424 case '\\': in_qpair = 1;
1426 good = good && (*pos++ == ' ');
1427 good = good && (*pos++ == *ptr);
1430 case '"' : if (!in_com)
1433 good = good && (*pos++ == ' ');
1434 good = good && (*pos++ == *ptr);
1437 case '(' : if (!in_qstr)
1440 good = good && (*pos++ == ' ');
1441 good = good && (*pos++ == *ptr);
1444 case ')' : if (in_com)
1446 good = good && (*pos++ == *ptr);
1450 case '\t': if (addspace || !good)
1452 if (in_com || in_qstr)
1453 good = (*pos++ == *ptr);
1459 case ';' : if (!(in_com || in_qstr))
1461 good = good && (*pos++ == *ptr);
1463 default : if (!good)
1466 good = (*pos++ == ' ');
1467 if (in_com || in_qstr)
1468 good = good && (*pos++ == *ptr);
1471 && (apr_tolower(*pos++) == apr_tolower(*ptr));
1478 good = 0; /* not good if only a prefix was matched */
1480 } while (*ptr && !good);
1485 /* Find an item in canonical form (lowercase, no extra spaces) within
1486 * an HTTP field value list. Returns 1 if found, 0 if not found.
1487 * This would be much more efficient if we stored header fields as
1488 * an array of list items as they are received instead of a plain string.
1490 AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line,
1493 return find_list_item(p, line, tok, AP_ETAG_NONE);
1496 /* Find a strong Etag in canonical form (lowercase, no extra spaces) within
1497 * an HTTP field value list. Returns 1 if found, 0 if not found.
1499 AP_DECLARE(int) ap_find_etag_strong(apr_pool_t *p, const char *line,
1502 return find_list_item(p, line, tok, AP_ETAG_STRONG);
1505 /* Find a weak ETag in canonical form (lowercase, no extra spaces) within
1506 * an HTTP field value list. Returns 1 if found, 0 if not found.
1508 AP_DECLARE(int) ap_find_etag_weak(apr_pool_t *p, const char *line,
1511 return find_list_item(p, line, tok, AP_ETAG_WEAK);
1514 /* Grab a list of tokens of the format 1#token (from RFC7230) */
1515 AP_DECLARE(const char *) ap_parse_token_list_strict(apr_pool_t *p,
1517 apr_array_header_t **tokens,
1520 int in_leading_space = 1;
1521 int in_trailing_space = 0;
1523 const char *tok_begin;
1530 tok_begin = cur = str_in;
1532 while (!string_end) {
1533 const unsigned char c = (unsigned char)*cur;
1535 if (!TEST_CHAR(c, T_HTTP_TOKEN_STOP)) {
1536 /* Non-separator character; we are finished with leading
1537 * whitespace. We must never have encountered any trailing
1538 * whitespace before the delimiter (comma) */
1539 in_leading_space = 0;
1540 if (in_trailing_space) {
1541 return "Encountered illegal whitespace in token";
1544 else if (c == ' ' || c == '\t') {
1545 /* "Linear whitespace" only includes ASCII CRLF, space, and tab;
1546 * we can't get a CRLF since headers are split on them already,
1547 * so only look for a space or a tab */
1548 if (in_leading_space) {
1549 /* We're still in leading whitespace */
1553 /* We must be in trailing whitespace */
1554 ++in_trailing_space;
1557 else if (c == ',' || c == '\0') {
1558 if (!in_leading_space) {
1559 /* If we're out of the leading space, we know we've read some
1560 * characters of a token */
1561 if (*tokens == NULL) {
1562 *tokens = apr_array_make(p, 4, sizeof(char *));
1564 APR_ARRAY_PUSH(*tokens, char *) =
1565 apr_pstrmemdup((*tokens)->pool, tok_begin,
1566 (cur - tok_begin) - in_trailing_space);
1568 /* We're allowed to have null elements, just don't add them to the
1571 tok_begin = cur + 1;
1572 in_leading_space = 1;
1573 in_trailing_space = 0;
1574 string_end = (c == '\0');
1577 /* Encountered illegal separator char */
1579 /* Skip to the next separator */
1581 temp = ap_strchr_c(cur, ',');
1583 temp = ap_strchr_c(cur, '\0');
1586 /* Act like we haven't seen a token so we reset */
1588 in_leading_space = 1;
1589 in_trailing_space = 0;
1592 return apr_psprintf(p, "Encountered illegal separator "
1593 "'\\x%.2x'", (unsigned int)c);
1603 /* Scan a string for HTTP VCHAR/obs-text characters including HT and SP
1604 * (as used in header values, for example, in RFC 7230 section 3.2)
1605 * returning the pointer to the first non-HT ASCII ctrl character.
1607 AP_DECLARE(const char *) ap_scan_http_field_content(const char *ptr)
1609 for ( ; !TEST_CHAR(*ptr, T_HTTP_CTRLS); ++ptr) ;
1614 /* Scan a string for HTTP token characters, returning the pointer to
1615 * the first non-token character.
1617 AP_DECLARE(const char *) ap_scan_http_token(const char *ptr)
1619 for ( ; !TEST_CHAR(*ptr, T_HTTP_TOKEN_STOP); ++ptr) ;
1624 /* Scan a string for visible ASCII (0x21-0x7E) or obstext (0x80+)
1625 * and return a pointer to the first ctrl/space character encountered.
1627 AP_DECLARE(const char *) ap_scan_vchar_obstext(const char *ptr)
1629 for ( ; TEST_CHAR(*ptr, T_VCHAR_OBSTEXT); ++ptr) ;
1634 /* Retrieve a token, spacing over it and returning a pointer to
1635 * the first non-white byte afterwards. Note that these tokens
1636 * are delimited by semis and commas; and can also be delimited
1637 * by whitespace at the caller's option.
1640 AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line,
1643 const char *ptr = *accept_line;
1644 const char *tok_start;
1647 /* Find first non-white byte */
1649 while (apr_isspace(*ptr))
1654 /* find token end, skipping over quoted strings.
1655 * (comments are already gone).
1658 while (*ptr && (accept_white || !apr_isspace(*ptr))
1659 && *ptr != ';' && *ptr != ',') {
1666 token = apr_pstrmemdup(p, tok_start, ptr - tok_start);
1668 /* Advance accept_line pointer to the next non-white byte */
1670 while (apr_isspace(*ptr))
1678 /* find http tokens, see the definition of token from RFC2068 */
1679 AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
1681 const unsigned char *start_token;
1682 const unsigned char *s;
1687 s = (const unsigned char *)line;
1689 /* find start of token, skip all stop characters */
1690 while (*s && TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1697 /* find end of the token */
1698 while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1701 if (!ap_cstr_casecmpn((const char *)start_token, (const char *)tok,
1712 AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line,
1715 int llen, tlen, lidx;
1720 llen = strlen(line);
1725 (lidx > 0 && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1728 return (ap_cstr_casecmpn(&line[lidx], tok, tlen) == 0);
1731 AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1735 const unsigned char *s;
1737 cmd = apr_palloc(p, 2 * strlen(str) + 1); /* Be safe */
1738 d = (unsigned char *)cmd;
1739 s = (const unsigned char *)str;
1742 #if defined(OS2) || defined(WIN32)
1744 * Newlines to Win32/OS2 CreateProcess() are ill advised.
1745 * Convert them to spaces since they are effectively white
1746 * space to most applications
1748 if (*s == '\r' || *s == '\n') {
1754 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1764 static char x2c(const char *what)
1768 #if !APR_CHARSET_EBCDIC
1769 digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
1772 digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
1774 #else /*APR_CHARSET_EBCDIC*/
1781 digit = apr_xlate_conv_byte(ap_hdrs_from_ascii,
1782 0xFF & strtol(xstr, NULL, 16));
1783 #endif /*APR_CHARSET_EBCDIC*/
1788 * Unescapes a URL, leaving reserved characters intact.
1789 * Returns 0 on success, non-zero on error
1791 * bad % escape returns HTTP_BAD_REQUEST
1793 * decoding %00 or a forbidden character returns HTTP_NOT_FOUND
1796 static int unescape_url(char *url, const char *forbid, const char *reserved)
1798 int badesc, badpath;
1807 /* Initial scan for first '%'. Don't bother writing values before
1809 y = strchr(url, '%');
1813 for (x = y; *y; ++x, ++y) {
1818 if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1824 decoded = x2c(y + 1);
1825 if ((decoded == '\0')
1826 || (forbid && ap_strchr_c(forbid, decoded))) {
1831 else if (reserved && ap_strchr_c(reserved, decoded)) {
1845 return HTTP_BAD_REQUEST;
1848 return HTTP_NOT_FOUND;
1854 AP_DECLARE(int) ap_unescape_url(char *url)
1857 return unescape_url(url, SLASHES, NULL);
1859 AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes)
1861 /* AllowEncodedSlashes (corrected) */
1862 if (decode_slashes) {
1863 /* no chars reserved */
1864 return unescape_url(url, NULL, NULL);
1866 /* reserve (do not decode) encoded slashes */
1867 return unescape_url(url, NULL, SLASHES);
1871 /* IFDEF these out until they've been thought through.
1872 * Just a germ of an API extension for now
1874 AP_DECLARE(int) ap_unescape_url_proxy(char *url)
1876 /* leave RFC1738 reserved characters intact, * so proxied URLs
1877 * don't get mangled. Where does that leave encoded '&' ?
1879 return unescape_url(url, NULL, "/;?");
1881 AP_DECLARE(int) ap_unescape_url_reserved(char *url, const char *reserved)
1883 return unescape_url(url, NULL, reserved);
1887 AP_DECLARE(int) ap_unescape_urlencoded(char *query)
1891 /* replace plus with a space */
1893 for (slider = query; *slider; slider++) {
1894 if (*slider == '+') {
1900 /* unescape everything else */
1901 return unescape_url(query, NULL, NULL);
1904 AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname,
1905 apr_port_t port, const request_rec *r)
1907 if (ap_is_default_port(port, r)) {
1908 return apr_pstrdup(p, hostname);
1911 return apr_psprintf(p, "%s:%u", hostname, port);
1915 AP_DECLARE(int) ap_unescape_all(char *url)
1917 return unescape_url(url, NULL, NULL);
1920 /* c2x takes an unsigned, and expects the caller has guaranteed that
1921 * 0 <= what < 256... which usually means that you have to cast to
1922 * unsigned char first, because (unsigned)(char)(x) first goes through
1923 * signed extension to an int before the unsigned cast.
1925 * The reason for this assumption is to assist gcc code generation --
1926 * the unsigned char -> unsigned extension is already done earlier in
1927 * both uses of this code, so there's no need to waste time doing it
1930 static const char c2x_table[] = "0123456789abcdef";
1932 static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
1933 unsigned char *where)
1935 #if APR_CHARSET_EBCDIC
1936 what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
1937 #endif /*APR_CHARSET_EBCDIC*/
1939 *where++ = c2x_table[what >> 4];
1940 *where++ = c2x_table[what & 0xf];
1945 * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
1946 * routine is (should be) OS independent.
1948 * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
1949 * cases if a ':' occurs before the first '/' in the URL, the URL should be
1950 * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
1951 * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
1952 * efficiency reasons, we don't use escape_path_segment(), which is provided for
1953 * reference. Again, RFC 1808 is where this stuff is defined.
1955 * If partial is set, os_escape_path() assumes that the path will be appended to
1956 * something with a '/' in it (and thus does not prefix "./").
1959 AP_DECLARE(char *) ap_escape_path_segment_buffer(char *copy, const char *segment)
1961 const unsigned char *s = (const unsigned char *)segment;
1962 unsigned char *d = (unsigned char *)copy;
1966 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
1978 AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
1980 return ap_escape_path_segment_buffer(apr_palloc(p, 3 * strlen(segment) + 1), segment);
1983 AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
1985 /* Allocate +3 for potential "./" and trailing NULL.
1986 * Allocate another +1 to allow the caller to add a trailing '/' (see
1987 * comment in 'ap_sub_req_lookup_dirent')
1989 char *copy = apr_palloc(p, 3 * strlen(path) + 3 + 1);
1990 const unsigned char *s = (const unsigned char *)path;
1991 unsigned char *d = (unsigned char *)copy;
1995 const char *colon = ap_strchr_c(path, ':');
1996 const char *slash = ap_strchr_c(path, '/');
1998 if (colon && (!slash || colon < slash)) {
2004 if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
2016 AP_DECLARE(char *) ap_escape_urlencoded_buffer(char *copy, const char *buffer)
2018 const unsigned char *s = (const unsigned char *)buffer;
2019 unsigned char *d = (unsigned char *)copy;
2023 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
2026 else if (c == ' ') {
2038 AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
2040 return ap_escape_urlencoded_buffer(apr_palloc(p, 3 * strlen(buffer) + 1), buffer);
2043 /* ap_escape_uri is now a macro for os_escape_path */
2045 AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
2050 /* first, count the number of extra characters */
2051 for (i = 0, j = 0; s[i] != '\0'; i++)
2052 if (s[i] == '<' || s[i] == '>')
2054 else if (s[i] == '&')
2056 else if (s[i] == '"')
2058 else if (toasc && !apr_isascii(s[i]))
2062 return apr_pstrmemdup(p, s, i);
2064 x = apr_palloc(p, i + j + 1);
2065 for (i = 0, j = 0; s[i] != '\0'; i++, j++)
2067 memcpy(&x[j], "<", 4);
2070 else if (s[i] == '>') {
2071 memcpy(&x[j], ">", 4);
2074 else if (s[i] == '&') {
2075 memcpy(&x[j], "&", 5);
2078 else if (s[i] == '"') {
2079 memcpy(&x[j], """, 6);
2082 else if (toasc && !apr_isascii(s[i])) {
2083 char *esc = apr_psprintf(p, "&#%3.3d;", (unsigned char)s[i]);
2084 memcpy(&x[j], esc, 6);
2093 AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str)
2097 const unsigned char *s;
2098 apr_size_t length, escapes = 0;
2104 /* Compute how many characters need to be escaped */
2105 s = (const unsigned char *)str;
2107 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2112 /* Compute the length of the input string, including NULL */
2113 length = s - (const unsigned char *)str + 1;
2115 /* Fast path: nothing to escape */
2117 return apr_pmemdup(p, str, length);
2120 /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */
2121 ret = apr_palloc(p, length + 3 * escapes);
2122 d = (unsigned char *)ret;
2123 s = (const unsigned char *)str;
2125 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2161 AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
2164 unsigned char *d, *ep;
2165 const unsigned char *s;
2167 if (!source || !buflen) { /* be safe */
2171 d = (unsigned char *)dest;
2172 s = (const unsigned char *)source;
2173 ep = d + buflen - 1;
2175 for (; d < ep && *s; ++s) {
2177 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2203 case '"': /* no need for this in error log */
2208 ep = --d; /* break the for loop as well */
2221 return (d - (unsigned char *)dest);
2224 AP_DECLARE(void) ap_bin2hex(const void *src, apr_size_t srclen, char *dest)
2226 const unsigned char *in = src;
2229 for (i = 0; i < srclen; i++) {
2230 *dest++ = c2x_table[in[i] >> 4];
2231 *dest++ = c2x_table[in[i] & 0xf];
2236 AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
2240 if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS)
2241 return 0; /* in error condition, just return no */
2243 return (finfo.filetype == APR_DIR);
2246 AP_DECLARE(int) ap_is_rdirectory(apr_pool_t *p, const char *path)
2250 if (apr_stat(&finfo, path, APR_FINFO_LINK | APR_FINFO_TYPE, p) != APR_SUCCESS)
2251 return 0; /* in error condition, just return no */
2253 return (finfo.filetype == APR_DIR);
2256 AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
2259 apr_size_t len1, len2;
2262 len1 = strlen(src1);
2263 len2 = strlen(src2);
2264 /* allocate +3 for '/' delimiter, trailing NULL and overallocate
2265 * one extra byte to allow the caller to add a trailing '/'
2267 path = (char *)apr_palloc(a, len1 + len2 + 3);
2270 memcpy(path + 1, src2, len2 + 1);
2274 memcpy(path, src1, len1);
2276 if (next[-1] != '/') {
2279 memcpy(next, src2, len2 + 1);
2285 * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
2287 AP_DECLARE(int) ap_is_url(const char *u)
2291 for (x = 0; u[x] != ':'; x++) {
2293 ((!apr_isalnum(u[x])) &&
2294 (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
2299 return (x ? 1 : 0); /* If the first character is ':', it's broken, too */
2302 AP_DECLARE(int) ap_ind(const char *s, char c)
2304 const char *p = ap_strchr_c(s, c);
2311 AP_DECLARE(int) ap_rind(const char *s, char c)
2313 const char *p = ap_strrchr_c(s, c);
2320 AP_DECLARE(void) ap_str_tolower(char *str)
2323 *str = apr_tolower(*str);
2328 AP_DECLARE(void) ap_str_toupper(char *str)
2331 *str = apr_toupper(*str);
2337 * We must return a FQDN
2339 char *ap_get_local_host(apr_pool_t *a)
2341 #ifndef MAXHOSTNAMELEN
2342 #define MAXHOSTNAMELEN 256
2344 char str[MAXHOSTNAMELEN + 1];
2345 char *server_hostname = NULL;
2346 apr_sockaddr_t *sockaddr;
2349 if (apr_gethostname(str, sizeof(str) - 1, a) != APR_SUCCESS) {
2350 ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00556)
2351 "%s: apr_gethostname() failed to determine ServerName",
2354 str[sizeof(str) - 1] = '\0';
2355 if (apr_sockaddr_info_get(&sockaddr, str, APR_UNSPEC, 0, 0, a) == APR_SUCCESS) {
2356 if ( (apr_getnameinfo(&hostname, sockaddr, 0) == APR_SUCCESS) &&
2357 (ap_strchr_c(hostname, '.')) ) {
2358 server_hostname = apr_pstrdup(a, hostname);
2359 return server_hostname;
2360 } else if (ap_strchr_c(str, '.')) {
2361 server_hostname = apr_pstrdup(a, str);
2363 apr_sockaddr_ip_get(&hostname, sockaddr);
2364 server_hostname = apr_pstrdup(a, hostname);
2367 ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00557)
2368 "%s: apr_sockaddr_info_get() failed for %s",
2369 ap_server_argv0, str);
2373 if (!server_hostname)
2374 server_hostname = apr_pstrdup(a, "127.0.0.1");
2376 ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, a, APLOGNO(00558)
2377 "%s: Could not reliably determine the server's fully qualified "
2378 "domain name, using %s. Set the 'ServerName' directive globally "
2379 "to suppress this message",
2380 ap_server_argv0, server_hostname);
2382 return server_hostname;
2385 /* simple 'pool' alloc()ing glue to apr_base64.c
2387 AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
2392 decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded));
2393 l = apr_base64_decode(decoded, bufcoded);
2394 decoded[l] = '\0'; /* make binary sequence into string */
2399 /* a stringent version of ap_pbase64decode() */
2400 AP_DECLARE(apr_status_t) ap_pbase64decode_strict(apr_pool_t *p,
2401 const char *encoded,
2405 apr_size_t end_index;
2410 * TODO: this would be a lot more efficient if we had access to the lookup
2411 * table used by APR. If that gets pulled in at any point, make use of it.
2413 end_index = strspn(encoded, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2414 "abcdefghijklmnopqrstuvwxyz"
2417 last_group_len = end_index % 4;
2418 end = encoded + end_index;
2420 /* The only non-alphabet character allowed is the padding character '=' at
2421 * the end of the string. There are two allowable padding cases for the last
2422 * group of four: "xY==" or "xyZ=". We require the final (non-padding)
2423 * character to have been zero-padded during encoding, which limits the
2424 * character choices.
2426 if (last_group_len == 1) {
2427 /* This isn't ever valid. */
2430 else if (last_group_len == 2) {
2432 if (*end != '=' || end[1] != '=') {
2435 else if (!ap_strchr("AQgw", end[-1])) {
2436 /* Correctly zero-padded input data will result in a final character
2437 * that is one of the four above. */
2443 else if (last_group_len == 3) {
2448 else if (!ap_strchr("AEIMQUYcgkosw048", end[-1])) {
2449 /* Correctly zero-padded input data will result in a final character
2450 * that is one of the sixteen above. */
2457 /* At this point, if the encoded buffer is correct, we should be at the end
2463 *decoded = apr_palloc(p, apr_base64_decode_len(encoded));
2464 *len = apr_base64_decode(*decoded, encoded);
2469 AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
2472 int l = strlen(string);
2474 encoded = (char *) apr_palloc(p, 1 + apr_base64_encode_len(l));
2475 l = apr_base64_encode(encoded, string, l);
2476 encoded[l] = '\0'; /* make binary sequence into string */
2481 /* we want to downcase the type/subtype for comparison purposes
2482 * but nothing else because ;parameter=foo values are case sensitive.
2483 * XXX: in truth we want to downcase parameter names... but really,
2484 * apache has never handled parameters and such correctly. You
2485 * also need to compress spaces and such to be able to compare
2488 AP_DECLARE(void) ap_content_type_tolower(char *str)
2492 semi = strchr(str, ';');
2497 ap_str_tolower(str);
2505 * Given a string, replace any bare " with \" .
2507 AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
2510 const char *inchr = instring;
2511 char *outchr, *outstring;
2514 * Look through the input string, jogging the length of the output
2515 * string up by an extra byte each time we find an unescaped ".
2517 while (*inchr != '\0') {
2519 if (*inchr == '"') {
2523 * If we find a slosh, and it's not the last byte in the string,
2524 * it's escaping something - advance past both bytes.
2526 if ((*inchr == '\\') && (inchr[1] != '\0')) {
2532 outstring = apr_palloc(p, newlen + 1);
2536 * Now copy the input string to the output string, inserting a slosh
2537 * in front of every " that doesn't already have one.
2539 while (*inchr != '\0') {
2540 if ((*inchr == '\\') && (inchr[1] != '\0')) {
2541 *outchr++ = *inchr++;
2542 *outchr++ = *inchr++;
2544 if (*inchr == '"') {
2547 if (*inchr != '\0') {
2548 *outchr++ = *inchr++;
2556 * Given a string, append the PID deliminated by delim.
2557 * Usually used to create a pid-appended filepath name
2558 * (eg: /a/b/foo -> /a/b/foo.6726). A function, and not
2559 * a macro, to avoid unistd.h dependency
2561 AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string,
2564 return apr_psprintf(p, "%s%s%" APR_PID_T_FMT, string,
2570 * Parse a given timeout parameter string into an apr_interval_time_t value.
2571 * The unit of the time interval is given as postfix string to the numeric
2572 * string. Currently the following units are understood (case insensitive):
2579 * If no unit is contained in the given timeout parameter the default_time_unit
2580 * will be used instead.
2581 * @param timeout_parameter The string containing the timeout parameter.
2582 * @param timeout The timeout value to be returned.
2583 * @param default_time_unit The default time unit to use if none is specified
2584 * in timeout_parameter.
2585 * @return Status value indicating whether the parsing was successful or not.
2587 AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
2588 const char *timeout_parameter,
2589 apr_interval_time_t *timeout,
2590 const char *default_time_unit)
2593 const char *time_str;
2596 tout = apr_strtoi64(timeout_parameter, &endp, 10);
2600 if (!endp || !*endp) {
2601 time_str = default_time_unit;
2607 switch (*time_str) {
2608 /* Time is in seconds */
2611 *timeout = (apr_interval_time_t) apr_time_from_sec(tout);
2615 /* Time is in hours */
2616 *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 3600);
2620 switch (*(++time_str)) {
2621 /* Time is in milliseconds */
2624 *timeout = (apr_interval_time_t) tout * 1000;
2626 /* Time is in minutes */
2629 *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 60);
2632 return APR_EGENERAL;
2636 return APR_EGENERAL;
2642 * Determine if a request has a request body or not.
2644 * @param r the request_rec of the request
2645 * @return truth value
2647 AP_DECLARE(int) ap_request_has_body(request_rec *r)
2654 has_body = (!r->header_only
2656 || apr_table_get(r->headers_in, "Transfer-Encoding")
2657 || ( (cls = apr_table_get(r->headers_in, "Content-Length"))
2658 && (apr_strtoff(&cl, cls, &estr, 10) == APR_SUCCESS)
2667 * Check whether a request is tainted by exposure to something
2668 * potentially untrusted.
2671 AP_DECLARE(int) ap_request_tainted(request_rec *r, int flags)
2673 /** Potential future: a hook or callback here could serve modules
2674 * like mod_security and ironbee with more complex needs.
2676 return r && ((r->taint&flags)
2677 || ap_request_tainted(r->main, flags)
2678 || ap_request_tainted(r->prev, flags));
2681 AP_DECLARE_NONSTD(apr_status_t) ap_pool_cleanup_set_null(void *data_)
2683 void **ptr = (void **)data_;
2688 AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
2690 for ( ; *src; src++, dest++)
2692 if (!apr_isprint(*src))
2694 else if (!apr_isalnum(*src))
2704 AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
2707 char *new = apr_palloc(p, strlen(src)+1);
2711 return ap_str2_alnum(src, new);
2715 * Read the body and parse any form found, which must be of the
2716 * type application/x-www-form-urlencoded.
2718 * Name/value pairs are returned in an array, with the names as
2719 * strings with a maximum length of HUGE_STRING_LEN, and the
2720 * values as bucket brigades. This allows values to be arbitrarily
2723 * All url-encoding is removed from both the names and the values
2724 * on the fly. The names are interpreted as strings, while the
2725 * values are interpreted as blocks of binary data, that may
2726 * contain the 0 character.
2728 * In order to ensure that resource limits are not exceeded, a
2729 * maximum size must be provided. If the sum of the lengths of
2730 * the names and the values exceed this size, this function
2731 * will return HTTP_REQUEST_ENTITY_TOO_LARGE.
2733 * An optional number of parameters can be provided, if the number
2734 * of parameters provided exceeds this amount, this function will
2735 * return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
2736 * no limit is imposed, and the number of parameters is in turn
2737 * constrained by the size parameter above.
2739 * This function honours any kept_body configuration, and the
2740 * original raw request body will be saved to the kept_body brigade
2741 * if so configured, just as ap_discard_request_body does.
2743 * NOTE: File upload is not yet supported, but can be without change
2744 * to the function call.
2747 /* form parsing stuff */
2758 AP_DECLARE(int) ap_parse_form_data(request_rec *r, ap_filter_t *f,
2759 apr_array_header_t **ptr,
2760 apr_size_t num, apr_size_t usize)
2762 apr_bucket_brigade *bb = NULL;
2764 char buffer[HUGE_STRING_LEN + 1];
2766 apr_size_t offset = 0;
2768 ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
2769 ap_form_pair_t *pair = NULL;
2770 apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
2771 char escaped_char[2] = { 0 };
2775 /* sanity check - we only support forms for now */
2776 ct = apr_table_get(r->headers_in, "Content-Type");
2777 if (!ct || ap_cstr_casecmpn("application/x-www-form-urlencoded", ct, 33)) {
2778 return ap_discard_request_body(r);
2781 if (usize > APR_SIZE_MAX >> 1)
2782 size = APR_SIZE_MAX >> 1;
2787 f = r->input_filters;
2790 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2792 apr_bucket *bucket = NULL, *last = NULL;
2794 int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
2795 APR_BLOCK_READ, HUGE_STRING_LEN);
2796 if (rv != APR_SUCCESS) {
2797 apr_brigade_destroy(bb);
2798 return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
2801 for (bucket = APR_BRIGADE_FIRST(bb);
2802 bucket != APR_BRIGADE_SENTINEL(bb);
2803 last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
2805 apr_size_t len, slide;
2808 apr_bucket_delete(last);
2810 if (APR_BUCKET_IS_EOS(bucket)) {
2814 if (bucket->length == 0) {
2818 rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
2819 if (rv != APR_SUCCESS) {
2820 apr_brigade_destroy(bb);
2821 return HTTP_BAD_REQUEST;
2825 while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
2830 else if ('&' == c) {
2834 percent = FORM_PERCENTA;
2837 if (FORM_PERCENTA == percent) {
2838 escaped_char[0] = c;
2839 percent = FORM_PERCENTB;
2842 if (FORM_PERCENTB == percent) {
2843 escaped_char[1] = c;
2844 c = x2c(escaped_char);
2845 percent = FORM_NORMAL;
2850 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2851 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2852 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2860 if (offset < HUGE_STRING_LEN) {
2862 pair = (ap_form_pair_t *) apr_array_push(pairs);
2863 pair->name = apr_pstrmemdup(r->pool, buffer, offset);
2864 pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2869 buffer[offset++] = c;
2878 if (offset >= HUGE_STRING_LEN) {
2879 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2880 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2881 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2884 buffer[offset++] = c;
2894 apr_brigade_cleanup(bb);
2895 } while (!seen_eos);
2897 if (FORM_ABORT == state || size < 0 || num == 0) {
2898 return HTTP_REQUEST_ENTITY_TOO_LARGE;
2900 else if (FORM_VALUE == state && pair && offset > 0) {
2901 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2902 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2903 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2910 #define VARBUF_SMALL_SIZE 2048
2911 #define VARBUF_MAX_SIZE (APR_SIZE_MAX - 1 - \
2912 APR_ALIGN_DEFAULT(sizeof(struct ap_varbuf_info)))
2914 struct ap_varbuf_info {
2915 struct apr_memnode_t *node;
2916 apr_allocator_t *allocator;
2919 static apr_status_t varbuf_cleanup(void *info_)
2921 struct ap_varbuf_info *info = info_;
2922 info->node->next = NULL;
2923 apr_allocator_free(info->allocator, info->node);
2927 const char nul = '\0';
2928 static char * const varbuf_empty = (char *)&nul;
2930 AP_DECLARE(void) ap_varbuf_init(apr_pool_t *p, struct ap_varbuf *vb,
2931 apr_size_t init_size)
2933 vb->buf = varbuf_empty;
2935 vb->strlen = AP_VARBUF_UNKNOWN;
2939 ap_varbuf_grow(vb, init_size);
2942 AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
2944 apr_memnode_t *new_node = NULL;
2945 apr_allocator_t *allocator;
2946 struct ap_varbuf_info *new_info;
2949 AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN || vb->avail >= vb->strlen);
2951 if (new_len <= vb->avail)
2954 if (new_len < 2 * vb->avail && vb->avail < VARBUF_MAX_SIZE/2) {
2955 /* at least double the size, to avoid repeated reallocations */
2956 new_len = 2 * vb->avail;
2958 else if (new_len > VARBUF_MAX_SIZE) {
2959 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2960 ap_assert(abort_fn != NULL);
2961 abort_fn(APR_ENOMEM);
2965 new_len++; /* add space for trailing \0 */
2966 if (new_len <= VARBUF_SMALL_SIZE) {
2967 new_len = APR_ALIGN_DEFAULT(new_len);
2968 new = apr_palloc(vb->pool, new_len);
2969 if (vb->avail && vb->strlen != 0) {
2970 AP_DEBUG_ASSERT(vb->buf != NULL);
2971 AP_DEBUG_ASSERT(vb->buf != varbuf_empty);
2972 if (new == vb->buf + vb->avail + 1) {
2973 /* We are lucky: the new memory lies directly after our old
2974 * buffer, we can now use both.
2976 vb->avail += new_len;
2980 /* copy up to vb->strlen + 1 bytes */
2981 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2982 vb->avail + 1 : vb->strlen + 1);
2988 vb->avail = new_len - 1;
2993 /* The required block is rather larger. Use allocator directly so that
2994 * the memory can be freed independently from the pool. */
2995 allocator = apr_pool_allocator_get(vb->pool);
2996 if (new_len <= VARBUF_MAX_SIZE)
2997 new_node = apr_allocator_alloc(allocator,
2998 new_len + APR_ALIGN_DEFAULT(sizeof(*new_info)));
3000 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
3001 ap_assert(abort_fn != NULL);
3002 abort_fn(APR_ENOMEM);
3005 new_info = (struct ap_varbuf_info *)new_node->first_avail;
3006 new_node->first_avail += APR_ALIGN_DEFAULT(sizeof(*new_info));
3007 new_info->node = new_node;
3008 new_info->allocator = allocator;
3009 new = new_node->first_avail;
3010 AP_DEBUG_ASSERT(new_node->endp - new_node->first_avail >= new_len);
3011 new_len = new_node->endp - new_node->first_avail;
3013 if (vb->avail && vb->strlen != 0)
3014 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
3015 vb->avail + 1 : vb->strlen + 1);
3019 apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
3020 apr_pool_cleanup_register(vb->pool, new_info, varbuf_cleanup,
3021 apr_pool_cleanup_null);
3022 vb->info = new_info;
3024 vb->avail = new_len - 1;
3027 AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
3033 ap_varbuf_grow(vb, len);
3034 memcpy(vb->buf, str, len);
3035 vb->buf[len] = '\0';
3039 if (vb->strlen == AP_VARBUF_UNKNOWN)
3040 vb->strlen = strlen(vb->buf);
3041 ap_varbuf_grow(vb, vb->strlen + len);
3042 memcpy(vb->buf + vb->strlen, str, len);
3044 vb->buf[vb->strlen] = '\0';
3047 AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb)
3050 apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
3056 AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *buf,
3057 const char *prepend, apr_size_t prepend_len,
3058 const char *append, apr_size_t append_len,
3059 apr_size_t *new_len)
3062 struct iovec vec[3];
3065 vec[i].iov_base = (void *)prepend;
3066 vec[i].iov_len = prepend_len;
3069 if (buf->avail && buf->strlen) {
3070 if (buf->strlen == AP_VARBUF_UNKNOWN)
3071 buf->strlen = strlen(buf->buf);
3072 vec[i].iov_base = (void *)buf->buf;
3073 vec[i].iov_len = buf->strlen;
3077 vec[i].iov_base = (void *)append;
3078 vec[i].iov_len = append_len;
3082 return apr_pstrcatv(p, vec, i, new_len);
3089 AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb,
3093 ap_regmatch_t pmatch[],
3096 return regsub_core(NULL, NULL, vb, input, source, nmatch, pmatch, maxlen);
3099 static const char * const oom_message = "[crit] Memory allocation failed, "
3100 "aborting process." APR_EOL_STR;
3102 AP_DECLARE(void) ap_abort_on_oom()
3104 int written, count = strlen(oom_message);
3105 const char *buf = oom_message;
3107 written = write(STDERR_FILENO, buf, count);
3108 if (written == count)
3114 } while (written >= 0 || errno == EINTR);
3118 AP_DECLARE(void *) ap_malloc(size_t size)
3120 void *p = malloc(size);
3121 if (p == NULL && size != 0)
3126 AP_DECLARE(void *) ap_calloc(size_t nelem, size_t size)
3128 void *p = calloc(nelem, size);
3129 if (p == NULL && nelem != 0 && size != 0)
3134 AP_DECLARE(void *) ap_realloc(void *ptr, size_t size)
3136 void *p = realloc(ptr, size);
3137 if (p == NULL && size != 0)
3142 AP_DECLARE(void) ap_get_sload(ap_sload_t *ld)
3144 int i, j, server_limit, thread_limit;
3148 ap_generation_t mpm_generation;
3150 /* preload errored fields, we overwrite */
3153 ld->bytes_served = 0;
3154 ld->access_count = 0;
3156 ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
3157 ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
3158 ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
3160 for (i = 0; i < server_limit; i++) {
3162 ps = ap_get_scoreboard_process(i);
3164 for (j = 0; j < thread_limit; j++) {
3166 worker_score *ws = NULL;
3167 ws = &ap_scoreboard_image->servers[i][j];
3170 if (!ps->quiescing && ps->pid) {
3171 if (res == SERVER_READY && ps->generation == mpm_generation) {
3174 else if (res != SERVER_DEAD &&
3175 res != SERVER_STARTING && res != SERVER_IDLE_KILL &&
3176 ps->generation == mpm_generation) {
3181 if (ap_extended_status && !ps->quiescing && ps->pid) {
3182 if (ws->access_count != 0
3183 || (res != SERVER_READY && res != SERVER_DEAD)) {
3184 ld->access_count += ws->access_count;
3185 ld->bytes_served += ws->bytes_served;
3190 total = busy + ready;
3192 ld->idle = ready * 100 / total;
3193 ld->busy = busy * 100 / total;
3197 AP_DECLARE(void) ap_get_loadavg(ap_loadavg_t *ld)
3199 /* preload errored fields, we overwrite */
3201 ld->loadavg5 = -1.0;
3202 ld->loadavg15 = -1.0;
3209 num = getloadavg(la, 3);
3211 ld->loadavg = (float)la[0];
3214 ld->loadavg5 = (float)la[1];
3217 ld->loadavg15 = (float)la[2];
3223 static const char * const pw_cache_note_name = "conn_cache_note";
3225 /* varbuf contains concatenated password and hash */
3226 struct ap_varbuf vb;
3228 apr_status_t result;
3231 AP_DECLARE(apr_status_t) ap_password_validate(request_rec *r,
3232 const char *username,
3236 struct pw_cache *cache;
3239 cache = (struct pw_cache *)apr_table_get(r->connection->notes, pw_cache_note_name);
3240 if (cache != NULL) {
3241 if (strncmp(passwd, cache->vb.buf, cache->pwlen) == 0
3242 && strcmp(hash, cache->vb.buf + cache->pwlen) == 0) {
3243 return cache->result;
3245 /* make ap_varbuf_grow below not copy the old data */
3246 cache->vb.strlen = 0;
3249 cache = apr_palloc(r->connection->pool, sizeof(struct pw_cache));
3250 ap_varbuf_init(r->connection->pool, &cache->vb, 0);
3251 apr_table_setn(r->connection->notes, pw_cache_note_name, (void *)cache);
3253 cache->pwlen = strlen(passwd);
3254 hashlen = strlen(hash);
3255 ap_varbuf_grow(&cache->vb, cache->pwlen + hashlen + 1);
3256 memcpy(cache->vb.buf, passwd, cache->pwlen);
3257 memcpy(cache->vb.buf + cache->pwlen, hash, hashlen + 1);
3258 cache->result = apr_password_validate(passwd, hash);
3259 return cache->result;
3262 AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p,
3264 const char * const * argv)
3266 char buf[MAX_STRING_LEN];
3267 apr_procattr_t *procattr;
3270 apr_size_t nbytes = 1;
3274 if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
3276 if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
3277 APR_FULL_BLOCK) != APR_SUCCESS)
3279 if (apr_procattr_dir_set(procattr,
3280 ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
3282 if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
3284 proc = apr_pcalloc(p, sizeof(apr_proc_t));
3285 if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
3291 /* XXX: we are reading 1 byte at a time here */
3292 for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
3293 && nbytes == 1 && (k < MAX_STRING_LEN-1) ; ) {
3294 if (c == '\n' || c == '\r')
3301 return apr_pstrndup(p, buf, k);
3304 AP_DECLARE(int) ap_array_str_index(const apr_array_header_t *array,
3311 for (i = start; i < array->nelts; i++) {
3312 const char *p = APR_ARRAY_IDX(array, i, const char *);
3313 if (!strcmp(p, s)) {
3322 AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array,
3325 return (ap_array_str_index(array, s, 0) >= 0);
3328 #if !APR_CHARSET_EBCDIC
3330 * Our own known-fast translation table for casecmp by character.
3331 * Only ASCII alpha characters 41-5A are folded to 61-7A, other
3332 * octets (such as extended latin alphabetics) are never case-folded.
3333 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3335 static const short ucharmap[] = {
3336 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
3337 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
3338 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3339 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3340 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3341 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3342 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3343 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3344 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3345 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3346 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3347 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3348 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3349 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3350 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3351 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3352 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3353 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3354 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3355 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3356 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3357 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3358 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3359 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3360 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3361 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3362 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3363 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3364 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3365 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3366 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3367 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3369 #else /* APR_CHARSET_EBCDIC */
3371 * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison,
3372 * provides unique identity of every char value (strict ISO-646
3373 * conformance, arbitrary election of an ISO-8859-1 ordering, and
3374 * very arbitrary control code assignments into C1 to achieve
3375 * identity and a reversible mapping of code points),
3376 * then folding the equivalences of ASCII 41-5A into 61-7A,
3377 * presenting comparison results in a somewhat ISO/IEC 10646
3378 * (ASCII-like) order, depending on the EBCDIC code page in use.
3380 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3382 static const short ucharmap[] = {
3383 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
3384 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
3385 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
3386 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
3387 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
3388 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
3389 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
3390 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
3391 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,
3392 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
3393 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,
3394 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
3395 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,
3396 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
3397 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,
3398 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
3399 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3400 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,
3401 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3402 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,
3403 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3404 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE,
3405 0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,
3406 0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7,
3407 0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3408 0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,
3409 0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3410 0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,
3411 0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3412 0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,
3413 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3414 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F
3418 AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2)
3420 const unsigned char *str1 = (const unsigned char *)s1;
3421 const unsigned char *str2 = (const unsigned char *)s2;
3424 const int c1 = (int)(*str1);
3425 const int c2 = (int)(*str2);
3426 const int cmp = ucharmap[c1] - ucharmap[c2];
3427 /* Not necessary to test for !c2, this is caught by cmp */
3435 AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
3437 const unsigned char *str1 = (const unsigned char *)s1;
3438 const unsigned char *str2 = (const unsigned char *)s2;
3441 const int c1 = (int)(*str1);
3442 const int c2 = (int)(*str2);
3443 const int cmp = ucharmap[c1] - ucharmap[c2];
3444 /* Not necessary to test for !c2, this is caught by cmp */
3457 static int fname_alphasort(const void *fn1, const void *fn2)
3459 const fnames *f1 = fn1;
3460 const fnames *f2 = fn2;
3462 return strcmp(f1->fname,f2->fname);
3465 AP_DECLARE(ap_dir_match_t *)ap_dir_cfgmatch(cmd_parms *cmd, int flags,
3466 const char *(*cb)(ap_dir_match_t *w, const char *fname), void *ctx)
3468 ap_dir_match_t *w = apr_palloc(cmd->temp_pool, sizeof(cmd_parms));
3470 w->prefix = apr_pstrcat(cmd->pool, cmd->cmd->name, ": ", NULL);
3472 w->ptemp = cmd->temp_pool;
3481 AP_DECLARE(const char *)ap_dir_nofnmatch(ap_dir_match_t *w, const char *fname)
3486 if ((w->flags & AP_DIR_FLAG_RECURSIVE) && ap_is_directory(w->ptemp, fname)) {
3490 apr_array_header_t *candidates = NULL;
3492 char *path = apr_pstrdup(w->ptemp, fname);
3494 if (++w->depth > AP_MAX_FNMATCH_DIR_DEPTH) {
3495 return apr_psprintf(w->p, "%sDirectory '%s' exceeds the maximum include "
3496 "directory nesting level of %u. You have "
3497 "probably a recursion somewhere.", w->prefix ? w->prefix : "", path,
3498 AP_MAX_FNMATCH_DIR_DEPTH);
3502 * first course of business is to grok all the directory
3503 * entries here and store 'em away. Recall we need full pathnames
3506 rv = apr_dir_open(&dirp, path, w->ptemp);
3507 if (rv != APR_SUCCESS) {
3508 return apr_psprintf(w->p, "%sCould not open directory %s: %pm",
3509 w->prefix ? w->prefix : "", path, &rv);
3512 candidates = apr_array_make(w->ptemp, 1, sizeof(fnames));
3513 while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) {
3514 /* strip out '.' and '..' */
3515 if (strcmp(dirent.name, ".")
3516 && strcmp(dirent.name, "..")) {
3517 fnew = (fnames *) apr_array_push(candidates);
3518 fnew->fname = ap_make_full_path(w->ptemp, path, dirent.name);
3522 apr_dir_close(dirp);
3523 if (candidates->nelts != 0) {
3524 qsort((void *) candidates->elts, candidates->nelts,
3525 sizeof(fnames), fname_alphasort);
3528 * Now recurse these... we handle errors and subdirectories
3529 * via the recursion, which is nice
3531 for (current = 0; current < candidates->nelts; ++current) {
3532 fnew = &((fnames *) candidates->elts)[current];
3533 error = ap_dir_nofnmatch(w, fnew->fname);
3544 else if (w->flags & AP_DIR_FLAG_OPTIONAL) {
3545 /* If the optional flag is set (like for IncludeOptional) we can
3546 * tolerate that no file or directory is present and bail out.
3549 if (apr_stat(&finfo, fname, APR_FINFO_TYPE, w->ptemp) != APR_SUCCESS
3550 || finfo.filetype == APR_NOFILE)
3554 return w->cb(w, fname);
3557 AP_DECLARE(const char *)ap_dir_fnmatch(ap_dir_match_t *w, const char *path,
3564 apr_array_header_t *candidates = NULL;
3568 /* find the first part of the filename */
3569 rest = ap_strchr_c(fname, '/');
3571 fname = apr_pstrmemdup(w->ptemp, fname, rest - fname);
3575 /* optimisation - if the filename isn't a wildcard, process it directly */
3576 if (!apr_fnmatch_test(fname)) {
3577 path = path ? ap_make_full_path(w->ptemp, path, fname) : fname;
3579 return ap_dir_nofnmatch(w, path);
3582 return ap_dir_fnmatch(w, path, rest);
3587 * first course of business is to grok all the directory
3588 * entries here and store 'em away. Recall we need full pathnames
3591 rv = apr_dir_open(&dirp, path, w->ptemp);
3592 if (rv != APR_SUCCESS) {
3593 /* If the directory doesn't exist and the optional flag is set
3594 * there is no need to return an error.
3596 if (rv == APR_ENOENT && (w->flags & AP_DIR_FLAG_OPTIONAL)) {
3599 return apr_psprintf(w->p, "%sCould not open directory %s: %pm",
3600 w->prefix ? w->prefix : "", path, &rv);
3603 candidates = apr_array_make(w->ptemp, 1, sizeof(fnames));
3604 while (apr_dir_read(&dirent, APR_FINFO_DIRENT | APR_FINFO_TYPE, dirp) == APR_SUCCESS) {
3605 /* strip out '.' and '..' */
3606 if (strcmp(dirent.name, ".")
3607 && strcmp(dirent.name, "..")
3608 && (apr_fnmatch(fname, dirent.name,
3609 APR_FNM_PERIOD) == APR_SUCCESS)) {
3610 const char *full_path = ap_make_full_path(w->ptemp, path, dirent.name);
3611 /* If matching internal to path, and we happen to match something
3612 * other than a directory, skip it
3614 if (rest && (dirent.filetype != APR_DIR)) {
3617 fnew = (fnames *) apr_array_push(candidates);
3618 fnew->fname = full_path;
3622 apr_dir_close(dirp);
3623 if (candidates->nelts != 0) {
3626 qsort((void *) candidates->elts, candidates->nelts,
3627 sizeof(fnames), fname_alphasort);
3630 * Now recurse these... we handle errors and subdirectories
3631 * via the recursion, which is nice
3633 for (current = 0; current < candidates->nelts; ++current) {
3634 fnew = &((fnames *) candidates->elts)[current];
3636 error = ap_dir_nofnmatch(w, fnew->fname);
3639 error = ap_dir_fnmatch(w, fnew->fname, rest);
3648 if (!(w->flags & AP_DIR_FLAG_OPTIONAL)) {
3649 return apr_psprintf(w->p, "%sNo matches for the wildcard '%s' in '%s', failing",
3650 w->prefix ? w->prefix : "", fname, path);