Coverage Report

Created: 2023-03-26 06:28

/src/httpd/server/apreq_util.c
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
#include "apreq_util.h"
19
#include "apreq_error.h"
20
#include "apr_time.h"
21
#include "apr_strings.h"
22
#include "apr_lib.h"
23
#include <assert.h>
24
25
#undef MAX
26
#undef MIN
27
5.08k
#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
28
#define MAX(a,b) ( (a) > (b) ? (a) : (b) )
29
30
/* used for specifying file sizes */
31
32
APREQ_DECLARE(apr_int64_t) apreq_atoi64f(const char *s)
33
0
{
34
0
    apr_int64_t n = 0;
35
0
    char *p;
36
0
    if (s == NULL)
37
0
        return 0;
38
39
0
    n = apr_strtoi64(s, &p, 0);
40
41
0
    if (p == NULL)
42
0
        return n;
43
0
    while (apr_isspace(*p))
44
0
        ++p;
45
46
0
    switch (*p) {
47
0
      case 'G': /* fall thru */
48
0
      case 'g': return n * 1024*1024*1024;
49
0
      case 'M': /* fall thru */
50
0
      case 'm': return n * 1024*1024;
51
0
      case 'K': /* fall thru */
52
0
      case 'k': return n * 1024;
53
0
    }
54
55
0
    return n;
56
0
}
57
58
59
/* converts date offsets (e.g. "+3M") to seconds */
60
61
APREQ_DECLARE(apr_int64_t) apreq_atoi64t(const char *s)
62
0
{
63
0
    apr_int64_t n = 0;
64
0
    char *p;
65
0
    if (s == NULL)
66
0
        return 0;
67
0
    n = apr_strtoi64(s, &p, 0); /* XXX: what about overflow? */
68
69
0
    if (p == NULL)
70
0
        return n;
71
0
    while (apr_isspace(*p))
72
0
        ++p;
73
74
0
    switch (*p) {
75
0
      case 'Y': /* fall thru */
76
0
      case 'y': return n * 60*60*24*365;
77
0
      case 'M': return n * 60*60*24*30;
78
0
      case 'D': /* fall thru */
79
0
      case 'd': return n * 60*60*24;
80
0
      case 'H': /* fall thru */
81
0
      case 'h': return n * 60*60;
82
0
      case 'm': return n * 60;
83
0
      case 's': /* fall thru */
84
0
      default:
85
0
          return n;
86
0
    }
87
    /* should never get here */
88
0
    return -1;
89
0
}
90
91
92
APREQ_DECLARE(apr_ssize_t ) apreq_index(const char* hay, apr_size_t hlen,
93
                                        const char* ndl, apr_size_t nlen,
94
                                        const apreq_match_t type)
95
1.39k
{
96
1.39k
    apr_size_t len = hlen;
97
1.39k
    const char *end = hay + hlen;
98
1.39k
    const char *begin = hay;
99
100
5.54k
    while ( (hay = memchr(hay, ndl[0], len)) ) {
101
5.08k
        len = end - hay;
102
103
        /* done if matches up to capacity of buffer */
104
5.08k
        if ( memcmp(hay, ndl, MIN(nlen, len)) == 0 ) {
105
941
            if (type == APREQ_MATCH_FULL && len < nlen)
106
0
                hay = NULL;     /* insufficient room for match */
107
941
            break;
108
941
        }
109
4.14k
        --len;
110
4.14k
        ++hay;
111
4.14k
    }
112
113
1.39k
    return hay ? hay - begin : -1;
114
1.39k
}
115
116
117
static const char c2x_table[] = "0123456789ABCDEF";
118
static APR_INLINE unsigned char hex2_to_char(const char *what)
119
552
{
120
552
    register unsigned char digit;
121
122
552
#if !APR_CHARSET_EBCDIC
123
552
    digit  = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
124
552
    digit *= 16;
125
552
    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
126
#else /*APR_CHARSET_EBCDIC*/
127
    char xstr[5];
128
    xstr[0]='0';
129
    xstr[1]='x';
130
    xstr[2]=what[0];
131
    xstr[3]=what[1];
132
    xstr[4]='\0';
133
    digit = apr_xlate_conv_byte(ap_hdrs_from_ascii, 0xFF & strtol(xstr, NULL, 16));
134
#endif /*APR_CHARSET_EBCDIC*/
135
552
    return (digit);
136
552
}
137
138
139
/* Unicode notes: "bmp" refers to the 16-bit
140
 * Unicode Basic Multilingual Plane. Here we're
141
 * restricting our unicode internals to 16-bit
142
 * codepoints, to keep the code as simple as possible.
143
 * This should be sufficient for apreq itself, since
144
 * we really only need to validate RFC3986-encoded utf8.
145
 */
