1251876Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251876Speter * contributor license agreements.  See the NOTICE file distributed with
3251876Speter * this work for additional information regarding copyright ownership.
4251876Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251876Speter * (the "License"); you may not use this file except in compliance with
6251876Speter * the License.  You may obtain a copy of the License at
7251876Speter *
8251876Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251876Speter *
10251876Speter * Unless required by applicable law or agreed to in writing, software
11251876Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251876Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251876Speter * See the License for the specific language governing permissions and
14251876Speter * limitations under the License.
15251876Speter */
16251876Speter
17251876Speter#include "apr_buckets.h"
18251876Speter#define APR_WANT_MEMFUNC
19251876Speter#include "apr_want.h"
20251876Speter
21251876Speterstatic apr_status_t pool_bucket_cleanup(void *data)
22251876Speter{
23251876Speter    apr_bucket_pool *p = data;
24251876Speter
25251876Speter    /*
26251876Speter     * If the pool gets cleaned up, we have to copy the data out
27251876Speter     * of the pool and onto the heap.  But the apr_buckets out there
28251876Speter     * that point to this pool bucket need to be notified such that
29251876Speter     * they can morph themselves into a regular heap bucket the next
30251876Speter     * time they try to read.  To avoid having to manipulate
31251876Speter     * reference counts and b->data pointers, the apr_bucket_pool
32251876Speter     * actually _contains_ an apr_bucket_heap as its first element,
33251876Speter     * so the two share their apr_bucket_refcount member, and you
34251876Speter     * can typecast a pool bucket struct to make it look like a
35251876Speter     * regular old heap bucket struct.
36251876Speter     */
37251876Speter    p->heap.base = apr_bucket_alloc(p->heap.alloc_len, p->list);
38251876Speter    memcpy(p->heap.base, p->base, p->heap.alloc_len);
39251876Speter    p->base = NULL;
40251876Speter    p->pool = NULL;
41251876Speter
42251876Speter    return APR_SUCCESS;
43251876Speter}
44251876Speter
45251876Speterstatic apr_status_t pool_bucket_read(apr_bucket *b, const char **str,
46251876Speter                                     apr_size_t *len, apr_read_type_e block)
47251876Speter{
48251876Speter    apr_bucket_pool *p = b->data;
49251876Speter    const char *base = p->base;
50251876Speter
51251876Speter    if (p->pool == NULL) {
52251876Speter        /*
53251876Speter         * pool has been cleaned up... masquerade as a heap bucket from now
54251876Speter         * on. subsequent bucket operations will use the heap bucket code.
55251876Speter         */
56251876Speter        b->type = &apr_bucket_type_heap;
57251876Speter        base = p->heap.base;
58251876Speter    }
59251876Speter    *str = base + b->start;
60251876Speter    *len = b->length;
61251876Speter    return APR_SUCCESS;
62251876Speter}
63251876Speter
64251876Speterstatic void pool_bucket_destroy(void *data)
65251876Speter{
66251876Speter    apr_bucket_pool *p = data;
67251876Speter
68251876Speter    /* If the pool is cleaned up before the last reference goes
69251876Speter     * away, the data is really now on the heap; heap_destroy() takes
70251876Speter     * over.  free() in heap_destroy() thinks it's freeing
71251876Speter     * an apr_bucket_heap, when in reality it's freeing the whole
72251876Speter     * apr_bucket_pool for us.
73251876Speter     */
74251876Speter    if (p->pool) {
75251876Speter        /* the shared resource is still in the pool
76251876Speter         * because the pool has not been cleaned up yet
77251876Speter         */
78251876Speter        if (apr_bucket_shared_destroy(p)) {
79251876Speter            apr_pool_cleanup_kill(p->pool, p, pool_bucket_cleanup);
80251876Speter            apr_bucket_free(p);
81251876Speter        }
82251876Speter    }
83251876Speter    else {
84251876Speter        /* the shared resource is no longer in the pool, it's
85251876Speter         * on the heap, but this reference still thinks it's a pool
86251876Speter         * bucket.  we should just go ahead and pass control to
87251876Speter         * heap_destroy() for it since it doesn't know any better.
88251876Speter         */
89251876Speter        apr_bucket_type_heap.destroy(p);
90251876Speter    }
91251876Speter}
92251876Speter
93251876SpeterAPU_DECLARE(apr_bucket *) apr_bucket_pool_make(apr_bucket *b,
94251876Speter                      const char *buf, apr_size_t length, apr_pool_t *pool)
95251876Speter{
96251876Speter    apr_bucket_pool *p;
97251876Speter
98251876Speter    p = apr_bucket_alloc(sizeof(*p), b->list);
99251876Speter
100251876Speter    /* XXX: we lose the const qualifier here which indicates
101251876Speter     * there's something screwy with the API...
102251876Speter     */
103251876Speter    /* XXX: why is this?  buf is const, p->base is const... what's
104251876Speter     * the problem?  --jcw */
105251876Speter    p->base = (char *) buf;
106251876Speter    p->pool = pool;
107251876Speter    p->list = b->list;
108251876Speter
109251876Speter    b = apr_bucket_shared_make(b, p, 0, length);
110251876Speter    b->type = &apr_bucket_type_pool;
111251876Speter
112251876Speter    /* pre-initialize heap bucket member */
113251876Speter    p->heap.alloc_len = length;
114251876Speter    p->heap.base      = NULL;
115251876Speter    p->heap.free_func = apr_bucket_free;
116251876Speter
117251876Speter    apr_pool_cleanup_register(p->pool, p, pool_bucket_cleanup,
118251876Speter                              apr_pool_cleanup_null);
119251876Speter    return b;
120251876Speter}
121251876Speter
122251876SpeterAPU_DECLARE(apr_bucket *) apr_bucket_pool_create(const char *buf,
123251876Speter                                                 apr_size_t length,
124251876Speter                                                 apr_pool_t *pool,
125251876Speter                                                 apr_bucket_alloc_t *list)
126251876Speter{
127251876Speter    apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
128251876Speter
129251876Speter    APR_BUCKET_INIT(b);
130251876Speter    b->free = apr_bucket_free;
131251876Speter    b->list = list;
132251876Speter    return apr_bucket_pool_make(b, buf, length, pool);
133251876Speter}
134251876Speter
135251876SpeterAPU_DECLARE_DATA const apr_bucket_type_t apr_bucket_type_pool = {
136251876Speter    "POOL", 5, APR_BUCKET_DATA,
137251876Speter    pool_bucket_destroy,
138251876Speter    pool_bucket_read,
139251876Speter    apr_bucket_setaside_noop, /* don't need to setaside thanks to the cleanup*/
140251876Speter    apr_bucket_shared_split,
141251876Speter    apr_bucket_shared_copy
142251876Speter};
143