apreq_util.h revision d5ef50bb5810983012435957be0680bde34d1e44
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke/*
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke** Licensed to the Apache Software Foundation (ASF) under one or more
9eb6a481980d81a55898ba418fba72fc3c09d8c8Dominik Luecke** contributor license agreements. See the NOTICE file distributed with
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke** this work for additional information regarding copyright ownership.
98890889ffb2e8f6f722b00e265a211f13b5a861Corneliu-Claudiu Prodescu** The ASF licenses this file to You under the Apache License, Version 2.0
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke** (the "License"); you may not use this file except in compliance with
2eeec5240b424984e3ee26296da1eeab6c6d739eChristian Maeder** the License. You may obtain a copy of the License at
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke**
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke** http://www.apache.org/licenses/LICENSE-2.0
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke**
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke** Unless required by applicable law or agreed to in writing, software
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder** distributed under the License is distributed on an "AS IS" BASIS,
2af38fde95f93562f2124ec615fba0e509c8202eDominik Luecke** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2af38fde95f93562f2124ec615fba0e509c8202eDominik Luecke** See the License for the specific language governing permissions and
2af38fde95f93562f2124ec615fba0e509c8202eDominik Luecke** limitations under the License.
cf04ba46b9eb495d334466e24e082e391055ca7bDominik Luecke*/
2af38fde95f93562f2124ec615fba0e509c8202eDominik Luecke
2af38fde95f93562f2124ec615fba0e509c8202eDominik Luecke#ifndef APREQ_UTIL_H
926b3c5491f1c608f5b79e2d8014d7a1385558c3Dominik Luecke#define APREQ_UTIL_H
2af38fde95f93562f2124ec615fba0e509c8202eDominik Luecke
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke#include "apr_file_io.h"
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke#include "apr_buckets.h"
da955132262baab309a50fdffe228c9efe68251dCui Jian#include "apreq.h"
16e124196c6b204769042028c74f533509c9b5d3Christian Maeder
16e124196c6b204769042028c74f533509c9b5d3Christian Maeder#ifdef __cplusplus
16e124196c6b204769042028c74f533509c9b5d3Christian Maeder extern "C" {
16e124196c6b204769042028c74f533509c9b5d3Christian Maeder#endif
16e124196c6b204769042028c74f533509c9b5d3Christian Maeder
16e124196c6b204769042028c74f533509c9b5d3Christian Maeder/**
16e124196c6b204769042028c74f533509c9b5d3Christian Maeder * This header contains useful functions for creating new
16e124196c6b204769042028c74f533509c9b5d3Christian Maeder * parsers, hooks or modules. It includes
16e124196c6b204769042028c74f533509c9b5d3Christian Maeder *
16e124196c6b204769042028c74f533509c9b5d3Christian Maeder * - string <-> array converters
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder * - substring search functions
16e124196c6b204769042028c74f533509c9b5d3Christian Maeder * - simple encoders & decoders for urlencoded strings
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke * - simple time, date, & file-size converters
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke * @file apreq_util.h
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke * @brief Utility functions for apreq.
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke * @ingroup libapreq2
5b9f5c1b3592b99fc74d3438740ebcf9eb4c94beDominik Luecke */
2ea0ce749d2525f96d5d2f285f519ab07b005b8dDominik Luecke
5b9f5c1b3592b99fc74d3438740ebcf9eb4c94beDominik Luecke/**
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke * Join an array of values. The result is an empty string if there are
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke * no values.
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke *
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke * @param p Pool to allocate return value.
da955132262baab309a50fdffe228c9efe68251dCui Jian * @param sep String that is inserted between the joined values.
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * @param arr Array of apreq_value_t entries.
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke * @param mode Join type- see apreq_join_t.
16e124196c6b204769042028c74f533509c9b5d3Christian Maeder *
16e124196c6b204769042028c74f533509c9b5d3Christian Maeder * @return Joined string, or NULL on error
16e124196c6b204769042028c74f533509c9b5d3Christian Maeder */
16e124196c6b204769042028c74f533509c9b5d3Christian MaederAPREQ_DECLARE(char *) apreq_join(apr_pool_t *p,
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke const char *sep,
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke const apr_array_header_t *arr,
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder apreq_join_t mode);
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder/**
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke * Returns offset of match string's location, or -1 if no match is found.
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder *
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke * @param hay Location of bytes to scan.
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke * @param hlen Number of bytes available for scanning.
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke * @param ndl Search string
da955132262baab309a50fdffe228c9efe68251dCui Jian * @param nlen Length of search string.
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * @param type Match type.
548f3850942936a8c6021185c8391dfcd3b03018Dominik Luecke *
548f3850942936a8c6021185c8391dfcd3b03018Dominik Luecke * @return Offset of match string, or -1 if no match is found.
0b53895114b00141ec17ffdc7e26acded4487328Christian Maeder *
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder */
548f3850942936a8c6021185c8391dfcd3b03018Dominik LueckeAPREQ_DECLARE(apr_ssize_t) apreq_index(const char* hay, apr_size_t hlen,
548f3850942936a8c6021185c8391dfcd3b03018Dominik Luecke const char* ndl, apr_size_t nlen,
548f3850942936a8c6021185c8391dfcd3b03018Dominik Luecke const apreq_match_t type);
548f3850942936a8c6021185c8391dfcd3b03018Dominik Luecke
548f3850942936a8c6021185c8391dfcd3b03018Dominik Luecke/**
548f3850942936a8c6021185c8391dfcd3b03018Dominik Luecke * Places a quoted copy of src into dest. Embedded quotes are escaped with a
5b2e9f4673599e1bc6e18a43ad615da28305b8e1Christian Maeder * backslash ('\').
548f3850942936a8c6021185c8391dfcd3b03018Dominik Luecke *
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke * @param dest Location of quoted copy. Must be large enough to hold the copy
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke * and trailing null byte.
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke * @param src Original string.
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * @param slen Length of original string.
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * @param dest Destination string.
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke *
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke * @return length of quoted copy in dest.
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke */
a23e572c8f957cc051a1b0831abd6fe9380d45c7Christian MaederAPREQ_DECLARE(apr_size_t) apreq_quote(char *dest, const char *src,
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder const apr_size_t slen);
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder/**
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder *
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * Same as apreq_quote() except when src begins and ends in quote marks. In
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * that case it assumes src is quoted correctly, and just copies src to dest.
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke *
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke * @param dest Location of quoted copy. Must be large enough to hold the copy
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke * and trailing null byte.
0859769b65851f4c06d6d32fac084b0f4db56c94Christian Maeder * @param src Original string.
da955132262baab309a50fdffe228c9efe68251dCui Jian * @param slen Length of original string.
4df63f7187b1ba16cbe5c781db187a42f2f49579Dominik Luecke * @param dest Destination string.
b694e4b3f771a2f32042c9c505dd698bde969558Dominik Luecke *
5b9f5c1b3592b99fc74d3438740ebcf9eb4c94beDominik Luecke * @return length of quoted copy in dest.
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder */
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian MaederAPREQ_DECLARE(apr_size_t) apreq_quote_once(char *dest, const char *src,
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder const apr_size_t slen);
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder/**
2ea0ce749d2525f96d5d2f285f519ab07b005b8dDominik Luecke * Url-encodes a string.
2ea0ce749d2525f96d5d2f285f519ab07b005b8dDominik Luecke *
2ea0ce749d2525f96d5d2f285f519ab07b005b8dDominik Luecke * @param dest Location of url-encoded result string. Caller must ensure it
2ea0ce749d2525f96d5d2f285f519ab07b005b8dDominik Luecke * is large enough to hold the encoded string and trailing '\\0'.
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * @param src Original string.
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * @param slen Length of original string.
2ea0ce749d2525f96d5d2f285f519ab07b005b8dDominik Luecke *
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * @return length of url-encoded string in dest; does not exceed 3 * slen.
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder */
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian MaederAPREQ_DECLARE(apr_size_t) apreq_encode(char *dest, const char *src,
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder const apr_size_t slen);
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder/**
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * Convert a string from cp1252 to utf8. Caller must ensure it is large enough
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * to hold the encoded string and trailing '\\0'.
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder *
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * @param dest Location of utf8-encoded result string. Caller must ensure it
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * is large enough to hold the encoded string and trailing '\\0'.
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * @param src Original string.
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * @param slen Length of original string.
0b53895114b00141ec17ffdc7e26acded4487328Christian Maeder *
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder * @return length of utf8-encoded string in dest; does not exceed 3 * slen.
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder */
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian MaederAPREQ_DECLARE(apr_size_t) apreq_cp1252_to_utf8(char *dest,
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder const char *src, apr_size_t slen);
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder/**
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder * Heuristically determine the charset of a string.
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder *
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder * @param src String to scan.
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder * @param slen Length of string.
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder *
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder * @return APREQ_CHARSET_ASCII if the string contains only 7-bit chars;
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder * @return APREQ_CHARSET_UTF8 if the string is a valid utf8 byte sequence;
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder * @return APREQ_CHARSET_LATIN1 if the string has no control chars;
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder * @return APREQ_CHARSET_CP1252 if the string has control chars.
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder */
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian MaederAPREQ_DECLARE(apreq_charset_t) apreq_charset_divine(const char *src,
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder apr_size_t slen);
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder/**
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder * Url-decodes a string.
202df46772cac2ee2e8627ba196a5faebb6f9a05Christian Maeder *
* @param dest Location of url-encoded result string. Caller must ensure dest is
* large enough to hold the encoded string and trailing null character.
* @param dlen points to resultant length of url-decoded string in dest
* @param src Original string.
* @param slen Length of original string.
*
* @return APR_SUCCESS.
* @return APR_INCOMPLETE if the string
* ends in the middle of an escape sequence.
* @return ::APREQ_ERROR_BADSEQ or ::APREQ_ERROR_BADCHAR on malformed input.
*
* @remarks In the non-success case, dlen will be set to include
* the last succesfully decoded value. This function decodes
* \%uXXXX into a utf8 (wide) character, following ECMA-262
* (the Javascript spec) Section B.2.1.
*/
APREQ_DECLARE(apr_status_t) apreq_decode(char *dest, apr_size_t *dlen,
const char *src, apr_size_t slen);
/**
* Url-decodes an iovec array.
*
* @param dest Location of url-encoded result string. Caller must ensure dest is
* large enough to hold the encoded string and trailing null character.
* @param dlen Resultant length of dest.
* @param v Array of iovecs that represent the source string
* @param nelts Number of iovecs in the array.
*
* @return APR_SUCCESS.
* @return APR_INCOMPLETE if the iovec
* ends in the middle of an escape sequence.
* @return ::APREQ_ERROR_BADSEQ or ::APREQ_ERROR_BADCHAR on malformed input.
*
* @remarks In the non-APR_SUCCESS case, dlen will be set to include
* the last succesfully decoded value. This function decodes
* \%uXXXX into a utf8 (wide) character, following ECMA-262
* (the Javascript spec) Section B.2.1.
*/
APREQ_DECLARE(apr_status_t) apreq_decodev(char *dest, apr_size_t *dlen,
struct iovec *v, int nelts);
/**
* Returns an url-encoded copy of a string.
*
* @param p Pool used to allocate the return value.
* @param src Original string.
* @param slen Length of original string.
*
* @return The url-encoded string.
*
* @remarks Use this function insead of apreq_encode if its
* caller might otherwise overflow dest.
*/
static APR_INLINE
char *apreq_escape(apr_pool_t *p, const char *src, const apr_size_t slen)
{
char *rv;
if (src == NULL)
return NULL;
rv = (char *)apr_palloc(p, 3 * slen + 1);
apreq_encode(rv, src, slen);
return rv;
}
/**
* An \e in-situ url-decoder.
*
* @param str The string to decode
*
* @return Length of decoded string, or < 0 on error.
*/
static APR_INLINE apr_ssize_t apreq_unescape(char *str)
{
apr_size_t len;
apr_status_t rv = apreq_decode(str, &len, str, strlen(str));
if (rv == APR_SUCCESS)
return (apr_ssize_t)len;
else
return -1;
}
/**
* Converts file sizes (KMG) to bytes
*
* @param s file size matching m/^\\d+[KMG]b?$/i
*
* @return 64-bit integer representation of s.
*
* @todo What happens when s is malformed? Should this return
* an unsigned value instead?
*/
APREQ_DECLARE(apr_int64_t) apreq_atoi64f(const char *s);
/**
* Converts time strings (YMDhms) to seconds
*
* @param s time string matching m/^\\+?\\d+[YMDhms]$/
*
* @return 64-bit integer representation of s as seconds.
*
* @todo What happens when s is malformed? Should this return
* an unsigned value instead?
*/
APREQ_DECLARE(apr_int64_t) apreq_atoi64t(const char *s);
/**
* Writes brigade to a file.
*
* @param f File that gets the brigade.
* @param wlen On a successful return, wlen holds the length of
* the brigade, which is the amount of data written to
* the file.
* @param bb Bucket brigade.
*
* @return APR_SUCCESS.
* @return Error status code from either an unsuccessful apr_bucket_read(),
* or a failed apr_file_writev().
*
* @remarks This function leaks a bucket brigade into bb->p whenever
* the final bucket in bb is a spool bucket.
*/
APREQ_DECLARE(apr_status_t) apreq_brigade_fwrite(apr_file_t *f,
apr_off_t *wlen,
apr_bucket_brigade *bb);
/**
* Makes a temporary file.
*
* @param fp Points to the temporary apr_file_t on success.
* @param pool Pool to associate with the temp file. When the
* pool is destroyed, the temp file will be closed
* and deleted.
* @param path The base directory which will contain the temp file.
* If param == NULL, the directory will be selected via
* tempnam(). See the tempnam manpage for details.
*
* @return APR_SUCCESS.
* @return Error status code from unsuccessful apr_filepath_merge(),
* or a failed apr_file_mktemp().
*/
APREQ_DECLARE(apr_status_t) apreq_file_mktemp(apr_file_t **fp,
apr_pool_t *pool,
const char *path);
/**
* Set aside all buckets in the brigade.
*
* @param bb Brigade.
* @param p Setaside buckets into this pool.
* @return APR_SUCCESS.
* @return Error status code from an unsuccessful apr_bucket_setaside().
*/
static APR_INLINE
apr_status_t apreq_brigade_setaside(apr_bucket_brigade *bb, apr_pool_t *p)
{
apr_bucket *e;
for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb);
e = APR_BUCKET_NEXT(e))
{
apr_status_t rv = apr_bucket_setaside(e, p);
if (rv != APR_SUCCESS)
return rv;
}
return APR_SUCCESS;
}
/**
* Copy a brigade.
*
* @param d (destination) Copied buckets are appended to this brigade.
* @param s (source) Brigade to copy from.
*
* @return APR_SUCCESS.
* @return Error status code from an unsuccessful apr_bucket_copy().
*
* @remarks s == d produces Undefined Behavior.
*/
static APR_INLINE
apr_status_t apreq_brigade_copy(apr_bucket_brigade *d, apr_bucket_brigade *s) {
apr_bucket *e;
for (e = APR_BRIGADE_FIRST(s); e != APR_BRIGADE_SENTINEL(s);
e = APR_BUCKET_NEXT(e))
{
apr_bucket *c;
apr_status_t rv = apr_bucket_copy(e, &c);
if (rv != APR_SUCCESS)
return rv;
APR_BRIGADE_INSERT_TAIL(d, c);
}
return APR_SUCCESS;
}
/**
* Move the front of a brigade.
*
* @param d (destination) Append buckets to this brigade.
* @param s (source) Brigade to take buckets from.
* @param e First bucket of s after the move. All buckets
* before e are appended to d.
*
* @remarks This moves all buckets when e == APR_BRIGADE_SENTINEL(s).
*/
static APR_INLINE
void apreq_brigade_move(apr_bucket_brigade *d, apr_bucket_brigade *s,
apr_bucket *e)
{
apr_bucket *f;
if (e != APR_BRIGADE_SENTINEL(s)) {
f = APR_RING_FIRST(&s->list);
if (f == e) /* zero buckets to be moved */
return;
/* obtain the last bucket to be moved */
e = APR_RING_PREV(e, link);
APR_RING_UNSPLICE(f, e, link);
APR_RING_SPLICE_HEAD(&d->list, f, e, apr_bucket, link);
}
else {
APR_BRIGADE_CONCAT(d, s);
}
}
/**
* Search a header string for the value of a particular named attribute.
*
* @param hdr Header string to scan.
* @param name Name of attribute to search for.
* @param nlen Length of name.
* @param val Location of (first) matching value.
* @param vlen Length of matching value.
*
* @return APR_SUCCESS.
* @return ::APREQ_ERROR_NOATTR if the attribute is not found.
* @return ::APREQ_ERROR_BADSEQ if an unpaired quote mark was detected.
*/
APREQ_DECLARE(apr_status_t) apreq_header_attribute(const char *hdr,
const char *name,
const apr_size_t nlen,
const char **val,
apr_size_t *vlen);
/**
* Concatenates the brigades, spooling large brigades into
* a tempfile (APREQ_SPOOL) bucket.
*
* @param pool Pool for creating a tempfile bucket.
* @param temp_dir Directory for tempfile creation.
* @param brigade_limit If out's length would exceed this value,
* the appended buckets get written to a tempfile.
* @param out Resulting brigade.
* @param in Brigade to append.
*
* @return APR_SUCCESS.
* @return Error status code resulting from either apr_brigade_length(),
* apreq_file_mktemp(), apreq_brigade_fwrite(), or apr_file_seek().
*
* @todo Flesh out these error codes, making them as explicit as possible.
*/
APREQ_DECLARE(apr_status_t) apreq_brigade_concat(apr_pool_t *pool,
const char *temp_dir,
apr_size_t brigade_limit,
apr_bucket_brigade *out,
apr_bucket_brigade *in);
/**
* Determines the spool file used by the brigade. Returns NULL if the
* brigade is not spooled in a file (does not use an APREQ_SPOOL
* bucket).
*
* @param bb the bucket brigade
* @return the spool file, or NULL.
*/
APREQ_DECLARE(apr_file_t *) apreq_brigade_spoolfile(apr_bucket_brigade *bb);
#ifdef __cplusplus
}
#endif
#endif /* APREQ_UTIL_H */