Coverage Report

Created: 2023-03-26 06:28

/src/httpd/srclib/apr/buckets/apr_brigade.c
Line
Count
Source (jump to first uncovered line)
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
 * contributor license agreements.  See the NOTICE file distributed with
3
 * this work for additional information regarding copyright ownership.
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * (the "License"); you may not use this file except in compliance with
6
 * the License.  You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include "apr.h"
18
#include "apr_lib.h"
19
#include "apr_strings.h"
20
#include "apr_pools.h"
21
#include "apr_tables.h"
22
#include "apr_buckets.h"
23
#include "apr_errno.h"
24
#define APR_WANT_MEMFUNC
25
#define APR_WANT_STRFUNC
26
#include "apr_want.h"
27
28
#if APR_HAVE_SYS_UIO_H
29
#include <sys/uio.h>
30
#endif
31
32
static apr_status_t brigade_cleanup(void *data)
33
5.01k
{
34
5.01k
    return apr_brigade_cleanup(data);
35
5.01k
}
36
37
APR_DECLARE(apr_status_t) apr_brigade_cleanup(void *data)
38
6.02k
{
39
6.02k
    apr_bucket_brigade *b = data;
40
41
6.02k
#ifndef APR_BUCKET_DEBUG
42
8.70k
    while (!APR_BRIGADE_EMPTY(b)) {
43
2.68k
        apr_bucket_delete(APR_BRIGADE_FIRST(b));
44
2.68k
    }
45
#else
46
    /* Debugging version with checks which will only trigger if the
47
     * bucket list becomes corrupt. */
48
    apr_bucket *e;
49
    apr_bucket *prev = NULL;
50
51
    APR_BRIGADE_CHECK_CONSISTENCY(b);
52
53
    while (!APR_BRIGADE_EMPTY(b)) {
54
        e = APR_BRIGADE_FIRST(b);
55
        assert(e != prev);
56
        prev = e;
57
        apr_bucket_delete(e);
58
    }
59
#endif
60
61
    /* We don't need to free(bb) because it's allocated from a pool. */
62
6.02k
    return APR_SUCCESS;
63
6.02k
}
64
65
APR_DECLARE(apr_status_t) apr_brigade_destroy(apr_bucket_brigade *b)
66
0
{
67
0
#ifndef APR_BUCKET_DEBUG
68
0
    return apr_pool_cleanup_run(b->p, b, brigade_cleanup);
69
#else
70
    apr_status_t rv;
71
72
    APR_BRIGADE_CHECK_CONSISTENCY(b);
73
74
    rv = apr_pool_cleanup_run(b->p, b, brigade_cleanup);
75
76
    /* Trigger consistency check failures if the brigade is
77
     * re-used. */
78
    b->p = NULL;
79
    b->bucket_alloc = NULL;
80
81
    return rv;
82
#endif
83
0
}
84
85
APR_DECLARE(apr_bucket_brigade *) apr_brigade_create(apr_pool_t *p,
86
                                                     apr_bucket_alloc_t *list)
87
5.01k
{
88
5.01k
    apr_bucket_brigade *b;
89
90
5.01k
    b = apr_palloc(p, sizeof(*b));
91
5.01k
    b->p = p;
92
5.01k
    b->bucket_alloc = list;
93
94
5.01k
    APR_RING_INIT(&b->list, apr_bucket, link);
95
96
5.01k
    apr_pool_cleanup_register(b->p, b, brigade_cleanup, apr_pool_cleanup_null);
97
5.01k
    return b;
98
5.01k
}
99
100
APR_DECLARE(apr_bucket_brigade *) apr_brigade_split_ex(apr_bucket_brigade *b,
101
                                                       apr_bucket *e,
102
                                                       apr_bucket_brigade *a)
103
0
{
104
0
    apr_bucket *f;
105
106
0
    if (!a) {
107
0
        a = apr_brigade_create(b->p, b->bucket_alloc);
108
0
    }
109
0
    else if (!APR_BRIGADE_EMPTY(a)) {
110
0
        apr_brigade_cleanup(a);
111
0
    }
112
    /* Return an empty brigade if there is nothing left in
113
     * the first brigade to split off
114
     */
115
0
    if (e != APR_BRIGADE_SENTINEL(b)) {
116
0
        f = APR_RING_LAST(&b->list);
117
0
        APR_RING_UNSPLICE(e, f, link);
118
0
        APR_RING_SPLICE_HEAD(&a->list, e, f, apr_bucket, link);
119
0
    }
120
121
0
    APR_BRIGADE_CHECK_CONSISTENCY(a);
122
0
    APR_BRIGADE_CHECK_CONSISTENCY(b);
123
124
0
    return a;
125
0
}
126
127
APR_DECLARE(apr_bucket_brigade *) apr_brigade_split(apr_bucket_brigade *b,
128
                                                    apr_bucket *e)
129
0
{
130
0
    return apr_brigade_split_ex(b, e, NULL);
131
0
}
132
133
APR_DECLARE(apr_status_t) apr_brigade_partition(apr_bucket_brigade *b,
134
                                                apr_off_t point,
135
                                                apr_bucket **after_point)
