]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Some varbuf enhancements:
authorStefan Fritsch <sf@apache.org>
Mon, 26 Sep 2011 20:05:09 +0000 (20:05 +0000)
committerStefan Fritsch <sf@apache.org>
Mon, 26 Sep 2011 20:05:09 +0000 (20:05 +0000)
- 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

include/ap_mmn.h
include/util_varbuf.h
server/util.c

index 94796ddd6836566fe02ece4c9a441a9ca31d86b8..7a0f04943ff868d402b8a8ac5f46dd30898b867b 100644 (file)
  * 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" */
 #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
index ceb46feb3cb4e37d7ae86a1d3e96f5e59a795adc..dc55e2c90cb2a7d0e96ca736f378f076ff9aabd0 100644 (file)
@@ -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
index a6c60a9f2aec5a0777a3dd6673750ab06cc1ca30..e58ad76aeb4519ba8063326ed60426b99246d6ad 100644 (file)
@@ -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