Coverage Report

Created: 2025-07-11 06:40

/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
4.73k
{
34
4.73k
    return apr_brigade_cleanup(data);
35
4.73k
}
36
37
APR_DECLARE(apr_status_t) apr_brigade_cleanup(void *data)
38
5.91k
{
39
5.91k
    apr_bucket_brigade *b = data;
40
41
5.91k
#ifndef APR_BUCKET_DEBUG
42
8.72k
    while (!APR_BRIGADE_EMPTY(b)) {
43
2.80k
        apr_bucket_delete(APR_BRIGADE_FIRST(b));
44
2.80k
    }
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
5.91k
    return APR_SUCCESS;
63
5.91k
}
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
4.73k
{
88
4.73k
    apr_bucket_brigade *b;
89
90
4.73k
    b = apr_palloc(p, sizeof(*b));
91
4.73k
    b->p = p;
92
4.73k
    b->bucket_alloc = list;
93
94
4.73k
    APR_RING_INIT(&b->list, apr_bucket, link);
95
96
4.73k
    apr_pool_cleanup_register(b->p, b, brigade_cleanup, apr_pool_cleanup_null);
97
4.73k
    return b;
98
4.73k
}
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.72k
{
222
1.72k
    apr_off_t total = 0;
223
1.72k
    apr_bucket *bkt;
224
1.72k
    apr_status_t status = APR_SUCCESS;
225
226
1.72k
    for (bkt = APR_BRIGADE_FIRST(bb);
227
2.84k
         bkt != APR_BRIGADE_SENTINEL(bb);
228
1.72k
         bkt = APR_BUCKET_NEXT(bkt))
229
1.12k
    {
230
1.12k
        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
1.12k
        total += bkt->length;
246
1.12k
    }
247
248
1.72k
    *length = total;
249
1.72k
    return status;
250
1.72k
}
251
252
APR_DECLARE(apr_status_t) apr_brigade_flatten(apr_bucket_brigade *bb,
253
                                              char *c, apr_size_t *len)
254
621
{
255
621
    apr_size_t actual = 0;
256
621
    apr_bucket *b;
257
258
621
    for (b = APR_BRIGADE_FIRST(bb);
259
629
         b != APR_BRIGADE_SENTINEL(bb);
260
621
         b = APR_BUCKET_NEXT(b))
261
625
    {
262
625
        const char *str;
263
625
        apr_size_t str_len;
264
625
        apr_status_t status;
265
266
625
        status = apr_bucket_read(b, &str, &str_len, APR_BLOCK_READ);
267
625
        if (status != APR_SUCCESS) {
268
0
            return status;
269
0
        }
270
271
        /* If we would overflow. */
272
625
        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
625
        if (str_len) {
282
625
            memcpy(c, str, str_len);
283
625
        }
284
285
625
        c += str_len;
286
625
        actual += str_len;
287
288
        /* This could probably be actual == *len, but be safe from stray
289
         * photons. */
290
625
        if (actual >= *len) {
291
617
            break;
292
617
        }
293
625
    }
294
295
621
    *len = actual;
296
621
    return APR_SUCCESS;
297
621
}
298
299
APR_DECLARE(apr_status_t) apr_brigade_pflatten(apr_bucket_brigade *bb,
300
                                               char **c,
301
                                               apr_size_t *len,
302
                                               apr_pool_t *pool)
303
566
{
304
566
    apr_off_t actual;
305
566
    apr_size_t total;
306
566
    apr_status_t rv;
307
308
566
    apr_brigade_length(bb, 1, &actual);
309
310
    /* XXX: This is dangerous beyond belief.  At least in the
311
     * apr_brigade_flatten case, the user explicitly stated their
312
     * buffer length - so we don't up and palloc 4GB for a single
313
     * file bucket.  This API must grow a useful max boundry,
314
     * either compiled-in or preset via the *len value.
315
     *
316
     * Shouldn't both fn's grow an additional return value for
317
     * the case that the brigade couldn't be flattened into the
318
     * provided or allocated buffer (such as APR_EMOREDATA?)
319
     * Not a failure, simply an advisory result.
320
     */
321
566
    total = (apr_size_t)actual;
322
323
566
    *c = apr_palloc(pool, total);
324
325
566
    rv = apr_brigade_flatten(bb, *c, &total);
326
327
566
    if (rv != APR_SUCCESS) {
328
0
        return rv;
329
0
    }
330
331
566
    *len = total;
332
566
    return APR_SUCCESS;
333
566
}
334
335
APR_DECLARE(apr_status_t) apr_brigade_split_line(apr_bucket_brigade *bbOut,
336
                                                 apr_bucket_brigade *bbIn,
337
                                                 apr_read_type_e block,
338
                                                 apr_off_t maxbytes)
