Coverage Report

Created: 2025-04-11 06:08

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