]> granicus.if.org Git - apache/blob - server/apreq_util.c
Move two variable assignments off the fast path.
[apache] / server / apreq_util.c
1 /*
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
8 **
9 **      http://www.apache.org/licenses/LICENSE-2.0
10 **
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.
16 */
17
18 #include "apreq_util.h"
19 #include "apreq_error.h"
20 #include "apr_time.h"
21 #include "apr_strings.h"
22 #include "apr_lib.h"
23 #include <assert.h>
24
25 #undef MAX
26 #undef MIN
27 #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
28 #define MAX(a,b) ( (a) > (b) ? (a) : (b) )
29
30 /* used for specifying file sizes */
31
32 APREQ_DECLARE(apr_int64_t) apreq_atoi64f(const char *s)
33 {
34     apr_int64_t n = 0;
35     char *p;
36     if (s == NULL)
37         return 0;
38
39     n = apr_strtoi64(s, &p, 0);
40
41     if (p == NULL)
42         return n;
43     while (apr_isspace(*p))
44         ++p;
45
46     switch (*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;
53     }
54
55     return n;
56 }
57
58
59 /* converts date offsets (e.g. "+3M") to seconds */
60
61 APREQ_DECLARE(apr_int64_t) apreq_atoi64t(const char *s)
62 {
63     apr_int64_t n = 0;
64     char *p;
65     if (s == NULL)
66         return 0;
67     n = apr_strtoi64(s, &p, 0); /* XXX: what about overflow? */
68
69     if (p == NULL)
70         return n;
71     while (apr_isspace(*p))
72         ++p;
73
74     switch (*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 */
84       default:
85           return n;
86     }
87     /* should never get here */
88     return -1;
89 }
90
91
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)
95 {
96     apr_size_t len = hlen;
97     const char *end = hay + hlen;
98     const char *begin = hay;
99
100     while ( (hay = memchr(hay, ndl[0], len)) ) {
101         len = end - hay;
102
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 */
107             break;
108         }
109         --len;
110         ++hay;
111     }
112
113     return hay ? hay - begin : -1;
114 }
115
116
117 static const char c2x_table[] = "0123456789ABCDEF";
118 static APR_INLINE unsigned char hex2_to_char(const char *what)
119 {
120     register unsigned char digit;
121
122 #if !APR_CHARSET_EBCDIC
123     digit  = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
124     digit *= 16;
125     digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
126 #else /*APR_CHARSET_EBCDIC*/
127     char xstr[5];
128     xstr[0]='0';
129     xstr[1]='x';
130     xstr[2]=what[0];
131     xstr[3]=what[1];
132     xstr[4]='\0';
133     digit = apr_xlate_conv_byte(ap_hdrs_from_ascii, 0xFF & strtol(xstr, NULL, 16));
134 #endif /*APR_CHARSET_EBCDIC*/
135     return (digit);
136 }
137
138
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.
145  */
146
147 /* Converts Windows cp1252 to Unicode. */
148
149 static APR_INLINE
150 apr_uint16_t cp1252_to_bmp(unsigned char c)
151 {
152     /* We only need to deal with iso-8859-1 control chars
153      * in the 0x80 - 0x9F range.
154      */
155     if ((c & 0xE0) != 0x80)
156         return c;
157
158     switch (c) {
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;
186     }
187     return c;
188 }
189
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)
193 {
194     const unsigned char *s = (unsigned const char *)src;
195     const unsigned char *end = s + slen;
196     unsigned char *d = (unsigned char *)dest;
197     apr_uint16_t c;
198
199     while (s < end) {
200         c = cp1252_to_bmp(*s++);
201
202         if (c < 0x80) {
203             *d++ = c;
204         }
205         else if (c < 0x800) {
206             *d++ = 0xC0 | (c >> 6);
207             *d++ = 0x80 | (c & 0x3F);
208         }
209         else {
210             *d++ = 0xE0 | (c >> 12);
211             *d++ = 0x80 | ((c >> 6) & 0x3F);
212             *d++ = 0x80 | (c & 0x3F);
213         }
214     }
215     *d = 0;
216     return d - (unsigned char *)dest;
217 }
218
219
220 /**
221  * Valid utf8 bit patterns: (true utf8 must satisfy a minimality condition)
222  *
223  * 0aaaaaaa
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
229  *
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
234  * 4) punt to cp1252.
235  *
236  * Note: in downgrading from 2 to 3, we need to be careful
237  * about earlier control characters presumed to be valid utf8.
238  */
239
240 APREQ_DECLARE(apreq_charset_t) apreq_charset_divine(const char *src,
241                                                     apr_size_t slen)
242
243 {
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;
248
249     for (; s < end; ++s) {
250         if (trail) {
251             if ((*s & 0xC0) == 0x80 && (mask == 0 || (mask & *s))) {
252                 mask = 0;
253                 --trail;
254
255                 if ((*s & 0xE0) == 0x80) {
256                     saw_cntrl = 1;
257                 }
258             }
259             else {
260                 trail = 0;
261                 if (saw_cntrl)
262                     return APREQ_CHARSET_CP1252;
263                 rv = APREQ_CHARSET_LATIN1;
264             }
265         }
266         else if (*s < 0x80) {
267             /* do nothing */
268         }
269         else if (*s < 0xA0) {
270             return APREQ_CHARSET_CP1252;
271         }
272         else if (*s < 0xC0) {
273             if (saw_cntrl)
274                 return APREQ_CHARSET_CP1252;
275             rv = APREQ_CHARSET_LATIN1;
276         }
277         else if (rv == APREQ_CHARSET_LATIN1) {
278             /* do nothing */
279         }
280
281         /* utf8 cases */
282
283         else if (*s < 0xE0) {
284             if (*s & 0x1E) {
285                 rv = APREQ_CHARSET_UTF8;
286                 trail = 1;
287                 mask = 0;
288             }
289             else if (saw_cntrl)
290                 return APREQ_CHARSET_CP1252;
291             else
292                 rv = APREQ_CHARSET_LATIN1;
293         }
294         else if (*s < 0xF0) {
295             mask = (*s & 0x0F) ? 0 : 0x20;
296             rv = APREQ_CHARSET_UTF8;
297             trail = 2;
298         }
299         else if (*s < 0xF8) {
300             mask = (*s & 0x07) ? 0 : 0x30;
301             rv = APREQ_CHARSET_UTF8;
302             trail = 3;
303         }
304         else if (*s < 0xFC) {
305             mask = (*s & 0x03) ? 0 : 0x38;
306             rv = APREQ_CHARSET_UTF8;
307             trail = 4;
308         }
309         else if (*s < 0xFE) {
310             mask = (*s & 0x01) ? 0 : 0x3C;
311             rv = APREQ_CHARSET_UTF8;
312             trail = 5;
313         }
314         else {
315             rv = APREQ_CHARSET_UTF8;
316         }
317     }
318
319     return trail ? saw_cntrl ?
320         APREQ_CHARSET_CP1252 : APREQ_CHARSET_LATIN1 : rv;
321 }
322
323
324 static APR_INLINE apr_uint16_t hex4_to_bmp(const char *what) {
325     register apr_uint16_t digit = 0;
326
327 #if !APR_CHARSET_EBCDIC
328     digit  = (what[0] >= 'A' ? ((what[0] & 0xDF)-'A') + 10 : (what[0]-'0'));
329     digit *= 16;
330     digit += (what[1] >= 'A' ? ((what[1] & 0xDF)-'A') + 10 : (what[1]-'0'));
331     digit *= 16;
332     digit += (what[2] >= 'A' ? ((what[2] & 0xDF)-'A') + 10 : (what[2]-'0'));
333     digit *= 16;
334     digit += (what[3] >= 'A' ? ((what[3] & 0xDF)-'A') + 10 : (what[3]-'0'));
335
336 #else /*APR_CHARSET_EBCDIC*/
337     char xstr[7];
338     xstr[0]='0';
339     xstr[1]='x';
340     xstr[2]=what[0];
341     xstr[3]=what[1];
342     xstr[4]=what[2];
343     xstr[5]=what[3];
344     xstr[6]='\0';
345     digit = apr_xlate_conv_byte(ap_hdrs_from_ascii, 0xFFFF & strtol(xstr, NULL, 16));
346 #endif /*APR_CHARSET_EBCDIC*/
347     return (digit);
348 }
349
350
351 static apr_status_t url_decode(char *dest, apr_size_t *dlen,
352                                const char *src, apr_size_t *slen)
353 {
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;
358
359     for (; s < end; ++d, ++s) {
360         switch (*s) {
361
362         case '+':
363             *d = ' ';
364             break;
365
366         case '%':
367             if (s + 2 < end && apr_isxdigit(s[1]) && apr_isxdigit(s[2]))
368             {
369                 *d = hex2_to_char(s + 1);
370                 s += 2;
371             }
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]))
375             {
376                 apr_uint16_t c = hex4_to_bmp(s+2);
377
378                 if (c < 0x80) {
379                     *d = c;
380                 }
381                 else if (c < 0x800) {
382                     *d++ = 0xC0 | (c >> 6);
383                     *d   = 0x80 | (c & 0x3F);
384                 }
385                 else {
386                     *d++ = 0xE0 | (c >> 12);
387                     *d++ = 0x80 | ((c >> 6) & 0x3F);
388                     *d   = 0x80 | (c & 0x3F);
389                 }
390                 s += 5;
391             }
392             else {
393                 *dlen = d - start;
394                 *slen = s - src;
395                 if (s + 5 < end
396                     || (s + 2 < end && !apr_isxdigit(s[2]))
397                     || (s + 1 < end && !apr_isxdigit(s[1])
398                         && s[1] != 'u' && s[1] != 'U'))
399                 {
400                     *d = 0;
401                     return APREQ_ERROR_BADSEQ;
402                 }
403
404                 memmove(d, s, end - s);
405                 d[end - s] = 0;
406                 return APR_INCOMPLETE;
407             }
408             break;
409
410         default:
411             if (*s > 0) {
412                 *d = *s;
413             }
414             else {
415                 *d = 0;
416                 *dlen = d - start;
417                 *slen = s - src;
418                 return APREQ_ERROR_BADCHAR;
419             }
420         }
421     }
422
423     *d = 0;
424     *dlen = d - start;
425     *slen = s - src;
426     return APR_SUCCESS;
427 }
428
429
430 APREQ_DECLARE(apr_status_t) apreq_decode(char *d, apr_size_t *dlen,
431                                          const char *s, apr_size_t slen)
432 {
433     apr_size_t len = 0;
434     const char *end = s + slen;
435
436     if (s == (const char *)d) {     /* optimize for src = dest case */
437         for ( ; d < end; ++d) {
438             if (*d == '%' || *d == '+')
439                 break;
440             else if (*d == 0) {
441                 *dlen = (const char *)d - s;
442                 return APREQ_ERROR_BADCHAR;
443             }
444         }
445         len = (const char *)d - s;
446         s = (const char *)d;
447         slen -= len;
448     }
449
450     return url_decode(d, dlen, s, &slen);
451 }
452
453 APREQ_DECLARE(apr_status_t) apreq_decodev(char *d, apr_size_t *dlen,
454                                           struct iovec *v, int nelts)
455 {
456     apr_status_t status = APR_SUCCESS;
457     int n = 0;
458
459     *dlen = 0;
460
461     while (n < nelts) {
462         apr_size_t slen, len;
463
464         slen = v[n].iov_len;
465         switch (status = url_decode(d, &len, v[n].iov_base, &slen)) {
466
467         case APR_SUCCESS:
468             d += len;
469             *dlen += len;
470             ++n;
471             continue;
472
473         case APR_INCOMPLETE:
474             d += len;
475             *dlen += len;
476             slen = v[n].iov_len - slen;
477
478             if (++n == nelts) {
479                 return status;
480             }
481             memcpy(d + slen, v[n].iov_base, v[n].iov_len);
482             v[n].iov_len += slen;
483             v[n].iov_base = d;
484             continue;
485
486         default:
487             *dlen += len;
488             return status;
489         }
490     }
491
492     return status;
493 }
494
495
496 APREQ_DECLARE(apr_size_t) apreq_encode(char *dest, const char *src,
497                                        const apr_size_t slen)
498 {
499     char *d = dest;
500     const unsigned char *s = (const unsigned char *)src;
501     unsigned char c;
502
503     for ( ; s < (const unsigned char *)src + slen; ++s) {
504         c = *s;
505         if ( c < 0x80 && (apr_isalnum(c)
506                           || c == '-' || c == '.'
507                           || c == '_' || c == '~') )
508             *d++ = c;
509
510         else if ( c == ' ' )
511             *d++ = '+';
512
513         else {
514 #if APR_CHARSET_EBCDIC
515             c = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)c);
516 #endif
517             *d++ = '%';
518             *d++ = c2x_table[c >> 4];
519             *d++ = c2x_table[c & 0xf];
520         }
521     }
522     *d = 0;
523
524     return d - dest;
525 }
526
527 static int is_quoted(const char *p, const apr_size_t len) {
528     if (len > 1 && p[0] == '"' && p[len-1] == '"') {
529         apr_size_t i;
530         int backslash = 0;
531
532         for (i = 1; i < len - 1; i++) {
533             if (p[i] == '\\')
534                 backslash = !backslash;
535             else if (p[i] == 0 || (p[i] == '"' && !backslash))
536                 return 0;
537             else
538                 backslash = 0;
539         }
540
541         return !backslash;
542     }
543
544     return 0;
545 }
546
547 APREQ_DECLARE(apr_size_t) apreq_quote_once(char *dest, const char *src,
548                                            const apr_size_t slen)
549 {
550     if (is_quoted(src, slen)) {
551         /* looks like src is already quoted */
552         memcpy(dest, src, slen);
553         dest[slen] = 0;
554         return slen;
555     }
556     else
557         return apreq_quote(dest, src, slen);
558 }
559
560 APREQ_DECLARE(apr_size_t) apreq_quote(char *dest, const char *src,
561                                       const apr_size_t slen)
562 {
563     char *d = dest;
564     const char *s = src;
565     const char *const last = src + slen - 1;
566
567     if (slen == 0) {
568         *d = 0;
569         return 0;
570     }
571
572     *d++ = '"';
573
574     while (s <= last) {
575         switch (*s) {
576         case 0:
577             *d++ = '\\';
578             *d++ = '0';
579             s++;
580             break;
581
582         case '\\':
583         case '"':
584             *d++ = '\\';
585
586         default:
587             *d++ = *s++;
588         }
589     }
590
591     *d++ = '"';
592     *d = 0;
593
594     return d - dest;
595 }
596
597 APREQ_DECLARE(char *) apreq_join(apr_pool_t *p,
598                                  const char *sep,
599                                  const apr_array_header_t *arr,
600                                  apreq_join_t mode)
601 {
602     apr_size_t len, slen;
603     char *rv;
604     const apreq_value_t **a = (const apreq_value_t **)arr->elts;
605     char *d;
606     const int n = arr->nelts;
607     int j;
608
609     slen = sep ? strlen(sep) : 0;
610
611     if (n == 0)
612         return apr_pstrdup(p, "");
613
614     for (j=0, len=0; j < n; ++j)
615         len += a[j]->dlen + slen + 1;
616
617     /* Allocated the required space */
618
619     switch (mode) {
620     case APREQ_JOIN_ENCODE:
621         len += 2 * len;
622         break;
623     case APREQ_JOIN_QUOTE:
624         len = 2 * (len + n);
625         break;
626     case APREQ_JOIN_AS_IS:
627     case APREQ_JOIN_DECODE:
628         /* nothing special required, just here to keep noisy compilers happy */
629         break;
630     }
631
632     rv = apr_palloc(p, len);
633
634     /* Pass two --- copy the argument strings into the result space */
635
636     d = rv;
637
638     switch (mode) {
639
640     case APREQ_JOIN_ENCODE:
641         d += apreq_encode(d, a[0]->data, a[0]->dlen);
642
643         for (j = 1; j < n; ++j) {
644                 memcpy(d, sep, slen);
645                 d += slen;
646                 d += apreq_encode(d, a[j]->data, a[j]->dlen);
647         }
648         break;
649
650     case APREQ_JOIN_DECODE:
651         if (apreq_decode(d, &len, a[0]->data, a[0]->dlen))
652             return NULL;
653         else
654             d += len;
655
656         for (j = 1; j < n; ++j) {
657             memcpy(d, sep, slen);
658             d += slen;
659
660             if (apreq_decode(d, &len, a[j]->data, a[j]->dlen))
661                 return NULL;
662             else
663                 d += len;
664         }
665         break;
666
667
668     case APREQ_JOIN_QUOTE:
669         d += apreq_quote_once(d, a[0]->data, a[0]->dlen);
670
671         for (j = 1; j < n; ++j) {
672             memcpy(d, sep, slen);
673             d += slen;
674             d += apreq_quote_once(d, a[j]->data, a[j]->dlen);
675         }
676         break;
677
678
679     case APREQ_JOIN_AS_IS:
680         memcpy(d,a[0]->data, a[0]->dlen);
681         d += a[0]->dlen;
682
683         for (j = 1; j < n ; ++j) {
684             memcpy(d, sep, slen);
685             d += slen;
686             memcpy(d, a[j]->data, a[j]->dlen);
687             d += a[j]->dlen;
688         }
689         break;
690     }
691
692     *d = 0;
693     return rv;
694 }
695
696 /*
697  * This is intentionally not apr_file_writev()
698  * note, this is iterative and not recursive
699  */
700 APR_INLINE
701 static apr_status_t apreq_fwritev(apr_file_t *f, struct iovec *v,
702                                   int *nelts, apr_size_t *bytes_written)
703 {
704     apr_size_t len;
705     int n;
706     apr_status_t s;
707
708     *bytes_written = 0;
709
710     while (1) {
711         /* try to write */
712         s = apr_file_writev(f, v, *nelts, &len);
713
714         *bytes_written += len;
715
716         if (s != APR_SUCCESS)
717             return s;
718
719         /* see how far we've come */
720         n = 0;
721
722 #ifdef SOLARIS2
723 # ifdef __GNUC__
724         /*
725          * iovec.iov_len is a long here
726          * which causes a comparison between 
727          * signed(long) and unsigned(apr_size_t)
728          *
729          */
730         while (n < *nelts && len >= (apr_size_t)v[n].iov_len)
731 # else
732           /*
733            * Sun C however defines this as size_t which is unsigned
734            * 
735            */
736         while (n < *nelts && len >= v[n].iov_len)
737 # endif /* !__GNUC__ */
738 #else
739           /*
740            * Hopefully everything else does this
741            * (this was the default for years)
742            */
743         while (n < *nelts && len >= v[n].iov_len)
744 #endif
745             len -= v[n++].iov_len;
746
747         if (n == *nelts) {
748             /* nothing left to write, report success */
749             *nelts = 0;
750             return APR_SUCCESS;
751         }
752
753         /* incomplete write: must shift v */
754         v[n].iov_len -= len;
755         v[n].iov_base = (char *)(v[n].iov_base) + len;
756
757         if (n > 0) {
758             /* we're satisfied for now if we can remove one iovec from
759                the "v" array */
760             (*nelts) -= n;
761             memmove(v, v + n, sizeof(*v) * *nelts);
762
763             return APR_SUCCESS;
764         }
765
766         /* we're still in the first iovec - check for endless loop,
767            and then try again */
768         if (len == 0)
769             return APREQ_ERROR_GENERAL;
770     }
771 }
772
773
774
775
776 struct cleanup_data {
777     const char *fname;
778     apr_pool_t *pool;
779 };
780
781 static apr_status_t apreq_file_cleanup(void *d)
782 {
783     struct cleanup_data *data = d;
784     return apr_file_remove(data->fname, data->pool);
785 }
786
787 /*
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.
796  */
797
798 APREQ_DECLARE(apr_status_t) apreq_file_mktemp(apr_file_t **fp,
799                                               apr_pool_t *pool,
800                                               const char *path)
801 {
802     apr_status_t rc;
803     char *tmpl;
804     struct cleanup_data *data;
805     apr_int32_t flag;
806
807     if (path == NULL) {
808         rc = apr_temp_dir_get(&path, pool);
809         if (rc != APR_SUCCESS)
810             return rc;
811     }
812     rc = apr_filepath_merge(&tmpl, path, "apreqXXXXXX",
813                             APR_FILEPATH_NOTRELATIVE, pool);
814
815     if (rc != APR_SUCCESS)
816         return rc;
817
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);
823
824     /* NO APR_DELONCLOSE! see comment above */
825     flag = APR_CREATE | APR_READ | APR_WRITE | APR_EXCL | APR_BINARY;
826
827     rc = apr_file_mktemp(fp, tmpl, flag, pool);
828
829     if (rc == APR_SUCCESS) {
830         apr_file_name_get(&data->fname, *fp);
831         data->pool = pool;
832     }
833     else {
834         apr_pool_cleanup_kill(pool, data, apreq_file_cleanup);
835     }
836
837     return rc;
838 }
839
840
841 /*
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.
846  */
847
848 static APR_INLINE
849 unsigned is_2616_token(const char c) {
850     switch (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 '/':
855     case '(': case ')':
856     case '<': case '>':
857     case '{': case '}':
858     case '[': case ']':
859         return 0;
860     default:
861         if (apr_iscntrl(c))
862             return 0;
863     }
864     return 1;
865 }
866
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)
871 {
872     const char *key, *v;
873
874     /* Must ensure first char isn't '=', so we can safely backstep. */
875     while (*hdr == '=')
876         ++hdr;
877
878     while ((key = strchr(hdr, '=')) != NULL) {
879
880         v = key + 1;
881         --key;
882
883         while (apr_isspace(*key) && key > hdr + nlen)
884             --key;
885
886         key -= nlen - 1;
887
888         while (apr_isspace(*v))
889             ++v;
890
891         if (*v == '"') {
892             ++v;
893             *val = v;
894
895         look_for_end_quote:
896             switch (*v) {
897             case '"':
898                 break;
899             case 0:
900                 return APREQ_ERROR_BADSEQ;
901             case '\\':
902                 if (v[1] != 0)
903                     ++v;
904             default:
905                 ++v;
906                 goto look_for_end_quote;
907             }
908         }
909         else {
910             *val = v;
911
912         look_for_terminator:
913             switch (*v) {
914             case 0:
915             case ' ':
916             case ';':
917             case ',':
918             case '\t':
919             case '\r':
920             case '\n':
921                 break;
922             default:
923                 ++v;
924                 goto look_for_terminator;
925             }
926         }
927
928         if (key >= hdr && strncasecmp(key, name, nlen) == 0) {
929             *vlen = v - *val;
930             if (key == hdr || ! is_2616_token(key[-1]))
931                 return APR_SUCCESS;
932         }
933         hdr = v;
934     }
935
936     return APREQ_ERROR_NOATTR;
937 }
938
939
940
941 #define BUCKET_IS_SPOOL(e) ((e)->type == &spool_bucket_type)
942 #define FILE_BUCKET_LIMIT      ((apr_size_t)-1 - 1)
943
944 static
945 void spool_bucket_destroy(void *data)
946 {
947     apr_bucket_type_file.destroy(data);
948 }
949
950 static
951 apr_status_t spool_bucket_read(apr_bucket *e, const char **str,
952                                    apr_size_t *len, apr_read_type_e block)
953 {
954     return apr_bucket_type_file.read(e, str, len, block);
955 }
956
957 static
958 apr_status_t spool_bucket_setaside(apr_bucket *data, apr_pool_t *reqpool)
959 {
960     return apr_bucket_type_file.setaside(data, reqpool);
961 }
962
963 static
964 apr_status_t spool_bucket_split(apr_bucket *a, apr_size_t point)
965 {
966     apr_status_t rv = apr_bucket_shared_split(a, point);
967     a->type = &apr_bucket_type_file;
968     return rv;
969 }
970
971 static
972 apr_status_t spool_bucket_copy(apr_bucket *e, apr_bucket **c)
973 {
974     apr_status_t rv = apr_bucket_shared_copy(e, c);
975     (*c)->type = &apr_bucket_type_file;
976     return rv;
977 }
978
979 static const apr_bucket_type_t spool_bucket_type = {
980     "APREQ_SPOOL", 5, APR_BUCKET_DATA,
981     spool_bucket_destroy,
982     spool_bucket_read,
983     spool_bucket_setaside,
984     spool_bucket_split,
985     spool_bucket_copy,
986 };
987
988 APREQ_DECLARE(apr_file_t *)apreq_brigade_spoolfile(apr_bucket_brigade *bb)
989 {
990     apr_bucket *last;
991
992     last = APR_BRIGADE_LAST(bb);
993     if (BUCKET_IS_SPOOL(last))
994         return ((apr_bucket_file *)last->data)->fd;
995
996     return NULL;
997 }
998
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)
1004 {
1005     apr_status_t s;
1006     apr_bucket_file *f;
1007     apr_off_t wlen;
1008     apr_file_t *file;
1009     apr_off_t in_len, out_len;
1010     apr_bucket *last_in, *last_out;
1011
1012     last_out = APR_BRIGADE_LAST(out);
1013
1014     if (APR_BUCKET_IS_EOS(last_out))
1015         return APR_EOF;
1016
1017     s = apr_brigade_length(out, 0, &out_len);
1018     if (s != APR_SUCCESS)
1019         return s;
1020
1021     /* This cast, when out_len = -1, is intentional */
1022     if ((apr_uint64_t)out_len < heap_limit) {
1023
1024         s = apr_brigade_length(in, 0, &in_len);
1025         if (s != APR_SUCCESS)
1026             return s;
1027
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);
1031             return APR_SUCCESS;
1032         }
1033     }
1034
1035     if (!BUCKET_IS_SPOOL(last_out)) {
1036
1037         s = apreq_file_mktemp(&file, pool, temp_dir);
1038         if (s != APR_SUCCESS)
1039             return s;
1040
1041         s = apreq_brigade_fwrite(file, &wlen, out);
1042
1043         if (s != APR_SUCCESS)
1044             return s;
1045
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);
1050         f = last_out->data;
1051     }
1052     else {
1053         f = last_out->data;
1054         /* Need to seek here, just in case our spool bucket
1055          * was read from between apreq_brigade_concat calls.
1056          */
1057         wlen = last_out->start + last_out->length;
1058         s = apr_file_seek(f->fd, APR_SET, &wlen);
1059         if (s != APR_SUCCESS)
1060             return s;
1061     }
1062
1063     if (in == out)
1064         return APR_SUCCESS;
1065
1066     last_in = APR_BRIGADE_LAST(in);
1067
1068     if (APR_BUCKET_IS_EOS(last_in))
1069         APR_BUCKET_REMOVE(last_in);
1070
1071     s = apreq_brigade_fwrite(f->fd, &wlen, in);
1072
1073     if (s == APR_SUCCESS) {
1074
1075         /* We have to deal with the possibility that the new
1076          * data may be too large to be represented by a single
1077          * temp_file bucket.
1078          */
1079
1080         while ((apr_uint64_t)wlen > FILE_BUCKET_LIMIT - last_out->length) {
1081             apr_bucket *e;
1082
1083             apr_bucket_copy(last_out, &e);
1084             e->length = 0;
1085             e->start = last_out->start + FILE_BUCKET_LIMIT;
1086             wlen -= FILE_BUCKET_LIMIT - last_out->length;
1087             last_out->length = FILE_BUCKET_LIMIT;
1088
1089             /* Copying makes the bucket types exactly the
1090              * opposite of what we need here.
1091              */
1092             last_out->type = &apr_bucket_type_file;
1093             e->type = &spool_bucket_type;
1094
1095             APR_BRIGADE_INSERT_TAIL(out, e);
1096             last_out = e;
1097         }
1098
1099         last_out->length += wlen;
1100
1101         if (APR_BUCKET_IS_EOS(last_in))
1102             APR_BRIGADE_INSERT_TAIL(out, last_in);
1103
1104     }
1105     else if (APR_BUCKET_IS_EOS(last_in))
1106         APR_BRIGADE_INSERT_TAIL(in, last_in);
1107
1108     apr_brigade_cleanup(in);
1109     return s;
1110 }
1111
1112 APREQ_DECLARE(apr_status_t) apreq_brigade_fwrite(apr_file_t *f,
1113                                                  apr_off_t *wlen,
1114                                                  apr_bucket_brigade *bb)
1115 {
1116     struct iovec v[APREQ_DEFAULT_NELTS];
1117     apr_status_t s;
1118     apr_bucket *e, *first;
1119     int n = 0;
1120     apr_bucket_brigade *tmp = bb;
1121     *wlen = 0;
1122
1123     if (BUCKET_IS_SPOOL(APR_BRIGADE_LAST(bb))) {
1124         tmp = apr_brigade_create(bb->p, bb->bucket_alloc);
1125
1126         s = apreq_brigade_copy(tmp, bb);
1127         if (s != APR_SUCCESS)
1128             return s;
1129     }
1130
1131     for (e = APR_BRIGADE_FIRST(tmp); e != APR_BRIGADE_SENTINEL(tmp);
1132          e = APR_BUCKET_NEXT(e))
1133     {
1134         apr_size_t len;
1135         if (n == APREQ_DEFAULT_NELTS) {
1136             s = apreq_fwritev(f, v, &n, &len);
1137             if (s != APR_SUCCESS)
1138                 return s;
1139
1140             if (tmp != bb) {
1141                 while ((first = APR_BRIGADE_FIRST(tmp)) != e)
1142                     apr_bucket_delete(first);
1143             }
1144
1145             *wlen += len;
1146         }
1147         s = apr_bucket_read(e, (const char **)&(v[n].iov_base),
1148                             &len, APR_BLOCK_READ);
1149         if (s != APR_SUCCESS)
1150             return s;
1151
1152         v[n++].iov_len = len;
1153     }
1154
1155     while (n > 0) {
1156         apr_size_t len;
1157         s = apreq_fwritev(f, v, &n, &len);
1158         if (s != APR_SUCCESS)
1159             return s;
1160         *wlen += len;
1161
1162         if (tmp != bb) {
1163             while ((first = APR_BRIGADE_FIRST(tmp)) != e)
1164                 apr_bucket_delete(first);
1165         }
1166     }
1167     return APR_SUCCESS;
1168 }