146
147
/* Converts Windows cp1252 to Unicode. */
148
149
static APR_INLINE
150
apr_uint16_t cp1252_to_bmp(unsigned char c)
151
0
{
152
    /* We only need to deal with iso-8859-1 control chars
153
     * in the 0x80 - 0x9F range.
154
     */
155
0
    if ((c & 0xE0) != 0x80)
156
0
        return c;
157
158
0
    switch (c) {
159
0
    case 0x80: return 0x20AC;
160
0
    case 0x82: return 0x201A;
161
0
    case 0x83: return 0x192;
162
0
    case 0x84: return 0x201E;
163
0
    case 0x85: return 0x2026;
164
0
    case 0x86: return 0x2020;
165
0
    case 0x87: return 0x2021;
166
0
    case 0x88: return 0x2C6;
167
0
    case 0x89: return 0x2030;
168
0
    case 0x8A: return 0x160;
169
0
    case 0x8B: return 0x2039;
170
0
    case 0x8C: return 0x152;
171
0
    case 0x8E: return 0x17D;
172
0
    case 0x91: return 0x2018;
173
0
    case 0x92: return 0x2019;
174
0
    case 0x93: return 0x201C;
175
0
    case 0x94: return 0x201D;
176
0
    case 0x95: return 0x2022;
177
0
    case 0x96: return 0x2013;
178
0
    case 0x97: return 0x2014;
179
0
    case 0x98: return 0x2DC;
180
0
    case 0x99: return 0x2122;
181
0
    case 0x9A: return 0x161;
182
0
    case 0x9B: return 0x203A;
183
0
    case 0x9C: return 0x153;
184
0
    case 0x9E: return 0x17E;
185
0
    case 0x9F: return 0x178;
186
0
    }
187
0
    return c;
188
0
}
189
190
/* converts cp1252 to utf8 */
191
APREQ_DECLARE(apr_size_t) apreq_cp1252_to_utf8(char *dest,
192
                                               const char *src, apr_size_t slen)
193
0
{
194
0
    const unsigned char *s = (unsigned const char *)src;
195
0
    const unsigned char *end = s + slen;
196
0
    unsigned char *d = (unsigned char *)dest;
197
0
    apr_uint16_t c;
198
199
0
    while (s < end) {
200
0
        c = cp1252_to_bmp(*s++);
201
202
0
        if (c < 0x80) {
203
0
            *d++ = c;
204
0
        }
205
0
        else if (c < 0x800) {
206
0
            *d++ = 0xC0 | (c >> 6);
207
0
            *d++ = 0x80 | (c & 0x3F);
208
0
        }
209
0
        else {
210
0
            *d++ = 0xE0 | (c >> 12);
211
0
            *d++ = 0x80 | ((c >> 6) & 0x3F);
212
0
            *d++ = 0x80 | (c & 0x3F);
213
0
        }
214
0
    }
215
0
    *d = 0;
216
0
    return d - (unsigned char *)dest;
217
0
}
218
219
220
/**
221
 * Valid utf8 bit patterns: (true utf8 must satisfy a minimality condition)
222
 *
223
 * 0aaaaaaa
224
 * 110bbbba 10aaaaaa                        minimality mask: 0x1E
225
 * 1110cccc 10cbbbba 10aaaaaa                                0x0F || 0x20
226
 * 11110ddd 10ddcccc 10cbbbba 10aaaaaa                       0x07 || 0x30
227
 * 111110ee 10eeeddd 10ddcccc 10cbbbba 10aaaaaa              0x03 || 0x38
228
 * 1111110f 10ffffee 10eeeddd 10ddcccc 10cbbbba 10aaaaaa     0x01 || 0x3C
229
 *
230
 * Charset divination heuristics:
231
 * 1) presume ascii; if not, then
232
 * 2) presume utf8; if not, then
233
 * 3) presume latin1; unless there are control chars, in which case
234
 * 4) punt to cp1252.
235
 *
236
 * Note: in downgrading from 2 to 3, we need to be careful
237
 * about earlier control characters presumed to be valid utf8.
238
 */
239
240
APREQ_DECLARE(apreq_charset_t) apreq_charset_divine(const char *src,
241
                                                    apr_size_t slen)
242
243
1.08k
{
244
1.08k
    apreq_charset_t rv = APREQ_CHARSET_ASCII;
245
1.08k
    register unsigned char trail = 0, saw_cntrl = 0, mask = 0;
246
1.08k
    register const unsigned char *s = (const unsigned char *)src;
247
1.08k
    const unsigned char *end = s + slen;
248
249
5.09k
    for (; s < end; ++s) {
250
4.14k
        if (trail) {
251
673
            if ((*s & 0xC0) == 0x80 && (mask == 0 || (mask & *s))) {
252
536
                mask = 0;
253
536
                --trail;
254
255
536
                if ((*s & 0xE0) == 0x80) {
256
259
                    saw_cntrl = 1;
257
259
                }
258
536
            }
259
137
            else {
260
137
                trail = 0;
261
137
                if (saw_cntrl)
262
33
                    return APREQ_CHARSET_CP1252;
263
104
                rv = APREQ_CHARSET_LATIN1;
264
104
            }
265
673
        }
266
3.47k
        else if (*s < 0x80) {
267
            /* do nothing */
268
2.31k
        }
269
1.16k
        else if (*s < 0xA0) {
270
71
            return APREQ_CHARSET_CP1252;
271
71
        }
272
1.09k
        else if (*s < 0xC0) {
273
127
            if (saw_cntrl)
274
13
                return APREQ_CHARSET_CP1252;
275
114
            rv = APREQ_CHARSET_LATIN1;
276
114
        }
277
963
        else if (rv == APREQ_CHARSET_LATIN1) {
278
            /* do nothing */
279
162
        }
280
281
        /* utf8 cases */
282
283
801
        else if (*s < 0xE0) {
284
214
            if (*s & 0x1E) {
285
141
                rv = APREQ_CHARSET_UTF8;
286
141
                trail = 1;
287
141
                mask = 0;
288
141
            }
289
73
            else if (saw_cntrl)
290
16
                return APREQ_CHARSET_CP1252;
291
57
            else
292
57
                rv = APREQ_CHARSET_LATIN1;
293
214
        }
294
587
        else if (*s < 0xF0) {
295
182
            mask = (*s & 0x0F) ? 0 : 0x20;
296
182
            rv = APREQ_CHARSET_UTF8;
297
182
            trail = 2;
298
182
        }
299
405
        else if (*s < 0xF8) {
300
91
            mask = (*s & 0x07) ? 0 : 0x30;
301
91
            rv = APREQ_CHARSET_UTF8;
302
91
            trail = 3;
303
91
        }
304
314
        else if (*s < 0xFC) {
305
73
            mask = (*s & 0x03) ? 0 : 0x38;
306
73
            rv = APREQ_CHARSET_UTF8;
307
73
            trail = 4;
308
73
        }
309
241
        else if (*s < 0xFE) {
310
70
            mask = (*s & 0x01) ? 0 : 0x3C;
311
70
            rv = APREQ_CHARSET_UTF8;
312
70
            trail = 5;
313
70
        }
314
171
        else {
315
171
            rv = APREQ_CHARSET_UTF8;
316
171
        }
317
4.14k
    }
318
319
948
    return trail ? saw_cntrl ?
320
790
        APREQ_CHARSET_CP1252 : APREQ_CHARSET_LATIN1 : rv;
321
1.08k
}
322
323
324
static APR_INLINE apr_uint16_t hex4_to_bmp(const char *what)
325
274
{
326
274
    register apr_uint16_t digit = 0;
327
328
274
#if !APR_CHARSET_EBCDIC
329
274
    digit  = (what[0] >= 'A' ? ((what[0] & 0xDF)-'A') + 10 : (what[0]-'0'));
330
274
    digit *= 16;
331
274
    digit += (what[1] >= 'A' ? ((what[1] & 0xDF)-'A') + 10 : (what[1]-'0'));
332
274
    digit *= 16;
333
274
    digit += (what[2] >= 'A' ? ((what[2] & 0xDF)-'A') + 10 : (what[2]-'0'));
334
274
    digit *= 16;
335
274
    digit += (what[3] >= 'A' ? ((what[3] & 0xDF)-'A') + 10 : (what[3]-'0'));
336
337
#else /*APR_CHARSET_EBCDIC*/
338
    char xstr[7];
339
    xstr[0]='0';
340
    xstr[1]='x';
341
    xstr[2]=what[0];
342
    xstr[3]=what[1];
343
    xstr[4]=what[2];
344
    xstr[5]=what[3];
345
    xstr[6]='\0';
346
    digit = apr_xlate_conv_byte(ap_hdrs_from_ascii, 0xFFFF & strtol(xstr, NULL, 16));
347
#endif /*APR_CHARSET_EBCDIC*/
348
274
    return (digit);
349
274
}
350
351
352
static apr_status_t url_decode(char *dest, apr_size_t *dlen,
353
                               const char *src, apr_size_t *slen)