136
0
{
137
0
    apr_bucket *e;
138
0
    const char *s;
139
0
    apr_size_t len;
140
0
    apr_uint64_t point64;
141
0
    apr_status_t rv;
142
143
0
    if (point < 0) {
144
        /* this could cause weird (not necessarily SEGV) things to happen */
145
0
        return APR_EINVAL;
146
0
    }
147
0
    if (point == 0) {
148
0
        *after_point = APR_BRIGADE_FIRST(b);
149
0
        return APR_SUCCESS;
150
0
    }
151
152
    /*
153
     * Try to reduce the following casting mess: We know that point will be
154
     * larger equal 0 now and forever and thus that point (apr_off_t) and
155
     * apr_size_t will fit into apr_uint64_t in any case.
156
     */
157
0
    point64 = (apr_uint64_t)point;
158
159
0
    APR_BRIGADE_CHECK_CONSISTENCY(b);
160
161
0
    for (e = APR_BRIGADE_FIRST(b);
162
0
         e != APR_BRIGADE_SENTINEL(b);
163
0
         e = APR_BUCKET_NEXT(e))
164
0
    {
165
        /* For an unknown length bucket, while 'point64' is beyond the possible
166
         * size contained in apr_size_t, read and continue...
167
         */
168
0
        if ((e->length == (apr_size_t)(-1))
169
0
            && (point64 > (apr_uint64_t)APR_SIZE_MAX)) {
170
            /* point64 is too far out to simply split this bucket,
171
             * we must fix this bucket's size and keep going... */
172
0
            rv = apr_bucket_read(e, &s, &len, APR_BLOCK_READ);
173
0
            if (rv != APR_SUCCESS) {
174
0
                *after_point = e;
175
0
                return rv;
176
0
            }
177
0
        }
178
0
        else if ((point64 < (apr_uint64_t)e->length)
179
0
                 || (e->length == (apr_size_t)(-1))) {
180
            /* We already consumed buckets where point64 is beyond
181
             * our interest ( point64 > APR_SIZE_MAX ), above.
182
             * Here point falls between 0 and APR_SIZE_MAX
183
             * and is within this bucket, or this bucket's len
184
             * is undefined, so now we are ready to split it.
185
             * First try to split the bucket natively... */
186
0
            if ((rv = apr_bucket_split(e, (apr_size_t)point64))
187
0
                    != APR_ENOTIMPL) {
188
0
                *after_point = APR_BUCKET_NEXT(e);
189
0
                return rv;
190
0
            }
191
192
            /* if the bucket cannot be split, we must read from it,
193
             * changing its type to one that can be split */
194
0
            rv = apr_bucket_read(e, &s, &len, APR_BLOCK_READ);
195
0
            if (rv != APR_SUCCESS) {
196
0
                *after_point = e;
197
0
                return rv;
198
0
            }
199
200
            /* this assumes that len == e->length, which is okay because e
201
             * might have been morphed by the apr_bucket_read() above, but
202
             * if it was, the length would have been adjusted appropriately */
203
0
            if (point64 < (apr_uint64_t)e->length) {
204
0
                rv = apr_bucket_split(e, (apr_size_t)point64);
205
0
                *after_point = APR_BUCKET_NEXT(e);
206
0
                return rv;
207
0
            }
208
0
        }
209
0
        if (point64 == (apr_uint64_t)e->length) {
210
0
            *after_point = APR_BUCKET_NEXT(e);
211
0
            return APR_SUCCESS;
212
0
        }
213
0
        point64 -= (apr_uint64_t)e->length;
214
0
    }
215
0
    *after_point = APR_BRIGADE_SENTINEL(b);
216
0
    return APR_INCOMPLETE;
217
0
}
218
219
APR_DECLARE(apr_status_t) apr_brigade_length(apr_bucket_brigade *bb,
220
                                             int read_all, apr_off_t *length)
221
1.63k
{
222
1.63k
    apr_off_t total = 0;
223
1.63k
    apr_bucket *bkt;
224
1.63k
    apr_status_t status = APR_SUCCESS;
225
226
1.63k
    for (bkt = APR_BRIGADE_FIRST(bb);
227
2.61k
         bkt != APR_BRIGADE_SENTINEL(bb);
228
1.63k
         bkt = APR_BUCKET_NEXT(bkt))
229
977
    {
230
977
        if (bkt->length == (apr_size_t)(-1)) {
231
0
            const char *ignore;
232
0
            apr_size_t len;
233
234
0
            if (!read_all) {
235
0
                total = -1;
236
0
                break;
237
0
            }
238
239
0
            if ((status = apr_bucket_read(bkt, &ignore, &len,
240
0
                                          APR_BLOCK_READ)) != APR_SUCCESS) {
241
0
                break;
242
0
            }
243
0
        }
244
245
977
        total += bkt->length;
246
977
    }
247
248
1.63k
    *length = total;
249
1.63k
    return status;
250
1.63k
}
251
252
APR_DECLARE(apr_status_t) apr_brigade_flatten(apr_bucket_brigade *bb,
253
                                              char *c, apr_size_t *len)
