1169691Skan/* Licensed to the Apache Software Foundation (ASF) under one or more
2169691Skan * contributor license agreements.  See the NOTICE file distributed with
3169691Skan * this work for additional information regarding copyright ownership.
4169691Skan * The ASF licenses this file to You under the Apache License, Version 2.0
5169691Skan * (the "License"); you may not use this file except in compliance with
6169691Skan * the License.  You may obtain a copy of the License at
7169691Skan *
8169691Skan *     http://www.apache.org/licenses/LICENSE-2.0
9169691Skan *
10169691Skan * Unless required by applicable law or agreed to in writing, software
11169691Skan * distributed under the License is distributed on an "AS IS" BASIS,
12169691Skan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13169691Skan * See the License for the specific language governing permissions and
14169691Skan * limitations under the License.
15169691Skan */
16169691Skan
17169691Skan#include "apr_buckets.h"
18169691Skan#define APR_WANT_MEMFUNC
19169691Skan#include "apr_want.h"
20169691Skan
21169691Skanstatic apr_status_t pool_bucket_cleanup(void *data)
22169691Skan{
23169691Skan    apr_bucket_pool *p = data;
24169691Skan
25169691Skan    /*
26169691Skan     * If the pool gets cleaned up, we have to copy the data out
27169691Skan     * of the pool and onto the heap.  But the apr_buckets out there
28169691Skan     * that point to this pool bucket need to be notified such that
29169691Skan     * they can morph themselves into a regular heap bucket the next
30169691Skan     * time they try to read.  To avoid having to manipulate
31169691Skan     * reference counts and b->data pointers, the apr_bucket_pool
32169691Skan     * actually _contains_ an apr_bucket_heap as its first element,
33169691Skan     * so the two share their apr_bucket_refcount member, and you
34169691Skan     * can typecast a pool bucket struct to make it look like a
35169691Skan     * regular old heap bucket struct.
36169691Skan     */
37169691Skan    p->heap.base = apr_bucket_alloc(p->heap.alloc_len, p->list);
38169691Skan    memcpy(p->heap.base, p->base, p->heap.alloc_len);
39169691Skan    p->base = NULL;
40169691Skan    p->pool = NULL;
41169691Skan
42169691Skan    return APR_SUCCESS;
43169691Skan}
44169691Skan
45169691Skanstatic apr_status_t pool_bucket_read(apr_bucket *b, const char **str,
46169691Skan                                     apr_size_t *len, apr_read_type_e block)
47169691Skan{
48169691Skan    apr_bucket_pool *p = b->data;
49169691Skan    const char *base = p->base;
50169691Skan
51169691Skan    if (p->pool == NULL) {
52169691Skan        /*
53169691Skan         * pool has been cleaned up... masquerade as a heap bucket from now
54169691Skan         * on. subsequent bucket operations will use the heap bucket code.
55169691Skan         */
56169691Skan        b->type = &apr_bucket_type_heap;
57169691Skan        base = p->heap.base;
58169691Skan    }
59169691Skan    *str = base + b->start;
60169691Skan    *len = b->length;
61169691Skan    return APR_SUCCESS;
62169691Skan}
63169691Skan
64169691Skanstatic void pool_bucket_destroy(void *data)
65169691Skan{
66169691Skan    apr_bucket_pool *p = data;
67169691Skan
68169691Skan    /* If the pool is cleaned up before the last reference goes
69169691Skan     * away, the data is really now on the heap; heap_destroy() takes
70169691Skan     * over.  free() in heap_destroy() thinks it's freeing
71169691Skan     * an apr_bucket_heap, when in reality it's freeing the whole
72169691Skan     * apr_bucket_pool for us.
73169691Skan     */
74169691Skan    if (p->pool) {
75169691Skan        /* the shared resource is still in the pool
76169691Skan         * because the pool has not been cleaned up yet
77169691Skan         */
78169691Skan        if (apr_bucket_shared_destroy(p)) {
79169691Skan            apr_pool_cleanup_kill(p->pool, p, pool_bucket_cleanup);
80169691Skan            apr_bucket_free(p);
81169691Skan        }
82169691Skan    }
83169691Skan    else {
84169691Skan        /* the shared resource is no longer in the pool, it's
85169691Skan         * on the heap, but this reference still thinks it's a pool
86169691Skan         * bucket.  we should just go ahead and pass control to
87169691Skan         * heap_destroy() for it since it doesn't know any better.
88169691Skan         */
89169691Skan        apr_bucket_type_heap.destroy(p);
90169691Skan    }
91169691Skan}
92169691Skan
93169691SkanAPU_DECLARE(apr_bucket *) apr_bucket_pool_make(apr_bucket *b,
94169691Skan                      const char *buf, apr_size_t length, apr_pool_t *pool)
95169691Skan{
96169691Skan    apr_bucket_pool *p;
97169691Skan
98169691Skan    p = apr_bucket_alloc(sizeof(*p), b->list);
99169691Skan
100169691Skan    /* XXX: we lose the const qualifier here which indicates
101169691Skan     * there's something screwy with the API...
102169691Skan     */
103169691Skan    /* XXX: why is this?  buf is const, p->base is const... what's
104169691Skan     * the problem?  --jcw */
105169691Skan    p->base = (char *) buf;
106169691Skan    p->pool = pool;
107169691Skan    p->list = b->list;
108
109    b = apr_bucket_shared_make(b, p, 0, length);
110    b->type = &apr_bucket_type_pool;
111
112    /* pre-initialize heap bucket member */
113    p->heap.alloc_len = length;
114    p->heap.base      = NULL;
115    p->heap.free_func = apr_bucket_free;
116
117    apr_pool_cleanup_register(p->pool, p, pool_bucket_cleanup,
118                              apr_pool_cleanup_null);
119    return b;
120}
121
122APU_DECLARE(apr_bucket *) apr_bucket_pool_create(const char *buf,
123                                                 apr_size_t length,
124                                                 apr_pool_t *pool,
125                                                 apr_bucket_alloc_t *list)
126{
127    apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
128
129    APR_BUCKET_INIT(b);
130    b->free = apr_bucket_free;
131    b->list = list;
132    return apr_bucket_pool_make(b, buf, length, pool);
133}
134
135APU_DECLARE_DATA const apr_bucket_type_t apr_bucket_type_pool = {
136    "POOL", 5, APR_BUCKET_DATA,
137    pool_bucket_destroy,
138    pool_bucket_read,
139    apr_bucket_setaside_noop, /* don't need to setaside thanks to the cleanup*/
140    apr_bucket_shared_split,
141    apr_bucket_shared_copy
142};
143