354
1.10k
{
355
1.10k
    register const char *s = src;
356
1.10k
    unsigned char *start = (unsigned char *)dest;
357
1.10k
    register unsigned char *d = (unsigned char *)dest;
358
1.10k
    const char *end = src + *slen;
359
360
4.59k
    for (; s < end; ++d, ++s) {
361
3.56k
        switch (*s) {
362
363
203
        case '+':
364
203
            *d = ' ';
365
203
            break;
366
367
883
        case '%':
368
883
            if (s + 2 < end && apr_isxdigit(s[1]) && apr_isxdigit(s[2])) {
369
552
                *d = hex2_to_char(s + 1);
370
552
                s += 2;
371
552
            }
372
331
            else if (s + 5 < end && (s[1] == 'u' || s[1] == 'U') &&
373
331
                     apr_isxdigit(s[2]) && apr_isxdigit(s[3]) &&
374
331
                     apr_isxdigit(s[4]) && apr_isxdigit(s[5]))
375
274
            {
376
274
                apr_uint16_t c = hex4_to_bmp(s+2);
377
378
274
                if (c < 0x80) {
379
39
                    *d = c;
380
39
                }
381
235
                else if (c < 0x800) {
382
78
                    *d++ = 0xC0 | (c >> 6);
383
78
                    *d   = 0x80 | (c & 0x3F);
384
78
                }
385
157
                else {
386
157
                    *d++ = 0xE0 | (c >> 12);
387
157
                    *d++ = 0x80 | ((c >> 6) & 0x3F);
388
157
                    *d   = 0x80 | (c & 0x3F);
389
157
                }
390
274
                s += 5;
391
274
            }
392
57
            else {
393
57
                *dlen = d - start;
394
57
                *slen = s - src;
395
57
                if (s + 5 < end
396
57
                    || (s + 2 < end && !apr_isxdigit(s[2]))
397
57
                    || (s + 1 < end && !apr_isxdigit(s[1])
398
25
                        && s[1] != 'u' && s[1] != 'U'))
399
49
                {
400
49
                    *d = 0;
401
49
                    return APREQ_ERROR_BADSEQ;
402
49
                }
403
404
8
                memmove(d, s, end - s);
405
8
                d[end - s] = 0;
406
8
                return APR_INCOMPLETE;
407
57
            }
408
826
            break;
409
410
2.47k
        default:
411
2.47k
            if (*s > 0) {
412
2.46k
                *d = *s;
413
2.46k
            }
414
12
            else {
415
12
                *d = 0;
416
12
                *dlen = d - start;
417
12
                *slen = s - src;
418
12
                return APREQ_ERROR_BADCHAR;
419
12
            }
420
3.56k
        }
421
3.56k
    }
422
423
1.03k
    *d = 0;
424
1.03k
    *dlen = d - start;
425
1.03k
    *slen = s - src;
426
1.03k
    return APR_SUCCESS;
427
1.10k
}
428
429
430
APREQ_DECLARE(apr_status_t) apreq_decode(char *d, apr_size_t *dlen,
431
                                         const char *s, apr_size_t slen)
