Commit 8e27e800 authored by Stefan Fritsch's avatar Stefan Fritsch
Browse files

Some varbuf enhancements:

- Introduce new ap_varbuf_pdup() and ap_varbuf_regsub() functions.
- Fix some bugs in ap_varbuf_strmemcat().
- Make ap_varbuf.buf point to an empty string if no buffer has been allocated,
  yet.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1176018 13f79535-47bb-0310-9956-ffa450edef68
parent b66f8dd1
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -354,6 +354,7 @@
 * 20110724.7 (2.3.15-dev) add ap_random_insecure_bytes(), ap_random_pick()
 * 20110724.8 (2.3.15-dev) add ap_abort_on_oom(), ap_malloc(), ap_calloc(),
 *                         ap_realloc()
 * 20110724.9 (2.3.15-dev) add ap_varbuf_pdup() and ap_varbuf_regsub()
 */

#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
@@ -361,7 +362,7 @@
#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 20110724
#endif
#define MODULE_MAGIC_NUMBER_MINOR 8                    /* 0...n */
#define MODULE_MAGIC_NUMBER_MINOR 9                    /* 0...n */

/**
 * Determine if the server's current MODULE_MAGIC_NUMBER is at least a
+37 −1
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ struct ap_varbuf_info;

/** A resizable buffer */
struct ap_varbuf {
    /** the actual buffer */
    /** the actual buffer; will point to a const '\0' if avail == 0 */
    char *buf;

    /** allocated size of the buffer (minus one for the final \0);
@@ -100,6 +100,26 @@ AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb);
AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
                                     int len);

/** Duplicate an ap_varbuf's content into pool memory
 * @param p the pool to allocate from
 * @param vb the ap_varbuf to copy from
 * @param prepend an optional buffer to prepend (may be NULL)
 * @param prepend_len length of prepend
 * @param append an optional buffer to append (may be NULL)
 * @param append_len length of append
 * @param new_len where to store the length of the resulting string
 *        (may be NULL)
 * @return the new string
 * @note ap_varbuf_pdup() uses vb->strlen to determine how much memory to
 *       copy. It works even if 0-bytes are embedded in vb->buf, prepend, or
 *       append
 */
AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *vb,
                                  const char *prepend, apr_size_t prepend_len,
                                  const char *append, apr_size_t append_len,
                                  apr_size_t *new_len);


/** Concatenate a string to an ap_varbuf
 * @param vb pointer to the ap_varbuf struct
 * @param str the string to append
@@ -107,6 +127,22 @@ AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
 */
#define ap_varbuf_strcat(vb, str) ap_varbuf_strmemcat(vb, str, strlen(str))

/** Perform string substitutions based on regexp match, using an ap_varbuf.
 * This function behaves like ap_pregsub(), but appends to an ap_varbuf
 * instead of allocating the result from a pool.
 * @param input An arbitrary string containing $1 through $9.  These are
 *              replaced with the corresponding matched sub-expressions
 * @param source The string that was originally matched to the regex
 * @param nmatch the nmatch returned from ap_pregex
 * @param pmatch the pmatch array returned from ap_pregex
 * @note Just like ap_pregsub(), this function does not copy the part of
 *       *source before the matching part (i.e. the first pmatch[0].rm_so
 *       characters).
 */
AP_DECLARE(void) ap_varbuf_regsub(struct ap_varbuf *vb, const char *input,
                                  const char *source, size_t nmatch,
                                  ap_regmatch_t pmatch[]);

/** Read a line from an ap_configfile_t into an ap_varbuf.
 * @param vb pointer to the ap_varbuf struct
 * @param cfg pointer to the ap_configfile_t
+86 −19
Original line number Diff line number Diff line
@@ -361,15 +361,15 @@ AP_DECLARE(const char *) ap_stripprefix(const char *bigstring,
 * input should be the string with the $-expressions, source should be the
 * string that was matched against.
 *
 * It returns the substituted string, or NULL on error.
 * It returns the substituted string, or NULL if a vbuf is used.
 *
 * Parts of this code are based on Henry Spencer's regsub(), from his
 * AT&T V8 regexp package.
 */

AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
                              const char *source, size_t nmatch,
                              ap_regmatch_t pmatch[])
static char *regsub_core(apr_pool_t *p, struct ap_varbuf *vb,
                         const char *input, const char *source,
                         size_t nmatch, ap_regmatch_t pmatch[])
{
    const char *src = input;
    char *dest, *dst;
@@ -379,8 +379,15 @@ AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,

    if (!source)
        return NULL;
    if (!nmatch)
    if (!nmatch) {
        if (!vb) {
            return apr_pstrdup(p, src);
        }
        else {
            ap_varbuf_strcat(vb, src);
            return NULL;
        }
    }

    /* First pass, find the size */

@@ -403,7 +410,16 @@ AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,

    }

    if (!vb) {
        dest = dst = apr_pcalloc(p, len + 1);
    }
    else {
        if (vb->buf && vb->strlen == AP_VARBUF_UNKNOWN)
            vb->strlen = strlen(vb->buf);
        ap_varbuf_grow(vb, vb->strlen + len);
        dest = dst = vb->buf + vb->strlen;
        vb->strlen += len;
    }

    /* Now actually fill in the string */