254
445
{
255
445
    apr_size_t actual = 0;
256
445
    apr_bucket *b;
257
258
445
    for (b = APR_BRIGADE_FIRST(bb);
259
451
         b != APR_BRIGADE_SENTINEL(bb);
260
445
         b = APR_BUCKET_NEXT(b))
261
449
    {
262
449
        const char *str;
263
449
        apr_size_t str_len;
264
449
        apr_status_t status;
265
266
449
        status = apr_bucket_read(b, &str, &str_len, APR_BLOCK_READ);
267
449
        if (status != APR_SUCCESS) {
268
0
            return status;
269
0
        }
270
271
        /* If we would overflow. */
272
449
        if (str_len + actual > *len) {
273
0
            str_len = *len - actual;
274
0
        }
275
276
        /* XXX: It appears that overflow of the final bucket
277
         * is DISCARDED without any warning to the caller.
278
         *
279
         * No, we only copy the data up to their requested size.  -- jre
280
         */
281
449
        memcpy(c, str, str_len);
282
283
449
        c += str_len;
284
449
        actual += str_len;
285
286
        /* This could probably be actual == *len, but be safe from stray
287
         * photons. */
288
449
        if (actual >= *len) {
289
443
            break;
290
443
        }
291
449
    }
292
293
445
    *len = actual;
294
445
    return APR_SUCCESS;
295
445
}
296
297
APR_DECLARE(apr_status_t) apr_brigade_pflatten(apr_bucket_brigade *bb,
298
                                               char **c,
299
                                               apr_size_t *len,
300
                                               apr_pool_t *pool)
301
399
{
302
399
    apr_off_t actual;
303
399
    apr_size_t total;
304
399
    apr_status_t rv;
305
306
399
    apr_brigade_length(bb, 1, &actual);
307
308
    /* XXX: This is dangerous beyond belief.  At least in the
309
     * apr_brigade_flatten case, the user explicitly stated their
310
     * buffer length - so we don't up and palloc 4GB for a single
311
     * file bucket.  This API must grow a useful max boundry,
312
     * either compiled-in or preset via the *len value.
313
     *
314
     * Shouldn't both fn's grow an additional return value for
315
     * the case that the brigade couldn't be flattened into the
316
     * provided or allocated buffer (such as APR_EMOREDATA?)
317
     * Not a failure, simply an advisory result.
318
     */
319
399
    total = (apr_size_t)actual;
320
321
399
    *c = apr_palloc(pool, total);
322
323
399
    rv = apr_brigade_flatten(bb, *c, &total);
324
325
399
    if (rv != APR_SUCCESS) {
326
0
        return rv;
327
0
    }
328
329
399
    *len = total;
330
399
    return APR_SUCCESS;
331
399
}
332
333
APR_DECLARE(apr_status_t) apr_brigade_split_line(apr_bucket_brigade *bbOut,
334
                                                 apr_bucket_brigade *bbIn,
335
                                                 apr_read_type_e block,
336
                                                 apr_off_t maxbytes)
337
0
{
338
0
    apr_off_t readbytes = 0;
339
0
    apr_bucket *prev = NULL;
340
341
0
    while (!APR_BRIGADE_EMPTY(bbIn)) {
342
0
        const char *pos;
343
0
        const char *str;
344
0
        apr_size_t len;
345
0
        apr_status_t rv;
346
0
        apr_bucket *e;
347
348
0
        e = APR_BRIGADE_FIRST(bbIn);
349
0
        if (e == prev) {         /* PR#51062: prevent infinite loop on a corrupt brigade */
350
0
            return APR_EGENERAL; /* FIXME: this should definitely be a "can't happen"!   */
351
0
        }
352
0
        prev = e;
353
0
        rv = apr_bucket_read(e, &str, &len, block);
354
355
0
        if (rv != APR_SUCCESS) {
356
0
            return rv;
357
0
        }
358
359
0
        pos = memchr(str, APR_ASCII_LF, len);
360
        /* We found a match. */
361
0
        if (pos != NULL) {
362
0
            apr_bucket_split(e, pos - str + 1);
363
0
            APR_BUCKET_REMOVE(e);
364
0
            APR_BRIGADE_INSERT_TAIL(bbOut, e);
365
0
            return APR_SUCCESS;
366
0
        }
367
0
        APR_BUCKET_REMOVE(e);
368
0
        if (APR_BUCKET_IS_METADATA(e) || len > APR_BUCKET_BUFF_SIZE/4) {
369
0
            APR_BRIGADE_INSERT_TAIL(bbOut, e);
370
0
        }
371
0
        else {
372
0
            if (len > 0) {
373
0
                rv = apr_brigade_write(bbOut, NULL, NULL, str, len);
374
0
                if (rv != APR_SUCCESS) {
375
0
                    return rv;
376
0
                }
377
0
            }
378
0
            apr_bucket_destroy(e);
379
0
        }
380
0
        readbytes += len;
381
        /* We didn't find an APR_ASCII_LF within the maximum line length. */
382
0
        if (readbytes >= maxbytes) {
383
0
            break;
384
0
        }
385
0
    }
386
387
0
    return APR_SUCCESS;
388
0
}
389
390
#if !APR_HAVE_MEMMEM
391
static const void *
392
memmem(const void *_hay, size_t hay_len, const void *needle, size_t needle_len)
393
{
394
    if (hay_len < needle_len || !needle_len || !hay_len) {
395
        return NULL;
396
    }
397
    else {
398
        apr_size_t len = hay_len - needle_len + 1;
399
        const apr_byte_t *hay = (apr_byte_t *)_hay;
400
        const apr_byte_t *end = hay + hay_len;
401
402
        while ((hay = memchr(hay, *(char *)needle, len))) {
403
            len = (apr_size_t)(end - hay) - needle_len + 1;
404
405
            if (memcmp(hay, needle, needle_len) == 0 ) {
406
                break;
407
            }
408
409
            --len;
410
            ++hay;
411
        }
412
413
        return hay;
414
    }
415
}
416
#endif
417
418
APR_DECLARE(apr_status_t) apr_brigade_split_boundary(apr_bucket_brigade *bbOut,
419
                                                     apr_bucket_brigade *bbIn,
420
                                                     apr_read_type_e block,
421
                                                     const char *boundary,
422
                                                     apr_size_t boundary_len,
423
                                                     apr_off_t maxbytes)