432
0
{
433
0
    apr_size_t len = 0;
434
0
    const char *end = s + slen;
435
436
0
    if (s == (const char *)d) {     /* optimize for src = dest case */
437
0
        for ( ; d < end; ++d) {
438
0
            if (*d == '%' || *d == '+')
439
0
                break;
440
0
            else if (*d == 0) {
441
0
                *dlen = (const char *)d - s;
442
0
                return APREQ_ERROR_BADCHAR;
443
0
            }
444
0
        }
445
0
        len = (const char *)d - s;
446
0
        s = (const char *)d;
447
0
        slen -= len;
448
0
    }
449
450
0
    return url_decode(d, dlen, s, &slen);
451
0
}
452
453
APREQ_DECLARE(apr_status_t) apreq_decodev(char *d, apr_size_t *dlen,
454
                                          struct iovec *v, int nelts)
455
1.10k
{
456
1.10k
    apr_status_t status = APR_SUCCESS;
457
1.10k
    int n = 0;
458
459
1.10k
    *dlen = 0;
460
461
2.13k
    while (n < nelts) {
462
1.10k
        apr_size_t slen, len;
463
464
1.10k
        slen = v[n].iov_len;
465
1.10k
        switch (status = url_decode(d, &len, v[n].iov_base, &slen)) {
466
467
1.03k
        case APR_SUCCESS:
468
1.03k
            d += len;
469
1.03k
            *dlen += len;
470
1.03k
            ++n;
471
1.03k
            continue;
472
473
8
        case APR_INCOMPLETE:
474
8
            d += len;
475
8
            *dlen += len;
476
8
            slen = v[n].iov_len - slen;
477
478
8
            if (++n == nelts) {
479
8
                return status;
480
8
            }
481
0
            memcpy(d + slen, v[n].iov_base, v[n].iov_len);
482
0
            v[n].iov_len += slen;
483
0
            v[n].iov_base = d;
484
0
            continue;
485
486
61
        default:
487
61
            *dlen += len;
488
61
            return status;
489
1.10k
        }
490
1.10k
    }
491
492
1.03k
    return status;
493
1.10k
}
494
495
496
APREQ_DECLARE(apr_size_t) apreq_encode(char *dest, const char *src,
497
                                       const apr_size_t slen)
498
0
{
499
0
    char *d = dest;
500
0
    const unsigned char *s = (const unsigned char *)src;
501
0
    unsigned char c;
502
503
0
    for ( ; s < (const unsigned char *)src + slen; ++s) {
504
0
        c = *s;
505
0
        if ( c < 0x80 && (apr_isalnum(c)
506
0
                          || c == '-' || c == '.'
507
0
                          || c == '_' || c == '~') )
508
0
            *d++ = c;
509
510
0
        else if ( c == ' ' )
511
0
            *d++ = '+';
512
513
0
        else {
514
#if APR_CHARSET_EBCDIC
515
            c = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)c);
516
#endif
517
0
            *d++ = '%';
518
0
            *d++ = c2x_table[c >> 4];
519
0
            *d++ = c2x_table[c & 0xf];
520
0
        }
521
0
    }
522
0
    *d = 0;
523
524
0
    return d - dest;
525
0
}
526
527
static int is_quoted(const char *p, const apr_size_t len)
528
0
{
529
0
    if (len > 1 && p[0] == '"' && p[len-1] == '"') {
530
0
        apr_size_t i;
531
0
        int backslash = 0;
532
533
0
        for (i = 1; i < len - 1; i++) {
534
0
            if (p[i] == '\\')
535
0
                backslash = !backslash;
536
0
            else if (p[i] == 0 || (p[i] == '"' && !backslash))
537
0
                return 0;
538
0
            else
539
0
                backslash = 0;
540
0
        }
541
542
0
        return !backslash;
543
0
    }
544
545
0
    return 0;
546
0
}
547
548
APREQ_DECLARE(apr_size_t) apreq_quote_once(char *dest, const char *src,
549
                                           const apr_size_t slen)
550
0
{
551
0
    if (is_quoted(src, slen)) {
552
        /* looks like src is already quoted */
553
0
        memcpy(dest, src, slen);
554
0
        dest[slen] = 0;
555
0
        return slen;
556
0
    }
557
0
    else
558
0
        return apreq_quote(dest, src, slen);
559
0
}
560
561
APREQ_DECLARE(apr_size_t) apreq_quote(char *dest, const char *src,
562
                                      const apr_size_t slen)
563
0
{
564
0
    char *d = dest;
565
0
    const char *s = src;
566
0
    const char *const last = src + slen - 1;
567
568
0
    if (slen == 0) {
569
0
        *d = 0;
570
0
        return 0;
571
0
    }
572
573
0
    *d++ = '"';
574
575
0
    while (s <= last) {
576
0
        switch (*s) {
577
0
        case 0:
578
0
            *d++ = '\\';
579
0
            *d++ = '0';
580
0
            s++;
581
0
            break;
582
583
0
        case '\\':
584
0
        case '"':
585
0
            *d++ = '\\';
586
587
0
        default:
588
0
            *d++ = *s++;
589
0
        }
590
0
    }
591
592
0
    *d++ = '"';
593
0
    *d = 0;
594
595
0
    return d - dest;
596
0
}
597
598
APREQ_DECLARE(char *) apreq_join(apr_pool_t *p,
599
                                 const char *sep,
600
                                 const apr_array_header_t *arr,
601
                                 apreq_join_t mode)