@@ -434,6 +450,13 @@ AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
    return dest;
}

AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input,
                              const char *source, size_t nmatch,
                              ap_regmatch_t pmatch[])
{
    return regsub_core(p, NULL, input, source, nmatch, pmatch);
}

/*
 * Parse .. so we don't compromise security
 */
@@ -2462,10 +2485,13 @@ static apr_status_t varbuf_cleanup(void *info_)
    return APR_SUCCESS;
}

const char nul = '\0';
static char * const varbuf_empty = (char *)&nul;

AP_DECLARE(void) ap_varbuf_init(apr_pool_t *p, struct ap_varbuf *vb,
                                apr_size_t init_size)
{
    vb->buf = NULL;
    vb->buf = varbuf_empty;
    vb->avail = 0;
    vb->strlen = AP_VARBUF_UNKNOWN;
    vb->pool = p;
@@ -2499,8 +2525,9 @@ AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
    if (new_len <= VARBUF_SMALL_SIZE) {
        new_len = APR_ALIGN_DEFAULT(new_len);
        new = apr_palloc(vb->pool, new_len);
        if (vb->buf && vb->strlen > 0) {
            AP_DEBUG_ASSERT(vb->avail > 0);
        if (vb->avail && vb->strlen != 0) {
            AP_DEBUG_ASSERT(vb->buf != NULL);
            AP_DEBUG_ASSERT(vb->buf != varbuf_empty);
            if (new == vb->buf + vb->avail + 1) {
                /* We are lucky: the new memory lies directly after our old
                 * buffer, we can now use both.
@@ -2510,7 +2537,7 @@ AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
            }
            else {
                /* copy up to vb->strlen + 1 bytes */
                memcpy(new, vb->buf, vb->strlen > vb->avail ?
                memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
                                     vb->avail + 1 : vb->strlen + 1);
            }
        }
@@ -2542,8 +2569,8 @@ AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
    AP_DEBUG_ASSERT(new_node->endp - new_node->first_avail >= new_len);
    new_len = new_node->endp - new_node->first_avail;

    if (vb->buf && vb->strlen > 0)
        memcpy(new, vb->buf, vb->strlen > vb->avail ?
    if (vb->avail && vb->strlen != 0)
        memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ?
                             vb->avail + 1 : vb->strlen + 1);
    else
        *new = '\0';
@@ -2559,16 +2586,17 @@ AP_DECLARE(void) ap_varbuf_grow(struct ap_varbuf *vb, apr_size_t new_len)
AP_DECLARE(void) ap_varbuf_strmemcat(struct ap_varbuf *vb, const char *str,
                                     int len)
{
    AP_DEBUG_ASSERT(len == strlen(str));
    if (len == 0)
        return;
    if (!vb->avail) {
        ap_varbuf_grow(vb, len);
        memcpy(vb->buf, str, len + 1);
        memcpy(vb->buf, str, len);
        vb->buf[len] = '\0';
        vb->strlen = len;
        return;
    }
    if (vb->strlen > vb->avail) {
        AP_DEBUG_ASSERT(vb->strlen == AP_VARBUF_UNKNOWN);
    if (vb->strlen == AP_VARBUF_UNKNOWN)
        vb->strlen = strlen(vb->buf);
    }
    ap_varbuf_grow(vb, vb->strlen + len);
    memcpy(vb->buf + vb->strlen, str, len);
    vb->strlen += len;
@@ -2584,6 +2612,45 @@ AP_DECLARE(void) ap_varbuf_free(struct ap_varbuf *vb)
    vb->buf = NULL;
}

AP_DECLARE(char *) ap_varbuf_pdup(apr_pool_t *p, struct ap_varbuf *buf,
                                  const char *prepend, apr_size_t prepend_len,
                                  const char *append, apr_size_t append_len,
                                  apr_size_t *new_len)
{
    apr_size_t i = 0;
    struct iovec vec[3];

    if (prepend) {
        vec[i].iov_base = (void *)prepend;
        vec[i].iov_len = prepend_len;
        i++;
    }
    if (buf->avail && buf->strlen) {
        vec[i].iov_base = (void *)buf->buf;
        vec[i].iov_len = (buf->strlen == AP_VARBUF_UNKNOWN) ? buf->avail
                                                            : buf->strlen;
        i++;
    }
    if (append) {
        vec[i].iov_base = (void *)append;
        vec[i].iov_len = append_len;
        i++;
    }
    if (i)
        return apr_pstrcatv(p, vec, i, new_len);

    if (new_len)
        *new_len = 0;
    return "";
}

AP_DECLARE(void) ap_varbuf_regsub(struct ap_varbuf *vb, const char *input,
                                  const char *source, size_t nmatch,
                                  ap_regmatch_t pmatch[])
{
    regsub_core(NULL, vb, input, source, nmatch, pmatch);
}

#define OOM_MESSAGE "[crit] Memory allocation failed, " \
        "aborting process." APR_EOL_STR