424
0
{
425
0
    apr_off_t outbytes = 0;
426
0
    apr_size_t ignore = 0;
427
428
0
    if (!boundary || !boundary[0]) {
429
0
        return APR_EINVAL;
430
0
    }
431
432
0
    if (APR_BUCKETS_STRING == boundary_len) {
433
0
        boundary_len = strlen(boundary);
434
0
    }
435
436
    /*
437
     * While the call describes itself as searching for a boundary string,
438
     * what we actually do is search for anything that is definitely not
439
     * a boundary string, and allow that not-boundary data to pass through.
440
     *
441
     * If we find data that might be a boundary, we try read more data in
442
     * until we know for sure.
443
     */
444
0
    while (!APR_BRIGADE_EMPTY(bbIn)) {
445
446
0
        const char *pos;
447
0
        const char *str;
448
0
        apr_bucket *e, *next, *prev;
449
0
        apr_size_t inbytes = 0;
450
0
        apr_size_t len;
451
0
        apr_status_t rv;
452
453
        /* We didn't find a boundary within the maximum line length. */
454
0
        if (outbytes >= maxbytes) {
455
0
            return APR_INCOMPLETE;
456
0
        }
457
458
0
        e = APR_BRIGADE_FIRST(bbIn);
459
460
        /* We hit a metadata bucket, stop and let the caller handle it */
461
0
        if (APR_BUCKET_IS_METADATA(e)) {
462
0
            return APR_INCOMPLETE;
463
0
        }
464
465
0
        rv = apr_bucket_read(e, &str, &len, block);
466
467
0
        if (rv != APR_SUCCESS) {
468
0
            return rv;
469
0
        }
470
471
0
        inbytes += len;
472
473
        /*
474
         * Fast path.
475
         *
476
         * If we have at least one boundary worth of data, do an optimised
477
         * substring search for the boundary, and split quickly if found.
478
         */
479
0
        if ((len - ignore) >= boundary_len) {
480
481
0
            apr_size_t off;
482
0
            apr_size_t leftover;
483
484
0
            pos = memmem(str + ignore, len - ignore, boundary, boundary_len);
485
486
            /* definitely found it, we leave */
487
0
            if (pos != NULL) {
488
489
0
                off = pos - str;
490
491
                /* everything up to the boundary */
492
0
                if (off) {
493
494
0
                    apr_bucket_split(e, off);
495
0
                    APR_BUCKET_REMOVE(e);
496
0
                    APR_BRIGADE_INSERT_TAIL(bbOut, e);
497
498
0
                    e = APR_BRIGADE_FIRST(bbIn);
499
0
                }
500
501
                /* cut out the boundary */
502
0
                apr_bucket_split(e, boundary_len);
503
0
                apr_bucket_delete(e);
504
505
0
                return APR_SUCCESS;
506
0
            }
507
508
            /* any partial matches at the end? */
509
0
            leftover = boundary_len - 1;
510
0
            off = (len - leftover);
511
512
0
            while (leftover) {
513
0
                if (!memcmp(str + off, boundary, leftover)) {
514
515
0
                    if (off) {
516
517
0
                        apr_bucket_split(e, off);
518
0
                        APR_BUCKET_REMOVE(e);
519
0
                        APR_BRIGADE_INSERT_TAIL(bbOut, e);
520
0
                        ignore = 0;
521
522
0
                        e = APR_BRIGADE_FIRST(bbIn);
523
0
                    }
524
525
0
                    outbytes += off;
526
0
                    inbytes -= off;
527
528
0
                    goto skip;
529
0
                }
530
0
                off++;
531
0
                leftover--;
532
0
            }
533
534
0
            APR_BUCKET_REMOVE(e);
535
0
            APR_BRIGADE_INSERT_TAIL(bbOut, e);
536
0
            ignore = 0;
537
538
0
            outbytes += len;
539
540
0
            continue;
541
542
0
        }
543
544
        /*
545
         * Slow path.
546
         *
547
         * We need to read ahead at least one boundary worth of data so
548
         * we can search across the bucket edges.
549
         */
550
0
        else {
551
552
0
            apr_size_t off = ignore;
553
554
0
            len -= ignore;
555
556
            /* find all definite non matches */
557
0
            while (len) {
558
0
                if (!memcmp(str + off, boundary, len)) {
559
560
0
                    if (off) {
561
562
0
                        apr_bucket_split(e, off);
563
0
                        APR_BUCKET_REMOVE(e);
564
0
                        APR_BRIGADE_INSERT_TAIL(bbOut, e);
565
0
                        ignore = 0;
566
567
0
                        outbytes += off;
568
569
0
                        e = APR_BRIGADE_FIRST(bbIn);
570
0
                    }
571
572
0
                    inbytes -= off;
573
574
0
                    goto skip;
575
0
                }
576
0
                off++;
577
0
                len--;
578
0
            }
579
580
0
            APR_BUCKET_REMOVE(e);
581
0
            APR_BRIGADE_INSERT_TAIL(bbOut, e);
582
0
            ignore = 0;
583
584
0
            outbytes += off;
585
586
0
            continue;
587
588
0
        }
589
590
        /*
591
         * If we reach skip, it means the bucket in e is:
592
         *
593
         * - shorter than the boundary
594
         * - matches the boundary up to the bucket length
595
         * - might match more buckets
596
         *
597
         * Read further buckets and check whether the boundary matches all
598
         * the way to the end. If so, we have a match. If no match, shave off
599
         * one byte and continue round to try again.
600
         */
601
0
skip:
602
603
0
        for (next = APR_BUCKET_NEXT(e);
604
0
                inbytes < boundary_len && next != APR_BRIGADE_SENTINEL(bbIn);
605
0
                next = APR_BUCKET_NEXT(next)) {
606
607
0
            const char *str;
608
0
            apr_size_t off;
609
0
            apr_size_t len;
610
611
0
            rv = apr_bucket_read(next, &str, &len, block);
612
613
0
            if (rv != APR_SUCCESS) {
614
0
                return rv;
615
0
            }
616
617
0
            off = boundary_len - inbytes;
618
619
0
            if (len > off) {
620
621
                /* not a match, bail out */
622
0
                if (memcmp(str, boundary + inbytes, off)) {
623
0
                    break;
624
0
                }
625
626
                /* a match! remove the boundary and return */
627
0
                apr_bucket_split(next, off);
628
629
0
                e = APR_BUCKET_NEXT(next);
630
631
0
                for (prev = APR_BRIGADE_FIRST(bbIn);
632
0
                        prev != e;
633
0
                        prev = APR_BRIGADE_FIRST(bbIn)) {
634
635
0
                    apr_bucket_delete(prev);
636
637
0
                }
638
639
0
                return APR_SUCCESS;
640
641
0
            }
642
0
            if (len == off) {
643
644
                /* not a match, bail out */
645
0
                if (memcmp(str, boundary + inbytes, off)) {
646
0
                    break;
647
0
                }
648
649
                /* a match! remove the boundary and return */
650
0
                e = APR_BUCKET_NEXT(next);
651
652
0
                for (prev = APR_BRIGADE_FIRST(bbIn);
653
0
                        prev != e;
654
0
                        prev = APR_BRIGADE_FIRST(bbIn)) {
655
656
0
                    apr_bucket_delete(prev);
657
658
0
                }
659
660
0
                return APR_SUCCESS;
661
662
0
            }
663
0
            else if (len) {
664
665
                /* not a match, bail out */
666
0
                if (memcmp(str, boundary + inbytes, len)) {
667
0
                    break;
668
0
                }
669
670
                /* still hope for a match */
671
0
                inbytes += len;
672
0
            }
673
674
0
        }
675
676
        /*
677
         * If we reach this point, the bucket e did not match the boundary
678
         * in the subsequent buckets.
679
         *
680
         * Bump one byte off, and loop round to search again.
681
         */
682
0
        ignore++;
683
684
0
    }
685
686
0
    return APR_INCOMPLETE;
687
0
}
688
689
690
APR_DECLARE(apr_status_t) apr_brigade_to_iovec(apr_bucket_brigade *b,
691
                                               struct iovec *vec, int *nvec)