602
0
{
603
0
    apr_size_t len, slen;
604
0
    char *rv;
605
0
    const apreq_value_t **a = (const apreq_value_t **)arr->elts;
606
0
    char *d;
607
0
    const int n = arr->nelts;
608
0
    int j;
609
610
0
    slen = sep ? strlen(sep) : 0;
611
612
0
    if (n == 0)
613
0
        return apr_pstrdup(p, "");
614
615
0
    for (j=0, len=0; j < n; ++j)
616
0
        len += a[j]->dlen + slen + 1;
617
618
    /* Allocated the required space */
619
620
0
    switch (mode) {
621
0
    case APREQ_JOIN_ENCODE:
622
0
        len += 2 * len;
623
0
        break;
624
0
    case APREQ_JOIN_QUOTE:
625
0
        len = 2 * (len + n);
626
0
        break;
627
0
    case APREQ_JOIN_AS_IS:
628
0
    case APREQ_JOIN_DECODE:
629
        /* nothing special required, just here to keep noisy compilers happy */
630
0
        break;
631
0
    }
632
633
0
    rv = apr_palloc(p, len);
634
635
    /* Pass two --- copy the argument strings into the result space */
636
637
0
    d = rv;
638
639
0
    switch (mode) {
640
641
0
    case APREQ_JOIN_ENCODE:
642
0
        d += apreq_encode(d, a[0]->data, a[0]->dlen);
643
644
0
        for (j = 1; j < n; ++j) {
645
0
                memcpy(d, sep, slen);
646
0
                d += slen;
647
0
                d += apreq_encode(d, a[j]->data, a[j]->dlen);
648
0
        }
649
0
        break;
650
651
0
    case APREQ_JOIN_DECODE:
652
0
        if (apreq_decode(d, &len, a[0]->data, a[0]->dlen))
653
0
            return NULL;
654
0
        else
655
0
            d += len;
656
657
0
        for (j = 1; j < n; ++j) {
658
0
            memcpy(d, sep, slen);
659
0
            d += slen;
660
661
0
            if (apreq_decode(d, &len, a[j]->data, a[j]->dlen))
662
0
                return NULL;
663
0
            else
664
0
                d += len;
665
0
        }
666
0
        break;
667
668
669
0
    case APREQ_JOIN_QUOTE:
670
0
        d += apreq_quote_once(d, a[0]->data, a[0]->dlen);
671
672
0
        for (j = 1; j < n; ++j) {
673
0
            memcpy(d, sep, slen);
674
0
            d += slen;
675
0
            d += apreq_quote_once(d, a[j]->data, a[j]->dlen);
676
0
        }
677
0
        break;
678
679
680
0
    case APREQ_JOIN_AS_IS:
681
0
        memcpy(d,a[0]->data, a[0]->dlen);
682
0
        d += a[0]->dlen;
683
684
0
        for (j = 1; j < n ; ++j) {
685
0
            memcpy(d, sep, slen);
686
0
            d += slen;
687
0
            memcpy(d, a[j]->data, a[j]->dlen);
688
0
            d += a[j]->dlen;
689
0
        }
690
0
        break;
691
0
    }
692
693
0
    *d = 0;
694
0
    return rv;
695
0
}
696
697
/*
698
 * This is intentionally not apr_file_writev()
699
 * note, this is iterative and not recursive
700
 */
701
APR_INLINE
702
static apr_status_t apreq_fwritev(apr_file_t *f, struct iovec *v,
703
                                  int *nelts, apr_size_t *bytes_written)
704
317
{
705
317
    apr_size_t len;
706
317
    int n;
707
317
    apr_status_t s;
708
709
317
    *bytes_written = 0;
710
711
317
    while (1) {
712
        /* try to write */
713
317
        s = apr_file_writev(f, v, *nelts, &len);
714
715
317
        *bytes_written += len;
716
717
317
        if (s != APR_SUCCESS)
718
0
            return s;
719
720
        /* see how far we've come */
721
317
        n = 0;
722
723
#ifdef SOLARIS2
724
# ifdef __GNUC__
725
        /*
726
         * iovec.iov_len is a long here
727
         * which causes a comparison between 
728
         * signed(long) and unsigned(apr_size_t)
729
         *
730
         */
731
        while (n < *nelts && len >= (apr_size_t)v[n].iov_len)
732
# else
733
          /*
734
           * Sun C however defines this as size_t which is unsigned
735
           * 
736
           */
737
        while (n < *nelts && len >= v[n].iov_len)
738
# endif /* !__GNUC__ */
739
#else
740
          /*
741
           * Hopefully everything else does this
742
           * (this was the default for years)
743
           */
744
647
        while (n < *nelts && len >= v[n].iov_len)
745
330
#endif
746
330
            len -= v[n++].iov_len;
747
748
317
        if (n == *nelts) {
749
            /* nothing left to write, report success */
750
317
            *nelts = 0;
751
317
            return APR_SUCCESS;
752
317
        }
753
754
        /* incomplete write: must shift v */
755
0
        v[n].iov_len -= len;
756
0
        v[n].iov_base = (char *)(v[n].iov_base) + len;
757
758
0
        if (n > 0) {
759
            /* we're satisfied for now if we can remove one iovec from
760
               the "v" array */
761
0
            (*nelts) -= n;
762
0
            memmove(v, v + n, sizeof(*v) * *nelts);
763
764
0
            return APR_SUCCESS;
765
0
        }
766
767
        /* we're still in the first iovec - check for endless loop,
768
           and then try again */
769
0
        if (len == 0)
770
0
            return APREQ_ERROR_GENERAL;
771
0
    }
772
317
}
773
774
775
776
777
struct cleanup_data {
778
    const char *fname;
779
    apr_pool_t *pool;
780
};
781
782
static apr_status_t apreq_file_cleanup(void *d)
783
317
{
784
317
    struct cleanup_data *data = d;
785
317
    return apr_file_remove(data->fname, data->pool);
786
317
}
787
788
/*
789
 * The reason we need the above cleanup is because on Windows, APR_DELONCLOSE
790
 * forces applications to open the file with FILE_SHARED_DELETE
791
 * set, which is, unfortunately, a property that is preserved
792
 * across NTFS "hard" links.  This breaks apps that link() the temp
793
 * file to a permanent location, and subsequently expect to open it
794
 * before the original tempfile is closed+deleted. In fact, even
795
 * Apache::Upload does this, so it is a common enough event that the
796
 * apreq_file_cleanup workaround is necessary.
797
 */
