Coverage Report

Created: 2023-03-26 06:28

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