692
0
{
693
0
    int left = *nvec;
694
0
    apr_bucket *e;
695
0
    struct iovec *orig;
696
0
    apr_size_t iov_len;
697
0
    const char *iov_base;
698
0
    apr_status_t rv;
699
700
0
    orig = vec;
701
702
0
    for (e = APR_BRIGADE_FIRST(b);
703
0
         e != APR_BRIGADE_SENTINEL(b);
704
0
         e = APR_BUCKET_NEXT(e))
705
0
    {
706
0
        if (left-- == 0)
707
0
            break;
708
709
0
        rv = apr_bucket_read(e, &iov_base, &iov_len, APR_NONBLOCK_READ);
710
0
        if (rv != APR_SUCCESS)
711
0
            return rv;
712
        /* Set indirectly since types differ: */
713
0
        vec->iov_len = iov_len;
714
0
        vec->iov_base = (void *)iov_base;
715
0
        ++vec;
716
0
    }
717
718
0
    *nvec = (int)(vec - orig);
719
0
    return APR_SUCCESS;
720
0
}
721
722
APR_DECLARE(apr_status_t) apr_brigade_vputstrs(apr_bucket_brigade *b,
723
                                               apr_brigade_flush flush,
724
                                               void *ctx,
725
                                               va_list va)
726
0
{
727
0
#define MAX_VECS    8
728
0
    struct iovec vec[MAX_VECS];
729
0
    apr_size_t i = 0;
730
731
0
    for (;;) {
732
0
        char *str = va_arg(va, char *);
733
0
        apr_status_t rv;
734
735
0
        if (str == NULL)
736
0
            break;
737
738
0
        vec[i].iov_base = str;
739
0
        vec[i].iov_len = strlen(str);
740
0
        i++;
741
742
0
        if (i == MAX_VECS) {
743
0
            rv = apr_brigade_writev(b, flush, ctx, vec, i);
744
0
            if (rv != APR_SUCCESS)
745
0
                return rv;
746
0
            i = 0;
747
0
        }
748
0
    }
749
0
    if (i != 0)
750
0
       return apr_brigade_writev(b, flush, ctx, vec, i);
751
752
0
    return APR_SUCCESS;
753
0
}
754
755
APR_DECLARE(apr_status_t) apr_brigade_putc(apr_bucket_brigade *b,
756
                                           apr_brigade_flush flush, void *ctx,
757
                                           const char c)