339
0
{
340
0
    apr_off_t readbytes = 0;
341
342
0
    APR_BRIGADE_CHECK_CONSISTENCY(bbIn);
343
344
0
    while (!APR_BRIGADE_EMPTY(bbIn)) {
345
0
        const char *pos;
346
0
        const char *str;
347
0
        apr_size_t len;
348
0
        apr_status_t rv;
349
0
        apr_bucket *e;
350
351
0
        e = APR_BRIGADE_FIRST(bbIn);
352
0
        rv = apr_bucket_read(e, &str, &len, block);
353
354
0
        if (rv != APR_SUCCESS) {
355
0
            return rv;
356
0
        }
357
358
0
        if (len) {
359
0
            pos = memchr(str, APR_ASCII_LF, len);
360
            /* We found a match. */
361
0
            if (pos != NULL) {
362
0
                apr_size_t linelen = pos - str + 1;
363
                /* Split if the LF is not the last character in the bucket. */
364
0
                if (linelen < len) {
365
0
                    apr_bucket_split(e, linelen);
366
0
                }
367
0
                APR_BUCKET_REMOVE(e);
368
0
                APR_BRIGADE_INSERT_TAIL(bbOut, e);
369
0
                return APR_SUCCESS;
370
0
            }
371
0
        }
372
0
        APR_BUCKET_REMOVE(e);
373
0
        if (APR_BUCKET_IS_METADATA(e) || len > APR_BUCKET_BUFF_SIZE/4) {
374
0
            APR_BRIGADE_INSERT_TAIL(bbOut, e);
375
0
        }
376
0
        else {
377
0
            if (len > 0) {
378
0
                rv = apr_brigade_write(bbOut, NULL, NULL, str, len);
379
0
                if (rv != APR_SUCCESS) {
380
0
                    return rv;
381
0
                }
382
0
            }
383
0
            apr_bucket_destroy(e);
384
0
        }
385
0
        readbytes += len;
386
        /* We didn't find an APR_ASCII_LF within the maximum line length. */
387
0
        if (readbytes >= maxbytes) {
388
0
            break;
389
0
        }
390
0
    }
391
392
0
    return APR_SUCCESS;
393
0
}
394
395
#if !APR_HAVE_MEMMEM
396
static const void *
397
memmem(const void *_hay, size_t hay_len, const void *needle, size_t needle_len)
398
{
399
    if (hay_len < needle_len || !needle_len || !hay_len) {
400
        return NULL;
401
    }
402
    else {
403
        apr_size_t len = hay_len - needle_len + 1;
404
        const apr_byte_t *hay = (apr_byte_t *)_hay;
405
        const apr_byte_t *end = hay + hay_len;
406
407
        while ((hay = memchr(hay, *(char *)needle, len))) {
408
            len = (apr_size_t)(end - hay) - needle_len + 1;
409
410
            if (memcmp(hay, needle, needle_len) == 0 ) {
411
                break;
412
            }
413
414
            --len;
415
            ++hay;
416
        }
417
418
        return hay;
419
    }
420
}
421
#endif
422
423
APR_DECLARE(apr_status_t) apr_brigade_split_boundary(apr_bucket_brigade *bbOut,
424
                                                     apr_bucket_brigade *bbIn,
425
                                                     apr_read_type_e block,
426
                                                     const char *boundary,
427
                                                     apr_size_t boundary_len,
428
                                                     apr_off_t maxbytes)
