From: Stefan Fritsch Date: Mon, 26 Sep 2011 20:05:09 +0000 (+0000) Subject: Some varbuf enhancements: X-Git-Tag: 2.3.15~189 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e1fc6f9d0c3776f4b95261e4a75f71d0073fbb81;p=thirdparty%2Fapache%2Fhttpd.git 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 --- diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 94796ddd683..7a0f04943ff 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -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 diff --git a/include/util_varbuf.h b/include/util_varbuf.h index ceb46feb3cb..dc55e2c90cb 100644 --- a/include/util_varbuf.h +++ b/include/util_varbuf.h @@ -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 diff --git a/server/util.c b/server/util.c index a6c60a9f2ae..e58ad76aeb4 100644 --- a/server/util.c +++ b/server/util.c @@ -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) - return apr_pstrdup(p, src); + 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, } - dest = dst = apr_pcalloc(p, len + 1); + 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,9 +2569,9 @@ 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 ? - vb->avail + 1: vb->strlen + 1); + if (vb->avail && vb->strlen != 0) + memcpy(new, vb->buf, vb->strlen == AP_VARBUF_UNKNOWN ? + vb->avail + 1 : vb->strlen + 1); else *new = '\0'; if (vb->info) @@ -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