{ Copyright 2000-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. } { * @file apr_buckets.h * @brief APR-UTIL Buckets/Bucket Brigades } {#if defined(APR_BUCKET_DEBUG) && !defined(APR_RING_DEBUG) #define APR_RING_DEBUG #endif #include "apu.h" #include "apr_network_io.h" #include "apr_file_io.h" #include "apr_general.h" #include "apr_mmap.h" #include "apr_errno.h" #include "apr_ring.h" #include "apr.h" #if APR_HAVE_SYS_UIO_H #include for struct iovec #endif #if APR_HAVE_STDARG_H #include #endif} { * @defgroup APR_Util_Bucket_Brigades Bucket Brigades * @ingroup APR_Util } { default bucket buffer size - 8KB minus room for memory allocator headers } const APR_BUCKET_BUFF_SIZE = 8000; { Determines how a bucket or brigade should be read } type apr_read_type_e = ( APR_BLOCK_READ, {< block until data becomes available } APR_NONBLOCK_READ {< return immediately if no data is available } ); { * The one-sentence buzzword-laden overview: Bucket brigades represent * a complex data stream that can be passed through a layered IO * system without unnecessary copying. A longer overview follows... * * A bucket brigade is a doubly linked list (ring) of buckets, so we * aren't limited to inserting at the front and removing at the end. * Buckets are only passed around as members of a brigade, although * singleton buckets can occur for short periods of time. * * Buckets are data stores of various 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, 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 * so that it can refer to the new location of the data. If all the * data doesn't fit in the bucket then a new bucket is inserted into * the brigade to hold the rest of it. * * split divides the data in a bucket into two regions. After a split * the original bucket refers to the first part of the data and a new * bucket inserted into the brigade after the original bucket refers * to the second part of the data. Reference counts are maintained as * necessary. * * setaside ensures that the data in the bucket has a long enough * lifetime. Sometimes it is convenient to create a bucket referring * to data on the stack in the expectation that it will be consumed * (output to the network) before the stack is unwound. If that * 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 (apr_bucket_read(), * apr_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 * performance, then we need to compact the buckets before we convert to an * iovec, or possibly while we are converting to an iovec. } { * Forward declaration of the main types. } { @see apr_bucket_brigade } Papr_bucket_brigade = ^apr_bucket_brigade; PPapr_bucket_brigade = ^Papr_bucket_brigade; { @see apr_bucket } Papr_bucket = ^apr_bucket; PPapr_bucket = ^Papr_bucket; { @see apr_bucket_alloc_t } apr_bucket_alloc_t = record end; Papr_bucket_alloc_t = ^apr_bucket_alloc_t; { @see apr_bucket_type_t } Papr_bucket_type_t = ^apr_bucket_type_t; is_metadata = ( { This bucket type represents actual data to send to the client. } APR_BUCKET_DATA = 0, { This bucket type represents metadata. } APR_BUCKET_METADATA = 1 ); destroy_t = procedure (data: Pointer); read_t = function (b: Papr_bucket; const str: PPChar; len: Papr_size_t; block: apr_read_type_e): apr_status_t; setaside_t = function (e: Papr_bucket; pool: Papr_pool_t): apr_status_t; split_t = function (e: Papr_bucket; point: apr_size_t): apr_status_t; copy_t = function (e: Papr_bucket; c: PPapr_bucket): apr_status_t; { * Basic bucket type } apr_bucket_type_t = record { * The name of the bucket type } name: PChar; { * The number of functions this bucket understands. Can not be less than * five. } num_func: Integer; { * Whether the bucket contains metadata (ie, information that * describes the regular contents of the brigade). The metadata * is not returned by apr_bucket_read() and is not indicated by * the ->length of the apr_bucket itself. In other words, an * empty bucket is safe to arbitrarily remove if and only if it * contains no metadata. In this sense, "data" is just raw bytes * that are the "content" of the brigade and "metadata" describes * that data but is not a proper part of it. } { Declaration moved up } { * Free the private data and any resources used by the bucket (if they * aren't shared with another bucket). This function is required to be * implemented for all bucket types, though it might be a no-op on some * of them (namely ones that never allocate any private data structures). * @param data The private data pointer from the bucket to be destroyed } destroy: destroy_t; { * Read the data from the bucket. This is required 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. * @param len The amount of data read. * @param block Should this read function block if there is more data that * cannot be read immediately. } read: read_t; { * Make it possible to set aside the data for at least as long as the * given pool. Buckets containing data that could potentially die before * this pool (e.g. the data resides on the stack, in a child pool of * the given pool, or in a disjoint pool) must somehow copy, shift, or * transform the data to have the proper lifetime. * @param e The bucket to convert * @remark Some bucket types contain data that will always outlive the * bucket itself. For example no data (EOS and FLUSH), or the data * resides in global, constant memory (IMMORTAL), or the data is on * the heap (HEAP). For these buckets, apr_bucket_setaside_noop can * be used. } setaside: setaside_t; { * 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. * @param e The bucket to split * @param point The offset of the first byte in the new bucket } split: split_t; { * Copy the bucket structure (not the data), assuming that this is * possible for the bucket type. If it's not, APR_ENOTIMPL is returned. * @param e The bucket to copy * @param c Returns a pointer to the new bucket } copy: copy_t; end; { * apr_bucket structures are allocated on the malloc() heap and * their lifetime is controlled by the parent apr_bucket_brigade * structure. Buckets can move from one brigade to another e.g. by * calling APR_BRIGADE_CONCAT(). In general the data in a bucket has * the same lifetime as the bucket and is freed when the bucket is * destroyed; if the data is shared by more than one bucket (e.g. * after a split) the data is freed when the last bucket goes away. } free_t = procedure(e: Pointer); link_t = record next: Papr_bucket; prev: Papr_bucket; end; apr_bucket = record { Links to the rest of the brigade } link: link_t; { The type of bucket. } type_: Papr_bucket_type_t; { The length of the data in the bucket. This could have been implemented * with a function, but this is an optimization, because the most * common thing to do will be to get the length. If the length is unknown, * the value of this field will be (apr_size_t)(-1). } length: apr_size_t; { The start of the data in the bucket relative to the private base * pointer. The vast majority of bucket types allow a fixed block of * data to be referenced by multiple buckets, each bucket pointing to * a different segment of the data. That segment starts at base+start * and ends at base+start+length. * If the length == (apr_size_t)(-1), then start == -1. } start: apr_off_t; { type-dependent data hangs off this pointer } data: Pointer; { * Pointer to function used to free the bucket. This function should * always be defined and it should be consistent with the memory * function used to allocate the bucket. For example, if malloc() is * used to allocate the bucket, this pointer should point to free(). * @param e Pointer to the bucket being freed } free: free_t; { The freelist from which this bucket was allocated } list: Papr_bucket_alloc_t; end; { A list of buckets } apr_bucket_list = record next: Papr_bucket; prev: Papr_bucket; end; apr_bucket_brigade = record { The pool to associate the brigade with. The data is not allocated out * of the pool, but a cleanup is registered with this pool. If the * brigade is destroyed by some mechanism other than pool destruction, * the destroying function is responsible for killing the cleanup. } p: Papr_pool_t; { The buckets in the brigade are on this list. } { * The apr_bucket_list structure doesn't actually need a name tag * because it has no existence independent of struct apr_bucket_brigade; * the ring macros are designed so that you can leave the name tag * argument empty in this situation but apparently the Windows compiler * doesn't like that. } list: apr_bucket_list; { The freelist from which this bucket was allocated } bucket_alloc: Papr_bucket_alloc_t; end; { * Function called when a brigade should be flushed } apr_brigade_flush = function (bb: Papr_bucket_brigade; ctx: Pointer): apr_status_t; { * define APR_BUCKET_DEBUG if you want your brigades to be checked for * validity at every possible instant. this will slow your code down * substantially but is a very useful debugging tool. } {#ifdef APR_BUCKET_DEBUG #define APR_BRIGADE_CHECK_CONSISTENCY(b) \ APR_RING_CHECK_CONSISTENCY(&(b)->list, apr_bucket, link) #define APR_BUCKET_CHECK_CONSISTENCY(e) \ APR_RING_CHECK_ELEM_CONSISTENCY((e), apr_bucket, link) #else} { * checks the ring pointers in a bucket brigade for consistency. an * abort() will be triggered if any inconsistencies are found. * note: this is a no-op unless APR_BUCKET_DEBUG is defined. * @param b The brigade } //#define APR_BRIGADE_CHECK_CONSISTENCY(b) { * checks the brigade a bucket is in for ring consistency. an * abort() will be triggered if any inconsistencies are found. * note: this is a no-op unless APR_BUCKET_DEBUG is defined. * @param e The bucket } //#define APR_BUCKET_CHECK_CONSISTENCY(e) //#endif { * Wrappers around the RING macros to reduce the verbosity of the code * that handles bucket brigades. } { * The magic pointer value that indicates the head of the brigade * @remark This is used to find the beginning and end of the brigade, eg: *
 *      while (e != APR_BRIGADE_SENTINEL(b)) (
 *          ...
 *          e = APR_BUCKET_NEXT(e);
 *      )
 * 
* @param b The brigade * @return The magic pointer value } //#define APR_BRIGADE_SENTINEL(b) APR_RING_SENTINEL(&(b)->list, apr_bucket, link) { * Determine if the bucket brigade is empty * @param b The brigade to check * @return true or false } //#define APR_BRIGADE_EMPTY(b) APR_RING_EMPTY(&(b)->list, apr_bucket, link) { * Return the first bucket in a brigade * @param b The brigade to query * @return The first bucket in the brigade } //#define APR_BRIGADE_FIRST(b) APR_RING_FIRST(&(b)->list) { * Return the last bucket in a brigade * @param b The brigade to query * @return The last bucket in the brigade } //#define APR_BRIGADE_LAST(b) APR_RING_LAST(&(b)->list) { * Insert a list of buckets at the front of a brigade * @param b The brigade to add to * @param e The first bucket in a list of buckets to insert } {#define APR_BRIGADE_INSERT_HEAD(b, e) do ( \ apr_bucket *ap__b = (e); \ APR_RING_INSERT_HEAD(&(b)->list, ap__b, apr_bucket, link); \ APR_BRIGADE_CHECK_CONSISTENCY((b)); \ ) while (0)} { * Insert a list of buckets at the end of a brigade * @param b The brigade to add to * @param e The first bucket in a list of buckets to insert } {#define APR_BRIGADE_INSERT_TAIL(b, e) do begin \ apr_bucket *ap__b = (e); \ APR_RING_INSERT_TAIL(&(b)->list, ap__b, apr_bucket, link); \ APR_BRIGADE_CHECK_CONSISTENCY((b)); \ end while (0)} { * Concatenate brigade b onto the end of brigade a, leaving brigade b empty * @param a The first brigade * @param b The second brigade } {#define APR_BRIGADE_CONCAT(a, b) do begin APR_RING_CONCAT(&(a)->list, &(b)->list, apr_bucket, link); \ APR_BRIGADE_CHECK_CONSISTENCY((a)); \ end while (0);} { * Prepend brigade b onto the beginning of brigade a, leaving brigade b empty * @param a The first brigade * @param b The second brigade } {#define APR_BRIGADE_PREPEND(a, b) do begin APR_RING_PREPEND(&(a)->list, &(b)->list, apr_bucket, link); \ APR_BRIGADE_CHECK_CONSISTENCY((a)); \ end while (0)} { * Insert a list of buckets before a specified bucket * @param a The bucket to insert before * @param b The buckets to insert } {#define APR_BUCKET_INSERT_BEFORE(a, b) do begin apr_bucket *ap__a = (a), *ap__b = (b); \ APR_RING_INSERT_BEFORE(ap__a, ap__b, link); \ APR_BUCKET_CHECK_CONSISTENCY(ap__a); \ end while (0)} { * Insert a list of buckets after a specified bucket * @param a The bucket to insert after * @param b The buckets to insert } {#define APR_BUCKET_INSERT_AFTER(a, b) do begin apr_bucket *ap__a = (a), *ap__b = (b); \ APR_RING_INSERT_AFTER(ap__a, ap__b, link); \ APR_BUCKET_CHECK_CONSISTENCY(ap__a); \ end while (0)} { * Get the next bucket in the list * @param e The current bucket * @return The next bucket } //#define APR_BUCKET_NEXT(e) APR_RING_NEXT((e), link) { * Get the previous bucket in the list * @param e The current bucket * @return The previous bucket } //#define APR_BUCKET_PREV(e) APR_RING_PREV((e), link) { * Remove a bucket from its bucket brigade * @param e The bucket to remove } //#define APR_BUCKET_REMOVE(e) APR_RING_REMOVE((e), link) { * Initialize a new bucket's prev/next pointers * @param e The bucket to initialize } //#define APR_BUCKET_INIT(e) APR_RING_ELEM_INIT((e), link) { * Determine if a bucket contains metadata. An empty bucket is * safe to arbitrarily remove if and only if this is false. * @param e The bucket to inspect * @return true or false } //#define APR_BUCKET_IS_METADATA(e) ((e)->type->is_metadata) { * Determine if a bucket is a FLUSH bucket * @param e The bucket to inspect * @return true or false } //#define APR_BUCKET_IS_FLUSH(e) ((e)->type == &apr_bucket_type_flush) { * Determine if a bucket is an EOS bucket * @param e The bucket to inspect * @return true or false } //#define APR_BUCKET_IS_EOS(e) ((e)->type == &apr_bucket_type_eos) { * Determine if a bucket is a FILE bucket * @param e The bucket to inspect * @return true or false } //#define APR_BUCKET_IS_FILE(e) ((e)->type == &apr_bucket_type_file) { * Determine if a bucket is a PIPE bucket * @param e The bucket to inspect * @return true or false } //#define APR_BUCKET_IS_PIPE(e) ((e)->type == &apr_bucket_type_pipe) { * Determine if a bucket is a SOCKET bucket * @param e The bucket to inspect * @return true or false } //#define APR_BUCKET_IS_SOCKET(e) ((e)->type == &apr_bucket_type_socket) { * Determine if a bucket is a HEAP bucket * @param e The bucket to inspect * @return true or false } //#define APR_BUCKET_IS_HEAP(e) ((e)->type == &apr_bucket_type_heap) { * Determine if a bucket is a TRANSIENT bucket * @param e The bucket to inspect * @return true or false } //#define APR_BUCKET_IS_TRANSIENT(e) ((e)->type == &apr_bucket_type_transient) { * Determine if a bucket is a IMMORTAL bucket * @param e The bucket to inspect * @return true or false } //#define APR_BUCKET_IS_IMMORTAL(e) ((e)->type == &apr_bucket_type_immortal) //#if APR_HAS_MMAP { * Determine if a bucket is a MMAP bucket * @param e The bucket to inspect * @return true or false } //#define APR_BUCKET_IS_MMAP(e) ((e)->type == &apr_bucket_type_mmap) //#endif { * Determine if a bucket is a POOL bucket * @param e The bucket to inspect * @return true or false } //#define APR_BUCKET_IS_POOL(e) ((e)->type == &apr_bucket_type_pool) { * General-purpose reference counting for the various bucket types. * * Any bucket type that keeps track of the resources it uses (i.e. * most of them except for IMMORTAL, TRANSIENT, and EOS) needs to * attach a reference count to the resource so that it can be freed * when the last bucket that uses it goes away. Resource-sharing may * occur because of bucket splits or buckets that refer to globally * cached data. } { @see apr_bucket_refcount } Papr_bucket_refcount = ^apr_bucket_refcount; { * The structure used to manage the shared resource must start with an * apr_bucket_refcount which is updated by the general-purpose refcount * code. A pointer to the bucket-type-dependent private data structure * can be cast to a pointer to an apr_bucket_refcount and vice versa. } apr_bucket_refcount = record { The number of references to this bucket } refcount: Integer; end; { ***** Reference-counted bucket types ***** } { @see apr_bucket_heap } Papr_bucket_heap = ^apr_bucket_heap; { * A bucket referring to data allocated off the heap. } free_func_t = procedure (data: Pointer); apr_bucket_heap = record { Number of buckets using this memory } refcount: apr_bucket_refcount; { The start of the data actually allocated. This should never be * modified, it is only used to free the bucket. } base: PChar; { how much memory was allocated } alloc_len: apr_size_t; { function to use to delete the data } free_func: free_func_t; end; { @see apr_bucket_pool } Papr_bucket_pool = ^apr_bucket_pool; { * A bucket referring to data allocated from a pool } apr_bucket_pool = record { The pool bucket must be able to be easily morphed to a heap * bucket if the pool gets cleaned up before all references are * destroyed. This apr_bucket_heap structure is populated automatically * when the pool gets cleaned up, and subsequent calls to pool_read() * will result in the apr_bucket in question being morphed into a * regular heap bucket. (To avoid having to do many extra refcount * manipulations and b->data manipulations, the apr_bucket_pool * struct actually *contains* the apr_bucket_heap struct that it * will become as its first element; the two share their * apr_bucket_refcount members.) } heap: apr_bucket_heap; { The block of data actually allocated from the pool. * Segments of this block are referenced by adjusting * the start and length of the apr_bucket accordingly. * This will be NULL after the pool gets cleaned up. } base: PChar; { The pool the data was allocated from. When the pool * is cleaned up, this gets set to NULL as an indicator * to pool_read() that the data is now on the heap and * so it should morph the bucket into a regular heap * bucket before continuing. } pool: Papr_pool_t; { The freelist this structure was allocated from, which is * needed in the cleanup phase in order to allocate space on the heap } list: Papr_bucket_alloc_t; end; {$ifdef APR_HAS_MMAP} { @see apr_bucket_mmap } Papr_bucket_mmap = ^apr_bucket_mmap; { * A bucket referring to an mmap()ed file } apr_bucket_mmap = record { Number of buckets using this memory } refcount: apr_bucket_refcount; { The mmap this sub_bucket refers to } mmap: Papr_mmap_t; end; {$endif} { @see apr_bucket_file } Papr_bucket_file = ^apr_bucket_file; { * A bucket referring to an file } apr_bucket_file = record { Number of buckets using this memory } refcount: apr_bucket_refcount; { The file this bucket refers to } fd: Papr_file_t; { The pool into which any needed structures should * be created while reading from this file bucket } readpool: Papr_pool_t; {$ifdef APR_HAS_MMAP} { Whether this bucket should be memory-mapped if * a caller tries to read from it } can_mmap: Integer; {$endif} { APR_HAS_MMAP } end; { @see apr_bucket_structs } Papr_bucket_structs = ^apr_bucket_structs; { * A union of all bucket structures so we know what * the max size is. } apr_bucket_structs = record case Integer of 0: (b: apr_bucket); {< Bucket } 1: (heap: apr_bucket_heap); {< Heap } 2: (pool: apr_bucket_pool); {< Pool } {$ifdef APR_HAS_MMAP} 3: (mmap: apr_bucket_mmap); {< MMap } {$endif} 4: (file_: apr_bucket_file); {< File } end; { * The amount that apr_bucket_alloc() should allocate in the common case. * Note: this is twice as big as apr_bucket_structs to allow breathing * room for third-party bucket types. } //#define APR_BUCKET_ALLOC_SIZE APR_ALIGN_DEFAULT(2*sizeof(apr_bucket_structs)) { ***** Bucket Brigade Functions ***** } { * Create a new bucket brigade. The bucket brigade is originally empty. * @param p The pool to associate with the brigade. Data is not allocated out * of the pool, but a cleanup is registered. * @param list The bucket allocator to use * @return The empty bucket brigade } //APU_DECLARE(apr_bucket_brigade *) apr_brigade_create(apr_pool_t *p, // apr_bucket_alloc_t *list); { * destroy an entire bucket brigade. This includes destroying all of the * buckets within the bucket brigade's bucket list. * @param b The bucket brigade to destroy } //APU_DECLARE(apr_status_t) apr_brigade_destroy(apr_bucket_brigade *b); { * empty out an entire bucket brigade. This includes destroying all of the * buckets within the bucket brigade's bucket list. This is similar to * apr_brigade_destroy(), except that it does not deregister the brigade's * pool cleanup function. * @param data The bucket brigade to clean up * @remark Generally, you should use apr_brigade_destroy(). This function * can be useful in situations where you have a single brigade that * you wish to reuse many times by destroying all of the buckets in * the brigade and putting new buckets into it later. } //APU_DECLARE(apr_status_t) apr_brigade_cleanup(void *data); { * Split a bucket brigade into two, such that the given bucket is the * first in the new bucket brigade. This function is useful when a * filter wants to pass only the initial part of a brigade to the next * filter. * @param b The brigade to split * @param e The first element of the new brigade * @return The new brigade } //APU_DECLARE(apr_bucket_brigade *) apr_brigade_split(apr_bucket_brigade *b, // apr_bucket *e); { * Partition a bucket brigade at a given offset (in bytes from the start of * the brigade). This is useful whenever a filter wants to use known ranges * of bytes from the brigade; the ranges can even overlap. * @param b The brigade to partition * @param point The offset at which to partition the brigade * @param after_point Returns a pointer to the first bucket after the partition * @return APR_SUCCESS on success, APR_INCOMPLETE if the contents of the * brigade were shorter than @a point, or an error code. * @remark if APR_INCOMPLETE is returned, @a after_point will be set to * the brigade sentinel. } //APU_DECLARE(apr_status_t) apr_brigade_partition(apr_bucket_brigade *b, // apr_off_t point, // apr_bucket **after_point); { * Return the total length of the brigade. * @param bb The brigade to compute the length of * @param read_all Read unknown-length buckets to force a size * @param length Returns the length of the brigade, or -1 if the brigade has * buckets of indeterminate length and read_all is 0. } {APU_DECLARE(apr_status_t) apr_brigade_length(apr_bucket_brigade *bb, int read_all, apr_off_t *length); } { * Take a bucket brigade and store the data in a flat char* * @param bb The bucket brigade to create the char* from * @param c The char* to write into * @param len The maximum length of the char array. On return, it is the * actual length of the char array. } {APU_DECLARE(apr_status_t) apr_brigade_flatten(apr_bucket_brigade *bb, char *c, apr_size_t *len); } { * Creates a pool-allocated string representing a flat bucket brigade * @param bb The bucket brigade to create the char array from * @param c On return, the allocated char array * @param len On return, the length of the char array. * @param pool The pool to allocate the string from. } {APU_DECLARE(apr_status_t) apr_brigade_pflatten(apr_bucket_brigade *bb, char **c, apr_size_t *len, apr_pool_t *pool); } { * Split a brigade to represent one LF line. * @param bbOut The bucket brigade that will have the LF line appended to. * @param bbIn The input bucket brigade to search for a LF-line. * @param block The blocking mode to be used to split the line. * @param maxbytes The maximum bytes to read. If this many bytes are seen * without a LF, the brigade will contain a partial line. } {APU_DECLARE(apr_status_t) apr_brigade_split_line(apr_bucket_brigade *bbOut, apr_bucket_brigade *bbIn, apr_read_type_e block, apr_off_t maxbytes); } { * create an iovec of the elements in a bucket_brigade... return number * of elements used. This is useful for writing to a file or to the * network efficiently. * @param b The bucket brigade to create the iovec from * @param vec The iovec to create * @param nvec The number of elements in the iovec. On return, it is the * number of iovec elements actually filled out. } {APU_DECLARE(apr_status_t) apr_brigade_to_iovec(apr_bucket_brigade *b, struct iovec *vec, int *nvec); } { * This function writes a list of strings into a bucket brigade. * @param b The bucket brigade to add to * @param flush The flush function to use if the brigade is full * @param ctx The structure to pass to the flush function * @param va A list of strings to add * @return APR_SUCCESS or error code. } {APU_DECLARE(apr_status_t) apr_brigade_vputstrs(apr_bucket_brigade *b, apr_brigade_flush flush, void *ctx, va_list va); } { * This function writes a string into a bucket brigade. * @param b The bucket brigade to add to * @param flush The flush function to use if the brigade is full * @param ctx The structure to pass to the flush function * @param str The string to add * @param nbyte The number of bytes to write * @return APR_SUCCESS or error code } {APU_DECLARE(apr_status_t) apr_brigade_write(apr_bucket_brigade *b, apr_brigade_flush flush, void *ctx, const char *str, apr_size_t nbyte); } { * This function writes multiple strings into a bucket brigade. * @param b The bucket brigade to add to * @param flush The flush function to use if the brigade is full * @param ctx The structure to pass to the flush function * @param vec The strings to add (address plus length for each) * @param nvec The number of entries in iovec * @return APR_SUCCESS or error code } {APU_DECLARE(apr_status_t) apr_brigade_writev(apr_bucket_brigade *b, apr_brigade_flush flush, void *ctx, const struct iovec *vec, apr_size_t nvec); } { * This function writes a string into a bucket brigade. * @param bb The bucket brigade to add to * @param flush The flush function to use if the brigade is full * @param ctx The structure to pass to the flush function * @param str The string to add * @return APR_SUCCESS or error code } {APU_DECLARE(apr_status_t) apr_brigade_puts(apr_bucket_brigade *bb, apr_brigade_flush flush, void *ctx, const char *str); } { * This function writes a character into a bucket brigade. * @param b The bucket brigade to add to * @param flush The flush function to use if the brigade is full * @param ctx The structure to pass to the flush function * @param c The character to add * @return APR_SUCCESS or error code } {APU_DECLARE(apr_status_t) apr_brigade_putc(apr_bucket_brigade *b, apr_brigade_flush flush, void *ctx, const char c); } { * This function writes an unspecified number of strings into a bucket brigade. * @param b The bucket brigade to add to * @param flush The flush function to use if the brigade is full * @param ctx The structure to pass to the flush function * @param ... The strings to add * @return APR_SUCCESS or error code } {APU_DECLARE_NONSTD(apr_status_t) apr_brigade_putstrs(apr_bucket_brigade *b, apr_brigade_flush flush, void *ctx, ...); } { * Evaluate a printf and put the resulting string at the end * of the bucket brigade. * @param b The brigade to write to * @param flush The flush function to use if the brigade is full * @param ctx The structure to pass to the flush function * @param fmt The format of the string to write * @param ... The arguments to fill out the format * @return APR_SUCCESS or error code } {APU_DECLARE_NONSTD(apr_status_t) apr_brigade_printf(apr_bucket_brigade *b, apr_brigade_flush flush, void *ctx, const char *fmt, ...) __attribute__((format(printf,4,5))); } { * Evaluate a printf and put the resulting string at the end * of the bucket brigade. * @param b The brigade to write to * @param flush The flush function to use if the brigade is full * @param ctx The structure to pass to the flush function * @param fmt The format of the string to write * @param va The arguments to fill out the format * @return APR_SUCCESS or error code } {APU_DECLARE(apr_status_t) apr_brigade_vprintf(apr_bucket_brigade *b, apr_brigade_flush flush, void *ctx, const char *fmt, va_list va); } { * Utility function to insert a file (or a segment of a file) onto the * end of the brigade. The file is split into multiple buckets if it * is larger than the maximum size which can be represented by a * single bucket. * @param bb the brigade to insert into * @param f the file to insert * @param start the offset of the start of the segment * @param len the length of the segment of the file to insert * @param p pool from which file buckets are allocated * @return the last bucket inserted } {APU_DECLARE(apr_bucket *) apr_brigade_insert_file(apr_bucket_brigade *bb, apr_file_t *f, apr_off_t start, apr_off_t len, apr_pool_t *p);} { ***** Bucket freelist functions ***** } { * Create a bucket allocator. * @param p This pool's underlying apr_allocator_t is used to allocate memory * for the bucket allocator. When the pool is destroyed, the bucket * allocator's cleanup routine will free all memory that has been * allocated from it. * @remark The reason the allocator gets its memory from the pool's * apr_allocator_t rather than from the pool itself is because * the bucket allocator will free large memory blocks back to the * allocator when it's done with them, thereby preventing memory * footprint growth that would occur if we allocated from the pool. * @warning The allocator must never be used by more than one thread at a time. } //APU_DECLARE_NONSTD(apr_bucket_alloc_t *) apr_bucket_alloc_create(apr_pool_t *p); { * Create a bucket allocator. * @param allocator This apr_allocator_t is used to allocate both the bucket * allocator and all memory handed out by the bucket allocator. The * caller is responsible for destroying the bucket allocator and the * apr_allocator_t -- no automatic cleanups will happen. * @warning The allocator must never be used by more than one thread at a time. } //APU_DECLARE_NONSTD(apr_bucket_alloc_t *) apr_bucket_alloc_create_ex(apr_allocator_t *allocator); { * Destroy a bucket allocator. * @param list The allocator to be destroyed } //APU_DECLARE_NONSTD(void) apr_bucket_alloc_destroy(apr_bucket_alloc_t *list); { * Allocate memory for use by the buckets. * @param size The amount to allocate. * @param list The allocator from which to allocate the memory. } //APU_DECLARE_NONSTD(void *) apr_bucket_alloc(apr_size_t size, apr_bucket_alloc_t *list); { * Free memory previously allocated with apr_bucket_alloc(). * @param block The block of memory to be freed. } //APU_DECLARE_NONSTD(void) apr_bucket_free(void *block); { ***** Bucket Functions ***** } { * Free the resources used by a bucket. If multiple buckets refer to * the same resource it is freed when the last one goes away. * @see apr_bucket_delete() * @param e The bucket to destroy } {#define apr_bucket_destroy(e) do begin (e)->type->destroy((e)->data); \ (e)->free(e); \ end while (0)} { * Delete a bucket by removing it from its brigade (if any) and then * destroying it. * @remark This mainly acts as an aid in avoiding code verbosity. It is * the preferred exact equivalent to: *
 *      APR_BUCKET_REMOVE(e);
 *      apr_bucket_destroy(e);
 * 
