1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * util.c: string utility things
21 * 1995-96 Many changes by the Apache Software Foundation
26 * #define DEBUG to trace all cfg_open*()/cfg_closefile() calls
27 * #define DEBUG_CFG_LINES to trace every line read from the config files
31 #include "apr_strings.h"
33 #include "apr_md5.h" /* for apr_password_validate */
35 #define APR_WANT_STDIO
36 #define APR_WANT_STRFUNC
42 #if APR_HAVE_PROCESS_H
43 #include <process.h> /* for getpid() on Win32 */
46 #include <netdb.h> /* for gethostbyname() */
49 #include "ap_config.h"
50 #include "apr_base64.h"
52 #include "http_main.h"
54 #include "http_protocol.h"
55 #include "http_config.h"
56 #include "http_core.h"
57 #include "util_ebcdic.h"
58 #include "util_varbuf.h"
66 #ifdef HAVE_SYS_LOADAVG_H
67 #include <sys/loadavg.h>
72 /* A bunch of functions in util.c scan strings looking for certain characters.
73 * To make that more efficient we encode a lookup table. The test_char_table
74 * is generated automatically by gen_test_char.c.
76 #include "test_char.h"
78 /* we assume the folks using this ensure 0 <= c < 256... which means
79 * you need a cast to (unsigned char) first, you can't just plug a
80 * char in here and get it to work, because if char is signed then it
81 * will first be sign extended.
83 #define TEST_CHAR(c, f) (test_char_table[(unsigned char)(c)] & (f))
85 /* Win32/NetWare/OS2 need to check for both forward and back slashes
86 * in ap_getparents() and ap_escape_url.
88 #ifdef CASE_BLIND_FILESYSTEM
89 #define IS_SLASH(s) ((s == '/') || (s == '\\'))
92 #define IS_SLASH(s) (s == '/')
96 /* we know core's module_index is 0 */
97 #undef APLOG_MODULE_INDEX
98 #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
101 * Examine a field value (such as a media-/content-type) string and return
102 * it sans any parameters; e.g., strip off any ';charset=foo' and the like.
104 AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype)
108 if (intype == NULL) return NULL;
110 semi = ap_strchr_c(intype, ';');
112 return apr_pstrdup(p, intype);
115 while ((semi > intype) && apr_isspace(semi[-1])) {
118 return apr_pstrmemdup(p, intype, semi - intype);
122 AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt,
126 char ts[MAX_STRING_LEN];
127 char tf[MAX_STRING_LEN];
134 apr_time_exp_gmt(&xt, t);
135 /* Convert %Z to "GMT" and %z to "+0000";
136 * on hosts that do not have a time zone string in struct tm,
137 * strftime must assume its argument is local time.
139 for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f)
141 if (*f != '%') continue;
152 case 'z': /* common extension */
166 apr_time_exp_lt(&xt, t);
169 /* check return code? */
170 apr_strftime(ts, &retcode, MAX_STRING_LEN, fmt, &xt);
171 ts[MAX_STRING_LEN - 1] = '\0';
172 return apr_pstrdup(p, ts);
175 /* Roy owes Rob beer. */
176 /* Rob owes Roy dinner. */
178 /* These legacy comments would make a lot more sense if Roy hadn't
179 * replaced the old later_than() routine with util_date.c.
181 * Well, okay, they still wouldn't make any sense.
184 /* Match = 0, NoMatch = 1, Abort = -1
185 * Based loosely on sections of wildmat.c by Rich Salz
186 * Hmmm... shouldn't this really go component by component?
188 AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected)
192 for (x = 0, y = 0; expected[y]; ++y, ++x) {
193 if ((!str[x]) && (expected[y] != '*'))
195 if (expected[y] == '*') {
196 while (expected[++y] == '*');
201 if ((ret = ap_strcmp_match(&str[x++], &expected[y])) != 1)
206 else if ((expected[y] != '?') && (str[x] != expected[y]))
209 return (str[x] != '\0');
212 AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
216 for (x = 0, y = 0; expected[y]; ++y, ++x) {
217 if (!str[x] && expected[y] != '*')
219 if (expected[y] == '*') {
220 while (expected[++y] == '*');
225 if ((ret = ap_strcasecmp_match(&str[x++], &expected[y])) != 1)
230 else if (expected[y] != '?'
231 && apr_tolower(str[x]) != apr_tolower(expected[y]))
234 return (str[x] != '\0');
237 /* We actually compare the canonical root to this root, (but we don't
238 * waste time checking the case), since every use of this function in
239 * httpd-2.1 tests if the path is 'proper', meaning we've already passed
240 * it through apr_filepath_merge, or we haven't.
242 AP_DECLARE(int) ap_os_is_path_absolute(apr_pool_t *p, const char *dir)
245 const char *ourdir = dir;
246 if (apr_filepath_root(&newpath, &dir, 0, p) != APR_SUCCESS
247 || strncmp(newpath, ourdir, strlen(newpath)) != 0) {
253 AP_DECLARE(int) ap_is_matchexp(const char *str)
257 for (x = 0; str[x]; x++)
258 if ((str[x] == '*') || (str[x] == '?'))
264 * Here's a pool-based interface to the POSIX-esque ap_regcomp().
265 * Note that we return ap_regex_t instead of being passed one.
266 * The reason is that if you use an already-used ap_regex_t structure,
267 * the memory that you've already allocated gets forgotten, and
268 * regfree() doesn't clear it. So we don't allow it.
271 static apr_status_t regex_cleanup(void *preg)
273 ap_regfree((ap_regex_t *) preg);
277 AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
280 ap_regex_t *preg = apr_palloc(p, sizeof *preg);
281 int err = ap_regcomp(preg, pattern, cflags);
283 if (err == AP_REG_ESPACE)
288 apr_pool_cleanup_register(p, (void *) preg, regex_cleanup,
289 apr_pool_cleanup_null);
294 AP_DECLARE(void) ap_pregfree(apr_pool_t *p, ap_regex_t *reg)
297 apr_pool_cleanup_kill(p, (void *) reg, regex_cleanup);
301 * Similar to standard strstr() but we ignore case in this version.
302 * Based on the strstr() implementation further below.
304 AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2)
312 for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
316 /* found first character of s2, see if the rest matches */
319 for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) {
321 /* both strings ended together */
326 /* second string ended, a match */
329 /* didn't find a match here, try starting at next character in s1 */
336 * Returns an offsetted pointer in bigstring immediately after
337 * prefix. Returns bigstring if bigstring doesn't start with
338 * prefix or if prefix is longer than bigstring while still matching.
339 * NOTE: pointer returned is relative to bigstring, so we
340 * can use standard pointer comparisons in the calling function
341 * (eg: test if ap_stripprefix(a,b) == a)
343 AP_DECLARE(const char *) ap_stripprefix(const char *bigstring,
352 while (*p1 && *prefix) {
353 if (*p1++ != *prefix++)
359 /* hit the end of bigstring! */
363 /* This function substitutes for $0-$9, filling in regular expression
364 * submatches. Pass it the same nmatch and pmatch arguments that you
365 * passed ap_regexec(). pmatch should not be greater than the maximum number
366 * of subexpressions - i.e. one more than the re_nsub member of ap_regex_t.
368 * nmatch must be <=AP_MAX_REG_MATCH (10).
370 * input should be the string with the $-expressions, source should be the
371 * string that was matched against.
373 * It returns the substituted string, or NULL if a vbuf is used.
374 * On errors, returns the orig string.
376 * Parts of this code are based on Henry Spencer's regsub(), from his
377 * AT&T V8 regexp package.
380 static apr_status_t regsub_core(apr_pool_t *p, char **result,
381 struct ap_varbuf *vb, const char *input,
382 const char *source, apr_size_t nmatch,
383 ap_regmatch_t pmatch[], apr_size_t maxlen)
385 const char *src = input;
391 AP_DEBUG_ASSERT((result && p && !vb) || (vb && !p && !result));
392 if (!source || nmatch>AP_MAX_REG_MATCH)
396 if (maxlen > 0 && len >= maxlen)
399 *result = apr_pstrmemdup(p, src, len);
403 ap_varbuf_strmemcat(vb, src, len);
408 /* First pass, find the size */
409 while ((c = *src++) != '\0') {
410 if (c == '$' && apr_isdigit(*src))
413 no = AP_MAX_REG_MATCH;
415 if (no >= AP_MAX_REG_MATCH) { /* Ordinary character. */
416 if (c == '\\' && *src)
420 else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
421 if (APR_SIZE_MAX - len <= pmatch[no].rm_eo - pmatch[no].rm_so)
423 len += pmatch[no].rm_eo - pmatch[no].rm_so;
428 if (len >= maxlen && maxlen > 0)
432 *result = dst = apr_palloc(p, len + 1);
435 if (vb->strlen == AP_VARBUF_UNKNOWN)
436 vb->strlen = strlen(vb->buf);
437 ap_varbuf_grow(vb, vb->strlen + len);
438 dst = vb->buf + vb->strlen;
442 /* Now actually fill in the string */
446 while ((c = *src++) != '\0') {
447 if (c == '$' && apr_isdigit(*src))
450 no = AP_MAX_REG_MATCH;
452 if (no >= AP_MAX_REG_MATCH) { /* Ordinary character. */
453 if (c == '\\' && *src)
457 else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
458 len = pmatch[no].rm_eo - pmatch[no].rm_so;
459 memcpy(dst, source + pmatch[no].rm_so, len);
469 #ifndef AP_PREGSUB_MAXLEN
470 #define AP_PREGSUB_MAXLEN (HUGE_STRING_LEN * 8)
472 AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
473 const char *source, apr_size_t nmatch,
474 ap_regmatch_t pmatch[])
477 apr_status_t rc = regsub_core(p, &result, NULL, input, source, nmatch,
478 pmatch, AP_PREGSUB_MAXLEN);
479 if (rc != APR_SUCCESS)
484 AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result,
485 const char *input, const char *source,
486 apr_size_t nmatch, ap_regmatch_t pmatch[],
489 apr_status_t rc = regsub_core(p, result, NULL, input, source, nmatch,
491 if (rc != APR_SUCCESS)
497 * Parse .. so we don't compromise security
499 AP_DECLARE(void) ap_getparents(char *name)
504 /* Four paseses, as per RFC 1808 */
505 /* a) remove ./ path segments */
506 for (next = name; *next && (*next != '.'); next++) {
509 l = w = first_dot = next - name;
510 while (name[l] != '\0') {
511 if (name[l] == '.' && IS_SLASH(name[l + 1])
512 && (l == 0 || IS_SLASH(name[l - 1])))
515 name[w++] = name[l++];
518 /* b) remove trailing . path, segment */
519 if (w == 1 && name[0] == '.')
521 else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2]))
525 /* c) remove all xx/../ segments. (including leading ../ and /../) */
528 while (name[l] != '\0') {
529 if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2])
530 && (l == 0 || IS_SLASH(name[l - 1]))) {
535 while (l >= 0 && !IS_SLASH(name[l]))
542 while ((name[n] = name[m]))
549 /* d) remove trailing xx/.. segment. */
550 if (l == 2 && name[0] == '.' && name[1] == '.')
552 else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
553 && IS_SLASH(name[l - 3])) {
556 while (l >= 0 && !IS_SLASH(name[l]))
566 AP_DECLARE(void) ap_no2slash(char *name)
572 #ifdef HAVE_UNC_PATHS
573 /* Check for UNC names. Leave leading two slashes. */
574 if (s[0] == '/' && s[1] == '/')
579 if ((*d++ = *s) == '/') {
593 * copy at most n leading directories of s into d
594 * d should be at least as large as s plus 1 extra byte
596 * the return value is the ever useful pointer to the trailing \0 of d
598 * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments,
599 * so that if n == 0, "/" is returned in d with n == 1
600 * and s == "e:/test.html", "e:/" is returned in d
601 * *** See also directory_walk in modules/http/http_request.c
604 * /a/b, 0 ==> / (true for all platforms)
613 * c:/a/b 3 ==> c:/a/b
614 * c:/a/b 4 ==> c:/a/b
616 AP_DECLARE(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
625 if (*s == '\0' || (*s == '/' && (--n) == 0)) {
637 * return the parent directory name including trailing / of the file s
639 AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s)
641 const char *last_slash = ap_strrchr_c(s, '/');
645 if (last_slash == NULL) {
646 return apr_pstrdup(p, "");
648 l = (last_slash - s) + 1;
649 d = apr_pstrmemdup(p, s, l);
655 AP_DECLARE(int) ap_count_dirs(const char *path)
659 for (x = 0, n = 0; path[x]; x++)
665 AP_DECLARE(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop)
667 return ap_getword(atrans, (const char **) line, stop);
670 AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop)
672 const char *pos = *line;
676 while ((*pos != stop) && *pos) {
681 res = apr_pstrmemdup(atrans, *line, len);
684 while (*pos == stop) {
693 AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
695 return ap_getword_white(atrans, (const char **) line);
698 AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
700 const char *pos = *line;
704 while (!apr_isspace(*pos) && *pos) {
709 res = apr_pstrmemdup(atrans, *line, len);
711 while (apr_isspace(*pos)) {
720 AP_DECLARE(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line,
723 return ap_getword_nulls(atrans, (const char **) line, stop);
726 AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line,
729 const char *pos = ap_strchr_c(*line, stop);
733 apr_size_t len = strlen(*line);
734 res = apr_pstrmemdup(atrans, *line, len);
739 res = apr_pstrmemdup(atrans, *line, pos - *line);
748 /* Get a word, (new) config-file style --- quoted strings and backslashes
752 static char *substring_conf(apr_pool_t *p, const char *start, int len,
755 char *result = apr_palloc(p, len + 1);
759 for (i = 0; i < len; ++i) {
760 if (start[i] == '\\' && (start[i + 1] == '\\'
761 || (quote && start[i + 1] == quote)))
762 *resp++ = start[++i];
768 #if RESOLVE_ENV_PER_TOKEN
769 return (char *)ap_resolve_env(p,result);
775 AP_DECLARE(char *) ap_getword_conf_nc(apr_pool_t *p, char **line)
777 return ap_getword_conf(p, (const char **) line);
780 AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line)
782 const char *str = *line, *strend;
786 while (apr_isspace(*str))
794 if ((quote = *str) == '"' || quote == '\'') {
796 while (*strend && *strend != quote) {
797 if (*strend == '\\' && strend[1] &&
798 (strend[1] == quote || strend[1] == '\\')) {
805 res = substring_conf(p, str + 1, strend - str - 1, quote);
807 if (*strend == quote)
812 while (*strend && !apr_isspace(*strend))
815 res = substring_conf(p, str, strend - str, 0);
818 while (apr_isspace(*strend))
824 AP_DECLARE(char *) ap_getword_conf2_nc(apr_pool_t *p, char **line)
826 return ap_getword_conf2(p, (const char **) line);
829 AP_DECLARE(char *) ap_getword_conf2(apr_pool_t *p, const char **line)
831 const char *str = *line, *strend;
836 while (apr_isspace(*str))
844 if ((quote = *str) == '"' || quote == '\'')
845 return ap_getword_conf(p, line);
850 if (*strend == '}' && !--count)
854 if (*strend == '\\' && strend[1] && strend[1] == '\\') {
859 res = substring_conf(p, str + 1, strend - str - 1, 0);
866 while (*strend && !apr_isspace(*strend))
869 res = substring_conf(p, str, strend - str, 0);
872 while (apr_isspace(*strend))
878 AP_DECLARE(int) ap_cfg_closefile(ap_configfile_t *cfp)
881 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00551)
882 "Done with config file %s", cfp->name);
884 return (cfp->close == NULL) ? 0 : cfp->close(cfp->param);
887 /* we can't use apr_file_* directly because of linking issues on Windows */
888 static apr_status_t cfg_close(void *param)
890 return apr_file_close(param);
893 static apr_status_t cfg_getch(char *ch, void *param)
895 return apr_file_getc(ch, param);
898 static apr_status_t cfg_getstr(void *buf, apr_size_t bufsiz, void *param)
900 return apr_file_gets(buf, bufsiz, param);
903 /* Open a ap_configfile_t as FILE, return open ap_configfile_t struct pointer */
904 AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg,
905 apr_pool_t *p, const char *name)
907 ap_configfile_t *new_cfg;
908 apr_file_t *file = NULL;
916 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00552)
917 "Internal error: pcfg_openfile() called with NULL filename");
921 status = apr_file_open(&file, name, APR_READ | APR_BUFFERED,
924 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00553)
925 "Opening config file %s (%s)",
926 name, (status != APR_SUCCESS) ?
927 apr_strerror(status, buf, sizeof(buf)) : "successful");
929 if (status != APR_SUCCESS)
932 status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file);
933 if (status != APR_SUCCESS)
936 if (finfo.filetype != APR_REG &&
937 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
938 ap_cstr_casecmp(apr_filepath_name_get(name), "nul") != 0) {
940 strcmp(name, "/dev/null") != 0) {
941 #endif /* WIN32 || OS2 */
942 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00554)
943 "Access to file %s denied by server: not a regular file",
945 apr_file_close(file);
950 /* Some twisted character [no pun intended] at MS decided that a
951 * zero width joiner as the lead wide character would be ideal for
952 * describing Unicode text files. This was further convoluted to
953 * another MSism that the same character mapped into utf-8, EF BB BF
954 * would signify utf-8 text files.
956 * Since MS configuration files are all protecting utf-8 encoded
957 * Unicode path, file and resource names, we already have the correct
958 * WinNT encoding. But at least eat the stupid three bytes up front.
961 unsigned char buf[4];
963 status = apr_file_read(file, buf, &len);
964 if ((status != APR_SUCCESS) || (len < 3)
965 || memcmp(buf, "\xEF\xBB\xBF", 3) != 0) {
967 apr_file_seek(file, APR_SET, &zero);
972 new_cfg = apr_palloc(p, sizeof(*new_cfg));
973 new_cfg->param = file;
974 new_cfg->name = apr_pstrdup(p, name);
975 new_cfg->getch = cfg_getch;
976 new_cfg->getstr = cfg_getstr;
977 new_cfg->close = cfg_close;
978 new_cfg->line_number = 0;
984 /* Allocate a ap_configfile_t handle with user defined functions and params */
985 AP_DECLARE(ap_configfile_t *) ap_pcfg_open_custom(
986 apr_pool_t *p, const char *descr, void *param,
987 apr_status_t (*getc_func) (char *ch, void *param),
988 apr_status_t (*gets_func) (void *buf, apr_size_t bufsize, void *param),
989 apr_status_t (*close_func) (void *param))
991 ap_configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg));
992 new_cfg->param = param;
993 new_cfg->name = descr;
994 new_cfg->getch = getc_func;
995 new_cfg->getstr = gets_func;
996 new_cfg->close = close_func;
997 new_cfg->line_number = 0;
1001 /* Read one character from a configfile_t */
1002 AP_DECLARE(apr_status_t) ap_cfg_getc(char *ch, ap_configfile_t *cfp)
1004 apr_status_t rc = cfp->getch(ch, cfp->param);
1005 if (rc == APR_SUCCESS && *ch == LF)
1010 AP_DECLARE(const char *) ap_pcfg_strerror(apr_pool_t *p, ap_configfile_t *cfp,
1013 if (rc == APR_SUCCESS)
1016 if (rc == APR_ENOSPC)
1017 return apr_psprintf(p, "Error reading %s at line %d: Line too long",
1018 cfp->name, cfp->line_number);
1020 return apr_psprintf(p, "Error reading %s at line %d: %pm",
1021 cfp->name, cfp->line_number, &rc);
1024 /* Read one line from open ap_configfile_t, strip LF, increase line number */
1025 /* If custom handler does not define a getstr() function, read char by char */
1026 static apr_status_t ap_cfg_getline_core(char *buf, apr_size_t bufsize,
1027 apr_size_t offset, ap_configfile_t *cfp)
1030 /* If a "get string" function is defined, use it */
1031 if (cfp->getstr != NULL) {
1033 char *cbuf = buf + offset;
1034 apr_size_t cbufsize = bufsize - offset;
1038 rc = cfp->getstr(cbuf, cbufsize, cfp->param);
1039 if (rc == APR_EOF) {
1040 if (cbuf != buf + offset) {
1048 if (rc != APR_SUCCESS) {
1053 * check for line continuation,
1054 * i.e. match [^\\]\\[\r]\n only
1058 if (cp > buf && cp[-1] == LF) {
1060 if (cp > buf && cp[-1] == CR)
1062 if (cp > buf && cp[-1] == '\\') {
1065 * line continuation requested -
1066 * then remove backslash and continue
1068 cbufsize -= (cp-cbuf);
1073 else if (cp - buf >= bufsize - 1) {
1079 /* No "get string" function defined; read character by character */
1080 apr_size_t i = offset;
1083 /* too small, assume caller is crazy */
1090 rc = cfp->getch(&c, cfp->param);
1091 if (rc == APR_EOF) {
1097 if (rc != APR_SUCCESS)
1101 /* check for line continuation */
1102 if (i > 0 && buf[i-1] == '\\') {
1112 if (i >= bufsize - 1) {
1121 static int cfg_trim_line(char *buf)
1125 * Leading and trailing white space is eliminated completely
1128 while (apr_isspace(*start))
1130 /* blast trailing whitespace */
1131 end = &start[strlen(start)];
1132 while (--end >= start && apr_isspace(*end))
1134 /* Zap leading whitespace by shifting */
1136 memmove(buf, start, end - start + 2);
1137 #ifdef DEBUG_CFG_LINES
1138 ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, APLOGNO(00555) "Read config: '%s'", buf);
1140 return end - start + 1;
1143 /* Read one line from open ap_configfile_t, strip LF, increase line number */
1144 /* If custom handler does not define a getstr() function, read char by char */
1145 AP_DECLARE(apr_status_t) ap_cfg_getline(char *buf, apr_size_t bufsize,
1146 ap_configfile_t *cfp)
1148 apr_status_t rc = ap_cfg_getline_core(buf, bufsize, 0, cfp);
1149 if (rc == APR_SUCCESS)
1154 AP_DECLARE(apr_status_t) ap_varbuf_cfg_getline(struct ap_varbuf *vb,
1155 ap_configfile_t *cfp,
1163 if (vb->strlen == AP_VARBUF_UNKNOWN)
1164 vb->strlen = strlen(vb->buf);
1165 if (vb->avail - vb->strlen < 3) {
1166 new_len = vb->avail * 2;
1167 if (new_len > max_len)
1169 else if (new_len < 3)
1171 ap_varbuf_grow(vb, new_len);
1175 rc = ap_cfg_getline_core(vb->buf, vb->avail, vb->strlen, cfp);
1176 if (rc == APR_ENOSPC || rc == APR_SUCCESS)
1177 vb->strlen += strlen(vb->buf + vb->strlen);
1178 if (rc != APR_ENOSPC)
1180 if (vb->avail >= max_len)
1182 new_len = vb->avail * 2;
1183 if (new_len > max_len)
1185 ap_varbuf_grow(vb, new_len);
1188 if (vb->strlen > max_len)
1190 if (rc == APR_SUCCESS)
1191 vb->strlen = cfg_trim_line(vb->buf);
1195 /* Size an HTTP header field list item, as separated by a comma.
1196 * The return value is a pointer to the beginning of the non-empty list item
1197 * within the original string (or NULL if there is none) and the address
1198 * of field is shifted to the next non-comma, non-whitespace character.
1199 * len is the length of the item excluding any beginning whitespace.
1201 AP_DECLARE(const char *) ap_size_list_item(const char **field, int *len)
1203 const unsigned char *ptr = (const unsigned char *)*field;
1204 const unsigned char *token;
1205 int in_qpair, in_qstr, in_com;
1207 /* Find first non-comma, non-whitespace byte */
1209 while (*ptr == ',' || apr_isspace(*ptr))
1214 /* Find the end of this item, skipping over dead bits */
1216 for (in_qpair = in_qstr = in_com = 0;
1217 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1225 case '\\': in_qpair = 1; /* quoted-pair */
1227 case '"' : if (!in_com) /* quoted string delim */
1230 case '(' : if (!in_qstr) /* comment (may nest) */
1233 case ')' : if (in_com) /* end comment */
1241 if ((*len = (ptr - token)) == 0) {
1242 *field = (const char *)ptr;
1246 /* Advance field pointer to the next non-comma, non-white byte */
1248 while (*ptr == ',' || apr_isspace(*ptr))
1251 *field = (const char *)ptr;
1252 return (const char *)token;
1255 /* Retrieve an HTTP header field list item, as separated by a comma,
1256 * while stripping insignificant whitespace and lowercasing anything not in
1257 * a quoted string or comment. The return value is a new string containing
1258 * the converted list item (or NULL if none) and the address pointed to by
1259 * field is shifted to the next non-comma, non-whitespace.
1261 AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field)
1263 const char *tok_start;
1264 const unsigned char *ptr;
1267 int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
1269 /* Find the beginning and maximum length of the list item so that
1270 * we can allocate a buffer for the new string and reset the field.
1272 if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
1275 token = apr_palloc(p, tok_len + 1);
1277 /* Scan the token again, but this time copy only the good bytes.
1278 * We skip extra whitespace and any whitespace around a '=', '/',
1279 * or ';' and lowercase normal characters not within a comment,
1280 * quoted-string or quoted-pair.
1282 for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
1283 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1292 case '\\': in_qpair = 1;
1298 case '"' : if (!in_com)
1305 case '(' : if (!in_qstr)
1312 case ')' : if (in_com)
1318 case '\t': if (addspace)
1320 if (in_com || in_qstr)
1327 case ';' : if (!(in_com || in_qstr))
1331 default : if (addspace == 1)
1333 *pos++ = (in_com || in_qstr) ? *ptr
1334 : apr_tolower(*ptr);
1345 typedef enum ap_etag_e {
1351 /* Find an item in canonical form (lowercase, no extra spaces) within
1352 * an HTTP field value list. Returns 1 if found, 0 if not found.
1353 * This would be much more efficient if we stored header fields as
1354 * an array of list items as they are received instead of a plain string.
1356 static int find_list_item(apr_pool_t *p, const char *line,
1357 const char *tok, ap_etag_e type)
1359 const unsigned char *pos;
1360 const unsigned char *ptr = (const unsigned char *)line;
1361 int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
1363 if (!line || !tok) {
1366 if (type == AP_ETAG_STRONG && *tok != '\"') {
1369 if (type == AP_ETAG_WEAK) {
1370 if (*tok == 'W' && (*(tok+1)) == '/' && (*(tok+2)) == '\"') {
1373 else if (*tok != '\"') {
1378 do { /* loop for each item in line's list */
1380 /* Find first non-comma, non-whitespace byte */
1381 while (*ptr == ',' || apr_isspace(*ptr)) {
1385 /* Account for strong or weak Etags, depending on our search */
1386 if (type == AP_ETAG_STRONG && *ptr != '\"') {
1389 if (type == AP_ETAG_WEAK) {
1390 if (*ptr == 'W' && (*(ptr+1)) == '/' && (*(ptr+2)) == '\"') {
1393 else if (*ptr != '\"') {
1399 good = 1; /* until proven otherwise for this item */
1401 break; /* no items left and nothing good found */
1403 /* We skip extra whitespace and any whitespace around a '=', '/',
1404 * or ';' and lowercase normal characters not within a comment,
1405 * quoted-string or quoted-pair.
1407 for (pos = (const unsigned char *)tok;
1408 *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
1414 good = (*pos++ == *ptr);
1418 case '\\': in_qpair = 1;
1420 good = good && (*pos++ == ' ');
1421 good = good && (*pos++ == *ptr);
1424 case '"' : if (!in_com)
1427 good = good && (*pos++ == ' ');
1428 good = good && (*pos++ == *ptr);
1431 case '(' : if (!in_qstr)
1434 good = good && (*pos++ == ' ');
1435 good = good && (*pos++ == *ptr);
1438 case ')' : if (in_com)
1440 good = good && (*pos++ == *ptr);
1444 case '\t': if (addspace || !good)
1446 if (in_com || in_qstr)
1447 good = (*pos++ == *ptr);
1453 case ';' : if (!(in_com || in_qstr))
1455 good = good && (*pos++ == *ptr);
1457 default : if (!good)
1460 good = (*pos++ == ' ');
1461 if (in_com || in_qstr)
1462 good = good && (*pos++ == *ptr);
1465 && (apr_tolower(*pos++) == apr_tolower(*ptr));
1472 good = 0; /* not good if only a prefix was matched */
1474 } while (*ptr && !good);
1479 /* Find an item in canonical form (lowercase, no extra spaces) within
1480 * an HTTP field value list. Returns 1 if found, 0 if not found.
1481 * This would be much more efficient if we stored header fields as
1482 * an array of list items as they are received instead of a plain string.
1484 AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line,
1487 return find_list_item(p, line, tok, AP_ETAG_NONE);
1490 /* Find a strong Etag in canonical form (lowercase, no extra spaces) within
1491 * an HTTP field value list. Returns 1 if found, 0 if not found.
1493 AP_DECLARE(int) ap_find_etag_strong(apr_pool_t *p, const char *line,
1496 return find_list_item(p, line, tok, AP_ETAG_STRONG);
1499 /* Find a weak ETag in canonical form (lowercase, no extra spaces) within
1500 * an HTTP field value list. Returns 1 if found, 0 if not found.
1502 AP_DECLARE(int) ap_find_etag_weak(apr_pool_t *p, const char *line,
1505 return find_list_item(p, line, tok, AP_ETAG_WEAK);
1508 /* Grab a list of tokens of the format 1#token (from RFC7230) */
1509 AP_DECLARE(const char *) ap_parse_token_list_strict(apr_pool_t *p,
1511 apr_array_header_t **tokens,
1514 int in_leading_space = 1;
1515 int in_trailing_space = 0;
1517 const char *tok_begin;
1524 tok_begin = cur = str_in;
1526 while (!string_end) {
1527 const unsigned char c = (unsigned char)*cur;
1529 if (!TEST_CHAR(c, T_HTTP_TOKEN_STOP)) {
1530 /* Non-separator character; we are finished with leading
1531 * whitespace. We must never have encountered any trailing
1532 * whitespace before the delimiter (comma) */
1533 in_leading_space = 0;
1534 if (in_trailing_space) {
1535 return "Encountered illegal whitespace in token";
1538 else if (c == ' ' || c == '\t') {
1539 /* "Linear whitespace" only includes ASCII CRLF, space, and tab;
1540 * we can't get a CRLF since headers are split on them already,
1541 * so only look for a space or a tab */
1542 if (in_leading_space) {
1543 /* We're still in leading whitespace */
1547 /* We must be in trailing whitespace */
1548 ++in_trailing_space;
1551 else if (c == ',' || c == '\0') {
1552 if (!in_leading_space) {
1553 /* If we're out of the leading space, we know we've read some
1554 * characters of a token */
1555 if (*tokens == NULL) {
1556 *tokens = apr_array_make(p, 4, sizeof(char *));
1558 APR_ARRAY_PUSH(*tokens, char *) =
1559 apr_pstrmemdup((*tokens)->pool, tok_begin,
1560 (cur - tok_begin) - in_trailing_space);
1562 /* We're allowed to have null elements, just don't add them to the
1565 tok_begin = cur + 1;
1566 in_leading_space = 1;
1567 in_trailing_space = 0;
1568 string_end = (c == '\0');
1571 /* Encountered illegal separator char */
1573 /* Skip to the next separator */
1575 temp = ap_strchr_c(cur, ',');
1577 temp = ap_strchr_c(cur, '\0');
1580 /* Act like we haven't seen a token so we reset */
1582 in_leading_space = 1;
1583 in_trailing_space = 0;
1586 return apr_psprintf(p, "Encountered illegal separator "
1587 "'\\x%.2x'", (unsigned int)c);
1597 /* Scan a string for HTTP VCHAR/obs-text characters including HT and SP
1598 * (as used in header values, for example, in RFC 7230 section 3.2)
1599 * returning the pointer to the first non-HT ASCII ctrl character.
1601 AP_DECLARE(const char *) ap_scan_http_field_content(const char *ptr)
1603 for ( ; !TEST_CHAR(*ptr, T_HTTP_CTRLS); ++ptr) ;
1608 /* Scan a string for HTTP token characters, returning the pointer to
1609 * the first non-token character.
1611 AP_DECLARE(const char *) ap_scan_http_token(const char *ptr)
1613 for ( ; !TEST_CHAR(*ptr, T_HTTP_TOKEN_STOP); ++ptr) ;
1618 /* Scan a string for visible ASCII (0x21-0x7E) or obstext (0x80+)
1619 * and return a pointer to the first ctrl/space character encountered.
1621 AP_DECLARE(const char *) ap_scan_vchar_obstext(const char *ptr)
1623 for ( ; TEST_CHAR(*ptr, T_VCHAR_OBSTEXT); ++ptr) ;
1628 /* Retrieve a token, spacing over it and returning a pointer to
1629 * the first non-white byte afterwards. Note that these tokens
1630 * are delimited by semis and commas; and can also be delimited
1631 * by whitespace at the caller's option.
1634 AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line,
1637 const char *ptr = *accept_line;
1638 const char *tok_start;
1641 /* Find first non-white byte */
1643 while (apr_isspace(*ptr))
1648 /* find token end, skipping over quoted strings.
1649 * (comments are already gone).
1652 while (*ptr && (accept_white || !apr_isspace(*ptr))
1653 && *ptr != ';' && *ptr != ',') {
1660 token = apr_pstrmemdup(p, tok_start, ptr - tok_start);
1662 /* Advance accept_line pointer to the next non-white byte */
1664 while (apr_isspace(*ptr))
1672 /* find http tokens, see the definition of token from RFC2068 */
1673 AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
1675 const unsigned char *start_token;
1676 const unsigned char *s;
1681 s = (const unsigned char *)line;
1683 /* find start of token, skip all stop characters */
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_status_t) ap_str2_alnum(const char *src, char *dest) {
2680 for ( ; *src; src++, dest++)
2682 if (!apr_isprint(*src))
2684 else if (!apr_isalnum(*src))
2694 AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
2697 char *new = apr_palloc(p, strlen(src)+1);
2701 return ap_str2_alnum(src, new);
2705 * Read the body and parse any form found, which must be of the
2706 * type application/x-www-form-urlencoded.
2708 * Name/value pairs are returned in an array, with the names as
2709 * strings with a maximum length of HUGE_STRING_LEN, and the
2710 * values as bucket brigades. This allows values to be arbitrarily
2713 * All url-encoding is removed from both the names and the values
2714 * on the fly. The names are interpreted as strings, while the
2715 * values are interpreted as blocks of binary data, that may
2716 * contain the 0 character.
2718 * In order to ensure that resource limits are not exceeded, a
2719 * maximum size must be provided. If the sum of the lengths of
2720 * the names and the values exceed this size, this function
2721 * will return HTTP_REQUEST_ENTITY_TOO_LARGE.
2723 * An optional number of parameters can be provided, if the number
2724 * of parameters provided exceeds this amount, this function will
2725 * return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
2726 * no limit is imposed, and the number of parameters is in turn
2727 * constrained by the size parameter above.
2729 * This function honours any kept_body configuration, and the
2730 * original raw request body will be saved to the kept_body brigade
2731 * if so configured, just as ap_discard_request_body does.
2733 * NOTE: File upload is not yet supported, but can be without change
2734 * to the function call.
2737 /* form parsing stuff */
2748 AP_DECLARE(int) ap_parse_form_data(request_rec *r, ap_filter_t *f,
2749 apr_array_header_t **ptr,
2750 apr_size_t num, apr_size_t usize)
2752 apr_bucket_brigade *bb = NULL;
2754 char buffer[HUGE_STRING_LEN + 1];
2756 apr_size_t offset = 0;
2758 ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
2759 ap_form_pair_t *pair = NULL;
2760 apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
2761 char escaped_char[2] = { 0 };
2765 /* sanity check - we only support forms for now */
2766 ct = apr_table_get(r->headers_in, "Content-Type");
2767 if (!ct || ap_cstr_casecmpn("application/x-www-form-urlencoded", ct, 33)) {
2768 return ap_discard_request_body(r);
2771 if (usize > APR_SIZE_MAX >> 1)
2772 size = APR_SIZE_MAX >> 1;
2777 f = r->input_filters;
2780 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2782 apr_bucket *bucket = NULL, *last = NULL;
2784 int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
2785 APR_BLOCK_READ, HUGE_STRING_LEN);
2786 if (rv != APR_SUCCESS) {
2787 apr_brigade_destroy(bb);
2788 return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
2791 for (bucket = APR_BRIGADE_FIRST(bb);
2792 bucket != APR_BRIGADE_SENTINEL(bb);
2793 last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
2795 apr_size_t len, slide;
2798 apr_bucket_delete(last);
2800 if (APR_BUCKET_IS_EOS(bucket)) {
2804 if (bucket->length == 0) {
2808 rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
2809 if (rv != APR_SUCCESS) {
2810 apr_brigade_destroy(bb);
2811 return HTTP_BAD_REQUEST;
2815 while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
2820 else if ('&' == c) {
2824 percent = FORM_PERCENTA;
2827 if (FORM_PERCENTA == percent) {
2828 escaped_char[0] = c;
2829 percent = FORM_PERCENTB;
2832 if (FORM_PERCENTB == percent) {
2833 escaped_char[1] = c;
2834 c = x2c(escaped_char);
2835 percent = FORM_NORMAL;
2840 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2841 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2842 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2850 if (offset < HUGE_STRING_LEN) {
2854 pair = (ap_form_pair_t *) apr_array_push(pairs);
2855 pair->name = apr_pstrdup(r->pool, buffer);
2856 pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
2860 buffer[offset++] = c;
2869 if (offset >= HUGE_STRING_LEN) {
2870 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2871 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2872 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2875 buffer[offset++] = c;
2885 apr_brigade_cleanup(bb);
2886 } while (!seen_eos);
2888 if (FORM_ABORT == state || size < 0 || num == 0) {
2889 return HTTP_REQUEST_ENTITY_TOO_LARGE;
2891 else if (FORM_VALUE == state && pair && offset > 0) {
2892 const char *tmp = apr_pmemdup(r->pool, buffer, offset);
2893 apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
2894 APR_BRIGADE_INSERT_TAIL(pair->value, b);
2901 #define VARBUF_SMALL_SIZE 2048
2902 #define VARBUF_MAX_SIZE (APR_SIZE_MAX - 1 - \
2903 APR_ALIGN_DEFAULT(sizeof(struct ap_varbuf_info)))
2905 struct ap_varbuf_info {
2906 struct apr_memnode_t *node;
2907 apr_allocator_t *allocator;
2910 static apr_status_t varbuf_cleanup(void *info_)
2912 struct ap_varbuf_info *info = info_;
2913 info->node->next = NULL;
2914 apr_allocator_free(info->allocator, info->node);
2918 const char nul = '\0';
2919 static char * const varbuf_empty = (char *)&nul;
2921 AP_DECLARE(void) ap_varbuf_init(apr_pool_t *p, struct ap_varbuf *vb,
2922 apr_size_t init_size)
2924 vb->buf = varbuf_empty;
2926 vb->strlen = AP_VARBUF_UNKNOWN;
2930 ap_varbuf_grow(vb, init_size);
2933 AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
2935 apr_memnode_t *new_node = NULL;
2936 apr_allocator_t *allocator;
2937 struct ap_varbuf_info *new_info;
2940 AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN || vb->avail >= vb->strlen);
2942 if (new_len <= vb->avail)
2945 if (new_len < 2 * vb->avail && vb->avail < VARBUF_MAX_SIZE/2) {
2946 /* at least double the size, to avoid repeated reallocations */
2947 new_len = 2 * vb->avail;
2949 else if (new_len > VARBUF_MAX_SIZE) {
2950 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2951 ap_assert(abort_fn != NULL);
2952 abort_fn(APR_ENOMEM);
2956 new_len++; /* add space for trailing \0 */
2957 if (new_len <= VARBUF_SMALL_SIZE) {
2958 new_len = APR_ALIGN_DEFAULT(new_len);
2959 new = apr_palloc(vb->pool, new_len);
2960 if (vb->avail && vb->strlen != 0) {
2961 AP_DEBUG_ASSERT(vb->buf != NULL);
2962 AP_DEBUG_ASSERT(vb->buf != varbuf_empty);
2963 if (new == vb->buf + vb->avail + 1) {
2964 /* We are lucky: the new memory lies directly after our old
2965 * buffer, we can now use both.
2967 vb->avail += new_len;
2971 /* copy up to vb->strlen + 1 bytes */
2972 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
2973 vb->avail + 1 : vb->strlen + 1);
2979 vb->avail = new_len - 1;
2984 /* The required block is rather larger. Use allocator directly so that
2985 * the memory can be freed independently from the pool. */
2986 allocator = apr_pool_allocator_get(vb->pool);
2987 if (new_len <= VARBUF_MAX_SIZE)
2988 new_node = apr_allocator_alloc(allocator,
2989 new_len + APR_ALIGN_DEFAULT(sizeof(*new_info)));
2991 apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
2992 ap_assert(abort_fn != NULL);
2993 abort_fn(APR_ENOMEM);
2996 new_info = (struct ap_varbuf_info *)new_node->first_avail;
2997 new_node->first_avail += APR_ALIGN_DEFAULT(sizeof(*new_info));
2998 new_info->node = new_node;
2999 new_info->allocator = allocator;
3000 new = new_node->first_avail;
3001 AP_DEBUG_ASSERT(new_node->endp - new_node->first_avail >= new_len);
3002 new_len = new_node->endp - new_node->first_avail;
3004 if (vb->avail && vb->strlen != 0)
3005 memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
3006 vb->avail + 1 : vb->strlen + 1);
3010 apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
3011 apr_pool_cleanup_register(vb->pool, new_info, varbuf_cleanup,
3012 apr_pool_cleanup_null);
3013 vb->info = new_info;
3015 vb->avail = new_len - 1;
3018 AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
3024 ap_varbuf_grow(vb, len);
3025 memcpy(vb->buf, str, len);
3026 vb->buf[len] = '\0';
3030 if (vb->strlen == AP_VARBUF_UNKNOWN)
3031 vb->strlen = strlen(vb->buf);
3032 ap_varbuf_grow(vb, vb->strlen + len);
3033 memcpy(vb->buf + vb->strlen, str, len);
3035 vb->buf[vb->strlen] = '\0';
3038 AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb)
3041 apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
3047 AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *buf,
3048 const char *prepend, apr_size_t prepend_len,
3049 const char *append, apr_size_t append_len,
3050 apr_size_t *new_len)
3053 struct iovec vec[3];
3056 vec[i].iov_base = (void *)prepend;
3057 vec[i].iov_len = prepend_len;
3060 if (buf->avail && buf->strlen) {
3061 if (buf->strlen == AP_VARBUF_UNKNOWN)
3062 buf->strlen = strlen(buf->buf);
3063 vec[i].iov_base = (void *)buf->buf;
3064 vec[i].iov_len = buf->strlen;
3068 vec[i].iov_base = (void *)append;
3069 vec[i].iov_len = append_len;
3073 return apr_pstrcatv(p, vec, i, new_len);
3080 AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb,
3084 ap_regmatch_t pmatch[],
3087 return regsub_core(NULL, NULL, vb, input, source, nmatch, pmatch, maxlen);
3090 static const char * const oom_message = "[crit] Memory allocation failed, "
3091 "aborting process." APR_EOL_STR;
3093 AP_DECLARE(void) ap_abort_on_oom()
3095 int written, count = strlen(oom_message);
3096 const char *buf = oom_message;
3098 written = write(STDERR_FILENO, buf, count);
3099 if (written == count)
3105 } while (written >= 0 || errno == EINTR);
3109 AP_DECLARE(void *) ap_malloc(size_t size)
3111 void *p = malloc(size);
3112 if (p == NULL && size != 0)
3117 AP_DECLARE(void *) ap_calloc(size_t nelem, size_t size)
3119 void *p = calloc(nelem, size);
3120 if (p == NULL && nelem != 0 && size != 0)
3125 AP_DECLARE(void *) ap_realloc(void *ptr, size_t size)
3127 void *p = realloc(ptr, size);
3128 if (p == NULL && size != 0)
3133 AP_DECLARE(void) ap_get_sload(ap_sload_t *ld)
3135 int i, j, server_limit, thread_limit;
3139 ap_generation_t mpm_generation;
3141 /* preload errored fields, we overwrite */
3144 ld->bytes_served = 0;
3145 ld->access_count = 0;
3147 ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
3148 ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
3149 ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
3151 for (i = 0; i < server_limit; i++) {
3153 ps = ap_get_scoreboard_process(i);
3155 for (j = 0; j < thread_limit; j++) {
3157 worker_score *ws = NULL;
3158 ws = &ap_scoreboard_image->servers[i][j];
3161 if (!ps->quiescing && ps->pid) {
3162 if (res == SERVER_READY && ps->generation == mpm_generation) {
3165 else if (res != SERVER_DEAD &&
3166 res != SERVER_STARTING && res != SERVER_IDLE_KILL &&
3167 ps->generation == mpm_generation) {
3172 if (ap_extended_status && !ps->quiescing && ps->pid) {
3173 if (ws->access_count != 0
3174 || (res != SERVER_READY && res != SERVER_DEAD)) {
3175 ld->access_count += ws->access_count;
3176 ld->bytes_served += ws->bytes_served;
3181 total = busy + ready;
3183 ld->idle = ready * 100 / total;
3184 ld->busy = busy * 100 / total;
3188 AP_DECLARE(void) ap_get_loadavg(ap_loadavg_t *ld)
3190 /* preload errored fields, we overwrite */
3192 ld->loadavg5 = -1.0;
3193 ld->loadavg15 = -1.0;
3200 num = getloadavg(la, 3);
3202 ld->loadavg = (float)la[0];
3205 ld->loadavg5 = (float)la[1];
3208 ld->loadavg15 = (float)la[2];
3214 static const char * const pw_cache_note_name = "conn_cache_note";
3216 /* varbuf contains concatenated password and hash */
3217 struct ap_varbuf vb;
3219 apr_status_t result;
3222 AP_DECLARE(apr_status_t) ap_password_validate(request_rec *r,
3223 const char *username,
3227 struct pw_cache *cache;
3230 cache = (struct pw_cache *)apr_table_get(r->connection->notes, pw_cache_note_name);
3231 if (cache != NULL) {
3232 if (strncmp(passwd, cache->vb.buf, cache->pwlen) == 0
3233 && strcmp(hash, cache->vb.buf + cache->pwlen) == 0) {
3234 return cache->result;
3236 /* make ap_varbuf_grow below not copy the old data */
3237 cache->vb.strlen = 0;
3240 cache = apr_palloc(r->connection->pool, sizeof(struct pw_cache));
3241 ap_varbuf_init(r->connection->pool, &cache->vb, 0);
3242 apr_table_setn(r->connection->notes, pw_cache_note_name, (void *)cache);
3244 cache->pwlen = strlen(passwd);
3245 hashlen = strlen(hash);
3246 ap_varbuf_grow(&cache->vb, cache->pwlen + hashlen + 1);
3247 memcpy(cache->vb.buf, passwd, cache->pwlen);
3248 memcpy(cache->vb.buf + cache->pwlen, hash, hashlen + 1);
3249 cache->result = apr_password_validate(passwd, hash);
3250 return cache->result;
3253 AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p,
3255 const char * const * argv)
3257 char buf[MAX_STRING_LEN];
3258 apr_procattr_t *procattr;
3261 apr_size_t nbytes = 1;
3265 if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
3267 if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
3268 APR_FULL_BLOCK) != APR_SUCCESS)
3270 if (apr_procattr_dir_set(procattr,
3271 ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
3273 if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
3275 proc = apr_pcalloc(p, sizeof(apr_proc_t));
3276 if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
3282 /* XXX: we are reading 1 byte at a time here */
3283 for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
3284 && nbytes == 1 && (k < MAX_STRING_LEN-1) ; ) {
3285 if (c == '\n' || c == '\r')
3292 return apr_pstrndup(p, buf, k);
3295 AP_DECLARE(int) ap_array_str_index(const apr_array_header_t *array,
3302 for (i = start; i < array->nelts; i++) {
3303 const char *p = APR_ARRAY_IDX(array, i, const char *);
3304 if (!strcmp(p, s)) {
3313 AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array,
3316 return (ap_array_str_index(array, s, 0) >= 0);
3319 #if !APR_CHARSET_EBCDIC
3321 * Our own known-fast translation table for casecmp by character.
3322 * Only ASCII alpha characters 41-5A are folded to 61-7A, other
3323 * octets (such as extended latin alphabetics) are never case-folded.
3324 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3326 static const short ucharmap[] = {
3327 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
3328 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
3329 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3330 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3331 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3332 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3333 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3334 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3335 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3336 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3337 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3338 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3339 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3340 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3341 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3342 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3343 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3344 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3345 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3346 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3347 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3348 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3349 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3350 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3351 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3352 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3353 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3354 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3355 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3356 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3357 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3358 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3360 #else /* APR_CHARSET_EBCDIC */
3362 * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison,
3363 * provides unique identity of every char value (strict ISO-646
3364 * conformance, arbitrary election of an ISO-8859-1 ordering, and
3365 * very arbitrary control code assignments into C1 to achieve
3366 * identity and a reversible mapping of code points),
3367 * then folding the equivalences of ASCII 41-5A into 61-7A,
3368 * presenting comparison results in a somewhat ISO/IEC 10646
3369 * (ASCII-like) order, depending on the EBCDIC code page in use.
3371 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
3373 static const short ucharmap[] = {
3374 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
3375 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
3376 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
3377 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
3378 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
3379 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
3380 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
3381 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
3382 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,
3383 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
3384 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,
3385 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
3386 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,
3387 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
3388 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,
3389 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
3390 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3391 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,
3392 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3393 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,
3394 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3395 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE,
3396 0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,
3397 0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7,
3398 0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3399 0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,
3400 0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
3401 0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,
3402 0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
3403 0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,
3404 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3405 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F
3409 AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2)
3411 const unsigned char *str1 = (const unsigned char *)s1;
3412 const unsigned char *str2 = (const unsigned char *)s2;
3415 const int c1 = (int)(*str1);
3416 const int c2 = (int)(*str2);
3417 const int cmp = ucharmap[c1] - ucharmap[c2];
3418 /* Not necessary to test for !c2, this is caught by cmp */
3426 AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
3428 const unsigned char *str1 = (const unsigned char *)s1;
3429 const unsigned char *str2 = (const unsigned char *)s2;
3432 const int c1 = (int)(*str1);
3433 const int c2 = (int)(*str2);
3434 const int cmp = ucharmap[c1] - ucharmap[c2];
3435 /* Not necessary to test for !c2, this is caught by cmp */