798
799
APREQ_DECLARE(apr_status_t) apreq_file_mktemp(apr_file_t **fp,
800
                                              apr_pool_t *pool,
801
                                              const char *path)
802
317
{
803
317
    apr_status_t rc;
804
317
    char *tmpl;
805
317
    struct cleanup_data *data;
806
317
    apr_int32_t flag;
807
808
317
    if (path == NULL) {
809
0
        rc = apr_temp_dir_get(&path, pool);
810
0
        if (rc != APR_SUCCESS)
811
0
            return rc;
812
0
    }
813
317
    rc = apr_filepath_merge(&tmpl, path, "apreqXXXXXX",
814
317
                            APR_FILEPATH_NOTRELATIVE, pool);
815
816
317
    if (rc != APR_SUCCESS)
817
0
        return rc;
818
819
317
    data = apr_palloc(pool, sizeof *data);
820
    /* cleanups are LIFO, so this one will run just after
821
       the cleanup set by mktemp */
822
317
    apr_pool_cleanup_register(pool, data,
823
317
                              apreq_file_cleanup, apreq_file_cleanup);
824
825
    /* NO APR_DELONCLOSE! see comment above */
826
317
    flag = APR_CREATE | APR_READ | APR_WRITE | APR_EXCL | APR_BINARY;
827
828
317
    rc = apr_file_mktemp(fp, tmpl, flag, pool);
829
830
317
    if (rc == APR_SUCCESS) {
831
317
        apr_file_name_get(&data->fname, *fp);
832
317
        data->pool = pool;
833
317
    }
834
0
    else {
835
0
        apr_pool_cleanup_kill(pool, data, apreq_file_cleanup);
836
0
    }
837
838
317
    return rc;
839
317
}
840
841
842
1.68k
#define IS_SPACE_CHAR(c) ((c) == '\t' || (c) == ' ')
843
11.1k
#define IS_TOKEN_CHAR(c) (apr_isalnum(c) \
844
11.1k
                          || ((c) && strchr("!#$%&'*+-.^_`|~", (c))))
845
846
APREQ_DECLARE(apr_status_t)
847
    apreq_header_attribute(const char *hdr,
848
                           const char *name, const apr_size_t nlen,
849
                           const char **val, apr_size_t *vlen)
850
1.12k
{
851
1.12k
    int done = 0;
852
853
1.12k
    if (!nlen)
854
0
        return APREQ_ERROR_NOATTR;
855
856
2.14k
    do {
857
2.14k
        const char *hde, *v;
858
2.14k
        apr_size_t tail = 0;
859
860
        /* Parse the name => [hdr:hde[ */
861
2.14k
        hde = hdr;
862
13.6k
    look_for_end_name:
863
13.6k
        switch (*hde) {
864
18
        case 0:
865
21
        case '\r':
866
26
        case '\n':
867
26
            done = 1;
868
1.40k
        case '=':
869
1.60k
        case ';':
870
2.11k
        case ',':
871
2.11k
            v = hde;
872
2.11k
            hde -= tail;
873
2.11k
            break;
874
282
        case ' ':
875
403
        case '\t':
876
403
            if (hde == hdr)
877
161
                ++hdr;
878
242
            else
879
242
                ++tail;
880
403
            ++hde;
881
403
            goto look_for_end_name;
882
11.1k
        default:
883
            /* The name is a token */
884
11.1k
            if (!IS_TOKEN_CHAR(*hde))
885
21
                return APREQ_ERROR_BADCHAR;
886
            /* Nothing after the tail */
887
11.1k
            if (tail)
888
4
                return APREQ_ERROR_BADATTR;
889
11.1k
            ++hde;
890
11.1k
            goto look_for_end_name;
891
13.6k
        }
892
893
        /* Parse the value => (*val, *vlen) */
894
2.11k
        if (*v == '=') {
895
1.38k
            if (hde == hdr) {
896
                /* The name can't be empty */
897
4
                return APREQ_ERROR_BADATTR;
898
4
            }
899
900
1.37k
            ++v;
901
1.68k
            while (IS_SPACE_CHAR(*v))
902
308
                ++v;
903
904
            /* Quoted string ? */
905
1.37k
            if (*v == '"') {
906
20
                *val = ++v;
907
908
                /* XXX: the interface does not permit unescaping,
909
                 *      it should have pool to allocate from.
910
                 * The caller can't know whether a returned '\\' is
911
                 * a quoted-char or not..
912
                 */
913
367
            look_for_end_quote:
914
367
                switch (*v) {
915
12
                case 0:
916
15
                case '\r':
917
17
                case '\n':
918
17
                    return APREQ_ERROR_BADSEQ;
919
1
                case '"':
920
1
                    *vlen = v - *val;
921
1
                    break;
922
185
                case '\\':
923
185
                    if (v[1] != 0)
924
183
                        ++v;
925
185
                    ++v;
926
185
                    goto look_for_end_quote;
927
164
                default:
928
164
                    if (apr_iscntrl(*v))
929
2
                        return APREQ_ERROR_BADCHAR;
930
162
                    ++v;
931
162
                    goto look_for_end_quote;
932
367
                }
933
934
1
            look_for_after_quote:
935
1
                switch (*v) {
936
0
                case 0:
937
0
                case '\r':
938
0
                case '\n':
939
0
                    done = 1;
940
0
                case ';':
941
0
                case ',':
942
0
                    break;
943
0
                case ' ':
944
0
                case '\t':
945
0
                    goto look_for_after_quote;
946
1
                default:
947
1
                    if (apr_iscntrl(*v))
948
0
                        return APREQ_ERROR_BADCHAR;
949
1
                    return APREQ_ERROR_BADSEQ;
950
1
                }
951
1
            }
952
1.35k
            else {
953
1.35k
                *val = v;
954
1.35k
                tail = 0;
955
956
7.58k
            look_for_end_value:
957
7.58k
                switch (*v) {
958
608
                case 0:
959
802
                case '\r':
960
855
                case '\n':
961
855
                    done = 1;
962
1.08k
                case ';':
963
1.34k
                case ',':
964
1.34k
                    *vlen = v - *val - tail;
965
1.34k
                    break;
966
205
                case ' ':
967
418
                case '\t':
968
418
                    if (*val == v)
969
0
                        ++*val;
970
418
                    else
971
418
                        ++tail;
972
418
                    ++v;
973
418
                    goto look_for_end_value;
974
5.82k
                default:
975
5.82k
                    if (apr_iscntrl(*v))
976
9
                        return APREQ_ERROR_BADCHAR;
977
5.81k
                    ++v;
978
5.81k
                    tail = 0;
979
5.81k
                    goto look_for_end_value;
980
7.58k
                }
981
7.58k
            }
982
1.37k
        }
983
739
        else {
984
739
            *val = NULL;
985
739
            *vlen = 0;
986
739
        }
987
988
2.08k
        if (hdr + nlen == hde && strncasecmp(hdr, name, nlen) == 0) {
989
959
            return APR_SUCCESS;
990
959
        }
991
992
1.12k
        hdr = v + 1;
993
1.12k
    } while (!done);
994
995
106
    return APREQ_ERROR_NOATTR;
996
1.12k
}
997
998
999
1000
951
#define BUCKET_IS_SPOOL(e) ((e)->type == &spool_bucket_type)
1001
317
#define FILE_BUCKET_LIMIT      ((apr_size_t)-1 - 1)
1002
1003
static
1004
void spool_bucket_destroy(void *data)
1005
317
{
1006
317
    apr_bucket_type_file.destroy(data);
1007
317
}
1008
1009
static
1010
apr_status_t spool_bucket_read(apr_bucket *e, const char **str,
1011
                                   apr_size_t *len, apr_read_type_e block)
