1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * util.c: string utility things
21 * 1995-96 Many changes by the Apache Software Foundation
26 * #define DEBUG to trace all cfg_open*()/cfg_closefile() calls
27 * #define DEBUG_CFG_LINES to trace every line read from the config files
31 #include "apr_strings.h"
33 #include "apr_md5.h" /* for apr_password_validate */
35 #define APR_WANT_STDIO
36 #define APR_WANT_STRFUNC
42 #if APR_HAVE_PROCESS_H
43 #include <process.h> /* for getpid() on Win32 */
46 #include <netdb.h> /* for gethostbyname() */
49 #include "ap_config.h"
50 #include "apr_base64.h"
52 #include "http_main.h"
54 #include "http_protocol.h"
55 #include "http_config.h"
56 #include "http_core.h"
57 #include "util_ebcdic.h"
58 #include "util_varbuf.h"
66 #ifdef HAVE_SYS_LOADAVG_H
67 #include <sys/loadavg.h>
72 /* A bunch of functions in util.c scan strings looking for certain characters.
73 * To make that more efficient we encode a lookup table. The test_char_table
74 * is generated automatically by gen_test_char.c.
76 #include "test_char.h"
78 /* we assume the folks using this ensure 0 <= c < 256... which means
79 * you need a cast to (unsigned char) first, you can't just plug a
80 * char in here and get it to work, because if char is signed then it
81 * will first be sign extended.
83 #define TEST_CHAR(c, f) (test_char_table[(unsigned char)(c)] & (f))
85 /* Win32/NetWare/OS2 need to check for both forward and back slashes
86 * in ap_getparents() and ap_escape_url.
88 #ifdef CASE_BLIND_FILESYSTEM
89 #define IS_SLASH(s) ((s == '/') || (s == '\\'))
92 #define IS_SLASH(s) (s == '/')
96 /* we know core's module_index is 0 */
97 #undef APLOG_MODULE_INDEX
98 #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
101 * Examine a field value (such as a media-/content-type) string and return
102 * it sans any parameters; e.g., strip off any ';charset=foo' and the like.
104 AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype)
108 if (intype == NULL) return NULL;
110 semi = ap_strchr_c(intype, ';');
112 return apr_pstrdup(p, intype);
115 while ((semi > intype) && apr_isspace(semi[-1])) {
118 return apr_pstrmemdup(p, intype, semi - intype);
122 AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt,
126 char ts[MAX_STRING_LEN];
127 char tf[MAX_STRING_LEN];
134 apr_time_exp_gmt(&xt, t);
135 /* Convert %Z to "GMT" and %z to "+0000";
136 * on hosts that do not have a time zone string in struct tm,
137 * strftime must assume its argument is local time.
139 for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f)
141 if (*f != '%') continue;
152 case 'z': /* common extension */
166 apr_time_exp_lt(&xt, t);
169 /* check return code? */
170 apr_strftime(ts, &retcode, MAX_STRING_LEN, fmt, &xt);
171 ts[MAX_STRING_LEN - 1] = '\0';
172 return apr_pstrdup(p, ts);
175 /* Roy owes Rob beer. */
176 /* Rob owes Roy dinner. */
178 /* These legacy comments would make a lot more sense if Roy hadn't
179 * replaced the old later_than() routine with util_date.c.
181 * Well, okay, they still wouldn't make any sense.
184 /* Match = 0, NoMatch = 1, Abort = -1
185 * Based loosely on sections of wildmat.c by Rich Salz
186 * Hmmm... shouldn't this really go component by component?
188 AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected)
192 for (x = 0, y = 0; expected[y]; ++y, ++x) {
193 if (expected[y] == '*') {
194 while (expected[++y] == '*');
199 if ((ret = ap_strcmp_match(&str[x++], &expected[y])) != 1)
206 else if ((expected[y] != '?') && (str[x] != expected[y]))
209 return (str[x] != '\0');
212 AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
216 for (x = 0, y = 0; expected[y]; ++y, ++x) {
217 if (!str[x] && expected[y] != '*')
219 if (expected[y] == '*') {
220 while (expected[++y] == '*');
225 if ((ret = ap_strcasecmp_match(&str[x++], &expected[y])) != 1)
230 else if (expected[y] != '?'
231 && apr_tolower(str[x]) != apr_tolower(expected[y]))
234 return (str[x] != '\0');
237 /* We actually compare the canonical root to this root, (but we don't
238 * waste time checking the case), since every use of this function in
239 * httpd-2.1 tests if the path is 'proper', meaning we've already passed
240 * it through apr_filepath_merge, or we haven't.
242 AP_DECLARE(int) ap_os_is_path_absolute(apr_pool_t *p, const char *dir)
245 const char *ourdir = dir;
246 if (apr_filepath_root(&newpath, &dir, 0, p) != APR_SUCCESS
247 || strncmp(newpath, ourdir, strlen(newpath)) != 0) {
253 AP_DECLARE(int) ap_is_matchexp(const char *str)
257 for (x = 0; str[x]; x++)
258 if ((str[x] == '*') || (str[x] == '?'))
264 * Here's a pool-based interface to the POSIX-esque ap_regcomp().
265 * Note that we return ap_regex_t instead of being passed one.
266 * The reason is that if you use an already-used ap_regex_t structure,
267 * the memory that you've already allocated gets forgotten, and
268 * regfree() doesn't clear it. So we don't allow it.
271 static apr_status_t regex_cleanup(void *preg)
273 ap_regfree((ap_regex_t *) preg);
277 AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
280 ap_regex_t *preg = apr_palloc(p, sizeof *preg);
281 int err = ap_regcomp(preg, pattern, cflags);
283 if (err == AP_REG_ESPACE)
288 apr_pool_cleanup_register(p, (void *) preg, regex_cleanup,
289 apr_pool_cleanup_null);
294 AP_DECLARE(void) ap_pregfree(apr_pool_t *p, ap_regex_t *reg)
297 apr_pool_cleanup_kill(p, (void *) reg, regex_cleanup);
301 * Similar to standard strstr() but we ignore case in this version.
302 * Based on the strstr() implementation further below.
304 AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2)
312 for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
316 /* found first character of s2, see if the rest matches */
319 for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) {
321 /* both strings ended together */
326 /* second string ended, a match */
329 /* didn't find a match here, try starting at next character in s1 */
336 * Returns an offsetted pointer in bigstring immediately after
337 * prefix. Returns bigstring if bigstring doesn't start with
338 * prefix or if prefix is longer than bigstring while still matching.
339 * NOTE: pointer returned is relative to bigstring, so we
340 * can use standard pointer comparisons in the calling function
341 * (eg: test if ap_stripprefix(a,b) == a)
343 AP_DECLARE(const char *) ap_stripprefix(const char *bigstring,
352 while (*p1 && *prefix) {
353 if (*p1++ != *prefix++)
359 /* hit the end of bigstring! */
363 /* This function substitutes for $0-$9, filling in regular expression
364 * submatches. Pass it the same nmatch and pmatch arguments that you
365 * passed ap_regexec(). pmatch should not be greater than the maximum number
366 * of subexpressions - i.e. one more than the re_nsub member of ap_regex_t.
368 * nmatch must be <=AP_MAX_REG_MATCH (10).
370 * input should be the string with the $-expressions, source should be the
371 * string that was matched against.
373 * It returns the substituted string, or NULL if a vbuf is used.
374 * On errors, returns the orig string.
376 * Parts of this code are based on Henry Spencer's regsub(), from his
377 * AT&T V8 regexp package.
380 static apr_status_t regsub_core(apr_pool_t *p, char **result,
381 struct ap_varbuf *vb, const char *input,
382 const char *source, apr_size_t nmatch,
383 ap_regmatch_t pmatch[], apr_size_t maxlen)
385 const char *src = input;
391 AP_DEBUG_ASSERT((result && p && !vb) || (vb && !p && !result));
392 if (!source || nmatch>AP_MAX_REG_MATCH)
396 if (maxlen > 0 && len >= maxlen)
399 *result = apr_pstrmemdup(p, src, len);
403 ap_varbuf_strmemcat(vb, src, len);
408 /* First pass, find the size */
409 while ((c = *src++) != '\0') {
410 if (c == '$' && apr_isdigit(*src))
413 no = AP_MAX_REG_MATCH;
415 if (no >= AP_MAX_REG_MATCH) { /* Ordinary character. */
416 if (c == '\\' && *src)
420 else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
421 if (APR_SIZE_MAX - len <= pmatch[no].rm_eo - pmatch[no].rm_so)
423 len += pmatch[no].rm_eo - pmatch[no].rm_so;
428 if (len >= maxlen && maxlen > 0)
432 *result = dst = apr_palloc(p, len + 1);
435 if (vb->strlen == AP_VARBUF_UNKNOWN)
436 vb->strlen = strlen(vb->buf);
437 ap_varbuf_grow(vb, vb->strlen + len);
438 dst = vb->buf + vb->strlen;
442 /* Now actually fill in the string */
446 while ((c = *src++) != '\0') {
447 if (c == '$' && apr_isdigit(*src))
450 no = AP_MAX_REG_MATCH;
452 if (no >= AP_MAX_REG_MATCH) { /* Ordinary character. */
453 if (c == '\\' && *src)
457 else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
458 len = pmatch[no].rm_eo - pmatch[no].rm_so;
459 memcpy(dst, source + pmatch[no].rm_so, len);
469 #ifndef AP_PREGSUB_MAXLEN
470 #define AP_PREGSUB_MAXLEN (HUGE_STRING_LEN * 8)
472 AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
473 const char *source, apr_size_t nmatch,
474 ap_regmatch_t pmatch[])
477 apr_status_t rc = regsub_core(p, &result, NULL, input, source, nmatch,
478 pmatch, AP_PREGSUB_MAXLEN);
479 if (rc != APR_SUCCESS)
484 AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result,
485 const char *input, const char *source,
486 apr_size_t nmatch, ap_regmatch_t pmatch[],
489 apr_status_t rc = regsub_core(p, result, NULL, input, source, nmatch,
491 if (rc != APR_SUCCESS)
497 * Parse .. so we don't compromise security
499 AP_DECLARE(void) ap_getparents(char *name)
504 /* Four paseses, as per RFC 1808 */
505 /* a) remove ./ path segments */
506 for (next = name; *next && (*next != '.'); next++) {
509 l = w = first_dot = next - name;
510 while (name[l] != '\0') {
511 if (name[l] == '.' && IS_SLASH(name[l + 1])
512 && (l == 0 || IS_SLASH(name[l - 1])))
515 name[w++] = name[l++];
518 /* b) remove trailing . path, segment */
519 if (w == 1 && name[0] == '.')
521 else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2]))
525 /* c) remove all xx/../ segments. (including leading ../ and /../) */
528 while (name[l] != '\0') {
529 if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2])
530 && (l == 0 || IS_SLASH(name[l - 1]))) {
535 while (l >= 0 && !IS_SLASH(name[l]))
542 while ((name[n] = name[m]))
549 /* d) remove trailing xx/.. segment. */
550 if (l == 2 && name[0] == '.' && name[1] == '.')
552 else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
553 && IS_SLASH(name[l - 3])) {
556 while (l >= 0 && !IS_SLASH(name[l]))
566 AP_DECLARE(void) ap_no2slash(char *name)
572 #ifdef HAVE_UNC_PATHS
573 /* Check for UNC names. Leave leading two slashes. */
574 if (s[0] == '/' && s[1] == '/')
579 if ((*d++ = *s) == '/') {
593 * copy at most n leading directories of s into d
594 * d should be at least as large as s plus 1 extra byte
596 * the return value is the ever useful pointer to the trailing \0 of d
598 * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments,
599 * so that if n == 0, "/" is returned in d with n == 1
600 * and s == "e:/test.html", "e:/" is returned in d
601 * *** See also directory_walk in modules/http/http_request.c
604 * /a/b, 0 ==> / (true for all platforms)
613 * c:/a/b 3 ==> c:/a/b
614 * c:/a/b 4 ==> c:/a/b
616 AP_DECLARE(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
625 if (*s == '\0' || (*s == '/' && (--n) == 0)) {
637 * return the parent directory name including trailing / of the file s
639 AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s)
641 const char *last_slash = ap_strrchr_c(s, '/');
645 if (last_slash == NULL) {
646 return apr_pstrdup(p, "");
648 l = (last_slash - s) + 1;
649 d = apr_pstrmemdup(p, s, l);
655 AP_DECLARE(int) ap_count_dirs(const char *path)
659 for (x = 0, n = 0; path[x]; x++)
665 AP_DECLARE(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop)
667 return ap_getword(atrans, (const char **) line, stop);
670 AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop)
672 const char *pos = *line;
676 while ((*pos != stop) && *pos) {
681 res = apr_pstrmemdup(atrans, *line, len);
684 while (*pos == stop) {
693 AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
695 return ap_getword_white(atrans, (const char **) line);
698 AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
700 const char *pos = *line;
704 while (!apr_isspace(*pos) && *pos) {
709 res = apr_pstrmemdup(atrans, *line, len);
711 while (apr_isspace(*pos)) {
720 AP_DECLARE(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line,
723 return ap_getword_nulls(atrans, (const char **) line, stop);
726 AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line,
729 const char *pos = ap_strchr_c(*line, stop);
733 apr_size_t len = strlen(*line);
734 res = apr_pstrmemdup(atrans, *line, len);
739 res = apr_pstrmemdup(atrans, *line, pos - *line);
748 /* Get a word, (new) config-file style --- quoted strings and backslashes
752 static char *substring_conf(apr_pool_t *p, const char *start, int len,
755 char *result = apr_palloc(p, len + 1);
759 for (i = 0; i < len; ++i) {
760 if (start[i] == '\\' && (start[i + 1] == '\\'
761 || (quote && start[i + 1] == quote)))
762 *resp++ = start[++i];
768 #if RESOLVE_ENV_PER_TOKEN
769 return (char *)ap_resolve_env(p,result);
775 AP_DECLARE(char *) ap_getword_conf_nc(apr_pool_t *p, char **line)
777 return ap_getword_conf(p, (const char **) line);
780 AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line)
782 const char *str = *line, *strend;
786 while (apr_isspace(*str))
794 if ((quote = *str) == '"' || quote == '\'') {
796 while (*strend && *strend != quote) {
797 if (*strend == '\\' && strend[1] &&
798 (strend[1] == quote || strend[1] == '\\')) {
805 res = substring_conf(p, str + 1, strend - str - 1, quote);
807 if (*strend == quote)
812 while (*strend && !apr_isspace(*strend))
815 res = substring_conf(p, str, strend - str, 0);
818 while (apr_isspace(*strend))
824 AP_DECLARE(char *) ap_getword_conf2_nc(apr_pool_t *p, char **line)
826 return ap_getword_conf2(p, (const char **) line);
829 AP_DECLARE(char *) ap_getword_conf2(apr_pool_t *p, const char **line)
831 const char *str = *line, *strend;
836 while (apr_isspace(*str))
844 if ((quote = *str) == '"' || quote == '\'')
845 return ap_getword_conf(p, line);
850 if (*strend == '}' && !--count)
854 if (*strend == '\\' && strend[1] && strend[1] == '\\') {
859 res = substring_conf(p, str + 1, strend - str - 1, 0);
866 while (*strend && !apr_isspace(*strend))
869 res = substring_conf(p, str, strend - str, 0);
872 while (apr_isspace(*strend))
878 AP_DECLARE(int) ap_cfg_closefile(ap_configfile_t *cfp)
881 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00551)
882 "Done with config file %s", cfp->name);
884 return (cfp->close == NULL) ? 0 : cfp->close(cfp->param);
887 /* we can't use apr_file_* directly because of linking issues on Windows */
888 static apr_status_t cfg_close(void *param)
890 return apr_file_close(param);
893 static apr_status_t cfg_getch(char *ch, void *param)
895 return apr_file_getc(ch, param);
898 static apr_status_t cfg_getstr(void *buf, apr_size_t bufsiz, void *param)
900 return apr_file_gets(buf, bufsiz, param);
903 /* Open a ap_configfile_t as FILE, return open ap_configfile_t struct pointer */
904 AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg,
905 apr_pool_t *p, const char *name)
907 ap_configfile_t *new_cfg;
908 apr_file_t *file = NULL;
916 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00552)
917 "Internal error: pcfg_openfile() called with NULL filename");
921 status = apr_file_open(&file, name, APR_READ | APR_BUFFERED,
924 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00553)
925 "Opening config file %s (%s)",
926 name, (status != APR_SUCCESS) ?
927 apr_strerror(status, buf, sizeof(buf)) : "successful");
929 if (status != APR_SUCCESS)
932 status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file);
933 if (status != APR_SUCCESS)
936 if (finfo.filetype != APR_REG &&
937 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
938 ap_cstr_casecmp(apr_filepath_name_get(name), "nul") != 0) {
940 strcmp(name, "/dev/null") != 0) {
941 #endif /* WIN32 || OS2 */
942 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00554)
943 "Access to file %s denied by server: not a regular file",
945 apr_file_close(file);
950 /* Some twisted character [no pun intended] at MS decided that a
951 * zero width joiner as the lead wide character would be ideal for
952 * describing Unicode text files. This was further convoluted to
953 * another MSism that the same character mapped into utf-8, EF BB BF
954 * would signify utf-8 text files.
956 * Since MS configuration files are all protecting utf-8 encoded
957 * Unicode path, file and resource names, we already have the correct
958 * WinNT encoding. But at least eat the stupid three bytes up front.
961 unsigned char buf[4];
963 status = apr_file_read(file, buf, &len);
964 if ((status != APR_SUCCESS) || (len < 3)
965 || memcmp(buf, "\xEF\xBB\xBF", 3) != 0) {
967 apr_file_seek(file, APR_SET, &zero);
972 new_cfg = apr_palloc(p, sizeof(*new_cfg));
973 new_cfg->param = file;
974 new_cfg->name = apr_pstrdup(p, name);
975 new_cfg->getch = cfg_getch;
976 new_cfg->getstr = cfg_getstr;
977 new_cfg->close = cfg_close;
978 new_cfg->line_number = 0;
984 /* Allocate a ap_configfile_t handle with user defined functions and params */
985 AP_DECLARE(ap_configfile_t *) ap_pcfg_open_custom(
986 apr_pool_t *p, const char *descr, void *param,
987 apr_status_t (*getc_func) (char *ch, void *param),
988 apr_status_t (*gets_func) (void *buf, apr_size_t bufsize, void *param),
989 apr_status_t (*close_func) (void *param))
991 ap_configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg));
992 new_cfg->param = param;
993 new_cfg->name = descr;
994 new_cfg->getch = getc_func;
995 new_cfg->getstr = gets_func;
996 new_cfg->close = close_func;
997 new_cfg->line_number = 0;
1001 /* Read one character from a configfile_t */
1002 AP_DECLARE(apr_status_t) ap_cfg_getc(char *ch, ap_configfile_t *cfp)
1004 apr_status_t rc = cfp->getch(ch, cfp->param);
1005 if (rc == APR_SUCCESS && *ch == LF)
1010 AP_DECLARE(const char *) ap_pcfg_strerror(apr_pool_t *p, ap_configfile_t *cfp,
1013 if (rc == APR_SUCCESS)
1016 if (rc == APR_ENOSPC)
1017 return apr_psprintf(p, "Error reading %s at line %d: Line too long",
1018 cfp->name, cfp->line_number);
1020 return apr_psprintf(p, "Error reading %s at line %d: %pm",
1021 cfp->name, cfp->line_number, &rc);
1024 /* Read one line from open ap_configfile_t, strip LF, increase line number */
1025 /* If custom handler does not define a getstr() function, read char by char */
1026 static apr_status_t ap_cfg_getline_core(char *buf, apr_size_t bufsize,
1027 apr_size_t offset, ap_configfile_t *cfp)
1030 /* If a "get string" function is defined, use it */
1031 if (cfp->getstr != NULL) {
1033 char *cbuf = buf + offset;
1034 apr_size_t cbufsize = bufsize - offset;
1038 rc = cfp->getstr(cbuf, cbufsize, cfp->param);
1039 if (rc == APR_EOF) {
1040 if (cbuf != buf + offset) {
1048 if (rc != APR_SUCCESS) {
1053 * check for line continuation,
1054 * i.e. match [^\\]\\[\r]\n only
1058 if (cp > buf && cp[-1] == LF) {
1060 if (cp > buf && cp[-1] == CR)
1062 if (cp > buf && cp[-1] == '\\') {
1065 * line continuation requested -
1066 * then remove backslash and continue
1068 cbufsize -= (cp-cbuf);
1073 else if (cp - buf >= bufsize - 1) {
1079 /* No "get string" function defined; read character by character */
1080 apr_size_t i = offset;
1083 /* too small, assume caller is crazy */
1090 rc = cfp->getch(&c, cfp->param);
1091 if (rc == APR_EOF) {
1097 if (rc != APR_SUCCESS)
1101 /* check for line continuation */
1102 if (i > 0 && buf[i-1] == '\\') {
1112 if (i >= bufsize - 1) {
1121 static int cfg_trim_line(char *buf)
1125 * Leading and trailing white space is eliminated completely
1128 while (apr_isspace(*start))
1130 /* blast trailing whitespace */
1131 end = &start[strlen(start)];
1132 while (--end >= start && apr_isspace(*end))
1134 /* Zap leading whitespace by shifting */
1136 memmove(buf, start, end - start + 2);
1137 #ifdef DEBUG_CFG_LINES
1138 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, APLOGNO(00555) "Read config: '%s'", buf);
1140 return end - start + 1;
1143 /* Read one line from open ap_configfile_t, strip LF, increase line number */
1144 /* If custom handler does not define a getstr() function, read char by char */
1145 AP_DECLARE(apr_status_t) ap_cfg_getline(char *buf, apr_size_t bufsize,
1146 ap_configfile_t *cfp)
1148 apr_status_t rc = ap_cfg_getline_core(buf, bufsize, 0, cfp);
1149 if (rc == APR_SUCCESS)
1154 AP_DECLARE(apr_status_t) ap_varbuf_cfg_getline(struct ap_varbuf *vb,
1155 ap_configfile_t *cfp,
1163 if (vb->strlen == AP_VARBUF_UNKNOWN)
1164 vb->strlen = strlen(vb->buf);
1165 if (vb->avail - vb->strlen < 3) {
1166 new_len = vb->avail * 2;
1167 if (new_len > max_len)
1169 else if (new_len < 3)
1171 ap_varbuf_grow(vb, new_len);
1175 rc = ap_cfg_getline_core(vb->buf, vb->avail, vb->strlen, cfp);
1176 if (rc == APR_ENOSPC || rc == APR_SUCCESS)
1177 vb->strlen += strlen(vb->buf + vb->strlen);
1178 if (rc != APR_ENOSPC)
1180 if (vb->avail >= max_len)
1182 new_len = vb->avail * 2;
1183 if (new_len > max_len)
1185 ap_varbuf_grow(vb, new_len);
1188 if (vb->strlen > max_len)
1190 if (rc == APR_SUCCESS)
1191 vb->strlen = cfg_trim_line(vb->buf);
1195 /* Size an HTTP header field list item, as separated by a comma.
1196 * The return value is a pointer to the beginning of the non-empty list item
1197 * within the original string (or NULL if there is none) and the address
1198 * of field is shifted to the next non-comma, non-whitespace character.
1199 * len is the length of the item excluding any beginning whitespace.
1201 AP_DECLARE(const char *) ap_size_list_item(const char **field, int *len)
1203 const unsigned char *ptr = (const unsigned char *)*field;
1204 const unsigned char *token;
1205 int in_qpair, in_qstr, in_com;
1207 /* Find first non-comma, non-whitespace byte */
1209 while (*ptr == ',' || apr_isspace(*ptr))
1214 /* Find the end of this item, skipping over dead bits */
1216 for (in_qpair = in_qstr = in_com = 0;
1217 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1225 case '\\': in_qpair = 1; /* quoted-pair */
1227 case '"' : if (!in_com) /* quoted string delim */
1230 case '(' : if (!in_qstr) /* comment (may nest) */
1233 case ')' : if (in_com) /* end comment */
1241 if ((*len = (ptr - token)) == 0) {
1242 *field = (const char *)ptr;
1246 /* Advance field pointer to the next non-comma, non-white byte */
1248 while (*ptr == ',' || apr_isspace(*ptr))
1251 *field = (const char *)ptr;
1252 return (const char *)token;
1255 /* Retrieve an HTTP header field list item, as separated by a comma,
1256 * while stripping insignificant whitespace and lowercasing anything not in
1257 * a quoted string or comment. The return value is a new string containing
1258 * the converted list item (or NULL if none) and the address pointed to by
1259 * field is shifted to the next non-comma, non-whitespace.
1261 AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field)
1263 const char *tok_start;
1264 const unsigned char *ptr;
1267 int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
1269 /* Find the beginning and maximum length of the list item so that
1270 * we can allocate a buffer for the new string and reset the field.
1272 if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
1275 token = apr_palloc(p, tok_len + 1);
1277 /* Scan the token again, but this time copy only the good bytes.
1278 * We skip extra whitespace and any whitespace around a '=', '/',
1279 * or ';' and lowercase normal characters not within a comment,
1280 * quoted-string or quoted-pair.
1282 for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
1283 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1292 case '\\': in_qpair = 1;
1298 case '"' : if (!in_com)
1305 case '(' : if (!in_qstr)
1312 case ')' : if (in_com)
1318 case '\t': if (addspace)
1320 if (in_com || in_qstr)
1327 case ';' : if (!(in_com || in_qstr))
1331 default : if (addspace == 1)
1333 *pos++ = (in_com || in_qstr) ? *ptr
1334 : apr_tolower(*ptr);
1345 typedef enum ap_etag_e {
1351 /* Find an item in canonical form (lowercase, no extra spaces) within
1352 * an HTTP field value list. Returns 1 if found, 0 if not found.
1353 * This would be much more efficient if we stored header fields as
1354 * an array of list items as they are received instead of a plain string.
1356 static int find_list_item(apr_pool_t *p, const char *line,
1357 const char *tok, ap_etag_e type)
1359 const unsigned char *pos;
1360 const unsigned char *ptr = (const unsigned char *)line;
1361 int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
1363 if (!line || !tok) {
1366 if (type == AP_ETAG_STRONG && *tok != '\"') {
1369 if (type == AP_ETAG_WEAK) {
1370 if (*tok == 'W' && (*(tok+1)) == '/' && (*(tok+2)) == '\"') {
1373 else if (*tok != '\"') {
1378 do { /* loop for each item in line's list */
1380 /* Find first non-comma, non-whitespace byte */
1381 while (*ptr == ',' || apr_isspace(*ptr)) {
1385 /* Account for strong or weak Etags, depending on our search */
1386 if (type == AP_ETAG_STRONG && *ptr != '\"') {
1389 if (type == AP_ETAG_WEAK) {
1390 if (*ptr == 'W' && (*(ptr+1)) == '/' && (*(ptr+2)) == '\"') {
1393 else if (*ptr != '\"') {
1399 good = 1; /* until proven otherwise for this item */
1401 break; /* no items left and nothing good found */
1403 /* We skip extra whitespace and any whitespace around a '=', '/',
1404 * or ';' and lowercase normal characters not within a comment,
1405 * quoted-string or quoted-pair.
1407 for (pos = (const unsigned char *)tok;
1408 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1414 good = (*pos++ == *ptr);
1418 case '\\': in_qpair = 1;
1420 good = good && (*pos++ == ' ');
1421 good = good && (*pos++ == *ptr);
1424 case '"' : if (!in_com)
1427 good = good && (*pos++ == ' ');
1428 good = good && (*pos++ == *ptr);
1431 case '(' : if (!in_qstr)
1434 good = good && (*pos++ == ' ');
1435 good = good && (*pos++ == *ptr);
1438 case ')' : if (in_com)
1440 good = good && (*pos++ == *ptr);
1444 case '\t': if (addspace || !good)
1446 if (in_com || in_qstr)
1447 good = (*pos++ == *ptr);
1453 case ';' : if (!(in_com || in_qstr))
1455 good = good && (*pos++ == *ptr);
1457 default : if (!good)
1460 good = (*pos++ == ' ');
1461 if (in_com || in_qstr)
1462 good = good && (*pos++ == *ptr);
1465 && (apr_tolower(*pos++) == apr_tolower(*ptr));
1472 good = 0; /* not good if only a prefix was matched */
1474 } while (*ptr && !good);
1479 /* Find an item in canonical form (lowercase, no extra spaces) within
1480 * an HTTP field value list. Returns 1 if found, 0 if not found.
1481 * This would be much more efficient if we stored header fields as
1482 * an array of list items as they are received instead of a plain string.
1484 AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line,
1487 return find_list_item(p, line, tok, AP_ETAG_NONE);
1490 /* Find a strong Etag in canonical form (lowercase, no extra spaces) within
1491 * an HTTP field value list. Returns 1 if found, 0 if not found.
1493 AP_DECLARE(int) ap_find_etag_strong(apr_pool_t *p, const char *line,
1496 return find_list_item(p, line, tok, AP_ETAG_STRONG);
1499 /* Find a weak ETag in canonical form (lowercase, no extra spaces) within
1500 * an HTTP field value list. Returns 1 if found, 0 if not found.
1502 AP_DECLARE(int) ap_find_etag_weak(apr_pool_t *p, const char *line,
1505 return find_list_item(p, line, tok, AP_ETAG_WEAK);
1508 /* Grab a list of tokens of the format 1#token (from RFC7230) */
1509 AP_DECLARE(const char *) ap_parse_token_list_strict(apr_pool_t *p,
1511 apr_array_header_t **tokens,
1514 int in_leading_space = 1;
1515 int in_trailing_space = 0;
1517 const char *tok_begin;
1524 tok_begin = cur = str_in;
1526 while (!string_end) {
1527 const unsigned char c = (unsigned char)*cur;
1529 if (!TEST_CHAR(c, T_HTTP_TOKEN_STOP)) {
1530 /* Non-separator character; we are finished with leading
1531 * whitespace. We must never have encountered any trailing
1532 * whitespace before the delimiter (comma) */
1533 in_leading_space = 0;
1534 if (in_trailing_space) {
1535 return "Encountered illegal whitespace in token";
1538 else if (c == ' ' || c == '\t') {
1539 /* "Linear whitespace" only includes ASCII CRLF, space, and tab;
1540 * we can't get a CRLF since headers are split on them already,
1541 * so only look for a space or a tab */
1542 if (in_leading_space) {
1543 /* We're still in leading whitespace */
1547 /* We must be in trailing whitespace */
1548 ++in_trailing_space;
1551 else if (c == ',' || c == '\0') {
1552 if (!in_leading_space) {
1553 /* If we're out of the leading space, we know we've read some
1554 * characters of a token */
1555 if (*tokens == NULL) {
1556 *tokens = apr_array_make(p, 4, sizeof(char *));
1558 APR_ARRAY_PUSH(*tokens, char *) =
1559 apr_pstrmemdup((*tokens)->pool, tok_begin,
1560 (cur - tok_begin) - in_trailing_space);
1562 /* We're allowed to have null elements, just don't add them to the
1565 tok_begin = cur + 1;
1566 in_leading_space = 1;
1567 in_trailing_space = 0;
1568 string_end = (c == '\0');
1571 /* Encountered illegal separator char */
1573 /* Skip to the next separator */
1575 temp = ap_strchr_c(cur, ',');
1577 temp = ap_strchr_c(cur, '\0');
1580 /* Act like we haven't seen a token so we reset */
1582 in_leading_space = 1;
1583 in_trailing_space = 0;
1586 return apr_psprintf(p, "Encountered illegal separator "
1587 "'\\x%.2x'", (unsigned int)c);
1597 /* Scan a string for HTTP VCHAR/obs-text characters including HT and SP
1598 * (as used in header values, for example, in RFC 7230 section 3.2)
1599 * returning the pointer to the first non-HT ASCII ctrl character.
1601 AP_DECLARE(const char *) ap_scan_http_field_content(const char *ptr)
1603 for ( ; !TEST_CHAR(*ptr, T_HTTP_CTRLS); ++ptr) ;
1608 /* Scan a string for HTTP token characters, returning the pointer to
1609 * the first non-token character.
1611 AP_DECLARE(const char *) ap_scan_http_token(const char *ptr)
1613 for ( ; !TEST_CHAR(*ptr, T_HTTP_TOKEN_STOP); ++ptr) ;
1618 /* Scan a string for visible ASCII (0x21-0x7E) or obstext (0x80+)
1619 * and return a pointer to the first ctrl/space character encountered.
1621 AP_DECLARE(const char *) ap_scan_vchar_obstext(const char *ptr)
1623 for ( ; TEST_CHAR(*ptr, T_VCHAR_OBSTEXT); ++ptr) ;
1628 /* Retrieve a token, spacing over it and returning a pointer to
1629 * the first non-white byte afterwards. Note that these tokens
1630 * are delimited by semis and commas; and can also be delimited
1631 * by whitespace at the caller's option.
1634 AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line,
1637 const char *ptr = *accept_line;
1638 const char *tok_start;
1641 /* Find first non-white byte */
1643 while (apr_isspace(*ptr))
1648 /* find token end, skipping over quoted strings.
1649 * (comments are already gone).
1652 while (*ptr && (accept_white || !apr_isspace(*ptr))
1653 && *ptr != ';' && *ptr != ',') {
1660 token = apr_pstrmemdup(p, tok_start, ptr - tok_start);
1662 /* Advance accept_line pointer to the next non-white byte */
1664 while (apr_isspace(*ptr))
1672 /* find http tokens, see the definition of token from RFC2068 */
1673 AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
1675 const unsigned char *start_token;
1676 const unsigned char *s;
1681 s = (const unsigned char *)line;
1683 /* find start of token, skip all stop characters */
1684 while (*s && TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1691 /* find end of the token */
1692 while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
1695 if (!ap_cstr_casecmpn((const char *)start_token, (const char *)tok,
1706 AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line,
1709 int llen, tlen, lidx;
1714 llen = strlen(line);
1719 (lidx > 0 && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
1722 return (ap_cstr_casecmpn(&line[lidx], tok, tlen) == 0);
1725 AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
1729 const unsigned char *s;
1731 cmd = apr_palloc(p, 2 * strlen(str) + 1); /* Be safe */
1732 d = (unsigned char *)cmd;
1733 s = (const unsigned char *)str;
1736 #if defined(OS2) || defined(WIN32)
1738 * Newlines to Win32/OS2 CreateProcess() are ill advised.
1739 * Convert them to spaces since they are effectively white
1740 * space to most applications
1742 if (*s == '\r' || *s == '\n') {
1748 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
1758 static char x2c(const char *what)
1762 #if !APR_CHARSET_EBCDIC
1763 digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
1766 digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
1768 #else /*APR_CHARSET_EBCDIC*/
1775 digit = apr_xlate_conv_byte(ap_hdrs_from_ascii,
1776 0xFF & strtol(xstr, NULL, 16));
1777 #endif /*APR_CHARSET_EBCDIC*/
1782 * Unescapes a URL, leaving reserved characters intact.
1783 * Returns 0 on success, non-zero on error
1785 * bad % escape returns HTTP_BAD_REQUEST
1787 * decoding %00 or a forbidden character returns HTTP_NOT_FOUND
1790 static int unescape_url(char *url, const char *forbid, const char *reserved)
1792 int badesc, badpath;
1797 /* Initial scan for first '%'. Don't bother writing values before
1799 y = strchr(url, '%');
1803 for (x = y; *y; ++x, ++y) {
1808 if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
1814 decoded = x2c(y + 1);
1815 if ((decoded == '\0')
1816 || (forbid && ap_strchr_c(forbid, decoded))) {
1821 else if (reserved && ap_strchr_c(reserved, decoded)) {
1835 return HTTP_BAD_REQUEST;
1838 return HTTP_NOT_FOUND;
1844 AP_DECLARE(int) ap_unescape_url(char *url)
1847 return unescape_url(url, SLASHES, NULL);
1849 AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes)
1851 /* AllowEncodedSlashes (corrected) */
1852 if (decode_slashes) {
1853 /* no chars reserved */
1854 return unescape_url(url, NULL, NULL);
1856 /* reserve (do not decode) encoded slashes */
1857 return unescape_url(url, NULL, SLASHES);
1861 /* IFDEF these out until they've been thought through.
1862 * Just a germ of an API extension for now
1864 AP_DECLARE(int) ap_unescape_url_proxy(char *url)
1866 /* leave RFC1738 reserved characters intact, * so proxied URLs
1867 * don't get mangled. Where does that leave encoded '&' ?
1869 return unescape_url(url, NULL, "/;?");
1871 AP_DECLARE(int) ap_unescape_url_reserved(char *url, const char *reserved)
1873 return unescape_url(url, NULL, reserved);
1877 AP_DECLARE(int) ap_unescape_urlencoded(char *query)
1881 /* replace plus with a space */
1883 for (slider = query; *slider; slider++) {
1884 if (*slider == '+') {
1890 /* unescape everything else */
1891 return unescape_url(query, NULL, NULL);
1894 AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname,
1895 apr_port_t port, const request_rec *r)
1897 if (ap_is_default_port(port, r)) {
1898 return apr_pstrdup(p, hostname);
1901 return apr_psprintf(p, "%s:%u", hostname, port);
1905 AP_DECLARE(int) ap_unescape_all(char *url)
1907 return unescape_url(url, NULL, NULL);
1910 /* c2x takes an unsigned, and expects the caller has guaranteed that
1911 * 0 <= what < 256... which usually means that you have to cast to
1912 * unsigned char first, because (unsigned)(char)(x) first goes through
1913 * signed extension to an int before the unsigned cast.
1915 * The reason for this assumption is to assist gcc code generation --
1916 * the unsigned char -> unsigned extension is already done earlier in
1917 * both uses of this code, so there's no need to waste time doing it
1920 static const char c2x_table[] = "0123456789abcdef";
1922 static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
1923 unsigned char *where)
1925 #if APR_CHARSET_EBCDIC
1926 what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
1927 #endif /*APR_CHARSET_EBCDIC*/
1929 *where++ = c2x_table[what >> 4];
1930 *where++ = c2x_table[what & 0xf];
1935 * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
1936 * routine is (should be) OS independent.
1938 * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
1939 * cases if a ':' occurs before the first '/' in the URL, the URL should be
1940 * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
1941 * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
1942 * efficiency reasons, we don't use escape_path_segment(), which is provided for
1943 * reference. Again, RFC 1808 is where this stuff is defined.
1945 * If partial is set, os_escape_path() assumes that the path will be appended to
1946 * something with a '/' in it (and thus does not prefix "./").
1949 AP_DECLARE(char *) ap_escape_path_segment_buffer(char *copy, const char *segment)
1951 const unsigned char *s = (const unsigned char *)segment;
1952 unsigned char *d = (unsigned char *)copy;
1956 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
1968 AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
1970 return ap_escape_path_segment_buffer(apr_palloc(p, 3 * strlen(segment) + 1), segment);
1973 AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
1975 /* Allocate +3 for potential "./" and trailing NULL.
1976 * Allocate another +1 to allow the caller to add a trailing '/' (see
1977 * comment in 'ap_sub_req_lookup_dirent')
1979 char *copy = apr_palloc(p, 3 * strlen(path) + 3 + 1);
1980 const unsigned char *s = (const unsigned char *)path;
1981 unsigned char *d = (unsigned char *)copy;
1985 const char *colon = ap_strchr_c(path, ':');
1986 const char *slash = ap_strchr_c(path, '/');
1988 if (colon && (!slash || colon < slash)) {
1994 if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
2006 AP_DECLARE(char *) ap_escape_urlencoded_buffer(char *copy, const char *buffer)
2008 const unsigned char *s = (const unsigned char *)buffer;
2009 unsigned char *d = (unsigned char *)copy;
2013 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
2016 else if (c == ' ') {
2028 AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
2030 return ap_escape_urlencoded_buffer(apr_palloc(p, 3 * strlen(buffer) + 1), buffer);
2033 /* ap_escape_uri is now a macro for os_escape_path */
2035 AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
2040 /* first, count the number of extra characters */
2041 for (i = 0, j = 0; s[i] != '\0'; i++)
2042 if (s[i] == '<' || s[i] == '>')
2044 else if (s[i] == '&')
2046 else if (s[i] == '"')
2048 else if (toasc && !apr_isascii(s[i]))
2052 return apr_pstrmemdup(p, s, i);
2054 x = apr_palloc(p, i + j + 1);
2055 for (i = 0, j = 0; s[i] != '\0'; i++, j++)
2057 memcpy(&x[j], "<", 4);
2060 else if (s[i] == '>') {
2061 memcpy(&x[j], ">", 4);
2064 else if (s[i] == '&') {
2065 memcpy(&x[j], "&", 5);
2068 else if (s[i] == '"') {
2069 memcpy(&x[j], """, 6);
2072 else if (toasc && !apr_isascii(s[i])) {
2073 char *esc = apr_psprintf(p, "&#%3.3d;", (unsigned char)s[i]);
2074 memcpy(&x[j], esc, 6);
2083 AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str)
2087 const unsigned char *s;
2088 apr_size_t length, escapes = 0;
2094 /* Compute how many characters need to be escaped */
2095 s = (const unsigned char *)str;
2097 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2102 /* Compute the length of the input string, including NULL */
2103 length = s - (const unsigned char *)str + 1;
2105 /* Fast path: nothing to escape */
2107 return apr_pmemdup(p, str, length);
2110 /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */
2111 ret = apr_palloc(p, length + 3 * escapes);
2112 d = (unsigned char *)ret;
2113 s = (const unsigned char *)str;
2115 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2151 AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
2154 unsigned char *d, *ep;
2155 const unsigned char *s;
2157 if (!source || !buflen) { /* be safe */
2161 d = (unsigned char *)dest;
2162 s = (const unsigned char *)source;
2163 ep = d + buflen - 1;
2165 for (; d < ep && *s; ++s) {
2167 if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
2193 case '"': /* no need for this in error log */
2198 ep = --d; /* break the for loop as well */
2211 return (d - (unsigned char *)dest);
2214 AP_DECLARE(void) ap_bin2hex(const void *src, apr_size_t srclen, char *dest)
2216 const unsigned char *in = src;
2219 for (i = 0; i < srclen; i++) {
2220 *dest++ = c2x_table[in[i] >> 4];
2221 *dest++ = c2x_table[in[i] & 0xf];
2226 AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
2230 if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS)
2231 return 0; /* in error condition, just return no */
2233 return (finfo.filetype == APR_DIR);
2236 AP_DECLARE(int) ap_is_rdirectory(apr_pool_t *p, const char *path)
2240 if (apr_stat(&finfo, path, APR_FINFO_LINK | APR_FINFO_TYPE, p) != APR_SUCCESS)
2241 return 0; /* in error condition, just return no */
2243 return (finfo.filetype == APR_DIR);
2246 AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
2249 apr_size_t len1, len2;
2252 len1 = strlen(src1);
2253 len2 = strlen(src2);
2254 /* allocate +3 for '/' delimiter, trailing NULL and overallocate
2255 * one extra byte to allow the caller to add a trailing '/'
2257 path = (char *)apr_palloc(a, len1 + len2 + 3);
2260 memcpy(path + 1, src2, len2 + 1);
2264 memcpy(path, src1, len1);
2266 if (next[-1] != '/') {
2269 memcpy(next, src2, len2 + 1);
2275 * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
2277 AP_DECLARE(int) ap_is_url(const char *u)
2281 for (x = 0; u[x] != ':'; x++) {
2283 ((!apr_isalnum(u[x])) &&
2284 (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
2289 return (x ? 1 : 0); /* If the first character is ':', it's broken, too */
2292 AP_DECLARE(int) ap_ind(const char *s, char c)
2294 const char *p = ap_strchr_c(s, c);
2301 AP_DECLARE(int) ap_rind(const char *s, char c)
2303 const char *p = ap_strrchr_c(s, c);
2310 AP_DECLARE(void) ap_str_tolower(char *str)
2313 *str = apr_tolower(*str);
2318 AP_DECLARE(void) ap_str_toupper(char *str)
2321 *str = apr_toupper(*str);
2327 * We must return a FQDN
2329 char *ap_get_local_host(apr_pool_t *a)
2331 #ifndef MAXHOSTNAMELEN
2332 #define MAXHOSTNAMELEN 256
2334 char str[MAXHOSTNAMELEN + 1];
2335 char *server_hostname = NULL;
2336 apr_sockaddr_t *sockaddr;
2339 if (apr_gethostname(str, sizeof(str) - 1, a) != APR_SUCCESS) {
2340 ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00556)
2341 "%s: apr_gethostname() failed to determine ServerName",
2344 str[sizeof(str) - 1] = '\0';
2345 if (apr_sockaddr_info_get(&sockaddr, str, APR_UNSPEC, 0, 0, a) == APR_SUCCESS) {
2346 if ( (apr_getnameinfo(&hostname, sockaddr, 0) == APR_SUCCESS) &&
2347 (ap_strchr_c(hostname, '.')) ) {
2348 server_hostname = apr_pstrdup(a, hostname);
2349 return server_hostname;
2350 } else if (ap_strchr_c(str, '.')) {
2351 server_hostname = apr_pstrdup(a, str);
2353 apr_sockaddr_ip_get(&hostname, sockaddr);
2354 server_hostname = apr_pstrdup(a, hostname);
2357 ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00557)
2358 "%s: apr_sockaddr_info_get() failed for %s",
2359 ap_server_argv0, str);
2363 if (!server_hostname)
2364 server_hostname = apr_pstrdup(a, "127.0.0.1");
2366 ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, a, APLOGNO(00558)
2367 "%s: Could not reliably determine the server's fully qualified "
2368 "domain name, using %s. Set the 'ServerName' directive globally "
2369 "to suppress this message",
2370 ap_server_argv0, server_hostname);
2372 return server_hostname;
2375 /* simple 'pool' alloc()ing glue to apr_base64.c
2377 AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
2382 decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded));
2383 l = apr_base64_decode(decoded, bufcoded);
2384 decoded[l] = '\0'; /* make binary sequence into string */
2389 /* a stringent version of ap_pbase64decode() */
2390 AP_DECLARE(apr_status_t) ap_pbase64decode_strict(apr_pool_t *p,
2391 const char *encoded,
2395 apr_size_t end_index;
2400 * TODO: this would be a lot more efficient if we had access to the lookup
2401 * table used by APR. If that gets pulled in at any point, make use of it.
2403 end_index = strspn(encoded, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2404 "abcdefghijklmnopqrstuvwxyz"
2407 last_group_len = end_index % 4;
2408 end = encoded + end_index;
2410 /* The only non-alphabet character allowed is the padding character '=' at
2411 * the end of the string. There are two allowable padding cases for the last
2412 * group of four: "xY==" or "xyZ=". We require the final (non-padding)
2413 * character to have been zero-padded during encoding, which limits the
2414 * character choices.
2416 if (last_group_len == 1) {
2417 /* This isn't ever valid. */
2420 else if (last_group_len == 2) {
2422 if (*end != '=' || end[1] != '=') {
2425 else if (!ap_strchr("AQgw", end[-1])) {
2426 /* Correctly zero-padded input data will result in a final character
2427 * that is one of the four above. */
2433 else if (last_group_len == 3) {
2438 else if (!ap_strchr("AEIMQUYcgkosw048", end[-1])) {
2439 /* Correctly zero-padded input data will result in a final character
2440 * that is one of the sixteen above. */
2447 /* At this point, if the encoded buffer is correct, we should be at the end
2453 *decoded = apr_palloc(p, apr_base64_decode_len(encoded));
2454 *len = apr_base64_decode(*decoded, encoded);
2459 AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
2462 int l = strlen(string);
2464 encoded = (char *) apr_palloc(p, 1 + apr_base64_encode_len(l));
2465 l = apr_base64_encode(encoded, string, l);
2466 encoded[l] = '\0'; /* make binary sequence into string */
2471 /* we want to downcase the type/subtype for comparison purposes
2472 * but nothing else because ;parameter=foo values are case sensitive.
2473 * XXX: in truth we want to downcase parameter names... but really,
2474 * apache has never handled parameters and such correctly. You
2475 * also need to compress spaces and such to be able to compare
2478 AP_DECLARE(void) ap_content_type_tolower(char *str)
2482 semi = strchr(str, ';');
2487 ap_str_tolower(str);
2495 * Given a string, replace any bare " with \" .
2497 AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
2500 const char *inchr = instring;
2501 char *outchr, *outstring;
2504 * Look through the input string, jogging the length of the output
2505 * string up by an extra byte each time we find an unescaped ".
2507 while (*inchr != '\0') {
2509 if (*inchr == '"') {
2513 * If we find a slosh, and it's not the last byte in the string,
2514 * it's escaping something - advance past both bytes.
2516 if ((*inchr == '\\') && (inchr[1] != '\0')) {
2522 outstring = apr_palloc(p, newlen + 1);
2526 * Now copy the input string to the output string, inserting a slosh
2527 * in front of every " that doesn't already have one.
2529 while (*inchr != '\0') {
2530 if ((*inchr == '\\') && (inchr[1] != '\0')) {
2531 *outchr++ = *inchr++;
2532 *outchr++ = *inchr++;
2534 if (*inchr == '"') {
2537 if (*inchr != '\0') {
2538 *outchr++ = *inchr++;
2546 * Given a string, append the PID deliminated by delim.
2547 * Usually used to create a pid-appended filepath name
2548 * (eg: /a/b/foo -> /a/b/foo.6726). A function, and not
2549 * a macro, to avoid unistd.h dependency
2551 AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string,
2554 return apr_psprintf(p, "%s%s%" APR_PID_T_FMT, string,
2560 * Parse a given timeout parameter string into an apr_interval_time_t value.
2561 * The unit of the time interval is given as postfix string to the numeric
2562 * string. Currently the following units are understood (case insensitive):
2569 * If no unit is contained in the given timeout parameter the default_time_unit
2570 * will be used instead.
2571 * @param timeout_parameter The string containing the timeout parameter.
2572 * @param timeout The timeout value to be returned.
2573 * @param default_time_unit The default time unit to use if none is specified
2574 * in timeout_parameter.
2575 * @return Status value indicating whether the parsing was successful or not.
2577 AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
2578 const char *timeout_parameter,
2579 apr_interval_time_t *timeout,
2580 const char *default_time_unit)
2583 const char *time_str;
2586 tout = apr_strtoi64(timeout_parameter, &endp, 10);
2590 if (!endp || !*endp) {
2591 time_str = default_time_unit;
2597 switch (*time_str) {
2598 /* Time is in seconds */
2601 *timeout = (apr_interval_time_t) apr_time_from_sec(tout);
2605 /* Time is in hours */
2606 *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 3600);
2610 switch (*(++time_str)) {
2611 /* Time is in milliseconds */
2614 *timeout = (apr_interval_time_t) tout * 1000;
2616 /* Time is in minutes */
2619 *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 60);
2622 return APR_EGENERAL;
2626 return APR_EGENERAL;
2632 * Determine if a request has a request body or not.
2634 * @param r the request_rec of the request
2635 * @return truth value
2637 AP_DECLARE(int) ap_request_has_body(request_rec *r)
2644 has_body = (!r->header_only
2646 || apr_table_get(r->headers_in, "Transfer-Encoding")
2647 || ( (cls = apr_table_get(r->headers_in, "Content-Length"))
2648 && (apr_strtoff(&cl, cls, &estr, 10) == APR_SUCCESS)
2657 * Check whether a request is tainted by exposure to something
2658 * potentially untrusted.
2661 AP_DECLARE(int) ap_request_tainted(request_rec *r, int flags)
2663 /** Potential future: a hook or callback here could serve modules
2664 * like mod_security and ironbee with more complex needs.
2666 return r && ((r->taint&flags)
2667 || ap_request_tainted(r->main, flags)
2668 || ap_request_tainted(r->prev, flags));
2671 AP_DECLARE_NONSTD(apr_status_t) ap_pool_cleanup_set_null(void *data_)
2673 void **ptr = (void **)data_;
2678 AP_DECLARE(apr_bucket_brigade *) ap_reuse_brigade_from_pool(const char *key,
2680 apr_bucket_alloc_t *alloc)
2682 apr_bucket_brigade *bb = NULL;
2683 apr_pool_userdata_get((void **)&bb, key, pool);
2685 bb = apr_brigade_create(pool, alloc);
2686 apr_pool_userdata_set(bb, key, NULL, pool);
2689 apr_brigade_cleanup(bb);
2694 AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
2696 for ( ; *src; src++, dest++)
2698 if (!apr_isprint(*src))
2700 else if (!apr_isalnum(*src))
2710 AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
2713 char *new = apr_palloc(p, strlen(src)+1);
2717 return ap_str2_alnum(src, new);
2721 * Read the body and parse any form found, which must be of the
2722 * type application/x-www-form-urlencoded.
2724 * Name/value pairs are returned in an array, with the names as
2725 * strings with a maximum length of HUGE_STRING_LEN, and the
2726 * values as bucket brigades. This allows values to be arbitrarily
2729 * All url-encoding is removed from both the names and the values
2730 * on the fly. The names are interpreted as strings, while the
2731 * values are interpreted as blocks of binary data, that may
2732 * contain the 0 character.
2734 * In order to ensure that resource limits are not exceeded, a
2735 * maximum size must be provided. If the sum of the lengths of
2736 * the names and the values exceed this size, this function
2737 * will return HTTP_REQUEST_ENTITY_TOO_LARGE.
2739 * An optional number of parameters can be provided, if the number
2740 * of parameters provided exceeds this amount, this function will
2741 * return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
2742 * no limit is imposed, and the number of parameters is in turn
2743 * constrained by the size parameter above.
2745 * This function honours any kept_body configuration, and the
2746 * original raw request body will be saved to the kept_body brigade
2747 * if so configured, just as ap_discard_request_body does.
2749 * NOTE: File upload is not yet supported, but can be without change
2750 * to the function call.
2753 /* form parsing stuff */
2764 AP_DECLARE(int) ap_parse_form_data(request_rec *r, ap_filter_t *f,
2765 apr_array_header_t **ptr,
2766 apr_size_t num, apr_size_t usize)
2768 apr_bucket_brigade *bb = NULL;
2770 char buffer[HUGE_STRING_LEN + 1];
2772 apr_size_t offset = 0;
2774 ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
2775 ap_form_pair_t *pair = NULL;
2776 apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
2777 char escaped_char[2] = { 0 };
2781 /* sanity check - we only support forms for now */
2782 ct = apr_table_get(r->headers_in, "Content-Type");
2783 if (!ct || ap_cstr_casecmpn("application/x-www-form-urlencoded", ct, 33)) {
2784 return ap_discard_request_body(r);
2787 if (usize > APR_SIZE_MAX >> 1)
2788 size = APR_SIZE_MAX >> 1;
2793 f = r->input_filters;
2796 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2798 apr_bucket *bucket = NULL, *last = NULL;
2800 int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
2801 APR_BLOCK_READ, HUGE_STRING_LEN);
2802 if (rv != APR_SUCCESS) {
2803 apr_brigade_destroy(bb);
2804 return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
2807 for (bucket = APR_BRIGADE_FIRST(bb);
2808 bucket != APR_BRIGADE_SENTINEL(bb);
2809 last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
2811 apr_size_t len, slide;
2814 apr_bucket_delete(last);
2816 if (APR_BUCKET_IS_EOS(bucket)) {
2820 if (bucket->length == 0) {
2824 rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
2825 if (rv != APR_SUCCESS) {
2826 apr_brigade_destroy(bb);
2827 return HTTP_BAD_REQUEST;
2831 while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
2836 else if ('&' == c) {
2840 percent = FORM_PERCENTA;
2843 if (FORM_PERCENTA == percent) {
2844 escaped_char[0] = c;
2845 percent = FORM_PERCENTB;
2848 if (FORM_PERCENTB == percent) {
2849 escaped_char[1] = c;
2850 c = x2c(escaped_char);
2851 percent = FORM_NORMAL;
2856 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2857 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2858 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2866 if (offset < HUGE_STRING_LEN) {
2868 pair = (ap_form_pair_t *) apr_array_push(pairs);
2869 pair->name = apr_pstrmemdup(r->pool, buffer, offset);
2870 pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2875 buffer[offset++] = c;
2884 if (offset >= HUGE_STRING_LEN) {
2885 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2886 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2887 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2890 buffer[offset++] = c;
2900 apr_brigade_cleanup(bb);
2901 } while (!seen_eos);
2903 if (FORM_ABORT == state || size < 0 || num == 0) {
2904 return HTTP_REQUEST_ENTITY_TOO_LARGE;
2906 else if (FORM_VALUE == state && pair && offset > 0) {
2907 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2908 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2909 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2916 #define VARBUF_SMALL_SIZE 2048
2917 #define VARBUF_MAX_SIZE (APR_SIZE_MAX - 1 - \
2918 APR_ALIGN_DEFAULT(sizeof(struct ap_varbuf_info)))
2920 struct ap_varbuf_info {
2921 struct apr_memnode_t *node;
2922 apr_allocator_t *allocator;
2925 static apr_status_t varbuf_cleanup(void *info_)
2927 struct ap_varbuf_info *info = info_;
2928 info->node->next = NULL;
2929 apr_allocator_free(info->allocator, info->node);
2933 const char nul = '\0';
2934 static char * const varbuf_empty = (char *)&nul;
2936 AP_DECLARE(void) ap_varbuf_init(apr_pool_t *p, struct ap_varbuf *vb,
2937 apr_size_t init_size)
2939 vb->buf = varbuf_empty;
2941 vb->strlen = AP_VARBUF_UNKNOWN;
2945 ap_varbuf_grow(vb, init_size);
2948 AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
2950 apr_memnode_t *new_node = NULL;
2951 apr_allocator_t *allocator;
2952 struct ap_varbuf_info *new_info;
2955 AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN || vb->avail >= vb->strlen);
2957 if (new_len <= vb->avail)
2960 if (new_len < 2 * vb->avail && vb->avail < VARBUF_MAX_SIZE/2) {
2961 /* at least double the size, to avoid repeated reallocations */
2962 new_len = 2 * vb->avail;
2964 else if (new_len > VARBUF_MAX_SIZE) {
2965 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2966 ap_assert(abort_fn != NULL);
2967 abort_fn(APR_ENOMEM);
2971 new_len++; /* add space for trailing \0 */
2972 if (new_len <= VARBUF_SMALL_SIZE) {
2973 new_len = APR_ALIGN_DEFAULT(new_len);
2974 new = apr_palloc(vb->pool, new_len);
2975 if (vb->avail && vb->strlen != 0) {
2976 AP_DEBUG_ASSERT(vb->buf != NULL);
2977 AP_DEBUG_ASSERT(vb->buf != varbuf_empty);
2978 if (new == vb->buf + vb->avail + 1) {
2979 /* We are lucky: the new memory lies directly after our old
2980 * buffer, we can now use both.
2982 vb->avail += new_len;
2986 /* copy up to vb->strlen + 1 bytes */
2987 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2988 vb->avail + 1 : vb->strlen + 1);
2994 vb->avail = new_len - 1;
2999 /* The required block is rather larger. Use allocator directly so that
3000 * the memory can be freed independently from the pool. */
3001 allocator = apr_pool_allocator_get(vb->pool);
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 */