Blame server/util.c

Packit 90a5c9
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
 * contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
 * this work for additional information regarding copyright ownership.
Packit 90a5c9
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
 * (the "License"); you may not use this file except in compliance with
Packit 90a5c9
 * the License.  You may obtain a copy of the License at
Packit 90a5c9
 *
Packit 90a5c9
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
 *
Packit 90a5c9
 * Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
 * See the License for the specific language governing permissions and
Packit 90a5c9
 * limitations under the License.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * util.c: string utility things
Packit 90a5c9
 *
Packit 90a5c9
 * 3/21/93 Rob McCool
Packit 90a5c9
 * 1995-96 Many changes by the Apache Software Foundation
Packit 90a5c9
 *
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
/* Debugging aid:
Packit 90a5c9
 * #define DEBUG            to trace all cfg_open*()/cfg_closefile() calls
Packit 90a5c9
 * #define DEBUG_CFG_LINES  to trace every line read from the config files
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
#include "apr.h"
Packit 90a5c9
#include "apr_strings.h"
Packit 90a5c9
#include "apr_lib.h"
Packit 90a5c9
Packit 90a5c9
#define APR_WANT_STDIO
Packit 90a5c9
#define APR_WANT_STRFUNC
Packit 90a5c9
#include "apr_want.h"
Packit 90a5c9
Packit 90a5c9
#if APR_HAVE_UNISTD_H
Packit 90a5c9
#include <unistd.h>
Packit 90a5c9
#endif
Packit 90a5c9
#if APR_HAVE_PROCESS_H
Packit 90a5c9
#include <process.h>            /* for getpid() on Win32 */
Packit 90a5c9
#endif
Packit 90a5c9
#if APR_HAVE_NETDB_H
Packit 90a5c9
#include <netdb.h>              /* for gethostbyname() */
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
#include "ap_config.h"
Packit 90a5c9
#include "apr_base64.h"
Packit 90a5c9
#include "httpd.h"
Packit 90a5c9
#include "http_main.h"
Packit 90a5c9
#include "http_log.h"
Packit 90a5c9
#include "http_protocol.h"
Packit 90a5c9
#include "http_config.h"
Packit 90a5c9
#include "http_core.h"
Packit 90a5c9
#include "util_ebcdic.h"
Packit 90a5c9
#include "util_varbuf.h"
Packit 90a5c9
Packit 90a5c9
#ifdef HAVE_PWD_H
Packit 90a5c9
#include <pwd.h>
Packit 90a5c9
#endif
Packit 90a5c9
#ifdef HAVE_GRP_H
Packit 90a5c9
#include <grp.h>
Packit 90a5c9
#endif
Packit 90a5c9
#ifdef HAVE_SYS_LOADAVG_H
Packit 90a5c9
#include <sys/loadavg.h>
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
#include "ap_mpm.h"
Packit 90a5c9
Packit 90a5c9
/* A bunch of functions in util.c scan strings looking for certain characters.
Packit 90a5c9
 * To make that more efficient we encode a lookup table.  The test_char_table
Packit 90a5c9
 * is generated automatically by gen_test_char.c.
Packit 90a5c9
 */
Packit 90a5c9
#include "test_char.h"
Packit 90a5c9
Packit 90a5c9
/* we assume the folks using this ensure 0 <= c < 256... which means
Packit 90a5c9
 * you need a cast to (unsigned char) first, you can't just plug a
Packit 90a5c9
 * char in here and get it to work, because if char is signed then it
Packit 90a5c9
 * will first be sign extended.
Packit 90a5c9
 */
Packit 90a5c9
#define TEST_CHAR(c, f)        (test_char_table[(unsigned char)(c)] & (f))
Packit 90a5c9
Packit 90a5c9
/* Win32/NetWare/OS2 need to check for both forward and back slashes
Packit 90a5c9
 * in ap_getparents() and ap_escape_url.
Packit 90a5c9
 */
Packit 90a5c9
#ifdef CASE_BLIND_FILESYSTEM
Packit 90a5c9
#define IS_SLASH(s) ((s == '/') || (s == '\\'))
Packit 90a5c9
#define SLASHES "/\\"
Packit 90a5c9
#else
Packit 90a5c9
#define IS_SLASH(s) (s == '/')
Packit 90a5c9
#define SLASHES "/"
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
/* we know core's module_index is 0 */
Packit 90a5c9
#undef APLOG_MODULE_INDEX
Packit 90a5c9
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Examine a field value (such as a media-/content-type) string and return
Packit 90a5c9
 * it sans any parameters; e.g., strip off any ';charset=foo' and the like.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype)