758
0
{
759
0
    return apr_brigade_write(b, flush, ctx, &c, 1);
760
0
}
761
762
APR_DECLARE(apr_status_t) apr_brigade_write(apr_bucket_brigade *b,
763
                                            apr_brigade_flush flush,
764
                                            void *ctx,
765
                                            const char *str, apr_size_t nbyte)
766
1.06k
{
767
1.06k
    apr_bucket *e = APR_BRIGADE_LAST(b);
768
1.06k
    apr_size_t remaining = APR_BUCKET_BUFF_SIZE;
769
1.06k
    char *buf = NULL;
770
771
    /*
772
     * If the last bucket is a heap bucket and its buffer is not shared with
773
     * another bucket, we may write into that bucket.
774
     */
775
1.06k
    if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e)
776
1.06k
        && ((apr_bucket_heap *)(e->data))->refcount.refcount == 1) {
777
0
        apr_bucket_heap *h = e->data;
778
779
        /* HEAP bucket start offsets are always in-memory, safe to cast */
780
0
        remaining = h->alloc_len - (e->length + (apr_size_t)e->start);
781
0
        buf = h->base + e->start + e->length;
782
0
    }
783
784
1.06k
    if (nbyte > remaining) {
785
        /* either a buffer bucket exists but is full,
786
         * or no buffer bucket exists and the data is too big
787
         * to buffer.  In either case, we should flush.  */
788
0
        if (flush) {
789
0
            e = apr_bucket_transient_create(str, nbyte, b->bucket_alloc);
790
0
            APR_BRIGADE_INSERT_TAIL(b, e);
791
0
            return flush(b, ctx);
792
0
        }
793
0
        else {
794
0
            e = apr_bucket_heap_create(str, nbyte, NULL, b->bucket_alloc);
795
0
            APR_BRIGADE_INSERT_TAIL(b, e);
796
0
            return APR_SUCCESS;
797
0
        }
798
0
    }
799
1.06k
    else if (!buf) {
800
        /* we don't have a buffer, but the data is small enough
801
         * that we don't mind making a new buffer */
802
1.06k
        buf = apr_bucket_alloc(APR_BUCKET_BUFF_SIZE, b->bucket_alloc);
803
1.06k
        e = apr_bucket_heap_create(buf, APR_BUCKET_BUFF_SIZE,
804
1.06k
                                   apr_bucket_free, b->bucket_alloc);
805
1.06k
        APR_BRIGADE_INSERT_TAIL(b, e);
806
1.06k
        e->length = 0;   /* We are writing into the brigade, and
807
                          * allocating more memory than we need.  This
808
                          * ensures that the bucket thinks it is empty just
809
                          * after we create it.  We'll fix the length
810
                          * once we put data in it below.
811
                          */
812
1.06k
    }
813
814
    /* there is a sufficiently big buffer bucket available now */
815
1.06k
    memcpy(buf, str, nbyte);
816
1.06k
    e->length += nbyte;
817
818
1.06k
    return APR_SUCCESS;
819
1.06k
}
820
821
APR_DECLARE(apr_status_t) apr_brigade_writev(apr_bucket_brigade *b,
822
                                             apr_brigade_flush flush,
823
                                             void *ctx,
824
                                             const struct iovec *vec,
825
                                             apr_size_t nvec)
