/src/httpd/include/apreq_util.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
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 |
8 | | ** |
9 | | ** http://www.apache.org/licenses/LICENSE-2.0 |
10 | | ** |
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. |
16 | | */ |
17 | | |
18 | | #ifndef APREQ_UTIL_H |
19 | | #define APREQ_UTIL_H |
20 | | |
21 | | #include "apr_file_io.h" |
22 | | #include "apr_buckets.h" |
23 | | #include "apreq.h" |
24 | | |
25 | | #ifdef __cplusplus |
26 | | extern "C" { |
27 | | #endif |
28 | | |
29 | | /** |
30 | | * This header contains useful functions for creating new |
31 | | * parsers, hooks or modules. It includes |
32 | | * |
33 | | * - string <-> array converters |
34 | | * - substring search functions |
35 | | * - simple encoders & decoders for urlencoded strings |
36 | | * - simple time, date, & file-size converters |
37 | | * @file apreq_util.h |
38 | | * @brief Utility functions for apreq. |
39 | | * @ingroup libapreq2 |
40 | | */ |
41 | | |
42 | | /** |
43 | | * Join an array of values. The result is an empty string if there are |
44 | | * no values. |
45 | | * |
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. |
50 | | * |
51 | | * @return Joined string, or NULL on error |
52 | | */ |
53 | | APREQ_DECLARE(char *) apreq_join(apr_pool_t *p, |
54 | | const char *sep, |
55 | | const apr_array_header_t *arr, |
56 | | apreq_join_t mode); |
57 | | |
58 | | /** |
59 | | * Returns offset of match string's location, or -1 if no match is found. |
60 | | * |
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. |
66 | | * |
67 | | * @return Offset of match string, or -1 if no match is found. |
68 | | * |
69 | | */ |
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); |
73 | | |
74 | | /** |
75 | | * Places a quoted copy of src into dest. Embedded quotes are escaped with a |
76 | | * backslash ('\'). |
77 | | * |
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. |
83 | | * |
84 | | * @return length of quoted copy in dest. |
85 | | */ |
86 | | APREQ_DECLARE(apr_size_t) apreq_quote(char *dest, const char *src, |
87 | | const apr_size_t slen); |
88 | | |
89 | | /** |
90 | | * |
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. |
93 | | * |
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. |
99 | | * |
100 | | * @return length of quoted copy in dest. |
101 | | */ |
102 | | APREQ_DECLARE(apr_size_t) apreq_quote_once(char *dest, const char *src, |
103 | | const apr_size_t slen); |
104 | | |
105 | | /** |
106 | | * Url-encodes a string. |
107 | | * |
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. |
112 | | * |
113 | | * @return length of url-encoded string in dest; does not exceed 3 * slen. |
114 | | */ |
115 | | APREQ_DECLARE(apr_size_t) apreq_encode(char *dest, const char *src, |
116 | | const apr_size_t slen); |
117 | | |
118 | | /** |
119 | | * Convert a string from cp1252 to utf8. Caller must ensure it is large enough |
120 | | * to hold the encoded string and trailing '\\0'. |
121 | | * |
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. |
126 | | * |
127 | | * @return length of utf8-encoded string in dest; does not exceed 3 * slen. |
128 | | */ |
129 | | APREQ_DECLARE(apr_size_t) apreq_cp1252_to_utf8(char *dest, |
130 | | const char *src, apr_size_t slen); |
131 | | |
132 | | /** |
133 | | * Heuristically determine the charset of a string. |
134 | | * |
135 | | * @param src String to scan. |
136 | | * @param slen Length of string. |
137 | | * |
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. |
142 | | */ |
143 | | APREQ_DECLARE(apreq_charset_t) apreq_charset_divine(const char *src, |
144 | | apr_size_t slen); |
145 | | |
146 | | /** |
147 | | * Url-decodes a string. |
148 | | * |
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. |
154 | | * |
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. |
159 | | * |
160 | | * @remarks In the non-success case, dlen will be set to include |
161 | | * the last successfully decoded value. This function decodes |
162 | | * \%uXXXX into a utf8 (wide) character, following ECMA-262 |
163 | | * (the Javascript spec) Section B.2.1. |
164 | | */ |
165 | | |
166 | | APREQ_DECLARE(apr_status_t) apreq_decode(char *dest, apr_size_t *dlen, |
167 | | const char *src, apr_size_t slen); |
168 | | |
169 | | /** |
170 | | * Url-decodes an iovec array. |
171 | | * |
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. |
177 | | * |
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. |
182 | | * |
183 | | * @remarks In the non-APR_SUCCESS case, dlen will be set to include |
184 | | * the last successfully decoded value. This function decodes |
185 | | * \%uXXXX into a utf8 (wide) character, following ECMA-262 |
186 | | * (the Javascript spec) Section B.2.1. |
187 | | */ |
188 | | |
189 | | APREQ_DECLARE(apr_status_t) apreq_decodev(char *dest, apr_size_t *dlen, |
190 | | struct iovec *v, int nelts); |
191 | | |
192 | | /** |
193 | | * Returns an url-encoded copy of a string. |
194 | | * |
195 | | * @param p Pool used to allocate the return value. |
196 | | * @param src Original string. |
197 | | * @param slen Length of original string. |
198 | | * |
199 | | * @return The url-encoded string. |
200 | | * |
201 | | * @remarks Use this function insead of apreq_encode if its |
202 | | * caller might otherwise overflow dest. |
203 | | */ |
204 | | static APR_INLINE |
205 | | char *apreq_escape(apr_pool_t *p, const char *src, const apr_size_t slen) |
206 | 0 | { |
207 | 0 | char *rv; |
208 | 0 |
|
209 | 0 | if (src == NULL) |
210 | 0 | return NULL; |
211 | 0 |
|
212 | 0 | rv = (char *)apr_palloc(p, 3 * slen + 1); |
213 | 0 | apreq_encode(rv, src, slen); |
214 | 0 | return rv; |
215 | 0 | } Unexecuted instantiation: apreq_parser.c:apreq_escape Unexecuted instantiation: apreq_parser_multipart.c:apreq_escape Unexecuted instantiation: apreq_parser_urlencoded.c:apreq_escape Unexecuted instantiation: apreq_util.c:apreq_escape Unexecuted instantiation: apreq_param.c:apreq_escape Unexecuted instantiation: apreq_parser_header.c:apreq_escape |
216 | | |
217 | | /** |
218 | | * An \e in-situ url-decoder. |
219 | | * |
220 | | * @param str The string to decode |
221 | | * |
222 | | * @return Length of decoded string, or < 0 on error. |
223 | | */ |
224 | | static APR_INLINE apr_ssize_t apreq_unescape(char *str) |
225 | 0 | { |
226 | 0 | apr_size_t len; |
227 | 0 | apr_status_t rv = apreq_decode(str, &len, str, strlen(str)); |
228 | 0 | if (rv == APR_SUCCESS) |
229 | 0 | return (apr_ssize_t)len; |
230 | 0 | else |
231 | 0 | return -1; |
232 | 0 | } Unexecuted instantiation: apreq_parser.c:apreq_unescape Unexecuted instantiation: apreq_parser_multipart.c:apreq_unescape Unexecuted instantiation: apreq_parser_urlencoded.c:apreq_unescape Unexecuted instantiation: apreq_util.c:apreq_unescape Unexecuted instantiation: apreq_param.c:apreq_unescape Unexecuted instantiation: apreq_parser_header.c:apreq_unescape |
233 | | |
234 | | /** |
235 | | * Converts file sizes (KMG) to bytes |
236 | | * |
237 | | * @param s file size matching m/^\\d+[KMG]b?$/i |
238 | | * |
239 | | * @return 64-bit integer representation of s. |
240 | | * |
241 | | * @todo What happens when s is malformed? Should this return |
242 | | * an unsigned value instead? |
243 | | */ |
244 | | |
245 | | APREQ_DECLARE(apr_int64_t) apreq_atoi64f(const char *s); |
246 | | |
247 | | /** |
248 | | * Converts time strings (YMDhms) to seconds |
249 | | * |
250 | | * @param s time string matching m/^\\+?\\d+[YMDhms]$/ |
251 | | * |
252 | | * @return 64-bit integer representation of s as seconds. |
253 | | * |
254 | | * @todo What happens when s is malformed? Should this return |
255 | | * an unsigned value instead? |
256 | | */ |
257 | | |
258 | | APREQ_DECLARE(apr_int64_t) apreq_atoi64t(const char *s); |
259 | | |
260 | | /** |
261 | | * Writes brigade to a file. |
262 | | * |
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 |
266 | | * the file. |
267 | | * @param bb Bucket brigade. |
268 | | * |
269 | | * @return APR_SUCCESS. |
270 | | * @return Error status code from either an unsuccessful apr_bucket_read(), |
271 | | * or a failed apr_file_writev(). |
272 | | * |
273 | | * @remarks This function leaks a bucket brigade into bb->p whenever |
274 | | * the final bucket in bb is a spool bucket. |
275 | | */ |
276 | | |
277 | | APREQ_DECLARE(apr_status_t) apreq_brigade_fwrite(apr_file_t *f, |
278 | | apr_off_t *wlen, |
279 | | apr_bucket_brigade *bb); |
280 | | /** |
281 | | * Makes a temporary file. |
282 | | * |
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 |
286 | | * and deleted. |
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. |
290 | | * |
291 | | * @return APR_SUCCESS. |
292 | | * @return Error status code from unsuccessful apr_filepath_merge(), |
293 | | * or a failed apr_file_mktemp(). |
294 | | */ |
295 | | |
296 | | APREQ_DECLARE(apr_status_t) apreq_file_mktemp(apr_file_t **fp, |
297 | | apr_pool_t *pool, |
298 | | const char *path); |
299 | | |
300 | | /** |
301 | | * Set aside all buckets in the brigade. |
302 | | * |
303 | | * @param bb Brigade. |
304 | | * @param p Setaside buckets into this pool. |
305 | | * @return APR_SUCCESS. |
306 | | * @return Error status code from an unsuccessful apr_bucket_setaside(). |
307 | | */ |
308 | | |
309 | | static APR_INLINE |
310 | | apr_status_t apreq_brigade_setaside(apr_bucket_brigade *bb, apr_pool_t *p) |
311 | 1.64k | { |
312 | 1.64k | apr_bucket *e; |
313 | 2.74k | for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); |
314 | 1.64k | e = APR_BUCKET_NEXT(e)) |
315 | 1.10k | { |
316 | 1.10k | apr_status_t rv = apr_bucket_setaside(e, p); |
317 | 1.10k | if (rv != APR_SUCCESS) |
318 | 0 | return rv; |
319 | 1.10k | } |
320 | 1.64k | return APR_SUCCESS; |
321 | 1.64k | } Unexecuted instantiation: apreq_parser.c:apreq_brigade_setaside apreq_parser_multipart.c:apreq_brigade_setaside Line | Count | Source | 311 | 1.46k | { | 312 | 1.46k | apr_bucket *e; | 313 | 2.29k | for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); | 314 | 1.46k | e = APR_BUCKET_NEXT(e)) | 315 | 827 | { | 316 | 827 | apr_status_t rv = apr_bucket_setaside(e, p); | 317 | 827 | if (rv != APR_SUCCESS) | 318 | 0 | return rv; | 319 | 827 | } | 320 | 1.46k | return APR_SUCCESS; | 321 | 1.46k | } |
apreq_parser_urlencoded.c:apreq_brigade_setaside Line | Count | Source | 311 | 95 | { | 312 | 95 | apr_bucket *e; | 313 | 213 | for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); | 314 | 118 | e = APR_BUCKET_NEXT(e)) | 315 | 118 | { | 316 | 118 | apr_status_t rv = apr_bucket_setaside(e, p); | 317 | 118 | if (rv != APR_SUCCESS) | 318 | 0 | return rv; | 319 | 118 | } | 320 | 95 | return APR_SUCCESS; | 321 | 95 | } |
Unexecuted instantiation: apreq_util.c:apreq_brigade_setaside Unexecuted instantiation: apreq_param.c:apreq_brigade_setaside apreq_parser_header.c:apreq_brigade_setaside Line | Count | Source | 311 | 83 | { | 312 | 83 | apr_bucket *e; | 313 | 239 | for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); | 314 | 156 | e = APR_BUCKET_NEXT(e)) | 315 | 156 | { | 316 | 156 | apr_status_t rv = apr_bucket_setaside(e, p); | 317 | 156 | if (rv != APR_SUCCESS) | 318 | 0 | return rv; | 319 | 156 | } | 320 | 83 | return APR_SUCCESS; | 321 | 83 | } |
|
322 | | |
323 | | |
324 | | /** |
325 | | * Copy a brigade. |
326 | | * |
327 | | * @param d (destination) Copied buckets are appended to this brigade. |
328 | | * @param s (source) Brigade to copy from. |
329 | | * |
330 | | * @return APR_SUCCESS. |
331 | | * @return Error status code from an unsuccessful apr_bucket_copy(). |
332 | | * |
333 | | * @remarks s == d produces Undefined Behavior. |
334 | | */ |
335 | | |
336 | | static APR_INLINE |
337 | 0 | apr_status_t apreq_brigade_copy(apr_bucket_brigade *d, apr_bucket_brigade *s) { |
338 | 0 | apr_bucket *e; |
339 | 0 | for (e = APR_BRIGADE_FIRST(s); e != APR_BRIGADE_SENTINEL(s); |
340 | 0 | e = APR_BUCKET_NEXT(e)) |
341 | 0 | { |
342 | 0 | apr_bucket *c; |
343 | 0 | apr_status_t rv = apr_bucket_copy(e, &c); |
344 | 0 | if (rv != APR_SUCCESS) |
345 | 0 | return rv; |
346 | | |
347 | 0 | APR_BRIGADE_INSERT_TAIL(d, c); |
348 | 0 | } |
349 | 0 | return APR_SUCCESS; |
350 | 0 | } Unexecuted instantiation: apreq_parser.c:apreq_brigade_copy Unexecuted instantiation: apreq_parser_multipart.c:apreq_brigade_copy Unexecuted instantiation: apreq_parser_urlencoded.c:apreq_brigade_copy Unexecuted instantiation: apreq_util.c:apreq_brigade_copy Unexecuted instantiation: apreq_param.c:apreq_brigade_copy Unexecuted instantiation: apreq_parser_header.c:apreq_brigade_copy |
351 | | |
352 | | /** |
353 | | * Move the front of a brigade. |
354 | | * |
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. |
359 | | * |
360 | | * @remarks This moves all buckets when e == APR_BRIGADE_SENTINEL(s). |
361 | | */ |
362 | | |
363 | | static APR_INLINE |
364 | | void apreq_brigade_move(apr_bucket_brigade *d, apr_bucket_brigade *s, |
365 | | apr_bucket *e) |
366 | 0 | { |
367 | 0 | apr_bucket *f; |
368 | 0 |
|
369 | 0 | if (e != APR_BRIGADE_SENTINEL(s)) { |
370 | 0 | f = APR_RING_FIRST(&s->list); |
371 | 0 | if (f == e) /* zero buckets to be moved */ |
372 | 0 | return; |
373 | 0 |
|
374 | 0 | /* obtain the last bucket to be moved */ |
375 | 0 | e = APR_RING_PREV(e, link); |
376 | 0 |
|
377 | 0 | APR_RING_UNSPLICE(f, e, link); |
378 | 0 | APR_RING_SPLICE_HEAD(&d->list, f, e, apr_bucket, link); |
379 | 0 | } |
380 | 0 | else { |
381 | 0 | APR_BRIGADE_CONCAT(d, s); |
382 | 0 | } |
383 | 0 | } Unexecuted instantiation: apreq_parser.c:apreq_brigade_move Unexecuted instantiation: apreq_parser_multipart.c:apreq_brigade_move Unexecuted instantiation: apreq_parser_urlencoded.c:apreq_brigade_move Unexecuted instantiation: apreq_util.c:apreq_brigade_move Unexecuted instantiation: apreq_param.c:apreq_brigade_move Unexecuted instantiation: apreq_parser_header.c:apreq_brigade_move |
384 | | |
385 | | |
386 | | /** |
387 | | * Search a header string for the value of a particular named attribute. |
388 | | * |
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. |
394 | | * |
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. |
398 | | */ |
399 | | APREQ_DECLARE(apr_status_t) apreq_header_attribute(const char *hdr, |
400 | | const char *name, |
401 | | const apr_size_t nlen, |
402 | | const char **val, |
403 | | apr_size_t *vlen); |
404 | | |
405 | | |
406 | | /** |
407 | | * Concatenates the brigades, spooling large brigades into |
408 | | * a tempfile (APREQ_SPOOL) bucket. |
409 | | * |
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. |
416 | | * |
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(). |
420 | | * |
421 | | * @todo Flesh out these error codes, making them as explicit as possible. |
422 | | */ |
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); |
428 | | |
429 | | /** |
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 |
432 | | * bucket). |
433 | | * |
434 | | * @param bb the bucket brigade |
435 | | * @return the spool file, or NULL. |
436 | | */ |
437 | | APREQ_DECLARE(apr_file_t *) apreq_brigade_spoolfile(apr_bucket_brigade *bb); |
438 | | |
439 | | #ifdef __cplusplus |
440 | | } |
441 | | #endif |
442 | | |
443 | | #endif /* APREQ_UTIL_H */ |