| /* | |
| ** 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 */ |