You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Cliff Woolley <cl...@yahoo.com> on 2000/12/08 10:05:24 UTC

(oops) [PATCH] Buckets: add copy function, ap_bucket_split_any(), etc

--- Cliff Woolley <cl...@yahoo.com> wrote:
>    Here's a patch (sorry it took me so long) that adds a copy function to the
> bucket API.

It'd have been nice if I'd actually pasted in the patch BEFORE I hit send.  =-) 
4am, time for sleep...

Here it is, for real this time.


Index: include/ap_buckets.h
===================================================================
RCS file: /home/cvspublic/apr-util/include/ap_buckets.h,v
retrieving revision 1.56
diff -u -r1.56 ap_buckets.h
--- include/ap_buckets.h	2000/12/08 01:26:34	1.56
+++ include/ap_buckets.h	2000/12/08 08:41:32
@@ -88,7 +88,7 @@
  * Buckets are data stores of varous types. They can refer to data in
  * memory, or part of a file or mmap area, or the output of a process,
  * etc. Buckets also have some type-dependent accessor functions:
- * read, split, setaside, and destroy.
+ * read, split, copy, setaside, and destroy.
  *
  * read returns the address and size of the data in the bucket. If the
  * data isn't in memory then it is read in and the bucket changes type
@@ -109,9 +109,17 @@
  * expectation turns out not to be valid, the setaside function is
  * called to move the data somewhere safer.
  *
+ * copy makes a duplicate of the bucket structure as long as it's
+ * possible to have multiple references to a single copy of the
+ * data itself.  Not all bucket types can be copied.
+ *
  * destroy maintains the reference counts on the resources used by a
  * bucket and frees them if necessary.
  *
+ * Note: all of the above functions have wrapper macros (ap_bucket_read(),
+ * ap_bucket_destroy(), etc), and those macros should be used rather
+ * than using the function pointers directly.
+ *
  * To write a bucket brigade, they are first made into an iovec, so that we
  * don't write too little data at one time.  Currently we ignore compacting the
  * buckets into as few buckets as possible, but if we really want good
@@ -135,17 +143,19 @@
     const char *name;
     /** 
      * The number of functions this bucket understands.  Can not be less than
-     * four.
+     * five.
      */
     int num_func;
     /**
      * Free the private data and any resources used by the bucket
-     * (if they aren't shared with another bucket).
+     *  (if they aren't shared with another bucket).
      * @param data The private data pointer from the bucket to be destroyed
      */
     void (*destroy)(void *data);
 
-    /** Read the data from the bucket.
+    /**
+     * Read the data from the bucket. This is guaranteed to be implemented
+     *  for all bucket types.
      * @param b The bucket to read from
      * @param str A place to store the data read.  Allocation should only be
      *            done if absolutely necessary. 
@@ -156,20 +166,39 @@
      */
     apr_status_t (*read)(ap_bucket *b, const char **str, apr_size_t *len,
ap_read_type block);
     
-    /** Make it possible to set aside the data. For most bucket types this is
-     *  a no-op; buckets containing data that dies when the stack is un-wound
-     *  must convert the bucket into a heap bucket.
+    /**
+     * Make it possible to set aside the data. Buckets containing data that
+     *  dies when the stack is un-wound must convert the bucket into a heap
+     *  bucket. For most bucket types, though, this is a no-op and this
+     *  function will return APR_ENOTIMPL.
      * @param e The bucket to convert
      * @deffunc apr_status_t setaside(ap_bucket *e)
      */
     apr_status_t (*setaside)(ap_bucket *e);
 
-    /** Split one bucket in two at the specified position
+    /**
+     * Split one bucket in two at the specified position by duplicating
+     *  the bucket structure (not the data) and modifying any necessary
+     *  start/end/offset information.  If it's not possible to do this
+     *  for the bucket type (perhaps the length of the data is indeterminate,
+     *  as with pipe and socket buckets), then APR_ENOTIMPL is returned.
+     *  See also ap_bucket_split_any().
      * @param e The bucket to split
      * @param point The offset of the first byte in the new bucket
      * @deffunc apr_status_t split(ap_bucket *e, apr_off_t point)
      */
     apr_status_t (*split)(ap_bucket *e, apr_off_t point);