1012
0
{
1013
0
    return apr_bucket_type_file.read(e, str, len, block);
1014
0
}
1015
1016
static
1017
apr_status_t spool_bucket_setaside(apr_bucket *data, apr_pool_t *reqpool)
1018
0
{
1019
0
    return apr_bucket_type_file.setaside(data, reqpool);
1020
0
}
1021
1022
static
1023
apr_status_t spool_bucket_split(apr_bucket *a, apr_size_t point)
1024
0
{
1025
0
    apr_status_t rv = apr_bucket_shared_split(a, point);
1026
0
    a->type = &apr_bucket_type_file;
1027
0
    return rv;
1028
0
}
1029
1030
static
1031
apr_status_t spool_bucket_copy(apr_bucket *e, apr_bucket **c)
1032
0
{
1033
0
    apr_status_t rv = apr_bucket_shared_copy(e, c);
1034
0
    (*c)->type = &apr_bucket_type_file;
1035
0
    return rv;
1036
0
}
1037
1038
static const apr_bucket_type_t spool_bucket_type = {
1039
    "APREQ_SPOOL", 5, APR_BUCKET_DATA,
1040
    spool_bucket_destroy,
1041
    spool_bucket_read,
1042
    spool_bucket_setaside,
1043
    spool_bucket_split,
1044
    spool_bucket_copy,
1045
};
1046
1047
APREQ_DECLARE(apr_file_t *)apreq_brigade_spoolfile(apr_bucket_brigade *bb)
1048
0
{
1049
0
    apr_bucket *last;
1050
1051
0
    last = APR_BRIGADE_LAST(bb);
1052
0
    if (BUCKET_IS_SPOOL(last))
1053
0
        return ((apr_bucket_file *)last->data)->fd;
1054
1055
0
    return NULL;
1056
0
}
1057
1058
APREQ_DECLARE(apr_status_t) apreq_brigade_concat(apr_pool_t *pool,
1059
                                                 const char *temp_dir,
1060
                                                 apr_size_t heap_limit,
1061
                                                 apr_bucket_brigade *out,
1062
                                                 apr_bucket_brigade *in)