429
0
{
430
0
    apr_off_t outbytes = 0;
431
0
    apr_size_t ignore = 0;
432
433
0
    if (!boundary || !boundary[0]) {
434
0
        return APR_EINVAL;
435
0
    }
436
437
0
    if (APR_BUCKETS_STRING == boundary_len) {
438
0
        boundary_len = strlen(boundary);
439
0
    }
440
441
    /*
442
     * While the call describes itself as searching for a boundary string,
443
     * what we actually do is search for anything that is definitely not
444
     * a boundary string, and allow that not-boundary data to pass through.
445
     *
446
     * If we find data that might be a boundary, we try read more data in
447
     * until we know for sure.
448
     */
449
0
    while (!APR_BRIGADE_EMPTY(bbIn)) {
450
451
0
        const char *pos;
452
0
        const char *str;
453
0
        apr_bucket *e, *next, *prev;
454
0
        apr_size_t inbytes = 0;
455
0
        apr_size_t len;
456
0
        apr_status_t rv;
457
458
        /* We didn't find a boundary within the maximum line length. */
459
0
        if (outbytes >= maxbytes) {
460
0
            return APR_INCOMPLETE;
461
0
        }
462
463
0
        e = APR_BRIGADE_FIRST(bbIn);
464
465
        /* We hit a metadata bucket, stop and let the caller handle it */
466
0
        if (APR_BUCKET_IS_METADATA(e)) {
467
0
            return APR_INCOMPLETE;
468
0
        }
469
470
0
        rv = apr_bucket_read(e, &str, &len, block);
471
472
0
        if (rv != APR_SUCCESS) {
473
0
            return rv;
474
0
        }
475
476
0
        inbytes += len;
477
478
        /*
479
         * Fast path.
480
         *
481
         * If we have at least one boundary worth of data, do an optimised
482
         * substring search for the boundary, and split quickly if found.
483
         */
484
0
        if ((len - ignore) >= boundary_len) {
485
486
0
            apr_size_t off;
487
0
            apr_size_t leftover;
488
489
0
            pos = memmem(str + ignore, len - ignore, boundary, boundary_len);
490
491
            /* definitely found it, we leave */
492
0
            if (pos != NULL) {
493
494
0
                off = pos - str;
495
496
                /* everything up to the boundary */
497
0
                if (off) {
498
499
0
                    apr_bucket_split(e, off);
500
0
                    APR_BUCKET_REMOVE(e);
501
0
                    APR_BRIGADE_INSERT_TAIL(bbOut, e);
502
503
0
                    e = APR_BRIGADE_FIRST(bbIn);
504
0
                }
505
506
                /* cut out the boundary */
507
0
                apr_bucket_split(e, boundary_len);
508
0
                apr_bucket_delete(e);
509
510
0
                return APR_SUCCESS;
511
0
            }
512
513
            /* any partial matches at the end? */
514
0
            leftover = boundary_len - 1;
515
0
            off = (len - leftover);
516
517
0
            while (leftover) {
518
0
                if (!memcmp(str + off, boundary, leftover)) {
519
520
0
                    if (off) {
521
522
0
                        apr_bucket_split(e, off);
523
0
                        APR_BUCKET_REMOVE(e);
524
0
                        APR_BRIGADE_INSERT_TAIL(bbOut, e);
525
0
                        ignore = 0;
526
527
0
                        e = APR_BRIGADE_FIRST(bbIn);
528
0
                    }
529
530
0
                    outbytes += off;
531
0
                    inbytes -= off;
532
533
0
                    goto skip;
534
0
                }
535
0
                off++;
536
0
                leftover--;
537
0
            }
538
539
0
            APR_BUCKET_REMOVE(e);
540
0
            APR_BRIGADE_INSERT_TAIL(bbOut, e);
541
0
            ignore = 0;
542
543
0
            outbytes += len;
544
545
0
            continue;
546
547
0
        }
548
549
        /*
550
         * Slow path.
551
         *
552
         * We need to read ahead at least one boundary worth of data so
553
         * we can search across the bucket edges.
554
         */
555
0
        else {
556
557
0
            apr_size_t off = ignore;
558
559
0
            len -= ignore;
560
561
            /* find all definite non matches */
562
0
            while (len) {
563
0
                if (!memcmp(str + off, boundary, len)) {
564
565
0
                    if (off) {
566
567
0
                        apr_bucket_split(e, off);
568
0
                        APR_BUCKET_REMOVE(e);
569
0
                        APR_BRIGADE_INSERT_TAIL(bbOut, e);
570
0
                        ignore = 0;
571
572
0
                        outbytes += off;
573
574
0
                        e = APR_BRIGADE_FIRST(bbIn);
575
0
                    }
576
577
0
                    inbytes -= off;
578
579
0
                    goto skip;
580
0
                }
581
0
                off++;
582
0
                len--;
583
0
            }
584
585
0
            APR_BUCKET_REMOVE(e);
586
0
            APR_BRIGADE_INSERT_TAIL(bbOut, e);
587
0
            ignore = 0;
588
589
0
            outbytes += off;
590
591
0
            continue;
592
593
0
        }
594
595
        /*
596
         * If we reach skip, it means the bucket in e is:
597
         *
598
         * - shorter than the boundary
599
         * - matches the boundary up to the bucket length
600
         * - might match more buckets
601
         *
602
         * Read further buckets and check whether the boundary matches all
603
         * the way to the end. If so, we have a match. If no match, shave off
604
         * one byte and continue round to try again.
605
         */
606
0
skip:
607
608
0
        for (next = APR_BUCKET_NEXT(e);
609
0
                inbytes < boundary_len && next != APR_BRIGADE_SENTINEL(bbIn);
610
0
                next = APR_BUCKET_NEXT(next)) {
611
612
0
            const char *str;
613
0
            apr_size_t off;
614
0
            apr_size_t len;
615
616
0
            rv = apr_bucket_read(next, &str, &len, block);
617
618
0
            if (rv != APR_SUCCESS) {
619
0
                return rv;
620
0
            }
621
622
0
            off = boundary_len - inbytes;
623
624
0
            if (len > off) {
625
626
                /* not a match, bail out */
627
0
                if (memcmp(str, boundary + inbytes, off)) {
628
0
                    break;
629
0
                }
630
631
                /* a match! remove the boundary and return */
632
0
                apr_bucket_split(next, off);
633
634
0
                e = APR_BUCKET_NEXT(next);
635
636
0
                for (prev = APR_BRIGADE_FIRST(bbIn);
637
0
                        prev != e;
638
0
                        prev = APR_BRIGADE_FIRST(bbIn)) {
639
640
0
                    apr_bucket_delete(prev);
641
642
0
                }
643
644
0
                return APR_SUCCESS;
645
646
0
            }
647
0
            if (len == off) {
648
649
                /* not a match, bail out */
650
0
                if (memcmp(str, boundary + inbytes, off)) {
651
0
                    break;
652
0
                }
653
654
                /* a match! remove the boundary and return */
655
0
                e = APR_BUCKET_NEXT(next);
656
657
0
                for (prev = APR_BRIGADE_FIRST(bbIn);
658
0
                        prev != e;
659
0
                        prev = APR_BRIGADE_FIRST(bbIn)) {
660
661
0
                    apr_bucket_delete(prev);
662
663
0
                }
664
665
0
                return APR_SUCCESS;
666
667
0
            }
668
0
            else if (len) {
669
670
                /* not a match, bail out */
671
0
                if (memcmp(str, boundary + inbytes, len)) {
672
0
                    break;
673
0
                }
674
675
                /* still hope for a match */
676
0
                inbytes += len;
677
0
            }
678
679
0
        }
680
681
        /*
682
         * If we reach this point, the bucket e did not match the boundary
683
         * in the subsequent buckets.
684
         *
685
         * Bump one byte off, and loop round to search again.
686
         */
687
0
        ignore++;
688
689
0
    }
690
691
0
    return APR_INCOMPLETE;
692
0
}
693
694
695
APR_DECLARE(apr_status_t) apr_brigade_to_iovec(apr_bucket_brigade *b,
696
                                               struct iovec *vec, int *nvec)