+
+    /**
+     * Copy the bucket structure (not the data), assuming that this is
+     *  possible for the bucket type. If it's not, APR_ENOTIMPL is returned.
+     *  See also ap_bucket_copy_any().
+     * @param e The bucket to copy
+     * @param c Returns a pointer to the new bucket
+     * @deffunc apr_status_t copy
+     */
+    apr_status_t (*copy)(ap_bucket *e, ap_bucket **c);
+
 };
 
 /**
@@ -669,6 +698,37 @@
  */
 #define ap_bucket_split(e,point) e->type->split(e, point)
 
+/**
+ * Copy a bucket.
+ * @param e The bucket to copy
+ * @param c Returns a pointer to the new bucket
+ * @deffunc apr_status_t ap_bucket_copy(ap_bucket *e, ap_bucket **c)
+ */
+#define ap_bucket_copy(e,c) e->type->copy(e, c)
+
+/**
+ * Split a bucket into two, using ap_bucket_split() if that's possible
+ * for the given bucket type. If split() is not implemented for the
+ * bucket's type, then we perform a blocking read on the bucket. That
+ * morphs the bucket into a splittable bucket (eg, pipe becomes heap),
+ * and we then split the result.
+ * @param e The bucket to split
+ * @param point The offset to split the bucket at
+ * @deffunc apr_status_t ap_bucket_split_any(ap_bucket *e, apr_off_t point)
+ */
+APR_DECLARE(apr_status_t) ap_bucket_split_any(ap_bucket *e, apr_off_t point);
+
+/**
+ * Copy a bucket, using ap_bucket_copy() if that's possible for the given
+ * bucket type. If copy() is not implemented for the bucket's type, then
+ * we copy the data as well by performing a blocking read on the bucket.
+ * That morphs the bucket into a copyable one, which we then copy.
+ * @param e The bucket to copy
+ * @param c Returns a pointer to the new bucket
+ * @deffunc apr_status_t ap_bucket_copy_any(ap_bucket *e, ap_bucket **c)
+ */
+APR_DECLARE(apr_status_t) ap_bucket_copy_any(ap_bucket *e, ap_bucket **c);
+
 
 /* Bucket type handling */
 
@@ -691,6 +751,16 @@
 APR_DECLARE_NONSTD(apr_status_t) ap_bucket_split_notimpl(ap_bucket *data, 
                                                  apr_off_t point);
 /**
+ * A place holder function that signifies that the copy function was not
+ * implemented for this bucket
+ * @param e The bucket to copy
+ * @param c Returns a pointer to the new bucket
+ * @return APR_ENOTIMPL
+ * @deffunc apr_status_t ap_bucket_copy_notimpl(ap_bucket *e, ap_bucket **c)
+ */
+APR_DECLARE_NONSTD(apr_status_t) ap_bucket_copy_notimpl(ap_bucket *e,
+                                                        ap_bucket **c);
+/**
  * A place holder function that signifies that the destroy function was not
  * implemented for this bucket
  * @param data The bucket to destroy
@@ -807,6 +877,18 @@
  * @deffunc apr_status_t ap_bucket_split_shared(ap_bucket *b, apr_off_t point)
  */
 APR_DECLARE_NONSTD(apr_status_t) ap_bucket_split_shared(ap_bucket *b, apr_off_t
point);
+
+/**
+ * Copy a refcounted bucket, incrementing the reference count. Most
+ * reference-counting bucket types will be able to use this function
+ * as their copy function without any additional type-specific handling.
+ * @param a The bucket to copy
+ * @param c Returns a pointer to the new bucket
+ * @return APR_ENOMEM if allocation failed;
+           or APR_SUCCESS
+ * @deffunc apr_status_t ap_bucket_copy_shared(ap_bucket *a, ap_bucket **c)
+ */
+APR_DECLARE(apr_status_t) ap_bucket_copy_shared(ap_bucket *a, ap_bucket **c);
 
 
 /*  *****  Functions to Create Buckets of varying type  *****  */
