1251876Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251876Speter * contributor license agreements.  See the NOTICE file distributed with
3251876Speter * this work for additional information regarding copyright ownership.
4251876Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251876Speter * (the "License"); you may not use this file except in compliance with
6251876Speter * the License.  You may obtain a copy of the License at
7251876Speter *
8251876Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251876Speter *
10251876Speter * Unless required by applicable law or agreed to in writing, software
11251876Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251876Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251876Speter * See the License for the specific language governing permissions and
14251876Speter * limitations under the License.
15251876Speter */
16251876Speter
17251876Speter#include "apr.h"
18251876Speter#include "apr_lib.h"
19251876Speter#include "apr_strings.h"
20251876Speter#include "apr_pools.h"
21251876Speter#include "apr_tables.h"
22251876Speter#include "apr_buckets.h"
23251876Speter#include "apr_errno.h"
24251876Speter#define APR_WANT_MEMFUNC
25251876Speter#define APR_WANT_STRFUNC
26251876Speter#include "apr_want.h"
27251876Speter
28251876Speter#if APR_HAVE_SYS_UIO_H
29251876Speter#include <sys/uio.h>
30251876Speter#endif
31251876Speter
32251876Speterstatic apr_status_t brigade_cleanup(void *data)
33251876Speter{
34251876Speter    return apr_brigade_cleanup(data);
35251876Speter}
36251876Speter
37251876SpeterAPU_DECLARE(apr_status_t) apr_brigade_cleanup(void *data)
38251876Speter{
39251876Speter    apr_bucket_brigade *b = data;
40251876Speter    apr_bucket *e;
41251876Speter
42251876Speter    while (!APR_BRIGADE_EMPTY(b)) {
43251876Speter        e = APR_BRIGADE_FIRST(b);
44251876Speter        apr_bucket_delete(e);
45251876Speter    }
46251876Speter    /* We don't need to free(bb) because it's allocated from a pool. */
47251876Speter    return APR_SUCCESS;
48251876Speter}
49251876Speter
50251876SpeterAPU_DECLARE(apr_status_t) apr_brigade_destroy(apr_bucket_brigade *b)
51251876Speter{
52251876Speter    apr_pool_cleanup_kill(b->p, b, brigade_cleanup);
53251876Speter    return apr_brigade_cleanup(b);
54251876Speter}
55251876Speter
56251876SpeterAPU_DECLARE(apr_bucket_brigade *) apr_brigade_create(apr_pool_t *p,
57251876Speter                                                     apr_bucket_alloc_t *list)
58251876Speter{
59251876Speter    apr_bucket_brigade *b;
60251876Speter
61251876Speter    b = apr_palloc(p, sizeof(*b));
62251876Speter    b->p = p;
63251876Speter    b->bucket_alloc = list;
64251876Speter
65251876Speter    APR_RING_INIT(&b->list, apr_bucket, link);
66251876Speter
67251876Speter    apr_pool_cleanup_register(b->p, b, brigade_cleanup, apr_pool_cleanup_null);
68251876Speter    return b;
69251876Speter}
70251876Speter
71251876SpeterAPU_DECLARE(apr_bucket_brigade *) apr_brigade_split_ex(apr_bucket_brigade *b,
72251876Speter                                                       apr_bucket *e,
73251876Speter                                                       apr_bucket_brigade *a)
74251876Speter{
75251876Speter    apr_bucket *f;
76251876Speter
77251876Speter    if (!a) {
78251876Speter        a = apr_brigade_create(b->p, b->bucket_alloc);
79251876Speter    }
80251876Speter    else if (!APR_BRIGADE_EMPTY(a)) {
81251876Speter        apr_brigade_cleanup(a);
82251876Speter    }
83251876Speter    /* Return an empty brigade if there is nothing left in
84251876Speter     * the first brigade to split off
85251876Speter     */
86251876Speter    if (e != APR_BRIGADE_SENTINEL(b)) {
87251876Speter        f = APR_RING_LAST(&b->list);
88251876Speter        APR_RING_UNSPLICE(e, f, link);
89251876Speter        APR_RING_SPLICE_HEAD(&a->list, e, f, apr_bucket, link);
90251876Speter    }
91251876Speter
92251876Speter    APR_BRIGADE_CHECK_CONSISTENCY(a);
93251876Speter    APR_BRIGADE_CHECK_CONSISTENCY(b);
94251876Speter
95251876Speter    return a;
96251876Speter}
97251876Speter
98251876SpeterAPU_DECLARE(apr_bucket_brigade *) apr_brigade_split(apr_bucket_brigade *b,
99251876Speter                                                    apr_bucket *e)
100251876Speter{
101251876Speter    return apr_brigade_split_ex(b, e, NULL);
102251876Speter}
103251876Speter
104251876SpeterAPU_DECLARE(apr_status_t) apr_brigade_partition(apr_bucket_brigade *b,
105251876Speter                                                apr_off_t point,
106251876Speter                                                apr_bucket **after_point)
107251876Speter{
108251876Speter    apr_bucket *e;
109251876Speter    const char *s;
110251876Speter    apr_size_t len;
111251876Speter    apr_uint64_t point64;
112251876Speter    apr_status_t rv;
113251876Speter
114251876Speter    if (point < 0) {
115251876Speter        /* this could cause weird (not necessarily SEGV) things to happen */
116251876Speter        return APR_EINVAL;
117251876Speter    }
118251876Speter    if (point == 0) {
119251876Speter        *after_point = APR_BRIGADE_FIRST(b);
120251876Speter        return APR_SUCCESS;
121251876Speter    }
122251876Speter
123251876Speter    /*
124251876Speter     * Try to reduce the following casting mess: We know that point will be
125251876Speter     * larger equal 0 now and forever and thus that point (apr_off_t) and
126251876Speter     * apr_size_t will fit into apr_uint64_t in any case.
127251876Speter     */
128251876Speter    point64 = (apr_uint64_t)point;
129251876Speter
130251876Speter    APR_BRIGADE_CHECK_CONSISTENCY(b);
131251876Speter
132251876Speter    for (e = APR_BRIGADE_FIRST(b);
133251876Speter         e != APR_BRIGADE_SENTINEL(b);
134251876Speter         e = APR_BUCKET_NEXT(e))
135251876Speter    {
136251876Speter        /* For an unknown length bucket, while 'point64' is beyond the possible
137251876Speter         * size contained in apr_size_t, read and continue...
138251876Speter         */
139251876Speter        if ((e->length == (apr_size_t)(-1))
140251876Speter            && (point64 > (apr_uint64_t)APR_SIZE_MAX)) {
141251876Speter            /* point64 is too far out to simply split this bucket,
142251876Speter             * we must fix this bucket's size and keep going... */
143251876Speter            rv = apr_bucket_read(e, &s, &len, APR_BLOCK_READ);
144251876Speter            if (rv != APR_SUCCESS) {
145251876Speter                *after_point = e;
146251876Speter                return rv;
147251876Speter            }
148251876Speter        }
149251876Speter        else if ((point64 < (apr_uint64_t)e->length)
150251876Speter                 || (e->length == (apr_size_t)(-1))) {
151251876Speter            /* We already consumed buckets where point64 is beyond
152251876Speter             * our interest ( point64 > APR_SIZE_MAX ), above.
153251876Speter             * Here point falls between 0 and APR_SIZE_MAX
154251876Speter             * and is within this bucket, or this bucket's len
155251876Speter             * is undefined, so now we are ready to split it.
156251876Speter             * First try to split the bucket natively... */
157251876Speter            if ((rv = apr_bucket_split(e, (apr_size_t)point64))
158251876Speter                    != APR_ENOTIMPL) {
159251876Speter                *after_point = APR_BUCKET_NEXT(e);
160251876Speter                return rv;
161251876Speter            }
162251876Speter
163251876Speter            /* if the bucket cannot be split, we must read from it,
164251876Speter             * changing its type to one that can be split */
165251876Speter            rv = apr_bucket_read(e, &s, &len, APR_BLOCK_READ);
166251876Speter            if (rv != APR_SUCCESS) {
167251876Speter                *after_point = e;
168251876Speter                return rv;
169251876Speter            }
170251876Speter
171251876Speter            /* this assumes that len == e->length, which is okay because e
172251876Speter             * might have been morphed by the apr_bucket_read() above, but
173251876Speter             * if it was, the length would have been adjusted appropriately */
174251876Speter            if (point64 < (apr_uint64_t)e->length) {
175251876Speter                rv = apr_bucket_split(e, (apr_size_t)point64);
176251876Speter                *after_point = APR_BUCKET_NEXT(e);
177251876Speter                return rv;
178251876Speter            }
179251876Speter        }
180251876Speter        if (point64 == (apr_uint64_t)e->length) {
181251876Speter            *after_point = APR_BUCKET_NEXT(e);
182251876Speter            return APR_SUCCESS;
183251876Speter        }
184251876Speter        point64 -= (apr_uint64_t)e->length;
185251876Speter    }
186251876Speter    *after_point = APR_BRIGADE_SENTINEL(b);
187251876Speter    return APR_INCOMPLETE;
188251876Speter}
189251876Speter
190251876SpeterAPU_DECLARE(apr_status_t) apr_brigade_length(apr_bucket_brigade *bb,
191251876Speter                                             int read_all, apr_off_t *length)
192251876Speter{
193251876Speter    apr_off_t total = 0;
194251876Speter    apr_bucket *bkt;
195251876Speter    apr_status_t status = APR_SUCCESS;
196251876Speter
197251876Speter    for (bkt = APR_BRIGADE_FIRST(bb);
198251876Speter         bkt != APR_BRIGADE_SENTINEL(bb);
199251876Speter         bkt = APR_BUCKET_NEXT(bkt))
200251876Speter    {
201251876Speter        if (bkt->length == (apr_size_t)(-1)) {
202251876Speter            const char *ignore;
203251876Speter            apr_size_t len;
204251876Speter
205251876Speter            if (!read_all) {
206251876Speter                total = -1;
207251876Speter                break;
208251876Speter            }
209251876Speter
210251876Speter            if ((status = apr_bucket_read(bkt, &ignore, &len,
211251876Speter                                          APR_BLOCK_READ)) != APR_SUCCESS) {
212251876Speter                break;
213251876Speter            }
214251876Speter        }
215251876Speter
216251876Speter        total += bkt->length;
217251876Speter    }
218251876Speter
219251876Speter    *length = total;
220251876Speter    return status;
221251876Speter}
222251876Speter
223251876SpeterAPU_DECLARE(apr_status_t) apr_brigade_flatten(apr_bucket_brigade *bb,
224251876Speter                                              char *c, apr_size_t *len)
225251876Speter{
226251876Speter    apr_size_t actual = 0;
227251876Speter    apr_bucket *b;
228251876Speter
229251876Speter    for (b = APR_BRIGADE_FIRST(bb);
230251876Speter         b != APR_BRIGADE_SENTINEL(bb);
231251876Speter         b = APR_BUCKET_NEXT(b))
232251876Speter    {
233251876Speter        const char *str;
234251876Speter        apr_size_t str_len;
235251876Speter        apr_status_t status;
236251876Speter
237251876Speter        status = apr_bucket_read(b, &str, &str_len, APR_BLOCK_READ);
238251876Speter        if (status != APR_SUCCESS) {
239251876Speter            return status;
240251876Speter        }
241251876Speter
242251876Speter        /* If we would overflow. */
243251876Speter        if (str_len + actual > *len) {
244251876Speter            str_len = *len - actual;
245251876Speter        }
246251876Speter
247251876Speter        /* XXX: It appears that overflow of the final bucket
248251876Speter         * is DISCARDED without any warning to the caller.
249251876Speter         *
250251876Speter         * No, we only copy the data up to their requested size.  -- jre
251251876Speter         */
252251876Speter        memcpy(c, str, str_len);
253251876Speter
254251876Speter        c += str_len;
255251876Speter        actual += str_len;
256251876Speter
257251876Speter        /* This could probably be actual == *len, but be safe from stray
258251876Speter         * photons. */
259251876Speter        if (actual >= *len) {
260251876Speter            break;
261251876Speter        }
262251876Speter    }
263251876Speter
264251876Speter    *len = actual;
265251876Speter    return APR_SUCCESS;
266251876Speter}
267251876Speter
268251876SpeterAPU_DECLARE(apr_status_t) apr_brigade_pflatten(apr_bucket_brigade *bb,
269251876Speter                                               char **c,
270251876Speter                                               apr_size_t *len,
271251876Speter                                               apr_pool_t *pool)
272251876Speter{
273251876Speter    apr_off_t actual;
274251876Speter    apr_size_t total;
275251876Speter    apr_status_t rv;
276251876Speter
277251876Speter    apr_brigade_length(bb, 1, &actual);
278251876Speter
279251876Speter    /* XXX: This is dangerous beyond belief.  At least in the
280251876Speter     * apr_brigade_flatten case, the user explicitly stated their
281251876Speter     * buffer length - so we don't up and palloc 4GB for a single
282251876Speter     * file bucket.  This API must grow a useful max boundry,
283251876Speter     * either compiled-in or preset via the *len value.
284251876Speter     *
285251876Speter     * Shouldn't both fn's grow an additional return value for
286251876Speter     * the case that the brigade couldn't be flattened into the
287251876Speter     * provided or allocated buffer (such as APR_EMOREDATA?)
288251876Speter     * Not a failure, simply an advisory result.
289251876Speter     */
290251876Speter    total = (apr_size_t)actual;
291251876Speter
292251876Speter    *c = apr_palloc(pool, total);
293251876Speter
294251876Speter    rv = apr_brigade_flatten(bb, *c, &total);
295251876Speter
296251876Speter    if (rv != APR_SUCCESS) {
297251876Speter        return rv;
298251876Speter    }
299251876Speter
300251876Speter    *len = total;
301251876Speter    return APR_SUCCESS;
302251876Speter}
303251876Speter
304251876SpeterAPU_DECLARE(apr_status_t) apr_brigade_split_line(apr_bucket_brigade *bbOut,
305251876Speter                                                 apr_bucket_brigade *bbIn,
306251876Speter                                                 apr_read_type_e block,
307251876Speter                                                 apr_off_t maxbytes)
308251876Speter{
309251876Speter    apr_off_t readbytes = 0;
310251876Speter
311251876Speter    while (!APR_BRIGADE_EMPTY(bbIn)) {
312251876Speter        const char *pos;
313251876Speter        const char *str;
314251876Speter        apr_size_t len;
315251876Speter        apr_status_t rv;
316251876Speter        apr_bucket *e;
317251876Speter
318251876Speter        e = APR_BRIGADE_FIRST(bbIn);
319251876Speter        rv = apr_bucket_read(e, &str, &len, block);
320251876Speter
321251876Speter        if (rv != APR_SUCCESS) {
322251876Speter            return rv;
323251876Speter        }
324251876Speter
325251876Speter        pos = memchr(str, APR_ASCII_LF, len);
326251876Speter        /* We found a match. */
327251876Speter        if (pos != NULL) {
328251876Speter            apr_bucket_split(e, pos - str + 1);
329251876Speter            APR_BUCKET_REMOVE(e);
330251876Speter            APR_BRIGADE_INSERT_TAIL(bbOut, e);
331251876Speter            return APR_SUCCESS;
332251876Speter        }
333251876Speter        APR_BUCKET_REMOVE(e);
334251876Speter        if (APR_BUCKET_IS_METADATA(e) || len > APR_BUCKET_BUFF_SIZE/4) {
335251876Speter            APR_BRIGADE_INSERT_TAIL(bbOut, e);
336251876Speter        }
337251876Speter        else {
338251876Speter            if (len > 0) {
339251876Speter                rv = apr_brigade_write(bbOut, NULL, NULL, str, len);
340251876Speter                if (rv != APR_SUCCESS) {
341251876Speter                    return rv;
342251876Speter                }
343251876Speter            }
344251876Speter            apr_bucket_destroy(e);
345251876Speter        }
346251876Speter        readbytes += len;
347251876Speter        /* We didn't find an APR_ASCII_LF within the maximum line length. */
348251876Speter        if (readbytes >= maxbytes) {
349251876Speter            break;
350251876Speter        }
351251876Speter    }
352251876Speter
353251876Speter    return APR_SUCCESS;
354251876Speter}
355251876Speter
356251876Speter
357251876SpeterAPU_DECLARE(apr_status_t) apr_brigade_to_iovec(apr_bucket_brigade *b,
358251876Speter                                               struct iovec *vec, int *nvec)
359251876Speter{
360251876Speter    int left = *nvec;
361251876Speter    apr_bucket *e;
362251876Speter    struct iovec *orig;
363251876Speter    apr_size_t iov_len;
364251876Speter    const char *iov_base;
365251876Speter    apr_status_t rv;
366251876Speter
367251876Speter    orig = vec;
368251876Speter
369251876Speter    for (e = APR_BRIGADE_FIRST(b);
370251876Speter         e != APR_BRIGADE_SENTINEL(b);
371251876Speter         e = APR_BUCKET_NEXT(e))
372251876Speter    {
373251876Speter        if (left-- == 0)
374251876Speter            break;
375251876Speter
376251876Speter        rv = apr_bucket_read(e, &iov_base, &iov_len, APR_NONBLOCK_READ);
377251876Speter        if (rv != APR_SUCCESS)
378251876Speter            return rv;
379251876Speter        /* Set indirectly since types differ: */
380251876Speter        vec->iov_len = iov_len;
381251876Speter        vec->iov_base = (void *)iov_base;
382251876Speter        ++vec;
383251876Speter    }
384251876Speter
385251876Speter    *nvec = (int)(vec - orig);
386251876Speter    return APR_SUCCESS;
387251876Speter}
388251876Speter
389251876SpeterAPU_DECLARE(apr_status_t) apr_brigade_vputstrs(apr_bucket_brigade *b,
390251876Speter                                               apr_brigade_flush flush,
391251876Speter                                               void *ctx,
392251876Speter                                               va_list va)
393251876Speter{
394253734Speter#define MAX_VECS    8
395253734Speter    struct iovec vec[MAX_VECS];
396253734Speter    apr_size_t i = 0;
397253734Speter
398251876Speter    for (;;) {
399253734Speter        char *str = va_arg(va, char *);
400251876Speter        apr_status_t rv;
401251876Speter
402251876Speter        if (str == NULL)
403251876Speter            break;
404251876Speter
405253734Speter        vec[i].iov_base = str;
406253734Speter        vec[i].iov_len = strlen(str);
407253734Speter        i++;
408253734Speter
409253734Speter        if (i == MAX_VECS) {
410253734Speter            rv = apr_brigade_writev(b, flush, ctx, vec, i);
411253734Speter            if (rv != APR_SUCCESS)
412253734Speter                return rv;
413253734Speter            i = 0;
414253734Speter        }
415251876Speter    }
416253734Speter    if (i != 0)
417253734Speter       return apr_brigade_writev(b, flush, ctx, vec, i);
418251876Speter
419251876Speter    return APR_SUCCESS;
420251876Speter}
421251876Speter
422251876SpeterAPU_DECLARE(apr_status_t) apr_brigade_putc(apr_bucket_brigade *b,
423251876Speter                                           apr_brigade_flush flush, void *ctx,
424251876Speter                                           const char c)
425251876Speter{
426251876Speter    return apr_brigade_write(b, flush, ctx, &c, 1);
427251876Speter}
428251876Speter
429251876SpeterAPU_DECLARE(apr_status_t) apr_brigade_write(apr_bucket_brigade *b,
430251876Speter                                            apr_brigade_flush flush,
431251876Speter                                            void *ctx,
432251876Speter                                            const char *str, apr_size_t nbyte)
433251876Speter{
434251876Speter    apr_bucket *e = APR_BRIGADE_LAST(b);
435251876Speter    apr_size_t remaining = APR_BUCKET_BUFF_SIZE;
436251876Speter    char *buf = NULL;
437251876Speter
438253734Speter    /*
439253734Speter     * If the last bucket is a heap bucket and its buffer is not shared with
440253734Speter     * another bucket, we may write into that bucket.
441253734Speter     */
442253734Speter    if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e)
443253734Speter        && ((apr_bucket_heap *)(e->data))->refcount.refcount == 1) {
444251876Speter        apr_bucket_heap *h = e->data;
445251876Speter
446251876Speter        /* HEAP bucket start offsets are always in-memory, safe to cast */
447251876Speter        remaining = h->alloc_len - (e->length + (apr_size_t)e->start);
448251876Speter        buf = h->base + e->start + e->length;
449251876Speter    }
450251876Speter
451251876Speter    if (nbyte > remaining) {
452251876Speter        /* either a buffer bucket exists but is full,
453251876Speter         * or no buffer bucket exists and the data is too big
454251876Speter         * to buffer.  In either case, we should flush.  */
455251876Speter        if (flush) {
456251876Speter            e = apr_bucket_transient_create(str, nbyte, b->bucket_alloc);
457251876Speter            APR_BRIGADE_INSERT_TAIL(b, e);
458251876Speter            return flush(b, ctx);
459251876Speter        }
460251876Speter        else {
461251876Speter            e = apr_bucket_heap_create(str, nbyte, NULL, b->bucket_alloc);
462251876Speter            APR_BRIGADE_INSERT_TAIL(b, e);
463251876Speter            return APR_SUCCESS;
464251876Speter        }
465251876Speter    }
466251876Speter    else if (!buf) {
467251876Speter        /* we don't have a buffer, but the data is small enough
468251876Speter         * that we don't mind making a new buffer */
469251876Speter        buf = apr_bucket_alloc(APR_BUCKET_BUFF_SIZE, b->bucket_alloc);
470251876Speter        e = apr_bucket_heap_create(buf, APR_BUCKET_BUFF_SIZE,
471251876Speter                                   apr_bucket_free, b->bucket_alloc);
472251876Speter        APR_BRIGADE_INSERT_TAIL(b, e);
473251876Speter        e->length = 0;   /* We are writing into the brigade, and
474251876Speter                          * allocating more memory than we need.  This
475251876Speter                          * ensures that the bucket thinks it is empty just
476251876Speter                          * after we create it.  We'll fix the length
477251876Speter                          * once we put data in it below.
478251876Speter                          */
479251876Speter    }
480251876Speter
481251876Speter    /* there is a sufficiently big buffer bucket available now */
482251876Speter    memcpy(buf, str, nbyte);
483251876Speter    e->length += nbyte;
484251876Speter
485251876Speter    return APR_SUCCESS;
486251876Speter}
487251876Speter
488251876SpeterAPU_DECLARE(apr_status_t) apr_brigade_writev(apr_bucket_brigade *b,
489251876Speter                                             apr_brigade_flush flush,
490251876Speter                                             void *ctx,
491251876Speter                                             const struct iovec *vec,
492251876Speter                                             apr_size_t nvec)
493251876Speter{
494251876Speter    apr_bucket *e;
495251876Speter    apr_size_t total_len;
496251876Speter    apr_size_t i;
497251876Speter    char *buf;
498251876Speter
499251876Speter    /* Compute the total length of the data to be written.
500251876Speter     */
501251876Speter    total_len = 0;
502251876Speter    for (i = 0; i < nvec; i++) {
503251876Speter       total_len += vec[i].iov_len;
504251876Speter    }
505251876Speter
506251876Speter    /* If the data to be written is very large, try to convert
507251876Speter     * the iovec to transient buckets rather than copying.
508251876Speter     */
509251876Speter    if (total_len > APR_BUCKET_BUFF_SIZE) {
510251876Speter        if (flush) {
511251876Speter            for (i = 0; i < nvec; i++) {
512251876Speter                e = apr_bucket_transient_create(vec[i].iov_base,
513251876Speter                                                vec[i].iov_len,
514251876Speter                                                b->bucket_alloc);
515251876Speter                APR_BRIGADE_INSERT_TAIL(b, e);
516251876Speter            }
517251876Speter            return flush(b, ctx);
518251876Speter        }
519251876Speter        else {
520251876Speter            for (i = 0; i < nvec; i++) {
521251876Speter                e = apr_bucket_heap_create((const char *) vec[i].iov_base,
522251876Speter                                           vec[i].iov_len, NULL,
523251876Speter                                           b->bucket_alloc);
524251876Speter                APR_BRIGADE_INSERT_TAIL(b, e);
525251876Speter            }
526251876Speter            return APR_SUCCESS;
527251876Speter        }
528251876Speter    }
529251876Speter
530251876Speter    i = 0;
531251876Speter
532251876Speter    /* If there is a heap bucket at the end of the brigade
533253734Speter     * already, and its refcount is 1, copy into the existing bucket.
534251876Speter     */
535251876Speter    e = APR_BRIGADE_LAST(b);
536253734Speter    if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e)
537253734Speter        && ((apr_bucket_heap *)(e->data))->refcount.refcount == 1) {
538251876Speter        apr_bucket_heap *h = e->data;
539251876Speter        apr_size_t remaining = h->alloc_len -
540251876Speter            (e->length + (apr_size_t)e->start);
541251876Speter        buf = h->base + e->start + e->length;
542251876Speter
543251876Speter        if (remaining >= total_len) {
544251876Speter            /* Simple case: all the data will fit in the
545251876Speter             * existing heap bucket
546251876Speter             */
547251876Speter            for (; i < nvec; i++) {
548251876Speter                apr_size_t len = vec[i].iov_len;
549251876Speter                memcpy(buf, (const void *) vec[i].iov_base, len);
550251876Speter                buf += len;
551251876Speter            }
552251876Speter            e->length += total_len;
553251876Speter            return APR_SUCCESS;
554251876Speter        }
555251876Speter        else {
556251876Speter            /* More complicated case: not all of the data
557251876Speter             * will fit in the existing heap bucket.  The
558251876Speter             * total data size is <= APR_BUCKET_BUFF_SIZE,
559251876Speter             * so we'll need only one additional bucket.
560251876Speter             */
561251876Speter            const char *start_buf = buf;
562251876Speter            for (; i < nvec; i++) {
563251876Speter                apr_size_t len = vec[i].iov_len;
564251876Speter                if (len > remaining) {
565251876Speter                    break;
566251876Speter                }
567251876Speter                memcpy(buf, (const void *) vec[i].iov_base, len);
568251876Speter                buf += len;
569251876Speter                remaining -= len;
570251876Speter            }
571251876Speter            e->length += (buf - start_buf);
572251876Speter            total_len -= (buf - start_buf);
573251876Speter
574251876Speter            if (flush) {
575251876Speter                apr_status_t rv = flush(b, ctx);
576251876Speter                if (rv != APR_SUCCESS) {
577251876Speter                    return rv;
578251876Speter                }
579251876Speter            }
580251876Speter
581251876Speter            /* Now fall through into the case below to
582251876Speter             * allocate another heap bucket and copy the
583251876Speter             * rest of the array.  (Note that i is not
584251876Speter             * reset to zero here; it holds the index
585251876Speter             * of the first vector element to be
586251876Speter             * written to the new bucket.)
587251876Speter             */
588251876Speter        }
589251876Speter    }
590251876Speter
591251876Speter    /* Allocate a new heap bucket, and copy the data into it.
592251876Speter     * The checks above ensure that the amount of data to be
593251876Speter     * written here is no larger than APR_BUCKET_BUFF_SIZE.
594251876Speter     */
595251876Speter    buf = apr_bucket_alloc(APR_BUCKET_BUFF_SIZE, b->bucket_alloc);
596251876Speter    e = apr_bucket_heap_create(buf, APR_BUCKET_BUFF_SIZE,
597251876Speter                               apr_bucket_free, b->bucket_alloc);
598251876Speter    for (; i < nvec; i++) {
599251876Speter        apr_size_t len = vec[i].iov_len;
600251876Speter        memcpy(buf, (const void *) vec[i].iov_base, len);
601251876Speter        buf += len;
602251876Speter    }
603251876Speter    e->length = total_len;
604251876Speter    APR_BRIGADE_INSERT_TAIL(b, e);
605251876Speter
606251876Speter    return APR_SUCCESS;
607251876Speter}
608251876Speter
609251876SpeterAPU_DECLARE(apr_status_t) apr_brigade_puts(apr_bucket_brigade *bb,
610251876Speter                                           apr_brigade_flush flush, void *ctx,
611251876Speter                                           const char *str)
612251876Speter{
613253734Speter    return apr_brigade_write(bb, flush, ctx, str, strlen(str));
614251876Speter}
615251876Speter
616251876SpeterAPU_DECLARE_NONSTD(apr_status_t) apr_brigade_putstrs(apr_bucket_brigade *b,
617251876Speter                                                     apr_brigade_flush flush,
618251876Speter                                                     void *ctx, ...)
619251876Speter{
620251876Speter    va_list va;
621251876Speter    apr_status_t rv;
622251876Speter
623251876Speter    va_start(va, ctx);
624251876Speter    rv = apr_brigade_vputstrs(b, flush, ctx, va);
625251876Speter    va_end(va);
626251876Speter    return rv;
627251876Speter}
628251876Speter
629251876SpeterAPU_DECLARE_NONSTD(apr_status_t) apr_brigade_printf(apr_bucket_brigade *b,
630251876Speter                                                    apr_brigade_flush flush,
631251876Speter                                                    void *ctx,
632251876Speter                                                    const char *fmt, ...)
633251876Speter{
634251876Speter    va_list ap;
635251876Speter    apr_status_t rv;
636251876Speter
637251876Speter    va_start(ap, fmt);
638251876Speter    rv = apr_brigade_vprintf(b, flush, ctx, fmt, ap);
639251876Speter    va_end(ap);
640251876Speter    return rv;
641251876Speter}
642251876Speter
643251876Speterstruct brigade_vprintf_data_t {
644251876Speter    apr_vformatter_buff_t vbuff;
645251876Speter
646251876Speter    apr_bucket_brigade *b;  /* associated brigade */
647251876Speter    apr_brigade_flush *flusher; /* flushing function */
648251876Speter    void *ctx;
649251876Speter
650251876Speter    char *cbuff; /* buffer to flush from */
651251876Speter};
652251876Speter
653251876Speterstatic apr_status_t brigade_flush(apr_vformatter_buff_t *buff)
654251876Speter{
655251876Speter    /* callback function passed to ap_vformatter to be
656251876Speter     * called when vformatter needs to buff and
657251876Speter     * buff.curpos > buff.endpos
658251876Speter     */
659251876Speter
660251876Speter    /* "downcast," have really passed a brigade_vprintf_data_t* */
661251876Speter    struct brigade_vprintf_data_t *vd = (struct brigade_vprintf_data_t*)buff;
662251876Speter    apr_status_t res = APR_SUCCESS;
663251876Speter
664251876Speter    res = apr_brigade_write(vd->b, *vd->flusher, vd->ctx, vd->cbuff,
665251876Speter                          APR_BUCKET_BUFF_SIZE);
666251876Speter
667251876Speter    if(res != APR_SUCCESS) {
668251876Speter      return -1;
669251876Speter    }
670251876Speter
671251876Speter    vd->vbuff.curpos = vd->cbuff;
672251876Speter    vd->vbuff.endpos = vd->cbuff + APR_BUCKET_BUFF_SIZE;
673251876Speter
674251876Speter    return res;
675251876Speter}
676251876Speter
677251876SpeterAPU_DECLARE(apr_status_t) apr_brigade_vprintf(apr_bucket_brigade *b,
678251876Speter                                              apr_brigade_flush flush,
679251876Speter                                              void *ctx,
680251876Speter                                              const char *fmt, va_list va)
681251876Speter{
682251876Speter    /* the cast, in order of appearance */
683251876Speter    struct brigade_vprintf_data_t vd;
684251876Speter    char buf[APR_BUCKET_BUFF_SIZE];
685251876Speter    int written;
686251876Speter
687251876Speter    vd.vbuff.curpos = buf;
688251876Speter    vd.vbuff.endpos = buf + APR_BUCKET_BUFF_SIZE;
689251876Speter    vd.b = b;
690251876Speter    vd.flusher = &flush;
691251876Speter    vd.ctx = ctx;
692251876Speter    vd.cbuff = buf;
693251876Speter
694251876Speter    written = apr_vformatter(brigade_flush, &vd.vbuff, fmt, va);
695251876Speter
696251876Speter    if (written == -1) {
697251876Speter      return -1;
698251876Speter    }
699251876Speter
700251876Speter    /* write out what remains in the buffer */
701251876Speter    return apr_brigade_write(b, flush, ctx, buf, vd.vbuff.curpos - buf);
702251876Speter}
703251876Speter
704251876Speter/* A "safe" maximum bucket size, 1Gb */
705251876Speter#define MAX_BUCKET_SIZE (0x40000000)
706251876Speter
707251876SpeterAPU_DECLARE(apr_bucket *) apr_brigade_insert_file(apr_bucket_brigade *bb,
708251876Speter                                                  apr_file_t *f,
709251876Speter                                                  apr_off_t start,
710251876Speter                                                  apr_off_t length,
711251876Speter                                                  apr_pool_t *p)
712251876Speter{
713251876Speter    apr_bucket *e;
714251876Speter
715251876Speter    if (sizeof(apr_off_t) == sizeof(apr_size_t) || length < MAX_BUCKET_SIZE) {
716251876Speter        e = apr_bucket_file_create(f, start, (apr_size_t)length, p,
717251876Speter                                   bb->bucket_alloc);
718251876Speter    }
719251876Speter    else {
720251876Speter        /* Several buckets are needed. */
721251876Speter        e = apr_bucket_file_create(f, start, MAX_BUCKET_SIZE, p,
722251876Speter                                   bb->bucket_alloc);
723251876Speter
724251876Speter        while (length > MAX_BUCKET_SIZE) {
725251876Speter            apr_bucket *ce;
726251876Speter            apr_bucket_copy(e, &ce);
727251876Speter            APR_BRIGADE_INSERT_TAIL(bb, ce);
728251876Speter            e->start += MAX_BUCKET_SIZE;
729251876Speter            length -= MAX_BUCKET_SIZE;
730251876Speter        }
731251876Speter        e->length = (apr_size_t)length; /* Resize just the last bucket */
732251876Speter    }
733251876Speter
734251876Speter    APR_BRIGADE_INSERT_TAIL(bb, e);
735251876Speter    return e;
736251876Speter}
737