697
0
{
698
0
    int left = *nvec;
699
0
    apr_bucket *e;
700
0
    struct iovec *orig;
701
0
    apr_size_t iov_len;
702
0
    const char *iov_base;
703
0
    apr_status_t rv;
704
705
0
    orig = vec;
706
707
0
    for (e = APR_BRIGADE_FIRST(b);
708
0
         e != APR_BRIGADE_SENTINEL(b);
709
0
         e = APR_BUCKET_NEXT(e))
710
0
    {
711
        /* Skip metadata buckets. */
712
0
        if (APR_BUCKET_IS_METADATA(e)) continue;
713
714
0
        if (left-- == 0)
715
0
            break;
716
717
0
        rv = apr_bucket_read(e, &iov_base, &iov_len, APR_NONBLOCK_READ);
718
0
        if (rv != APR_SUCCESS)
719
0
            return rv;
720
        /* Set indirectly since types differ: */
721
0
        vec->iov_len = iov_len;
722
0
        vec->iov_base = (void *)iov_base;
723
0
        ++vec;
724
0
    }
725
726
0
    *nvec = (int)(vec - orig);
727
0
    return APR_SUCCESS;
728
0
}
729
730
APR_DECLARE(apr_status_t) apr_brigade_vputstrs(apr_bucket_brigade *b,
731
                                               apr_brigade_flush flush,
732
                                               void *ctx,
733
                                               va_list va)