1063
595
{
1064
595
    apr_status_t s;
1065
595
    apr_bucket_file *f;
1066
595
    apr_off_t wlen;
1067
595
    apr_file_t *file;
1068
595
    apr_off_t in_len, out_len;
1069
595
    apr_bucket *last_in, *last_out;
1070
1071
595
    last_out = APR_BRIGADE_LAST(out);
1072
1073
595
    if (APR_BUCKET_IS_EOS(last_out))
1074
0
        return APR_EOF;
1075
1076
595
    s = apr_brigade_length(out, 0, &out_len);
1077
595
    if (s != APR_SUCCESS)
1078
0
        return s;
1079
1080
    /* This cast, when out_len = -1, is intentional */
1081
595
    if ((apr_uint64_t)out_len < heap_limit) {
1082
1083
595
        s = apr_brigade_length(in, 0, &in_len);
1084
595
        if (s != APR_SUCCESS)
1085
0
            return s;
1086
1087
        /* This cast, when in_len = -1, is intentional */
1088
595
        if ((apr_uint64_t)in_len < heap_limit - (apr_uint64_t)out_len) {
1089
278
            APR_BRIGADE_CONCAT(out, in);
1090
278
            return APR_SUCCESS;
1091
278
        }
1092
595
    }
1093
1094
317
    if (!BUCKET_IS_SPOOL(last_out)) {
1095
1096
317
        s = apreq_file_mktemp(&file, pool, temp_dir);
1097
317
        if (s != APR_SUCCESS)
1098
0
            return s;
1099
1100
317
        s = apreq_brigade_fwrite(file, &wlen, out);
1101
1102
317
        if (s != APR_SUCCESS)
1103
0
            return s;
1104
1105
317
        apr_brigade_cleanup(out);
1106
317
        last_out = apr_bucket_file_create(file, 0, wlen,
1107
317
                                          out->p, out->bucket_alloc);
1108
317
        last_out->type = &spool_bucket_type;
1109
317
        APR_BRIGADE_INSERT_TAIL(out, last_out);
1110
317
        f = last_out->data;
1111
317
    }
1112
0
    else {
1113
0
        f = last_out->data;
1114
        /* Need to seek here, just in case our spool bucket
1115
         * was read from between apreq_brigade_concat calls.
1116
         */
1117
0
        wlen = last_out->start + last_out->length;
1118
0
        s = apr_file_seek(f->fd, APR_SET, &wlen);
1119
0
        if (s != APR_SUCCESS)
1120
0
            return s;
1121
0
    }
1122
1123
317
    if (in == out)
1124
0
        return APR_SUCCESS;
1125
1126
317
    last_in = APR_BRIGADE_LAST(in);
1127
1128
317
    if (APR_BUCKET_IS_EOS(last_in))
1129
317
        APR_BUCKET_REMOVE(last_in);
1130
1131
317
    s = apreq_brigade_fwrite(f->fd, &wlen, in);
1132
1133
317
    if (s == APR_SUCCESS) {
1134
1135
        /* We have to deal with the possibility that the new
1136
         * data may be too large to be represented by a single
1137
         * temp_file bucket.
1138
         */
1139
1140
317
        while ((apr_uint64_t)wlen > FILE_BUCKET_LIMIT - last_out->length) {
1141
0
            apr_bucket *e;
1142
1143
0
            apr_bucket_copy(last_out, &e);
1144
0
            e->length = 0;
1145
0
            e->start = last_out->start + FILE_BUCKET_LIMIT;
1146
0
            wlen -= FILE_BUCKET_LIMIT - last_out->length;
1147
0
            last_out->length = FILE_BUCKET_LIMIT;
1148
1149
            /* Copying makes the bucket types exactly the
1150
             * opposite of what we need here.
1151
             */
1152
0
            last_out->type = &apr_bucket_type_file;
1153
0
            e->type = &spool_bucket_type;
1154
1155
0
            APR_BRIGADE_INSERT_TAIL(out, e);
1156
0
            last_out = e;
1157
0
        }
1158
1159
317
        last_out->length += wlen;
1160
1161
317
        if (APR_BUCKET_IS_EOS(last_in))
1162
0
            APR_BRIGADE_INSERT_TAIL(out, last_in);
1163
1164
317
    }
1165
0
    else if (APR_BUCKET_IS_EOS(last_in))
1166
0
        APR_BRIGADE_INSERT_TAIL(in, last_in);
1167
1168
317
    apr_brigade_cleanup(in);
1169
317
    return s;
1170
317
}
1171
1172
APREQ_DECLARE(apr_status_t) apreq_brigade_fwrite(apr_file_t *f,
1173
                                                 apr_off_t *wlen,
1174
                                                 apr_bucket_brigade *bb)
1175
634
{
1176
634
    struct iovec v[APREQ_DEFAULT_NELTS];
1177
634
    apr_status_t s;
1178
634
    apr_bucket *e, *first;
1179
634
    int n = 0;
1180
634
    apr_bucket_brigade *tmp = bb;
1181
634
    *wlen = 0;
1182
1183
634
    if (BUCKET_IS_SPOOL(APR_BRIGADE_LAST(bb))) {
1184
0
        tmp = apr_brigade_create(bb->p, bb->bucket_alloc);
1185
1186
0
        s = apreq_brigade_copy(tmp, bb);
1187
0
        if (s != APR_SUCCESS)
1188
0
            return s;
1189
0
    }
1190
1191
964
    for (e = APR_BRIGADE_FIRST(tmp); e != APR_BRIGADE_SENTINEL(tmp);
1192
634
         e = APR_BUCKET_NEXT(e))
1193
330
    {
1194
330
        apr_size_t len;
1195
330
        if (n == APREQ_DEFAULT_NELTS) {
1196
0
            s = apreq_fwritev(f, v, &n, &len);
1197
0
            if (s != APR_SUCCESS)
1198
0
                return s;
1199
1200
0
            if (tmp != bb) {
1201
0
                while ((first = APR_BRIGADE_FIRST(tmp)) != e)
1202
0
                    apr_bucket_delete(first);
1203
0
            }
1204
1205
0
            *wlen += len;
1206
0
        }
1207
330
        s = apr_bucket_read(e, (const char **)&(v[n].iov_base),
1208
330
                            &len, APR_BLOCK_READ);
1209
330
        if (s != APR_SUCCESS)
1210
0
            return s;
1211
1212
330
        v[n++].iov_len = len;
1213
330
    }
1214
1215
951
    while (n > 0) {
1216
317
        apr_size_t len;
1217
317
        s = apreq_fwritev(f, v, &n, &len);
1218
317
        if (s != APR_SUCCESS)
1219
0
            return s;
1220
317
        *wlen += len;
1221
1222
317
        if (tmp != bb) {
1223
0
            while ((first = APR_BRIGADE_FIRST(tmp)) != e)
1224
0
                apr_bucket_delete(first);
1225
0
        }
1226
317
    }
1227
634
    return APR_SUCCESS;
1228
634
}