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