734
0
{
735
0
#define MAX_VECS    8
736
0
    struct iovec vec[MAX_VECS];
737
0
    apr_size_t i = 0;
738
739
0
    for (;;) {
740
0
        char *str = va_arg(va, char *);
741
0
        apr_status_t rv;
742
743
0
        if (str == NULL)
744
0
            break;
745
746
0
        vec[i].iov_base = str;
747
0
        vec[i].iov_len = strlen(str);
748
0
        i++;
749
750
0
        if (i == MAX_VECS) {
751
0
            rv = apr_brigade_writev(b, flush, ctx, vec, i);
752
0
            if (rv != APR_SUCCESS)
753
0
                return rv;
754
0
            i = 0;
755
0
        }
756
0
    }
757
0
    if (i != 0)
758
0
       return apr_brigade_writev(b, flush, ctx, vec, i);
759
760
0
    return APR_SUCCESS;
761
0
}
762
763
APR_DECLARE(apr_status_t) apr_brigade_putc(apr_bucket_brigade *b,
764
                                           apr_brigade_flush flush, void *ctx,
765
                                           const char c)
766
0
{
767
0
    return apr_brigade_write(b, flush, ctx, &c, 1);
768
0
}
769
770
APR_DECLARE(apr_status_t) apr_brigade_write(apr_bucket_brigade *b,
771
                                            apr_brigade_flush flush,
772
                                            void *ctx,
773
                                            const char *str, apr_size_t nbyte)
774
1.05k
{
775
1.05k
    apr_bucket *e = APR_BRIGADE_LAST(b);
776
1.05k
    apr_size_t remaining = APR_BUCKET_BUFF_SIZE;
777
1.05k
    char *buf = NULL;
778
779
    /*
780
     * If the last bucket is a heap bucket and its buffer is not shared with
781
     * another bucket, we may write into that bucket.
782
     */
783
1.05k
    if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e)
784
1.05k
        && ((apr_bucket_heap *)(e->data))->refcount.refcount == 1) {
785
0
        apr_bucket_heap *h = e->data;
786
787
        /* HEAP bucket start offsets are always in-memory, safe to cast */
788
0
        remaining = h->alloc_len - (e->length + (apr_size_t)e->start);
789
0
        buf = h->base + e->start + e->length;
790
0
    }