Index: src/buckets/Makefile.in
===================================================================
RCS file: /home/cvspublic/apr-util/src/buckets/Makefile.in,v
retrieving revision 1.3
diff -u -r1.3 Makefile.in
--- src/buckets/Makefile.in	2000/12/05 19:11:14	1.3
+++ src/buckets/Makefile.in	2000/12/08 08:41:35
@@ -2,7 +2,7 @@
 TARGETS = ap_buckets_file.lo ap_buckets_pool.lo ap_buckets_flush.lo \
 ap_buckets_refcount.lo ap_buckets_heap.lo ap_buckets_simple.lo ap_buckets.lo \
 ap_buckets_mmap.lo ap_buckets_socket.lo ap_buckets_eos.lo ap_buckets_pipe.lo \
-ap_buckets.lo
+ap_buckets_util.lo ap_buckets.lo
 
 top_builddir = @top_builddir@
 include $(top_builddir)/build/rules.mk
Index: src/buckets/ap_buckets.c
===================================================================
RCS file: /home/cvspublic/apr-util/src/buckets/ap_buckets.c,v
retrieving revision 1.34
diff -u -r1.34 ap_buckets.c
--- src/buckets/ap_buckets.c	2000/12/05 04:46:23	1.34
+++ src/buckets/ap_buckets.c	2000/12/08 08:41:35
@@ -241,7 +241,10 @@
 {
     return APR_ENOTIMPL;
 }
-
+APR_DECLARE_NONSTD(apr_status_t) ap_bucket_copy_notimpl(ap_bucket *e, ap_bucket
**c)
+{
+    return APR_ENOTIMPL;
+}
 APR_DECLARE_NONSTD(void) ap_bucket_destroy_notimpl(void *data)
 {
     return;
Index: src/buckets/ap_buckets_eos.c
===================================================================
RCS file: /home/cvspublic/apr-util/src/buckets/ap_buckets_eos.c,v
retrieving revision 1.15
diff -u -r1.15 ap_buckets_eos.c
--- src/buckets/ap_buckets_eos.c	2000/12/06 04:42:34	1.15
+++ src/buckets/ap_buckets_eos.c	2000/12/08 08:41:36
@@ -63,6 +63,12 @@
     return APR_SUCCESS;
 }
 
+static apr_status_t eos_copy(ap_bucket *e, ap_bucket **c)
+{
+    *c = ap_bucket_create_eos();
+    return APR_SUCCESS;
+}
+
 APR_DECLARE(ap_bucket *) ap_bucket_make_eos(ap_bucket *b)
 {
     b->length    = 0;
@@ -79,9 +85,10 @@
 }
 
 APR_DECLARE_DATA const ap_bucket_type ap_eos_type = {
-    "EOS", 4,
+    "EOS", 5,
     ap_bucket_destroy_notimpl,
     eos_read,
     ap_bucket_setaside_notimpl,
-    ap_bucket_split_notimpl
+    ap_bucket_split_notimpl,
+    eos_copy
 };
Index: src/buckets/ap_buckets_file.c
===================================================================
RCS file: /home/cvspublic/apr-util/src/buckets/ap_buckets_file.c,v
retrieving revision 1.13
diff -u -r1.13 ap_buckets_file.c
--- src/buckets/ap_buckets_file.c	2000/12/07 05:01:14	1.13
+++ src/buckets/ap_buckets_file.c	2000/12/08 08:41:37
@@ -187,9 +187,10 @@
 }
 
 APR_DECLARE_DATA const ap_bucket_type ap_file_type = {
-    "FILE", 4,
+    "FILE", 5,
     ap_bucket_destroy_notimpl,
     file_read,
     ap_bucket_setaside_notimpl,
-    ap_bucket_split_notimpl
+    ap_bucket_split_notimpl,
+    ap_bucket_copy_notimpl
 };
