diff options
Diffstat (limited to 'include/apreq_util.h')
-rw-r--r-- | include/apreq_util.h | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/include/apreq_util.h b/include/apreq_util.h new file mode 100644 index 0000000000..feb2d396ce --- /dev/null +++ b/include/apreq_util.h @@ -0,0 +1,443 @@ +/* +** Licensed to the Apache Software Foundation (ASF) under one or more +** contributor license agreements. See the NOTICE file distributed with +** this work for additional information regarding copyright ownership. +** The ASF licenses this file to You 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. +*/ + +#ifndef APREQ_UTIL_H +#define APREQ_UTIL_H + +#include "apr_file_io.h" +#include "apr_buckets.h" +#include "apreq.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * This header contains useful functions for creating new + * parsers, hooks or modules. It includes + * + * - string <-> array converters + * - substring search functions + * - simple encoders & decoders for urlencoded strings + * - simple time, date, & file-size converters + * @file apreq_util.h + * @brief Utility functions for apreq. + * @ingroup libapreq2 + */ + +/** + * Join an array of values. The result is an empty string if there are + * no values. + * + * @param p Pool to allocate return value. + * @param sep String that is inserted between the joined values. + * @param arr Array of apreq_value_t entries. + * @param mode Join type- see apreq_join_t. + * + * @return Joined string, or NULL on error + */ +APREQ_DECLARE(char *) apreq_join(apr_pool_t *p, + const char *sep, + const apr_array_header_t *arr, + apreq_join_t mode); + +/** + * Returns offset of match string's location, or -1 if no match is found. + * + * @param hay Location of bytes to scan. + * @param hlen Number of bytes available for scanning. + * @param ndl Search string + * @param nlen Length of search string. + * @param type Match type. + * + * @return Offset of match string, or -1 if no match is found. + * + */ +APREQ_DECLARE(apr_ssize_t) apreq_index(const char* hay, apr_size_t hlen, + const char* ndl, apr_size_t nlen, + const apreq_match_t type); + +/** + * Places a quoted copy of src into dest. Embedded quotes are escaped with a + * backslash ('\'). + * + * @param dest Location of quoted copy. Must be large enough to hold the copy + * and trailing null byte. + * @param src Original string. + * @param slen Length of original string. + * @param dest Destination string. + * + * @return length of quoted copy in dest. + */ +APREQ_DECLARE(apr_size_t) apreq_quote(char *dest, const char *src, + const apr_size_t slen); + +/** + * + * Same as apreq_quote() except when src begins and ends in quote marks. In + * that case it assumes src is quoted correctly, and just copies src to dest. + * + * @param dest Location of quoted copy. Must be large enough to hold the copy + * and trailing null byte. + * @param src Original string. + * @param slen Length of original string. + * @param dest Destination string. + * + * @return length of quoted copy in dest. + */ +APREQ_DECLARE(apr_size_t) apreq_quote_once(char *dest, const char *src, + const apr_size_t slen); + +/** + * Url-encodes a string. + * + * @param dest Location of url-encoded result string. Caller must ensure it + * is large enough to hold the encoded string and trailing '\\0'. + * @param src Original string. + * @param slen Length of original string. + * + * @return length of url-encoded string in dest; does not exceed 3 * slen. + */ +APREQ_DECLARE(apr_size_t) apreq_encode(char *dest, const char *src, + const apr_size_t slen); + +/** + * Convert a string from cp1252 to utf8. Caller must ensure it is large enough + * to hold the encoded string and trailing '\\0'. + * + * @param dest Location of utf8-encoded result string. Caller must ensure it + * is large enough to hold the encoded string and trailing '\\0'. + * @param src Original string. + * @param slen Length of original string. + * + * @return length of utf8-encoded string in dest; does not exceed 3 * slen. + */ +APREQ_DECLARE(apr_size_t) apreq_cp1252_to_utf8(char *dest, + const char *src, apr_size_t slen); + +/** + * Heuristically determine the charset of a string. + * + * @param src String to scan. + * @param slen Length of string. + * + * @return APREQ_CHARSET_ASCII if the string contains only 7-bit chars; + * @return APREQ_CHARSET_UTF8 if the string is a valid utf8 byte sequence; + * @return APREQ_CHARSET_LATIN1 if the string has no control chars; + * @return APREQ_CHARSET_CP1252 if the string has control chars. + */ +APREQ_DECLARE(apreq_charset_t) apreq_charset_divine(const char *src, + apr_size_t slen); + +/** + * Url-decodes a string. + * + * @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 */ |