826
0
{
827
0
    apr_bucket *e;
828
0
    apr_size_t total_len;
829
0
    apr_size_t i;
830
0
    char *buf;
831
832
    /* Compute the total length of the data to be written.
833
     */
834
0
    total_len = 0;
835
0
    for (i = 0; i < nvec; i++) {
836
0
       total_len += vec[i].iov_len;
837
0
    }
838
839
    /* If the data to be written is very large, try to convert
840
     * the iovec to transient buckets rather than copying.
841
     */
842
0
    if (total_len > APR_BUCKET_BUFF_SIZE) {
843
0
        if (flush) {
844
0
            for (i = 0; i < nvec; i++) {
845
0
                e = apr_bucket_transient_create(vec[i].iov_base,
846
0
                                                vec[i].iov_len,
847
0
                                                b->bucket_alloc);
848
0
                APR_BRIGADE_INSERT_TAIL(b, e);
849
0
            }
850
0
            return flush(b, ctx);
851
0
        }
852
0
        else {
853
0
            for (i = 0; i < nvec; i++) {
854
0
                e = apr_bucket_heap_create((const char *) vec[i].iov_base,
855
0
                                           vec[i].iov_len, NULL,
856
0
                                           b->bucket_alloc);
857
0
                APR_BRIGADE_INSERT_TAIL(b, e);
858
0
            }
859
0
            return APR_SUCCESS;
860
0
        }
861
0
    }
862
863
0
    i = 0;
864
865
    /* If there is a heap bucket at the end of the brigade
866
     * already, and its refcount is 1, copy into the existing bucket.
867
     */
868
0
    e = APR_BRIGADE_LAST(b);
869
0
    if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e)
870
0
        && ((apr_bucket_heap *)(e->data))->refcount.refcount == 1) {
871
0
        apr_bucket_heap *h = e->data;
872
0
        apr_size_t remaining = h->alloc_len -
873
0
            (e->length + (apr_size_t)e->start);
874
0
        buf = h->base + e->start + e->length;
875
876
0
        if (remaining >= total_len) {
877
            /* Simple case: all the data will fit in the
878
             * existing heap bucket
879
             */
880
0
            for (; i < nvec; i++) {
881
0
                apr_size_t len = vec[i].iov_len;
882
0
                memcpy(buf, (const void *) vec[i].iov_base, len);
883
0
                buf += len;
884
0
            }
885
0
            e->length += total_len;
886
0
            return APR_SUCCESS;
887
0
        }
888
0
        else {
889
            /* More complicated case: not all of the data
890
             * will fit in the existing heap bucket.  The
891
             * total data size is <= APR_BUCKET_BUFF_SIZE,
892
             * so we'll need only one additional bucket.
893
             */
894
0
            const char *start_buf = buf;
895
0
            for (; i < nvec; i++) {
896
0
                apr_size_t len = vec[i].iov_len;
897
0
                if (len > remaining) {
898
0
                    break;
899
0
                }
900
0
                memcpy(buf, (const void *) vec[i].iov_base, len);
901
0
                buf += len;
902
0
                remaining -= len;
903
0
            }
904
0
            e->length += (buf - start_buf);
905
0
            total_len -= (buf - start_buf);
906
907
0
            if (flush) {
908
0
                apr_status_t rv = flush(b, ctx);
909
0
                if (rv != APR_SUCCESS) {
910
0
                    return rv;
911
0
                }
912
0
            }
913
914
            /* Now fall through into the case below to
915
             * allocate another heap bucket and copy the
916
             * rest of the array.  (Note that i is not
917
             * reset to zero here; it holds the index
918
             * of the first vector element to be
919
             * written to the new bucket.)
920
             */
921
0
        }
922
0
    }
923
924
    /* Allocate a new heap bucket, and copy the data into it.
925
     * The checks above ensure that the amount of data to be
926
     * written here is no larger than APR_BUCKET_BUFF_SIZE.
927
     */
928
0
    buf = apr_bucket_alloc(APR_BUCKET_BUFF_SIZE, b->bucket_alloc);
929
0
    e = apr_bucket_heap_create(buf, APR_BUCKET_BUFF_SIZE,
930
0
                               apr_bucket_free, b->bucket_alloc);
931
0
    for (; i < nvec; i++) {
932
0
        apr_size_t len = vec[i].iov_len;
933
0
        memcpy(buf, (const void *) vec[i].iov_base, len);
934
0
        buf += len;
935
0
    }
936
0
    e->length = total_len;
937
0
    APR_BRIGADE_INSERT_TAIL(b, e);
938
939
0
    return APR_SUCCESS;
940
0
}
941
942
APR_DECLARE(apr_status_t) apr_brigade_puts(apr_bucket_brigade *bb,
943
                                           apr_brigade_flush flush, void *ctx,
944
                                           const char *str)
945
0
{
946
0
    return apr_brigade_write(bb, flush, ctx, str, strlen(str));
947
0
}
948
949
APR_DECLARE_NONSTD(apr_status_t) apr_brigade_putstrs(apr_bucket_brigade *b,
950
                                                     apr_brigade_flush flush,
951
                                                     void *ctx, ...)