791
792
1.05k
    if (nbyte > remaining) {
793
        /* either a buffer bucket exists but is full,
794
         * or no buffer bucket exists and the data is too big
795
         * to buffer.  In either case, we should flush.  */
796
0
        if (flush) {
797
0
            e = apr_bucket_transient_create(str, nbyte, b->bucket_alloc);
798
0
            APR_BRIGADE_INSERT_TAIL(b, e);
799
0
            return flush(b, ctx);
800
0
        }
801
0
        else {
802
0
            e = apr_bucket_heap_create(str, nbyte, NULL, b->bucket_alloc);
803
0
            APR_BRIGADE_INSERT_TAIL(b, e);
804
0
            return APR_SUCCESS;
805
0
        }
806
0
    }
807
1.05k
    else if (!buf) {
808
        /* we don't have a buffer, but the data is small enough
809
         * that we don't mind making a new buffer */
810
1.05k
        buf = apr_bucket_alloc(APR_BUCKET_BUFF_SIZE, b->bucket_alloc);
811
1.05k
        e = apr_bucket_heap_create(buf, APR_BUCKET_BUFF_SIZE,
812
1.05k
                                   apr_bucket_free, b->bucket_alloc);
813
1.05k
        APR_BRIGADE_INSERT_TAIL(b, e);
814
1.05k
        e->length = 0;   /* We are writing into the brigade, and
815
                          * allocating more memory than we need.  This
816
                          * ensures that the bucket thinks it is empty just
817
                          * after we create it.  We'll fix the length
818
                          * once we put data in it below.
819
                          */
820
1.05k
    }
821
822
    /* there is a sufficiently big buffer bucket available now */
823
1.05k
    memcpy(buf, str, nbyte);
824
1.05k
    e->length += nbyte;
825
826
1.05k
    return APR_SUCCESS;
827
1.05k
}
828
829
APR_DECLARE(apr_status_t) apr_brigade_writev(apr_bucket_brigade *b,
830
                                             apr_brigade_flush flush,
831
                                             void *ctx,
832
                                             const struct iovec *vec,
833
                                             apr_size_t nvec)
834
0
{
835
0
    apr_bucket *e;
836
0
    apr_size_t total_len;
837
0
    apr_size_t i;
838
0
    char *buf;
839
840
    /* Compute the total length of the data to be written.
841
     */
842
0
    total_len = 0;
843
0
    for (i = 0; i < nvec; i++) {
844
0
       total_len += vec[i].iov_len;
845
0
    }
846
847
    /* If the data to be written is very large, try to convert
848
     * the iovec to transient buckets rather than copying.
849
     */
850
0
    if (total_len > APR_BUCKET_BUFF_SIZE) {
851
0
        if (flush) {
852
0
            for (i = 0; i < nvec; i++) {
853
0
                e = apr_bucket_transient_create(vec[i].iov_base,
854
0
                                                vec[i].iov_len,
855
0
                                                b->bucket_alloc);
856
0
                APR_BRIGADE_INSERT_TAIL(b, e);
857
0
            }
858
0
            return flush(b, ctx);
859
0
        }
860
0
        else {
861
0
            for (i = 0; i < nvec; i++) {
862
0
                e = apr_bucket_heap_create((const char *) vec[i].iov_base,
863
0
                                           vec[i].iov_len, NULL,
864
0
                                           b->bucket_alloc);
865
0
                APR_BRIGADE_INSERT_TAIL(b, e);
866
0
            }
867
0
            return APR_SUCCESS;
868
0
        }
869
0
    }
870
871
0
    i = 0;
872
873
    /* If there is a heap bucket at the end of the brigade
874
     * already, and its refcount is 1, copy into the existing bucket.
875
     */
876
0
    e = APR_BRIGADE_LAST(b);
877
0
    if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e)
