1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "apr_buckets.h" 18#define APR_WANT_MEMFUNC 19#include "apr_want.h" 20 21static apr_status_t pool_bucket_cleanup(void *data) 22{ 23 apr_bucket_pool *p = data; 24 25 /* 26 * If the pool gets cleaned up, we have to copy the data out 27 * of the pool and onto the heap. But the apr_buckets out there 28 * that point to this pool bucket need to be notified such that 29 * they can morph themselves into a regular heap bucket the next 30 * time they try to read. To avoid having to manipulate 31 * reference counts and b->data pointers, the apr_bucket_pool 32 * actually _contains_ an apr_bucket_heap as its first element, 33 * so the two share their apr_bucket_refcount member, and you 34 * can typecast a pool bucket struct to make it look like a 35 * regular old heap bucket struct. 36 */ 37 p->heap.base = apr_bucket_alloc(p->heap.alloc_len, p->list); 38 memcpy(p->heap.base, p->base, p->heap.alloc_len); 39 p->base = NULL; 40 p->pool = NULL; 41 42 return APR_SUCCESS; 43} 44 45static apr_status_t pool_bucket_read(apr_bucket *b, const char **str, 46 apr_size_t *len, apr_read_type_e block) 47{ 48 apr_bucket_pool *p = b->data; 49 const char *base = p->base; 50 51 if (p->pool == NULL) { 52 /* 53 * pool has been cleaned up... masquerade as a heap bucket from now 54 * on. subsequent bucket operations will use the heap bucket code. 55 */ 56 b->type = &apr_bucket_type_heap; 57 base = p->heap.base; 58 } 59 *str = base + b->start; 60 *len = b->length; 61 return APR_SUCCESS; 62} 63 64static void pool_bucket_destroy(void *data) 65{ 66 apr_bucket_pool *p = data; 67 68 /* If the pool is cleaned up before the last reference goes 69 * away, the data is really now on the heap; heap_destroy() takes 70 * over. free() in heap_destroy() thinks it's freeing 71 * an apr_bucket_heap, when in reality it's freeing the whole 72 * apr_bucket_pool for us. 73 */ 74 if (p->pool) { 75 /* the shared resource is still in the pool 76 * because the pool has not been cleaned up yet 77 */ 78 if (apr_bucket_shared_destroy(p)) { 79 apr_pool_cleanup_kill(p->pool, p, pool_bucket_cleanup); 80 apr_bucket_free(p); 81 } 82 } 83 else { 84 /* the shared resource is no longer in the pool, it's 85 * on the heap, but this reference still thinks it's a pool 86 * bucket. we should just go ahead and pass control to 87 * heap_destroy() for it since it doesn't know any better. 88 */ 89 apr_bucket_type_heap.destroy(p); 90 } 91} 92 93APU_DECLARE(apr_bucket *) apr_bucket_pool_make(apr_bucket *b, 94 const char *buf, apr_size_t length, apr_pool_t *pool) 95{ 96 apr_bucket_pool *p; 97 98 p = apr_bucket_alloc(sizeof(*p), b->list); 99 100 /* XXX: we lose the const qualifier here which indicates 101 * there's something screwy with the API... 102 */ 103 /* XXX: why is this? buf is const, p->base is const... what's 104 * the problem? --jcw */ 105 p->base = (char *) buf; 106 p->pool = pool; 107 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