952
0
{
953
0
    va_list va;
954
0
    apr_status_t rv;
955
956
0
    va_start(va, ctx);
957
0
    rv = apr_brigade_vputstrs(b, flush, ctx, va);
958
0
    va_end(va);
959
0
    return rv;
960
0
}
961
962
APR_DECLARE_NONSTD(apr_status_t) apr_brigade_printf(apr_bucket_brigade *b,
963
                                                    apr_brigade_flush flush,
964
                                                    void *ctx,
965
                                                    const char *fmt, ...)
966
0
{
967
0
    va_list ap;
968
0
    apr_status_t rv;
969
970
0
    va_start(ap, fmt);
971
0
    rv = apr_brigade_vprintf(b, flush, ctx, fmt, ap);
972
0
    va_end(ap);
973
0
    return rv;
974
0
}
975
976
struct brigade_vprintf_data_t {
977
    apr_vformatter_buff_t vbuff;
978
979
    apr_bucket_brigade *b;  /* associated brigade */
980
    apr_brigade_flush *flusher; /* flushing function */
981
    void *ctx;
982
983
    char *cbuff; /* buffer to flush from */
984
};
985
986
static apr_status_t brigade_flush(apr_vformatter_buff_t *buff)
987
0
{
988
    /* callback function passed to ap_vformatter to be
989
     * called when vformatter needs to buff and
990
     * buff.curpos > buff.endpos
991
     */
992
993
    /* "downcast," have really passed a brigade_vprintf_data_t* */
994
0
    struct brigade_vprintf_data_t *vd = (struct brigade_vprintf_data_t*)buff;
995
0
    apr_status_t res = APR_SUCCESS;
996
997
0
    res = apr_brigade_write(vd->b, *vd->flusher, vd->ctx, vd->cbuff,
998
0
                          APR_BUCKET_BUFF_SIZE);
999
1000
0
    if(res != APR_SUCCESS) {
1001
0
      return -1;
1002
0
    }
1003
1004
0
    vd->vbuff.curpos = vd->cbuff;
1005
0
    vd->vbuff.endpos = vd->cbuff + APR_BUCKET_BUFF_SIZE;
1006
1007
0
    return res;
1008
0
}
1009
1010
APR_DECLARE(apr_status_t) apr_brigade_vprintf(apr_bucket_brigade *b,
1011
                                              apr_brigade_flush flush,
1012
                                              void *ctx,
1013
                                              const char *fmt, va_list va)
1014
0
{
1015
    /* the cast, in order of appearance */
1016
0
    struct brigade_vprintf_data_t vd;
1017
0
    char buf[APR_BUCKET_BUFF_SIZE];
1018
0
    int written;
1019
1020
0
    vd.vbuff.curpos = buf;
1021
0
    vd.vbuff.endpos = buf + APR_BUCKET_BUFF_SIZE;
1022
0
    vd.b = b;
1023
0
    vd.flusher = &flush;
1024
0
    vd.ctx = ctx;
1025
0
    vd.cbuff = buf;
1026
1027
0
    written = apr_vformatter(brigade_flush, &vd.vbuff, fmt, va);
1028
1029
0
    if (written == -1) {
1030
0
      return -1;
1031
0
    }
1032
1033
    /* write out what remains in the buffer */
1034
0
    return apr_brigade_write(b, flush, ctx, buf, vd.vbuff.curpos - buf);
1035
0
}
1036
1037
/* A "safe" maximum bucket size, 1Gb */
1038
0
#define MAX_BUCKET_SIZE (0x40000000)
1039
1040
APR_DECLARE(apr_bucket *) apr_brigade_insert_file(apr_bucket_brigade *bb,
1041
                                                  apr_file_t *f,
1042
                                                  apr_off_t start,
1043
                                                  apr_off_t length,
1044
                                                  apr_pool_t *p)
1045
0
{
1046
0
    apr_bucket *e;
1047
1048
0
    if (sizeof(apr_off_t) == sizeof(apr_size_t) || length < MAX_BUCKET_SIZE) {
1049
0
        e = apr_bucket_file_create(f, start, (apr_size_t)length, p,
1050
0
                                   bb->bucket_alloc);
1051
0
    }
1052
0
    else {
1053
        /* Several buckets are needed. */
1054
0
        e = apr_bucket_file_create(f, start, MAX_BUCKET_SIZE, p,
1055
0
                                   bb->bucket_alloc);
1056
1057
0
        while (length > MAX_BUCKET_SIZE) {
1058
0
            apr_bucket *ce;
1059
0
            apr_bucket_copy(e, &ce);
1060
0
            APR_BRIGADE_INSERT_TAIL(bb, ce);
1061
0
            e->start += MAX_BUCKET_SIZE;
1062
0
            length -= MAX_BUCKET_SIZE;
1063
0
        }
1064
0
        e->length = (apr_size_t)length; /* Resize just the last bucket */
1065
0
    }
1066
1067
0
    APR_BRIGADE_INSERT_TAIL(bb, e);
1068
0
    return e;
1069
0
}