2 ** Licensed to the Apache Software Foundation (ASF) under one or more
3 ** contributor license agreements. See the NOTICE file distributed with
4 ** this work for additional information regarding copyright ownership.
5 ** The ASF licenses this file to You under the Apache License, Version 2.0
6 ** (the "License"); you may not use this file except in compliance with
7 ** the License. You may obtain a copy of the License at
9 ** http://www.apache.org/licenses/LICENSE-2.0
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
21 #include "apr_file_io.h"
22 #include "apr_buckets.h"
30 * This header contains useful functions for creating new
31 * parsers, hooks or modules. It includes
33 * - string <-> array converters
34 * - substring search functions
35 * - simple encoders & decoders for urlencoded strings
36 * - simple time, date, & file-size converters
38 * @brief Utility functions for apreq.
43 * Join an array of values. The result is an empty string if there are
46 * @param p Pool to allocate return value.
47 * @param sep String that is inserted between the joined values.
48 * @param arr Array of apreq_value_t entries.
49 * @param mode Join type- see apreq_join_t.
51 * @return Joined string, or NULL on error
53 APREQ_DECLARE(char *) apreq_join(apr_pool_t *p,
55 const apr_array_header_t *arr,
59 * Returns offset of match string's location, or -1 if no match is found.
61 * @param hay Location of bytes to scan.
62 * @param hlen Number of bytes available for scanning.
63 * @param ndl Search string
64 * @param nlen Length of search string.
65 * @param type Match type.
67 * @return Offset of match string, or -1 if no match is found.
70 APREQ_DECLARE(apr_ssize_t) apreq_index(const char* hay, apr_size_t hlen,
71 const char* ndl, apr_size_t nlen,
72 const apreq_match_t type);
75 * Places a quoted copy of src into dest. Embedded quotes are escaped with a
78 * @param dest Location of quoted copy. Must be large enough to hold the copy
79 * and trailing null byte.
80 * @param src Original string.
81 * @param slen Length of original string.
82 * @param dest Destination string.
84 * @return length of quoted copy in dest.
86 APREQ_DECLARE(apr_size_t) apreq_quote(char *dest, const char *src,
87 const apr_size_t slen);
91 * Same as apreq_quote() except when src begins and ends in quote marks. In
92 * that case it assumes src is quoted correctly, and just copies src to dest.
94 * @param dest Location of quoted copy. Must be large enough to hold the copy
95 * and trailing null byte.
96 * @param src Original string.
97 * @param slen Length of original string.
98 * @param dest Destination string.
100 * @return length of quoted copy in dest.
102 APREQ_DECLARE(apr_size_t) apreq_quote_once(char *dest, const char *src,
103 const apr_size_t slen);
106 * Url-encodes a string.
108 * @param dest Location of url-encoded result string. Caller must ensure it
109 * is large enough to hold the encoded string and trailing '\\0'.
110 * @param src Original string.
111 * @param slen Length of original string.
113 * @return length of url-encoded string in dest; does not exceed 3 * slen.
115 APREQ_DECLARE(apr_size_t) apreq_encode(char *dest, const char *src,
116 const apr_size_t slen);
119 * Convert a string from cp1252 to utf8. Caller must ensure it is large enough
120 * to hold the encoded string and trailing '\\0'.
122 * @param dest Location of utf8-encoded result string. Caller must ensure it
123 * is large enough to hold the encoded string and trailing '\\0'.
124 * @param src Original string.
125 * @param slen Length of original string.
127 * @return length of utf8-encoded string in dest; does not exceed 3 * slen.
129 APREQ_DECLARE(apr_size_t) apreq_cp1252_to_utf8(char *dest,
130 const char *src, apr_size_t slen);
133 * Heuristically determine the charset of a string.
135 * @param src String to scan.
136 * @param slen Length of string.
138 * @return APREQ_CHARSET_ASCII if the string contains only 7-bit chars;
139 * @return APREQ_CHARSET_UTF8 if the string is a valid utf8 byte sequence;
140 * @return APREQ_CHARSET_LATIN1 if the string has no control chars;
141 * @return APREQ_CHARSET_CP1252 if the string has control chars.
143 APREQ_DECLARE(apreq_charset_t) apreq_charset_divine(const char *src,
147 * Url-decodes a string.
149 * @param dest Location of url-encoded result string. Caller must ensure dest is
150 * large enough to hold the encoded string and trailing null character.
151 * @param dlen points to resultant length of url-decoded string in dest
152 * @param src Original string.
153 * @param slen Length of original string.
155 * @return APR_SUCCESS.
156 * @return APR_INCOMPLETE if the string
157 * ends in the middle of an escape sequence.
158 * @return ::APREQ_ERROR_BADSEQ or ::APREQ_ERROR_BADCHAR on malformed input.
160 * @remarks In the non-success case, dlen will be set to include
161 * the last succesfully decoded value. This function decodes
162 * \%uXXXX into a utf8 (wide) character, following ECMA-262
163 * (the Javascript spec) Section B.2.1.
166 APREQ_DECLARE(apr_status_t) apreq_decode(char *dest, apr_size_t *dlen,
167 const char *src, apr_size_t slen);
170 * Url-decodes an iovec array.
172 * @param dest Location of url-encoded result string. Caller must ensure dest is
173 * large enough to hold the encoded string and trailing null character.
174 * @param dlen Resultant length of dest.
175 * @param v Array of iovecs that represent the source string
176 * @param nelts Number of iovecs in the array.
178 * @return APR_SUCCESS.
179 * @return APR_INCOMPLETE if the iovec
180 * ends in the middle of an escape sequence.
181 * @return ::APREQ_ERROR_BADSEQ or ::APREQ_ERROR_BADCHAR on malformed input.
183 * @remarks In the non-APR_SUCCESS case, dlen will be set to include
184 * the last succesfully decoded value. This function decodes
185 * \%uXXXX into a utf8 (wide) character, following ECMA-262
186 * (the Javascript spec) Section B.2.1.
189 APREQ_DECLARE(apr_status_t) apreq_decodev(char *dest, apr_size_t *dlen,
190 struct iovec *v, int nelts);
193 * Returns an url-encoded copy of a string.
195 * @param p Pool used to allocate the return value.
196 * @param src Original string.
197 * @param slen Length of original string.
199 * @return The url-encoded string.
201 * @remarks Use this function insead of apreq_encode if its
202 * caller might otherwise overflow dest.
205 char *apreq_escape(apr_pool_t *p, const char *src, const apr_size_t slen)
212 rv = (char *)apr_palloc(p, 3 * slen + 1);
213 apreq_encode(rv, src, slen);
218 * An \e in-situ url-decoder.
220 * @param str The string to decode
222 * @return Length of decoded string, or < 0 on error.
224 static APR_INLINE apr_ssize_t apreq_unescape(char *str)
227 apr_status_t rv = apreq_decode(str, &len, str, strlen(str));
228 if (rv == APR_SUCCESS)
229 return (apr_ssize_t)len;
235 * Converts file sizes (KMG) to bytes
237 * @param s file size matching m/^\\d+[KMG]b?$/i
239 * @return 64-bit integer representation of s.
241 * @todo What happens when s is malformed? Should this return
242 * an unsigned value instead?
245 APREQ_DECLARE(apr_int64_t) apreq_atoi64f(const char *s);
248 * Converts time strings (YMDhms) to seconds
250 * @param s time string matching m/^\\+?\\d+[YMDhms]$/
252 * @return 64-bit integer representation of s as seconds.
254 * @todo What happens when s is malformed? Should this return
255 * an unsigned value instead?
258 APREQ_DECLARE(apr_int64_t) apreq_atoi64t(const char *s);
261 * Writes brigade to a file.
263 * @param f File that gets the brigade.
264 * @param wlen On a successful return, wlen holds the length of
265 * the brigade, which is the amount of data written to
267 * @param bb Bucket brigade.
269 * @return APR_SUCCESS.
270 * @return Error status code from either an unsuccessful apr_bucket_read(),
271 * or a failed apr_file_writev().
273 * @remarks This function leaks a bucket brigade into bb->p whenever
274 * the final bucket in bb is a spool bucket.
277 APREQ_DECLARE(apr_status_t) apreq_brigade_fwrite(apr_file_t *f,
279 apr_bucket_brigade *bb);
281 * Makes a temporary file.
283 * @param fp Points to the temporary apr_file_t on success.
284 * @param pool Pool to associate with the temp file. When the
285 * pool is destroyed, the temp file will be closed
287 * @param path The base directory which will contain the temp file.
288 * If param == NULL, the directory will be selected via
289 * tempnam(). See the tempnam manpage for details.
291 * @return APR_SUCCESS.
292 * @return Error status code from unsuccessful apr_filepath_merge(),
293 * or a failed apr_file_mktemp().
296 APREQ_DECLARE(apr_status_t) apreq_file_mktemp(apr_file_t **fp,
301 * Set aside all buckets in the brigade.
304 * @param p Setaside buckets into this pool.
305 * @return APR_SUCCESS.
306 * @return Error status code from an unsuccessful apr_bucket_setaside().
310 apr_status_t apreq_brigade_setaside(apr_bucket_brigade *bb, apr_pool_t *p)
313 for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb);
314 e = APR_BUCKET_NEXT(e))
316 apr_status_t rv = apr_bucket_setaside(e, p);
317 if (rv != APR_SUCCESS)
327 * @param d (destination) Copied buckets are appended to this brigade.
328 * @param s (source) Brigade to copy from.
330 * @return APR_SUCCESS.
331 * @return Error status code from an unsuccessful apr_bucket_copy().
333 * @remarks s == d produces Undefined Behavior.
337 apr_status_t apreq_brigade_copy(apr_bucket_brigade *d, apr_bucket_brigade *s) {
339 for (e = APR_BRIGADE_FIRST(s); e != APR_BRIGADE_SENTINEL(s);
340 e = APR_BUCKET_NEXT(e))
343 apr_status_t rv = apr_bucket_copy(e, &c);
344 if (rv != APR_SUCCESS)
347 APR_BRIGADE_INSERT_TAIL(d, c);
353 * Move the front of a brigade.
355 * @param d (destination) Append buckets to this brigade.
356 * @param s (source) Brigade to take buckets from.
357 * @param e First bucket of s after the move. All buckets
358 * before e are appended to d.
360 * @remarks This moves all buckets when e == APR_BRIGADE_SENTINEL(s).
364 void apreq_brigade_move(apr_bucket_brigade *d, apr_bucket_brigade *s,
369 if (e != APR_BRIGADE_SENTINEL(s)) {
370 f = APR_RING_FIRST(&s->list);
371 if (f == e) /* zero buckets to be moved */
374 /* obtain the last bucket to be moved */
375 e = APR_RING_PREV(e, link);
377 APR_RING_UNSPLICE(f, e, link);
378 APR_RING_SPLICE_HEAD(&d->list, f, e, apr_bucket, link);
381 APR_BRIGADE_CONCAT(d, s);
387 * Search a header string for the value of a particular named attribute.
389 * @param hdr Header string to scan.
390 * @param name Name of attribute to search for.
391 * @param nlen Length of name.
392 * @param val Location of (first) matching value.
393 * @param vlen Length of matching value.
395 * @return APR_SUCCESS.
396 * @return ::APREQ_ERROR_NOATTR if the attribute is not found.
397 * @return ::APREQ_ERROR_BADSEQ if an unpaired quote mark was detected.
399 APREQ_DECLARE(apr_status_t) apreq_header_attribute(const char *hdr,
401 const apr_size_t nlen,
407 * Concatenates the brigades, spooling large brigades into
408 * a tempfile (APREQ_SPOOL) bucket.
410 * @param pool Pool for creating a tempfile bucket.
411 * @param temp_dir Directory for tempfile creation.
412 * @param brigade_limit If out's length would exceed this value,
413 * the appended buckets get written to a tempfile.
414 * @param out Resulting brigade.
415 * @param in Brigade to append.
417 * @return APR_SUCCESS.
418 * @return Error status code resulting from either apr_brigade_length(),
419 * apreq_file_mktemp(), apreq_brigade_fwrite(), or apr_file_seek().
421 * @todo Flesh out these error codes, making them as explicit as possible.
423 APREQ_DECLARE(apr_status_t) apreq_brigade_concat(apr_pool_t *pool,
424 const char *temp_dir,
425 apr_size_t brigade_limit,
426 apr_bucket_brigade *out,
427 apr_bucket_brigade *in);
430 * Determines the spool file used by the brigade. Returns NULL if the
431 * brigade is not spooled in a file (does not use an APREQ_SPOOL
434 * @param bb the bucket brigade
435 * @return the spool file, or NULL.
437 APREQ_DECLARE(apr_file_t *) apreq_brigade_spoolfile(apr_bucket_brigade *bb);
443 #endif /* APREQ_UTIL_H */