Index: src/buckets/ap_buckets_flush.c
===================================================================
RCS file: /home/cvspublic/apr-util/src/buckets/ap_buckets_flush.c,v
retrieving revision 1.7
diff -u -r1.7 ap_buckets_flush.c
--- src/buckets/ap_buckets_flush.c	2000/12/06 04:42:35	1.7
+++ src/buckets/ap_buckets_flush.c	2000/12/08 08:41:39
@@ -63,6 +63,12 @@
     return APR_SUCCESS;
 }
 
+static apr_status_t flush_copy(ap_bucket *e, ap_bucket **c)
+{
+    *c = ap_bucket_create_flush();
+    return APR_SUCCESS;
+}
+
 APR_DECLARE(ap_bucket *) ap_bucket_make_flush(ap_bucket *b)
 {
     b->length    = 0;
@@ -79,9 +85,10 @@
 }
 
 APR_DECLARE_DATA const ap_bucket_type ap_flush_type = {
-    "FLUSH", 4,
+    "FLUSH", 5,
     ap_bucket_destroy_notimpl,
     flush_read,
     ap_bucket_setaside_notimpl,
-    ap_bucket_split_notimpl
+    ap_bucket_split_notimpl,
+    flush_copy
 };
Index: src/buckets/ap_buckets_heap.c
===================================================================
RCS file: /home/cvspublic/apr-util/src/buckets/ap_buckets_heap.c,v
retrieving revision 1.18
diff -u -r1.18 ap_buckets_heap.c
--- src/buckets/ap_buckets_heap.c	2000/12/06 04:42:35	1.18
+++ src/buckets/ap_buckets_heap.c	2000/12/08 08:41:40
@@ -141,9 +141,10 @@
 }
 
 APR_DECLARE_DATA const ap_bucket_type ap_heap_type = {
-    "HEAP", 4,
+    "HEAP", 5,
     heap_destroy,
     heap_read,
     ap_bucket_setaside_notimpl,
-    ap_bucket_split_shared
+    ap_bucket_split_shared,
+    ap_bucket_copy_shared
 };
Index: src/buckets/ap_buckets_mmap.c
===================================================================
RCS file: /home/cvspublic/apr-util/src/buckets/ap_buckets_mmap.c,v
retrieving revision 1.22
diff -u -r1.22 ap_buckets_mmap.c
--- src/buckets/ap_buckets_mmap.c	2000/12/06 04:42:35	1.22
+++ src/buckets/ap_buckets_mmap.c	2000/12/08 08:41:42
@@ -116,9 +116,10 @@
 }
 
 APR_DECLARE_DATA const ap_bucket_type ap_mmap_type = {
-    "MMAP", 4,
+    "MMAP", 5,
     mmap_destroy,
     mmap_read,
     ap_bucket_setaside_notimpl,
-    ap_bucket_split_shared
+    ap_bucket_split_shared,
+    ap_bucket_copy_shared
 };
Index: src/buckets/ap_buckets_pipe.c
===================================================================
RCS file: /home/cvspublic/apr-util/src/buckets/ap_buckets_pipe.c,v
retrieving revision 1.22
diff -u -r1.22 ap_buckets_pipe.c
--- src/buckets/ap_buckets_pipe.c	2000/12/06 04:42:35	1.22
+++ src/buckets/ap_buckets_pipe.c	2000/12/08 08:41:44
@@ -140,9 +140,10 @@
 }
 
 APR_DECLARE_DATA const ap_bucket_type ap_pipe_type = {
-    "PIPE", 4,
+    "PIPE", 5,
     ap_bucket_destroy_notimpl,
     pipe_read,
     ap_bucket_setaside_notimpl,
-    ap_bucket_split_notimpl
+    ap_bucket_split_notimpl,
+    ap_bucket_copy_notimpl
 };
