2 ** Licensed to the Apache Software Foundation (ASF) under one or more
3 ** contributor license agreements. See the NOTICE file distributed with
4 ** this work for additional information regarding copyright ownership.
5 ** The ASF licenses this file to You under the Apache License, Version 2.0
6 ** (the "License"); you may not use this file except in compliance with
7 ** the License. You may obtain a copy of the License at
9 ** http://www.apache.org/licenses/LICENSE-2.0
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
18 #include "apreq_util.h"
19 #include "apreq_error.h"
21 #include "apr_strings.h"
27 #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
28 #define MAX(a,b) ( (a) > (b) ? (a) : (b) )
30 /* used for specifying file sizes */
32 APREQ_DECLARE(apr_int64_t) apreq_atoi64f(const char *s)
39 n = apr_strtoi64(s, &p, 0);
43 while (apr_isspace(*p))
47 case 'G': /* fall thru */
48 case 'g': return n * 1024*1024*1024;
49 case 'M': /* fall thru */
50 case 'm': return n * 1024*1024;
51 case 'K': /* fall thru */
52 case 'k': return n * 1024;
59 /* converts date offsets (e.g. "+3M") to seconds */
61 APREQ_DECLARE(apr_int64_t) apreq_atoi64t(const char *s)
67 n = apr_strtoi64(s, &p, 0); /* XXX: what about overflow? */
71 while (apr_isspace(*p))
75 case 'Y': /* fall thru */
76 case 'y': return n * 60*60*24*365;
77 case 'M': return n * 60*60*24*30;
78 case 'D': /* fall thru */
79 case 'd': return n * 60*60*24;
80 case 'H': /* fall thru */
81 case 'h': return n * 60*60;
82 case 'm': return n * 60;
83 case 's': /* fall thru */
87 /* should never get here */
92 APREQ_DECLARE(apr_ssize_t ) apreq_index(const char* hay, apr_size_t hlen,
93 const char* ndl, apr_size_t nlen,
94 const apreq_match_t type)
96 apr_size_t len = hlen;
97 const char *end = hay + hlen;
98 const char *begin = hay;
100 while ( (hay = memchr(hay, ndl[0], len)) ) {
103 /* done if matches up to capacity of buffer */
104 if ( memcmp(hay, ndl, MIN(nlen, len)) == 0 ) {
105 if (type == APREQ_MATCH_FULL && len < nlen)
106 hay = NULL; /* insufficient room for match */
113 return hay ? hay - begin : -1;
117 static const char c2x_table[] = "0123456789ABCDEF";
118 static APR_INLINE unsigned char hex2_to_char(const char *what)
120 register unsigned char digit;
122 #if !APR_CHARSET_EBCDIC
123 digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
125 digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
126 #else /*APR_CHARSET_EBCDIC*/
133 digit = apr_xlate_conv_byte(ap_hdrs_from_ascii, 0xFF & strtol(xstr, NULL, 16));
134 #endif /*APR_CHARSET_EBCDIC*/
139 /* Unicode notes: "bmp" refers to the 16-bit
140 * Unicode Basic Multilingual Plane. Here we're
141 * restricting our unicode internals to 16-bit
142 * codepoints, to keep the code as simple as possible.
143 * This should be sufficient for apreq itself, since
144 * we really only need to validate RFC3986-encoded utf8.
147 /* Converts Windows cp1252 to Unicode. */
150 apr_uint16_t cp1252_to_bmp(unsigned char c)
152 /* We only need to deal with iso-8859-1 control chars
153 * in the 0x80 - 0x9F range.
155 if ((c & 0xE0) != 0x80)
159 case 0x80: return 0x20AC;
160 case 0x82: return 0x201A;
161 case 0x83: return 0x192;
162 case 0x84: return 0x201E;
163 case 0x85: return 0x2026;
164 case 0x86: return 0x2020;
165 case 0x87: return 0x2021;
166 case 0x88: return 0x2C6;
167 case 0x89: return 0x2030;
168 case 0x8A: return 0x160;
169 case 0x8B: return 0x2039;
170 case 0x8C: return 0x152;
171 case 0x8E: return 0x17D;
172 case 0x91: return 0x2018;
173 case 0x92: return 0x2019;
174 case 0x93: return 0x201C;
175 case 0x94: return 0x201D;
176 case 0x95: return 0x2022;
177 case 0x96: return 0x2013;
178 case 0x97: return 0x2014;
179 case 0x98: return 0x2DC;
180 case 0x99: return 0x2122;
181 case 0x9A: return 0x161;
182 case 0x9B: return 0x203A;
183 case 0x9C: return 0x153;
184 case 0x9E: return 0x17E;
185 case 0x9F: return 0x178;
190 /* converts cp1252 to utf8 */
191 APREQ_DECLARE(apr_size_t) apreq_cp1252_to_utf8(char *dest,
192 const char *src, apr_size_t slen)
194 const unsigned char *s = (unsigned const char *)src;
195 const unsigned char *end = s + slen;
196 unsigned char *d = (unsigned char *)dest;
200 c = cp1252_to_bmp(*s++);
205 else if (c < 0x800) {
206 *d++ = 0xC0 | (c >> 6);
207 *d++ = 0x80 | (c & 0x3F);
210 *d++ = 0xE0 | (c >> 12);
211 *d++ = 0x80 | ((c >> 6) & 0x3F);
212 *d++ = 0x80 | (c & 0x3F);
216 return d - (unsigned char *)dest;
221 * Valid utf8 bit patterns: (true utf8 must satisfy a minimality condition)
224 * 110bbbba 10aaaaaa minimality mask: 0x1E
225 * 1110cccc 10cbbbba 10aaaaaa 0x0F || 0x20
226 * 11110ddd 10ddcccc 10cbbbba 10aaaaaa 0x07 || 0x30
227 * 111110ee 10eeeddd 10ddcccc 10cbbbba 10aaaaaa 0x03 || 0x38
228 * 1111110f 10ffffee 10eeeddd 10ddcccc 10cbbbba 10aaaaaa 0x01 || 0x3C
230 * Charset divination heuristics:
231 * 1) presume ascii; if not, then
232 * 2) presume utf8; if not, then
233 * 3) presume latin1; unless there are control chars, in which case
236 * Note: in downgrading from 2 to 3, we need to be careful
237 * about earlier control characters presumed to be valid utf8.
240 APREQ_DECLARE(apreq_charset_t) apreq_charset_divine(const char *src,
244 apreq_charset_t rv = APREQ_CHARSET_ASCII;
245 register unsigned char trail = 0, saw_cntrl = 0, mask = 0;
246 register const unsigned char *s = (const unsigned char *)src;
247 const unsigned char *end = s + slen;
249 for (; s < end; ++s) {
251 if ((*s & 0xC0) == 0x80 && (mask == 0 || (mask & *s))) {
255 if ((*s & 0xE0) == 0x80) {
262 return APREQ_CHARSET_CP1252;
263 rv = APREQ_CHARSET_LATIN1;
266 else if (*s < 0x80) {
269 else if (*s < 0xA0) {
270 return APREQ_CHARSET_CP1252;
272 else if (*s < 0xC0) {
274 return APREQ_CHARSET_CP1252;
275 rv = APREQ_CHARSET_LATIN1;
277 else if (rv == APREQ_CHARSET_LATIN1) {
283 else if (*s < 0xE0) {
285 rv = APREQ_CHARSET_UTF8;
290 return APREQ_CHARSET_CP1252;
292 rv = APREQ_CHARSET_LATIN1;
294 else if (*s < 0xF0) {
295 mask = (*s & 0x0F) ? 0 : 0x20;
296 rv = APREQ_CHARSET_UTF8;
299 else if (*s < 0xF8) {
300 mask = (*s & 0x07) ? 0 : 0x30;
301 rv = APREQ_CHARSET_UTF8;
304 else if (*s < 0xFC) {
305 mask = (*s & 0x03) ? 0 : 0x38;
306 rv = APREQ_CHARSET_UTF8;
309 else if (*s < 0xFE) {
310 mask = (*s & 0x01) ? 0 : 0x3C;
311 rv = APREQ_CHARSET_UTF8;
315 rv = APREQ_CHARSET_UTF8;
319 return trail ? saw_cntrl ?
320 APREQ_CHARSET_CP1252 : APREQ_CHARSET_LATIN1 : rv;
324 static APR_INLINE apr_uint16_t hex4_to_bmp(const char *what) {
325 register apr_uint16_t digit = 0;
327 #if !APR_CHARSET_EBCDIC
328 digit = (what[0] >= 'A' ? ((what[0] & 0xDF)-'A') + 10 : (what[0]-'0'));
330 digit += (what[1] >= 'A' ? ((what[1] & 0xDF)-'A') + 10 : (what[1]-'0'));
332 digit += (what[2] >= 'A' ? ((what[2] & 0xDF)-'A') + 10 : (what[2]-'0'));
334 digit += (what[3] >= 'A' ? ((what[3] & 0xDF)-'A') + 10 : (what[3]-'0'));
336 #else /*APR_CHARSET_EBCDIC*/
345 digit = apr_xlate_conv_byte(ap_hdrs_from_ascii, 0xFFFF & strtol(xstr, NULL, 16));
346 #endif /*APR_CHARSET_EBCDIC*/
351 static apr_status_t url_decode(char *dest, apr_size_t *dlen,
352 const char *src, apr_size_t *slen)
354 register const char *s = src;
355 unsigned char *start = (unsigned char *)dest;
356 register unsigned char *d = (unsigned char *)dest;
357 const char *end = src + *slen;
359 for (; s < end; ++d, ++s) {
367 if (s + 2 < end && apr_isxdigit(s[1]) && apr_isxdigit(s[2]))
369 *d = hex2_to_char(s + 1);
372 else if (s + 5 < end && (s[1] == 'u' || s[1] == 'U') &&
373 apr_isxdigit(s[2]) && apr_isxdigit(s[3]) &&
374 apr_isxdigit(s[4]) && apr_isxdigit(s[5]))
376 apr_uint16_t c = hex4_to_bmp(s+2);
381 else if (c < 0x800) {
382 *d++ = 0xC0 | (c >> 6);
383 *d = 0x80 | (c & 0x3F);
386 *d++ = 0xE0 | (c >> 12);
387 *d++ = 0x80 | ((c >> 6) & 0x3F);
388 *d = 0x80 | (c & 0x3F);
396 || (s + 2 < end && !apr_isxdigit(s[2]))
397 || (s + 1 < end && !apr_isxdigit(s[1])
398 && s[1] != 'u' && s[1] != 'U'))
401 return APREQ_ERROR_BADSEQ;
404 memmove(d, s, end - s);
406 return APR_INCOMPLETE;
418 return APREQ_ERROR_BADCHAR;
430 APREQ_DECLARE(apr_status_t) apreq_decode(char *d, apr_size_t *dlen,
431 const char *s, apr_size_t slen)
434 const char *end = s + slen;
436 if (s == (const char *)d) { /* optimize for src = dest case */
437 for ( ; d < end; ++d) {
438 if (*d == '%' || *d == '+')
441 *dlen = (const char *)d - s;
442 return APREQ_ERROR_BADCHAR;
445 len = (const char *)d - s;
450 return url_decode(d, dlen, s, &slen);
453 APREQ_DECLARE(apr_status_t) apreq_decodev(char *d, apr_size_t *dlen,
454 struct iovec *v, int nelts)
456 apr_status_t status = APR_SUCCESS;
462 apr_size_t slen, len;
465 switch (status = url_decode(d, &len, v[n].iov_base, &slen)) {
476 slen = v[n].iov_len - slen;
481 memcpy(d + slen, v[n].iov_base, v[n].iov_len);
482 v[n].iov_len += slen;
496 APREQ_DECLARE(apr_size_t) apreq_encode(char *dest, const char *src,
497 const apr_size_t slen)
500 const unsigned char *s = (const unsigned char *)src;
503 for ( ; s < (const unsigned char *)src + slen; ++s) {
505 if ( c < 0x80 && (apr_isalnum(c)
506 || c == '-' || c == '.'
507 || c == '_' || c == '~') )
514 #if APR_CHARSET_EBCDIC
515 c = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)c);
518 *d++ = c2x_table[c >> 4];
519 *d++ = c2x_table[c & 0xf];
527 static int is_quoted(const char *p, const apr_size_t len) {
528 if (len > 1 && p[0] == '"' && p[len-1] == '"') {
532 for (i = 1; i < len - 1; i++) {
534 backslash = !backslash;
535 else if (p[i] == 0 || (p[i] == '"' && !backslash))
547 APREQ_DECLARE(apr_size_t) apreq_quote_once(char *dest, const char *src,
548 const apr_size_t slen)
550 if (is_quoted(src, slen)) {
551 /* looks like src is already quoted */
552 memcpy(dest, src, slen);
557 return apreq_quote(dest, src, slen);
560 APREQ_DECLARE(apr_size_t) apreq_quote(char *dest, const char *src,
561 const apr_size_t slen)
565 const char *const last = src + slen - 1;
597 APREQ_DECLARE(char *) apreq_join(apr_pool_t *p,
599 const apr_array_header_t *arr,
602 apr_size_t len, slen;
604 const apreq_value_t **a = (const apreq_value_t **)arr->elts;
606 const int n = arr->nelts;
609 slen = sep ? strlen(sep) : 0;
612 return apr_pstrdup(p, "");
614 for (j=0, len=0; j < n; ++j)
615 len += a[j]->dlen + slen + 1;
617 /* Allocated the required space */
620 case APREQ_JOIN_ENCODE:
623 case APREQ_JOIN_QUOTE:
626 case APREQ_JOIN_AS_IS:
627 case APREQ_JOIN_DECODE:
628 /* nothing special required, just here to keep noisy compilers happy */
632 rv = apr_palloc(p, len);
634 /* Pass two --- copy the argument strings into the result space */
640 case APREQ_JOIN_ENCODE:
641 d += apreq_encode(d, a[0]->data, a[0]->dlen);
643 for (j = 1; j < n; ++j) {
644 memcpy(d, sep, slen);
646 d += apreq_encode(d, a[j]->data, a[j]->dlen);
650 case APREQ_JOIN_DECODE:
651 if (apreq_decode(d, &len, a[0]->data, a[0]->dlen))
656 for (j = 1; j < n; ++j) {
657 memcpy(d, sep, slen);
660 if (apreq_decode(d, &len, a[j]->data, a[j]->dlen))
668 case APREQ_JOIN_QUOTE:
669 d += apreq_quote_once(d, a[0]->data, a[0]->dlen);
671 for (j = 1; j < n; ++j) {
672 memcpy(d, sep, slen);
674 d += apreq_quote_once(d, a[j]->data, a[j]->dlen);
679 case APREQ_JOIN_AS_IS:
680 memcpy(d,a[0]->data, a[0]->dlen);
683 for (j = 1; j < n ; ++j) {
684 memcpy(d, sep, slen);
686 memcpy(d, a[j]->data, a[j]->dlen);
697 * This is intentionally not apr_file_writev()
698 * note, this is iterative and not recursive
701 static apr_status_t apreq_fwritev(apr_file_t *f, struct iovec *v,
702 int *nelts, apr_size_t *bytes_written)
712 s = apr_file_writev(f, v, *nelts, &len);
714 *bytes_written += len;
716 if (s != APR_SUCCESS)
719 /* see how far we've come */
725 * iovec.iov_len is a long here
726 * which causes a comparison between
727 * signed(long) and unsigned(apr_size_t)
730 while (n < *nelts && len >= (apr_size_t)v[n].iov_len)
733 * Sun C however defines this as size_t which is unsigned
736 while (n < *nelts && len >= v[n].iov_len)
737 # endif /* !__GNUC__ */
740 * Hopefully everything else does this
741 * (this was the default for years)
743 while (n < *nelts && len >= v[n].iov_len)
745 len -= v[n++].iov_len;
748 /* nothing left to write, report success */
753 /* incomplete write: must shift v */
755 v[n].iov_base = (char *)(v[n].iov_base) + len;
758 /* we're satisfied for now if we can remove one iovec from
761 memmove(v, v + n, sizeof(*v) * *nelts);
766 /* we're still in the first iovec - check for endless loop,
767 and then try again */
769 return APREQ_ERROR_GENERAL;
776 struct cleanup_data {
781 static apr_status_t apreq_file_cleanup(void *d)
783 struct cleanup_data *data = d;
784 return apr_file_remove(data->fname, data->pool);
788 * The reason we need the above cleanup is because on Windows, APR_DELONCLOSE
789 * forces applications to open the file with FILE_SHARED_DELETE
790 * set, which is, unfortunately, a property that is preserved
791 * across NTFS "hard" links. This breaks apps that link() the temp
792 * file to a permanent location, and subsequently expect to open it
793 * before the original tempfile is closed+deleted. In fact, even
794 * Apache::Upload does this, so it is a common enough event that the
795 * apreq_file_cleanup workaround is necessary.
798 APREQ_DECLARE(apr_status_t) apreq_file_mktemp(apr_file_t **fp,
804 struct cleanup_data *data;
808 rc = apr_temp_dir_get(&path, pool);
809 if (rc != APR_SUCCESS)
812 rc = apr_filepath_merge(&tmpl, path, "apreqXXXXXX",
813 APR_FILEPATH_NOTRELATIVE, pool);
815 if (rc != APR_SUCCESS)
818 data = apr_palloc(pool, sizeof *data);
819 /* cleanups are LIFO, so this one will run just after
820 the cleanup set by mktemp */
821 apr_pool_cleanup_register(pool, data,
822 apreq_file_cleanup, apreq_file_cleanup);
824 /* NO APR_DELONCLOSE! see comment above */
825 flag = APR_CREATE | APR_READ | APR_WRITE | APR_EXCL | APR_BINARY;
827 rc = apr_file_mktemp(fp, tmpl, flag, pool);
829 if (rc == APR_SUCCESS) {
830 apr_file_name_get(&data->fname, *fp);
834 apr_pool_cleanup_kill(pool, data, apreq_file_cleanup);
842 * is_2616_token() is the verbatim definition from section 2.2
843 * in the rfc itself. We try to optimize it around the
844 * expectation that the argument is not a token, which
845 * should be the typical usage.
849 unsigned is_2616_token(const char c) {
851 case ' ': case ';': case ',': case '"': case '\t':
852 /* The chars we are expecting are listed above;
853 the chars below are just for completeness. */
854 case '?': case '=': case '@': case ':': case '\\': case '/':
867 APREQ_DECLARE(apr_status_t)
868 apreq_header_attribute(const char *hdr,
869 const char *name, const apr_size_t nlen,
870 const char **val, apr_size_t *vlen)
874 /* Must ensure first char isn't '=', so we can safely backstep. */
878 while ((key = strchr(hdr, '=')) != NULL) {
883 while (apr_isspace(*key) && key > hdr + nlen)
888 while (apr_isspace(*v))
900 return APREQ_ERROR_BADSEQ;
906 goto look_for_end_quote;
924 goto look_for_terminator;
928 if (key >= hdr && strncasecmp(key, name, nlen) == 0) {
930 if (key == hdr || ! is_2616_token(key[-1]))
936 return APREQ_ERROR_NOATTR;
941 #define BUCKET_IS_SPOOL(e) ((e)->type == &spool_bucket_type)
942 #define FILE_BUCKET_LIMIT ((apr_size_t)-1 - 1)
945 void spool_bucket_destroy(void *data)
947 apr_bucket_type_file.destroy(data);
951 apr_status_t spool_bucket_read(apr_bucket *e, const char **str,
952 apr_size_t *len, apr_read_type_e block)
954 return apr_bucket_type_file.read(e, str, len, block);
958 apr_status_t spool_bucket_setaside(apr_bucket *data, apr_pool_t *reqpool)
960 return apr_bucket_type_file.setaside(data, reqpool);
964 apr_status_t spool_bucket_split(apr_bucket *a, apr_size_t point)
966 apr_status_t rv = apr_bucket_shared_split(a, point);
967 a->type = &apr_bucket_type_file;
972 apr_status_t spool_bucket_copy(apr_bucket *e, apr_bucket **c)
974 apr_status_t rv = apr_bucket_shared_copy(e, c);
975 (*c)->type = &apr_bucket_type_file;
979 static const apr_bucket_type_t spool_bucket_type = {
980 "APREQ_SPOOL", 5, APR_BUCKET_DATA,
981 spool_bucket_destroy,
983 spool_bucket_setaside,
988 APREQ_DECLARE(apr_file_t *)apreq_brigade_spoolfile(apr_bucket_brigade *bb)
992 last = APR_BRIGADE_LAST(bb);
993 if (BUCKET_IS_SPOOL(last))
994 return ((apr_bucket_file *)last->data)->fd;
999 APREQ_DECLARE(apr_status_t) apreq_brigade_concat(apr_pool_t *pool,
1000 const char *temp_dir,
1001 apr_size_t heap_limit,
1002 apr_bucket_brigade *out,
1003 apr_bucket_brigade *in)
1009 apr_off_t in_len, out_len;
1010 apr_bucket *last_in, *last_out;
1012 last_out = APR_BRIGADE_LAST(out);
1014 if (APR_BUCKET_IS_EOS(last_out))
1017 s = apr_brigade_length(out, 0, &out_len);
1018 if (s != APR_SUCCESS)
1021 /* This cast, when out_len = -1, is intentional */
1022 if ((apr_uint64_t)out_len < heap_limit) {
1024 s = apr_brigade_length(in, 0, &in_len);
1025 if (s != APR_SUCCESS)
1028 /* This cast, when in_len = -1, is intentional */
1029 if ((apr_uint64_t)in_len < heap_limit - (apr_uint64_t)out_len) {
1030 APR_BRIGADE_CONCAT(out, in);
1035 if (!BUCKET_IS_SPOOL(last_out)) {
1037 s = apreq_file_mktemp(&file, pool, temp_dir);
1038 if (s != APR_SUCCESS)
1041 s = apreq_brigade_fwrite(file, &wlen, out);
1043 if (s != APR_SUCCESS)
1046 last_out = apr_bucket_file_create(file, wlen, 0,
1047 out->p, out->bucket_alloc);
1048 last_out->type = &spool_bucket_type;
1049 APR_BRIGADE_INSERT_TAIL(out, last_out);
1054 /* Need to seek here, just in case our spool bucket
1055 * was read from between apreq_brigade_concat calls.
1057 wlen = last_out->start + last_out->length;
1058 s = apr_file_seek(f->fd, APR_SET, &wlen);
1059 if (s != APR_SUCCESS)
1066 last_in = APR_BRIGADE_LAST(in);
1068 if (APR_BUCKET_IS_EOS(last_in))
1069 APR_BUCKET_REMOVE(last_in);
1071 s = apreq_brigade_fwrite(f->fd, &wlen, in);
1073 if (s == APR_SUCCESS) {
1075 /* We have to deal with the possibility that the new
1076 * data may be too large to be represented by a single
1080 while ((apr_uint64_t)wlen > FILE_BUCKET_LIMIT - last_out->length) {
1083 apr_bucket_copy(last_out, &e);
1085 e->start = last_out->start + FILE_BUCKET_LIMIT;
1086 wlen -= FILE_BUCKET_LIMIT - last_out->length;
1087 last_out->length = FILE_BUCKET_LIMIT;
1089 /* Copying makes the bucket types exactly the
1090 * opposite of what we need here.
1092 last_out->type = &apr_bucket_type_file;
1093 e->type = &spool_bucket_type;
1095 APR_BRIGADE_INSERT_TAIL(out, e);
1099 last_out->length += wlen;
1101 if (APR_BUCKET_IS_EOS(last_in))
1102 APR_BRIGADE_INSERT_TAIL(out, last_in);
1105 else if (APR_BUCKET_IS_EOS(last_in))
1106 APR_BRIGADE_INSERT_TAIL(in, last_in);
1108 apr_brigade_cleanup(in);
1112 APREQ_DECLARE(apr_status_t) apreq_brigade_fwrite(apr_file_t *f,
1114 apr_bucket_brigade *bb)
1116 struct iovec v[APREQ_DEFAULT_NELTS];
1118 apr_bucket *e, *first;
1120 apr_bucket_brigade *tmp = bb;
1123 if (BUCKET_IS_SPOOL(APR_BRIGADE_LAST(bb))) {
1124 tmp = apr_brigade_create(bb->p, bb->bucket_alloc);
1126 s = apreq_brigade_copy(tmp, bb);
1127 if (s != APR_SUCCESS)
1131 for (e = APR_BRIGADE_FIRST(tmp); e != APR_BRIGADE_SENTINEL(tmp);
1132 e = APR_BUCKET_NEXT(e))
1135 if (n == APREQ_DEFAULT_NELTS) {
1136 s = apreq_fwritev(f, v, &n, &len);
1137 if (s != APR_SUCCESS)
1141 while ((first = APR_BRIGADE_FIRST(tmp)) != e)
1142 apr_bucket_delete(first);
1147 s = apr_bucket_read(e, (const char **)&(v[n].iov_base),
1148 &len, APR_BLOCK_READ);
1149 if (s != APR_SUCCESS)
1152 v[n++].iov_len = len;
1157 s = apreq_fwritev(f, v, &n, &len);
1158 if (s != APR_SUCCESS)
1163 while ((first = APR_BRIGADE_FIRST(tmp)) != e)
1164 apr_bucket_delete(first);