878
0
        && ((apr_bucket_heap *)(e->data))->refcount.refcount == 1) {
879
0
        apr_bucket_heap *h = e->data;
880
0
        apr_size_t remaining = h->alloc_len -
881
0
            (e->length + (apr_size_t)e->start);
882
0
        buf = h->base + e->start + e->length;
883
884
0
        if (remaining >= total_len) {
885
            /* Simple case: all the data will fit in the
886
             * existing heap bucket
887
             */
888
0
            for (; i < nvec; i++) {
889
0
                apr_size_t len = vec[i].iov_len;
890
0
                memcpy(buf, (const void *) vec[i].iov_base, len);
891
0
                buf += len;
892
0
            }
893
0
            e->length += total_len;
894
0
            return APR_SUCCESS;
895
0
        }
896
0
        else {
897
            /* More complicated case: not all of the data
898
             * will fit in the existing heap bucket.  The
899
             * total data size is <= APR_BUCKET_BUFF_SIZE,
900
             * so we'll need only one additional bucket.
901
             */
902
0
            const char *start_buf = buf;
903
0
            for (; i < nvec; i++) {
904
0
                apr_size_t len = vec[i].iov_len;
905
0
                if (len > remaining) {
906
0
                    break;
907
0
                }
908
0
                memcpy(buf, (const void *) vec[i].iov_base, len);
909
0
                buf += len;
910
0
                remaining -= len;
911
0
            }
912
0
            e->length += (buf - start_buf);
913
0
            total_len -= (buf - start_buf);
914
915
0
            if (flush) {
916
0
                apr_status_t rv = flush(b, ctx);
917
0
                if (rv != APR_SUCCESS) {
918
0
                    return rv;
919
0
                }
920
0
            }
921
922
            /* Now fall through into the case below to
923
             * allocate another heap bucket and copy the
924
             * rest of the array.  (Note that i is not
925
             * reset to zero here; it holds the index
926
             * of the first vector element to be
927
             * written to the new bucket.)
928
             */
929
0
        }
930
0
    }
931
932
    /* Allocate a new heap bucket, and copy the data into it.
933
     * The checks above ensure that the amount of data to be
934
     * written here is no larger than APR_BUCKET_BUFF_SIZE.
935
     */
936
0
    buf = apr_bucket_alloc(APR_BUCKET_BUFF_SIZE, b->bucket_alloc);
937
0
    e = apr_bucket_heap_create(buf, APR_BUCKET_BUFF_SIZE,
938
0
                               apr_bucket_free, b->bucket_alloc);
939
0
    for (; i < nvec; i++) {
940
0
        apr_size_t len = vec[i].iov_len;
941
0
        memcpy(buf, (const void *) vec[i].iov_base, len);
942
0
        buf += len;
943
0
    }
944
0
    e->length = total_len;
945
0
    APR_BRIGADE_INSERT_TAIL(b, e);
946
947
0
    return APR_SUCCESS;
948
0
}
949
950
APR_DECLARE(apr_status_t) apr_brigade_puts(apr_bucket_brigade *bb,
951
                                           apr_brigade_flush flush, void *ctx,
952
                                           const char *str)
953
0
{
954
0
    return apr_brigade_write(bb, flush, ctx, str, strlen(str));
955
0
}
956
957
APR_DECLARE_NONSTD(apr_status_t) apr_brigade_putstrs(apr_bucket_brigade *b,
958
                                                     apr_brigade_flush flush,
959
                                                     void *ctx, ...)
960
0
{
961
0
    va_list va;
962
0
    apr_status_t rv;
963
964
0
    va_start(va, ctx);
965
0
    rv = apr_brigade_vputstrs(b, flush, ctx, va);
966
0
    va_end(va);
967
0
    return rv;
968
0
}
969
970
APR_DECLARE_NONSTD(apr_status_t) apr_brigade_printf(apr_bucket_brigade *b,
971
                                                    apr_brigade_flush flush,
972
                                                    void *ctx,
973
                                                    const char *fmt, ...)
