diff options
Diffstat (limited to 'server/util.c')
-rw-r--r-- | server/util.c | 1907 |
1 files changed, 0 insertions, 1907 deletions
diff --git a/server/util.c b/server/util.c deleted file mode 100644 index 7ff05caa6e..0000000000 --- a/server/util.c +++ /dev/null @@ -1,1907 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. All rights - * reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * util.c: string utility things - * - * 3/21/93 Rob McCool - * 1995-96 Many changes by the Apache Software Foundation - * - */ - -/* Debugging aid: - * #define DEBUG to trace all cfg_open*()/cfg_closefile() calls - * #define DEBUG_CFG_LINES to trace every line read from the config files - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_lib.h" - -#define APR_WANT_STDIO -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#if APR_HAVE_NETDB_H -#include <netdb.h> /* for gethostbyname() */ -#endif - -#define CORE_PRIVATE - -#include "ap_config.h" -#include "apr_base64.h" -#include "httpd.h" -#include "http_main.h" -#include "http_log.h" -#include "http_protocol.h" -#include "http_config.h" -#include "util_ebcdic.h" - -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif -#ifdef HAVE_GRP_H -#include <grp.h> -#endif - -/* A bunch of functions in util.c scan strings looking for certain characters. - * To make that more efficient we encode a lookup table. The test_char_table - * is generated automatically by gen_test_char.c. - */ -#include "test_char.h" - -/* we assume the folks using this ensure 0 <= c < 256... which means - * you need a cast to (unsigned char) first, you can't just plug a - * char in here and get it to work, because if char is signed then it - * will first be sign extended. - */ -#define TEST_CHAR(c, f) (test_char_table[(unsigned)(c)] & (f)) - -/* - * Examine a field value (such as a media-/content-type) string and return - * it sans any parameters; e.g., strip off any ';charset=foo' and the like. - */ -AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype) -{ - const char *semi; - - if (intype == NULL) return NULL; - - semi = ap_strchr_c(intype, ';'); - if (semi == NULL) { - return apr_pstrdup(p, intype); - } - else { - while ((semi > intype) && apr_isspace(semi[-1])) { - semi--; - } - return apr_pstrndup(p, intype, semi - intype); - } -} - -AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt, int gmt) -{ - apr_size_t retcode; - char ts[MAX_STRING_LEN]; - char tf[MAX_STRING_LEN]; - apr_exploded_time_t xt; - - if (gmt) { - const char *f; - char *strp; - - apr_explode_gmt(&xt, t); - /* Convert %Z to "GMT" and %z to "+0000"; - * on hosts that do not have a time zone string in struct tm, - * strftime must assume its argument is local time. - */ - for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f) - ; f++, strp++) { - if (*f != '%') continue; - switch (f[1]) { - case '%': - *++strp = *++f; - break; - case 'Z': - *strp++ = 'G'; - *strp++ = 'M'; - *strp = 'T'; - f++; - break; - case 'z': /* common extension */ - *strp++ = '+'; - *strp++ = '0'; - *strp++ = '0'; - *strp++ = '0'; - *strp = '0'; - f++; - break; - } - } - *strp = '\0'; - fmt = tf; - } - else { - apr_explode_localtime(&xt, t); - } - - /* check return code? */ - apr_strftime(ts, &retcode, MAX_STRING_LEN, fmt, &xt); - ts[MAX_STRING_LEN - 1] = '\0'; - return apr_pstrdup(p, ts); -} - -/* Roy owes Rob beer. */ -/* Rob owes Roy dinner. */ - -/* These legacy comments would make a lot more sense if Roy hadn't - * replaced the old later_than() routine with util_date.c. - * - * Well, okay, they still wouldn't make any sense. - */ - -/* Match = 0, NoMatch = 1, Abort = -1 - * Based loosely on sections of wildmat.c by Rich Salz - * Hmmm... shouldn't this really go component by component? - */ -AP_DECLARE(int) ap_strcmp_match(const char *str, const char *exp) -{ - int x, y; - - for (x = 0, y = 0; exp[y]; ++y, ++x) { - if ((!str[x]) && (exp[y] != '*')) - return -1; - if (exp[y] == '*') { - while (exp[++y] == '*'); - if (!exp[y]) - return 0; - while (str[x]) { - int ret; - if ((ret = ap_strcmp_match(&str[x++], &exp[y])) != 1) - return ret; - } - return -1; - } - else if ((exp[y] != '?') && (str[x] != exp[y])) - return 1; - } - return (str[x] != '\0'); -} - -AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *exp) -{ - int x, y; - - for (x = 0, y = 0; exp[y]; ++y, ++x) { - if ((!str[x]) && (exp[y] != '*')) - return -1; - if (exp[y] == '*') { - while (exp[++y] == '*'); - if (!exp[y]) - return 0; - while (str[x]) { - int ret; - if ((ret = ap_strcasecmp_match(&str[x++], &exp[y])) != 1) - return ret; - } - return -1; - } - else if ((exp[y] != '?') && (apr_tolower(str[x]) != apr_tolower(exp[y]))) - return 1; - } - return (str[x] != '\0'); -} - -AP_DECLARE(int) ap_is_matchexp(const char *str) -{ - register int x; - - for (x = 0; str[x]; x++) - if ((str[x] == '*') || (str[x] == '?')) - return 1; - return 0; -} - -/* - * Here's a pool-based interface to POSIX regex's regcomp(). - * Note that we return regex_t instead of being passed one. - * The reason is that if you use an already-used regex_t structure, - * the memory that you've already allocated gets forgotten, and - * regfree() doesn't clear it. So we don't allow it. - */ - -static apr_status_t regex_cleanup(void *preg) -{ - regfree((regex_t *) preg); - return APR_SUCCESS; -} - -AP_DECLARE(regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern, - int cflags) -{ - regex_t *preg = apr_palloc(p, sizeof(regex_t)); - - if (regcomp(preg, pattern, cflags)) { - return NULL; - } - - apr_pool_cleanup_register(p, (void *) preg, regex_cleanup, regex_cleanup); - - return preg; -} - -AP_DECLARE(void) ap_pregfree(apr_pool_t *p, regex_t * reg) -{ - regfree(reg); - apr_pool_cleanup_kill(p, (void *) reg, regex_cleanup); -} - -/* - * Similar to standard strstr() but we ignore case in this version. - * Based on the strstr() implementation further below. - */ -AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2) -{ - char *p1, *p2; - if (*s2 == '\0') { - /* an empty s2 */ - return((char *)s1); - } - while(1) { - for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++); - if (*s1 == '\0') return(NULL); - /* found first character of s2, see if the rest matches */ - p1 = (char *)s1; - p2 = (char *)s2; - while (apr_tolower(*++p1) == apr_tolower(*++p2)) { - if (*p1 == '\0') { - /* both strings ended together */ - return((char *)s1); - } - } - if (*p2 == '\0') { - /* second string ended, a match */ - break; - } - /* didn't find a match here, try starting at next character in s1 */ - s1++; - } - return((char *)s1); -} - -/* - * Returns an offsetted pointer in bigstring immediately after - * prefix. Returns bigstring if bigstring doesn't start with - * prefix or if prefix is longer than bigstring while still matching. - * NOTE: pointer returned is relative to bigstring, so we - * can use standard pointer comparisons in the calling function - * (eg: test if ap_stripprefix(a,b) == a) - */ -AP_DECLARE(const char *) ap_stripprefix(const char *bigstring, - const char *prefix) -{ - const char *p1; - - if (*prefix == '\0') - return bigstring; - - p1 = bigstring; - while (*p1 && *prefix) { - if (*p1++ != *prefix++) - return bigstring; - } - if (*prefix == '\0') - return p1; - - /* hit the end of bigstring! */ - return bigstring; -} - -/* - * Apache stub function for the regex libraries regexec() to make sure the - * whole regex(3) API is available through the Apache (exported) namespace. - * This is especially important for the DSO situations of modules. - * DO NOT MAKE A MACRO OUT OF THIS FUNCTION! - */ -AP_DECLARE(int) ap_regexec(regex_t *preg, const char *string, - size_t nmatch, regmatch_t pmatch[], int eflags) -{ - return regexec(preg, string, nmatch, pmatch, eflags); -} - -AP_DECLARE(size_t) ap_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) -{ - return regerror(errcode, preg, errbuf, errbuf_size); -} - - -/* This function substitutes for $0-$9, filling in regular expression - * submatches. Pass it the same nmatch and pmatch arguments that you - * passed ap_regexec(). pmatch should not be greater than the maximum number - * of subexpressions - i.e. one more than the re_nsub member of regex_t. - * - * input should be the string with the $-expressions, source should be the - * string that was matched against. - * - * It returns the substituted string, or NULL on error. - * - * Parts of this code are based on Henry Spencer's regsub(), from his - * AT&T V8 regexp package. - */ - -AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input, const char *source, - size_t nmatch, regmatch_t pmatch[]) -{ - const char *src = input; - char *dest, *dst; - char c; - size_t no; - int len; - - if (!source) - return NULL; - if (!nmatch) - return apr_pstrdup(p, src); - - /* First pass, find the size */ - - len = 0; - - while ((c = *src++) != '\0') { - if (c == '&') - no = 0; - else if (c == '$' && apr_isdigit(*src)) - no = *src++ - '0'; - else - no = 10; - - if (no > 9) { /* Ordinary character. */ - if (c == '\\' && (*src == '$' || *src == '&')) - c = *src++; - len++; - } - else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) { - len += pmatch[no].rm_eo - pmatch[no].rm_so; - } - - } - - dest = dst = apr_pcalloc(p, len + 1); - - /* Now actually fill in the string */ - - src = input; - - while ((c = *src++) != '\0') { - if (c == '&') - no = 0; - else if (c == '$' && apr_isdigit(*src)) - no = *src++ - '0'; - else - no = 10; - - if (no > 9) { /* Ordinary character. */ - if (c == '\\' && (*src == '$' || *src == '&')) - c = *src++; - *dst++ = c; - } - else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) { - len = pmatch[no].rm_eo - pmatch[no].rm_so; - memcpy(dst, source + pmatch[no].rm_so, len); - dst += len; - } - - } - *dst = '\0'; - - return dest; -} - -/* - * Parse .. so we don't compromise security - */ -AP_DECLARE(void) ap_getparents(char *name) -{ - int l, w; - - /* Four paseses, as per RFC 1808 */ - /* a) remove ./ path segments */ - - for (l = 0, w = 0; name[l] != '\0';) { - if (name[l] == '.' && name[l + 1] == '/' && (l == 0 || name[l - 1] == '/')) - l += 2; - else - name[w++] = name[l++]; - } - - /* b) remove trailing . path, segment */ - if (w == 1 && name[0] == '.') - w--; - else if (w > 1 && name[w - 1] == '.' && name[w - 2] == '/') - w--; - name[w] = '\0'; - - /* c) remove all xx/../ segments. (including leading ../ and /../) */ - l = 0; - - while (name[l] != '\0') { - if (name[l] == '.' && name[l + 1] == '.' && name[l + 2] == '/' && - (l == 0 || name[l - 1] == '/')) { - register int m = l + 3, n; - - l = l - 2; - if (l >= 0) { - while (l >= 0 && name[l] != '/') - l--; - l++; - } - else - l = 0; - n = l; - while ((name[n] = name[m])) - (++n, ++m); - } - else - ++l; - } - - /* d) remove trailing xx/.. segment. */ - if (l == 2 && name[0] == '.' && name[1] == '.') - name[0] = '\0'; - else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.' && name[l - 3] == '/') { - l = l - 4; - if (l >= 0) { - while (l >= 0 && name[l] != '/') - l--; - l++; - } - else - l = 0; - name[l] = '\0'; - } -} - -AP_DECLARE(void) ap_no2slash(char *name) -{ - char *d, *s; - - s = d = name; - -#ifdef HAVE_UNC_PATHS - /* Check for UNC names. Leave leading two slashes. */ - if (s[0] == '/' && s[1] == '/') - *d++ = *s++; -#endif - - while (*s) { - if ((*d++ = *s) == '/') { - do { - ++s; - } while (*s == '/'); - } - else { - ++s; - } - } - *d = '\0'; -} - - -/* - * copy at most n leading directories of s into d - * d should be at least as large as s plus 1 extra byte - * assumes n > 0 - * the return value is the ever useful pointer to the trailing \0 of d - * - * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments, - * so that if n == 0, "/" is returned in d with n == 1 - * and s == "e:/test.html", "e:/" is returned in d - * *** See also directory_walk in modules/http/http_request.c - - * examples: - * /a/b, 0 ==> / (true for all platforms) - * /a/b, 1 ==> / - * /a/b, 2 ==> /a/ - * /a/b, 3 ==> /a/b/ - * /a/b, 4 ==> /a/b/ - * - * c:/a/b 0 ==> / - * c:/a/b 1 ==> c:/ - * c:/a/b 2 ==> c:/a/ - * c:/a/b 3 ==> c:/a/b - * c:/a/b 4 ==> c:/a/b - */ -AP_DECLARE(char *) ap_make_dirstr_prefix(char *d, const char *s, int n) -{ - if (n < 1) { - *d = '/'; - *++d = '\0'; - return (d); - } - - for (;;) { - if (*s == '\0' || (*s == '/' && (--n) == 0)) { - *d = '/'; - break; - } - *d++ = *s++; - } - *++d = 0; - return (d); -} - - -/* - * return the parent directory name including trailing / of the file s - */ -AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s) -{ - const char *last_slash = ap_strrchr_c(s, '/'); - char *d; - int l; - - if (last_slash == NULL) { - /* XXX: well this is really broken if this happens */ - return (apr_pstrdup(p, "/")); - } - l = (last_slash - s) + 1; - d = apr_palloc(p, l + 1); - memcpy(d, s, l); - d[l] = 0; - return (d); -} - - -AP_DECLARE(int) ap_count_dirs(const char *path) -{ - register int x, n; - - for (x = 0, n = 0; path[x]; x++) - if (path[x] == '/') - n++; - return n; -} - -AP_DECLARE(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop) -{ - return ap_getword(atrans, (const char **) line, stop); -} - -AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop) -{ - const char *pos = ap_strchr_c(*line, stop); - char *res; - - if (!pos) { - res = apr_pstrdup(atrans, *line); - *line += strlen(*line); - return res; - } - - res = apr_pstrndup(atrans, *line, pos - *line); - - while (*pos == stop) { - ++pos; - } - - *line = pos; - - return res; -} - -AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line) -{ - return ap_getword_white(atrans, (const char **) line); -} - -AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line) -{ - int pos = -1, x; - char *res; - - for (x = 0; (*line)[x]; x++) { - if (apr_isspace((*line)[x])) { - pos = x; - break; - } - } - - if (pos == -1) { - res = apr_pstrdup(atrans, *line); - *line += strlen(*line); - return res; - } - - res = apr_palloc(atrans, pos + 1); - apr_cpystrn(res, *line, pos + 1); - - while (apr_isspace((*line)[pos])) - ++pos; - - *line += pos; - - return res; -} - -AP_DECLARE(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line, char stop) -{ - return ap_getword_nulls(atrans, (const char **) line, stop); -} - -AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line, char stop) -{ - const char *pos = ap_strchr_c(*line, stop); - char *res; - - if (!pos) { - res = apr_pstrdup(atrans, *line); - *line += strlen(*line); - return res; - } - - res = apr_pstrndup(atrans, *line, pos - *line); - - ++pos; - - *line = pos; - - return res; -} - -/* Get a word, (new) config-file style --- quoted strings and backslashes - * all honored - */ - -static char *substring_conf(apr_pool_t *p, const char *start, int len, char quote) -{ - char *result = apr_palloc(p, len + 2); - char *resp = result; - int i; - - for (i = 0; i < len; ++i) { - if (start[i] == '\\' && (start[i + 1] == '\\' - || (quote && start[i + 1] == quote))) - *resp++ = start[++i]; - else - *resp++ = start[i]; - } - - *resp++ = '\0'; -#if RESOLVE_ENV_PER_TOKEN - return ap_resolve_env(p,result); -#else - return result; -#endif -} - -AP_DECLARE(char *) ap_getword_conf_nc(apr_pool_t *p, char **line) -{ - return ap_getword_conf(p, (const char **) line); -} - -AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line) -{ - const char *str = *line, *strend; - char *res; - char quote; - - while (*str && apr_isspace(*str)) - ++str; - - if (!*str) { - *line = str; - return ""; - } - - if ((quote = *str) == '"' || quote == '\'') { - strend = str + 1; - while (*strend && *strend != quote) { - if (*strend == '\\' && strend[1] && strend[1] == quote) - strend += 2; - else - ++strend; - } - res = substring_conf(p, str + 1, strend - str - 1, quote); - - if (*strend == quote) - ++strend; - } - else { - strend = str; - while (*strend && !apr_isspace(*strend)) - ++strend; - - res = substring_conf(p, str, strend - str, 0); - } - - while (*strend && apr_isspace(*strend)) - ++strend; - *line = strend; - return res; -} - -/* Check a string for any ${ENV} environment variable - * construct and replace each them by the value of - * that environment variable, if it exists. If the - * environment value does not exist, leave the ${ENV} - * construct alone; it means something else. - */ -AP_DECLARE(const char *) ap_resolve_env(apr_pool_t *p, const char * word) -{ - char tmp[ MAX_STRING_LEN ]; - const char *s, *e; - tmp[0] = '\0'; - - if (!(s=ap_strchr_c(word,'$'))) - return word; - - do { - /* XXX - relies on strncat() to add '\0' - */ - strncat(tmp,word,s - word); - if ((s[1] == '{') && (e=ap_strchr_c(s,'}'))) { - const char *e2 = e; - word = e + 1; - e = getenv(s+2); - if (e) { - strcat(tmp,e); - } else { - strncat(tmp, s, e2-s); - strcat(tmp,"}"); - } - } else { - /* ignore invalid strings */ - word = s+1; - strcat(tmp,"$"); - }; - } while ((s=ap_strchr_c(word,'$'))); - strcat(tmp,word); - - return apr_pstrdup(p,tmp); -} -AP_DECLARE(int) ap_cfg_closefile(ap_configfile_t *cfp) -{ -#ifdef DEBUG - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, - "Done with config file %s", cfp->name); -#endif - return (cfp->close == NULL) ? 0 : cfp->close(cfp->param); -} - -static apr_status_t cfg_close(void *param) -{ - apr_file_t *cfp = (apr_file_t *) param; - return (apr_file_close(cfp)); -} - -static int cfg_getch(void *param) -{ - char ch; - apr_file_t *cfp = (apr_file_t *) param; - if (apr_file_getc(&ch, cfp) == APR_SUCCESS) - return ch; - return (int)EOF; -} - -static void *cfg_getstr(void *buf, size_t bufsiz, void *param) -{ - apr_file_t *cfp = (apr_file_t *) param; - apr_status_t rv; - rv = apr_file_gets(buf, bufsiz, cfp); - if (rv == APR_SUCCESS || (rv == APR_EOF && strcmp(buf, ""))) - return buf; - return NULL; -} - -/* Open a ap_configfile_t as FILE, return open ap_configfile_t struct pointer */ -AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg, apr_pool_t *p, const char *name) -{ - ap_configfile_t *new_cfg; - apr_file_t *file = NULL; - apr_finfo_t finfo; - apr_status_t status; -#ifdef DEBUG - char buf[120]; -#endif - - if (name == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL, - "Internal error: pcfg_openfile() called with NULL filename"); - return APR_EBADF; - } - - /* ### We no longer need the test ap_os_is_filename_valid() here - * The directory was already walked on a segment by segment basis, - * so we should never be called with a bad path element, and device - * names as access file names never posed as security threats, since - * it was the admin's choice to assign the .htaccess file's name. - */ - - status = apr_file_open(&file, name, APR_READ | APR_BUFFERED, APR_OS_DEFAULT, p); -#ifdef DEBUG - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, NULL, - "Opening config file %s (%s)", - name, (status != APR_SUCCESS) ? - apr_strerror(status, buf, sizeof(buf)) : "successful"); -#endif - if (status != APR_SUCCESS) - return status; - - status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file); - if (status != APR_SUCCESS) - return status; - - if (finfo.filetype != APR_REG && -#if defined(WIN32) || defined(OS2) - !(strcasecmp(name, "nul") == 0 || - (strlen(name) >= 4 && - strcasecmp(name + strlen(name) - 4, "/nul") == 0))) { -#else - strcmp(name, "/dev/null") != 0) { -#endif /* WIN32 || OS2 */ - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL, - "Access to file %s denied by server: not a regular file", - name); - apr_file_close(file); - return APR_EBADF; - } - - new_cfg = apr_palloc(p, sizeof(*new_cfg)); - new_cfg->param = file; - new_cfg->name = apr_pstrdup(p, name); - new_cfg->getch = (int (*)(void *)) cfg_getch; - new_cfg->getstr = (void *(*)(void *, size_t, void *)) cfg_getstr; - new_cfg->close = (int (*)(void *)) cfg_close; - new_cfg->line_number = 0; - *ret_cfg = new_cfg; - return APR_SUCCESS; -} - - -/* Allocate a ap_configfile_t handle with user defined functions and params */ -AP_DECLARE(ap_configfile_t *) ap_pcfg_open_custom(apr_pool_t *p, const char *descr, - void *param, - int(*getch)(void *param), - void *(*getstr) (void *buf, size_t bufsiz, void *param), - int(*close_func)(void *param)) -{ - ap_configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg)); -#ifdef DEBUG - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, NULL, "Opening config handler %s", descr); -#endif - new_cfg->param = param; - new_cfg->name = descr; - new_cfg->getch = getch; - new_cfg->getstr = getstr; - new_cfg->close = close_func; - new_cfg->line_number = 0; - return new_cfg; -} - -/* Read one character from a configfile_t */ -AP_DECLARE(int) ap_cfg_getc(ap_configfile_t *cfp) -{ - register int ch = cfp->getch(cfp->param); - if (ch == LF) - ++cfp->line_number; - return ch; -} - -/* Read one line from open ap_configfile_t, strip LF, increase line number */ -/* If custom handler does not define a getstr() function, read char by char */ -AP_DECLARE(int) ap_cfg_getline(char *buf, size_t bufsize, ap_configfile_t *cfp) -{ - /* If a "get string" function is defined, use it */ - if (cfp->getstr != NULL) { - char *src, *dst; - char *cp; - char *cbuf = buf; - size_t cbufsize = bufsize; - - while (1) { - ++cfp->line_number; - if (cfp->getstr(cbuf, cbufsize, cfp->param) == NULL) - return 1; - - /* - * check for line continuation, - * i.e. match [^\\]\\[\r]\n only - */ - cp = cbuf; - while (cp < cbuf+cbufsize && *cp != '\0') - cp++; - if (cp > cbuf && cp[-1] == LF) { - cp--; - if (cp > cbuf && cp[-1] == CR) - cp--; - if (cp > cbuf && cp[-1] == '\\') { - cp--; - if (!(cp > cbuf && cp[-1] == '\\')) { - /* - * line continuation requested - - * then remove backslash and continue - */ - cbufsize -= (cp-cbuf); - cbuf = cp; - continue; - } - else { - /* - * no real continuation because escaped - - * then just remove escape character - */ - for ( ; cp < cbuf+cbufsize && *cp != '\0'; cp++) - cp[0] = cp[1]; - } - } - } - break; - } - - /* - * Leading and trailing white space is eliminated completely - */ - src = buf; - while (apr_isspace(*src)) - ++src; - /* blast trailing whitespace */ - dst = &src[strlen(src)]; - while (--dst >= src && apr_isspace(*dst)) - *dst = '\0'; - /* Zap leading whitespace by shifting */ - if (src != buf) - for (dst = buf; (*dst++ = *src++) != '\0'; ) - ; - -#ifdef DEBUG_CFG_LINES - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, "Read config: %s", buf); -#endif - return 0; - } else { - /* No "get string" function defined; read character by character */ - register int c; - register size_t i = 0; - - buf[0] = '\0'; - /* skip leading whitespace */ - do { - c = cfp->getch(cfp->param); - } while (c == '\t' || c == ' '); - - if (c == EOF) - return 1; - - if(bufsize < 2) { - /* too small, assume caller is crazy */ - return 1; - } - - while (1) { - if ((c == '\t') || (c == ' ')) { - buf[i++] = ' '; - while ((c == '\t') || (c == ' ')) - c = cfp->getch(cfp->param); - } - if (c == CR) { - /* silently ignore CR (_assume_ that a LF follows) */ - c = cfp->getch(cfp->param); - } - if (c == LF) { - /* increase line number and return on LF */ - ++cfp->line_number; - } - if (c == EOF || c == 0x4 || c == LF || i >= (bufsize - 2)) { - /* - * check for line continuation - */ - if (i > 0 && buf[i-1] == '\\') { - i--; - if (!(i > 0 && buf[i-1] == '\\')) { - /* line is continued */ - c = cfp->getch(cfp->param); - continue; - } - /* else nothing needs be done because - * then the backslash is escaped and - * we just strip to a single one - */ - } - /* blast trailing whitespace */ - while (i > 0 && apr_isspace(buf[i - 1])) - --i; - buf[i] = '\0'; -#ifdef DEBUG_CFG_LINES - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, "Read config: %s", buf); -#endif - return 0; - } - buf[i] = c; - ++i; - c = cfp->getch(cfp->param); - } - } -} - -/* Size an HTTP header field list item, as separated by a comma. - * The return value is a pointer to the beginning of the non-empty list item - * within the original string (or NULL if there is none) and the address - * of field is shifted to the next non-comma, non-whitespace character. - * len is the length of the item excluding any beginning whitespace. - */ -AP_DECLARE(const char *) ap_size_list_item(const char **field, int *len) -{ - const unsigned char *ptr = (const unsigned char *)*field; - const unsigned char *token; - int in_qpair, in_qstr, in_com; - - /* Find first non-comma, non-whitespace byte */ - - while (*ptr == ',' || apr_isspace(*ptr)) - ++ptr; - - token = ptr; - - /* Find the end of this item, skipping over dead bits */ - - for (in_qpair = in_qstr = in_com = 0; - *ptr && (in_qpair || in_qstr || in_com || *ptr != ','); - ++ptr) { - - if (in_qpair) { - in_qpair = 0; - } - else { - switch (*ptr) { - case '\\': in_qpair = 1; /* quoted-pair */ - break; - case '"' : if (!in_com) /* quoted string delim */ - in_qstr = !in_qstr; - break; - case '(' : if (!in_qstr) /* comment (may nest) */ - ++in_com; - break; - case ')' : if (in_com) /* end comment */ - --in_com; - break; - default : break; - } - } - } - - if ((*len = (ptr - token)) == 0) { - *field = (const char *)ptr; - return NULL; - } - - /* Advance field pointer to the next non-comma, non-white byte */ - - while (*ptr == ',' || apr_isspace(*ptr)) - ++ptr; - - *field = (const char *)ptr; - return (const char *)token; -} - -/* Retrieve an HTTP header field list item, as separated by a comma, - * while stripping insignificant whitespace and lowercasing anything not in - * a quoted string or comment. The return value is a new string containing - * the converted list item (or NULL if none) and the address pointed to by - * field is shifted to the next non-comma, non-whitespace. - */ -AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field) -{ - const char *tok_start; - const unsigned char *ptr; - unsigned char *pos; - char *token; - int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0; - - /* Find the beginning and maximum length of the list item so that - * we can allocate a buffer for the new string and reset the field. - */ - if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) { - return NULL; - } - token = apr_palloc(p, tok_len + 1); - - /* Scan the token again, but this time copy only the good bytes. - * We skip extra whitespace and any whitespace around a '=', '/', - * or ';' and lowercase normal characters not within a comment, - * quoted-string or quoted-pair. - */ - for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token; - *ptr && (in_qpair || in_qstr || in_com || *ptr != ','); - ++ptr) { - - if (in_qpair) { - in_qpair = 0; - *pos++ = *ptr; - } - else { - switch (*ptr) { - case '\\': in_qpair = 1; - if (addspace == 1) - *pos++ = ' '; - *pos++ = *ptr; - addspace = 0; - break; - case '"' : if (!in_com) - in_qstr = !in_qstr; - if (addspace == 1) - *pos++ = ' '; - *pos++ = *ptr; - addspace = 0; - break; - case '(' : if (!in_qstr) - ++in_com; - if (addspace == 1) - *pos++ = ' '; - *pos++ = *ptr; - addspace = 0; - break; - case ')' : if (in_com) - --in_com; - *pos++ = *ptr; - addspace = 0; - break; - case ' ' : - case '\t': if (addspace) - break; - if (in_com || in_qstr) - *pos++ = *ptr; - else - addspace = 1; - break; - case '=' : - case '/' : - case ';' : if (!(in_com || in_qstr)) - addspace = -1; - *pos++ = *ptr; - break; - default : if (addspace == 1) - *pos++ = ' '; - *pos++ = (in_com || in_qstr) ? *ptr - : apr_tolower(*ptr); - addspace = 0; - break; - } - } - } - *pos = '\0'; - - return token; -} - -/* Find an item in canonical form (lowercase, no extra spaces) within - * an HTTP field value list. Returns 1 if found, 0 if not found. - * This would be much more efficient if we stored header fields as - * an array of list items as they are received instead of a plain string. - */ -AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line, const char *tok) -{ - const unsigned char *pos; - const unsigned char *ptr = (const unsigned char *)line; - int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0; - - if (!line || !tok) - return 0; - - do { /* loop for each item in line's list */ - - /* Find first non-comma, non-whitespace byte */ - - while (*ptr == ',' || apr_isspace(*ptr)) - ++ptr; - - if (*ptr) - good = 1; /* until proven otherwise for this item */ - else - break; /* no items left and nothing good found */ - - /* We skip extra whitespace and any whitespace around a '=', '/', - * or ';' and lowercase normal characters not within a comment, - * quoted-string or quoted-pair. - */ - for (pos = (const unsigned char *)tok; - *ptr && (in_qpair || in_qstr || in_com || *ptr != ','); - ++ptr) { - - if (in_qpair) { - in_qpair = 0; - if (good) - good = (*pos++ == *ptr); - } - else { - switch (*ptr) { - case '\\': in_qpair = 1; - if (addspace == 1) - good = good && (*pos++ == ' '); - good = good && (*pos++ == *ptr); - addspace = 0; - break; - case '"' : if (!in_com) - in_qstr = !in_qstr; - if (addspace == 1) - good = good && (*pos++ == ' '); - good = good && (*pos++ == *ptr); - addspace = 0; - break; - case '(' : if (!in_qstr) - ++in_com; - if (addspace == 1) - good = good && (*pos++ == ' '); - good = good && (*pos++ == *ptr); - addspace = 0; - break; - case ')' : if (in_com) - --in_com; - good = good && (*pos++ == *ptr); - addspace = 0; - break; - case ' ' : - case '\t': if (addspace || !good) - break; - if (in_com || in_qstr) - good = (*pos++ == *ptr); - else - addspace = 1; - break; - case '=' : - case '/' : - case ';' : if (!(in_com || in_qstr)) - addspace = -1; - good = good && (*pos++ == *ptr); - break; - default : if (!good) - break; - if (addspace == 1) - good = (*pos++ == ' '); - if (in_com || in_qstr) - good = good && (*pos++ == *ptr); - else - good = good && (*pos++ == apr_tolower(*ptr)); - addspace = 0; - break; - } - } - } - if (good && *pos) - good = 0; /* not good if only a prefix was matched */ - - } while (*ptr && !good); - - return good; -} - - -/* Retrieve a token, spacing over it and returning a pointer to - * the first non-white byte afterwards. Note that these tokens - * are delimited by semis and commas; and can also be delimited - * by whitespace at the caller's option. - */ - -AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line, int accept_white) -{ - const char *ptr = *accept_line; - const char *tok_start; - char *token; - int tok_len; - - /* Find first non-white byte */ - - while (*ptr && apr_isspace(*ptr)) - ++ptr; - - tok_start = ptr; - - /* find token end, skipping over quoted strings. - * (comments are already gone). - */ - - while (*ptr && (accept_white || !apr_isspace(*ptr)) - && *ptr != ';' && *ptr != ',') { - if (*ptr++ == '"') - while (*ptr) - if (*ptr++ == '"') - break; - } - - tok_len = ptr - tok_start; - token = apr_pstrndup(p, tok_start, tok_len); - - /* Advance accept_line pointer to the next non-white byte */ - - while (*ptr && apr_isspace(*ptr)) - ++ptr; - - *accept_line = ptr; - return token; -} - - -/* find http tokens, see the definition of token from RFC2068 */ -AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok) -{ - const unsigned char *start_token; - const unsigned char *s; - - if (!line) - return 0; - - s = (const unsigned char *)line; - for (;;) { - /* find start of token, skip all stop characters, note NUL - * isn't a token stop, so we don't need to test for it - */ - while (TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) { - ++s; - } - if (!*s) { - return 0; - } - start_token = s; - /* find end of the token */ - while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) { - ++s; - } - if (!strncasecmp((const char *)start_token, (const char *)tok, s - start_token)) { - return 1; - } - if (!*s) { - return 0; - } - } -} - - -AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line, const char *tok) -{ - int llen, tlen, lidx; - - if (!line) - return 0; - - llen = strlen(line); - tlen = strlen(tok); - lidx = llen - tlen; - - if ((lidx < 0) || - ((lidx > 0) && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ','))) - return 0; - - return (strncasecmp(&line[lidx], tok, tlen) == 0); -} - -AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str) -{ - char *cmd; - unsigned char *d; - const unsigned char *s; - - cmd = apr_palloc(p, 2 * strlen(str) + 1); /* Be safe */ - d = (unsigned char *)cmd; - s = (const unsigned char *)str; - for (; *s; ++s) { - -#if defined(OS2) || defined(WIN32) - /* Don't allow '&' in parameters under OS/2. */ - /* This can be used to send commands to the shell. */ - if (*s == '&') { - *d++ = ' '; - continue; - } -#endif - - if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) { - *d++ = '\\'; - } - *d++ = *s; - } - *d = '\0'; - - return cmd; -} - -static char x2c(const char *what) -{ - register char digit; - -#if !APR_CHARSET_EBCDIC - digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); - digit *= 16; - digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); -#else /*APR_CHARSET_EBCDIC*/ - char xstr[5]; - xstr[0]='0'; - xstr[1]='x'; - xstr[2]=what[0]; - xstr[3]=what[1]; - xstr[4]='\0'; - digit = apr_xlate_conv_byte(ap_hdrs_from_ascii, 0xFF & strtol(xstr, NULL, 16)); -#endif /*APR_CHARSET_EBCDIC*/ - return (digit); -} - -/* - * Unescapes a URL. - * Returns 0 on success, non-zero on error - * Failure is due to - * bad % escape returns HTTP_BAD_REQUEST - * - * decoding %00 -> \0 - * decoding %2f -> / (a special character) - * returns HTTP_NOT_FOUND - */ -AP_DECLARE(int) ap_unescape_url(char *url) -{ - register int badesc, badpath; - char *x, *y; - - badesc = 0; - badpath = 0; - /* Initial scan for first '%'. Don't bother writing values before - * seeing a '%' */ - y = strchr(url, '%'); - if (y == NULL) { - return OK; - } - for (x = y; *y; ++x, ++y) { - if (*y != '%') - *x = *y; - else { - if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) { - badesc = 1; - *x = '%'; - } - else { - *x = x2c(y + 1); - y += 2; - if (*x == '/' || *x == '\0') - badpath = 1; - } - } - } - *x = '\0'; - if (badesc) - return HTTP_BAD_REQUEST; - else if (badpath) - return HTTP_NOT_FOUND; - else - return OK; -} - -AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname, - apr_port_t port, const request_rec *r) -{ - if (ap_is_default_port(port, r)) - return apr_pstrdup(p, hostname); - else { - return apr_psprintf(p, "%s:%u", hostname, port); - } -} - -/* c2x takes an unsigned, and expects the caller has guaranteed that - * 0 <= what < 256... which usually means that you have to cast to - * unsigned char first, because (unsigned)(char)(x) first goes through - * signed extension to an int before the unsigned cast. - * - * The reason for this assumption is to assist gcc code generation -- - * the unsigned char -> unsigned extension is already done earlier in - * both uses of this code, so there's no need to waste time doing it - * again. - */ -static const char c2x_table[] = "0123456789abcdef"; - -static APR_INLINE unsigned char *c2x(unsigned what, unsigned char *where) -{ -#if APR_CHARSET_EBCDIC - what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what); -#endif /*APR_CHARSET_EBCDIC*/ - *where++ = '%'; - *where++ = c2x_table[what >> 4]; - *where++ = c2x_table[what & 0xf]; - return where; -} - -/* - * escape_path_segment() escapes a path segment, as defined in RFC 1808. This - * routine is (should be) OS independent. - * - * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all - * cases if a ':' occurs before the first '/' in the URL, the URL should be - * prefixed with "./" (or the ':' escaped). In the case of Unix, this means - * leaving '/' alone, but otherwise doing what escape_path_segment() does. For - * efficiency reasons, we don't use escape_path_segment(), which is provided for - * reference. Again, RFC 1808 is where this stuff is defined. - * - * If partial is set, os_escape_path() assumes that the path will be appended to - * something with a '/' in it (and thus does not prefix "./"). - */ - -AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment) -{ - char *copy = apr_palloc(p, 3 * strlen(segment) + 1); - const unsigned char *s = (const unsigned char *)segment; - unsigned char *d = (unsigned char *)copy; - unsigned c; - - while ((c = *s)) { - if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) { - d = c2x(c, d); - } - else { - *d++ = c; - } - ++s; - } - *d = '\0'; - return copy; -} - -AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial) -{ - char *copy = apr_palloc(p, 3 * strlen(path) + 3); - const unsigned char *s = (const unsigned char *)path; - unsigned char *d = (unsigned char *)copy; - unsigned c; - - if (!partial) { - const char *colon = ap_strchr_c(path, ':'); - const char *slash = ap_strchr_c(path, '/'); - - if (colon && (!slash || colon < slash)) { - *d++ = '.'; - *d++ = '/'; - } - } - while ((c = *s)) { - if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) { - d = c2x(c, d); - } - else { - *d++ = c; - } - ++s; - } - *d = '\0'; - return copy; -} - -/* ap_escape_uri is now a macro for os_escape_path */ - -AP_DECLARE(char *) ap_escape_html(apr_pool_t *p, const char *s) -{ - int i, j; - char *x; - - /* first, count the number of extra characters */ - for (i = 0, j = 0; s[i] != '\0'; i++) - if (s[i] == '<' || s[i] == '>') - j += 3; - else if (s[i] == '&') - j += 4; - - if (j == 0) - return apr_pstrndup(p, s, i); - - x = apr_palloc(p, i + j + 1); - for (i = 0, j = 0; s[i] != '\0'; i++, j++) - if (s[i] == '<') { - memcpy(&x[j], "<", 4); - j += 3; - } - else if (s[i] == '>') { - memcpy(&x[j], ">", 4); - j += 3; - } - else if (s[i] == '&') { - memcpy(&x[j], "&", 5); - j += 4; - } - else - x[j] = s[i]; - - x[j] = '\0'; - return x; -} - -AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path) -{ - apr_finfo_t finfo; - - if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS) - return 0; /* in error condition, just return no */ - - return (finfo.filetype == APR_DIR); -} - -AP_DECLARE(int) ap_is_rdirectory(apr_pool_t *p, const char *path) -{ - apr_finfo_t finfo; - - if (apr_lstat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS) - return 0; /* in error condition, just return no */ - - return (finfo.filetype == APR_DIR); -} - -AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1, - const char *src2) -{ - register int x; - - x = strlen(src1); - if (x == 0) - return apr_pstrcat(a, "/", src2, NULL); - - if (src1[x - 1] != '/') - return apr_pstrcat(a, src1, "/", src2, NULL); - else - return apr_pstrcat(a, src1, src2, NULL); -} - -/* - * Check for an absoluteURI syntax (see section 3.2 in RFC2068). - */ -AP_DECLARE(int) ap_is_url(const char *u) -{ - register int x; - - for (x = 0; u[x] != ':'; x++) { - if ((!u[x]) || - ((!apr_isalpha(u[x])) && (!apr_isdigit(u[x])) && - (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) { - return 0; - } - } - - return (x ? 1 : 0); /* If the first character is ':', it's broken, too */ -} - -AP_DECLARE(int) ap_ind(const char *s, char c) -{ - const char *p = ap_strchr_c(s, c); - - if (p == NULL) - return -1; - return p - s; -} - -AP_DECLARE(int) ap_rind(const char *s, char c) -{ - const char *p = ap_strrchr_c(s, c); - - if (p == NULL) - return -1; - return p - s; -} - -AP_DECLARE(void) ap_str_tolower(char *str) -{ - while (*str) { - *str = apr_tolower(*str); - ++str; - } -} - -static char *find_fqdn(apr_pool_t *a, struct hostent *p) -{ - int x; - - if (!strchr(p->h_name, '.')) { - for (x = 0; p->h_aliases[x]; ++x) { - if (strchr(p->h_aliases[x], '.') && - (!strncasecmp(p->h_aliases[x], p->h_name, strlen(p->h_name)))) - return apr_pstrdup(a, p->h_aliases[x]); - } - return NULL; - } - return apr_pstrdup(a, (void *) p->h_name); -} - -char *ap_get_local_host(apr_pool_t *a) -{ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 256 -#endif - char str[MAXHOSTNAMELEN + 1]; - char *server_hostname = NULL; - struct hostent *p; - -#ifdef BEOS_R5 - if (gethostname(str, sizeof(str) - 1) == 0) -#else - if (gethostname(str, sizeof(str) - 1) != 0) -#endif - { - ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, - "%s: gethostname() failed to determine ServerName", - ap_server_argv0); - } - else - { - str[sizeof(str) - 1] = '\0'; - if ((!(p = gethostbyname(str))) - || (!(server_hostname = find_fqdn(a, p)))) { - /* Recovery - return the default servername by IP: */ - if (p && p->h_addr_list[0]) { - apr_snprintf(str, sizeof(str), "%pA", p->h_addr_list[0]); - server_hostname = apr_pstrdup(a, str); - /* We will drop through to report the IP-named server */ - } - } - else { - /* Since we found a fdqn, return it with no logged message. */ - return server_hostname; - } - } - - if (!server_hostname) - server_hostname = apr_pstrdup(a, "127.0.0.1"); - - ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO|APLOG_STARTUP, 0, a, - "%s: Could not determine the server's fully qualified " - "domain name, using %s for ServerName", - ap_server_argv0, server_hostname); - - return server_hostname; -} - -/* simple 'pool' alloc()ing glue to apr_base64.c - */ -AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded) -{ - char *decoded; - int l; - - decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded)); - l = apr_base64_decode(decoded, bufcoded); - decoded[l] = '\0'; /* make binary sequence into string */ - - return decoded; -} - -AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string) -{ - char *encoded; - int l = strlen(string); - - encoded = (char *) apr_palloc(p, 1 + apr_base64_encode_len(l)); - l = apr_base64_encode(encoded, string, l); - encoded[l] = '\0'; /* make binary sequence into string */ - - return encoded; -} - -/* we want to downcase the type/subtype for comparison purposes - * but nothing else because ;parameter=foo values are case sensitive. - * XXX: in truth we want to downcase parameter names... but really, - * apache has never handled parameters and such correctly. You - * also need to compress spaces and such to be able to compare - * properly. -djg - */ -AP_DECLARE(void) ap_content_type_tolower(char *str) -{ - char *semi; - - semi = strchr(str, ';'); - if (semi) { - *semi = '\0'; - } - while (*str) { - *str = apr_tolower(*str); - ++str; - } - if (semi) { - *semi = ';'; - } -} - -/* - * Given a string, replace any bare " with \" . - */ -AP_DECLARE(char *) ap_escape_quotes (apr_pool_t *p, const char *instring) -{ - int newlen = 0; - const char *inchr = instring; - char *outchr, *outstring; - - /* - * Look through the input string, jogging the length of the output - * string up by an extra byte each time we find an unescaped ". - */ - while (*inchr != '\0') { - newlen++; - if (*inchr == '"') { - newlen++; - } - /* - * If we find a slosh, and it's not the last byte in the string, - * it's escaping something - advance past both bytes. - */ - if ((*inchr == '\\') && (inchr[1] != '\0')) { - inchr++; - newlen++; - } - inchr++; - } - outstring = apr_palloc(p, newlen + 1); - inchr = instring; - outchr = outstring; - /* - * Now copy the input string to the output string, inserting a slosh - * in front of every " that doesn't already have one. - */ - while (*inchr != '\0') { - if ((*inchr == '\\') && (inchr[1] != '\0')) { - *outchr++ = *inchr++; - *outchr++ = *inchr++; - } - if (*inchr == '"') { - *outchr++ = '\\'; - } - if (*inchr != '\0') { - *outchr++ = *inchr++; - } - } - *outchr = '\0'; - return outstring; -} |