* @param e The bucket to delete } {#define apr_bucket_delete(e) do begin APR_BUCKET_REMOVE(e); \ apr_bucket_destroy(e); \ end while (0)} { * read the data from the bucket * @param e The bucket to read from * @param str The location to store the data in * @param len The amount of data read * @param block Whether the read function blocks } //#define apr_bucket_read(e,str,len,block) (e)->type->read(e, str, len, block) { * Setaside data so that stack data is not destroyed on returning from * the function * @param e The bucket to setaside * @param p The pool to setaside into } //#define apr_bucket_setaside(e,p) (e)->type->setaside(e,p) { * Split one bucket in two. * @param e The bucket to split * @param point The offset to split the bucket at } //#define apr_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 } //#define apr_bucket_copy(e,c) (e)->type->copy(e, c) { Bucket type handling } { * This function simply returns APR_SUCCESS to denote that the bucket does * not require anything to happen for its setaside() function. This is * appropriate for buckets that have "immortal" data -- the data will live * at least as long as the bucket. * @param data The bucket to setaside * @param pool The pool defining the desired lifetime of the bucket data * @return APR_SUCCESS } {APU_DECLARE_NONSTD(apr_status_t) apr_bucket_setaside_noop(apr_bucket *data, apr_pool_t *pool); } { * A place holder function that signifies that the setaside function was not * implemented for this bucket * @param data The bucket to setaside * @param pool The pool defining the desired lifetime of the bucket data * @return APR_ENOTIMPL } {APU_DECLARE_NONSTD(apr_status_t) apr_bucket_setaside_notimpl(apr_bucket *data, apr_pool_t *pool); } { * A place holder function that signifies that the split function was not * implemented for this bucket * @param data The bucket to split * @param point The location to split the bucket * @return APR_ENOTIMPL } {APU_DECLARE_NONSTD(apr_status_t) apr_bucket_split_notimpl(apr_bucket *data, apr_size_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 } {APU_DECLARE_NONSTD(apr_status_t) apr_bucket_copy_notimpl(apr_bucket *e, apr_bucket **c); } { * A place holder function that signifies that this bucket does not need * to do anything special to be destroyed. That's only the case for buckets * that either have no data (metadata buckets) or buckets whose data pointer * points to something that's not a bucket-type-specific structure, as with * simple buckets where data points to a string and pipe buckets where data * points directly to the apr_file_t. * @param data The bucket data to destroy } //APU_DECLARE_NONSTD(void) apr_bucket_destroy_noop(void *data); { * There is no apr_bucket_destroy_notimpl, because destruction is required * to be implemented (it could be a noop, but only if that makes sense for * the bucket type) } { There is no apr_bucket_read_notimpl, because it is a required function } { All of the bucket types implemented by the core } { * The flush bucket type. This signifies that all data should be flushed to * the next filter. The flush bucket should be sent with the other buckets. } //APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_flush; { * The EOS bucket type. This signifies that there will be no more data, ever. * All filters MUST send all data to the next filter when they receive a * bucket of this type } //APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_eos; { * The FILE bucket type. This bucket represents a file on disk } //APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_file; { * The HEAP bucket type. This bucket represents a data allocated from the * heap. } //APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_heap; //#if APR_HAS_MMAP { * The MMAP bucket type. This bucket represents an MMAP'ed file } //APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_mmap; //#endif { * The POOL bucket type. This bucket represents a data that was allocated * from a pool. IF this bucket is still available when the pool is cleared, * the data is copied on to the heap. } //APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_pool; { * The PIPE bucket type. This bucket represents a pipe to another program. } //APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_pipe; { * The IMMORTAL bucket type. This bucket represents a segment of data that * the creator is willing to take responsibility for. The core will do * nothing with the data in an immortal bucket } //APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_immortal; { * The TRANSIENT bucket type. This bucket represents a data allocated off * the stack. When the setaside function is called, this data is copied on * to the heap } //APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_transient; { * The SOCKET bucket type. This bucket represents a socket to another machine } //APU_DECLARE_DATA extern const apr_bucket_type_t apr_bucket_type_socket; { ***** Simple buckets ***** } { * Split a simple bucket into two at the given point. Most non-reference * counting buckets that allow multiple references to the same block of * data (eg transient and immortal) will use this as their split function * without any additional type-specific handling. * @param b The bucket to be split * @param point The offset of the first byte in the new bucket * @return APR_EINVAL if the point is not within the bucket; * APR_ENOMEM if allocation failed; * or APR_SUCCESS } //APU_DECLARE_NONSTD(apr_status_t) apr_bucket_simple_split(apr_bucket *b, // apr_size_t point); { * Copy a simple bucket. Most non-reference-counting buckets that allow * multiple references to the same block of data (eg transient and immortal) * will use this as their copy function without any additional type-specific * handling. * @param a The bucket to copy * @param b Returns a pointer to the new bucket * @return APR_ENOMEM if allocation failed; * or APR_SUCCESS } {APU_DECLARE_NONSTD(apr_status_t) apr_bucket_simple_copy(apr_bucket *a, apr_bucket **b); } { ***** Shared, reference-counted buckets ***** } { * Initialize a bucket containing reference-counted data that may be * shared. The caller must allocate the bucket if necessary and * initialize its type-dependent fields, and allocate and initialize * its own private data structure. This function should only be called * by type-specific bucket creation functions. * @param b The bucket to initialize * @param data A pointer to the private data structure * with the reference count at the start * @param start The start of the data in the bucket * relative to the private base pointer * @param length The length of the data in the bucket * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_shared_make(apr_bucket *b, void *data, apr_off_t start, apr_size_t length); } { * Decrement the refcount of the data in the bucket. This function * should only be called by type-specific bucket destruction functions. * @param data The private data pointer from the bucket to be destroyed * @return TRUE or FALSE; TRUE if the reference count is now * zero, indicating that the shared resource itself can * be destroyed by the caller. } //APU_DECLARE(int) apr_bucket_shared_destroy(void *data); { * Split a bucket into two at the given point, and adjust the refcount * to the underlying data. Most reference-counting bucket types will * be able to use this function as their split function without any * additional type-specific handling. * @param b The bucket to be split * @param point The offset of the first byte in the new bucket * @return APR_EINVAL if the point is not within the bucket; * APR_ENOMEM if allocation failed; * or APR_SUCCESS } //APU_DECLARE_NONSTD(apr_status_t) apr_bucket_shared_split(apr_bucket *b, // apr_size_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 b Returns a pointer to the new bucket * @return APR_ENOMEM if allocation failed; or APR_SUCCESS } //APU_DECLARE_NONSTD(apr_status_t) apr_bucket_shared_copy(apr_bucket *a, // apr_bucket **b); { ***** Functions to Create Buckets of varying types ***** } { * Each bucket type foo has two initialization functions: * apr_bucket_foo_make which sets up some already-allocated memory as a * bucket of type foo; and apr_bucket_foo_create which allocates memory * for the bucket, calls apr_bucket_make_foo, and initializes the * bucket's list pointers. The apr_bucket_foo_make functions are used * inside the bucket code to change the type of buckets in place; * other code should call apr_bucket_foo_create. All the initialization * functions change nothing if they fail. } { * Create an End of Stream bucket. This indicates that there is no more data * coming from down the filter stack. All filters should flush at this point. * @param list The freelist from which this bucket should be allocated * @return The new bucket, or NULL if allocation failed } //APU_DECLARE(apr_bucket *) apr_bucket_eos_create(apr_bucket_alloc_t *list); { * Make the bucket passed in an EOS bucket. This indicates that there is no * more data coming from down the filter stack. All filters should flush at * this point. * @param b The bucket to make into an EOS bucket * @return The new bucket, or NULL if allocation failed } //APU_DECLARE(apr_bucket *) apr_bucket_eos_make(apr_bucket *b); { * Create a flush bucket. This indicates that filters should flush their * data. There is no guarantee that they will flush it, but this is the * best we can do. * @param list The freelist from which this bucket should be allocated * @return The new bucket, or NULL if allocation failed } //APU_DECLARE(apr_bucket *) apr_bucket_flush_create(apr_bucket_alloc_t *list); { * Make the bucket passed in a FLUSH bucket. This indicates that filters * should flush their data. There is no guarantee that they will flush it, * but this is the best we can do. * @param b The bucket to make into a FLUSH bucket * @return The new bucket, or NULL if allocation failed } //APU_DECLARE(apr_bucket *) apr_bucket_flush_make(apr_bucket *b); { * Create a bucket referring to long-lived data. * @param buf The data to insert into the bucket * @param nbyte The size of the data to insert. * @param list The freelist from which this bucket should be allocated * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_immortal_create(const char *buf, apr_size_t nbyte, apr_bucket_alloc_t *list); } { * Make the bucket passed in a bucket refer to long-lived data * @param b The bucket to make into a IMMORTAL bucket * @param buf The data to insert into the bucket * @param nbyte The size of the data to insert. * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_immortal_make(apr_bucket *b, const char *buf, apr_size_t nbyte); } { * Create a bucket referring to data on the stack. * @param buf The data to insert into the bucket * @param nbyte The size of the data to insert. * @param list The freelist from which this bucket should be allocated * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_transient_create(const char *buf, apr_size_t nbyte, apr_bucket_alloc_t *list); } { * Make the bucket passed in a bucket refer to stack data * @param b The bucket to make into a TRANSIENT bucket * @param buf The data to insert into the bucket * @param nbyte The size of the data to insert. * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_transient_make(apr_bucket *b, const char *buf, apr_size_t nbyte); } { * Create a bucket referring to memory on the heap. If the caller asks * for the data to be copied, this function always allocates 4K of * memory so that more data can be added to the bucket without * requiring another allocation. Therefore not all the data may be put * into the bucket. If copying is not requested then the bucket takes * over responsibility for free()ing the memory. * @param buf The buffer to insert into the bucket * @param nbyte The size of the buffer to insert. * @param free_func Function to use to free the data; NULL indicates that the * bucket should make a copy of the data * @param list The freelist from which this bucket should be allocated * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_heap_create(const char *buf, apr_size_t nbyte, void ( *free_func)(void *data), apr_bucket_alloc_t *list);} { * Make the bucket passed in a bucket refer to heap data * @param b The bucket to make into a HEAP bucket * @param buf The buffer to insert into the bucket * @param nbyte The size of the buffer to insert. * @param free_func Function to use to free the data; NULL indicates that the * bucket should make a copy of the data * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_heap_make(apr_bucket *b, const char *buf, apr_size_t nbyte, void ( *free_func)(void *data));} { * Create a bucket referring to memory allocated from a pool. * * @param buf The buffer to insert into the bucket * @param length The number of bytes referred to by this bucket * @param pool The pool the memory was allocated from * @param list The freelist from which this bucket should be allocated * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_pool_create(const char *buf, apr_size_t length, apr_pool_t *pool, apr_bucket_alloc_t *list);} { * Make the bucket passed in a bucket refer to pool data * @param b The bucket to make into a pool bucket * @param buf The buffer to insert into the bucket * @param length The number of bytes referred to by this bucket * @param pool The pool the memory was allocated from * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_pool_make(apr_bucket *b, const char *buf, apr_size_t length, apr_pool_t *pool);} //#if APR_HAS_MMAP { * Create a bucket referring to mmap()ed memory. * @param mm The mmap to insert into the bucket * @param start The offset of the first byte in the mmap * that this bucket refers to * @param length The number of bytes referred to by this bucket * @param list The freelist from which this bucket should be allocated * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_mmap_create(apr_mmap_t *mm, apr_off_t start, apr_size_t length, apr_bucket_alloc_t *list); } { * Make the bucket passed in a bucket refer to an MMAP'ed file * @param b The bucket to make into a MMAP bucket * @param mm The mmap to insert into the bucket * @param start The offset of the first byte in the mmap * that this bucket refers to * @param length The number of bytes referred to by this bucket * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_mmap_make(apr_bucket *b, apr_mmap_t *mm, apr_off_t start, apr_size_t length); #endif} { * Create a bucket referring to a socket. * @param thissock The socket to put in the bucket * @param list The freelist from which this bucket should be allocated * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_socket_create(apr_socket_t *thissock, apr_bucket_alloc_t *list);} { * Make the bucket passed in a bucket refer to a socket * @param b The bucket to make into a SOCKET bucket * @param thissock The socket to put in the bucket * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_socket_make(apr_bucket *b, apr_socket_t *thissock);} { * Create a bucket referring to a pipe. * @param thispipe The pipe to put in the bucket * @param list The freelist from which this bucket should be allocated * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_pipe_create(apr_file_t *thispipe, apr_bucket_alloc_t *list);} { * Make the bucket passed in a bucket refer to a pipe * @param b The bucket to make into a PIPE bucket * @param thispipe The pipe to put in the bucket * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_pipe_make(apr_bucket *b, apr_file_t *thispipe);} { * Create a bucket referring to a file. * @param fd The file to put in the bucket * @param offset The offset where the data of interest begins in the file * @param len The amount of data in the file we are interested in * @param p The pool into which any needed structures should be created * while reading from this file bucket * @param list The freelist from which this bucket should be allocated * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_file_create(apr_file_t *fd, apr_off_t offset, apr_size_t len, apr_pool_t *p, apr_bucket_alloc_t *list); } { * Make the bucket passed in a bucket refer to a file * @param b The bucket to make into a FILE bucket * @param fd The file to put in the bucket * @param offset The offset where the data of interest begins in the file * @param len The amount of data in the file we are interested in * @param p The pool into which any needed structures should be created * while reading from this file bucket * @return The new bucket, or NULL if allocation failed } {APU_DECLARE(apr_bucket *) apr_bucket_file_make(apr_bucket *b, apr_file_t *fd, apr_off_t offset, apr_size_t len, apr_pool_t *p); } { * Enable or disable memory-mapping for a FILE bucket (default is enabled) * @param b The bucket * @param enabled Whether memory-mapping should be enabled * @return APR_SUCCESS normally, or an error code if the operation fails } {APU_DECLARE(apr_status_t) apr_bucket_file_enable_mmap(apr_bucket *b, int enabled);}