Index: src/buckets/ap_buckets_pool.c
===================================================================
RCS file: /home/cvspublic/apr-util/src/buckets/ap_buckets_pool.c,v
retrieving revision 1.6
diff -u -r1.6 ap_buckets_pool.c
--- src/buckets/ap_buckets_pool.c	2000/12/06 04:42:35	1.6
+++ src/buckets/ap_buckets_pool.c	2000/12/08 08:41:53
@@ -133,9 +133,10 @@
 }
 
 APR_DECLARE_DATA const ap_bucket_type ap_pool_type = {
-    "POOL", 4,
+    "POOL", 5,
     pool_destroy,
     pool_read,
     ap_bucket_setaside_notimpl,
-    ap_bucket_split_shared
+    ap_bucket_split_shared,
+    ap_bucket_copy_shared
 };
Index: src/buckets/ap_buckets_refcount.c
===================================================================
RCS file: /home/cvspublic/apr-util/src/buckets/ap_buckets_refcount.c,v
retrieving revision 1.8
diff -u -r1.8 ap_buckets_refcount.c
--- src/buckets/ap_buckets_refcount.c	2000/12/05 01:02:50	1.8
+++ src/buckets/ap_buckets_refcount.c	2000/12/08 08:41:55
@@ -62,20 +62,44 @@
 {
     ap_bucket *b;
     ap_bucket_shared *ad, *bd;
-    ap_bucket_refcount *r;
+    apr_status_t rv;
 
     if (point < 0 || point > a->length) {
 	return APR_EINVAL;
     }
+
+    rv = ap_bucket_copy_shared(a, &b);
+    if (rv != APR_SUCCESS) {
+        return rv;
+    }
 
-    b = malloc(sizeof(*b)); 
+    ad = a->data;
+    bd = b->data;
+
+    a->length = point;
+    ad->end = ad->start + point;
+    b->length -= point;
+    bd->start += point;
+
+    AP_BUCKET_INSERT_AFTER(a, b);
+
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) ap_bucket_copy_shared(ap_bucket *a, ap_bucket **c)
+{
+    ap_bucket *b;
+    ap_bucket_shared *ad, *bd;
+    ap_bucket_refcount *r;
+
+    b = malloc(sizeof(*b));
     if (b == NULL) {
-	return APR_ENOMEM;
+        return APR_ENOMEM;
     }
     bd = malloc(sizeof(*bd));
     if (bd == NULL) {
-	free(b);
-	return APR_ENOMEM;
+        free(b);
+        return APR_ENOMEM;
     }
     *b = *a;
     ad = a->data;
@@ -84,13 +108,8 @@
 
     r = ad->data;
     r->refcount += 1;
-
-    a->length = point;
-    ad->end = ad->start + point;
-    b->length -= point;
-    bd->start += point;
 
-    AP_BUCKET_INSERT_AFTER(a, b);
+    *c = b;
 
     return APR_SUCCESS;
 }
Index: src/buckets/ap_buckets_simple.c
===================================================================
RCS file: /home/cvspublic/apr-util/src/buckets/ap_buckets_simple.c,v
retrieving revision 1.15
diff -u -r1.15 ap_buckets_simple.c
--- src/buckets/ap_buckets_simple.c	2000/12/06 04:42:35	1.15
+++ src/buckets/ap_buckets_simple.c	2000/12/08 08:41:57
@@ -59,15 +59,11 @@
  * We can't simplify this function by using an ap_bucket_make function
  * because we aren't sure of the exact type of this bucket.
  */