Packit 90a5c9
{
Packit 90a5c9
    const char *semi;
Packit 90a5c9
Packit 90a5c9
    if (intype == NULL) return NULL;
Packit 90a5c9
Packit 90a5c9
    semi = ap_strchr_c(intype, ';');
Packit 90a5c9
    if (semi == NULL) {
Packit 90a5c9
        return apr_pstrdup(p, intype);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        while ((semi > intype) && apr_isspace(semi[-1])) {
Packit 90a5c9
            semi--;
Packit 90a5c9
        }
Packit 90a5c9
        return apr_pstrmemdup(p, intype, semi - intype);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt,
Packit 90a5c9
                              int gmt)
Packit 90a5c9
{
Packit 90a5c9
    apr_size_t retcode;
Packit 90a5c9
    char ts[MAX_STRING_LEN];
Packit 90a5c9
    char tf[MAX_STRING_LEN];
Packit 90a5c9
    apr_time_exp_t xt;
Packit 90a5c9
Packit 90a5c9
    if (gmt) {
Packit 90a5c9
        const char *f;
Packit 90a5c9
        char *strp;
Packit 90a5c9
Packit 90a5c9
        apr_time_exp_gmt(&xt, t);
Packit 90a5c9
        /* Convert %Z to "GMT" and %z to "+0000";
Packit 90a5c9
         * on hosts that do not have a time zone string in struct tm,
Packit 90a5c9
         * strftime must assume its argument is local time.
Packit 90a5c9
         */
Packit 90a5c9
        for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f)
Packit 90a5c9
            ; f++, strp++) {
Packit 90a5c9
            if (*f != '%') continue;
Packit 90a5c9
            switch (f[1]) {
Packit 90a5c9
            case '%':
Packit 90a5c9
                *++strp = *++f;
Packit 90a5c9
                break;
Packit 90a5c9
            case 'Z':
Packit 90a5c9
                *strp++ = 'G';
Packit 90a5c9
                *strp++ = 'M';
Packit 90a5c9
                *strp = 'T';
Packit 90a5c9
                f++;
Packit 90a5c9
                break;
Packit 90a5c9
            case 'z': /* common extension */
Packit 90a5c9
                *strp++ = '+';
Packit 90a5c9
                *strp++ = '0';
Packit 90a5c9
                *strp++ = '0';
Packit 90a5c9
                *strp++ = '0';
Packit 90a5c9
                *strp = '0';
Packit 90a5c9
                f++;
Packit 90a5c9
                break;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        *strp = '\0';
Packit 90a5c9
        fmt = tf;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        apr_time_exp_lt(&xt, t);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* check return code? */
Packit 90a5c9
    apr_strftime(ts, &retcode, MAX_STRING_LEN, fmt, &xt;;
Packit 90a5c9
    ts[MAX_STRING_LEN - 1] = '\0';
Packit 90a5c9
    return apr_pstrdup(p, ts);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Roy owes Rob beer. */
Packit 90a5c9
/* Rob owes Roy dinner. */
Packit 90a5c9
Packit 90a5c9
/* These legacy comments would make a lot more sense if Roy hadn't
Packit 90a5c9
 * replaced the old later_than() routine with util_date.c.
Packit 90a5c9
 *
Packit 90a5c9
 * Well, okay, they still wouldn't make any sense.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
/* Match = 0, NoMatch = 1, Abort = -1
Packit 90a5c9
 * Based loosely on sections of wildmat.c by Rich Salz
Packit 90a5c9
 * Hmmm... shouldn't this really go component by component?
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected)
Packit 90a5c9
{
Packit 90a5c9
    int x, y;
Packit 90a5c9
Packit 90a5c9
    for (x = 0, y = 0; expected[y]; ++y, ++x) {
Packit 90a5c9
        if ((!str[x]) && (expected[y] != '*'))
Packit 90a5c9
            return -1;
Packit 90a5c9
        if (expected[y] == '*') {
Packit 90a5c9
            while (expected[++y] == '*');
Packit 90a5c9
            if (!expected[y])
Packit 90a5c9
                return 0;
Packit 90a5c9
            while (str[x]) {
Packit 90a5c9
                int ret;
Packit 90a5c9
                if ((ret = ap_strcmp_match(&str[x++], &expected[y])) != 1)
Packit 90a5c9
                    return ret;
Packit 90a5c9
            }
Packit 90a5c9
            return -1;
Packit 90a5c9
        }
Packit 90a5c9
        else if ((expected[y] != '?') && (str[x] != expected[y]))
Packit 90a5c9
            return 1;
Packit 90a5c9
    }
Packit 90a5c9
    return (str[x] != '\0');
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected)
Packit 90a5c9
{
Packit 90a5c9
    int x, y;
Packit 90a5c9
Packit 90a5c9
    for (x = 0, y = 0; expected[y]; ++y, ++x) {
Packit 90a5c9
        if (!str[x] && expected[y] != '*')
Packit 90a5c9
            return -1;
Packit 90a5c9
        if (expected[y] == '*') {
Packit 90a5c9
            while (expected[++y] == '*');
Packit 90a5c9
            if (!expected[y])
Packit 90a5c9
                return 0;
Packit 90a5c9
            while (str[x]) {
Packit 90a5c9
                int ret;
Packit 90a5c9
                if ((ret = ap_strcasecmp_match(&str[x++], &expected[y])) != 1)
Packit 90a5c9
                    return ret;
Packit 90a5c9
            }
Packit 90a5c9
            return -1;
Packit 90a5c9
        }
Packit 90a5c9
        else if (expected[y] != '?'
Packit 90a5c9
                 && apr_tolower(str[x]) != apr_tolower(expected[y]))
Packit 90a5c9
            return 1;
Packit 90a5c9
    }
Packit 90a5c9
    return (str[x] != '\0');
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* We actually compare the canonical root to this root, (but we don't
Packit 90a5c9
 * waste time checking the case), since every use of this function in
Packit 90a5c9
 * httpd-2.1 tests if the path is 'proper', meaning we've already passed
Packit 90a5c9
 * it through apr_filepath_merge, or we haven't.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(int) ap_os_is_path_absolute(apr_pool_t *p, const char *dir)
Packit 90a5c9
{
Packit 90a5c9
    const char *newpath;
Packit 90a5c9
    const char *ourdir = dir;
Packit 90a5c9
    if (apr_filepath_root(&newpath, &dir, 0, p) != APR_SUCCESS
Packit 90a5c9
            || strncmp(newpath, ourdir, strlen(newpath)) != 0) {
Packit 90a5c9
        return 0;
Packit 90a5c9
    }
Packit 90a5c9
    return 1;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_is_matchexp(const char *str)
Packit 90a5c9
{
Packit 90a5c9
    int x;
Packit 90a5c9
Packit 90a5c9
    for (x = 0; str[x]; x++)
Packit 90a5c9
        if ((str[x] == '*') || (str[x] == '?'))
Packit 90a5c9
            return 1;
Packit 90a5c9
    return 0;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Here's a pool-based interface to the POSIX-esque ap_regcomp().
Packit 90a5c9
 * Note that we return ap_regex_t instead of being passed one.
Packit 90a5c9
 * The reason is that if you use an already-used ap_regex_t structure,
Packit 90a5c9
 * the memory that you've already allocated gets forgotten, and
Packit 90a5c9
 * regfree() doesn't clear it. So we don't allow it.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
static apr_status_t regex_cleanup(void *preg)
Packit 90a5c9
{
Packit 90a5c9
    ap_regfree((ap_regex_t *) preg);
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern,
Packit 90a5c9
                                     int cflags)
Packit 90a5c9
{
Packit 90a5c9
    ap_regex_t *preg = apr_palloc(p, sizeof *preg);
Packit 90a5c9
    int err = ap_regcomp(preg, pattern, cflags);
Packit 90a5c9
    if (err) {
Packit 90a5c9
        if (err == AP_REG_ESPACE)
Packit 90a5c9
            ap_abort_on_oom();
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    apr_pool_cleanup_register(p, (void *) preg, regex_cleanup,
Packit 90a5c9
                              apr_pool_cleanup_null);
Packit 90a5c9
Packit 90a5c9
    return preg;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_pregfree(apr_pool_t *p, ap_regex_t *reg)
Packit 90a5c9
{
Packit 90a5c9
    ap_regfree(reg);
Packit 90a5c9
    apr_pool_cleanup_kill(p, (void *) reg, regex_cleanup);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Similar to standard strstr() but we ignore case in this version.
Packit 90a5c9
 * Based on the strstr() implementation further below.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2)
Packit 90a5c9
{
Packit 90a5c9
    char *p1, *p2;
Packit 90a5c9
    if (*s2 == '\0') {
Packit 90a5c9
        /* an empty s2 */
Packit 90a5c9
        return((char *)s1);
Packit 90a5c9
    }
Packit 90a5c9
    while(1) {
Packit 90a5c9
        for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++);
Packit 90a5c9
        if (*s1 == '\0') {
Packit 90a5c9
            return(NULL);
Packit 90a5c9
        }
Packit 90a5c9
        /* found first character of s2, see if the rest matches */
Packit 90a5c9
        p1 = (char *)s1;
Packit 90a5c9
        p2 = (char *)s2;
Packit 90a5c9
        for (++p1, ++p2; apr_tolower(*p1) == apr_tolower(*p2); ++p1, ++p2) {
Packit 90a5c9
            if (*p1 == '\0') {
Packit 90a5c9
                /* both strings ended together */
Packit 90a5c9
                return((char *)s1);
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        if (*p2 == '\0') {
Packit 90a5c9
            /* second string ended, a match */
Packit 90a5c9
            break;
Packit 90a5c9
        }
Packit 90a5c9
        /* didn't find a match here, try starting at next character in s1 */
Packit 90a5c9
        s1++;
Packit 90a5c9
    }
Packit 90a5c9
    return((char *)s1);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Returns an offsetted pointer in bigstring immediately after
Packit 90a5c9
 * prefix. Returns bigstring if bigstring doesn't start with
Packit 90a5c9
 * prefix or if prefix is longer than bigstring while still matching.
Packit 90a5c9
 * NOTE: pointer returned is relative to bigstring, so we
Packit 90a5c9
 * can use standard pointer comparisons in the calling function
Packit 90a5c9
 * (eg: test if ap_stripprefix(a,b) == a)
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(const char *) ap_stripprefix(const char *bigstring,
Packit 90a5c9
                                        const char *prefix)
Packit 90a5c9
{
Packit 90a5c9
    const char *p1;
Packit 90a5c9
Packit 90a5c9
    if (*prefix == '\0')
Packit 90a5c9
        return bigstring;
Packit 90a5c9
Packit 90a5c9
    p1 = bigstring;
Packit 90a5c9
    while (*p1 && *prefix) {
Packit 90a5c9
        if (*p1++ != *prefix++)
Packit 90a5c9
            return bigstring;
Packit 90a5c9
    }
Packit 90a5c9
    if (*prefix == '\0')
Packit 90a5c9
        return p1;
Packit 90a5c9
Packit 90a5c9
    /* hit the end of bigstring! */
Packit 90a5c9
    return bigstring;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* This function substitutes for $0-$9, filling in regular expression
Packit 90a5c9
 * submatches. Pass it the same nmatch and pmatch arguments that you
Packit 90a5c9
 * passed ap_regexec(). pmatch should not be greater than the maximum number
Packit 90a5c9
 * of subexpressions - i.e. one more than the re_nsub member of ap_regex_t.
Packit 90a5c9
 *
Packit 90a5c9
 * nmatch must be <=AP_MAX_REG_MATCH (10).
Packit 90a5c9
 *
Packit 90a5c9
 * input should be the string with the $-expressions, source should be the
Packit 90a5c9
 * string that was matched against.
Packit 90a5c9
 *
Packit 90a5c9
 * It returns the substituted string, or NULL if a vbuf is used.
Packit 90a5c9
 * On errors, returns the orig string.
Packit 90a5c9
 *
Packit 90a5c9
 * Parts of this code are based on Henry Spencer's regsub(), from his
Packit 90a5c9
 * AT&T V8 regexp package.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
static apr_status_t regsub_core(apr_pool_t *p, char **result,
Packit 90a5c9
                                struct ap_varbuf *vb, const char *input,
Packit 90a5c9
                                const char *source, apr_size_t nmatch,
Packit 90a5c9
                                ap_regmatch_t pmatch[], apr_size_t maxlen)
Packit 90a5c9
{
Packit 90a5c9
    const char *src = input;
Packit 90a5c9
    char *dst;
Packit 90a5c9
    char c;
Packit 90a5c9
    apr_size_t no;
Packit 90a5c9
    apr_size_t len = 0;
Packit 90a5c9
Packit 90a5c9
    AP_DEBUG_ASSERT((result && p && !vb) || (vb && !p && !result));
Packit 90a5c9
    if (!source || nmatch>AP_MAX_REG_MATCH)
Packit 90a5c9
        return APR_EINVAL;
Packit 90a5c9
    if (!nmatch) {
Packit 90a5c9
        len = strlen(src);
Packit 90a5c9
        if (maxlen > 0 && len >= maxlen)
Packit 90a5c9
            return APR_ENOMEM;
Packit 90a5c9
        if (!vb) {
Packit 90a5c9
            *result = apr_pstrmemdup(p, src, len);
Packit 90a5c9
            return APR_SUCCESS;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            ap_varbuf_strmemcat(vb, src, len);
Packit 90a5c9
            return APR_SUCCESS;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* First pass, find the size */
Packit 90a5c9
    while ((c = *src++) != '\0') {
Packit 90a5c9
        if (c == '$' && apr_isdigit(*src))
Packit 90a5c9
            no = *src++ - '0';
Packit 90a5c9
        else
Packit 90a5c9
            no = AP_MAX_REG_MATCH;
Packit 90a5c9
Packit 90a5c9
        if (no >= AP_MAX_REG_MATCH) {  /* Ordinary character. */
Packit 90a5c9
            if (c == '\\' && *src)
Packit 90a5c9
                src++;
Packit 90a5c9
            len++;
Packit 90a5c9
        }
Packit 90a5c9
        else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
Packit 90a5c9
            if (APR_SIZE_MAX - len <= pmatch[no].rm_eo - pmatch[no].rm_so)
Packit 90a5c9
                return APR_ENOMEM;
Packit 90a5c9
            len += pmatch[no].rm_eo - pmatch[no].rm_so;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (len >= maxlen && maxlen > 0)
Packit 90a5c9
        return APR_ENOMEM;
Packit 90a5c9
Packit 90a5c9
    if (!vb) {
Packit 90a5c9
        *result = dst = apr_palloc(p, len + 1);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        if (vb->strlen == AP_VARBUF_UNKNOWN)
Packit 90a5c9
            vb->strlen = strlen(vb->buf);
Packit 90a5c9
        ap_varbuf_grow(vb, vb->strlen + len);
Packit 90a5c9
        dst = vb->buf + vb->strlen;
Packit 90a5c9
        vb->strlen += len;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* Now actually fill in the string */
Packit 90a5c9
Packit 90a5c9
    src = input;
Packit 90a5c9
Packit 90a5c9
    while ((c = *src++) != '\0') {
Packit 90a5c9
        if (c == '$' && apr_isdigit(*src))
Packit 90a5c9
            no = *src++ - '0';
Packit 90a5c9
        else
Packit 90a5c9
            no = AP_MAX_REG_MATCH;
Packit 90a5c9
Packit 90a5c9
        if (no >= AP_MAX_REG_MATCH) {  /* Ordinary character. */
Packit 90a5c9
            if (c == '\\' && *src)
Packit 90a5c9
                c = *src++;
Packit 90a5c9
            *dst++ = c;
Packit 90a5c9
        }
Packit 90a5c9
        else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
Packit 90a5c9
            len = pmatch[no].rm_eo - pmatch[no].rm_so;
Packit 90a5c9
            memcpy(dst, source + pmatch[no].rm_so, len);
Packit 90a5c9
            dst += len;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
    }
Packit 90a5c9
    *dst = '\0';
Packit 90a5c9
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#ifndef AP_PREGSUB_MAXLEN
Packit 90a5c9
#define AP_PREGSUB_MAXLEN   (HUGE_STRING_LEN * 8)
Packit 90a5c9
#endif
Packit 90a5c9
AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
Packit 90a5c9
                              const char *source, apr_size_t nmatch,
Packit 90a5c9
                              ap_regmatch_t pmatch[])
Packit 90a5c9
{
Packit 90a5c9
    char *result;
Packit 90a5c9
    apr_status_t rc = regsub_core(p, &result, NULL, input, source, nmatch,
Packit 90a5c9
                                  pmatch, AP_PREGSUB_MAXLEN);
Packit 90a5c9
    if (rc != APR_SUCCESS)
Packit 90a5c9
        result = NULL;
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result,
Packit 90a5c9
                                       const char *input, const char *source,
Packit 90a5c9
                                       apr_size_t nmatch, ap_regmatch_t pmatch[],
Packit 90a5c9
                                       apr_size_t maxlen)
Packit 90a5c9
{
Packit 90a5c9
    apr_status_t rc = regsub_core(p, result, NULL, input, source, nmatch,
Packit 90a5c9
                                  pmatch, maxlen);
Packit 90a5c9
    if (rc != APR_SUCCESS)
Packit 90a5c9
        *result = NULL;
Packit 90a5c9
    return rc;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Parse .. so we don't compromise security
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(void) ap_getparents(char *name)
Packit 90a5c9
{
Packit 90a5c9
    char *next;
Packit 90a5c9
    int l, w, first_dot;
Packit 90a5c9
Packit 90a5c9
    /* Four paseses, as per RFC 1808 */
Packit 90a5c9
    /* a) remove ./ path segments */
Packit 90a5c9
    for (next = name; *next && (*next != '.'); next++) {
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    l = w = first_dot = next - name;
Packit 90a5c9
    while (name[l] != '\0') {
Packit 90a5c9
        if (name[l] == '.' && IS_SLASH(name[l + 1])
Packit 90a5c9
            && (l == 0 || IS_SLASH(name[l - 1])))
Packit 90a5c9
            l += 2;
Packit 90a5c9
        else
Packit 90a5c9
            name[w++] = name[l++];
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* b) remove trailing . path, segment */
Packit 90a5c9
    if (w == 1 && name[0] == '.')
Packit 90a5c9
        w--;
Packit 90a5c9
    else if (w > 1 && name[w - 1] == '.' && IS_SLASH(name[w - 2]))
Packit 90a5c9
        w--;
Packit 90a5c9
    name[w] = '\0';
Packit 90a5c9
Packit 90a5c9
    /* c) remove all xx/../ segments. (including leading ../ and /../) */
Packit 90a5c9
    l = first_dot;
Packit 90a5c9
Packit 90a5c9
    while (name[l] != '\0') {
Packit 90a5c9
        if (name[l] == '.' && name[l + 1] == '.' && IS_SLASH(name[l + 2])
Packit 90a5c9
            && (l == 0 || IS_SLASH(name[l - 1]))) {
Packit 90a5c9
            int m = l + 3, n;
Packit 90a5c9
Packit 90a5c9
            l = l - 2;
Packit 90a5c9
            if (l >= 0) {
Packit 90a5c9
                while (l >= 0 && !IS_SLASH(name[l]))
Packit 90a5c9
                    l--;
Packit 90a5c9
                l++;
Packit 90a5c9
            }
Packit 90a5c9
            else
Packit 90a5c9
                l = 0;
Packit 90a5c9
            n = l;
Packit 90a5c9
            while ((name[n] = name[m]))
Packit 90a5c9
                (++n, ++m);
Packit 90a5c9
        }
Packit 90a5c9
        else
Packit 90a5c9
            ++l;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* d) remove trailing xx/.. segment. */
Packit 90a5c9
    if (l == 2 && name[0] == '.' && name[1] == '.')
Packit 90a5c9
        name[0] = '\0';
Packit 90a5c9
    else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
Packit 90a5c9
             && IS_SLASH(name[l - 3])) {
Packit 90a5c9
        l = l - 4;
Packit 90a5c9
        if (l >= 0) {
Packit 90a5c9
            while (l >= 0 && !IS_SLASH(name[l]))
Packit 90a5c9
                l--;
Packit 90a5c9
            l++;
Packit 90a5c9
        }
Packit 90a5c9
        else
Packit 90a5c9
            l = 0;
Packit 90a5c9
        name[l] = '\0';
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_no2slash(char *name)
Packit 90a5c9
{
Packit 90a5c9
    char *d, *s;
Packit 90a5c9
Packit 90a5c9
    s = d = name;
Packit 90a5c9
Packit 90a5c9
#ifdef HAVE_UNC_PATHS
Packit 90a5c9
    /* Check for UNC names.  Leave leading two slashes. */
Packit 90a5c9
    if (s[0] == '/' && s[1] == '/')
Packit 90a5c9
        *d++ = *s++;
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
    while (*s) {
Packit 90a5c9
        if ((*d++ = *s) == '/') {
Packit 90a5c9
            do {
Packit 90a5c9
                ++s;
Packit 90a5c9
            } while (*s == '/');
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            ++s;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    *d = '\0';
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * copy at most n leading directories of s into d
Packit 90a5c9
 * d should be at least as large as s plus 1 extra byte
Packit 90a5c9
 * assumes n > 0
Packit 90a5c9
 * the return value is the ever useful pointer to the trailing \0 of d
Packit 90a5c9
 *
Packit 90a5c9
 * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments,
Packit 90a5c9
 * so that if n == 0, "/" is returned in d with n == 1
Packit 90a5c9
 * and s == "e:/test.html", "e:/" is returned in d
Packit 90a5c9
 * *** See also ap_directory_walk in server/request.c
Packit 90a5c9
 *
Packit 90a5c9
 * examples:
Packit 90a5c9
 *    /a/b, 0  ==> /  (true for all platforms)
Packit 90a5c9
 *    /a/b, 1  ==> /
Packit 90a5c9
 *    /a/b, 2  ==> /a/
Packit 90a5c9
 *    /a/b, 3  ==> /a/b/
Packit 90a5c9
 *    /a/b, 4  ==> /a/b/
Packit 90a5c9
 *
Packit 90a5c9
 *    c:/a/b 0 ==> /
Packit 90a5c9
 *    c:/a/b 1 ==> c:/
Packit 90a5c9
 *    c:/a/b 2 ==> c:/a/
Packit 90a5c9
 *    c:/a/b 3 ==> c:/a/b
Packit 90a5c9
 *    c:/a/b 4 ==> c:/a/b
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(char *) ap_make_dirstr_prefix(char *d, const char *s, int n)
Packit 90a5c9
{
Packit 90a5c9
    if (n < 1) {
Packit 90a5c9
        *d = '/';
Packit 90a5c9
        *++d = '\0';
Packit 90a5c9
        return (d);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    for (;;) {
Packit 90a5c9
        if (*s == '\0' || (*s == '/' && (--n) == 0)) {
Packit 90a5c9
            *d = '/';
Packit 90a5c9
            break;
Packit 90a5c9
        }
Packit 90a5c9
        *d++ = *s++;
Packit 90a5c9
    }
Packit 90a5c9
    *++d = 0;
Packit 90a5c9
    return (d);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * return the parent directory name including trailing / of the file s
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s)
Packit 90a5c9
{
Packit 90a5c9
    const char *last_slash = ap_strrchr_c(s, '/');
Packit 90a5c9
    char *d;
Packit 90a5c9
    int l;
Packit 90a5c9
Packit 90a5c9
    if (last_slash == NULL) {
Packit 90a5c9
        return apr_pstrdup(p, "");
Packit 90a5c9
    }
Packit 90a5c9
    l = (last_slash - s) + 1;
Packit 90a5c9
    d = apr_pstrmemdup(p, s, l);
Packit 90a5c9
Packit 90a5c9
    return (d);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_count_dirs(const char *path)
Packit 90a5c9
{
Packit 90a5c9
    int x, n;
Packit 90a5c9
Packit 90a5c9
    for (x = 0, n = 0; path[x]; x++)
Packit 90a5c9
        if (path[x] == '/')
Packit 90a5c9
            n++;
Packit 90a5c9
    return n;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop)
Packit 90a5c9
{
Packit 90a5c9
    return ap_getword(atrans, (const char **) line, stop);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop)
Packit 90a5c9
{
Packit 90a5c9
    const char *pos = *line;
Packit 90a5c9
    int len;
Packit 90a5c9
    char *res;
Packit 90a5c9
Packit 90a5c9
    while ((*pos != stop) && *pos) {
Packit 90a5c9
        ++pos;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    len = pos - *line;
Packit 90a5c9
    res = apr_pstrmemdup(atrans, *line, len);
Packit 90a5c9
Packit 90a5c9
    if (stop) {
Packit 90a5c9
        while (*pos == stop) {
Packit 90a5c9
            ++pos;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    *line = pos;
Packit 90a5c9
Packit 90a5c9
    return res;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line)
Packit 90a5c9
{
Packit 90a5c9
    return ap_getword_white(atrans, (const char **) line);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line)
Packit 90a5c9
{
Packit 90a5c9
    const char *pos = *line;
Packit 90a5c9
    int len;
Packit 90a5c9
    char *res;
Packit 90a5c9
Packit 90a5c9
    while (!apr_isspace(*pos) && *pos) {
Packit 90a5c9
        ++pos;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    len = pos - *line;
Packit 90a5c9
    res = apr_pstrmemdup(atrans, *line, len);
Packit 90a5c9
Packit 90a5c9
    while (apr_isspace(*pos)) {
Packit 90a5c9
        ++pos;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    *line = pos;
Packit 90a5c9
Packit 90a5c9
    return res;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line,
Packit 90a5c9
                                       char stop)
Packit 90a5c9
{
Packit 90a5c9
    return ap_getword_nulls(atrans, (const char **) line, stop);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line,
Packit 90a5c9
                                    char stop)
Packit 90a5c9
{
Packit 90a5c9
    const char *pos = ap_strchr_c(*line, stop);
Packit 90a5c9
    char *res;
Packit 90a5c9
Packit 90a5c9
    if (!pos) {
Packit 90a5c9
        apr_size_t len = strlen(*line);
Packit 90a5c9
        res = apr_pstrmemdup(atrans, *line, len);
Packit 90a5c9
        *line += len;
Packit 90a5c9
        return res;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    res = apr_pstrmemdup(atrans, *line, pos - *line);
Packit 90a5c9
Packit 90a5c9
    ++pos;
Packit 90a5c9
Packit 90a5c9
    *line = pos;
Packit 90a5c9
Packit 90a5c9
    return res;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Get a word, (new) config-file style --- quoted strings and backslashes
Packit 90a5c9
 * all honored
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
static char *substring_conf(apr_pool_t *p, const char *start, int len,
Packit 90a5c9
                            char quote)
Packit 90a5c9
{
Packit 90a5c9
    char *result = apr_palloc(p, len + 1);
Packit 90a5c9
    char *resp = result;
Packit 90a5c9
    int i;
Packit 90a5c9
Packit 90a5c9
    for (i = 0; i < len; ++i) {
Packit 90a5c9
        if (start[i] == '\\' && (start[i + 1] == '\\'
Packit 90a5c9
                                 || (quote && start[i + 1] == quote)))
Packit 90a5c9
            *resp++ = start[++i];
Packit 90a5c9
        else
Packit 90a5c9
            *resp++ = start[i];
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    *resp++ = '\0';
Packit 90a5c9
#if RESOLVE_ENV_PER_TOKEN
Packit 90a5c9
    return (char *)ap_resolve_env(p,result);
Packit 90a5c9
#else
Packit 90a5c9
    return result;
Packit 90a5c9
#endif
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_getword_conf_nc(apr_pool_t *p, char **line)
Packit 90a5c9
{
Packit 90a5c9
    return ap_getword_conf(p, (const char **) line);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line)
Packit 90a5c9
{
Packit 90a5c9
    const char *str = *line, *strend;
Packit 90a5c9
    char *res;
Packit 90a5c9
    char quote;
Packit 90a5c9
Packit 90a5c9
    while (apr_isspace(*str))
Packit 90a5c9
        ++str;
Packit 90a5c9
Packit 90a5c9
    if (!*str) {
Packit 90a5c9
        *line = str;
Packit 90a5c9
        return "";
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if ((quote = *str) == '"' || quote == '\'') {
Packit 90a5c9
        strend = str + 1;
Packit 90a5c9
        while (*strend && *strend != quote) {
Packit 90a5c9
            if (*strend == '\\' && strend[1] &&
Packit 90a5c9
                (strend[1] == quote || strend[1] == '\\')) {
Packit 90a5c9
                strend += 2;
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                ++strend;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        res = substring_conf(p, str + 1, strend - str - 1, quote);
Packit 90a5c9
Packit 90a5c9
        if (*strend == quote)
Packit 90a5c9
            ++strend;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        strend = str;
Packit 90a5c9
        while (*strend && !apr_isspace(*strend))
Packit 90a5c9
            ++strend;
Packit 90a5c9
Packit 90a5c9
        res = substring_conf(p, str, strend - str, 0);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    while (apr_isspace(*strend))
Packit 90a5c9
        ++strend;
Packit 90a5c9
    *line = strend;
Packit 90a5c9
    return res;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_getword_conf2_nc(apr_pool_t *p, char **line)
Packit 90a5c9
{
Packit 90a5c9
    return ap_getword_conf2(p, (const char **) line);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_getword_conf2(apr_pool_t *p, const char **line)
Packit 90a5c9
{
Packit 90a5c9
    const char *str = *line, *strend;
Packit 90a5c9
    char *res;
Packit 90a5c9
    char quote;
Packit 90a5c9
    int count = 1;
Packit 90a5c9
Packit 90a5c9
    while (apr_isspace(*str))
Packit 90a5c9
        ++str;
Packit 90a5c9
Packit 90a5c9
    if (!*str) {
Packit 90a5c9
        *line = str;
Packit 90a5c9
        return "";
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if ((quote = *str) == '"' || quote == '\'')
Packit 90a5c9
        return ap_getword_conf(p, line);
Packit 90a5c9
Packit 90a5c9
    if (quote == '{') {
Packit 90a5c9
        strend = str + 1;
Packit 90a5c9
        while (*strend) {
Packit 90a5c9
            if (*strend == '}' && !--count)
Packit 90a5c9
                break;
Packit 90a5c9
            if (*strend == '{')
Packit 90a5c9
                ++count;
Packit 90a5c9
            if (*strend == '\\' && strend[1] && strend[1] == '\\') {
Packit 90a5c9
                ++strend;
Packit 90a5c9
            }
Packit 90a5c9
            ++strend;
Packit 90a5c9
        }
Packit 90a5c9
        res = substring_conf(p, str + 1, strend - str - 1, 0);
Packit 90a5c9
Packit 90a5c9
        if (*strend == '}')
Packit 90a5c9
            ++strend;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        strend = str;
Packit 90a5c9
        while (*strend && !apr_isspace(*strend))
Packit 90a5c9
            ++strend;
Packit 90a5c9
Packit 90a5c9
        res = substring_conf(p, str, strend - str, 0);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    while (apr_isspace(*strend))
Packit 90a5c9
        ++strend;
Packit 90a5c9
    *line = strend;
Packit 90a5c9
    return res;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_cfg_closefile(ap_configfile_t *cfp)
Packit 90a5c9
{
Packit 90a5c9
#ifdef DEBUG
Packit 90a5c9
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00551)
Packit 90a5c9
        "Done with config file %s", cfp->name);
Packit 90a5c9
#endif
Packit 90a5c9
    return (cfp->close == NULL) ? 0 : cfp->close(cfp->param);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* we can't use apr_file_* directly because of linking issues on Windows */
Packit 90a5c9
static apr_status_t cfg_close(void *param)
Packit 90a5c9
{
Packit 90a5c9
    return apr_file_close(param);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t cfg_getch(char *ch, void *param)
Packit 90a5c9
{
Packit 90a5c9
    return apr_file_getc(ch, param);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t cfg_getstr(void *buf, apr_size_t bufsiz, void *param)
Packit 90a5c9
{
Packit 90a5c9
    return apr_file_gets(buf, bufsiz, param);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Open a ap_configfile_t as FILE, return open ap_configfile_t struct pointer */
Packit 90a5c9
AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg,
Packit 90a5c9
                                          apr_pool_t *p, const char *name)
Packit 90a5c9
{
Packit 90a5c9
    ap_configfile_t *new_cfg;
Packit 90a5c9
    apr_file_t *file = NULL;
Packit 90a5c9
    apr_finfo_t finfo;
Packit 90a5c9
    apr_status_t status;
Packit 90a5c9
#ifdef DEBUG
Packit 90a5c9
    char buf[120];
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
    if (name == NULL) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00552)
Packit 90a5c9
               "Internal error: pcfg_openfile() called with NULL filename");
Packit 90a5c9
        return APR_EBADF;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    status = apr_file_open(&file, name, APR_READ | APR_BUFFERED,
Packit 90a5c9
                           APR_OS_DEFAULT, p);
Packit 90a5c9
#ifdef DEBUG
Packit 90a5c9
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(00553)
Packit 90a5c9
                "Opening config file %s (%s)",
Packit 90a5c9
                name, (status != APR_SUCCESS) ?
Packit 90a5c9
                apr_strerror(status, buf, sizeof(buf)) : "successful");
Packit 90a5c9
#endif
Packit 90a5c9
    if (status != APR_SUCCESS)
Packit 90a5c9
        return status;
Packit 90a5c9
Packit 90a5c9
    status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file);
Packit 90a5c9
    if (status != APR_SUCCESS)
Packit 90a5c9
        return status;
Packit 90a5c9
Packit 90a5c9
    if (finfo.filetype != APR_REG &&
Packit 90a5c9
#if defined(WIN32) || defined(OS2) || defined(NETWARE)
Packit 90a5c9
        strcasecmp(apr_filepath_name_get(name), "nul") != 0) {
Packit 90a5c9
#else
Packit 90a5c9
        strcmp(name, "/dev/null") != 0) {
Packit 90a5c9
#endif /* WIN32 || OS2 */
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, APLOGNO(00554)
Packit 90a5c9
                     "Access to file %s denied by server: not a regular file",
Packit 90a5c9
                     name);
Packit 90a5c9
        apr_file_close(file);
Packit 90a5c9
        return APR_EBADF;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
#ifdef WIN32
Packit 90a5c9
    /* Some twisted character [no pun intended] at MS decided that a
Packit 90a5c9
     * zero width joiner as the lead wide character would be ideal for
Packit 90a5c9
     * describing Unicode text files.  This was further convoluted to
Packit 90a5c9
     * another MSism that the same character mapped into utf-8, EF BB BF
Packit 90a5c9
     * would signify utf-8 text files.
Packit 90a5c9
     *
Packit 90a5c9
     * Since MS configuration files are all protecting utf-8 encoded
Packit 90a5c9
     * Unicode path, file and resource names, we already have the correct
Packit 90a5c9
     * WinNT encoding.  But at least eat the stupid three bytes up front.
Packit 90a5c9
     */
Packit 90a5c9
    {
Packit 90a5c9
        unsigned char buf[4];
Packit 90a5c9
        apr_size_t len = 3;
Packit 90a5c9
        status = apr_file_read(file, buf, &len;;
Packit 90a5c9
        if ((status != APR_SUCCESS) || (len < 3)
Packit 90a5c9
              || memcmp(buf, "\xEF\xBB\xBF", 3) != 0) {
Packit 90a5c9
            apr_off_t zero = 0;
Packit 90a5c9
            apr_file_seek(file, APR_SET, &zero);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
    new_cfg = apr_palloc(p, sizeof(*new_cfg));
Packit 90a5c9
    new_cfg->param = file;
Packit 90a5c9
    new_cfg->name = apr_pstrdup(p, name);
Packit 90a5c9
    new_cfg->getch = cfg_getch;
Packit 90a5c9
    new_cfg->getstr = cfg_getstr;
Packit 90a5c9
    new_cfg->close = cfg_close;
Packit 90a5c9
    new_cfg->line_number = 0;
Packit 90a5c9
    *ret_cfg = new_cfg;
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/* Allocate a ap_configfile_t handle with user defined functions and params */
Packit 90a5c9
AP_DECLARE(ap_configfile_t *) ap_pcfg_open_custom(
Packit 90a5c9
            apr_pool_t *p, const char *descr, void *param,
Packit 90a5c9
            apr_status_t (*getc_func) (char *ch, void *param),
Packit 90a5c9
            apr_status_t (*gets_func) (void *buf, apr_size_t bufsize, void *param),
Packit 90a5c9
            apr_status_t (*close_func) (void *param))
Packit 90a5c9
{
Packit 90a5c9
    ap_configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg));
Packit 90a5c9
    new_cfg->param = param;
Packit 90a5c9
    new_cfg->name = descr;
Packit 90a5c9
    new_cfg->getch = getc_func;
Packit 90a5c9
    new_cfg->getstr = gets_func;
Packit 90a5c9
    new_cfg->close = close_func;
Packit 90a5c9
    new_cfg->line_number = 0;
Packit 90a5c9
    return new_cfg;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Read one character from a configfile_t */
Packit 90a5c9
AP_DECLARE(apr_status_t) ap_cfg_getc(char *ch, ap_configfile_t *cfp)
Packit 90a5c9
{
Packit 90a5c9
    apr_status_t rc = cfp->getch(ch, cfp->param);
Packit 90a5c9
    if (rc == APR_SUCCESS && *ch == LF)
Packit 90a5c9
        ++cfp->line_number;
Packit 90a5c9
    return rc;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(const char *) ap_pcfg_strerror(apr_pool_t *p, ap_configfile_t *cfp,
Packit 90a5c9
                                          apr_status_t rc)
Packit 90a5c9
{
Packit 90a5c9
    if (rc == APR_SUCCESS)
Packit 90a5c9
        return NULL;
Packit 90a5c9
Packit 90a5c9
    if (rc == APR_ENOSPC)
Packit 90a5c9
        return apr_psprintf(p, "Error reading %s at line %d: Line too long",
Packit 90a5c9
                            cfp->name, cfp->line_number);
Packit 90a5c9
Packit 90a5c9
    return apr_psprintf(p, "Error reading %s at line %d: %pm",
Packit 90a5c9
                        cfp->name, cfp->line_number, &rc);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Read one line from open ap_configfile_t, strip LF, increase line number */
Packit 90a5c9
/* If custom handler does not define a getstr() function, read char by char */
Packit 90a5c9
static apr_status_t ap_cfg_getline_core(char *buf, apr_size_t bufsize,
Packit 90a5c9
                                        apr_size_t offset, ap_configfile_t *cfp)
Packit 90a5c9
{
Packit 90a5c9
    apr_status_t rc;
Packit 90a5c9
    /* If a "get string" function is defined, use it */
Packit 90a5c9
    if (cfp->getstr != NULL) {
Packit 90a5c9
        char *cp;
Packit 90a5c9
        char *cbuf = buf + offset;
Packit 90a5c9
        apr_size_t cbufsize = bufsize - offset;
Packit 90a5c9
Packit 90a5c9
        while (1) {
Packit 90a5c9
            ++cfp->line_number;
Packit 90a5c9
            rc = cfp->getstr(cbuf, cbufsize, cfp->param);
Packit 90a5c9
            if (rc == APR_EOF) {
Packit 90a5c9
                if (cbuf != buf + offset) {
Packit 90a5c9
                    *cbuf = '\0';
Packit 90a5c9
                    break;
Packit 90a5c9
                }
Packit 90a5c9
                else {
Packit 90a5c9
                    return APR_EOF;
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
            if (rc != APR_SUCCESS) {
Packit 90a5c9
                return rc;
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
            /*
Packit 90a5c9
             *  check for line continuation,
Packit 90a5c9
             *  i.e. match [^\\]\\[\r]\n only
Packit 90a5c9
             */
Packit 90a5c9
            cp = cbuf;
Packit 90a5c9
            cp += strlen(cp);
Packit 90a5c9
            if (cp > buf && cp[-1] == LF) {
Packit 90a5c9
                cp--;
Packit 90a5c9
                if (cp > buf && cp[-1] == CR)
Packit 90a5c9
                    cp--;
Packit 90a5c9
                if (cp > buf && cp[-1] == '\\') {
Packit 90a5c9
                    cp--;
Packit 90a5c9
                    /*
Packit 90a5c9
                     * line continuation requested -
Packit 90a5c9
                     * then remove backslash and continue
Packit 90a5c9
                     */
Packit 90a5c9
                    cbufsize -= (cp-cbuf);
Packit 90a5c9
                    cbuf = cp;
Packit 90a5c9
                    continue;
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
            else if (cp - buf >= bufsize - 1) {
Packit 90a5c9
                return APR_ENOSPC;
Packit 90a5c9
            }
Packit 90a5c9
            break;
Packit 90a5c9
        }
Packit 90a5c9
    } else {
Packit 90a5c9
        /* No "get string" function defined; read character by character */
Packit 90a5c9
        apr_size_t i = offset;
Packit 90a5c9
Packit 90a5c9
        if (bufsize < 2) {
Packit 90a5c9
            /* too small, assume caller is crazy */
Packit 90a5c9
            return APR_EINVAL;
Packit 90a5c9
        }
Packit 90a5c9
        buf[offset] = '\0';
Packit 90a5c9
Packit 90a5c9
        while (1) {
Packit 90a5c9
            char c;
Packit 90a5c9
            rc = cfp->getch(&c, cfp->param);
Packit 90a5c9
            if (rc == APR_EOF) {
Packit 90a5c9
                if (i > offset)
Packit 90a5c9
                    break;
Packit 90a5c9
                else
Packit 90a5c9
                    return APR_EOF;
Packit 90a5c9
            }
Packit 90a5c9
            if (rc != APR_SUCCESS)
Packit 90a5c9
                return rc;
Packit 90a5c9
            if (c == LF) {
Packit 90a5c9
                ++cfp->line_number;
Packit 90a5c9
                /* check for line continuation */
Packit 90a5c9
                if (i > 0 && buf[i-1] == '\\') {
Packit 90a5c9
                    i--;
Packit 90a5c9
                    continue;
Packit 90a5c9
                }
Packit 90a5c9
                else {
Packit 90a5c9
                    break;
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
            buf[i] = c;
Packit 90a5c9
            ++i;
Packit 90a5c9
            if (i >= bufsize - 1) {
Packit 90a5c9
                return APR_ENOSPC;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        buf[i] = '\0';
Packit 90a5c9
    }
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int cfg_trim_line(char *buf)
Packit 90a5c9
{
Packit 90a5c9
    char *start, *end;
Packit 90a5c9
    /*
Packit 90a5c9
     * Leading and trailing white space is eliminated completely
Packit 90a5c9
     */
Packit 90a5c9
    start = buf;
Packit 90a5c9
    while (apr_isspace(*start))
Packit 90a5c9
        ++start;
Packit 90a5c9
    /* blast trailing whitespace */
Packit 90a5c9
    end = &start[strlen(start)];
Packit 90a5c9
    while (--end >= start && apr_isspace(*end))
Packit 90a5c9
        *end = '\0';
Packit 90a5c9
    /* Zap leading whitespace by shifting */
Packit 90a5c9
    if (start != buf)
Packit 90a5c9
        memmove(buf, start, end - start + 2);
Packit 90a5c9
#ifdef DEBUG_CFG_LINES
Packit 90a5c9
    ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, APLOGNO(00555) "Read config: '%s'", buf);
Packit 90a5c9
#endif
Packit 90a5c9
    return end - start + 1;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Read one line from open ap_configfile_t, strip LF, increase line number */
Packit 90a5c9
/* If custom handler does not define a getstr() function, read char by char */
Packit 90a5c9
AP_DECLARE(apr_status_t) ap_cfg_getline(char *buf, apr_size_t bufsize,
Packit 90a5c9
                                        ap_configfile_t *cfp)
Packit 90a5c9
{
Packit 90a5c9
    apr_status_t rc = ap_cfg_getline_core(buf, bufsize, 0, cfp);
Packit 90a5c9
    if (rc == APR_SUCCESS)
Packit 90a5c9
        cfg_trim_line(buf);
Packit 90a5c9
    return rc;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(apr_status_t) ap_varbuf_cfg_getline(struct ap_varbuf *vb,
Packit 90a5c9
                                               ap_configfile_t *cfp,
Packit 90a5c9
                                               apr_size_t max_len)
Packit 90a5c9
{
Packit 90a5c9
    apr_status_t rc;
Packit 90a5c9
    apr_size_t new_len;
Packit 90a5c9
    vb->strlen = 0;
Packit 90a5c9
    *vb->buf = '\0';
Packit 90a5c9
Packit 90a5c9
    if (vb->strlen == AP_VARBUF_UNKNOWN)
Packit 90a5c9
        vb->strlen = strlen(vb->buf);
Packit 90a5c9
    if (vb->avail - vb->strlen < 3) {
Packit 90a5c9
        new_len = vb->avail * 2;
Packit 90a5c9
        if (new_len > max_len)
Packit 90a5c9
            new_len = max_len;
Packit 90a5c9
        else if (new_len < 3)
Packit 90a5c9
            new_len = 3;
Packit 90a5c9
        ap_varbuf_grow(vb, new_len);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    for (;;) {
Packit 90a5c9
        rc = ap_cfg_getline_core(vb->buf, vb->avail, vb->strlen, cfp);
Packit 90a5c9
        if (rc == APR_ENOSPC || rc == APR_SUCCESS)
Packit 90a5c9
            vb->strlen += strlen(vb->buf + vb->strlen);
Packit 90a5c9
        if (rc != APR_ENOSPC)
Packit 90a5c9
            break;
Packit 90a5c9
        if (vb->avail >= max_len)
Packit 90a5c9
            return APR_ENOSPC;
Packit 90a5c9
        new_len = vb->avail * 2;
Packit 90a5c9
        if (new_len > max_len)
Packit 90a5c9
            new_len = max_len;
Packit 90a5c9
        ap_varbuf_grow(vb, new_len);
Packit 90a5c9
        --cfp->line_number;
Packit 90a5c9
    }
Packit 90a5c9
    if (vb->strlen > max_len)
Packit 90a5c9
        return APR_ENOSPC;
Packit 90a5c9
    if (rc == APR_SUCCESS)
Packit 90a5c9
        vb->strlen = cfg_trim_line(vb->buf);
Packit 90a5c9
    return rc;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Size an HTTP header field list item, as separated by a comma.
Packit 90a5c9
 * The return value is a pointer to the beginning of the non-empty list item
Packit 90a5c9
 * within the original string (or NULL if there is none) and the address
Packit 90a5c9
 * of field is shifted to the next non-comma, non-whitespace character.
Packit 90a5c9
 * len is the length of the item excluding any beginning whitespace.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(const char *) ap_size_list_item(const char **field, int *len)
Packit 90a5c9
{
Packit 90a5c9
    const unsigned char *ptr = (const unsigned char *)*field;
Packit 90a5c9
    const unsigned char *token;
Packit 90a5c9
    int in_qpair, in_qstr, in_com;
Packit 90a5c9
Packit 90a5c9
    /* Find first non-comma, non-whitespace byte */
Packit 90a5c9
Packit 90a5c9
    while (*ptr == ',' || apr_isspace(*ptr))
Packit 90a5c9
        ++ptr;
Packit 90a5c9
Packit 90a5c9
    token = ptr;
Packit 90a5c9
Packit 90a5c9
    /* Find the end of this item, skipping over dead bits */
Packit 90a5c9
Packit 90a5c9
    for (in_qpair = in_qstr = in_com = 0;
Packit 90a5c9
         *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
Packit 90a5c9
         ++ptr) {
Packit 90a5c9
Packit 90a5c9
        if (in_qpair) {
Packit 90a5c9
            in_qpair = 0;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            switch (*ptr) {
Packit 90a5c9
                case '\\': in_qpair = 1;      /* quoted-pair         */
Packit 90a5c9
                           break;
Packit 90a5c9
                case '"' : if (!in_com)       /* quoted string delim */
Packit 90a5c9
                               in_qstr = !in_qstr;
Packit 90a5c9
                           break;
Packit 90a5c9
                case '(' : if (!in_qstr)      /* comment (may nest)  */
Packit 90a5c9
                               ++in_com;
Packit 90a5c9
                           break;
Packit 90a5c9
                case ')' : if (in_com)        /* end comment         */
Packit 90a5c9
                               --in_com;
Packit 90a5c9
                           break;
Packit 90a5c9
                default  : break;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if ((*len = (ptr - token)) == 0) {
Packit 90a5c9
        *field = (const char *)ptr;
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* Advance field pointer to the next non-comma, non-white byte */
Packit 90a5c9
Packit 90a5c9
    while (*ptr == ',' || apr_isspace(*ptr))
Packit 90a5c9
        ++ptr;
Packit 90a5c9
Packit 90a5c9
    *field = (const char *)ptr;
Packit 90a5c9
    return (const char *)token;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Retrieve an HTTP header field list item, as separated by a comma,
Packit 90a5c9
 * while stripping insignificant whitespace and lowercasing anything not in
Packit 90a5c9
 * a quoted string or comment.  The return value is a new string containing
Packit 90a5c9
 * the converted list item (or NULL if none) and the address pointed to by
Packit 90a5c9
 * field is shifted to the next non-comma, non-whitespace.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field)
Packit 90a5c9
{
Packit 90a5c9
    const char *tok_start;
Packit 90a5c9
    const unsigned char *ptr;
Packit 90a5c9
    unsigned char *pos;
Packit 90a5c9
    char *token;
Packit 90a5c9
    int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0;
Packit 90a5c9
Packit 90a5c9
    /* Find the beginning and maximum length of the list item so that
Packit 90a5c9
     * we can allocate a buffer for the new string and reset the field.
Packit 90a5c9
     */
Packit 90a5c9
    if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) {
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
    token = apr_palloc(p, tok_len + 1);
Packit 90a5c9
Packit 90a5c9
    /* Scan the token again, but this time copy only the good bytes.
Packit 90a5c9
     * We skip extra whitespace and any whitespace around a '=', '/',
Packit 90a5c9
     * or ';' and lowercase normal characters not within a comment,
Packit 90a5c9
     * quoted-string or quoted-pair.
Packit 90a5c9
     */
Packit 90a5c9
    for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token;
Packit 90a5c9
         *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
Packit 90a5c9
         ++ptr) {
Packit 90a5c9
Packit 90a5c9
        if (in_qpair) {
Packit 90a5c9
            in_qpair = 0;
Packit 90a5c9
            *pos++ = *ptr;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            switch (*ptr) {
Packit 90a5c9
                case '\\': in_qpair = 1;
Packit 90a5c9
                           if (addspace == 1)
Packit 90a5c9
                               *pos++ = ' ';
Packit 90a5c9
                           *pos++ = *ptr;
Packit 90a5c9
                           addspace = 0;
Packit 90a5c9
                           break;
Packit 90a5c9
                case '"' : if (!in_com)
Packit 90a5c9
                               in_qstr = !in_qstr;
Packit 90a5c9
                           if (addspace == 1)
Packit 90a5c9
                               *pos++ = ' ';
Packit 90a5c9
                           *pos++ = *ptr;
Packit 90a5c9
                           addspace = 0;
Packit 90a5c9
                           break;
Packit 90a5c9
                case '(' : if (!in_qstr)
Packit 90a5c9
                               ++in_com;
Packit 90a5c9
                           if (addspace == 1)
Packit 90a5c9
                               *pos++ = ' ';
Packit 90a5c9
                           *pos++ = *ptr;
Packit 90a5c9
                           addspace = 0;
Packit 90a5c9
                           break;
Packit 90a5c9
                case ')' : if (in_com)
Packit 90a5c9
                               --in_com;
Packit 90a5c9
                           *pos++ = *ptr;
Packit 90a5c9
                           addspace = 0;
Packit 90a5c9
                           break;
Packit 90a5c9
                case ' ' :
Packit 90a5c9
                case '\t': if (addspace)
Packit 90a5c9
                               break;
Packit 90a5c9
                           if (in_com || in_qstr)
Packit 90a5c9
                               *pos++ = *ptr;
Packit 90a5c9
                           else
Packit 90a5c9
                               addspace = 1;
Packit 90a5c9
                           break;
Packit 90a5c9
                case '=' :
Packit 90a5c9
                case '/' :
Packit 90a5c9
                case ';' : if (!(in_com || in_qstr))
Packit 90a5c9
                               addspace = -1;
Packit 90a5c9
                           *pos++ = *ptr;
Packit 90a5c9
                           break;
Packit 90a5c9
                default  : if (addspace == 1)
Packit 90a5c9
                               *pos++ = ' ';
Packit 90a5c9
                           *pos++ = (in_com || in_qstr) ? *ptr
Packit 90a5c9
                                                        : apr_tolower(*ptr);
Packit 90a5c9
                           addspace = 0;
Packit 90a5c9
                           break;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    *pos = '\0';
Packit 90a5c9
Packit 90a5c9
    return token;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
typedef enum ap_etag_e {
Packit 90a5c9
    AP_ETAG_NONE,
Packit 90a5c9
    AP_ETAG_WEAK,
Packit 90a5c9
    AP_ETAG_STRONG
Packit 90a5c9
} ap_etag_e;
Packit 90a5c9
Packit 90a5c9
/* Find an item in canonical form (lowercase, no extra spaces) within
Packit 90a5c9
 * an HTTP field value list.  Returns 1 if found, 0 if not found.
Packit 90a5c9
 * This would be much more efficient if we stored header fields as
Packit 90a5c9
 * an array of list items as they are received instead of a plain string.
Packit 90a5c9
 */
Packit 90a5c9
static int find_list_item(apr_pool_t *p, const char *line,
Packit 90a5c9
                                  const char *tok, ap_etag_e type)
Packit 90a5c9
{
Packit 90a5c9
    const unsigned char *pos;
Packit 90a5c9
    const unsigned char *ptr = (const unsigned char *)line;
Packit 90a5c9
    int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0;
Packit 90a5c9
Packit 90a5c9
    if (!line || !tok) {
Packit 90a5c9
        return 0;
Packit 90a5c9
    }
Packit 90a5c9
    if (type == AP_ETAG_STRONG && *tok != '\"') {
Packit 90a5c9
        return 0;
Packit 90a5c9
    }
Packit 90a5c9
    if (type == AP_ETAG_WEAK) {
Packit 90a5c9
        if (*tok == 'W' && (*(tok+1)) == '/' && (*(tok+2)) == '\"') {
Packit 90a5c9
            tok += 2;
Packit 90a5c9
        }
Packit 90a5c9
        else if (*tok != '\"') {
Packit 90a5c9
            return 0;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    do {  /* loop for each item in line's list */
Packit 90a5c9
Packit 90a5c9
        /* Find first non-comma, non-whitespace byte */
Packit 90a5c9
        while (*ptr == ',' || apr_isspace(*ptr)) {
Packit 90a5c9
            ++ptr;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        /* Account for strong or weak Etags, depending on our search */
Packit 90a5c9
        if (type == AP_ETAG_STRONG && *ptr != '\"') {
Packit 90a5c9
            break;
Packit 90a5c9
        }
Packit 90a5c9
        if (type == AP_ETAG_WEAK) {
Packit 90a5c9
            if (*ptr == 'W' && (*(ptr+1)) == '/' && (*(ptr+2)) == '\"') {
Packit 90a5c9
                ptr += 2;
Packit 90a5c9
            }
Packit 90a5c9
            else if (*ptr != '\"') {
Packit 90a5c9
                break;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        if (*ptr)
Packit 90a5c9
            good = 1;  /* until proven otherwise for this item */
Packit 90a5c9
        else
Packit 90a5c9
            break;     /* no items left and nothing good found */
Packit 90a5c9
Packit 90a5c9
        /* We skip extra whitespace and any whitespace around a '=', '/',
Packit 90a5c9
         * or ';' and lowercase normal characters not within a comment,
Packit 90a5c9
         * quoted-string or quoted-pair.
Packit 90a5c9
         */
Packit 90a5c9
        for (pos = (const unsigned char *)tok;
Packit 90a5c9
             *ptr && (in_qpair || in_qstr || in_com || *ptr != ',');
Packit 90a5c9
             ++ptr) {
Packit 90a5c9
Packit 90a5c9
            if (in_qpair) {
Packit 90a5c9
                in_qpair = 0;
Packit 90a5c9
                if (good)
Packit 90a5c9
                    good = (*pos++ == *ptr);
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                switch (*ptr) {
Packit 90a5c9
                    case '\\': in_qpair = 1;
Packit 90a5c9
                               if (addspace == 1)
Packit 90a5c9
                                   good = good && (*pos++ == ' ');
Packit 90a5c9
                               good = good && (*pos++ == *ptr);
Packit 90a5c9
                               addspace = 0;
Packit 90a5c9
                               break;
Packit 90a5c9
                    case '"' : if (!in_com)
Packit 90a5c9
                                   in_qstr = !in_qstr;
Packit 90a5c9
                               if (addspace == 1)
Packit 90a5c9
                                   good = good && (*pos++ == ' ');
Packit 90a5c9
                               good = good && (*pos++ == *ptr);
Packit 90a5c9
                               addspace = 0;
Packit 90a5c9
                               break;
Packit 90a5c9
                    case '(' : if (!in_qstr)
Packit 90a5c9
                                   ++in_com;
Packit 90a5c9
                               if (addspace == 1)
Packit 90a5c9
                                   good = good && (*pos++ == ' ');
Packit 90a5c9
                               good = good && (*pos++ == *ptr);
Packit 90a5c9
                               addspace = 0;
Packit 90a5c9
                               break;
Packit 90a5c9
                    case ')' : if (in_com)
Packit 90a5c9
                                   --in_com;
Packit 90a5c9
                               good = good && (*pos++ == *ptr);
Packit 90a5c9
                               addspace = 0;
Packit 90a5c9
                               break;
Packit 90a5c9
                    case ' ' :
Packit 90a5c9
                    case '\t': if (addspace || !good)
Packit 90a5c9
                                   break;
Packit 90a5c9
                               if (in_com || in_qstr)
Packit 90a5c9
                                   good = (*pos++ == *ptr);
Packit 90a5c9
                               else
Packit 90a5c9
                                   addspace = 1;
Packit 90a5c9
                               break;
Packit 90a5c9
                    case '=' :
Packit 90a5c9
                    case '/' :
Packit 90a5c9
                    case ';' : if (!(in_com || in_qstr))
Packit 90a5c9
                                   addspace = -1;
Packit 90a5c9
                               good = good && (*pos++ == *ptr);
Packit 90a5c9
                               break;
Packit 90a5c9
                    default  : if (!good)
Packit 90a5c9
                                   break;
Packit 90a5c9
                               if (addspace == 1)
Packit 90a5c9
                                   good = (*pos++ == ' ');
Packit 90a5c9
                               if (in_com || in_qstr)
Packit 90a5c9
                                   good = good && (*pos++ == *ptr);
Packit 90a5c9
                               else
Packit 90a5c9
                                   good = good
Packit 90a5c9
                                       && (apr_tolower(*pos++) == apr_tolower(*ptr));
Packit 90a5c9
                               addspace = 0;
Packit 90a5c9
                               break;
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        if (good && *pos)
Packit 90a5c9
            good = 0;          /* not good if only a prefix was matched */
Packit 90a5c9
Packit 90a5c9
    } while (*ptr && !good);
Packit 90a5c9
Packit 90a5c9
    return good;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Find an item in canonical form (lowercase, no extra spaces) within
Packit 90a5c9
 * an HTTP field value list.  Returns 1 if found, 0 if not found.
Packit 90a5c9
 * This would be much more efficient if we stored header fields as
Packit 90a5c9
 * an array of list items as they are received instead of a plain string.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line,
Packit 90a5c9
                                  const char *tok)
Packit 90a5c9
{
Packit 90a5c9
    return find_list_item(p, line, tok, AP_ETAG_NONE);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Find a strong Etag in canonical form (lowercase, no extra spaces) within
Packit 90a5c9
 * an HTTP field value list.  Returns 1 if found, 0 if not found.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(int) ap_find_etag_strong(apr_pool_t *p, const char *line,
Packit 90a5c9
                                    const char *tok)
Packit 90a5c9
{
Packit 90a5c9
    return find_list_item(p, line, tok, AP_ETAG_STRONG);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Find a weak ETag in canonical form (lowercase, no extra spaces) within
Packit 90a5c9
 * an HTTP field value list.  Returns 1 if found, 0 if not found.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(int) ap_find_etag_weak(apr_pool_t *p, const char *line,
Packit 90a5c9
                                  const char *tok)
Packit 90a5c9
{
Packit 90a5c9
    return find_list_item(p, line, tok, AP_ETAG_WEAK);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Grab a list of tokens of the format 1#token (from RFC7230) */
Packit 90a5c9
AP_DECLARE(const char *) ap_parse_token_list_strict(apr_pool_t *p,
Packit 90a5c9
                                                const char *str_in,
Packit 90a5c9
                                                apr_array_header_t **tokens,
Packit 90a5c9
                                                int skip_invalid)
Packit 90a5c9
{
Packit 90a5c9
    int in_leading_space = 1;
Packit 90a5c9
    int in_trailing_space = 0;
Packit 90a5c9
    int string_end = 0;
Packit 90a5c9
    const char *tok_begin;
Packit 90a5c9
    const char *cur;
Packit 90a5c9
Packit 90a5c9
    if (!str_in) {
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    tok_begin = cur = str_in;
Packit 90a5c9
Packit 90a5c9
    while (!string_end) {
Packit 90a5c9
        const unsigned char c = (unsigned char)*cur;
Packit 90a5c9
Packit 90a5c9
        if (!TEST_CHAR(c, T_HTTP_TOKEN_STOP)) {
Packit 90a5c9
            /* Non-separator character; we are finished with leading
Packit 90a5c9
             * whitespace. We must never have encountered any trailing
Packit 90a5c9
             * whitespace before the delimiter (comma) */
Packit 90a5c9
            in_leading_space = 0;
Packit 90a5c9
            if (in_trailing_space) {
Packit 90a5c9
                return "Encountered illegal whitespace in token";
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        else if (c == ' ' || c == '\t') {
Packit 90a5c9
            /* "Linear whitespace" only includes ASCII CRLF, space, and tab;
Packit 90a5c9
             * we can't get a CRLF since headers are split on them already,
Packit 90a5c9
             * so only look for a space or a tab */
Packit 90a5c9
            if (in_leading_space) {
Packit 90a5c9
                /* We're still in leading whitespace */
Packit 90a5c9
                ++tok_begin;
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                /* We must be in trailing whitespace */
Packit 90a5c9
                ++in_trailing_space;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        else if (c == ',' || c == '\0') {
Packit 90a5c9
            if (!in_leading_space) {
Packit 90a5c9
                /* If we're out of the leading space, we know we've read some
Packit 90a5c9
                 * characters of a token */
Packit 90a5c9
                if (*tokens == NULL) {
Packit 90a5c9
                    *tokens = apr_array_make(p, 4, sizeof(char *));
Packit 90a5c9
                }
Packit 90a5c9
                APR_ARRAY_PUSH(*tokens, char *) =
Packit 90a5c9
                    apr_pstrmemdup((*tokens)->pool, tok_begin,
Packit 90a5c9
                                   (cur - tok_begin) - in_trailing_space);
Packit 90a5c9
            }
Packit 90a5c9
            /* We're allowed to have null elements, just don't add them to the
Packit 90a5c9
             * array */
Packit 90a5c9
Packit 90a5c9
            tok_begin = cur + 1;
Packit 90a5c9
            in_leading_space = 1;
Packit 90a5c9
            in_trailing_space = 0;
Packit 90a5c9
            string_end = (c == '\0');
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            /* Encountered illegal separator char */
Packit 90a5c9
            if (skip_invalid) {
Packit 90a5c9
                /* Skip to the next separator */
Packit 90a5c9
                const char *temp;
Packit 90a5c9
                temp = ap_strchr_c(cur, ',');
Packit 90a5c9
                if(!temp) {
Packit 90a5c9
                    temp = ap_strchr_c(cur, '\0');
Packit 90a5c9
                }
Packit 90a5c9
Packit 90a5c9
                /* Act like we haven't seen a token so we reset */
Packit 90a5c9
                cur = temp - 1;
Packit 90a5c9
                in_leading_space = 1;
Packit 90a5c9
                in_trailing_space = 0;
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                return apr_psprintf(p, "Encountered illegal separator "
Packit 90a5c9
                                    "'\\x%.2x'", (unsigned int)c);
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        ++cur;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Scan a string for HTTP VCHAR/obs-text characters including HT and SP
Packit 90a5c9
 * (as used in header values, for example, in RFC 7230 section 3.2)
Packit 90a5c9
 * returning the pointer to the first non-HT ASCII ctrl character.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(const char *) ap_scan_http_field_content(const char *ptr)
Packit 90a5c9
{
Packit 90a5c9
    for ( ; !TEST_CHAR(*ptr, T_HTTP_CTRLS); ++ptr) ;
Packit 90a5c9
Packit 90a5c9
    return ptr;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Scan a string for HTTP token characters, returning the pointer to
Packit 90a5c9
 * the first non-token character.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(const char *) ap_scan_http_token(const char *ptr)
Packit 90a5c9
{
Packit 90a5c9
    for ( ; !TEST_CHAR(*ptr, T_HTTP_TOKEN_STOP); ++ptr) ;
Packit 90a5c9
Packit 90a5c9
    return ptr;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Scan a string for visible ASCII (0x21-0x7E) or obstext (0x80+)
Packit 90a5c9
 * and return a pointer to the first ctrl/space character encountered.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(const char *) ap_scan_vchar_obstext(const char *ptr)
Packit 90a5c9
{
Packit 90a5c9
    for ( ; TEST_CHAR(*ptr, T_VCHAR_OBSTEXT); ++ptr) ;
Packit 90a5c9
Packit 90a5c9
    return ptr;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Retrieve a token, spacing over it and returning a pointer to
Packit 90a5c9
 * the first non-white byte afterwards.  Note that these tokens
Packit 90a5c9
 * are delimited by semis and commas; and can also be delimited
Packit 90a5c9
 * by whitespace at the caller's option.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line,
Packit 90a5c9
                                int accept_white)
Packit 90a5c9
{
Packit 90a5c9
    const char *ptr = *accept_line;
Packit 90a5c9
    const char *tok_start;
Packit 90a5c9
    char *token;
Packit 90a5c9
Packit 90a5c9
    /* Find first non-white byte */
Packit 90a5c9
Packit 90a5c9
    while (apr_isspace(*ptr))
Packit 90a5c9
        ++ptr;
Packit 90a5c9
Packit 90a5c9
    tok_start = ptr;
Packit 90a5c9
Packit 90a5c9
    /* find token end, skipping over quoted strings.
Packit 90a5c9
     * (comments are already gone).
Packit 90a5c9
     */
Packit 90a5c9
Packit 90a5c9
    while (*ptr && (accept_white || !apr_isspace(*ptr))
Packit 90a5c9
           && *ptr != ';' && *ptr != ',') {
Packit 90a5c9
        if (*ptr++ == '"')
Packit 90a5c9
            while (*ptr)
Packit 90a5c9
                if (*ptr++ == '"')
Packit 90a5c9
                    break;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    token = apr_pstrmemdup(p, tok_start, ptr - tok_start);
Packit 90a5c9
Packit 90a5c9
    /* Advance accept_line pointer to the next non-white byte */
Packit 90a5c9
Packit 90a5c9
    while (apr_isspace(*ptr))
Packit 90a5c9
        ++ptr;
Packit 90a5c9
Packit 90a5c9
    *accept_line = ptr;
Packit 90a5c9
    return token;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/* find http tokens, see the definition of token from RFC2068 */
Packit 90a5c9
AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok)
Packit 90a5c9
{
Packit 90a5c9
    const unsigned char *start_token;
Packit 90a5c9
    const unsigned char *s;
Packit 90a5c9
Packit 90a5c9
    if (!line)
Packit 90a5c9
        return 0;
Packit 90a5c9
Packit 90a5c9
    s = (const unsigned char *)line;
Packit 90a5c9
    for (;;) {
Packit 90a5c9
        /* find start of token, skip all stop characters */
Packit 90a5c9
        while (*s && TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
Packit 90a5c9
            ++s;
Packit 90a5c9
        }
Packit 90a5c9
        if (!*s) {
Packit 90a5c9
            return 0;
Packit 90a5c9
        }
Packit 90a5c9
        start_token = s;
Packit 90a5c9
        /* find end of the token */
Packit 90a5c9
        while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) {
Packit 90a5c9
            ++s;
Packit 90a5c9
        }
Packit 90a5c9
        if (!strncasecmp((const char *)start_token, (const char *)tok,
Packit 90a5c9
                         s - start_token)) {
Packit 90a5c9
            return 1;
Packit 90a5c9
        }
Packit 90a5c9
        if (!*s) {
Packit 90a5c9
            return 0;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line,
Packit 90a5c9
                                   const char *tok)
Packit 90a5c9
{
Packit 90a5c9
    int llen, tlen, lidx;
Packit 90a5c9
Packit 90a5c9
    if (!line)
Packit 90a5c9
        return 0;
Packit 90a5c9
Packit 90a5c9
    llen = strlen(line);
Packit 90a5c9
    tlen = strlen(tok);
Packit 90a5c9
    lidx = llen - tlen;
Packit 90a5c9
Packit 90a5c9
    if (lidx < 0 ||
Packit 90a5c9
        (lidx > 0 && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ',')))
Packit 90a5c9
        return 0;
Packit 90a5c9
Packit 90a5c9
    return (strncasecmp(&line[lidx], tok, tlen) == 0);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str)
Packit 90a5c9
{
Packit 90a5c9
    char *cmd;
Packit 90a5c9
    unsigned char *d;
Packit 90a5c9
    const unsigned char *s;
Packit 90a5c9
Packit 90a5c9
    cmd = apr_palloc(p, 2 * strlen(str) + 1);        /* Be safe */
Packit 90a5c9
    d = (unsigned char *)cmd;
Packit 90a5c9
    s = (const unsigned char *)str;
Packit 90a5c9
    for (; *s; ++s) {
Packit 90a5c9
Packit 90a5c9
#if defined(OS2) || defined(WIN32)
Packit 90a5c9
        /*
Packit 90a5c9
         * Newlines to Win32/OS2 CreateProcess() are ill advised.
Packit 90a5c9
         * Convert them to spaces since they are effectively white
Packit 90a5c9
         * space to most applications
Packit 90a5c9
         */
Packit 90a5c9
        if (*s == '\r' || *s == '\n') {
Packit 90a5c9
             *d++ = ' ';
Packit 90a5c9
             continue;
Packit 90a5c9
         }
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
        if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
Packit 90a5c9
            *d++ = '\\';
Packit 90a5c9
        }
Packit 90a5c9
        *d++ = *s;
Packit 90a5c9
    }
Packit 90a5c9
    *d = '\0';
Packit 90a5c9
Packit 90a5c9
    return cmd;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static char x2c(const char *what)
Packit 90a5c9
{
Packit 90a5c9
    char digit;
Packit 90a5c9
Packit 90a5c9
#if !APR_CHARSET_EBCDIC
Packit 90a5c9
    digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
Packit 90a5c9
             : (what[0] - '0'));
Packit 90a5c9
    digit *= 16;
Packit 90a5c9
    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
Packit 90a5c9
              : (what[1] - '0'));
Packit 90a5c9
#else /*APR_CHARSET_EBCDIC*/
Packit 90a5c9
    char xstr[5];
Packit 90a5c9
    xstr[0]='0';
Packit 90a5c9
    xstr[1]='x';
Packit 90a5c9
    xstr[2]=what[0];
Packit 90a5c9
    xstr[3]=what[1];
Packit 90a5c9
    xstr[4]='\0';
Packit 90a5c9
    digit = apr_xlate_conv_byte(ap_hdrs_from_ascii,
Packit 90a5c9
                                0xFF & strtol(xstr, NULL, 16));
Packit 90a5c9
#endif /*APR_CHARSET_EBCDIC*/
Packit 90a5c9
    return (digit);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Unescapes a URL, leaving reserved characters intact.
Packit 90a5c9
 * Returns 0 on success, non-zero on error
Packit 90a5c9
 * Failure is due to
Packit 90a5c9
 *   bad % escape       returns HTTP_BAD_REQUEST
Packit 90a5c9
 *
Packit 90a5c9
 *   decoding %00 or a forbidden character returns HTTP_NOT_FOUND
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
static int unescape_url(char *url, const char *forbid, const char *reserved)
Packit 90a5c9
{
Packit 90a5c9
    int badesc, badpath;
Packit 90a5c9
    char *x, *y;
Packit 90a5c9
Packit 90a5c9
    badesc = 0;
Packit 90a5c9
    badpath = 0;
Packit 90a5c9
    /* Initial scan for first '%'. Don't bother writing values before
Packit 90a5c9
     * seeing a '%' */
Packit 90a5c9
    y = strchr(url, '%');
Packit 90a5c9
    if (y == NULL) {
Packit 90a5c9
        return OK;
Packit 90a5c9
    }
Packit 90a5c9
    for (x = y; *y; ++x, ++y) {
Packit 90a5c9
        if (*y != '%') {
Packit 90a5c9
            *x = *y;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
Packit 90a5c9
                badesc = 1;
Packit 90a5c9
                *x = '%';
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                char decoded;
Packit 90a5c9
                decoded = x2c(y + 1);
Packit 90a5c9
                if ((decoded == '\0')
Packit 90a5c9
                    || (forbid && ap_strchr_c(forbid, decoded))) {
Packit 90a5c9
                    badpath = 1;
Packit 90a5c9
                    *x = decoded;
Packit 90a5c9
                    y += 2;
Packit 90a5c9
                }
Packit 90a5c9
                else if (reserved && ap_strchr_c(reserved, decoded)) {
Packit 90a5c9
                    *x++ = *y++;
Packit 90a5c9
                    *x++ = *y++;
Packit 90a5c9
                    *x = *y;
Packit 90a5c9
                }
Packit 90a5c9
                else {
Packit 90a5c9
                    *x = decoded;
Packit 90a5c9
                    y += 2;
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    *x = '\0';
Packit 90a5c9
    if (badesc) {
Packit 90a5c9
        return HTTP_BAD_REQUEST;
Packit 90a5c9
    }
Packit 90a5c9
    else if (badpath) {
Packit 90a5c9
        return HTTP_NOT_FOUND;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        return OK;
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
AP_DECLARE(int) ap_unescape_url(char *url)
Packit 90a5c9
{
Packit 90a5c9
    /* Traditional */
Packit 90a5c9
    return unescape_url(url, SLASHES, NULL);
Packit 90a5c9
}
Packit 90a5c9
AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes)
Packit 90a5c9
{
Packit 90a5c9
    /* AllowEncodedSlashes (corrected) */
Packit 90a5c9
    if (decode_slashes) {
Packit 90a5c9
        /* no chars reserved */
Packit 90a5c9
        return unescape_url(url, NULL, NULL);
Packit 90a5c9
    } else {
Packit 90a5c9
        /* reserve (do not decode) encoded slashes */
Packit 90a5c9
        return unescape_url(url, NULL, SLASHES);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
#ifdef NEW_APIS
Packit 90a5c9
/* IFDEF these out until they've been thought through.
Packit 90a5c9
 * Just a germ of an API extension for now
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(int) ap_unescape_url_proxy(char *url)
Packit 90a5c9
{
Packit 90a5c9
    /* leave RFC1738 reserved characters intact, * so proxied URLs
Packit 90a5c9
     * don't get mangled.  Where does that leave encoded '&' ?
Packit 90a5c9
     */
Packit 90a5c9
    return unescape_url(url, NULL, "/;?");
Packit 90a5c9
}
Packit 90a5c9
AP_DECLARE(int) ap_unescape_url_reserved(char *url, const char *reserved)
Packit 90a5c9
{
Packit 90a5c9
    return unescape_url(url, NULL, reserved);
Packit 90a5c9
}
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_unescape_urlencoded(char *query)
Packit 90a5c9
{
Packit 90a5c9
    char *slider;
Packit 90a5c9
Packit 90a5c9
    /* replace plus with a space */
Packit 90a5c9
    if (query) {
Packit 90a5c9
        for (slider = query; *slider; slider++) {
Packit 90a5c9
            if (*slider == '+') {
Packit 90a5c9
                *slider = ' ';
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* unescape everything else */
Packit 90a5c9
    return unescape_url(query, NULL, NULL);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname,
Packit 90a5c9
                                       apr_port_t port, const request_rec *r)
Packit 90a5c9
{
Packit 90a5c9
    if (ap_is_default_port(port, r)) {
Packit 90a5c9
        return apr_pstrdup(p, hostname);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        return apr_psprintf(p, "%s:%u", hostname, port);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_unescape_all(char *url)
Packit 90a5c9
{
Packit 90a5c9
    return unescape_url(url, NULL, NULL);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* c2x takes an unsigned, and expects the caller has guaranteed that
Packit 90a5c9
 * 0 <= what < 256... which usually means that you have to cast to
Packit 90a5c9
 * unsigned char first, because (unsigned)(char)(x) first goes through
Packit 90a5c9
 * signed extension to an int before the unsigned cast.
Packit 90a5c9
 *
Packit 90a5c9
 * The reason for this assumption is to assist gcc code generation --
Packit 90a5c9
 * the unsigned char -> unsigned extension is already done earlier in
Packit 90a5c9
 * both uses of this code, so there's no need to waste time doing it
Packit 90a5c9
 * again.
Packit 90a5c9
 */
Packit 90a5c9
static const char c2x_table[] = "0123456789abcdef";
Packit 90a5c9
Packit 90a5c9
static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
Packit 90a5c9
                                     unsigned char *where)
Packit 90a5c9
{
Packit 90a5c9
#if APR_CHARSET_EBCDIC
Packit 90a5c9
    what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
Packit 90a5c9
#endif /*APR_CHARSET_EBCDIC*/
Packit 90a5c9
    *where++ = prefix;
Packit 90a5c9
    *where++ = c2x_table[what >> 4];
Packit 90a5c9
    *where++ = c2x_table[what & 0xf];
Packit 90a5c9
    return where;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * escape_path_segment() escapes a path segment, as defined in RFC 1808. This
Packit 90a5c9
 * routine is (should be) OS independent.
Packit 90a5c9
 *
Packit 90a5c9
 * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
Packit 90a5c9
 * cases if a ':' occurs before the first '/' in the URL, the URL should be
Packit 90a5c9
 * prefixed with "./" (or the ':' escaped). In the case of Unix, this means
Packit 90a5c9
 * leaving '/' alone, but otherwise doing what escape_path_segment() does. For
Packit 90a5c9
 * efficiency reasons, we don't use escape_path_segment(), which is provided for
Packit 90a5c9
 * reference. Again, RFC 1808 is where this stuff is defined.
Packit 90a5c9
 *
Packit 90a5c9
 * If partial is set, os_escape_path() assumes that the path will be appended to
Packit 90a5c9
 * something with a '/' in it (and thus does not prefix "./").
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_escape_path_segment_buffer(char *copy, const char *segment)
Packit 90a5c9
{
Packit 90a5c9
    const unsigned char *s = (const unsigned char *)segment;
Packit 90a5c9
    unsigned char *d = (unsigned char *)copy;
Packit 90a5c9
    unsigned c;
Packit 90a5c9
Packit 90a5c9
    while ((c = *s)) {
Packit 90a5c9
        if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
Packit 90a5c9
            d = c2x(c, '%', d);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            *d++ = c;
Packit 90a5c9
        }
Packit 90a5c9
        ++s;
Packit 90a5c9
    }
Packit 90a5c9
    *d = '\0';
Packit 90a5c9
    return copy;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment)
Packit 90a5c9
{
Packit 90a5c9
    return ap_escape_path_segment_buffer(apr_palloc(p, 3 * strlen(segment) + 1), segment);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial)
Packit 90a5c9
{
Packit 90a5c9
    char *copy = apr_palloc(p, 3 * strlen(path) + 3);
Packit 90a5c9
    const unsigned char *s = (const unsigned char *)path;
Packit 90a5c9
    unsigned char *d = (unsigned char *)copy;
Packit 90a5c9
    unsigned c;
Packit 90a5c9
Packit 90a5c9
    if (!partial) {
Packit 90a5c9
        const char *colon = ap_strchr_c(path, ':');
Packit 90a5c9
        const char *slash = ap_strchr_c(path, '/');
Packit 90a5c9
Packit 90a5c9
        if (colon && (!slash || colon < slash)) {
Packit 90a5c9
            *d++ = '.';
Packit 90a5c9
            *d++ = '/';
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    while ((c = *s)) {
Packit 90a5c9
        if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
Packit 90a5c9
            d = c2x(c, '%', d);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            *d++ = c;
Packit 90a5c9
        }
Packit 90a5c9
        ++s;
Packit 90a5c9
    }
Packit 90a5c9
    *d = '\0';
Packit 90a5c9
    return copy;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_escape_urlencoded_buffer(char *copy, const char *buffer)
Packit 90a5c9
{
Packit 90a5c9
    const unsigned char *s = (const unsigned char *)buffer;
Packit 90a5c9
    unsigned char *d = (unsigned char *)copy;
Packit 90a5c9
    unsigned c;
Packit 90a5c9
Packit 90a5c9
    while ((c = *s)) {
Packit 90a5c9
        if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
Packit 90a5c9
            d = c2x(c, '%', d);
Packit 90a5c9
        }
Packit 90a5c9
        else if (c == ' ') {
Packit 90a5c9
            *d++ = '+';
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            *d++ = c;
Packit 90a5c9
        }
Packit 90a5c9
        ++s;
Packit 90a5c9
    }
Packit 90a5c9
    *d = '\0';
Packit 90a5c9
    return copy;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
Packit 90a5c9
{
Packit 90a5c9
    return ap_escape_urlencoded_buffer(apr_palloc(p, 3 * strlen(buffer) + 1), buffer);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* ap_escape_uri is now a macro for os_escape_path */
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
Packit 90a5c9
{
Packit 90a5c9
    int i, j;
Packit 90a5c9
    char *x;
Packit 90a5c9
Packit 90a5c9
    /* first, count the number of extra characters */
Packit 90a5c9
    for (i = 0, j = 0; s[i] != '\0'; i++)
Packit 90a5c9
        if (s[i] == '<' || s[i] == '>')
Packit 90a5c9
            j += 3;
Packit 90a5c9
        else if (s[i] == '&')
Packit 90a5c9
            j += 4;
Packit 90a5c9
        else if (s[i] == '"')
Packit 90a5c9
            j += 5;
Packit 90a5c9
        else if (toasc && !apr_isascii(s[i]))
Packit 90a5c9
            j += 5;
Packit 90a5c9
Packit 90a5c9
    if (j == 0)
Packit 90a5c9
        return apr_pstrmemdup(p, s, i);
Packit 90a5c9
Packit 90a5c9
    x = apr_palloc(p, i + j + 1);
Packit 90a5c9
    for (i = 0, j = 0; s[i] != '\0'; i++, j++)
Packit 90a5c9
        if (s[i] == '<') {
Packit 90a5c9
            memcpy(&x[j], "<", 4);
Packit 90a5c9
            j += 3;
Packit 90a5c9
        }
Packit 90a5c9
        else if (s[i] == '>') {
Packit 90a5c9
            memcpy(&x[j], ">", 4);
Packit 90a5c9
            j += 3;
Packit 90a5c9
        }
Packit 90a5c9
        else if (s[i] == '&') {
Packit 90a5c9
            memcpy(&x[j], "&", 5);
Packit 90a5c9
            j += 4;
Packit 90a5c9
        }
Packit 90a5c9
        else if (s[i] == '"') {
Packit 90a5c9
            memcpy(&x[j], """, 6);
Packit 90a5c9
            j += 5;
Packit 90a5c9
        }
Packit 90a5c9
        else if (toasc && !apr_isascii(s[i])) {
Packit 90a5c9
            char *esc = apr_psprintf(p, "&#%3.3d;", (unsigned char)s[i]);
Packit 90a5c9
            memcpy(&x[j], esc, 6);
Packit 90a5c9
            j += 5;
Packit 90a5c9
        }
Packit 90a5c9
        else
Packit 90a5c9
            x[j] = s[i];
Packit 90a5c9
Packit 90a5c9
    x[j] = '\0';
Packit 90a5c9
    return x;
Packit 90a5c9
}
Packit 90a5c9
AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str)
Packit 90a5c9
{
Packit 90a5c9
    char *ret;
Packit 90a5c9
    unsigned char *d;
Packit 90a5c9
    const unsigned char *s;
Packit 90a5c9
    apr_size_t length, escapes = 0;
Packit 90a5c9
Packit 90a5c9
    if (!str) {
Packit 90a5c9
        return NULL;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* Compute how many characters need to be escaped */
Packit 90a5c9
    s = (const unsigned char *)str;
Packit 90a5c9
    for (; *s; ++s) {
Packit 90a5c9
        if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
Packit 90a5c9
            escapes++;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    /* Compute the length of the input string, including NULL */
Packit 90a5c9
    length = s - (const unsigned char *)str + 1;
Packit 90a5c9
    
Packit 90a5c9
    /* Fast path: nothing to escape */
Packit 90a5c9
    if (escapes == 0) {
Packit 90a5c9
        return apr_pmemdup(p, str, length);
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    /* Each escaped character needs up to 3 extra bytes (0 --> \x00) */
Packit 90a5c9
    ret = apr_palloc(p, length + 3 * escapes);
Packit 90a5c9
    d = (unsigned char *)ret;
Packit 90a5c9
    s = (const unsigned char *)str;
Packit 90a5c9
    for (; *s; ++s) {
Packit 90a5c9
        if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
Packit 90a5c9
            *d++ = '\\';
Packit 90a5c9
            switch(*s) {
Packit 90a5c9
            case '\b':
Packit 90a5c9
                *d++ = 'b';
Packit 90a5c9
                break;
Packit 90a5c9
            case '\n':
Packit 90a5c9
                *d++ = 'n';
Packit 90a5c9
                break;
Packit 90a5c9
            case '\r':
Packit 90a5c9
                *d++ = 'r';
Packit 90a5c9
                break;
Packit 90a5c9
            case '\t':
Packit 90a5c9
                *d++ = 't';
Packit 90a5c9
                break;
Packit 90a5c9
            case '\v':
Packit 90a5c9
                *d++ = 'v';
Packit 90a5c9
                break;
Packit 90a5c9
            case '\\':
Packit 90a5c9
            case '"':
Packit 90a5c9
                *d++ = *s;
Packit 90a5c9
                break;
Packit 90a5c9
            default:
Packit 90a5c9
                c2x(*s, 'x', d);
Packit 90a5c9
                d += 3;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            *d++ = *s;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    *d = '\0';
Packit 90a5c9
Packit 90a5c9
    return ret;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
Packit 90a5c9
                                               apr_size_t buflen)
Packit 90a5c9
{
Packit 90a5c9
    unsigned char *d, *ep;
Packit 90a5c9
    const unsigned char *s;
Packit 90a5c9
Packit 90a5c9
    if (!source || !buflen) { /* be safe */
Packit 90a5c9
        return 0;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    d = (unsigned char *)dest;
Packit 90a5c9
    s = (const unsigned char *)source;
Packit 90a5c9
    ep = d + buflen - 1;
Packit 90a5c9
Packit 90a5c9
    for (; d < ep && *s; ++s) {
Packit 90a5c9
Packit 90a5c9
        if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
Packit 90a5c9
            *d++ = '\\';
Packit 90a5c9
            if (d >= ep) {
Packit 90a5c9
                --d;
Packit 90a5c9
                break;
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
            switch(*s) {
Packit 90a5c9
            case '\b':
Packit 90a5c9
                *d++ = 'b';
Packit 90a5c9
                break;
Packit 90a5c9
            case '\n':
Packit 90a5c9
                *d++ = 'n';
Packit 90a5c9
                break;
Packit 90a5c9
            case '\r':
Packit 90a5c9
                *d++ = 'r';
Packit 90a5c9
                break;
Packit 90a5c9
            case '\t':
Packit 90a5c9
                *d++ = 't';
Packit 90a5c9
                break;
Packit 90a5c9
            case '\v':
Packit 90a5c9
                *d++ = 'v';
Packit 90a5c9
                break;
Packit 90a5c9
            case '\\':
Packit 90a5c9
                *d++ = *s;
Packit 90a5c9
                break;
Packit 90a5c9
            case '"': /* no need for this in error log */
Packit 90a5c9
                d[-1] = *s;
Packit 90a5c9
                break;
Packit 90a5c9
            default:
Packit 90a5c9
                if (d >= ep - 2) {
Packit 90a5c9
                    ep = --d; /* break the for loop as well */
Packit 90a5c9
                    break;
Packit 90a5c9
                }
Packit 90a5c9
                c2x(*s, 'x', d);
Packit 90a5c9
                d += 3;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            *d++ = *s;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    *d = '\0';
Packit 90a5c9
Packit 90a5c9
    return (d - (unsigned char *)dest);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_bin2hex(const void *src, apr_size_t srclen, char *dest)
Packit 90a5c9
{
Packit 90a5c9
    const unsigned char *in = src;
Packit 90a5c9
    apr_size_t i;
Packit 90a5c9
Packit 90a5c9
    for (i = 0; i < srclen; i++) {
Packit 90a5c9
        *dest++ = c2x_table[in[i] >> 4];
Packit 90a5c9
        *dest++ = c2x_table[in[i] & 0xf];
Packit 90a5c9
    }
Packit 90a5c9
    *dest = '\0';
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
Packit 90a5c9
{
Packit 90a5c9
    apr_finfo_t finfo;
Packit 90a5c9
Packit 90a5c9
    if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS)
Packit 90a5c9
        return 0;                /* in error condition, just return no */
Packit 90a5c9
Packit 90a5c9
    return (finfo.filetype == APR_DIR);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_is_rdirectory(apr_pool_t *p, const char *path)
Packit 90a5c9
{
Packit 90a5c9
    apr_finfo_t finfo;
Packit 90a5c9
Packit 90a5c9
    if (apr_stat(&finfo, path, APR_FINFO_LINK | APR_FINFO_TYPE, p) != APR_SUCCESS)
Packit 90a5c9
        return 0;                /* in error condition, just return no */
Packit 90a5c9
Packit 90a5c9
    return (finfo.filetype == APR_DIR);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1,
Packit 90a5c9
                                  const char *src2)
Packit 90a5c9
{
Packit 90a5c9
    apr_size_t len1, len2;
Packit 90a5c9
    char *path;
Packit 90a5c9
Packit 90a5c9
    len1 = strlen(src1);
Packit 90a5c9
    len2 = strlen(src2);
Packit 90a5c9
     /* allocate +3 for '/' delimiter, trailing NULL and overallocate
Packit 90a5c9
      * one extra byte to allow the caller to add a trailing '/'
Packit 90a5c9
      */
Packit 90a5c9
    path = (char *)apr_palloc(a, len1 + len2 + 3);
Packit 90a5c9
    if (len1 == 0) {
Packit 90a5c9
        *path = '/';
Packit 90a5c9
        memcpy(path + 1, src2, len2 + 1);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        char *next;
Packit 90a5c9
        memcpy(path, src1, len1);
Packit 90a5c9
        next = path + len1;
Packit 90a5c9
        if (next[-1] != '/') {
Packit 90a5c9
            *next++ = '/';
Packit 90a5c9
        }
Packit 90a5c9
        memcpy(next, src2, len2 + 1);
Packit 90a5c9
    }
Packit 90a5c9
    return path;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Check for an absoluteURI syntax (see section 3.2 in RFC2068).
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(int) ap_is_url(const char *u)
Packit 90a5c9
{
Packit 90a5c9
    int x;
Packit 90a5c9
Packit 90a5c9
    for (x = 0; u[x] != ':'; x++) {
Packit 90a5c9
        if ((!u[x]) ||
Packit 90a5c9
            ((!apr_isalnum(u[x])) &&
Packit 90a5c9
             (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) {
Packit 90a5c9
            return 0;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return (x ? 1 : 0);                /* If the first character is ':', it's broken, too */
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_ind(const char *s, char c)
Packit 90a5c9
{
Packit 90a5c9
    const char *p = ap_strchr_c(s, c);
Packit 90a5c9
Packit 90a5c9
    if (p == NULL)
Packit 90a5c9
        return -1;
Packit 90a5c9
    return p - s;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_rind(const char *s, char c)
Packit 90a5c9
{
Packit 90a5c9
    const char *p = ap_strrchr_c(s, c);
Packit 90a5c9
Packit 90a5c9
    if (p == NULL)
Packit 90a5c9
        return -1;
Packit 90a5c9
    return p - s;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_str_tolower(char *str)
Packit 90a5c9
{
Packit 90a5c9
    while (*str) {
Packit 90a5c9
        *str = apr_tolower(*str);
Packit 90a5c9
        ++str;
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_str_toupper(char *str)
Packit 90a5c9
{
Packit 90a5c9
    while (*str) {
Packit 90a5c9
        *str = apr_toupper(*str);
Packit 90a5c9
        ++str;
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * We must return a FQDN
Packit 90a5c9
 */
Packit 90a5c9
char *ap_get_local_host(apr_pool_t *a)
Packit 90a5c9
{
Packit 90a5c9
#ifndef MAXHOSTNAMELEN
Packit 90a5c9
#define MAXHOSTNAMELEN 256
Packit 90a5c9
#endif
Packit 90a5c9
    char str[MAXHOSTNAMELEN + 1];
Packit 90a5c9
    char *server_hostname = NULL;
Packit 90a5c9
    apr_sockaddr_t *sockaddr;
Packit 90a5c9
    char *hostname;
Packit 90a5c9
Packit 90a5c9
    if (apr_gethostname(str, sizeof(str) - 1, a) != APR_SUCCESS) {
Packit 90a5c9
        ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00556)
Packit 90a5c9
                     "%s: apr_gethostname() failed to determine ServerName",
Packit 90a5c9
                     ap_server_argv0);
Packit 90a5c9
    } else {
Packit 90a5c9
        str[sizeof(str) - 1] = '\0';
Packit 90a5c9
        if (apr_sockaddr_info_get(&sockaddr, str, APR_UNSPEC, 0, 0, a) == APR_SUCCESS) {
Packit 90a5c9
            if ( (apr_getnameinfo(&hostname, sockaddr, 0) == APR_SUCCESS) &&
Packit 90a5c9
                (ap_strchr_c(hostname, '.')) ) {
Packit 90a5c9
                server_hostname = apr_pstrdup(a, hostname);
Packit 90a5c9
                return server_hostname;
Packit 90a5c9
            } else if (ap_strchr_c(str, '.')) {
Packit 90a5c9
                server_hostname = apr_pstrdup(a, str);
Packit 90a5c9
            } else {
Packit 90a5c9
                apr_sockaddr_ip_get(&hostname, sockaddr);
Packit 90a5c9
                server_hostname = apr_pstrdup(a, hostname);
Packit 90a5c9
            }
Packit 90a5c9
        } else {
Packit 90a5c9
            ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, APLOGNO(00557)
Packit 90a5c9
                         "%s: apr_sockaddr_info_get() failed for %s",
Packit 90a5c9
                         ap_server_argv0, str);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (!server_hostname)
Packit 90a5c9
        server_hostname = apr_pstrdup(a, "127.0.0.1");
Packit 90a5c9
Packit 90a5c9
    ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0, a, APLOGNO(00558)
Packit 90a5c9
                 "%s: Could not reliably determine the server's fully qualified "
Packit 90a5c9
                 "domain name, using %s. Set the 'ServerName' directive globally "
Packit 90a5c9
                 "to suppress this message",
Packit 90a5c9
                 ap_server_argv0, server_hostname);
Packit 90a5c9
Packit 90a5c9
    return server_hostname;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* simple 'pool' alloc()ing glue to apr_base64.c
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
Packit 90a5c9
{
Packit 90a5c9
    char *decoded;
Packit 90a5c9
    int l;
Packit 90a5c9
Packit 90a5c9
    decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded));
Packit 90a5c9
    l = apr_base64_decode(decoded, bufcoded);
Packit 90a5c9
    decoded[l] = '\0'; /* make binary sequence into string */
Packit 90a5c9
Packit 90a5c9
    return decoded;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
Packit 90a5c9
{
Packit 90a5c9
    char *encoded;
Packit 90a5c9
    int l = strlen(string);
Packit 90a5c9
Packit 90a5c9
    encoded = (char *) apr_palloc(p, 1 + apr_base64_encode_len(l));
Packit 90a5c9
    l = apr_base64_encode(encoded, string, l);
Packit 90a5c9
    encoded[l] = '\0'; /* make binary sequence into string */
Packit 90a5c9
Packit 90a5c9
    return encoded;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* we want to downcase the type/subtype for comparison purposes
Packit 90a5c9
 * but nothing else because ;parameter=foo values are case sensitive.
Packit 90a5c9
 * XXX: in truth we want to downcase parameter names... but really,
Packit 90a5c9
 * apache has never handled parameters and such correctly.  You
Packit 90a5c9
 * also need to compress spaces and such to be able to compare
Packit 90a5c9
 * properly. -djg
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(void) ap_content_type_tolower(char *str)
Packit 90a5c9
{
Packit 90a5c9
    char *semi;
Packit 90a5c9
Packit 90a5c9
    semi = strchr(str, ';');
Packit 90a5c9
    if (semi) {
Packit 90a5c9
        *semi = '\0';
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    ap_str_tolower(str);
Packit 90a5c9
Packit 90a5c9
    if (semi) {
Packit 90a5c9
        *semi = ';';
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Given a string, replace any bare " with \" .
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring)
Packit 90a5c9
{
Packit 90a5c9
    int newlen = 0;
Packit 90a5c9
    const char *inchr = instring;
Packit 90a5c9
    char *outchr, *outstring;
Packit 90a5c9
Packit 90a5c9
    /*
Packit 90a5c9
     * Look through the input string, jogging the length of the output
Packit 90a5c9
     * string up by an extra byte each time we find an unescaped ".
Packit 90a5c9
     */
Packit 90a5c9
    while (*inchr != '\0') {
Packit 90a5c9
        newlen++;
Packit 90a5c9
        if (*inchr == '"') {
Packit 90a5c9
            newlen++;
Packit 90a5c9
        }
Packit 90a5c9
        /*
Packit 90a5c9
         * If we find a slosh, and it's not the last byte in the string,
Packit 90a5c9
         * it's escaping something - advance past both bytes.
Packit 90a5c9
         */
Packit 90a5c9
        if ((*inchr == '\\') && (inchr[1] != '\0')) {
Packit 90a5c9
            inchr++;
Packit 90a5c9
            newlen++;
Packit 90a5c9
        }
Packit 90a5c9
        inchr++;
Packit 90a5c9
    }
Packit 90a5c9
    outstring = apr_palloc(p, newlen + 1);
Packit 90a5c9
    inchr = instring;
Packit 90a5c9
    outchr = outstring;
Packit 90a5c9
    /*
Packit 90a5c9
     * Now copy the input string to the output string, inserting a slosh
Packit 90a5c9
     * in front of every " that doesn't already have one.
Packit 90a5c9
     */
Packit 90a5c9
    while (*inchr != '\0') {
Packit 90a5c9
        if ((*inchr == '\\') && (inchr[1] != '\0')) {
Packit 90a5c9
            *outchr++ = *inchr++;
Packit 90a5c9
            *outchr++ = *inchr++;
Packit 90a5c9
        }
Packit 90a5c9
        if (*inchr == '"') {
Packit 90a5c9
            *outchr++ = '\\';
Packit 90a5c9
        }
Packit 90a5c9
        if (*inchr != '\0') {
Packit 90a5c9
            *outchr++ = *inchr++;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    *outchr = '\0';
Packit 90a5c9
    return outstring;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Given a string, append the PID deliminated by delim.
Packit 90a5c9
 * Usually used to create a pid-appended filepath name
Packit 90a5c9
 * (eg: /a/b/foo -> /a/b/foo.6726). A function, and not
Packit 90a5c9
 * a macro, to avoid unistd.h dependency
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(char *) ap_append_pid(apr_pool_t *p, const char *string,
Packit 90a5c9
                                    const char *delim)
Packit 90a5c9
{
Packit 90a5c9
    return apr_psprintf(p, "%s%s%" APR_PID_T_FMT, string,
Packit 90a5c9
                        delim, getpid());
Packit 90a5c9
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Parse a given timeout parameter string into an apr_interval_time_t value.
Packit 90a5c9
 * The unit of the time interval is given as postfix string to the numeric
Packit 90a5c9
 * string. Currently the following units are understood:
Packit 90a5c9
 *
Packit 90a5c9
 * ms    : milliseconds
Packit 90a5c9
 * s     : seconds
Packit 90a5c9
 * mi[n] : minutes
Packit 90a5c9
 * h     : hours
Packit 90a5c9
 *
Packit 90a5c9
 * If no unit is contained in the given timeout parameter the default_time_unit
Packit 90a5c9
 * will be used instead.
Packit 90a5c9
 * @param timeout_parameter The string containing the timeout parameter.
Packit 90a5c9
 * @param timeout The timeout value to be returned.
Packit 90a5c9
 * @param default_time_unit The default time unit to use if none is specified
Packit 90a5c9
 * in timeout_parameter.
Packit 90a5c9
 * @return Status value indicating whether the parsing was successful or not.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(apr_status_t) ap_timeout_parameter_parse(
Packit 90a5c9
                                               const char *timeout_parameter,
Packit 90a5c9
                                               apr_interval_time_t *timeout,
Packit 90a5c9
                                               const char *default_time_unit)
Packit 90a5c9
{
Packit 90a5c9
    char *endp;
Packit 90a5c9
    const char *time_str;
Packit 90a5c9
    apr_int64_t tout;
Packit 90a5c9
Packit 90a5c9
    tout = apr_strtoi64(timeout_parameter, &endp, 10);
Packit 90a5c9
    if (errno) {
Packit 90a5c9
        return errno;
Packit 90a5c9
    }
Packit 90a5c9
    if (!endp || !*endp) {
Packit 90a5c9
        time_str = default_time_unit;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        time_str = endp;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    switch (*time_str) {
Packit 90a5c9
        /* Time is in seconds */
Packit 90a5c9
    case 's':
Packit 90a5c9
        *timeout = (apr_interval_time_t) apr_time_from_sec(tout);
Packit 90a5c9
        break;
Packit 90a5c9
    case 'h':
Packit 90a5c9
        /* Time is in hours */
Packit 90a5c9
        *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 3600);
Packit 90a5c9
        break;
Packit 90a5c9
    case 'm':
Packit 90a5c9
        switch (*(++time_str)) {
Packit 90a5c9
        /* Time is in milliseconds */
Packit 90a5c9
        case 's':
Packit 90a5c9
            *timeout = (apr_interval_time_t) tout * 1000;
Packit 90a5c9
            break;
Packit 90a5c9
        /* Time is in minutes */
Packit 90a5c9
        case 'i':
Packit 90a5c9
            *timeout = (apr_interval_time_t) apr_time_from_sec(tout * 60);
Packit 90a5c9
            break;
Packit 90a5c9
        default:
Packit 90a5c9
            return APR_EGENERAL;
Packit 90a5c9
        }
Packit 90a5c9
        break;
Packit 90a5c9
    default:
Packit 90a5c9
        return APR_EGENERAL;
Packit 90a5c9
    }
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Determine if a request has a request body or not.
Packit 90a5c9
 *
Packit 90a5c9
 * @param r the request_rec of the request
Packit 90a5c9
 * @return truth value
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(int) ap_request_has_body(request_rec *r)
Packit 90a5c9
{
Packit 90a5c9
    apr_off_t cl;
Packit 90a5c9
    char *estr;
Packit 90a5c9
    const char *cls;
Packit 90a5c9
    int has_body;
Packit 90a5c9
Packit 90a5c9
    has_body = (!r->header_only
Packit 90a5c9
                && (r->kept_body
Packit 90a5c9
                    || apr_table_get(r->headers_in, "Transfer-Encoding")
Packit 90a5c9
                    || ( (cls = apr_table_get(r->headers_in, "Content-Length"))
Packit 90a5c9
                        && (apr_strtoff(&cl, cls, &estr, 10) == APR_SUCCESS)
Packit 90a5c9
                        && (!*estr)
Packit 90a5c9
                        && (cl > 0) )
Packit 90a5c9
                    )
Packit 90a5c9
                );
Packit 90a5c9
    return has_body;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE_NONSTD(apr_status_t) ap_pool_cleanup_set_null(void *data_)
Packit 90a5c9
{
Packit 90a5c9
    void **ptr = (void **)data_;
Packit 90a5c9
    *ptr = NULL;
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
Packit 90a5c9
Packit 90a5c9
    for ( ; *src; src++, dest++)
Packit 90a5c9
    {
Packit 90a5c9
        if (!apr_isprint(*src))
Packit 90a5c9
            *dest = 'x';
Packit 90a5c9
        else if (!apr_isalnum(*src))
Packit 90a5c9
            *dest = '_';
Packit 90a5c9
        else
Packit 90a5c9
            *dest = (char)*src;
Packit 90a5c9
    }
Packit 90a5c9
    *dest = '\0';
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
Packit 90a5c9
                                        const char **dest)
Packit 90a5c9
{
Packit 90a5c9
    char *new = apr_palloc(p, strlen(src)+1);
Packit 90a5c9
    if (!new)
Packit 90a5c9
        return APR_ENOMEM;
Packit 90a5c9
    *dest = new;
Packit 90a5c9
    return ap_str2_alnum(src, new);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * Read the body and parse any form found, which must be of the
Packit 90a5c9
 * type application/x-www-form-urlencoded.
Packit 90a5c9
 *
Packit 90a5c9
 * Name/value pairs are returned in an array, with the names as
Packit 90a5c9
 * strings with a maximum length of HUGE_STRING_LEN, and the
Packit 90a5c9
 * values as bucket brigades. This allows values to be arbitrarily
Packit 90a5c9
 * large.
Packit 90a5c9
 *
Packit 90a5c9
 * All url-encoding is removed from both the names and the values
Packit 90a5c9
 * on the fly. The names are interpreted as strings, while the
Packit 90a5c9
 * values are interpreted as blocks of binary data, that may
Packit 90a5c9
 * contain the 0 character.
Packit 90a5c9
 *
Packit 90a5c9
 * In order to ensure that resource limits are not exceeded, a
Packit 90a5c9
 * maximum size must be provided. If the sum of the lengths of
Packit 90a5c9
 * the names and the values exceed this size, this function
Packit 90a5c9
 * will return HTTP_REQUEST_ENTITY_TOO_LARGE.
Packit 90a5c9
 *
Packit 90a5c9
 * An optional number of parameters can be provided, if the number
Packit 90a5c9
 * of parameters provided exceeds this amount, this function will
Packit 90a5c9
 * return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
Packit 90a5c9
 * no limit is imposed, and the number of parameters is in turn
Packit 90a5c9
 * constrained by the size parameter above.
Packit 90a5c9
 *
Packit 90a5c9
 * This function honours any kept_body configuration, and the
Packit 90a5c9
 * original raw request body will be saved to the kept_body brigade
Packit 90a5c9
 * if so configured, just as ap_discard_request_body does.
Packit 90a5c9
 *
Packit 90a5c9
 * NOTE: File upload is not yet supported, but can be without change
Packit 90a5c9
 * to the function call.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
/* form parsing stuff */
Packit 90a5c9
typedef enum {
Packit 90a5c9
    FORM_NORMAL,
Packit 90a5c9
    FORM_AMP,
Packit 90a5c9
    FORM_NAME,
Packit 90a5c9
    FORM_VALUE,
Packit 90a5c9
    FORM_PERCENTA,
Packit 90a5c9
    FORM_PERCENTB,
Packit 90a5c9
    FORM_ABORT
Packit 90a5c9
} ap_form_type_t;
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_parse_form_data(request_rec *r, ap_filter_t *f,
Packit 90a5c9
                                   apr_array_header_t **ptr,
Packit 90a5c9
                                   apr_size_t num, apr_size_t usize)
Packit 90a5c9
{
Packit 90a5c9
    apr_bucket_brigade *bb = NULL;
Packit 90a5c9
    int seen_eos = 0;
Packit 90a5c9
    char buffer[HUGE_STRING_LEN + 1];
Packit 90a5c9
    const char *ct;
Packit 90a5c9
    apr_size_t offset = 0;
Packit 90a5c9
    apr_ssize_t size;
Packit 90a5c9
    ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
Packit 90a5c9
    ap_form_pair_t *pair = NULL;
Packit 90a5c9
    apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
Packit 90a5c9
    char escaped_char[2] = { 0 };
Packit 90a5c9
Packit 90a5c9
    *ptr = pairs;
Packit 90a5c9
Packit 90a5c9
    /* sanity check - we only support forms for now */
Packit 90a5c9
    ct = apr_table_get(r->headers_in, "Content-Type");
Packit 90a5c9
    if (!ct || strncasecmp("application/x-www-form-urlencoded", ct, 33)) {
Packit 90a5c9
        return ap_discard_request_body(r);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (usize > APR_SIZE_MAX >> 1)
Packit 90a5c9
        size = APR_SIZE_MAX >> 1;
Packit 90a5c9
    else
Packit 90a5c9
        size = usize;
Packit 90a5c9
Packit 90a5c9
    if (!f) {
Packit 90a5c9
        f = r->input_filters;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
Packit 90a5c9
    do {
Packit 90a5c9
        apr_bucket *bucket = NULL, *last = NULL;
Packit 90a5c9
Packit 90a5c9
        int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
Packit 90a5c9
                                APR_BLOCK_READ, HUGE_STRING_LEN);
Packit 90a5c9
        if (rv != APR_SUCCESS) {
Packit 90a5c9
            apr_brigade_destroy(bb);
Packit 90a5c9
            return ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        for (bucket = APR_BRIGADE_FIRST(bb);
Packit 90a5c9
             bucket != APR_BRIGADE_SENTINEL(bb);
Packit 90a5c9
             last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
Packit 90a5c9
            const char *data;
Packit 90a5c9
            apr_size_t len, slide;
Packit 90a5c9
Packit 90a5c9
            if (last) {
Packit 90a5c9
                apr_bucket_delete(last);
Packit 90a5c9
            }
Packit 90a5c9
            if (APR_BUCKET_IS_EOS(bucket)) {
Packit 90a5c9
                seen_eos = 1;
Packit 90a5c9
                break;
Packit 90a5c9
            }
Packit 90a5c9
            if (bucket->length == 0) {
Packit 90a5c9
                continue;
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
            rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
Packit 90a5c9
            if (rv != APR_SUCCESS) {
Packit 90a5c9
                apr_brigade_destroy(bb);
Packit 90a5c9
                return HTTP_BAD_REQUEST;
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
            slide = len;
Packit 90a5c9
            while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
Packit 90a5c9
                char c = *data++;
Packit 90a5c9
                if ('+' == c) {
Packit 90a5c9
                    c = ' ';
Packit 90a5c9
                }
Packit 90a5c9
                else if ('&' == c) {
Packit 90a5c9
                    state = FORM_AMP;
Packit 90a5c9
                }
Packit 90a5c9
                if ('%' == c) {
Packit 90a5c9
                    percent = FORM_PERCENTA;
Packit 90a5c9
                    continue;
Packit 90a5c9
                }
Packit 90a5c9
                if (FORM_PERCENTA == percent) {
Packit 90a5c9
                    escaped_char[0] = c;
Packit 90a5c9
                    percent = FORM_PERCENTB;
Packit 90a5c9
                    continue;
Packit 90a5c9
                }
Packit 90a5c9
                if (FORM_PERCENTB == percent) {
Packit 90a5c9
                    escaped_char[1] = c;
Packit 90a5c9
                    c = x2c(escaped_char);
Packit 90a5c9
                    percent = FORM_NORMAL;
Packit 90a5c9
                }
Packit 90a5c9
                switch (state) {
Packit 90a5c9
                    case FORM_AMP:
Packit 90a5c9
                        if (pair) {
Packit 90a5c9
                            const char *tmp = apr_pmemdup(r->pool, buffer, offset);
Packit 90a5c9
                            apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
Packit 90a5c9
                            APR_BRIGADE_INSERT_TAIL(pair->value, b);
Packit 90a5c9
                        }
Packit 90a5c9
                        state = FORM_NAME;
Packit 90a5c9
                        pair = NULL;
Packit 90a5c9
                        offset = 0;
Packit 90a5c9
                        num--;
Packit 90a5c9
                        break;
Packit 90a5c9
                    case FORM_NAME:
Packit 90a5c9
                        if (offset < HUGE_STRING_LEN) {
Packit 90a5c9
                            if ('=' == c) {
Packit 90a5c9
                                buffer[offset] = 0;
Packit 90a5c9
                                offset = 0;
Packit 90a5c9
                                pair = (ap_form_pair_t *) apr_array_push(pairs);
Packit 90a5c9
                                pair->name = apr_pstrdup(r->pool, buffer);
Packit 90a5c9
                                pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
Packit 90a5c9
                                state = FORM_VALUE;
Packit 90a5c9
                            }
Packit 90a5c9
                            else {
Packit 90a5c9
                                buffer[offset++] = c;
Packit 90a5c9
                                size--;
Packit 90a5c9
                            }
Packit 90a5c9
                        }
Packit 90a5c9
                        else {
Packit 90a5c9
                            state = FORM_ABORT;
Packit 90a5c9
                        }
Packit 90a5c9
                        break;
Packit 90a5c9
                    case FORM_VALUE:
Packit 90a5c9
                        if (offset >= HUGE_STRING_LEN) {
Packit 90a5c9
                            const char *tmp = apr_pmemdup(r->pool, buffer, offset);
Packit 90a5c9
                            apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
Packit 90a5c9
                            APR_BRIGADE_INSERT_TAIL(pair->value, b);
Packit 90a5c9
                            offset = 0;
Packit 90a5c9
                        }
Packit 90a5c9
                        buffer[offset++] = c;
Packit 90a5c9
                        size--;
Packit 90a5c9
                        break;
Packit 90a5c9
                    default:
Packit 90a5c9
                        break;
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        apr_brigade_cleanup(bb);
Packit 90a5c9
    } while (!seen_eos);
Packit 90a5c9
Packit 90a5c9
    if (FORM_ABORT == state || size < 0 || num == 0) {
Packit 90a5c9
        return HTTP_REQUEST_ENTITY_TOO_LARGE;
Packit 90a5c9
    }
Packit 90a5c9
    else if (FORM_VALUE == state && pair && offset > 0) {
Packit 90a5c9
        const char *tmp = apr_pmemdup(r->pool, buffer, offset);
Packit 90a5c9
        apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
Packit 90a5c9
        APR_BRIGADE_INSERT_TAIL(pair->value, b);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return OK;
Packit 90a5c9
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#define VARBUF_SMALL_SIZE 2048
Packit 90a5c9
#define VARBUF_MAX_SIZE   (APR_SIZE_MAX - 1 -                                \
Packit 90a5c9
                           APR_ALIGN_DEFAULT(sizeof(struct ap_varbuf_info)))
Packit 90a5c9
Packit 90a5c9
struct ap_varbuf_info {
Packit 90a5c9
    struct apr_memnode_t *node;
Packit 90a5c9
    apr_allocator_t *allocator;
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
static apr_status_t varbuf_cleanup(void *info_)
Packit 90a5c9
{
Packit 90a5c9
    struct ap_varbuf_info *info = info_;
Packit 90a5c9
    info->node->next = NULL;
Packit 90a5c9
    apr_allocator_free(info->allocator, info->node);
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
const char nul = '\0';
Packit 90a5c9
static char * const varbuf_empty = (char *)&nul;
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_varbuf_init(apr_pool_t *p, struct ap_varbuf *vb,
Packit 90a5c9
                                apr_size_t init_size)
Packit 90a5c9
{
Packit 90a5c9
    vb->buf = varbuf_empty;
Packit 90a5c9
    vb->avail = 0;
Packit 90a5c9
    vb->strlen = AP_VARBUF_UNKNOWN;
Packit 90a5c9
    vb->pool = p;
Packit 90a5c9
    vb->info = NULL;
Packit 90a5c9
Packit 90a5c9
    ap_varbuf_grow(vb, init_size);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
Packit 90a5c9
{
Packit 90a5c9
    apr_memnode_t *new_node = NULL;
Packit 90a5c9
    apr_allocator_t *allocator;
Packit 90a5c9
    struct ap_varbuf_info *new_info;
Packit 90a5c9
    char *new;
Packit 90a5c9
Packit 90a5c9
    AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN || vb->avail >= vb->strlen);
Packit 90a5c9
Packit 90a5c9
    if (new_len <= vb->avail)
Packit 90a5c9
        return;
Packit 90a5c9
Packit 90a5c9
    if (new_len < 2 * vb->avail && vb->avail < VARBUF_MAX_SIZE/2) {
Packit 90a5c9
        /* at least double the size, to avoid repeated reallocations */
Packit 90a5c9
        new_len = 2 * vb->avail;
Packit 90a5c9
    }
Packit 90a5c9
    else if (new_len > VARBUF_MAX_SIZE) {
Packit 90a5c9
        apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
Packit 90a5c9
        ap_assert(abort_fn != NULL);
Packit 90a5c9
        abort_fn(APR_ENOMEM);
Packit 90a5c9
        return;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    new_len++;  /* add space for trailing \0 */
Packit 90a5c9
    if (new_len <= VARBUF_SMALL_SIZE) {
Packit 90a5c9
        new_len = APR_ALIGN_DEFAULT(new_len);
Packit 90a5c9
        new = apr_palloc(vb->pool, new_len);
Packit 90a5c9
        if (vb->avail && vb->strlen != 0) {
Packit 90a5c9
            AP_DEBUG_ASSERT(vb->buf != NULL);
Packit 90a5c9
            AP_DEBUG_ASSERT(vb->buf != varbuf_empty);
Packit 90a5c9
            if (new == vb->buf + vb->avail + 1) {
Packit 90a5c9
                /* We are lucky: the new memory lies directly after our old
Packit 90a5c9
                 * buffer, we can now use both.
Packit 90a5c9
                 */
Packit 90a5c9
                vb->avail += new_len;
Packit 90a5c9
                return;
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                /* copy up to vb->strlen + 1 bytes */
Packit 90a5c9
                memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
Packit 90a5c9
                                     vb->avail + 1 : vb->strlen + 1);
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            *new = '\0';
Packit 90a5c9
        }
Packit 90a5c9
        vb->avail = new_len - 1;
Packit 90a5c9
        vb->buf = new;
Packit 90a5c9
        return;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* The required block is rather larger. Use allocator directly so that
Packit 90a5c9
     * the memory can be freed independently from the pool. */
Packit 90a5c9
    allocator = apr_pool_allocator_get(vb->pool);
Packit 90a5c9
    if (new_len <= VARBUF_MAX_SIZE)
Packit 90a5c9
        new_node = apr_allocator_alloc(allocator,
Packit 90a5c9
                                       new_len + APR_ALIGN_DEFAULT(sizeof(*new_info)));
Packit 90a5c9
    if (!new_node) {
Packit 90a5c9
        apr_abortfunc_t abort_fn = apr_pool_abort_get(vb->pool);
Packit 90a5c9
        ap_assert(abort_fn != NULL);
Packit 90a5c9
        abort_fn(APR_ENOMEM);
Packit 90a5c9
        return;
Packit 90a5c9
    }
Packit 90a5c9
    new_info = (struct ap_varbuf_info *)new_node->first_avail;
Packit 90a5c9
    new_node->first_avail += APR_ALIGN_DEFAULT(sizeof(*new_info));
Packit 90a5c9
    new_info->node = new_node;
Packit 90a5c9
    new_info->allocator = allocator;
Packit 90a5c9
    new = new_node->first_avail;
Packit 90a5c9
    AP_DEBUG_ASSERT(new_node->endp - new_node->first_avail >= new_len);
Packit 90a5c9
    new_len = new_node->endp - new_node->first_avail;
Packit 90a5c9
Packit 90a5c9
    if (vb->avail && vb->strlen != 0)
Packit 90a5c9
        memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
Packit 90a5c9
                             vb->avail + 1 : vb->strlen + 1);
Packit 90a5c9
    else
Packit 90a5c9
        *new = '\0';
Packit 90a5c9
    if (vb->info)
Packit 90a5c9
        apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
Packit 90a5c9
    apr_pool_cleanup_register(vb->pool, new_info, varbuf_cleanup,
Packit 90a5c9
                              apr_pool_cleanup_null);
Packit 90a5c9
    vb->info = new_info;
Packit 90a5c9
    vb->buf = new;
Packit 90a5c9
    vb->avail = new_len - 1;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
Packit 90a5c9
                                     int len)
Packit 90a5c9
{
Packit 90a5c9
    if (len == 0)
Packit 90a5c9
        return;
Packit 90a5c9
    if (!vb->avail) {
Packit 90a5c9
        ap_varbuf_grow(vb, len);
Packit 90a5c9
        memcpy(vb->buf, str, len);
Packit 90a5c9
        vb->buf[len] = '\0';
Packit 90a5c9
        vb->strlen = len;
Packit 90a5c9
        return;
Packit 90a5c9
    }
Packit 90a5c9
    if (vb->strlen == AP_VARBUF_UNKNOWN)
Packit 90a5c9
        vb->strlen = strlen(vb->buf);
Packit 90a5c9
    ap_varbuf_grow(vb, vb->strlen + len);
Packit 90a5c9
    memcpy(vb->buf + vb->strlen, str, len);
Packit 90a5c9
    vb->strlen += len;
Packit 90a5c9
    vb->buf[vb->strlen] = '\0';
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb)
Packit 90a5c9
{
Packit 90a5c9
    if (vb->info) {
Packit 90a5c9
        apr_pool_cleanup_run(vb->pool, vb->info, varbuf_cleanup);
Packit 90a5c9
        vb->info = NULL;
Packit 90a5c9
    }
Packit 90a5c9
    vb->buf = NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *buf,
Packit 90a5c9
                                  const char *prepend, apr_size_t prepend_len,
Packit 90a5c9
                                  const char *append, apr_size_t append_len,
Packit 90a5c9
                                  apr_size_t *new_len)
Packit 90a5c9
{
Packit 90a5c9
    apr_size_t i = 0;
Packit 90a5c9
    struct iovec vec[3];
Packit 90a5c9
Packit 90a5c9
    if (prepend) {
Packit 90a5c9
        vec[i].iov_base = (void *)prepend;
Packit 90a5c9
        vec[i].iov_len = prepend_len;
Packit 90a5c9
        i++;
Packit 90a5c9
    }
Packit 90a5c9
    if (buf->avail && buf->strlen) {
Packit 90a5c9
        if (buf->strlen == AP_VARBUF_UNKNOWN)
Packit 90a5c9
            buf->strlen = strlen(buf->buf);
Packit 90a5c9
        vec[i].iov_base = (void *)buf->buf;
Packit 90a5c9
        vec[i].iov_len = buf->strlen;
Packit 90a5c9
        i++;
Packit 90a5c9
    }
Packit 90a5c9
    if (append) {
Packit 90a5c9
        vec[i].iov_base = (void *)append;
Packit 90a5c9
        vec[i].iov_len = append_len;
Packit 90a5c9
        i++;
Packit 90a5c9
    }
Packit 90a5c9
    if (i)
Packit 90a5c9
        return apr_pstrcatv(p, vec, i, new_len);
Packit 90a5c9
Packit 90a5c9
    if (new_len)
Packit 90a5c9
        *new_len = 0;
Packit 90a5c9
    return "";
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(apr_status_t) ap_varbuf_regsub(struct ap_varbuf *vb,
Packit 90a5c9
                                          const char *input,
Packit 90a5c9
                                          const char *source,
Packit 90a5c9
                                          apr_size_t nmatch,
Packit 90a5c9
                                          ap_regmatch_t pmatch[],
Packit 90a5c9
                                          apr_size_t maxlen)
Packit 90a5c9
{
Packit 90a5c9
    return regsub_core(NULL, NULL, vb, input, source, nmatch, pmatch, maxlen);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static const char * const oom_message = "[crit] Memory allocation failed, "
Packit 90a5c9
                                        "aborting process." APR_EOL_STR;
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_abort_on_oom()
Packit 90a5c9
{
Packit 90a5c9
    int written, count = strlen(oom_message);
Packit 90a5c9
    const char *buf = oom_message;
Packit 90a5c9
    do {
Packit 90a5c9
        written = write(STDERR_FILENO, buf, count);
Packit 90a5c9
        if (written == count)
Packit 90a5c9
            break;
Packit 90a5c9
        if (written > 0) {
Packit 90a5c9
            buf += written;
Packit 90a5c9
            count -= written;
Packit 90a5c9
        }
Packit 90a5c9
    } while (written >= 0 || errno == EINTR);
Packit 90a5c9
    abort();
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void *) ap_malloc(size_t size)
Packit 90a5c9
{
Packit 90a5c9
    void *p = malloc(size);
Packit 90a5c9
    if (p == NULL && size != 0)
Packit 90a5c9
        ap_abort_on_oom();
Packit 90a5c9
    return p;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void *) ap_calloc(size_t nelem, size_t size)
Packit 90a5c9
{
Packit 90a5c9
    void *p = calloc(nelem, size);
Packit 90a5c9
    if (p == NULL && nelem != 0 && size != 0)
Packit 90a5c9
        ap_abort_on_oom();
Packit 90a5c9
    return p;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void *) ap_realloc(void *ptr, size_t size)
Packit 90a5c9
{
Packit 90a5c9
    void *p = realloc(ptr, size);
Packit 90a5c9
    if (p == NULL && size != 0)
Packit 90a5c9
        ap_abort_on_oom();
Packit 90a5c9
    return p;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_get_sload(ap_sload_t *ld)
Packit 90a5c9
{
Packit 90a5c9
    int i, j, server_limit, thread_limit;
Packit 90a5c9
    int ready = 0;
Packit 90a5c9
    int busy = 0;
Packit 90a5c9
    int total;
Packit 90a5c9
    ap_generation_t mpm_generation;
Packit 90a5c9
Packit 90a5c9
    /* preload errored fields, we overwrite */
Packit 90a5c9
    ld->idle = -1;
Packit 90a5c9
    ld->busy = -1;
Packit 90a5c9
    ld->bytes_served = 0;
Packit 90a5c9
    ld->access_count = 0;
Packit 90a5c9
Packit 90a5c9
    ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
Packit 90a5c9
    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
Packit 90a5c9
    ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
Packit 90a5c9
Packit 90a5c9
    for (i = 0; i < server_limit; i++) {
Packit 90a5c9
        process_score *ps;
Packit 90a5c9
        ps = ap_get_scoreboard_process(i);
Packit 90a5c9
Packit 90a5c9
        for (j = 0; j < thread_limit; j++) {
Packit 90a5c9
            int res;
Packit 90a5c9
            worker_score *ws = NULL;
Packit 90a5c9
            ws = &ap_scoreboard_image->servers[i][j];
Packit 90a5c9
            res = ws->status;
Packit 90a5c9
Packit 90a5c9
            if (!ps->quiescing && ps->pid) {
Packit 90a5c9
                if (res == SERVER_READY && ps->generation == mpm_generation) {
Packit 90a5c9
                    ready++;
Packit 90a5c9
                }
Packit 90a5c9
                else if (res != SERVER_DEAD &&
Packit 90a5c9
                         res != SERVER_STARTING && res != SERVER_IDLE_KILL &&
Packit 90a5c9
                         ps->generation == mpm_generation) {
Packit 90a5c9
                    busy++;
Packit 90a5c9
                }   
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
            if (ap_extended_status && !ps->quiescing && ps->pid) {
Packit 90a5c9
                if (ws->access_count != 0 
Packit 90a5c9
                    || (res != SERVER_READY && res != SERVER_DEAD)) {
Packit 90a5c9
                    ld->access_count += ws->access_count;
Packit 90a5c9
                    ld->bytes_served += ws->bytes_served;
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    total = busy + ready;
Packit 90a5c9
    if (total) {
Packit 90a5c9
        ld->idle = ready * 100 / total;
Packit 90a5c9
        ld->busy = busy * 100 / total;
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_get_loadavg(ap_loadavg_t *ld)
Packit 90a5c9
{
Packit 90a5c9
    /* preload errored fields, we overwrite */
Packit 90a5c9
    ld->loadavg = -1.0;
Packit 90a5c9
    ld->loadavg5 = -1.0;
Packit 90a5c9
    ld->loadavg15 = -1.0;
Packit 90a5c9
Packit 90a5c9
#if HAVE_GETLOADAVG
Packit 90a5c9
    {
Packit 90a5c9
        double la[3];
Packit 90a5c9
        int num;
Packit 90a5c9
Packit 90a5c9
        num = getloadavg(la, 3);
Packit 90a5c9
        if (num > 0) {
Packit 90a5c9
            ld->loadavg = (float)la[0];
Packit 90a5c9
        }
Packit 90a5c9
        if (num > 1) {
Packit 90a5c9
            ld->loadavg5 = (float)la[1];
Packit 90a5c9
        }
Packit 90a5c9
        if (num > 2) {
Packit 90a5c9
            ld->loadavg15 = (float)la[2];
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
#endif
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p,
Packit 90a5c9
                                    const char *cmd,
Packit 90a5c9
                                    const char * const * argv)
Packit 90a5c9
{
Packit 90a5c9
    char buf[MAX_STRING_LEN];
Packit 90a5c9
    apr_procattr_t *procattr;
Packit 90a5c9
    apr_proc_t *proc;
Packit 90a5c9
    apr_file_t *fp;
Packit 90a5c9
    apr_size_t nbytes = 1;
Packit 90a5c9
    char c;
Packit 90a5c9
    int k;
Packit 90a5c9
Packit 90a5c9
    if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
Packit 90a5c9
        return NULL;
Packit 90a5c9
    if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
Packit 90a5c9
                            APR_FULL_BLOCK) != APR_SUCCESS)
Packit 90a5c9
        return NULL;
Packit 90a5c9
    if (apr_procattr_dir_set(procattr,
Packit 90a5c9
                             ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
Packit 90a5c9
        return NULL;
Packit 90a5c9
    if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
Packit 90a5c9
        return NULL;
Packit 90a5c9
    proc = apr_pcalloc(p, sizeof(apr_proc_t));
Packit 90a5c9
    if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
Packit 90a5c9
        return NULL;
Packit 90a5c9
    fp = proc->out;
Packit 90a5c9
Packit 90a5c9
    if (fp == NULL)
Packit 90a5c9
        return NULL;
Packit 90a5c9
    /* XXX: we are reading 1 byte at a time here */
Packit 90a5c9
    for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
Packit 90a5c9
                && nbytes == 1 && (k < MAX_STRING_LEN-1)     ; ) {
Packit 90a5c9
        if (c == '\n' || c == '\r')
Packit 90a5c9
            break;
Packit 90a5c9
        buf[k++] = c;
Packit 90a5c9
    }
Packit 90a5c9
    buf[k] = '\0'; 
Packit 90a5c9
    apr_file_close(fp);
Packit 90a5c9
Packit 90a5c9
    return apr_pstrndup(p, buf, k);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_array_str_index(const apr_array_header_t *array, 
Packit 90a5c9
                                   const char *s,
Packit 90a5c9
                                   int start)
Packit 90a5c9
{
Packit 90a5c9
    if (start >= 0) {
Packit 90a5c9
        int i;
Packit 90a5c9
        
Packit 90a5c9
        for (i = start; i < array->nelts; i++) {
Packit 90a5c9
            const char *p = APR_ARRAY_IDX(array, i, const char *);
Packit 90a5c9
            if (!strcmp(p, s)) {
Packit 90a5c9
                return i;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    
Packit 90a5c9
    return -1;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_array_str_contains(const apr_array_header_t *array, 
Packit 90a5c9
                                      const char *s)
Packit 90a5c9
{
Packit 90a5c9
    return (ap_array_str_index(array, s, 0) >= 0);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#if !APR_CHARSET_EBCDIC
Packit 90a5c9
/*
Packit 90a5c9
 * Our own known-fast translation table for casecmp by character.
Packit 90a5c9
 * Only ASCII alpha characters 41-5A are folded to 61-7A, other
Packit 90a5c9
 * octets (such as extended latin alphabetics) are never case-folded.
Packit 90a5c9
 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
Packit 90a5c9
 */
Packit 90a5c9
static const short ucharmap[] = {
Packit 90a5c9
    0x0,  0x1,  0x2,  0x3,  0x4,  0x5,  0x6,  0x7,
Packit 90a5c9
    0x8,  0x9,  0xa,  0xb,  0xc,  0xd,  0xe,  0xf,
Packit 90a5c9
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
Packit 90a5c9
    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
Packit 90a5c9
    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
Packit 90a5c9
    0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
Packit 90a5c9
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
Packit 90a5c9
    0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
Packit 90a5c9
    0x40,  'a',  'b',  'c',  'd',  'e',  'f',  'g',
Packit 90a5c9
     'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
Packit 90a5c9
     'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
Packit 90a5c9
     'x',  'y',  'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
Packit 90a5c9
    0x60,  'a',  'b',  'c',  'd',  'e',  'f',  'g',
Packit 90a5c9
     'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
Packit 90a5c9
     'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
Packit 90a5c9
     'x',  'y',  'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
Packit 90a5c9
    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
Packit 90a5c9
    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
Packit 90a5c9
    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
Packit 90a5c9
    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
Packit 90a5c9
    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
Packit 90a5c9
    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
Packit 90a5c9
    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
Packit 90a5c9
    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
Packit 90a5c9
    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
Packit 90a5c9
    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
Packit 90a5c9
    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
Packit 90a5c9
    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
Packit 90a5c9
    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
Packit 90a5c9
    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
Packit 90a5c9
    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
Packit 90a5c9
    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
Packit 90a5c9
};
Packit 90a5c9
#else /* APR_CHARSET_EBCDIC */
Packit 90a5c9
/*
Packit 90a5c9
 * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison,
Packit 90a5c9
 * provides unique identity of every char value (strict ISO-646
Packit 90a5c9
 * conformance, arbitrary election of an ISO-8859-1 ordering, and
Packit 90a5c9
 * very arbitrary control code assignments into C1 to achieve
Packit 90a5c9
 * identity and a reversible mapping of code points),
Packit 90a5c9
 * then folding the equivalences of ASCII 41-5A into 61-7A, 
Packit 90a5c9
 * presenting comparison results in a somewhat ISO/IEC 10646
Packit 90a5c9
 * (ASCII-like) order, depending on the EBCDIC code page in use.
Packit 90a5c9
 *
Packit 90a5c9
 * NOTE: Other than Alpha A-Z/a-z, each code point is unique!
Packit 90a5c9
 */
Packit 90a5c9
static const short ucharmap[] = {
Packit 90a5c9
    0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
Packit 90a5c9
    0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
Packit 90a5c9
    0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
Packit 90a5c9
    0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
Packit 90a5c9
    0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
Packit 90a5c9
    0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
Packit 90a5c9
    0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
Packit 90a5c9
    0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
Packit 90a5c9
    0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,
Packit 90a5c9
    0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
Packit 90a5c9
    0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,
Packit 90a5c9
    0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
Packit 90a5c9
    0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,
Packit 90a5c9
    0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
Packit 90a5c9
    0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,
Packit 90a5c9
    0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
Packit 90a5c9
    0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
Packit 90a5c9
    0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,
Packit 90a5c9
    0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
Packit 90a5c9
    0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,
Packit 90a5c9
    0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
Packit 90a5c9
    0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE,
Packit 90a5c9
    0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,
Packit 90a5c9
    0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7,
Packit 90a5c9
    0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
Packit 90a5c9
    0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,
Packit 90a5c9
    0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
Packit 90a5c9
    0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,
Packit 90a5c9
    0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
Packit 90a5c9
    0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,
Packit 90a5c9
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
Packit 90a5c9
    0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F
Packit 90a5c9
};
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2)
Packit 90a5c9
{
Packit 90a5c9
    const unsigned char *str1 = (const unsigned char *)s1;
Packit 90a5c9
    const unsigned char *str2 = (const unsigned char *)s2;
Packit 90a5c9
    for (;;)
Packit 90a5c9
    {
Packit 90a5c9
        const int c1 = (int)(*str1);
Packit 90a5c9
        const int c2 = (int)(*str2);
Packit 90a5c9
        const int cmp = ucharmap[c1] - ucharmap[c2];
Packit 90a5c9
        /* Not necessary to test for !c2, this is caught by cmp */
Packit 90a5c9
        if (cmp || !c1)
Packit 90a5c9
            return cmp;
Packit 90a5c9
        str1++;
Packit 90a5c9
        str2++;
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
Packit 90a5c9
{
Packit 90a5c9
    const unsigned char *str1 = (const unsigned char *)s1;
Packit 90a5c9
    const unsigned char *str2 = (const unsigned char *)s2;
Packit 90a5c9
    while (n--)
Packit 90a5c9
    {
Packit 90a5c9
        const int c1 = (int)(*str1);
Packit 90a5c9
        const int c2 = (int)(*str2);
Packit 90a5c9
        const int cmp = ucharmap[c1] - ucharmap[c2];
Packit 90a5c9
        /* Not necessary to test for !c2, this is caught by cmp */
Packit 90a5c9
        if (cmp || !c1)
Packit 90a5c9
            return cmp;
Packit 90a5c9
        str1++;
Packit 90a5c9
        str2++;
Packit 90a5c9
    }
Packit 90a5c9
    return 0;
Packit 90a5c9
}
Packit 90a5c9