974
0
{
975
0
    va_list ap;
976
0
    apr_status_t rv;
977
978
0
    va_start(ap, fmt);
979
0
    rv = apr_brigade_vprintf(b, flush, ctx, fmt, ap);
980
0
    va_end(ap);
981
0
    return rv;
982
0
}
983
984
struct brigade_vprintf_data_t {
985
    apr_vformatter_buff_t vbuff;
986
987
    apr_bucket_brigade *b;  /* associated brigade */
988
    apr_brigade_flush *flusher; /* flushing function */
989
    void *ctx;
990
991
    char *cbuff; /* buffer to flush from */
992
};
993
994
static apr_status_t brigade_flush(apr_vformatter_buff_t *buff)
995
0
{
996
    /* callback function passed to ap_vformatter to be
997
     * called when vformatter needs to buff and
998
     * buff.curpos > buff.endpos
999
     */
1000
1001
    /* "downcast," have really passed a brigade_vprintf_data_t* */
1002
0
    struct brigade_vprintf_data_t *vd = (struct brigade_vprintf_data_t*)buff;
1003
0
    apr_status_t res = APR_SUCCESS;
1004
1005
0
    res = apr_brigade_write(vd->b, *vd->flusher, vd->ctx, vd->cbuff,
1006
0
                          APR_BUCKET_BUFF_SIZE);
1007
1008
0
    if(res != APR_SUCCESS) {
1009
0
      return -1;
1010
0
    }
1011
1012
0
    vd->vbuff.curpos = vd->cbuff;
1013
0
    vd->vbuff.endpos = vd->cbuff + APR_BUCKET_BUFF_SIZE;
1014
1015
0
    return res;
1016
0
}
1017
1018
APR_DECLARE(apr_status_t) apr_brigade_vprintf(apr_bucket_brigade *b,
1019
                                              apr_brigade_flush flush,
1020
                                              void *ctx,
1021
                                              const char *fmt, va_list va)
1022
0
{
1023
    /* the cast, in order of appearance */
1024
0
    struct brigade_vprintf_data_t vd;
1025
0
    char buf[APR_BUCKET_BUFF_SIZE];
1026
0
    int written;
1027
1028
0
    vd.vbuff.curpos = buf;
1029
0
    vd.vbuff.endpos = buf + APR_BUCKET_BUFF_SIZE;
1030
0
    vd.b = b;
1031
0
    vd.flusher = &flush;
1032
0
    vd.ctx = ctx;
1033
0
    vd.cbuff = buf;
1034
1035
0
    written = apr_vformatter(brigade_flush, &vd.vbuff, fmt, va);
1036
1037
0
    if (written == -1) {
1038
0
      return -1;
1039
0
    }
1040
1041
    /* write out what remains in the buffer */
1042
0
    return apr_brigade_write(b, flush, ctx, buf, vd.vbuff.curpos - buf);
1043
0
}
1044
1045
/* A "safe" maximum bucket size, 1Gb */
1046
0
#define MAX_BUCKET_SIZE (0x40000000)
1047
1048
APR_DECLARE(apr_bucket *) apr_brigade_insert_file(apr_bucket_brigade *bb,
1049
                                                  apr_file_t *f,
1050
                                                  apr_off_t start,
1051
                                                  apr_off_t length,
1052
                                                  apr_pool_t *p)
1053
0
{
1054
0
    apr_bucket *e;
1055
1056
0
    if (sizeof(apr_off_t) == sizeof(apr_size_t) || length < MAX_BUCKET_SIZE) {
1057
0
        e = apr_bucket_file_create(f, start, (apr_size_t)length, p,
1058
0
                                   bb->bucket_alloc);
1059
0
    }
1060
0
    else {
1061
        /* Several buckets are needed. */
1062
0
        e = apr_bucket_file_create(f, start, MAX_BUCKET_SIZE, p,
1063
0
                                   bb->bucket_alloc);
1064
1065
0
        while (length > MAX_BUCKET_SIZE) {
1066
0
            apr_bucket *ce;
1067
0
            apr_bucket_copy(e, &ce);
1068
0
            APR_BRIGADE_INSERT_TAIL(bb, ce);
1069
0
            e->start += MAX_BUCKET_SIZE;
1070
0
            length -= MAX_BUCKET_SIZE;
1071
0
        }
1072
0
        e->length = (apr_size_t)length; /* Resize just the last bucket */
1073
0
    }
1074
1075
0
    APR_BRIGADE_INSERT_TAIL(bb, e);
1076
0
    return e;
1077
0
}