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