Annotation of embedaddon/curl/lib/mime.c, revision 1.1.1.1
1.1 misho 1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
9: *
10: * This software is licensed as described in the file COPYING, which
11: * you should have received as part of this distribution. The terms
12: * are also available at https://curl.haxx.se/docs/copyright.html.
13: *
14: * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15: * copies of the Software, and permit persons to whom the Software is
16: * furnished to do so, under the terms of the COPYING file.
17: *
18: * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19: * KIND, either express or implied.
20: *
21: ***************************************************************************/
22:
23: #include "curl_setup.h"
24:
25: #include <curl/curl.h>
26:
27: #include "mime.h"
28: #include "non-ascii.h"
29: #include "warnless.h"
30: #include "urldata.h"
31: #include "sendf.h"
32:
33: #if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \
34: !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP)
35:
36: #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
37: #include <libgen.h>
38: #endif
39:
40: #include "rand.h"
41: #include "slist.h"
42: #include "strcase.h"
43: /* The last 3 #include files should be in this order */
44: #include "curl_printf.h"
45: #include "curl_memory.h"
46: #include "memdebug.h"
47:
48: #ifdef WIN32
49: # ifndef R_OK
50: # define R_OK 4
51: # endif
52: #endif
53:
54:
55: #define READ_ERROR ((size_t) -1)
56: #define STOP_FILLING ((size_t) -2)
57:
58: static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
59: void *instream, bool *hasread);
60:
61: /* Encoders. */
62: static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
63: curl_mimepart *part);
64: static curl_off_t encoder_nop_size(curl_mimepart *part);
65: static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
66: curl_mimepart *part);
67: static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
68: curl_mimepart *part);
69: static curl_off_t encoder_base64_size(curl_mimepart *part);
70: static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
71: curl_mimepart *part);
72: static curl_off_t encoder_qp_size(curl_mimepart *part);
73:
74: static const mime_encoder encoders[] = {
75: {"binary", encoder_nop_read, encoder_nop_size},
76: {"8bit", encoder_nop_read, encoder_nop_size},
77: {"7bit", encoder_7bit_read, encoder_nop_size},
78: {"base64", encoder_base64_read, encoder_base64_size},
79: {"quoted-printable", encoder_qp_read, encoder_qp_size},
80: {ZERO_NULL, ZERO_NULL, ZERO_NULL}
81: };
82:
83: /* Base64 encoding table */
84: static const char base64[] =
85: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
86:
87: /* Quoted-printable character class table.
88: *
89: * We cannot rely on ctype functions since quoted-printable input data
90: * is assumed to be ascii-compatible, even on non-ascii platforms. */
91: #define QP_OK 1 /* Can be represented by itself. */
92: #define QP_SP 2 /* Space or tab. */
93: #define QP_CR 3 /* Carriage return. */
94: #define QP_LF 4 /* Line-feed. */
95: static const unsigned char qp_class[] = {
96: 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */
97: 0, QP_SP, QP_LF, 0, 0, QP_CR, 0, 0, /* 08 - 0F */
98: 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */
99: 0, 0, 0, 0, 0, 0, 0, 0, /* 18 - 1F */
100: QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 20 - 27 */
101: QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 28 - 2F */
102: QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 30 - 37 */
103: QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0 , QP_OK, QP_OK, /* 38 - 3F */
104: QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 40 - 47 */
105: QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 48 - 4F */
106: QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 50 - 57 */
107: QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 58 - 5F */
108: QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 60 - 67 */
109: QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 68 - 6F */
110: QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 70 - 77 */
111: QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0, /* 78 - 7F */
112: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
113: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
114: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
115: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
116: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
117: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
118: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
119: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */
120: };
121:
122:
123: /* Binary --> hexadecimal ASCII table. */
124: static const char aschex[] =
125: "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46";
126:
127:
128:
129: #ifndef __VMS
130: #define filesize(name, stat_data) (stat_data.st_size)
131: #define fopen_read fopen
132:
133: #else
134:
135: #include <fabdef.h>
136: /*
137: * get_vms_file_size does what it takes to get the real size of the file
138: *
139: * For fixed files, find out the size of the EOF block and adjust.
140: *
141: * For all others, have to read the entire file in, discarding the contents.
142: * Most posted text files will be small, and binary files like zlib archives
143: * and CD/DVD images should be either a STREAM_LF format or a fixed format.
144: *
145: */
146: curl_off_t VmsRealFileSize(const char *name,
147: const struct_stat *stat_buf)
148: {
149: char buffer[8192];
150: curl_off_t count;
151: int ret_stat;
152: FILE * file;
153:
154: file = fopen(name, FOPEN_READTEXT); /* VMS */
155: if(file == NULL)
156: return 0;
157:
158: count = 0;
159: ret_stat = 1;
160: while(ret_stat > 0) {
161: ret_stat = fread(buffer, 1, sizeof(buffer), file);
162: if(ret_stat != 0)
163: count += ret_stat;
164: }
165: fclose(file);
166:
167: return count;
168: }
169:
170: /*
171: *
172: * VmsSpecialSize checks to see if the stat st_size can be trusted and
173: * if not to call a routine to get the correct size.
174: *
175: */
176: static curl_off_t VmsSpecialSize(const char *name,
177: const struct_stat *stat_buf)
178: {
179: switch(stat_buf->st_fab_rfm) {
180: case FAB$C_VAR:
181: case FAB$C_VFC:
182: return VmsRealFileSize(name, stat_buf);
183: break;
184: default:
185: return stat_buf->st_size;
186: }
187: }
188:
189: #define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
190:
191: /*
192: * vmsfopenread
193: *
194: * For upload to work as expected on VMS, different optional
195: * parameters must be added to the fopen command based on
196: * record format of the file.
197: *
198: */
199: static FILE * vmsfopenread(const char *file, const char *mode)
200: {
201: struct_stat statbuf;
202: int result;
203:
204: result = stat(file, &statbuf);
205:
206: switch(statbuf.st_fab_rfm) {
207: case FAB$C_VAR:
208: case FAB$C_VFC:
209: case FAB$C_STMCR:
210: return fopen(file, FOPEN_READTEXT); /* VMS */
211: break;
212: default:
213: return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
214: }
215: }
216:
217: #define fopen_read vmsfopenread
218: #endif
219:
220:
221: #ifndef HAVE_BASENAME
222: /*
223: (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
224: Edition)
225:
226: The basename() function shall take the pathname pointed to by path and
227: return a pointer to the final component of the pathname, deleting any
228: trailing '/' characters.
229:
230: If the string pointed to by path consists entirely of the '/' character,
231: basename() shall return a pointer to the string "/". If the string pointed
232: to by path is exactly "//", it is implementation-defined whether '/' or "//"
233: is returned.
234:
235: If path is a null pointer or points to an empty string, basename() shall
236: return a pointer to the string ".".
237:
238: The basename() function may modify the string pointed to by path, and may
239: return a pointer to static storage that may then be overwritten by a
240: subsequent call to basename().
241:
242: The basename() function need not be reentrant. A function that is not
243: required to be reentrant is not required to be thread-safe.
244:
245: */
246: static char *Curl_basename(char *path)
247: {
248: /* Ignore all the details above for now and make a quick and simple
249: implementation here */
250: char *s1;
251: char *s2;
252:
253: s1 = strrchr(path, '/');
254: s2 = strrchr(path, '\\');
255:
256: if(s1 && s2) {
257: path = (s1 > s2? s1 : s2) + 1;
258: }
259: else if(s1)
260: path = s1 + 1;
261: else if(s2)
262: path = s2 + 1;
263:
264: return path;
265: }
266:
267: #define basename(x) Curl_basename((x))
268: #endif
269:
270:
271: /* Set readback state. */
272: static void mimesetstate(mime_state *state, enum mimestate tok, void *ptr)
273: {
274: state->state = tok;
275: state->ptr = ptr;
276: state->offset = 0;
277: }
278:
279:
280: /* Escape header string into allocated memory. */
281: static char *escape_string(const char *src)
282: {
283: size_t bytecount = 0;
284: size_t i;
285: char *dst;
286:
287: for(i = 0; src[i]; i++)
288: if(src[i] == '"' || src[i] == '\\')
289: bytecount++;
290:
291: bytecount += i;
292: dst = malloc(bytecount + 1);
293: if(!dst)
294: return NULL;
295:
296: for(i = 0; *src; src++) {
297: if(*src == '"' || *src == '\\')
298: dst[i++] = '\\';
299: dst[i++] = *src;
300: }
301:
302: dst[i] = '\0';
303: return dst;
304: }
305:
306: /* Check if header matches. */
307: static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
308: {
309: char *value = NULL;
310:
311: if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':')
312: for(value = hdr->data + len + 1; *value == ' '; value++)
313: ;
314: return value;
315: }
316:
317: /* Get a header from an slist. */
318: static char *search_header(struct curl_slist *hdrlist, const char *hdr)
319: {
320: size_t len = strlen(hdr);
321: char *value = NULL;
322:
323: for(; !value && hdrlist; hdrlist = hdrlist->next)
324: value = match_header(hdrlist, hdr, len);
325:
326: return value;
327: }
328:
329: static char *strippath(const char *fullfile)
330: {
331: char *filename;
332: char *base;
333: filename = strdup(fullfile); /* duplicate since basename() may ruin the
334: buffer it works on */
335: if(!filename)
336: return NULL;
337: base = strdup(basename(filename));
338:
339: free(filename); /* free temporary buffer */
340:
341: return base; /* returns an allocated string or NULL ! */
342: }
343:
344: /* Initialize data encoder state. */
345: static void cleanup_encoder_state(mime_encoder_state *p)
346: {
347: p->pos = 0;
348: p->bufbeg = 0;
349: p->bufend = 0;
350: }
351:
352:
353: /* Dummy encoder. This is used for 8bit and binary content encodings. */
354: static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
355: curl_mimepart *part)
356: {
357: mime_encoder_state *st = &part->encstate;
358: size_t insize = st->bufend - st->bufbeg;
359:
360: (void) ateof;
361:
362: if(!size)
363: return STOP_FILLING;
364:
365: if(size > insize)
366: size = insize;
367:
368: if(size)
369: memcpy(buffer, st->buf + st->bufbeg, size);
370:
371: st->bufbeg += size;
372: return size;
373: }
374:
375: static curl_off_t encoder_nop_size(curl_mimepart *part)
376: {
377: return part->datasize;
378: }
379:
380:
381: /* 7bit encoder: the encoder is just a data validity check. */
382: static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
383: curl_mimepart *part)
384: {
385: mime_encoder_state *st = &part->encstate;
386: size_t cursize = st->bufend - st->bufbeg;
387:
388: (void) ateof;
389:
390: if(!size)
391: return STOP_FILLING;
392:
393: if(size > cursize)
394: size = cursize;
395:
396: for(cursize = 0; cursize < size; cursize++) {
397: *buffer = st->buf[st->bufbeg];
398: if(*buffer++ & 0x80)
399: return cursize? cursize: READ_ERROR;
400: st->bufbeg++;
401: }
402:
403: return cursize;
404: }
405:
406:
407: /* Base64 content encoder. */
408: static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
409: curl_mimepart *part)
410: {
411: mime_encoder_state *st = &part->encstate;
412: size_t cursize = 0;
413: int i;
414: char *ptr = buffer;
415:
416: while(st->bufbeg < st->bufend) {
417: /* Line full ? */
418: if(st->pos > MAX_ENCODED_LINE_LENGTH - 4) {
419: /* Yes, we need 2 characters for CRLF. */
420: if(size < 2) {
421: if(!cursize)
422: return STOP_FILLING;
423: break;
424: }
425: *ptr++ = '\r';
426: *ptr++ = '\n';
427: st->pos = 0;
428: cursize += 2;
429: size -= 2;
430: }
431:
432: /* Be sure there is enough space and input data for a base64 group. */
433: if(size < 4) {
434: if(!cursize)
435: return STOP_FILLING;
436: break;
437: }
438: if(st->bufend - st->bufbeg < 3)
439: break;
440:
441: /* Encode three bytes as four characters. */
442: i = st->buf[st->bufbeg++] & 0xFF;
443: i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
444: i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
445: *ptr++ = base64[(i >> 18) & 0x3F];
446: *ptr++ = base64[(i >> 12) & 0x3F];
447: *ptr++ = base64[(i >> 6) & 0x3F];
448: *ptr++ = base64[i & 0x3F];
449: cursize += 4;
450: st->pos += 4;
451: size -= 4;
452: }
453:
454: /* If at eof, we have to flush the buffered data. */
455: if(ateof) {
456: if(size < 4) {
457: if(!cursize)
458: return STOP_FILLING;
459: }
460: else {
461: /* Buffered data size can only be 0, 1 or 2. */
462: ptr[2] = ptr[3] = '=';
463: i = 0;
464: switch(st->bufend - st->bufbeg) {
465: case 2:
466: i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
467: /* FALLTHROUGH */
468: case 1:
469: i |= (st->buf[st->bufbeg] & 0xFF) << 16;
470: ptr[0] = base64[(i >> 18) & 0x3F];
471: ptr[1] = base64[(i >> 12) & 0x3F];
472: if(++st->bufbeg != st->bufend) {
473: ptr[2] = base64[(i >> 6) & 0x3F];
474: st->bufbeg++;
475: }
476: cursize += 4;
477: st->pos += 4;
478: break;
479: }
480: }
481: }
482:
483: #ifdef CURL_DOES_CONVERSIONS
484: /* This is now textual data, Convert character codes. */
485: if(part->easy && cursize) {
486: CURLcode result = Curl_convert_to_network(part->easy, buffer, cursize);
487: if(result)
488: return READ_ERROR;
489: }
490: #endif
491:
492: return cursize;
493: }
494:
495: static curl_off_t encoder_base64_size(curl_mimepart *part)
496: {
497: curl_off_t size = part->datasize;
498:
499: if(size <= 0)
500: return size; /* Unknown size or no data. */
501:
502: /* Compute base64 character count. */
503: size = 4 * (1 + (size - 1) / 3);
504:
505: /* Effective character count must include CRLFs. */
506: return size + 2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH);
507: }
508:
509:
510: /* Quoted-printable lookahead.
511: *
512: * Check if a CRLF or end of data is in input buffer at current position + n.
513: * Return -1 if more data needed, 1 if CRLF or end of data, else 0.
514: */
515: static int qp_lookahead_eol(mime_encoder_state *st, int ateof, size_t n)
516: {
517: n += st->bufbeg;
518: if(n >= st->bufend && ateof)
519: return 1;
520: if(n + 2 > st->bufend)
521: return ateof? 0: -1;
522: if(qp_class[st->buf[n] & 0xFF] == QP_CR &&
523: qp_class[st->buf[n + 1] & 0xFF] == QP_LF)
524: return 1;
525: return 0;
526: }
527:
528: /* Quoted-printable encoder. */
529: static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
530: curl_mimepart *part)
531: {
532: mime_encoder_state *st = &part->encstate;
533: char *ptr = buffer;
534: size_t cursize = 0;
535: int softlinebreak;
536: char buf[4];
537:
538: /* On all platforms, input is supposed to be ASCII compatible: for this
539: reason, we use hexadecimal ASCII codes in this function rather than
540: character constants that can be interpreted as non-ascii on some
541: platforms. Preserve ASCII encoding on output too. */
542: while(st->bufbeg < st->bufend) {
543: size_t len = 1;
544: size_t consumed = 1;
545: int i = st->buf[st->bufbeg];
546: buf[0] = (char) i;
547: buf[1] = aschex[(i >> 4) & 0xF];
548: buf[2] = aschex[i & 0xF];
549:
550: switch(qp_class[st->buf[st->bufbeg] & 0xFF]) {
551: case QP_OK: /* Not a special character. */
552: break;
553: case QP_SP: /* Space or tab. */
554: /* Spacing must be escaped if followed by CRLF. */
555: switch(qp_lookahead_eol(st, ateof, 1)) {
556: case -1: /* More input data needed. */
557: return cursize;
558: case 0: /* No encoding needed. */
559: break;
560: default: /* CRLF after space or tab. */
561: buf[0] = '\x3D'; /* '=' */
562: len = 3;
563: break;
564: }
565: break;
566: case QP_CR: /* Carriage return. */
567: /* If followed by a line-feed, output the CRLF pair.
568: Else escape it. */
569: switch(qp_lookahead_eol(st, ateof, 0)) {
570: case -1: /* Need more data. */
571: return cursize;
572: case 1: /* CRLF found. */
573: buf[len++] = '\x0A'; /* Append '\n'. */
574: consumed = 2;
575: break;
576: default: /* Not followed by LF: escape. */
577: buf[0] = '\x3D'; /* '=' */
578: len = 3;
579: break;
580: }
581: break;
582: default: /* Character must be escaped. */
583: buf[0] = '\x3D'; /* '=' */
584: len = 3;
585: break;
586: }
587:
588: /* Be sure the encoded character fits within maximum line length. */
589: if(buf[len - 1] != '\x0A') { /* '\n' */
590: softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH;
591: if(!softlinebreak && st->pos + len == MAX_ENCODED_LINE_LENGTH) {
592: /* We may use the current line only if end of data or followed by
593: a CRLF. */
594: switch(qp_lookahead_eol(st, ateof, consumed)) {
595: case -1: /* Need more data. */
596: return cursize;
597: break;
598: case 0: /* Not followed by a CRLF. */
599: softlinebreak = 1;
600: break;
601: }
602: }
603: if(softlinebreak) {
604: strcpy(buf, "\x3D\x0D\x0A"); /* "=\r\n" */
605: len = 3;
606: consumed = 0;
607: }
608: }
609:
610: /* If the output buffer would overflow, do not store. */
611: if(len > size) {
612: if(!cursize)
613: return STOP_FILLING;
614: break;
615: }
616:
617: /* Append to output buffer. */
618: memcpy(ptr, buf, len);
619: cursize += len;
620: ptr += len;
621: size -= len;
622: st->pos += len;
623: if(buf[len - 1] == '\x0A') /* '\n' */
624: st->pos = 0;
625: st->bufbeg += consumed;
626: }
627:
628: return cursize;
629: }
630:
631: static curl_off_t encoder_qp_size(curl_mimepart *part)
632: {
633: /* Determining the size can only be done by reading the data: unless the
634: data size is 0, we return it as unknown (-1). */
635: return part->datasize? -1: 0;
636: }
637:
638:
639: /* In-memory data callbacks. */
640: /* Argument is a pointer to the mime part. */
641: static size_t mime_mem_read(char *buffer, size_t size, size_t nitems,
642: void *instream)
643: {
644: curl_mimepart *part = (curl_mimepart *) instream;
645: size_t sz = curlx_sotouz(part->datasize - part->state.offset);
646: (void) size; /* Always 1.*/
647:
648: if(!nitems)
649: return STOP_FILLING;
650:
651: if(sz > nitems)
652: sz = nitems;
653:
654: if(sz)
655: memcpy(buffer, part->data + curlx_sotouz(part->state.offset), sz);
656:
657: return sz;
658: }
659:
660: static int mime_mem_seek(void *instream, curl_off_t offset, int whence)
661: {
662: curl_mimepart *part = (curl_mimepart *) instream;
663:
664: switch(whence) {
665: case SEEK_CUR:
666: offset += part->state.offset;
667: break;
668: case SEEK_END:
669: offset += part->datasize;
670: break;
671: }
672:
673: if(offset < 0 || offset > part->datasize)
674: return CURL_SEEKFUNC_FAIL;
675:
676: part->state.offset = offset;
677: return CURL_SEEKFUNC_OK;
678: }
679:
680: static void mime_mem_free(void *ptr)
681: {
682: Curl_safefree(((curl_mimepart *) ptr)->data);
683: }
684:
685:
686: /* Named file callbacks. */
687: /* Argument is a pointer to the mime part. */
688: static int mime_open_file(curl_mimepart * part)
689: {
690: /* Open a MIMEKIND_FILE part. */
691:
692: if(part->fp)
693: return 0;
694: part->fp = fopen_read(part->data, "rb");
695: return part->fp? 0: -1;
696: }
697:
698: static size_t mime_file_read(char *buffer, size_t size, size_t nitems,
699: void *instream)
700: {
701: curl_mimepart *part = (curl_mimepart *) instream;
702:
703: if(!nitems)
704: return STOP_FILLING;
705:
706: if(mime_open_file(part))
707: return READ_ERROR;
708:
709: return fread(buffer, size, nitems, part->fp);
710: }
711:
712: static int mime_file_seek(void *instream, curl_off_t offset, int whence)
713: {
714: curl_mimepart *part = (curl_mimepart *) instream;
715:
716: if(whence == SEEK_SET && !offset && !part->fp)
717: return CURL_SEEKFUNC_OK; /* Not open: implicitly already at BOF. */
718:
719: if(mime_open_file(part))
720: return CURL_SEEKFUNC_FAIL;
721:
722: return fseek(part->fp, (long) offset, whence)?
723: CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK;
724: }
725:
726: static void mime_file_free(void *ptr)
727: {
728: curl_mimepart *part = (curl_mimepart *) ptr;
729:
730: if(part->fp) {
731: fclose(part->fp);
732: part->fp = NULL;
733: }
734: Curl_safefree(part->data);
735: part->data = NULL;
736: }
737:
738:
739: /* Subparts callbacks. */
740: /* Argument is a pointer to the mime structure. */
741:
742: /* Readback a byte string segment. */
743: static size_t readback_bytes(mime_state *state,
744: char *buffer, size_t bufsize,
745: const char *bytes, size_t numbytes,
746: const char *trail)
747: {
748: size_t sz;
749: size_t offset = curlx_sotouz(state->offset);
750:
751: if(numbytes > offset) {
752: sz = numbytes - offset;
753: bytes += offset;
754: }
755: else {
756: size_t tsz = strlen(trail);
757:
758: sz = offset - numbytes;
759: if(sz >= tsz)
760: return 0;
761: bytes = trail + sz;
762: sz = tsz - sz;
763: }
764:
765: if(sz > bufsize)
766: sz = bufsize;
767:
768: memcpy(buffer, bytes, sz);
769: state->offset += sz;
770: return sz;
771: }
772:
773: /* Read a non-encoded part content. */
774: static size_t read_part_content(curl_mimepart *part,
775: char *buffer, size_t bufsize, bool *hasread)
776: {
777: size_t sz = 0;
778:
779: switch(part->lastreadstatus) {
780: case 0:
781: case CURL_READFUNC_ABORT:
782: case CURL_READFUNC_PAUSE:
783: case READ_ERROR:
784: return part->lastreadstatus;
785: default:
786: break;
787: }
788:
789: /* If we can determine we are at end of part data, spare a read. */
790: if(part->datasize != (curl_off_t) -1 &&
791: part->state.offset >= part->datasize) {
792: /* sz is already zero. */
793: }
794: else {
795: switch(part->kind) {
796: case MIMEKIND_MULTIPART:
797: /*
798: * Cannot be processed as other kinds since read function requires
799: * an additional parameter and is highly recursive.
800: */
801: sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread);
802: break;
803: case MIMEKIND_FILE:
804: if(part->fp && feof(part->fp))
805: break; /* At EOF. */
806: /* FALLTHROUGH */
807: default:
808: if(part->readfunc) {
809: if(!(part->flags & MIME_FAST_READ)) {
810: if(*hasread)
811: return STOP_FILLING;
812: *hasread = TRUE;
813: }
814: sz = part->readfunc(buffer, 1, bufsize, part->arg);
815: }
816: break;
817: }
818: }
819:
820: switch(sz) {
821: case STOP_FILLING:
822: break;
823: case 0:
824: case CURL_READFUNC_ABORT:
825: case CURL_READFUNC_PAUSE:
826: case READ_ERROR:
827: part->lastreadstatus = sz;
828: break;
829: default:
830: part->state.offset += sz;
831: part->lastreadstatus = sz;
832: break;
833: }
834:
835: return sz;
836: }
837:
838: /* Read and encode part content. */
839: static size_t read_encoded_part_content(curl_mimepart *part, char *buffer,
840: size_t bufsize, bool *hasread)
841: {
842: mime_encoder_state *st = &part->encstate;
843: size_t cursize = 0;
844: size_t sz;
845: bool ateof = FALSE;
846:
847: for(;;) {
848: if(st->bufbeg < st->bufend || ateof) {
849: /* Encode buffered data. */
850: sz = part->encoder->encodefunc(buffer, bufsize, ateof, part);
851: switch(sz) {
852: case 0:
853: if(ateof)
854: return cursize;
855: break;
856: case READ_ERROR:
857: case STOP_FILLING:
858: return cursize? cursize: sz;
859: default:
860: cursize += sz;
861: buffer += sz;
862: bufsize -= sz;
863: continue;
864: }
865: }
866:
867: /* We need more data in input buffer. */
868: if(st->bufbeg) {
869: size_t len = st->bufend - st->bufbeg;
870:
871: if(len)
872: memmove(st->buf, st->buf + st->bufbeg, len);
873: st->bufbeg = 0;
874: st->bufend = len;
875: }
876: if(st->bufend >= sizeof(st->buf))
877: return cursize? cursize: READ_ERROR; /* Buffer full. */
878: sz = read_part_content(part, st->buf + st->bufend,
879: sizeof(st->buf) - st->bufend, hasread);
880: switch(sz) {
881: case 0:
882: ateof = TRUE;
883: break;
884: case CURL_READFUNC_ABORT:
885: case CURL_READFUNC_PAUSE:
886: case READ_ERROR:
887: case STOP_FILLING:
888: return cursize? cursize: sz;
889: default:
890: st->bufend += sz;
891: break;
892: }
893: }
894:
895: /* NOTREACHED */
896: }
897:
898: /* Readback a mime part. */
899: static size_t readback_part(curl_mimepart *part,
900: char *buffer, size_t bufsize, bool *hasread)
901: {
902: size_t cursize = 0;
903: #ifdef CURL_DOES_CONVERSIONS
904: char *convbuf = buffer;
905: #endif
906:
907: /* Readback from part. */
908:
909: while(bufsize) {
910: size_t sz = 0;
911: struct curl_slist *hdr = (struct curl_slist *) part->state.ptr;
912: switch(part->state.state) {
913: case MIMESTATE_BEGIN:
914: mimesetstate(&part->state,
915: (part->flags & MIME_BODY_ONLY)?
916: MIMESTATE_BODY: MIMESTATE_CURLHEADERS,
917: part->curlheaders);
918: break;
919: case MIMESTATE_USERHEADERS:
920: if(!hdr) {
921: mimesetstate(&part->state, MIMESTATE_EOH, NULL);
922: break;
923: }
924: if(match_header(hdr, "Content-Type", 12)) {
925: mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next);
926: break;
927: }
928: /* FALLTHROUGH */
929: case MIMESTATE_CURLHEADERS:
930: if(!hdr)
931: mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
932: else {
933: sz = readback_bytes(&part->state, buffer, bufsize,
934: hdr->data, strlen(hdr->data), "\r\n");
935: if(!sz)
936: mimesetstate(&part->state, part->state.state, hdr->next);
937: }
938: break;
939: case MIMESTATE_EOH:
940: sz = readback_bytes(&part->state, buffer, bufsize, "\r\n", 2, "");
941: if(!sz)
942: mimesetstate(&part->state, MIMESTATE_BODY, NULL);
943: break;
944: case MIMESTATE_BODY:
945: #ifdef CURL_DOES_CONVERSIONS
946: if(part->easy && convbuf < buffer) {
947: CURLcode result = Curl_convert_to_network(part->easy, convbuf,
948: buffer - convbuf);
949: if(result)
950: return READ_ERROR;
951: convbuf = buffer;
952: }
953: #endif
954: cleanup_encoder_state(&part->encstate);
955: mimesetstate(&part->state, MIMESTATE_CONTENT, NULL);
956: break;
957: case MIMESTATE_CONTENT:
958: if(part->encoder)
959: sz = read_encoded_part_content(part, buffer, bufsize, hasread);
960: else
961: sz = read_part_content(part, buffer, bufsize, hasread);
962: switch(sz) {
963: case 0:
964: mimesetstate(&part->state, MIMESTATE_END, NULL);
965: /* Try sparing open file descriptors. */
966: if(part->kind == MIMEKIND_FILE && part->fp) {
967: fclose(part->fp);
968: part->fp = NULL;
969: }
970: /* FALLTHROUGH */
971: case CURL_READFUNC_ABORT:
972: case CURL_READFUNC_PAUSE:
973: case READ_ERROR:
974: case STOP_FILLING:
975: return cursize? cursize: sz;
976: }
977: break;
978: case MIMESTATE_END:
979: return cursize;
980: default:
981: break; /* Other values not in part state. */
982: }
983:
984: /* Bump buffer and counters according to read size. */
985: cursize += sz;
986: buffer += sz;
987: bufsize -= sz;
988: }
989:
990: #ifdef CURL_DOES_CONVERSIONS
991: if(part->easy && convbuf < buffer &&
992: part->state.state < MIMESTATE_BODY) {
993: CURLcode result = Curl_convert_to_network(part->easy, convbuf,
994: buffer - convbuf);
995: if(result)
996: return READ_ERROR;
997: }
998: #endif
999:
1000: return cursize;
1001: }
1002:
1003: /* Readback from mime. Warning: not a read callback function. */
1004: static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
1005: void *instream, bool *hasread)
1006: {
1007: curl_mime *mime = (curl_mime *) instream;
1008: size_t cursize = 0;
1009: #ifdef CURL_DOES_CONVERSIONS
1010: char *convbuf = buffer;
1011: #endif
1012:
1013: (void) size; /* Always 1. */
1014:
1015: while(nitems) {
1016: size_t sz = 0;
1017: curl_mimepart *part = mime->state.ptr;
1018: switch(mime->state.state) {
1019: case MIMESTATE_BEGIN:
1020: case MIMESTATE_BODY:
1021: #ifdef CURL_DOES_CONVERSIONS
1022: convbuf = buffer;
1023: #endif
1024: mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, mime->firstpart);
1025: /* The first boundary always follows the header termination empty line,
1026: so is always preceded by a CRLF. We can then spare 2 characters
1027: by skipping the leading CRLF in boundary. */
1028: mime->state.offset += 2;
1029: break;
1030: case MIMESTATE_BOUNDARY1:
1031: sz = readback_bytes(&mime->state, buffer, nitems, "\r\n--", 4, "");
1032: if(!sz)
1033: mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part);
1034: break;
1035: case MIMESTATE_BOUNDARY2:
1036: sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
1037: strlen(mime->boundary), part? "\r\n": "--\r\n");
1038: if(!sz) {
1039: #ifdef CURL_DOES_CONVERSIONS
1040: if(mime->easy && convbuf < buffer) {
1041: CURLcode result = Curl_convert_to_network(mime->easy, convbuf,
1042: buffer - convbuf);
1043: if(result)
1044: return READ_ERROR;
1045: convbuf = buffer;
1046: }
1047: #endif
1048: mimesetstate(&mime->state, MIMESTATE_CONTENT, part);
1049: }
1050: break;
1051: case MIMESTATE_CONTENT:
1052: if(!part) {
1053: mimesetstate(&mime->state, MIMESTATE_END, NULL);
1054: break;
1055: }
1056: sz = readback_part(part, buffer, nitems, hasread);
1057: switch(sz) {
1058: case CURL_READFUNC_ABORT:
1059: case CURL_READFUNC_PAUSE:
1060: case READ_ERROR:
1061: case STOP_FILLING:
1062: return cursize? cursize: sz;
1063: case 0:
1064: #ifdef CURL_DOES_CONVERSIONS
1065: convbuf = buffer;
1066: #endif
1067: mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart);
1068: break;
1069: }
1070: break;
1071: case MIMESTATE_END:
1072: return cursize;
1073: default:
1074: break; /* other values not used in mime state. */
1075: }
1076:
1077: /* Bump buffer and counters according to read size. */
1078: cursize += sz;
1079: buffer += sz;
1080: nitems -= sz;
1081: }
1082:
1083: #ifdef CURL_DOES_CONVERSIONS
1084: if(mime->easy && convbuf < buffer &&
1085: mime->state.state <= MIMESTATE_CONTENT) {
1086: CURLcode result = Curl_convert_to_network(mime->easy, convbuf,
1087: buffer - convbuf);
1088: if(result)
1089: return READ_ERROR;
1090: }
1091: #endif
1092:
1093: return cursize;
1094: }
1095:
1096: static int mime_part_rewind(curl_mimepart *part)
1097: {
1098: int res = CURL_SEEKFUNC_OK;
1099: enum mimestate targetstate = MIMESTATE_BEGIN;
1100:
1101: if(part->flags & MIME_BODY_ONLY)
1102: targetstate = MIMESTATE_BODY;
1103: cleanup_encoder_state(&part->encstate);
1104: if(part->state.state > targetstate) {
1105: res = CURL_SEEKFUNC_CANTSEEK;
1106: if(part->seekfunc) {
1107: res = part->seekfunc(part->arg, (curl_off_t) 0, SEEK_SET);
1108: switch(res) {
1109: case CURL_SEEKFUNC_OK:
1110: case CURL_SEEKFUNC_FAIL:
1111: case CURL_SEEKFUNC_CANTSEEK:
1112: break;
1113: case -1: /* For fseek() error. */
1114: res = CURL_SEEKFUNC_CANTSEEK;
1115: break;
1116: default:
1117: res = CURL_SEEKFUNC_FAIL;
1118: break;
1119: }
1120: }
1121: }
1122:
1123: if(res == CURL_SEEKFUNC_OK)
1124: mimesetstate(&part->state, targetstate, NULL);
1125:
1126: part->lastreadstatus = 1; /* Successful read status. */
1127: return res;
1128: }
1129:
1130: static int mime_subparts_seek(void *instream, curl_off_t offset, int whence)
1131: {
1132: curl_mime *mime = (curl_mime *) instream;
1133: curl_mimepart *part;
1134: int result = CURL_SEEKFUNC_OK;
1135:
1136: if(whence != SEEK_SET || offset)
1137: return CURL_SEEKFUNC_CANTSEEK; /* Only support full rewind. */
1138:
1139: if(mime->state.state == MIMESTATE_BEGIN)
1140: return CURL_SEEKFUNC_OK; /* Already rewound. */
1141:
1142: for(part = mime->firstpart; part; part = part->nextpart) {
1143: int res = mime_part_rewind(part);
1144: if(res != CURL_SEEKFUNC_OK)
1145: result = res;
1146: }
1147:
1148: if(result == CURL_SEEKFUNC_OK)
1149: mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1150:
1151: return result;
1152: }
1153:
1154: /* Release part content. */
1155: static void cleanup_part_content(curl_mimepart *part)
1156: {
1157: if(part->freefunc)
1158: part->freefunc(part->arg);
1159:
1160: part->readfunc = NULL;
1161: part->seekfunc = NULL;
1162: part->freefunc = NULL;
1163: part->arg = (void *) part; /* Defaults to part itself. */
1164: part->data = NULL;
1165: part->fp = NULL;
1166: part->datasize = (curl_off_t) 0; /* No size yet. */
1167: cleanup_encoder_state(&part->encstate);
1168: part->kind = MIMEKIND_NONE;
1169: part->flags &= ~MIME_FAST_READ;
1170: part->lastreadstatus = 1; /* Successful read status. */
1171: }
1172:
1173: static void mime_subparts_free(void *ptr)
1174: {
1175: curl_mime *mime = (curl_mime *) ptr;
1176:
1177: if(mime && mime->parent) {
1178: mime->parent->freefunc = NULL; /* Be sure we won't be called again. */
1179: cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */
1180: }
1181: curl_mime_free(mime);
1182: }
1183:
1184: /* Do not free subparts: unbind them. This is used for the top level only. */
1185: static void mime_subparts_unbind(void *ptr)
1186: {
1187: curl_mime *mime = (curl_mime *) ptr;
1188:
1189: if(mime && mime->parent) {
1190: mime->parent->freefunc = NULL; /* Be sure we won't be called again. */
1191: cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */
1192: mime->parent = NULL;
1193: }
1194: }
1195:
1196:
1197: void Curl_mime_cleanpart(curl_mimepart *part)
1198: {
1199: cleanup_part_content(part);
1200: curl_slist_free_all(part->curlheaders);
1201: if(part->flags & MIME_USERHEADERS_OWNER)
1202: curl_slist_free_all(part->userheaders);
1203: Curl_safefree(part->mimetype);
1204: Curl_safefree(part->name);
1205: Curl_safefree(part->filename);
1206: Curl_mime_initpart(part, part->easy);
1207: }
1208:
1209: /* Recursively delete a mime handle and its parts. */
1210: void curl_mime_free(curl_mime *mime)
1211: {
1212: curl_mimepart *part;
1213:
1214: if(mime) {
1215: mime_subparts_unbind(mime); /* Be sure it's not referenced anymore. */
1216: while(mime->firstpart) {
1217: part = mime->firstpart;
1218: mime->firstpart = part->nextpart;
1219: Curl_mime_cleanpart(part);
1220: free(part);
1221: }
1222: free(mime);
1223: }
1224: }
1225:
1226: CURLcode Curl_mime_duppart(curl_mimepart *dst, const curl_mimepart *src)
1227: {
1228: curl_mime *mime;
1229: curl_mimepart *d;
1230: const curl_mimepart *s;
1231: CURLcode res = CURLE_OK;
1232:
1233: DEBUGASSERT(dst);
1234:
1235: /* Duplicate content. */
1236: switch(src->kind) {
1237: case MIMEKIND_NONE:
1238: break;
1239: case MIMEKIND_DATA:
1240: res = curl_mime_data(dst, src->data, (size_t) src->datasize);
1241: break;
1242: case MIMEKIND_FILE:
1243: res = curl_mime_filedata(dst, src->data);
1244: /* Do not abort duplication if file is not readable. */
1245: if(res == CURLE_READ_ERROR)
1246: res = CURLE_OK;
1247: break;
1248: case MIMEKIND_CALLBACK:
1249: res = curl_mime_data_cb(dst, src->datasize, src->readfunc,
1250: src->seekfunc, src->freefunc, src->arg);
1251: break;
1252: case MIMEKIND_MULTIPART:
1253: /* No one knows about the cloned subparts, thus always attach ownership
1254: to the part. */
1255: mime = curl_mime_init(dst->easy);
1256: res = mime? curl_mime_subparts(dst, mime): CURLE_OUT_OF_MEMORY;
1257:
1258: /* Duplicate subparts. */
1259: for(s = ((curl_mime *) src->arg)->firstpart; !res && s; s = s->nextpart) {
1260: d = curl_mime_addpart(mime);
1261: res = d? Curl_mime_duppart(d, s): CURLE_OUT_OF_MEMORY;
1262: }
1263: break;
1264: default: /* Invalid kind: should not occur. */
1265: res = CURLE_BAD_FUNCTION_ARGUMENT; /* Internal error? */
1266: break;
1267: }
1268:
1269: /* Duplicate headers. */
1270: if(!res && src->userheaders) {
1271: struct curl_slist *hdrs = Curl_slist_duplicate(src->userheaders);
1272:
1273: if(!hdrs)
1274: res = CURLE_OUT_OF_MEMORY;
1275: else {
1276: /* No one but this procedure knows about the new header list,
1277: so always take ownership. */
1278: res = curl_mime_headers(dst, hdrs, TRUE);
1279: if(res)
1280: curl_slist_free_all(hdrs);
1281: }
1282: }
1283:
1284: if(!res) {
1285: /* Duplicate other fields. */
1286: dst->encoder = src->encoder;
1287: res = curl_mime_type(dst, src->mimetype);
1288: }
1289: if(!res)
1290: res = curl_mime_name(dst, src->name);
1291: if(!res)
1292: res = curl_mime_filename(dst, src->filename);
1293:
1294: /* If an error occurred, rollback. */
1295: if(res)
1296: Curl_mime_cleanpart(dst);
1297:
1298: return res;
1299: }
1300:
1301: /*
1302: * Mime build functions.
1303: */
1304:
1305: /* Create a mime handle. */
1306: curl_mime *curl_mime_init(struct Curl_easy *easy)
1307: {
1308: curl_mime *mime;
1309:
1310: mime = (curl_mime *) malloc(sizeof(*mime));
1311:
1312: if(mime) {
1313: mime->easy = easy;
1314: mime->parent = NULL;
1315: mime->firstpart = NULL;
1316: mime->lastpart = NULL;
1317:
1318: memset(mime->boundary, '-', 24);
1319: if(Curl_rand_hex(easy, (unsigned char *) &mime->boundary[24],
1320: MIME_RAND_BOUNDARY_CHARS + 1)) {
1321: /* failed to get random separator, bail out */
1322: free(mime);
1323: return NULL;
1324: }
1325: mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1326: }
1327:
1328: return mime;
1329: }
1330:
1331: /* Initialize a mime part. */
1332: void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy)
1333: {
1334: memset((char *) part, 0, sizeof(*part));
1335: part->easy = easy;
1336: part->lastreadstatus = 1; /* Successful read status. */
1337: mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
1338: }
1339:
1340: /* Create a mime part and append it to a mime handle's part list. */
1341: curl_mimepart *curl_mime_addpart(curl_mime *mime)
1342: {
1343: curl_mimepart *part;
1344:
1345: if(!mime)
1346: return NULL;
1347:
1348: part = (curl_mimepart *) malloc(sizeof(*part));
1349:
1350: if(part) {
1351: Curl_mime_initpart(part, mime->easy);
1352: part->parent = mime;
1353:
1354: if(mime->lastpart)
1355: mime->lastpart->nextpart = part;
1356: else
1357: mime->firstpart = part;
1358:
1359: mime->lastpart = part;
1360: }
1361:
1362: return part;
1363: }
1364:
1365: /* Set mime part name. */
1366: CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1367: {
1368: if(!part)
1369: return CURLE_BAD_FUNCTION_ARGUMENT;
1370:
1371: Curl_safefree(part->name);
1372: part->name = NULL;
1373:
1374: if(name) {
1375: part->name = strdup(name);
1376: if(!part->name)
1377: return CURLE_OUT_OF_MEMORY;
1378: }
1379:
1380: return CURLE_OK;
1381: }
1382:
1383: /* Set mime part remote file name. */
1384: CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1385: {
1386: if(!part)
1387: return CURLE_BAD_FUNCTION_ARGUMENT;
1388:
1389: Curl_safefree(part->filename);
1390: part->filename = NULL;
1391:
1392: if(filename) {
1393: part->filename = strdup(filename);
1394: if(!part->filename)
1395: return CURLE_OUT_OF_MEMORY;
1396: }
1397:
1398: return CURLE_OK;
1399: }
1400:
1401: /* Set mime part content from memory data. */
1402: CURLcode curl_mime_data(curl_mimepart *part,
1403: const char *data, size_t datasize)
1404: {
1405: if(!part)
1406: return CURLE_BAD_FUNCTION_ARGUMENT;
1407:
1408: cleanup_part_content(part);
1409:
1410: if(data) {
1411: if(datasize == CURL_ZERO_TERMINATED)
1412: datasize = strlen(data);
1413:
1414: part->data = malloc(datasize + 1);
1415: if(!part->data)
1416: return CURLE_OUT_OF_MEMORY;
1417:
1418: part->datasize = datasize;
1419:
1420: if(datasize)
1421: memcpy(part->data, data, datasize);
1422: part->data[datasize] = '\0'; /* Set a nul terminator as sentinel. */
1423:
1424: part->readfunc = mime_mem_read;
1425: part->seekfunc = mime_mem_seek;
1426: part->freefunc = mime_mem_free;
1427: part->flags |= MIME_FAST_READ;
1428: part->kind = MIMEKIND_DATA;
1429: }
1430:
1431: return CURLE_OK;
1432: }
1433:
1434: /* Set mime part content from named local file. */
1435: CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1436: {
1437: CURLcode result = CURLE_OK;
1438:
1439: if(!part)
1440: return CURLE_BAD_FUNCTION_ARGUMENT;
1441:
1442: cleanup_part_content(part);
1443:
1444: if(filename) {
1445: char *base;
1446: struct_stat sbuf;
1447:
1448: if(stat(filename, &sbuf) || access(filename, R_OK))
1449: result = CURLE_READ_ERROR;
1450:
1451: part->data = strdup(filename);
1452: if(!part->data)
1453: result = CURLE_OUT_OF_MEMORY;
1454:
1455: part->datasize = -1;
1456: if(!result && S_ISREG(sbuf.st_mode)) {
1457: part->datasize = filesize(filename, sbuf);
1458: part->seekfunc = mime_file_seek;
1459: }
1460:
1461: part->readfunc = mime_file_read;
1462: part->freefunc = mime_file_free;
1463: part->kind = MIMEKIND_FILE;
1464:
1465: /* As a side effect, set the filename to the current file's base name.
1466: It is possible to withdraw this by explicitly calling
1467: curl_mime_filename() with a NULL filename argument after the current
1468: call. */
1469: base = strippath(filename);
1470: if(!base)
1471: result = CURLE_OUT_OF_MEMORY;
1472: else {
1473: CURLcode res = curl_mime_filename(part, base);
1474:
1475: if(res)
1476: result = res;
1477: free(base);
1478: }
1479: }
1480: return result;
1481: }
1482:
1483: /* Set mime part type. */
1484: CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1485: {
1486: if(!part)
1487: return CURLE_BAD_FUNCTION_ARGUMENT;
1488:
1489: Curl_safefree(part->mimetype);
1490: part->mimetype = NULL;
1491:
1492: if(mimetype) {
1493: part->mimetype = strdup(mimetype);
1494: if(!part->mimetype)
1495: return CURLE_OUT_OF_MEMORY;
1496: }
1497:
1498: return CURLE_OK;
1499: }
1500:
1501: /* Set mime data transfer encoder. */
1502: CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1503: {
1504: CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
1505: const mime_encoder *mep;
1506:
1507: if(!part)
1508: return result;
1509:
1510: part->encoder = NULL;
1511:
1512: if(!encoding)
1513: return CURLE_OK; /* Removing current encoder. */
1514:
1515: for(mep = encoders; mep->name; mep++)
1516: if(strcasecompare(encoding, mep->name)) {
1517: part->encoder = mep;
1518: result = CURLE_OK;
1519: }
1520:
1521: return result;
1522: }
1523:
1524: /* Set mime part headers. */
1525: CURLcode curl_mime_headers(curl_mimepart *part,
1526: struct curl_slist *headers, int take_ownership)
1527: {
1528: if(!part)
1529: return CURLE_BAD_FUNCTION_ARGUMENT;
1530:
1531: if(part->flags & MIME_USERHEADERS_OWNER) {
1532: if(part->userheaders != headers) /* Allow setting twice the same list. */
1533: curl_slist_free_all(part->userheaders);
1534: part->flags &= ~MIME_USERHEADERS_OWNER;
1535: }
1536: part->userheaders = headers;
1537: if(headers && take_ownership)
1538: part->flags |= MIME_USERHEADERS_OWNER;
1539: return CURLE_OK;
1540: }
1541:
1542: /* Set mime part content from callback. */
1543: CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize,
1544: curl_read_callback readfunc,
1545: curl_seek_callback seekfunc,
1546: curl_free_callback freefunc, void *arg)
1547: {
1548: if(!part)
1549: return CURLE_BAD_FUNCTION_ARGUMENT;
1550:
1551: cleanup_part_content(part);
1552:
1553: if(readfunc) {
1554: part->readfunc = readfunc;
1555: part->seekfunc = seekfunc;
1556: part->freefunc = freefunc;
1557: part->arg = arg;
1558: part->datasize = datasize;
1559: part->kind = MIMEKIND_CALLBACK;
1560: }
1561:
1562: return CURLE_OK;
1563: }
1564:
1565: /* Set mime part content from subparts. */
1566: CURLcode Curl_mime_set_subparts(curl_mimepart *part,
1567: curl_mime *subparts, int take_ownership)
1568: {
1569: curl_mime *root;
1570:
1571: if(!part)
1572: return CURLE_BAD_FUNCTION_ARGUMENT;
1573:
1574: /* Accept setting twice the same subparts. */
1575: if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
1576: return CURLE_OK;
1577:
1578: cleanup_part_content(part);
1579:
1580: if(subparts) {
1581: /* Must belong to the same data handle. */
1582: if(part->easy && subparts->easy && part->easy != subparts->easy)
1583: return CURLE_BAD_FUNCTION_ARGUMENT;
1584:
1585: /* Should not have been attached already. */
1586: if(subparts->parent)
1587: return CURLE_BAD_FUNCTION_ARGUMENT;
1588:
1589: /* Should not be the part's root. */
1590: root = part->parent;
1591: if(root) {
1592: while(root->parent && root->parent->parent)
1593: root = root->parent->parent;
1594: if(subparts == root) {
1595: if(part->easy)
1596: failf(part->easy, "Can't add itself as a subpart!");
1597: return CURLE_BAD_FUNCTION_ARGUMENT;
1598: }
1599: }
1600:
1601: subparts->parent = part;
1602: /* Subparts are processed internally: no read callback. */
1603: part->seekfunc = mime_subparts_seek;
1604: part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind;
1605: part->arg = subparts;
1606: part->datasize = -1;
1607: part->kind = MIMEKIND_MULTIPART;
1608: }
1609:
1610: return CURLE_OK;
1611: }
1612:
1613: CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
1614: {
1615: return Curl_mime_set_subparts(part, subparts, TRUE);
1616: }
1617:
1618:
1619: /* Readback from top mime. */
1620: /* Argument is the dummy top part. */
1621: size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
1622: {
1623: curl_mimepart *part = (curl_mimepart *) instream;
1624: size_t ret;
1625: bool hasread;
1626:
1627: (void) size; /* Always 1. */
1628:
1629: do {
1630: hasread = FALSE;
1631: ret = readback_part(part, buffer, nitems, &hasread);
1632: /*
1633: * If this is not possible to get some data without calling more than
1634: * one read callback (probably because a content encoder is not able to
1635: * deliver a new bunch for the few data accumulated so far), force another
1636: * read until we get enough data or a special exit code.
1637: */
1638: } while(ret == STOP_FILLING);
1639:
1640: return ret;
1641: }
1642:
1643: /* Rewind mime stream. */
1644: CURLcode Curl_mime_rewind(curl_mimepart *part)
1645: {
1646: return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
1647: CURLE_OK: CURLE_SEND_FAIL_REWIND;
1648: }
1649:
1650: /* Compute header list size. */
1651: static size_t slist_size(struct curl_slist *s,
1652: size_t overhead, const char *skip)
1653: {
1654: size_t size = 0;
1655: size_t skiplen = skip? strlen(skip): 0;
1656:
1657: for(; s; s = s->next)
1658: if(!skip || !match_header(s, skip, skiplen))
1659: size += strlen(s->data) + overhead;
1660: return size;
1661: }
1662:
1663: /* Get/compute multipart size. */
1664: static curl_off_t multipart_size(curl_mime *mime)
1665: {
1666: curl_off_t size;
1667: size_t boundarysize;
1668: curl_mimepart *part;
1669:
1670: if(!mime)
1671: return 0; /* Not present -> empty. */
1672:
1673: boundarysize = 4 + strlen(mime->boundary) + 2;
1674: size = boundarysize; /* Final boundary - CRLF after headers. */
1675:
1676: for(part = mime->firstpart; part; part = part->nextpart) {
1677: curl_off_t sz = Curl_mime_size(part);
1678:
1679: if(sz < 0)
1680: size = sz;
1681:
1682: if(size >= 0)
1683: size += boundarysize + sz;
1684: }
1685:
1686: return size;
1687: }
1688:
1689: /* Get/compute mime size. */
1690: curl_off_t Curl_mime_size(curl_mimepart *part)
1691: {
1692: curl_off_t size;
1693:
1694: if(part->kind == MIMEKIND_MULTIPART)
1695: part->datasize = multipart_size(part->arg);
1696:
1697: size = part->datasize;
1698:
1699: if(part->encoder)
1700: size = part->encoder->sizefunc(part);
1701:
1702: if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
1703: /* Compute total part size. */
1704: size += slist_size(part->curlheaders, 2, NULL);
1705: size += slist_size(part->userheaders, 2, "Content-Type");
1706: size += 2; /* CRLF after headers. */
1707: }
1708: return size;
1709: }
1710:
1711: /* Add a header. */
1712: /* VARARGS2 */
1713: CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
1714: {
1715: struct curl_slist *hdr = NULL;
1716: char *s = NULL;
1717: va_list ap;
1718:
1719: va_start(ap, fmt);
1720: s = curl_mvaprintf(fmt, ap);
1721: va_end(ap);
1722:
1723: if(s) {
1724: hdr = Curl_slist_append_nodup(*slp, s);
1725: if(hdr)
1726: *slp = hdr;
1727: else
1728: free(s);
1729: }
1730:
1731: return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY;
1732: }
1733:
1734: /* Add a content type header. */
1735: static CURLcode add_content_type(struct curl_slist **slp,
1736: const char *type, const char *boundary)
1737: {
1738: return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
1739: boundary? "; boundary=": "",
1740: boundary? boundary: "");
1741: }
1742:
1743: const char *Curl_mime_contenttype(const char *filename)
1744: {
1745: /*
1746: * If no content type was specified, we scan through a few well-known
1747: * extensions and pick the first we match!
1748: */
1749: struct ContentType {
1750: const char *extension;
1751: const char *type;
1752: };
1753: static const struct ContentType ctts[] = {
1754: {".gif", "image/gif"},
1755: {".jpg", "image/jpeg"},
1756: {".jpeg", "image/jpeg"},
1757: {".png", "image/png"},
1758: {".svg", "image/svg+xml"},
1759: {".txt", "text/plain"},
1760: {".htm", "text/html"},
1761: {".html", "text/html"},
1762: {".pdf", "application/pdf"},
1763: {".xml", "application/xml"}
1764: };
1765:
1766: if(filename) {
1767: size_t len1 = strlen(filename);
1768: const char *nameend = filename + len1;
1769: unsigned int i;
1770:
1771: for(i = 0; i < sizeof(ctts) / sizeof(ctts[0]); i++) {
1772: size_t len2 = strlen(ctts[i].extension);
1773:
1774: if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension))
1775: return ctts[i].type;
1776: }
1777: }
1778: return NULL;
1779: }
1780:
1781: static bool content_type_match(const char *contenttype, const char *target)
1782: {
1783: size_t len = strlen(target);
1784:
1785: if(contenttype && strncasecompare(contenttype, target, len))
1786: switch(contenttype[len]) {
1787: case '\0':
1788: case '\t':
1789: case '\r':
1790: case '\n':
1791: case ' ':
1792: case ';':
1793: return TRUE;
1794: }
1795: return FALSE;
1796: }
1797:
1798: CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
1799: const char *contenttype,
1800: const char *disposition,
1801: enum mimestrategy strategy)
1802: {
1803: curl_mime *mime = NULL;
1804: const char *boundary = NULL;
1805: char *customct;
1806: const char *cte = NULL;
1807: CURLcode ret = CURLE_OK;
1808:
1809: /* Get rid of previously prepared headers. */
1810: curl_slist_free_all(part->curlheaders);
1811: part->curlheaders = NULL;
1812:
1813: /* Be sure we won't access old headers later. */
1814: if(part->state.state == MIMESTATE_CURLHEADERS)
1815: mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
1816:
1817: /* Check if content type is specified. */
1818: customct = part->mimetype;
1819: if(!customct)
1820: customct = search_header(part->userheaders, "Content-Type");
1821: if(customct)
1822: contenttype = customct;
1823:
1824: /* If content type is not specified, try to determine it. */
1825: if(!contenttype) {
1826: switch(part->kind) {
1827: case MIMEKIND_MULTIPART:
1828: contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
1829: break;
1830: case MIMEKIND_FILE:
1831: contenttype = Curl_mime_contenttype(part->filename);
1832: if(!contenttype)
1833: contenttype = Curl_mime_contenttype(part->data);
1834: if(!contenttype && part->filename)
1835: contenttype = FILE_CONTENTTYPE_DEFAULT;
1836: break;
1837: default:
1838: contenttype = Curl_mime_contenttype(part->filename);
1839: break;
1840: }
1841: }
1842:
1843: if(part->kind == MIMEKIND_MULTIPART) {
1844: mime = (curl_mime *) part->arg;
1845: if(mime)
1846: boundary = mime->boundary;
1847: }
1848: else if(contenttype && !customct &&
1849: content_type_match(contenttype, "text/plain"))
1850: if(strategy == MIMESTRATEGY_MAIL || !part->filename)
1851: contenttype = NULL;
1852:
1853: /* Issue content-disposition header only if not already set by caller. */
1854: if(!search_header(part->userheaders, "Content-Disposition")) {
1855: if(!disposition)
1856: if(part->filename || part->name ||
1857: (contenttype && !strncasecompare(contenttype, "multipart/", 10)))
1858: disposition = DISPOSITION_DEFAULT;
1859: if(disposition && curl_strequal(disposition, "attachment") &&
1860: !part->name && !part->filename)
1861: disposition = NULL;
1862: if(disposition) {
1863: char *name = NULL;
1864: char *filename = NULL;
1865:
1866: if(part->name) {
1867: name = escape_string(part->name);
1868: if(!name)
1869: ret = CURLE_OUT_OF_MEMORY;
1870: }
1871: if(!ret && part->filename) {
1872: filename = escape_string(part->filename);
1873: if(!filename)
1874: ret = CURLE_OUT_OF_MEMORY;
1875: }
1876: if(!ret)
1877: ret = Curl_mime_add_header(&part->curlheaders,
1878: "Content-Disposition: %s%s%s%s%s%s%s",
1879: disposition,
1880: name? "; name=\"": "",
1881: name? name: "",
1882: name? "\"": "",
1883: filename? "; filename=\"": "",
1884: filename? filename: "",
1885: filename? "\"": "");
1886: Curl_safefree(name);
1887: Curl_safefree(filename);
1888: if(ret)
1889: return ret;
1890: }
1891: }
1892:
1893: /* Issue Content-Type header. */
1894: if(contenttype) {
1895: ret = add_content_type(&part->curlheaders, contenttype, boundary);
1896: if(ret)
1897: return ret;
1898: }
1899:
1900: /* Content-Transfer-Encoding header. */
1901: if(!search_header(part->userheaders, "Content-Transfer-Encoding")) {
1902: if(part->encoder)
1903: cte = part->encoder->name;
1904: else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
1905: part->kind != MIMEKIND_MULTIPART)
1906: cte = "8bit";
1907: if(cte) {
1908: ret = Curl_mime_add_header(&part->curlheaders,
1909: "Content-Transfer-Encoding: %s", cte);
1910: if(ret)
1911: return ret;
1912: }
1913: }
1914:
1915: /* If we were reading curl-generated headers, restart with new ones (this
1916: should not occur). */
1917: if(part->state.state == MIMESTATE_CURLHEADERS)
1918: mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
1919:
1920: /* Process subparts. */
1921: if(part->kind == MIMEKIND_MULTIPART && mime) {
1922: curl_mimepart *subpart;
1923:
1924: disposition = NULL;
1925: if(content_type_match(contenttype, "multipart/form-data"))
1926: disposition = "form-data";
1927: for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
1928: ret = Curl_mime_prepare_headers(subpart, NULL, disposition, strategy);
1929: if(ret)
1930: return ret;
1931: }
1932: }
1933: return ret;
1934: }
1935:
1936: /* Recursively reset paused status in the given part. */
1937: void Curl_mime_unpause(curl_mimepart *part)
1938: {
1939: if(part) {
1940: if(part->lastreadstatus == CURL_READFUNC_PAUSE)
1941: part->lastreadstatus = 1; /* Successful read status. */
1942: if(part->kind == MIMEKIND_MULTIPART) {
1943: curl_mime *mime = (curl_mime *) part->arg;
1944:
1945: if(mime) {
1946: curl_mimepart *subpart;
1947:
1948: for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart)
1949: Curl_mime_unpause(subpart);
1950: }
1951: }
1952: }
1953: }
1954:
1955:
1956: #else /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */
1957:
1958: /* Mime not compiled in: define stubs for externally-referenced functions. */
1959: curl_mime *curl_mime_init(CURL *easy)
1960: {
1961: (void) easy;
1962: return NULL;
1963: }
1964:
1965: void curl_mime_free(curl_mime *mime)
1966: {
1967: (void) mime;
1968: }
1969:
1970: curl_mimepart *curl_mime_addpart(curl_mime *mime)
1971: {
1972: (void) mime;
1973: return NULL;
1974: }
1975:
1976: CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1977: {
1978: (void) part;
1979: (void) name;
1980: return CURLE_NOT_BUILT_IN;
1981: }
1982:
1983: CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1984: {
1985: (void) part;
1986: (void) filename;
1987: return CURLE_NOT_BUILT_IN;
1988: }
1989:
1990: CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1991: {
1992: (void) part;
1993: (void) mimetype;
1994: return CURLE_NOT_BUILT_IN;
1995: }
1996:
1997: CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1998: {
1999: (void) part;
2000: (void) encoding;
2001: return CURLE_NOT_BUILT_IN;
2002: }
2003:
2004: CURLcode curl_mime_data(curl_mimepart *part,
2005: const char *data, size_t datasize)
2006: {
2007: (void) part;
2008: (void) data;
2009: (void) datasize;
2010: return CURLE_NOT_BUILT_IN;
2011: }
2012:
2013: CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
2014: {
2015: (void) part;
2016: (void) filename;
2017: return CURLE_NOT_BUILT_IN;
2018: }
2019:
2020: CURLcode curl_mime_data_cb(curl_mimepart *part,
2021: curl_off_t datasize,
2022: curl_read_callback readfunc,
2023: curl_seek_callback seekfunc,
2024: curl_free_callback freefunc,
2025: void *arg)
2026: {
2027: (void) part;
2028: (void) datasize;
2029: (void) readfunc;
2030: (void) seekfunc;
2031: (void) freefunc;
2032: (void) arg;
2033: return CURLE_NOT_BUILT_IN;
2034: }
2035:
2036: CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
2037: {
2038: (void) part;
2039: (void) subparts;
2040: return CURLE_NOT_BUILT_IN;
2041: }
2042:
2043: CURLcode curl_mime_headers(curl_mimepart *part,
2044: struct curl_slist *headers, int take_ownership)
2045: {
2046: (void) part;
2047: (void) headers;
2048: (void) take_ownership;
2049: return CURLE_NOT_BUILT_IN;
2050: }
2051:
2052: CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
2053: {
2054: (void)slp;
2055: (void)fmt;
2056: return CURLE_NOT_BUILT_IN;
2057: }
2058:
2059: #endif /* if disabled */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>