-static apr_status_t simple_split(ap_bucket *a, apr_off_t point)
+static apr_status_t simple_copy(ap_bucket *a, ap_bucket **c)
 {
     ap_bucket *b;
     ap_bucket_simple *ad, *bd;
 
-    if (point < 0 || point > a->length) {
-	return APR_EINVAL;
-    }
-
     b = malloc(sizeof(*b)); 
     if (b == NULL) {
 	return APR_ENOMEM;
@@ -82,6 +78,29 @@
     b->data = bd;
     *bd = *ad;
 
+    *c = b;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t simple_split(ap_bucket *a, apr_off_t point)
+{
+    ap_bucket *b;
+    ap_bucket_simple *ad, *bd;
+    apr_status_t rv;
+
+    if (point < 0 || point > a->length) {
+	return APR_EINVAL;
+    }
+
+    rv = simple_copy(a, &b);
+    if (rv != APR_SUCCESS) {
+        return rv;
+    }
+
+    ad = a->data;
+    bd = b->data;
+
     a->length = point;
     ad->end = ad->start + point;
     b->length -= point;
@@ -172,17 +191,19 @@
 }
 
 const ap_bucket_type ap_immortal_type = {
-    "IMMORTAL", 4,
+    "IMMORTAL", 5,
     free,
     simple_read,
     ap_bucket_setaside_notimpl,
-    simple_split
+    simple_split,
+    simple_copy
 };
 
 APR_DECLARE_DATA const ap_bucket_type ap_transient_type = {
-    "TRANSIENT", 4,
+    "TRANSIENT", 5,
     ap_bucket_destroy_notimpl, 
     simple_read,
     transient_setaside,
-    simple_split
+    simple_split,
+    simple_copy
 };
Index: src/buckets/ap_buckets_socket.c
===================================================================
RCS file: /home/cvspublic/apr-util/src/buckets/ap_buckets_socket.c,v
retrieving revision 1.11
diff -u -r1.11 ap_buckets_socket.c
--- src/buckets/ap_buckets_socket.c	2000/12/06 04:42:35	1.11
+++ src/buckets/ap_buckets_socket.c	2000/12/08 08:41:58
@@ -135,9 +135,10 @@
 }
 
 APR_DECLARE_DATA const ap_bucket_type ap_socket_type = {
-    "SOCKET", 4,
+    "SOCKET", 5,
     ap_bucket_destroy_notimpl,
     socket_read,
     ap_bucket_setaside_notimpl, 
-    ap_bucket_split_notimpl
+    ap_bucket_split_notimpl,
+    ap_bucket_copy_notimpl
 };
? src/buckets/ap_buckets_util.c
/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#include "apr_lib.h"
#include "ap_buckets.h"

APR_DECLARE(apr_status_t) ap_bucket_split_any(ap_bucket *e, apr_off_t point)
{
    apr_status_t rv;
    const char *str;
    apr_size_t len;

    /* try to split this bucket directly */
    rv = ap_bucket_split(e, point);
    if (rv != APR_ENOTIMPL) {
        return rv;
    }

    /* if the bucket cannot be split, we must read from it,
     * changing its type to one that can be split */
    if (point < 0) {
        return APR_EINVAL;
    }
    rv = ap_bucket_read(e, &str, &len, AP_BLOCK_READ);
    if (rv != APR_SUCCESS) {
        return rv;
    }
    if (point > len) {
        return APR_EINVAL;
    }
    return ap_bucket_split(e, point);
}

APR_DECLARE(apr_status_t) ap_bucket_copy_any(ap_bucket *e, ap_bucket **c)
{
    apr_status_t rv;
    const char *str;
    apr_size_t len;

    /* try to copy the bucket directly */
    rv = ap_bucket_copy(e, c);
    if (rv != APR_ENOTIMPL) {
        return rv;
    }

    /* if the bucket cannot be copied, we must read from it,
     * changing its type to one that can be copied */
    rv = ap_bucket_read(e, &str, &len, AP_BLOCK_READ);
    if (rv != APR_SUCCESS) {
        return rv;
    }
    return ap_bucket_copy(e, c);
}

__________________________________________________
Do You Yahoo!?
Yahoo! Shopping - Thousands of Stores. Millions of Products.
http://shopping.yahoo.com/