1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 #include <curl/curl.h>
28 #include "non-ascii.h"
32 #if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \
33 !defined(CURL_DISABLE_IMAP)
35 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
42 /* The last 3 #include files should be in this order */
43 #include "curl_printf.h"
44 #include "curl_memory.h"
54 #define FILE_CONTENTTYPE_DEFAULT "application/octet-stream"
55 #define MULTIPART_CONTENTTYPE_DEFAULT "multipart/mixed"
56 #define DISPOSITION_DEFAULT "attachment"
58 #define READ_ERROR ((size_t) -1)
61 static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
63 static curl_off_t encoder_nop_size(curl_mimepart *part);
64 static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
66 static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
68 static curl_off_t encoder_base64_size(curl_mimepart *part);
69 static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
71 static curl_off_t encoder_qp_size(curl_mimepart *part);
73 static const mime_encoder encoders[] = {
74 {"binary", encoder_nop_read, encoder_nop_size},
75 {"8bit", encoder_nop_read, encoder_nop_size},
76 {"7bit", encoder_7bit_read, encoder_nop_size},
77 {"base64", encoder_base64_read, encoder_base64_size},
78 {"quoted-printable", encoder_qp_read, encoder_qp_size},
79 {ZERO_NULL, ZERO_NULL, ZERO_NULL}
82 /* Base64 encoding table */
83 static const char base64[] =
84 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
86 /* Quoted-printable character class table.
88 * We cannot rely on ctype functions since quoted-printable input data
89 * is assumed to be ascii-compatible, even on non-ascii platforms. */
90 #define QP_OK 1 /* Can be represented by itself. */
91 #define QP_SP 2 /* Space or tab. */
92 #define QP_CR 3 /* Carriage return. */
93 #define QP_LF 4 /* Line-feed. */
94 static const unsigned char qp_class[] = {
95 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */
96 0, QP_SP, QP_LF, 0, 0, QP_CR, 0, 0, /* 08 - 0F */
97 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */
98 0, 0, 0, 0, 0, 0, 0, 0, /* 18 - 1F */
99 QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 20 - 27 */
100 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 28 - 2F */
101 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 30 - 37 */
102 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0 , QP_OK, QP_OK, /* 38 - 3F */
103 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 40 - 47 */
104 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 48 - 4F */
105 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 50 - 57 */
106 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 58 - 5F */
107 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 60 - 67 */
108 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 68 - 6F */
109 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 70 - 77 */
110 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0, /* 78 - 7F */
111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */
122 /* Binary --> hexadecimal ASCII table. */
123 static const char aschex[] =
124 "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46";
129 #define filesize(name, stat_data) (stat_data.st_size)
130 #define fopen_read fopen
136 * get_vms_file_size does what it takes to get the real size of the file
138 * For fixed files, find out the size of the EOF block and adjust.
140 * For all others, have to read the entire file in, discarding the contents.
141 * Most posted text files will be small, and binary files like zlib archives
142 * and CD/DVD images should be either a STREAM_LF format or a fixed format.
145 curl_off_t VmsRealFileSize(const char *name,
146 const struct_stat *stat_buf)
153 file = fopen(name, FOPEN_READTEXT); /* VMS */
159 while(ret_stat > 0) {
160 ret_stat = fread(buffer, 1, sizeof(buffer), file);
171 * VmsSpecialSize checks to see if the stat st_size can be trusted and
172 * if not to call a routine to get the correct size.
175 static curl_off_t VmsSpecialSize(const char *name,
176 const struct_stat *stat_buf)
178 switch(stat_buf->st_fab_rfm) {
181 return VmsRealFileSize(name, stat_buf);
184 return stat_buf->st_size;
188 #define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
193 * For upload to work as expected on VMS, different optional
194 * parameters must be added to the fopen command based on
195 * record format of the file.
198 static FILE * vmsfopenread(const char *file, const char *mode)
203 result = stat(file, &statbuf);
205 switch(statbuf.st_fab_rfm) {
209 return fopen(file, FOPEN_READTEXT); /* VMS */
212 return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
216 #define fopen_read vmsfopenread
220 #ifndef HAVE_BASENAME
222 (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
225 The basename() function shall take the pathname pointed to by path and
226 return a pointer to the final component of the pathname, deleting any
227 trailing '/' characters.
229 If the string pointed to by path consists entirely of the '/' character,
230 basename() shall return a pointer to the string "/". If the string pointed
231 to by path is exactly "//", it is implementation-defined whether '/' or "//"
234 If path is a null pointer or points to an empty string, basename() shall
235 return a pointer to the string ".".
237 The basename() function may modify the string pointed to by path, and may
238 return a pointer to static storage that may then be overwritten by a
239 subsequent call to basename().
241 The basename() function need not be reentrant. A function that is not
242 required to be reentrant is not required to be thread-safe.
245 static char *Curl_basename(char *path)
247 /* Ignore all the details above for now and make a quick and simple
248 implementaion here */
252 s1 = strrchr(path, '/');
253 s2 = strrchr(path, '\\');
256 path = (s1 > s2? s1 : s2) + 1;
266 #define basename(x) Curl_basename((x))
270 /* Set readback state. */
271 static void mimesetstate(mime_state *state, enum mimestate tok, void *ptr)
279 /* Escape header string into allocated memory. */
280 static char *escape_string(const char *src)
282 size_t bytecount = 0;
286 for(i = 0; src[i]; i++)
287 if(src[i] == '"' || src[i] == '\\')
291 dst = malloc(bytecount + 1);
295 for(i = 0; *src; src++) {
296 if(*src == '"' || *src == '\\')
305 /* Check if header matches. */
306 static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
310 if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':')
311 for(value = hdr->data + len + 1; *value == ' '; value++)
316 /* Get a header from an slist. */
317 static char *search_header(struct curl_slist *hdrlist, const char *hdr)
319 size_t len = strlen(hdr);
322 for(; !value && hdrlist; hdrlist = hdrlist->next)
323 value = match_header(hdrlist, hdr, len);
328 static char *strippath(const char *fullfile)
332 filename = strdup(fullfile); /* duplicate since basename() may ruin the
333 buffer it works on */
336 base = strdup(basename(filename));
338 free(filename); /* free temporary buffer */
340 return base; /* returns an allocated string or NULL ! */
343 /* Initialize data encoder state. */
344 static void cleanup_encoder_state(mime_encoder_state *p)
352 /* Dummy encoder. This is used for 8bit and binary content encodings. */
353 static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
356 mime_encoder_state *st = &part->encstate;
357 size_t insize = st->bufend - st->bufbeg;
364 memcpy(buffer, st->buf, size);
369 static curl_off_t encoder_nop_size(curl_mimepart *part)
371 return part->datasize;
375 /* 7bit encoder: the encoder is just a data validity check. */
376 static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
379 mime_encoder_state *st = &part->encstate;
380 size_t cursize = st->bufend - st->bufbeg;
387 for(cursize = 0; cursize < size; cursize++) {
388 *buffer = st->buf[st->bufbeg];
390 return cursize? cursize: READ_ERROR;
398 /* Base64 content encoder. */
399 static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
402 mime_encoder_state *st = &part->encstate;
407 while(st->bufbeg < st->bufend) {
409 if(st->pos > MAX_ENCODED_LINE_LENGTH - 4) {
410 /* Yes, we need 2 characters for CRLF. */
420 /* Be sure there is enough space and input data for a base64 group. */
421 if(size < 4 || st->bufend - st->bufbeg < 3)
424 /* Encode three bytes as four characters. */
425 i = st->buf[st->bufbeg++] & 0xFF;
426 i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
427 i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
428 *ptr++ = base64[(i >> 18) & 0x3F];
429 *ptr++ = base64[(i >> 12) & 0x3F];
430 *ptr++ = base64[(i >> 6) & 0x3F];
431 *ptr++ = base64[i & 0x3F];
437 /* If at eof, we have to flush the buffered data. */
438 if(ateof && size >= 4) {
439 /* Buffered data size can only be 0, 1 or 2. */
440 ptr[2] = ptr[3] = '=';
442 switch(st->bufend - st->bufbeg) {
444 i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
447 i |= (st->buf[st->bufbeg] & 0xFF) << 16;
448 ptr[0] = base64[(i >> 18) & 0x3F];
449 ptr[1] = base64[(i >> 12) & 0x3F];
450 if(++st->bufbeg != st->bufend) {
451 ptr[2] = base64[(i >> 6) & 0x3F];
460 #ifdef CURL_DOES_CONVERSIONS
461 /* This is now textual data, Convert character codes. */
462 if(part->easy && cursize) {
463 CURLcode result = Curl_convert_to_network(part->easy, buffer, cursize);
472 static curl_off_t encoder_base64_size(curl_mimepart *part)
474 curl_off_t size = part->datasize;
477 return size; /* Unknown size or no data. */
479 /* Compute base64 character count. */
480 size = 4 * (1 + (size - 1) / 3);
482 /* Effective character count must include CRLFs. */
483 return size + 2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH);
487 /* Quoted-printable lookahead.
489 * Check if a CRLF or end of data is in input buffer at current position + n.
490 * Return -1 if more data needed, 1 if CRLF or end of data, else 0.
492 static int qp_lookahead_eol(mime_encoder_state *st, int ateof, size_t n)
495 if(n >= st->bufend && ateof)
497 if(n + 2 > st->bufend)
499 if(qp_class[st->buf[n] & 0xFF] == QP_CR &&
500 qp_class[st->buf[n + 1] & 0xFF] == QP_LF)
505 /* Quoted-printable encoder. */
506 static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
509 mime_encoder_state *st = &part->encstate;
518 /* On all platforms, input is supposed to be ASCII compatible: for this
519 reason, we use hexadecimal ASCII codes in this function rather than
520 character constants that can be interpreted as non-ascii on some
521 platforms. Preserve ASCII encoding on output too. */
522 while(st->bufbeg < st->bufend) {
525 i = st->buf[st->bufbeg];
527 buf[1] = aschex[(i >> 4) & 0xF];
528 buf[2] = aschex[i & 0xF];
530 switch(qp_class[st->buf[st->bufbeg] & 0xFF]) {
531 case QP_OK: /* Not a special character. */
533 case QP_SP: /* Space or tab. */
534 /* Spacing must be escaped if followed by CRLF. */
535 switch(qp_lookahead_eol(st, ateof, 1)) {
536 case -1: /* More input data needed. */
538 case 0: /* No encoding needed. */
540 default: /* CRLF after space or tab. */
541 buf[0] = '\x3D'; /* '=' */
546 case QP_CR: /* Carriage return. */
547 /* If followed by a line-feed, output the CRLF pair.
549 switch(qp_lookahead_eol(st, ateof, 0)) {
550 case -1: /* Need more data. */
552 case 1: /* CRLF found. */
553 buf[len++] = '\x0A'; /* Append '\n'. */
556 default: /* Not followed by LF: escape. */
557 buf[0] = '\x3D'; /* '=' */
562 default: /* Character must be escaped. */
563 buf[0] = '\x3D'; /* '=' */
568 /* Be sure the encoded character fits within maximum line length. */
569 if(buf[len - 1] != '\x0A') { /* '\n' */
570 softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH;
571 if(!softlinebreak && st->pos + len == MAX_ENCODED_LINE_LENGTH) {
572 /* We may use the current line only if end of data or followed by
574 switch(qp_lookahead_eol(st, ateof, consumed)) {
575 case -1: /* Need more data. */
578 case 0: /* Not followed by a CRLF. */
584 strcpy(buf, "\x3D\x0D\x0A"); /* "=\r\n" */
590 /* If the output buffer would overflow, do not store. */
594 /* Append to output buffer. */
595 memcpy(ptr, buf, len);
600 if(buf[len - 1] == '\x0A') /* '\n' */
602 st->bufbeg += consumed;
608 static curl_off_t encoder_qp_size(curl_mimepart *part)
610 /* Determining the size can only be done by reading the data: unless the
611 data size is 0, we return it as unknown (-1). */
612 return part->datasize? -1: 0;
616 /* In-memory data callbacks. */
617 /* Argument is a pointer to the mime part. */
618 static size_t mime_mem_read(char *buffer, size_t size, size_t nitems,
621 curl_mimepart *part = (curl_mimepart *) instream;
622 size_t sz = (size_t) part->datasize - part->state.offset;
623 (void) size; /* Always 1.*/
629 memcpy(buffer, (char *) &part->data[part->state.offset], sz);
631 part->state.offset += sz;
635 static int mime_mem_seek(void *instream, curl_off_t offset, int whence)
637 curl_mimepart *part = (curl_mimepart *) instream;
641 offset += part->state.offset;
644 offset += part->datasize;
648 if(offset < 0 || offset > part->datasize)
649 return CURL_SEEKFUNC_FAIL;
651 part->state.offset = (size_t) offset;
652 return CURL_SEEKFUNC_OK;
655 static void mime_mem_free(void *ptr)
657 Curl_safefree(((curl_mimepart *) ptr)->data);
661 /* Named file callbacks. */
662 /* Argument is a pointer to the mime part. */
663 static int mime_open_file(curl_mimepart * part)
665 /* Open a MIMEKIND_FILE part. */
669 part->fp = fopen_read(part->data, "rb");
670 return part->fp? 0: -1;
673 static size_t mime_file_read(char *buffer, size_t size, size_t nitems,
676 curl_mimepart *part = (curl_mimepart *) instream;
678 if(mime_open_file(part))
681 return fread(buffer, size, nitems, part->fp);
684 static int mime_file_seek(void *instream, curl_off_t offset, int whence)
686 curl_mimepart *part = (curl_mimepart *) instream;
688 if(whence == SEEK_SET && !offset && !part->fp)
689 return CURL_SEEKFUNC_OK; /* Not open: implicitly already at BOF. */
691 if(mime_open_file(part))
692 return CURL_SEEKFUNC_FAIL;
694 return fseek(part->fp, (long) offset, whence)?
695 CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK;
698 static void mime_file_free(void *ptr)
700 curl_mimepart *part = (curl_mimepart *) ptr;
706 Curl_safefree(part->data);
711 /* Subparts callbacks. */
712 /* Argument is a pointer to the mime structure. */
714 /* Readback a byte string segment. */
715 static size_t readback_bytes(mime_state *state,
716 char *buffer, size_t bufsize,
717 const char *bytes, size_t numbytes,
722 sz = numbytes - state->offset;
724 if(numbytes > state->offset) {
725 sz = numbytes - state->offset;
726 bytes += state->offset;
729 size_t tsz = strlen(trail);
731 sz = state->offset - numbytes;
741 memcpy(buffer, bytes, sz);
746 /* Read a non-encoded part content. */
747 static size_t read_part_content(curl_mimepart *part,
748 char *buffer, size_t bufsize)
753 sz = part->readfunc(buffer, 1, bufsize, part->arg);
757 /* Read and encode part content. */
758 static size_t read_encoded_part_content(curl_mimepart *part,
759 char *buffer, size_t bufsize)
761 mime_encoder_state *st = &part->encstate;
767 if(st->bufbeg < st->bufend || ateof) {
768 /* Encode buffered data. */
769 sz = part->encoder->encodefunc(buffer, bufsize, ateof, part);
775 case CURL_READFUNC_ABORT:
776 case CURL_READFUNC_PAUSE:
778 return cursize? cursize: sz;
787 /* We need more data in input buffer. */
789 size_t len = st->bufend - st->bufbeg;
792 memmove(st->buf, st->buf + st->bufbeg, len);
796 if(st->bufend >= sizeof st->buf)
797 return cursize? cursize: READ_ERROR; /* Buffer full. */
798 sz = read_part_content(part, st->buf + st->bufend,
799 sizeof st->buf - st->bufend);
804 case CURL_READFUNC_ABORT:
805 case CURL_READFUNC_PAUSE:
807 return cursize? cursize: sz;
817 /* Readback a mime part. */
818 static size_t readback_part(curl_mimepart *part,
819 char *buffer, size_t bufsize)
823 struct curl_slist *hdr;
824 #ifdef CURL_DOES_CONVERSIONS
825 char *convbuf = buffer;
828 /* Readback from part. */
832 hdr = (struct curl_slist *) part->state.ptr;
833 switch(part->state.state) {
834 case MIMESTATE_BEGIN:
835 mimesetstate(&part->state, part->flags & MIME_BODY_ONLY? MIMESTATE_BODY:
836 MIMESTATE_CURLHEADERS, part->curlheaders);
838 case MIMESTATE_USERHEADERS:
840 mimesetstate(&part->state, MIMESTATE_EOH, NULL);
843 if(match_header(hdr, "Content-Type", 12)) {
844 mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next);
848 case MIMESTATE_CURLHEADERS:
850 mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
852 sz = readback_bytes(&part->state, buffer, bufsize,
853 hdr->data, strlen(hdr->data), "\r\n");
855 mimesetstate(&part->state, part->state.state, hdr->next);
859 sz = readback_bytes(&part->state, buffer, bufsize, "\r\n", 2, "");
861 mimesetstate(&part->state, MIMESTATE_BODY, NULL);
864 #ifdef CURL_DOES_CONVERSIONS
865 if(part->easy && convbuf < buffer) {
866 CURLcode result = Curl_convert_to_network(part->easy, convbuf,
873 cleanup_encoder_state(&part->encstate);
874 mimesetstate(&part->state, MIMESTATE_CONTENT, NULL);
876 case MIMESTATE_CONTENT:
878 sz = read_encoded_part_content(part, buffer, bufsize);
880 sz = read_part_content(part, buffer, bufsize);
883 mimesetstate(&part->state, MIMESTATE_END, NULL);
884 /* Try sparing open file descriptors. */
885 if(part->kind == MIMEKIND_FILE && part->fp) {
890 case CURL_READFUNC_ABORT:
891 case CURL_READFUNC_PAUSE:
893 return cursize? cursize: sz;
899 break; /* Other values not in part state. */
902 /* Bump buffer and counters according to read size. */
908 #ifdef CURL_DOES_CONVERSIONS
909 if(part->easy && convbuf < buffer &&
910 part->state.state < MIMESTATE_BODY) {
911 CURLcode result = Curl_convert_to_network(part->easy, convbuf,
921 /* Readback from mime. */
922 static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
925 curl_mime *mime = (curl_mime *) instream;
929 #ifdef CURL_DOES_CONVERSIONS
930 char *convbuf = buffer;
933 (void) size; /* Always 1. */
937 part = mime->state.ptr;
938 switch(mime->state.state) {
939 case MIMESTATE_BEGIN:
941 #ifdef CURL_DOES_CONVERSIONS
944 mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, mime->firstpart);
945 /* The first boundary always follows the header termination empty line,
946 so is always preceded by a CRLK. We can then spare 2 characters
947 by skipping the leading CRLF in boundary. */
948 mime->state.offset += 2;
950 case MIMESTATE_BOUNDARY1:
951 sz = readback_bytes(&mime->state, buffer, nitems, "\r\n--", 4, "");
953 mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part);
955 case MIMESTATE_BOUNDARY2:
956 sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
957 strlen(mime->boundary), part? "\r\n": "--\r\n");
959 #ifdef CURL_DOES_CONVERSIONS
960 if(mime->easy && convbuf < buffer) {
961 CURLcode result = Curl_convert_to_network(mime->easy, convbuf,
968 mimesetstate(&mime->state, MIMESTATE_CONTENT, part);
971 case MIMESTATE_CONTENT:
973 mimesetstate(&mime->state, MIMESTATE_END, NULL);
976 sz = readback_part(part, buffer, nitems);
978 case CURL_READFUNC_ABORT:
979 case CURL_READFUNC_PAUSE:
981 return cursize? cursize: sz;
983 #ifdef CURL_DOES_CONVERSIONS
986 mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart);
993 break; /* other values not used in mime state. */
996 /* Bump buffer and counters according to read size. */
1002 #ifdef CURL_DOES_CONVERSIONS
1003 if(mime->easy && convbuf < buffer &&
1004 mime->state.state <= MIMESTATE_CONTENT) {
1005 CURLcode result = Curl_convert_to_network(mime->easy, convbuf,
1015 static int mime_part_rewind(curl_mimepart *part)
1017 int res = CURL_SEEKFUNC_OK;
1018 enum mimestate targetstate = MIMESTATE_BEGIN;
1020 if(part->flags & MIME_BODY_ONLY)
1021 targetstate = MIMESTATE_BODY;
1022 cleanup_encoder_state(&part->encstate);
1023 if(part->state.state > targetstate) {
1024 res = CURL_SEEKFUNC_CANTSEEK;
1025 if(part->seekfunc) {
1026 res = part->seekfunc(part->arg, (curl_off_t) 0, SEEK_SET);
1028 case CURL_SEEKFUNC_OK:
1029 case CURL_SEEKFUNC_FAIL:
1030 case CURL_SEEKFUNC_CANTSEEK:
1032 case -1: /* For fseek() error. */
1033 res = CURL_SEEKFUNC_CANTSEEK;
1036 res = CURL_SEEKFUNC_FAIL;
1042 if(res == CURL_SEEKFUNC_OK)
1043 mimesetstate(&part->state, targetstate, NULL);
1048 static int mime_subparts_seek(void *instream, curl_off_t offset, int whence)
1050 curl_mime *mime = (curl_mime *) instream;
1051 curl_mimepart *part;
1052 int result = CURL_SEEKFUNC_OK;
1055 if(whence != SEEK_SET || offset)
1056 return CURL_SEEKFUNC_CANTSEEK; /* Only support full rewind. */
1058 if(mime->state.state == MIMESTATE_BEGIN)
1059 return CURL_SEEKFUNC_OK; /* Already rewound. */
1061 for(part = mime->firstpart; part; part = part->nextpart) {
1062 res = mime_part_rewind(part);
1063 if(res != CURL_SEEKFUNC_OK)
1067 if(result == CURL_SEEKFUNC_OK)
1068 mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1073 /* Release part content. */
1074 static void cleanup_part_content(curl_mimepart *part)
1077 part->freefunc(part->arg);
1079 part->readfunc = NULL;
1080 part->seekfunc = NULL;
1081 part->freefunc = NULL;
1082 part->arg = (void *) part; /* Defaults to part itself. */
1085 part->datasize = (curl_off_t) 0; /* No size yet. */
1086 cleanup_encoder_state(&part->encstate);
1087 part->kind = MIMEKIND_NONE;
1090 static void mime_subparts_free(void *ptr)
1092 curl_mime *mime = (curl_mime *) ptr;
1094 if(mime && mime->parent) {
1095 mime->parent->freefunc = NULL; /* Be sure we won't be called again. */
1096 cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */
1098 curl_mime_free(mime);
1101 /* Do not free subparts: unbind them. This is used for the top level only. */
1102 static void mime_subparts_unbind(void *ptr)
1104 curl_mime *mime = (curl_mime *) ptr;
1106 if(mime && mime->parent) {
1107 mime->parent->freefunc = NULL; /* Be sure we won't be called again. */
1108 cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */
1109 mime->parent = NULL;
1114 void Curl_mime_cleanpart(curl_mimepart *part)
1116 cleanup_part_content(part);
1117 curl_slist_free_all(part->curlheaders);
1118 if(part->flags & MIME_USERHEADERS_OWNER)
1119 curl_slist_free_all(part->userheaders);
1120 Curl_safefree(part->mimetype);
1121 Curl_safefree(part->name);
1122 Curl_safefree(part->filename);
1123 Curl_mime_initpart(part, part->easy);
1126 /* Recursively delete a mime handle and its parts. */
1127 void curl_mime_free(curl_mime *mime)
1129 curl_mimepart *part;
1132 mime_subparts_unbind(mime); /* Be sure it's not referenced anymore. */
1133 while(mime->firstpart) {
1134 part = mime->firstpart;
1135 mime->firstpart = part->nextpart;
1136 Curl_mime_cleanpart(part);
1140 free(mime->boundary);
1146 * Mime build functions.
1149 /* Create a mime handle. */
1150 curl_mime *curl_mime_init(struct Curl_easy *easy)
1154 mime = (curl_mime *) malloc(sizeof *mime);
1158 mime->parent = NULL;
1159 mime->firstpart = NULL;
1160 mime->lastpart = NULL;
1162 /* Get a part boundary. */
1163 mime->boundary = malloc(24 + MIME_RAND_BOUNDARY_CHARS + 1);
1164 if(!mime->boundary) {
1169 memset(mime->boundary, '-', 24);
1170 Curl_rand_hex(easy, (unsigned char *) mime->boundary + 24,
1171 MIME_RAND_BOUNDARY_CHARS + 1);
1172 mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1178 /* Initialize a mime part. */
1179 void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy)
1181 memset((char *) part, 0, sizeof *part);
1183 mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
1186 /* Create a mime part and append it to a mime handle's part list. */
1187 curl_mimepart *curl_mime_addpart(curl_mime *mime)
1189 curl_mimepart *part;
1194 part = (curl_mimepart *) malloc(sizeof *part);
1197 Curl_mime_initpart(part, mime->easy);
1198 part->parent = mime;
1201 mime->lastpart->nextpart = part;
1203 mime->firstpart = part;
1205 mime->lastpart = part;
1211 /* Set mime part name. */
1212 CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1215 return CURLE_BAD_FUNCTION_ARGUMENT;
1217 Curl_safefree(part->name);
1221 part->name = strdup(name);
1223 return CURLE_OUT_OF_MEMORY;
1229 /* Set mime part remote file name. */
1230 CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1233 return CURLE_BAD_FUNCTION_ARGUMENT;
1235 Curl_safefree(part->filename);
1236 part->filename = NULL;
1239 part->filename = strdup(filename);
1241 return CURLE_OUT_OF_MEMORY;
1247 /* Set mime part content from memory data. */
1248 CURLcode curl_mime_data(curl_mimepart *part,
1249 const char *data, size_t datasize)
1252 return CURLE_BAD_FUNCTION_ARGUMENT;
1254 cleanup_part_content(part);
1257 if(datasize == CURL_ZERO_TERMINATED)
1258 datasize = strlen(data);
1260 part->data = malloc(datasize + 1);
1262 return CURLE_OUT_OF_MEMORY;
1264 part->datasize = datasize;
1267 memcpy(part->data, data, datasize);
1268 part->data[datasize] = '\0'; /* Set a nul terminator as sentinel. */
1270 part->readfunc = mime_mem_read;
1271 part->seekfunc = mime_mem_seek;
1272 part->freefunc = mime_mem_free;
1273 part->kind = MIMEKIND_DATA;
1279 /* Set mime part content from named local file. */
1280 CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1282 CURLcode result = CURLE_OK;
1286 return CURLE_BAD_FUNCTION_ARGUMENT;
1288 cleanup_part_content(part);
1293 if(stat(filename, &sbuf) || access(filename, R_OK))
1294 result = CURLE_READ_ERROR;
1296 part->data = strdup(filename);
1298 result = CURLE_OUT_OF_MEMORY;
1300 part->datasize = -1;
1301 if(!result && S_ISREG(sbuf.st_mode)) {
1302 part->datasize = filesize(filename, sbuf);
1303 part->seekfunc = mime_file_seek;
1306 part->readfunc = mime_file_read;
1307 part->freefunc = mime_file_free;
1308 part->kind = MIMEKIND_FILE;
1310 /* As a side effect, set the filename to the current file's base name.
1311 It is possible to withdraw this by explicitly calling
1312 curl_mime_filename() with a NULL filename argument after the current
1314 base = strippath(filename);
1316 result = CURLE_OUT_OF_MEMORY;
1318 CURLcode res = curl_mime_filename(part, base);
1328 /* Set mime part type. */
1329 CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1332 return CURLE_BAD_FUNCTION_ARGUMENT;
1334 Curl_safefree(part->mimetype);
1335 part->mimetype = NULL;
1338 part->mimetype = strdup(mimetype);
1340 return CURLE_OUT_OF_MEMORY;
1346 /* Set mime data transfer encoder. */
1347 CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1349 CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
1350 const mime_encoder *mep;
1355 part->encoder = NULL;
1358 return CURLE_OK; /* Removing current encoder. */
1360 for(mep = encoders; mep->name; mep++)
1361 if(strcasecompare(encoding, mep->name)) {
1362 part->encoder = mep;
1369 /* Set mime part headers. */
1370 CURLcode curl_mime_headers(curl_mimepart *part,
1371 struct curl_slist *headers, int take_ownership)
1374 return CURLE_BAD_FUNCTION_ARGUMENT;
1376 if(part->flags & MIME_USERHEADERS_OWNER) {
1377 if(part->userheaders != headers) /* Allow setting twice the same list. */
1378 curl_slist_free_all(part->userheaders);
1379 part->flags &= ~MIME_USERHEADERS_OWNER;
1381 part->userheaders = headers;
1382 if(headers && take_ownership)
1383 part->flags |= MIME_USERHEADERS_OWNER;
1387 /* Set mime part content from callback. */
1388 CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize,
1389 curl_read_callback readfunc,
1390 curl_seek_callback seekfunc,
1391 curl_free_callback freefunc, void *arg)
1394 return CURLE_BAD_FUNCTION_ARGUMENT;
1396 cleanup_part_content(part);
1399 part->readfunc = readfunc;
1400 part->seekfunc = seekfunc;
1401 part->freefunc = freefunc;
1403 part->datasize = datasize;
1404 part->kind = MIMEKIND_CALLBACK;
1410 /* Set mime part content from subparts. */
1411 CURLcode Curl_mime_set_subparts(curl_mimepart *part,
1412 curl_mime *subparts, int take_ownership)
1417 return CURLE_BAD_FUNCTION_ARGUMENT;
1419 /* Accept setting twice the same subparts. */
1420 if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
1423 cleanup_part_content(part);
1426 /* Must belong to the same data handle. */
1427 if(part->easy && subparts->easy && part->easy != subparts->easy)
1428 return CURLE_BAD_FUNCTION_ARGUMENT;
1430 /* Should not have been attached already. */
1431 if(subparts->parent)
1432 return CURLE_BAD_FUNCTION_ARGUMENT;
1434 /* Should not be the part's root. */
1435 root = part->parent;
1437 while(root->parent && root->parent->parent)
1438 root = root->parent->parent;
1439 if(subparts == root) {
1441 failf(part->easy, "Can't add itself as a subpart!");
1442 return CURLE_BAD_FUNCTION_ARGUMENT;
1446 subparts->parent = part;
1447 part->readfunc = mime_subparts_read;
1448 part->seekfunc = mime_subparts_seek;
1449 part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind;
1450 part->arg = subparts;
1451 part->datasize = -1;
1452 part->kind = MIMEKIND_MULTIPART;
1458 CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
1460 return Curl_mime_set_subparts(part, subparts, TRUE);
1464 /* Readback from top mime. */
1465 /* Argument is the dummy top part. */
1466 size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
1468 curl_mimepart *part = (curl_mimepart *) instream;
1470 (void) size; /* Always 1. */
1471 return readback_part(part, buffer, nitems);
1474 /* Rewind mime stream. */
1475 CURLcode Curl_mime_rewind(curl_mimepart *part)
1477 return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
1478 CURLE_OK: CURLE_SEND_FAIL_REWIND;
1481 /* Compute header list size. */
1482 static size_t slist_size(struct curl_slist *s,
1483 size_t overhead, const char *skip)
1486 size_t skiplen = skip? strlen(skip): 0;
1488 for(; s; s = s->next)
1489 if(!skip || !match_header(s, skip, skiplen))
1490 size += strlen(s->data) + overhead;
1494 /* Get/compute multipart size. */
1495 static curl_off_t multipart_size(curl_mime *mime)
1499 size_t boundarysize;
1500 curl_mimepart *part;
1503 return 0; /* Not present -> empty. */
1505 boundarysize = 4 + strlen(mime->boundary) + 2;
1506 size = boundarysize; /* Final boundary - CRLF after headers. */
1508 for(part = mime->firstpart; part; part = part->nextpart) {
1509 sz = Curl_mime_size(part);
1515 size += boundarysize + sz;
1521 /* Get/compute mime size. */
1522 curl_off_t Curl_mime_size(curl_mimepart *part)
1526 if(part->kind == MIMEKIND_MULTIPART)
1527 part->datasize = multipart_size(part->arg);
1529 size = part->datasize;
1532 size = part->encoder->sizefunc(part);
1534 if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
1535 /* Compute total part size. */
1536 size += slist_size(part->curlheaders, 2, NULL);
1537 size += slist_size(part->userheaders, 2, "Content-Type");
1538 size += 2; /* CRLF after headers. */
1545 CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
1547 struct curl_slist *hdr = NULL;
1552 s = curl_mvaprintf(fmt, ap);
1556 hdr = Curl_slist_append_nodup(*slp, s);
1563 return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY;
1566 /* Add a content type header. */
1567 static CURLcode add_content_type(struct curl_slist **slp,
1568 const char *type, const char *boundary)
1570 return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
1571 boundary? "; boundary=": "",
1572 boundary? boundary: "");
1576 static const char *ContentTypeForFilename(const char *filename)
1581 * If no content type was specified, we scan through a few well-known
1582 * extensions and pick the first we match!
1584 struct ContentType {
1585 const char *extension;
1588 static const struct ContentType ctts[] = {
1589 {".gif", "image/gif"},
1590 {".jpg", "image/jpeg"},
1591 {".jpeg", "image/jpeg"},
1592 {".png", "image/png"},
1593 {".svg", "image/svg+xml"},
1594 {".txt", "text/plain"},
1595 {".htm", "text/html"},
1596 {".html", "text/html"},
1597 {".pdf", "application/pdf"},
1598 {".xml", "application/xml"}
1602 size_t len1 = strlen(filename);
1603 const char *nameend = filename + len1;
1605 for(i = 0; i < sizeof ctts / sizeof ctts[0]; i++) {
1606 size_t len2 = strlen(ctts[i].extension);
1608 if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension))
1609 return ctts[i].type;
1615 CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
1616 const char *contenttype,
1617 const char *disposition,
1618 enum mimestrategy strategy)
1620 curl_mime *mime = NULL;
1621 const char *boundary = NULL;
1623 const char *cte = NULL;
1624 CURLcode ret = CURLE_OK;
1626 /* Get rid of previously prepared headers. */
1627 curl_slist_free_all(part->curlheaders);
1628 part->curlheaders = NULL;
1630 /* Be sure we won't access old headers later. */
1631 if(part->state.state == MIMESTATE_CURLHEADERS)
1632 mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
1634 /* Check if content type is specified. */
1635 customct = part->mimetype;
1637 customct = search_header(part->userheaders, "Content-Type");
1639 contenttype = customct;
1641 /* If content type is not specified, try to determine it. */
1643 switch(part->kind) {
1644 case MIMEKIND_MULTIPART:
1645 contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
1648 contenttype = ContentTypeForFilename(part->filename);
1650 contenttype = ContentTypeForFilename(part->data);
1651 if(!contenttype && part->filename)
1652 contenttype = FILE_CONTENTTYPE_DEFAULT;
1655 contenttype = ContentTypeForFilename(part->filename);
1660 if(part->kind == MIMEKIND_MULTIPART) {
1661 mime = (curl_mime *) part->arg;
1663 boundary = mime->boundary;
1665 else if(contenttype && !customct &&
1666 strcasecompare(contenttype, "text/plain"))
1667 if(strategy == MIMESTRATEGY_MAIL || !part->filename)
1670 /* Issue content-disposition header only if not already set by caller. */
1671 if(!search_header(part->userheaders, "Content-Disposition")) {
1673 if(part->filename || part->name ||
1674 (contenttype && !strncasecompare(contenttype, "multipart/", 10)))
1675 disposition = DISPOSITION_DEFAULT;
1676 if(disposition && curl_strequal(disposition, "attachment") &&
1677 !part->name && !part->filename)
1681 char *filename = NULL;
1684 name = escape_string(part->name);
1686 ret = CURLE_OUT_OF_MEMORY;
1688 if(!ret && part->filename) {
1689 filename = escape_string(part->filename);
1691 ret = CURLE_OUT_OF_MEMORY;
1694 ret = Curl_mime_add_header(&part->curlheaders,
1695 "Content-Disposition: %s%s%s%s%s%s%s",
1697 name? "; name=\"": "",
1700 filename? "; filename=\"": "",
1701 filename? filename: "",
1702 filename? "\"": "");
1703 Curl_safefree(name);
1704 Curl_safefree(filename);
1710 /* Issue Content-Type header. */
1712 ret = add_content_type(&part->curlheaders, contenttype, boundary);
1717 /* Content-Transfer-Encoding header. */
1718 if(!search_header(part->userheaders, "Content-Transfer-Encoding")) {
1720 cte = part->encoder->name;
1721 else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
1722 part->kind != MIMEKIND_MULTIPART)
1725 ret = Curl_mime_add_header(&part->curlheaders,
1726 "Content-Transfer-Encoding: %s", cte);
1732 /* If we were reading curl-generated headers, restart with new ones (this
1733 should not occur). */
1734 if(part->state.state == MIMESTATE_CURLHEADERS)
1735 mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
1737 /* Process subparts. */
1738 if(part->kind == MIMEKIND_MULTIPART && mime) {
1739 curl_mimepart *subpart;
1742 if(strcasecompare(contenttype, "multipart/form-data"))
1743 disposition = "form-data";
1744 for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
1745 ret = Curl_mime_prepare_headers(subpart, NULL, disposition, strategy);
1753 #else /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */
1755 /* Mime not compiled in: define stubs for externally-referenced functions. */
1756 curl_mime *curl_mime_init(CURL *easy)
1762 void curl_mime_free(curl_mime *mime)
1767 curl_mimepart *curl_mime_addpart(curl_mime *mime)
1773 CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1777 return CURLE_NOT_BUILT_IN;
1780 CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1784 return CURLE_NOT_BUILT_IN;
1787 CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1791 return CURLE_NOT_BUILT_IN;
1794 CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1798 return CURLE_NOT_BUILT_IN;
1801 CURLcode curl_mime_data(curl_mimepart *part,
1802 const char *data, size_t datasize)
1807 return CURLE_NOT_BUILT_IN;
1810 CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1814 return CURLE_NOT_BUILT_IN;
1817 CURLcode curl_mime_data_cb(curl_mimepart *part,
1818 curl_off_t datasize,
1819 curl_read_callback readfunc,
1820 curl_seek_callback seekfunc,
1821 curl_free_callback freefunc,
1830 return CURLE_NOT_BUILT_IN;
1833 CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
1837 return CURLE_NOT_BUILT_IN;
1840 CURLcode curl_mime_headers(curl_mimepart *part,
1841 struct curl_slist *headers, int take_ownership)
1845 (void) take_ownership;
1846 return CURLE_NOT_BUILT_IN;
1849 void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy)
1855 void Curl_mime_cleanpart(curl_mimepart *part)
1860 CURLcode Curl_mime_set_subparts(curl_mimepart *part,
1861 curl_mime *subparts, int take_ownership)
1865 (void) take_ownership;
1866 return CURLE_NOT_BUILT_IN;
1869 CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
1870 const char *contenttype,
1871 const char *disposition,
1872 enum mimestrategy strategy)
1878 return CURLE_NOT_BUILT_IN;
1881 curl_off_t Curl_mime_size(curl_mimepart *part)
1884 return (curl_off_t) -1;
1887 size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
1896 CURLcode Curl_mime_rewind(curl_mimepart *part)
1899 return CURLE_NOT_BUILT_IN;
1903 CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
1907 return CURLE_NOT_BUILT_IN;
1910 #endif /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */