xref: /curl/lib/mime.c (revision fc81bf42)
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 #include "strdup.h"
34 
35 #if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) ||      \
36                                     !defined(CURL_DISABLE_SMTP) ||      \
37                                     !defined(CURL_DISABLE_IMAP))
38 
39 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
40 #include <libgen.h>
41 #endif
42 
43 #include "rand.h"
44 #include "slist.h"
45 #include "strcase.h"
46 #include "dynbuf.h"
47 /* The last 3 #include files should be in this order */
48 #include "curl_printf.h"
49 #include "curl_memory.h"
50 #include "memdebug.h"
51 
52 #ifdef _WIN32
53 # ifndef R_OK
54 #  define R_OK 4
55 # endif
56 #endif
57 
58 
59 #define READ_ERROR                      ((size_t) -1)
60 #define STOP_FILLING                    ((size_t) -2)
61 
62 static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
63                                  void *instream, bool *hasread);
64 
65 /* Encoders. */
66 static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
67                                 curl_mimepart *part);
68 static curl_off_t encoder_nop_size(curl_mimepart *part);
69 static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
70                                 curl_mimepart *part);
71 static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
72                                 curl_mimepart *part);
73 static curl_off_t encoder_base64_size(curl_mimepart *part);
74 static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
75                               curl_mimepart *part);
76 static curl_off_t encoder_qp_size(curl_mimepart *part);
77 static curl_off_t mime_size(curl_mimepart *part);
78 
79 static const struct mime_encoder encoders[] = {
80   {"binary", encoder_nop_read, encoder_nop_size},
81   {"8bit", encoder_nop_read, encoder_nop_size},
82   {"7bit", encoder_7bit_read, encoder_nop_size},
83   {"base64", encoder_base64_read, encoder_base64_size},
84   {"quoted-printable", encoder_qp_read, encoder_qp_size},
85   {ZERO_NULL, ZERO_NULL, ZERO_NULL}
86 };
87 
88 /* Base64 encoding table */
89 static const char base64enc[] =
90   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
91 
92 /* Quoted-printable character class table.
93  *
94  * We cannot rely on ctype functions since quoted-printable input data
95  * is assumed to be ascii-compatible, even on non-ascii platforms. */
96 #define QP_OK           1       /* Can be represented by itself. */
97 #define QP_SP           2       /* Space or tab. */
98 #define QP_CR           3       /* Carriage return. */
99 #define QP_LF           4       /* Line-feed. */
100 static const unsigned char qp_class[] = {
101  0,     0,     0,     0,     0,     0,     0,     0,            /* 00 - 07 */
102  0,     QP_SP, QP_LF, 0,     0,     QP_CR, 0,     0,            /* 08 - 0F */
103  0,     0,     0,     0,     0,     0,     0,     0,            /* 10 - 17 */
104  0,     0,     0,     0,     0,     0,     0,     0,            /* 18 - 1F */
105  QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 20 - 27 */
106  QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 28 - 2F */
107  QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 30 - 37 */
108  QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0    , QP_OK, QP_OK,        /* 38 - 3F */
109  QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 40 - 47 */
110  QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 48 - 4F */
111  QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 50 - 57 */
112  QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 58 - 5F */
113  QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 60 - 67 */
114  QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 68 - 6F */
115  QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 70 - 77 */
116  QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0,            /* 78 - 7F */
117  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* 80 - 8F */
118  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* 90 - 9F */
119  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* A0 - AF */
120  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* B0 - BF */
121  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* C0 - CF */
122  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* D0 - DF */
123  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* E0 - EF */
124  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0                 /* F0 - FF */
125 };
126 
127 
128 /* Binary --> hexadecimal ASCII table. */
129 static const char aschex[] =
130   "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46";
131 
132 
133 
134 #ifndef __VMS
135 #define filesize(name, stat_data) (stat_data.st_size)
136 #define fopen_read fopen
137 
138 #else
139 
140 #include <fabdef.h>
141 /*
142  * get_vms_file_size does what it takes to get the real size of the file
143  *
144  * For fixed files, find out the size of the EOF block and adjust.
145  *
146  * For all others, have to read the entire file in, discarding the contents.
147  * Most posted text files will be small, and binary files like zlib archives
148  * and CD/DVD images should be either a STREAM_LF format or a fixed format.
149  *
150  */
VmsRealFileSize(const char * name,const struct_stat * stat_buf)151 curl_off_t VmsRealFileSize(const char *name,
152                            const struct_stat *stat_buf)
153 {
154   char buffer[8192];
155   curl_off_t count;
156   int ret_stat;
157   FILE * file;
158 
159   file = fopen(name, FOPEN_READTEXT); /* VMS */
160   if(!file)
161     return 0;
162 
163   count = 0;
164   ret_stat = 1;
165   while(ret_stat > 0) {
166     ret_stat = fread(buffer, 1, sizeof(buffer), file);
167     if(ret_stat)
168       count += ret_stat;
169   }
170   fclose(file);
171 
172   return count;
173 }
174 
175 /*
176  *
177  *  VmsSpecialSize checks to see if the stat st_size can be trusted and
178  *  if not to call a routine to get the correct size.
179  *
180  */
VmsSpecialSize(const char * name,const struct_stat * stat_buf)181 static curl_off_t VmsSpecialSize(const char *name,
182                                  const struct_stat *stat_buf)
183 {
184   switch(stat_buf->st_fab_rfm) {
185   case FAB$C_VAR:
186   case FAB$C_VFC:
187     return VmsRealFileSize(name, stat_buf);
188     break;
189   default:
190     return stat_buf->st_size;
191   }
192 }
193 
194 #define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
195 
196 /*
197  * vmsfopenread
198  *
199  * For upload to work as expected on VMS, different optional
200  * parameters must be added to the fopen command based on
201  * record format of the file.
202  *
203  */
vmsfopenread(const char * file,const char * mode)204 static FILE * vmsfopenread(const char *file, const char *mode)
205 {
206   struct_stat statbuf;
207   int result;
208 
209   result = stat(file, &statbuf);
210 
211   switch(statbuf.st_fab_rfm) {
212   case FAB$C_VAR:
213   case FAB$C_VFC:
214   case FAB$C_STMCR:
215     return fopen(file, FOPEN_READTEXT); /* VMS */
216     break;
217   default:
218     return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
219   }
220 }
221 
222 #define fopen_read vmsfopenread
223 #endif
224 
225 
226 #ifndef HAVE_BASENAME
227 /*
228   (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
229   Edition)
230 
231   The basename() function shall take the pathname pointed to by path and
232   return a pointer to the final component of the pathname, deleting any
233   trailing '/' characters.
234 
235   If the string pointed to by path consists entirely of the '/' character,
236   basename() shall return a pointer to the string "/". If the string pointed
237   to by path is exactly "//", it is implementation-defined whether '/' or "//"
238   is returned.
239 
240   If path is a null pointer or points to an empty string, basename() shall
241   return a pointer to the string ".".
242 
243   The basename() function may modify the string pointed to by path, and may
244   return a pointer to static storage that may then be overwritten by a
245   subsequent call to basename().
246 
247   The basename() function need not be reentrant. A function that is not
248   required to be reentrant is not required to be thread-safe.
249 
250 */
Curl_basename(char * path)251 static char *Curl_basename(char *path)
252 {
253   /* Ignore all the details above for now and make a quick and simple
254      implementation here */
255   char *s1;
256   char *s2;
257 
258   s1 = strrchr(path, '/');
259   s2 = strrchr(path, '\\');
260 
261   if(s1 && s2) {
262     path = (s1 > s2? s1 : s2) + 1;
263   }
264   else if(s1)
265     path = s1 + 1;
266   else if(s2)
267     path = s2 + 1;
268 
269   return path;
270 }
271 
272 #define basename(x)  Curl_basename((x))
273 #endif
274 
275 
276 /* Set readback state. */
mimesetstate(struct mime_state * state,enum mimestate tok,void * ptr)277 static void mimesetstate(struct mime_state *state,
278                          enum mimestate tok, void *ptr)
279 {
280   state->state = tok;
281   state->ptr = ptr;
282   state->offset = 0;
283 }
284 
285 
286 /* Escape header string into allocated memory. */
escape_string(struct Curl_easy * data,const char * src,enum mimestrategy strategy)287 static char *escape_string(struct Curl_easy *data,
288                            const char *src, enum mimestrategy strategy)
289 {
290   CURLcode result;
291   struct dynbuf db;
292   const char * const *table;
293   const char * const *p;
294   /* replace first character by rest of string. */
295   static const char * const mimetable[] = {
296     "\\\\\\",
297     "\"\\\"",
298     NULL
299   };
300   /* WHATWG HTML living standard 4.10.21.8 2 specifies:
301      For field names and filenames for file fields, the result of the
302      encoding in the previous bullet point must be escaped by replacing
303      any 0x0A (LF) bytes with the byte sequence `%0A`, 0x0D (CR) with `%0D`
304      and 0x22 (") with `%22`.
305      The user agent must not perform any other escapes. */
306   static const char * const formtable[] = {
307     "\"%22",
308     "\r%0D",
309     "\n%0A",
310     NULL
311   };
312 
313   table = formtable;
314   /* data can be NULL when this function is called indirectly from
315      curl_formget(). */
316   if(strategy == MIMESTRATEGY_MAIL || (data && (data->set.mime_formescape)))
317     table = mimetable;
318 
319   Curl_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
320 
321   for(result = Curl_dyn_addn(&db, STRCONST("")); !result && *src; src++) {
322     for(p = table; *p && **p != *src; p++)
323       ;
324 
325     if(*p)
326       result = Curl_dyn_add(&db, *p + 1);
327     else
328       result = Curl_dyn_addn(&db, src, 1);
329   }
330 
331   return Curl_dyn_ptr(&db);
332 }
333 
334 /* Check if header matches. */
match_header(struct curl_slist * hdr,const char * lbl,size_t len)335 static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
336 {
337   char *value = NULL;
338 
339   if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':')
340     for(value = hdr->data + len + 1; *value == ' '; value++)
341       ;
342   return value;
343 }
344 
345 /* Get a header from an slist. */
search_header(struct curl_slist * hdrlist,const char * hdr,size_t len)346 static char *search_header(struct curl_slist *hdrlist,
347                            const char *hdr, size_t len)
348 {
349   char *value = NULL;
350 
351   for(; !value && hdrlist; hdrlist = hdrlist->next)
352     value = match_header(hdrlist, hdr, len);
353 
354   return value;
355 }
356 
strippath(const char * fullfile)357 static char *strippath(const char *fullfile)
358 {
359   char *filename;
360   char *base;
361   filename = strdup(fullfile); /* duplicate since basename() may ruin the
362                                   buffer it works on */
363   if(!filename)
364     return NULL;
365   base = strdup(basename(filename));
366 
367   free(filename); /* free temporary buffer */
368 
369   return base; /* returns an allocated string or NULL ! */
370 }
371 
372 /* Initialize data encoder state. */
cleanup_encoder_state(struct mime_encoder_state * p)373 static void cleanup_encoder_state(struct mime_encoder_state *p)
374 {
375   p->pos = 0;
376   p->bufbeg = 0;
377   p->bufend = 0;
378 }
379 
380 
381 /* 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)382 static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
383                                struct curl_mimepart *part)
384 {
385   struct mime_encoder_state *st = &part->encstate;
386   size_t insize = st->bufend - st->bufbeg;
387 
388   (void) ateof;
389 
390   if(!size)
391     return STOP_FILLING;
392 
393   if(size > insize)
394     size = insize;
395 
396   if(size)
397     memcpy(buffer, st->buf + st->bufbeg, size);
398 
399   st->bufbeg += size;
400   return size;
401 }
402 
encoder_nop_size(curl_mimepart * part)403 static curl_off_t encoder_nop_size(curl_mimepart *part)
404 {
405   return part->datasize;
406 }
407 
408 
409 /* 7bit encoder: the encoder is just a data validity check. */
encoder_7bit_read(char * buffer,size_t size,bool ateof,curl_mimepart * part)410 static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
411                                 curl_mimepart *part)
412 {
413   struct mime_encoder_state *st = &part->encstate;
414   size_t cursize = st->bufend - st->bufbeg;
415 
416   (void) ateof;
417 
418   if(!size)
419     return STOP_FILLING;
420 
421   if(size > cursize)
422     size = cursize;
423 
424   for(cursize = 0; cursize < size; cursize++) {
425     *buffer = st->buf[st->bufbeg];
426     if(*buffer++ & 0x80)
427       return cursize? cursize: READ_ERROR;
428     st->bufbeg++;
429   }
430 
431   return cursize;
432 }
433 
434 
435 /* Base64 content encoder. */
encoder_base64_read(char * buffer,size_t size,bool ateof,curl_mimepart * part)436 static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
437                                 curl_mimepart *part)
438 {
439   struct mime_encoder_state *st = &part->encstate;
440   size_t cursize = 0;
441   int i;
442   char *ptr = buffer;
443 
444   while(st->bufbeg < st->bufend) {
445     /* Line full ? */
446     if(st->pos > MAX_ENCODED_LINE_LENGTH - 4) {
447       /* Yes, we need 2 characters for CRLF. */
448       if(size < 2) {
449         if(!cursize)
450           return STOP_FILLING;
451         break;
452       }
453       *ptr++ = '\r';
454       *ptr++ = '\n';
455       st->pos = 0;
456       cursize += 2;
457       size -= 2;
458     }
459 
460     /* Be sure there is enough space and input data for a base64 group. */
461     if(size < 4) {
462       if(!cursize)
463         return STOP_FILLING;
464       break;
465     }
466     if(st->bufend - st->bufbeg < 3)
467       break;
468 
469     /* Encode three bytes as four characters. */
470     i = st->buf[st->bufbeg++] & 0xFF;
471     i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
472     i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
473     *ptr++ = base64enc[(i >> 18) & 0x3F];
474     *ptr++ = base64enc[(i >> 12) & 0x3F];
475     *ptr++ = base64enc[(i >> 6) & 0x3F];
476     *ptr++ = base64enc[i & 0x3F];
477     cursize += 4;
478     st->pos += 4;
479     size -= 4;
480   }
481 
482   /* If at eof, we have to flush the buffered data. */
483   if(ateof) {
484     if(size < 4) {
485       if(!cursize)
486         return STOP_FILLING;
487     }
488     else {
489       /* Buffered data size can only be 0, 1 or 2. */
490       ptr[2] = ptr[3] = '=';
491       i = 0;
492 
493       /* If there is buffered data */
494       if(st->bufend != st->bufbeg) {
495 
496         if(st->bufend - st->bufbeg == 2)
497           i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
498 
499         i |= (st->buf[st->bufbeg] & 0xFF) << 16;
500         ptr[0] = base64enc[(i >> 18) & 0x3F];
501         ptr[1] = base64enc[(i >> 12) & 0x3F];
502         if(++st->bufbeg != st->bufend) {
503           ptr[2] = base64enc[(i >> 6) & 0x3F];
504           st->bufbeg++;
505         }
506         cursize += 4;
507         st->pos += 4;
508       }
509     }
510   }
511 
512   return cursize;
513 }
514 
encoder_base64_size(curl_mimepart * part)515 static curl_off_t encoder_base64_size(curl_mimepart *part)
516 {
517   curl_off_t size = part->datasize;
518 
519   if(size <= 0)
520     return size;    /* Unknown size or no data. */
521 
522   /* Compute base64 character count. */
523   size = 4 * (1 + (size - 1) / 3);
524 
525   /* Effective character count must include CRLFs. */
526   return size + 2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH);
527 }
528 
529 
530 /* Quoted-printable lookahead.
531  *
532  * Check if a CRLF or end of data is in input buffer at current position + n.
533  * Return -1 if more data needed, 1 if CRLF or end of data, else 0.
534  */
qp_lookahead_eol(struct mime_encoder_state * st,int ateof,size_t n)535 static int qp_lookahead_eol(struct mime_encoder_state *st, int ateof, size_t n)
536 {
537   n += st->bufbeg;
538   if(n >= st->bufend && ateof)
539     return 1;
540   if(n + 2 > st->bufend)
541     return ateof? 0: -1;
542   if(qp_class[st->buf[n] & 0xFF] == QP_CR &&
543      qp_class[st->buf[n + 1] & 0xFF] == QP_LF)
544     return 1;
545   return 0;
546 }
547 
548 /* Quoted-printable encoder. */
encoder_qp_read(char * buffer,size_t size,bool ateof,curl_mimepart * part)549 static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
550                               curl_mimepart *part)
551 {
552   struct mime_encoder_state *st = &part->encstate;
553   char *ptr = buffer;
554   size_t cursize = 0;
555   int softlinebreak;
556   char buf[4];
557 
558   /* On all platforms, input is supposed to be ASCII compatible: for this
559      reason, we use hexadecimal ASCII codes in this function rather than
560      character constants that can be interpreted as non-ascii on some
561      platforms. Preserve ASCII encoding on output too. */
562   while(st->bufbeg < st->bufend) {
563     size_t len = 1;
564     size_t consumed = 1;
565     int i = st->buf[st->bufbeg];
566     buf[0] = (char) i;
567     buf[1] = aschex[(i >> 4) & 0xF];
568     buf[2] = aschex[i & 0xF];
569 
570     switch(qp_class[st->buf[st->bufbeg] & 0xFF]) {
571     case QP_OK:          /* Not a special character. */
572       break;
573     case QP_SP:          /* Space or tab. */
574       /* Spacing must be escaped if followed by CRLF. */
575       switch(qp_lookahead_eol(st, ateof, 1)) {
576       case -1:          /* More input data needed. */
577         return cursize;
578       case 0:           /* No encoding needed. */
579         break;
580       default:          /* CRLF after space or tab. */
581         buf[0] = '\x3D';    /* '=' */
582         len = 3;
583         break;
584       }
585       break;
586     case QP_CR:         /* Carriage return. */
587       /* If followed by a line-feed, output the CRLF pair.
588          Else escape it. */
589       switch(qp_lookahead_eol(st, ateof, 0)) {
590       case -1:          /* Need more data. */
591         return cursize;
592       case 1:           /* CRLF found. */
593         buf[len++] = '\x0A';    /* Append '\n'. */
594         consumed = 2;
595         break;
596       default:          /* Not followed by LF: escape. */
597         buf[0] = '\x3D';    /* '=' */
598         len = 3;
599         break;
600       }
601       break;
602     default:            /* Character must be escaped. */
603       buf[0] = '\x3D';    /* '=' */
604       len = 3;
605       break;
606     }
607 
608     /* Be sure the encoded character fits within maximum line length. */
609     if(buf[len - 1] != '\x0A') {    /* '\n' */
610       softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH;
611       if(!softlinebreak && st->pos + len == MAX_ENCODED_LINE_LENGTH) {
612         /* We may use the current line only if end of data or followed by
613            a CRLF. */
614         switch(qp_lookahead_eol(st, ateof, consumed)) {
615         case -1:        /* Need more data. */
616           return cursize;
617         case 0:         /* Not followed by a CRLF. */
618           softlinebreak = 1;
619           break;
620         }
621       }
622       if(softlinebreak) {
623         strcpy(buf, "\x3D\x0D\x0A");    /* "=\r\n" */
624         len = 3;
625         consumed = 0;
626       }
627     }
628 
629     /* If the output buffer would overflow, do not store. */
630     if(len > size) {
631       if(!cursize)
632         return STOP_FILLING;
633       break;
634     }
635 
636     /* Append to output buffer. */
637     memcpy(ptr, buf, len);
638     cursize += len;
639     ptr += len;
640     size -= len;
641     st->pos += len;
642     if(buf[len - 1] == '\x0A')    /* '\n' */
643       st->pos = 0;
644     st->bufbeg += consumed;
645   }
646 
647   return cursize;
648 }
649 
encoder_qp_size(curl_mimepart * part)650 static curl_off_t encoder_qp_size(curl_mimepart *part)
651 {
652   /* Determining the size can only be done by reading the data: unless the
653      data size is 0, we return it as unknown (-1). */
654   return part->datasize? -1: 0;
655 }
656 
657 
658 /* In-memory data callbacks. */
659 /* Argument is a pointer to the mime part. */
mime_mem_read(char * buffer,size_t size,size_t nitems,void * instream)660 static size_t mime_mem_read(char *buffer, size_t size, size_t nitems,
661                             void *instream)
662 {
663   curl_mimepart *part = (curl_mimepart *) instream;
664   size_t sz = curlx_sotouz(part->datasize - part->state.offset);
665   (void) size;   /* Always 1.*/
666 
667   if(!nitems)
668     return STOP_FILLING;
669 
670   if(sz > nitems)
671     sz = nitems;
672 
673   if(sz)
674     memcpy(buffer, part->data + curlx_sotouz(part->state.offset), sz);
675 
676   return sz;
677 }
678 
mime_mem_seek(void * instream,curl_off_t offset,int whence)679 static int mime_mem_seek(void *instream, curl_off_t offset, int whence)
680 {
681   curl_mimepart *part = (curl_mimepart *) instream;
682 
683   switch(whence) {
684   case SEEK_CUR:
685     offset += part->state.offset;
686     break;
687   case SEEK_END:
688     offset += part->datasize;
689     break;
690   }
691 
692   if(offset < 0 || offset > part->datasize)
693     return CURL_SEEKFUNC_FAIL;
694 
695   part->state.offset = offset;
696   return CURL_SEEKFUNC_OK;
697 }
698 
mime_mem_free(void * ptr)699 static void mime_mem_free(void *ptr)
700 {
701   Curl_safefree(((curl_mimepart *) ptr)->data);
702 }
703 
704 
705 /* Named file callbacks. */
706 /* Argument is a pointer to the mime part. */
mime_open_file(curl_mimepart * part)707 static int mime_open_file(curl_mimepart *part)
708 {
709   /* Open a MIMEKIND_FILE part. */
710 
711   if(part->fp)
712     return 0;
713   part->fp = fopen_read(part->data, "rb");
714   return part->fp? 0: -1;
715 }
716 
mime_file_read(char * buffer,size_t size,size_t nitems,void * instream)717 static size_t mime_file_read(char *buffer, size_t size, size_t nitems,
718                              void *instream)
719 {
720   curl_mimepart *part = (curl_mimepart *) instream;
721 
722   if(!nitems)
723     return STOP_FILLING;
724 
725   if(mime_open_file(part))
726     return READ_ERROR;
727 
728   return fread(buffer, size, nitems, part->fp);
729 }
730 
mime_file_seek(void * instream,curl_off_t offset,int whence)731 static int mime_file_seek(void *instream, curl_off_t offset, int whence)
732 {
733   curl_mimepart *part = (curl_mimepart *) instream;
734 
735   if(whence == SEEK_SET && !offset && !part->fp)
736     return CURL_SEEKFUNC_OK;   /* Not open: implicitly already at BOF. */
737 
738   if(mime_open_file(part))
739     return CURL_SEEKFUNC_FAIL;
740 
741   return fseek(part->fp, (long) offset, whence)?
742                CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK;
743 }
744 
mime_file_free(void * ptr)745 static void mime_file_free(void *ptr)
746 {
747   curl_mimepart *part = (curl_mimepart *) ptr;
748 
749   if(part->fp) {
750     fclose(part->fp);
751     part->fp = NULL;
752   }
753   Curl_safefree(part->data);
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   if(part) {
1172     cleanup_part_content(part);
1173     curl_slist_free_all(part->curlheaders);
1174     if(part->flags & MIME_USERHEADERS_OWNER)
1175       curl_slist_free_all(part->userheaders);
1176     Curl_safefree(part->mimetype);
1177     Curl_safefree(part->name);
1178     Curl_safefree(part->filename);
1179     Curl_mime_initpart(part);
1180   }
1181 }
1182 
1183 /* Recursively delete a mime handle and its parts. */
curl_mime_free(curl_mime * mime)1184 void curl_mime_free(curl_mime *mime)
1185 {
1186   curl_mimepart *part;
1187 
1188   if(mime) {
1189     mime_subparts_unbind(mime);  /* Be sure it's not referenced anymore. */
1190     while(mime->firstpart) {
1191       part = mime->firstpart;
1192       mime->firstpart = part->nextpart;
1193       Curl_mime_cleanpart(part);
1194       free(part);
1195     }
1196     free(mime);
1197   }
1198 }
1199 
Curl_mime_duppart(struct Curl_easy * data,curl_mimepart * dst,const curl_mimepart * src)1200 CURLcode Curl_mime_duppart(struct Curl_easy *data,
1201                            curl_mimepart *dst, const curl_mimepart *src)
1202 {
1203   curl_mime *mime;
1204   curl_mimepart *d;
1205   const curl_mimepart *s;
1206   CURLcode res = CURLE_OK;
1207 
1208   DEBUGASSERT(dst);
1209 
1210   /* Duplicate content. */
1211   switch(src->kind) {
1212   case MIMEKIND_NONE:
1213     break;
1214   case MIMEKIND_DATA:
1215     res = curl_mime_data(dst, src->data, (size_t) src->datasize);
1216     break;
1217   case MIMEKIND_FILE:
1218     res = curl_mime_filedata(dst, src->data);
1219     /* Do not abort duplication if file is not readable. */
1220     if(res == CURLE_READ_ERROR)
1221       res = CURLE_OK;
1222     break;
1223   case MIMEKIND_CALLBACK:
1224     res = curl_mime_data_cb(dst, src->datasize, src->readfunc,
1225                             src->seekfunc, src->freefunc, src->arg);
1226     break;
1227   case MIMEKIND_MULTIPART:
1228     /* No one knows about the cloned subparts, thus always attach ownership
1229        to the part. */
1230     mime = curl_mime_init(data);
1231     res = mime? curl_mime_subparts(dst, mime): CURLE_OUT_OF_MEMORY;
1232 
1233     /* Duplicate subparts. */
1234     for(s = ((curl_mime *) src->arg)->firstpart; !res && s; s = s->nextpart) {
1235       d = curl_mime_addpart(mime);
1236       res = d? Curl_mime_duppart(data, d, s): CURLE_OUT_OF_MEMORY;
1237     }
1238     break;
1239   default:  /* Invalid kind: should not occur. */
1240     DEBUGF(infof(data, "invalid MIMEKIND* attempt"));
1241     res = CURLE_BAD_FUNCTION_ARGUMENT;  /* Internal error? */
1242     break;
1243   }
1244 
1245   /* Duplicate headers. */
1246   if(!res && src->userheaders) {
1247     struct curl_slist *hdrs = Curl_slist_duplicate(src->userheaders);
1248 
1249     if(!hdrs)
1250       res = CURLE_OUT_OF_MEMORY;
1251     else {
1252       /* No one but this procedure knows about the new header list,
1253          so always take ownership. */
1254       res = curl_mime_headers(dst, hdrs, TRUE);
1255       if(res)
1256         curl_slist_free_all(hdrs);
1257     }
1258   }
1259 
1260   if(!res) {
1261     /* Duplicate other fields. */
1262     dst->encoder = src->encoder;
1263     res = curl_mime_type(dst, src->mimetype);
1264   }
1265   if(!res)
1266     res = curl_mime_name(dst, src->name);
1267   if(!res)
1268     res = curl_mime_filename(dst, src->filename);
1269 
1270   /* If an error occurred, rollback. */
1271   if(res)
1272     Curl_mime_cleanpart(dst);
1273 
1274   return res;
1275 }
1276 
1277 /*
1278  * Mime build functions.
1279  */
1280 
1281 /* Create a mime handle. */
curl_mime_init(struct Curl_easy * easy)1282 curl_mime *curl_mime_init(struct Curl_easy *easy)
1283 {
1284   curl_mime *mime;
1285 
1286   mime = (curl_mime *) malloc(sizeof(*mime));
1287 
1288   if(mime) {
1289     mime->parent = NULL;
1290     mime->firstpart = NULL;
1291     mime->lastpart = NULL;
1292 
1293     memset(mime->boundary, '-', MIME_BOUNDARY_DASHES);
1294     if(Curl_rand_alnum(easy,
1295                        (unsigned char *) &mime->boundary[MIME_BOUNDARY_DASHES],
1296                        MIME_RAND_BOUNDARY_CHARS + 1)) {
1297       /* failed to get random separator, bail out */
1298       free(mime);
1299       return NULL;
1300     }
1301     mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1302   }
1303 
1304   return mime;
1305 }
1306 
1307 /* Initialize a mime part. */
Curl_mime_initpart(curl_mimepart * part)1308 void Curl_mime_initpart(curl_mimepart *part)
1309 {
1310   memset((char *) part, 0, sizeof(*part));
1311   part->lastreadstatus = 1; /* Successful read status. */
1312   mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
1313 }
1314 
1315 /* Create a mime part and append it to a mime handle's part list. */
curl_mime_addpart(curl_mime * mime)1316 curl_mimepart *curl_mime_addpart(curl_mime *mime)
1317 {
1318   curl_mimepart *part;
1319 
1320   if(!mime)
1321     return NULL;
1322 
1323   part = (curl_mimepart *) malloc(sizeof(*part));
1324 
1325   if(part) {
1326     Curl_mime_initpart(part);
1327     part->parent = mime;
1328 
1329     if(mime->lastpart)
1330       mime->lastpart->nextpart = part;
1331     else
1332       mime->firstpart = part;
1333 
1334     mime->lastpart = part;
1335   }
1336 
1337   return part;
1338 }
1339 
1340 /* Set mime part name. */
curl_mime_name(curl_mimepart * part,const char * name)1341 CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1342 {
1343   if(!part)
1344     return CURLE_BAD_FUNCTION_ARGUMENT;
1345 
1346   Curl_safefree(part->name);
1347 
1348   if(name) {
1349     part->name = strdup(name);
1350     if(!part->name)
1351       return CURLE_OUT_OF_MEMORY;
1352   }
1353 
1354   return CURLE_OK;
1355 }
1356 
1357 /* Set mime part remote file name. */
curl_mime_filename(curl_mimepart * part,const char * filename)1358 CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1359 {
1360   if(!part)
1361     return CURLE_BAD_FUNCTION_ARGUMENT;
1362 
1363   Curl_safefree(part->filename);
1364 
1365   if(filename) {
1366     part->filename = strdup(filename);
1367     if(!part->filename)
1368       return CURLE_OUT_OF_MEMORY;
1369   }
1370 
1371   return CURLE_OK;
1372 }
1373 
1374 /* Set mime part content from memory data. */
curl_mime_data(curl_mimepart * part,const char * ptr,size_t datasize)1375 CURLcode curl_mime_data(curl_mimepart *part,
1376                         const char *ptr, size_t datasize)
1377 {
1378   if(!part)
1379     return CURLE_BAD_FUNCTION_ARGUMENT;
1380 
1381   cleanup_part_content(part);
1382 
1383   if(ptr) {
1384     if(datasize == CURL_ZERO_TERMINATED)
1385       datasize = strlen(ptr);
1386 
1387     part->data = Curl_memdup0(ptr, datasize);
1388     if(!part->data)
1389       return CURLE_OUT_OF_MEMORY;
1390 
1391     part->datasize = datasize;
1392     part->readfunc = mime_mem_read;
1393     part->seekfunc = mime_mem_seek;
1394     part->freefunc = mime_mem_free;
1395     part->flags |= MIME_FAST_READ;
1396     part->kind = MIMEKIND_DATA;
1397   }
1398 
1399   return CURLE_OK;
1400 }
1401 
1402 /* Set mime part content from named local file. */
curl_mime_filedata(curl_mimepart * part,const char * filename)1403 CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1404 {
1405   CURLcode result = CURLE_OK;
1406 
1407   if(!part)
1408     return CURLE_BAD_FUNCTION_ARGUMENT;
1409 
1410   cleanup_part_content(part);
1411 
1412   if(filename) {
1413     char *base;
1414     struct_stat sbuf;
1415 
1416     if(stat(filename, &sbuf))
1417       result = CURLE_READ_ERROR;
1418     else {
1419       part->data = strdup(filename);
1420       if(!part->data)
1421         result = CURLE_OUT_OF_MEMORY;
1422       else {
1423         part->datasize = -1;
1424         if(S_ISREG(sbuf.st_mode)) {
1425           part->datasize = filesize(filename, sbuf);
1426           part->seekfunc = mime_file_seek;
1427         }
1428 
1429         part->readfunc = mime_file_read;
1430         part->freefunc = mime_file_free;
1431         part->kind = MIMEKIND_FILE;
1432 
1433         /* As a side effect, set the filename to the current file's base name.
1434            It is possible to withdraw this by explicitly calling
1435            curl_mime_filename() with a NULL filename argument after the current
1436            call. */
1437         base = strippath(filename);
1438         if(!base)
1439           result = CURLE_OUT_OF_MEMORY;
1440         else {
1441           result = curl_mime_filename(part, base);
1442           free(base);
1443         }
1444       }
1445     }
1446   }
1447   return result;
1448 }
1449 
1450 /* Set mime part type. */
curl_mime_type(curl_mimepart * part,const char * mimetype)1451 CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1452 {
1453   if(!part)
1454     return CURLE_BAD_FUNCTION_ARGUMENT;
1455 
1456   Curl_safefree(part->mimetype);
1457 
1458   if(mimetype) {
1459     part->mimetype = strdup(mimetype);
1460     if(!part->mimetype)
1461       return CURLE_OUT_OF_MEMORY;
1462   }
1463 
1464   return CURLE_OK;
1465 }
1466 
1467 /* Set mime data transfer encoder. */
curl_mime_encoder(curl_mimepart * part,const char * encoding)1468 CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1469 {
1470   CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
1471   const struct mime_encoder *mep;
1472 
1473   if(!part)
1474     return result;
1475 
1476   part->encoder = NULL;
1477 
1478   if(!encoding)
1479     return CURLE_OK;    /* Removing current encoder. */
1480 
1481   for(mep = encoders; mep->name; mep++)
1482     if(strcasecompare(encoding, mep->name)) {
1483       part->encoder = mep;
1484       result = CURLE_OK;
1485     }
1486 
1487   return result;
1488 }
1489 
1490 /* Set mime part headers. */
curl_mime_headers(curl_mimepart * part,struct curl_slist * headers,int take_ownership)1491 CURLcode curl_mime_headers(curl_mimepart *part,
1492                            struct curl_slist *headers, int take_ownership)
1493 {
1494   if(!part)
1495     return CURLE_BAD_FUNCTION_ARGUMENT;
1496 
1497   if(part->flags & MIME_USERHEADERS_OWNER) {
1498     if(part->userheaders != headers)  /* Allow setting twice the same list. */
1499       curl_slist_free_all(part->userheaders);
1500     part->flags &= ~MIME_USERHEADERS_OWNER;
1501   }
1502   part->userheaders = headers;
1503   if(headers && take_ownership)
1504     part->flags |= MIME_USERHEADERS_OWNER;
1505   return CURLE_OK;
1506 }
1507 
1508 /* 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)1509 CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize,
1510                            curl_read_callback readfunc,
1511                            curl_seek_callback seekfunc,
1512                            curl_free_callback freefunc, void *arg)
1513 {
1514   if(!part)
1515     return CURLE_BAD_FUNCTION_ARGUMENT;
1516 
1517   cleanup_part_content(part);
1518 
1519   if(readfunc) {
1520     part->readfunc = readfunc;
1521     part->seekfunc = seekfunc;
1522     part->freefunc = freefunc;
1523     part->arg = arg;
1524     part->datasize = datasize;
1525     part->kind = MIMEKIND_CALLBACK;
1526   }
1527 
1528   return CURLE_OK;
1529 }
1530 
1531 /* Set mime part content from subparts. */
Curl_mime_set_subparts(curl_mimepart * part,curl_mime * subparts,int take_ownership)1532 CURLcode Curl_mime_set_subparts(curl_mimepart *part,
1533                                 curl_mime *subparts, int take_ownership)
1534 {
1535   curl_mime *root;
1536 
1537   if(!part)
1538     return CURLE_BAD_FUNCTION_ARGUMENT;
1539 
1540   /* Accept setting twice the same subparts. */
1541   if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
1542     return CURLE_OK;
1543 
1544   cleanup_part_content(part);
1545 
1546   if(subparts) {
1547     /* Should not have been attached already. */
1548     if(subparts->parent)
1549       return CURLE_BAD_FUNCTION_ARGUMENT;
1550 
1551     /* Should not be the part's root. */
1552     root = part->parent;
1553     if(root) {
1554       while(root->parent && root->parent->parent)
1555         root = root->parent->parent;
1556       if(subparts == root) {
1557         /* Can't add as a subpart of itself. */
1558         return CURLE_BAD_FUNCTION_ARGUMENT;
1559       }
1560     }
1561 
1562     subparts->parent = part;
1563     /* Subparts are processed internally: no read callback. */
1564     part->seekfunc = mime_subparts_seek;
1565     part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind;
1566     part->arg = subparts;
1567     part->datasize = -1;
1568     part->kind = MIMEKIND_MULTIPART;
1569   }
1570 
1571   return CURLE_OK;
1572 }
1573 
curl_mime_subparts(curl_mimepart * part,curl_mime * subparts)1574 CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
1575 {
1576   return Curl_mime_set_subparts(part, subparts, TRUE);
1577 }
1578 
1579 
1580 /* Readback from top mime. */
1581 /* Argument is the dummy top part. */
Curl_mime_read(char * buffer,size_t size,size_t nitems,void * instream)1582 size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
1583 {
1584   curl_mimepart *part = (curl_mimepart *) instream;
1585   size_t ret;
1586   bool hasread;
1587 
1588   (void) size;   /* Always 1. */
1589 
1590   do {
1591     hasread = FALSE;
1592     ret = readback_part(part, buffer, nitems, &hasread);
1593     /*
1594      * If this is not possible to get some data without calling more than
1595      * one read callback (probably because a content encoder is not able to
1596      * deliver a new bunch for the few data accumulated so far), force another
1597      * read until we get enough data or a special exit code.
1598      */
1599   } while(ret == STOP_FILLING);
1600 
1601   return ret;
1602 }
1603 
1604 /* Rewind mime stream. */
mime_rewind(curl_mimepart * part)1605 static CURLcode mime_rewind(curl_mimepart *part)
1606 {
1607   return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
1608          CURLE_OK: CURLE_SEND_FAIL_REWIND;
1609 }
1610 
1611 /* Compute header list size. */
slist_size(struct curl_slist * s,size_t overhead,const char * skip,size_t skiplen)1612 static size_t slist_size(struct curl_slist *s,
1613                          size_t overhead, const char *skip, size_t skiplen)
1614 {
1615   size_t size = 0;
1616 
1617   for(; s; s = s->next)
1618     if(!skip || !match_header(s, skip, skiplen))
1619       size += strlen(s->data) + overhead;
1620   return size;
1621 }
1622 
1623 /* Get/compute multipart size. */
multipart_size(curl_mime * mime)1624 static curl_off_t multipart_size(curl_mime *mime)
1625 {
1626   curl_off_t size;
1627   curl_off_t boundarysize;
1628   curl_mimepart *part;
1629 
1630   if(!mime)
1631     return 0;           /* Not present -> empty. */
1632 
1633   boundarysize = 4 + MIME_BOUNDARY_LEN + 2;
1634   size = boundarysize;  /* Final boundary - CRLF after headers. */
1635 
1636   for(part = mime->firstpart; part; part = part->nextpart) {
1637     curl_off_t sz = mime_size(part);
1638 
1639     if(sz < 0)
1640       size = sz;
1641 
1642     if(size >= 0)
1643       size += boundarysize + sz;
1644   }
1645 
1646   return size;
1647 }
1648 
1649 /* Get/compute mime size. */
mime_size(curl_mimepart * part)1650 static curl_off_t mime_size(curl_mimepart *part)
1651 {
1652   curl_off_t size;
1653 
1654   if(part->kind == MIMEKIND_MULTIPART)
1655     part->datasize = multipart_size(part->arg);
1656 
1657   size = part->datasize;
1658 
1659   if(part->encoder)
1660     size = part->encoder->sizefunc(part);
1661 
1662   if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
1663     /* Compute total part size. */
1664     size += slist_size(part->curlheaders, 2, NULL, 0);
1665     size += slist_size(part->userheaders, 2, STRCONST("Content-Type"));
1666     size += 2;    /* CRLF after headers. */
1667   }
1668   return size;
1669 }
1670 
1671 /* Add a header. */
1672 /* VARARGS2 */
Curl_mime_add_header(struct curl_slist ** slp,const char * fmt,...)1673 CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
1674 {
1675   struct curl_slist *hdr = NULL;
1676   char *s = NULL;
1677   va_list ap;
1678 
1679   va_start(ap, fmt);
1680   s = curl_mvaprintf(fmt, ap);
1681   va_end(ap);
1682 
1683   if(s) {
1684     hdr = Curl_slist_append_nodup(*slp, s);
1685     if(hdr)
1686       *slp = hdr;
1687     else
1688       free(s);
1689   }
1690 
1691   return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY;
1692 }
1693 
1694 /* Add a content type header. */
add_content_type(struct curl_slist ** slp,const char * type,const char * boundary)1695 static CURLcode add_content_type(struct curl_slist **slp,
1696                                  const char *type, const char *boundary)
1697 {
1698   return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
1699                               boundary? "; boundary=": "",
1700                               boundary? boundary: "");
1701 }
1702 
Curl_mime_contenttype(const char * filename)1703 const char *Curl_mime_contenttype(const char *filename)
1704 {
1705   /*
1706    * If no content type was specified, we scan through a few well-known
1707    * extensions and pick the first we match!
1708    */
1709   struct ContentType {
1710     const char *extension;
1711     const char *type;
1712   };
1713   static const struct ContentType ctts[] = {
1714     {".gif",  "image/gif"},
1715     {".jpg",  "image/jpeg"},
1716     {".jpeg", "image/jpeg"},
1717     {".png",  "image/png"},
1718     {".svg",  "image/svg+xml"},
1719     {".txt",  "text/plain"},
1720     {".htm",  "text/html"},
1721     {".html", "text/html"},
1722     {".pdf",  "application/pdf"},
1723     {".xml",  "application/xml"}
1724   };
1725 
1726   if(filename) {
1727     size_t len1 = strlen(filename);
1728     const char *nameend = filename + len1;
1729     unsigned int i;
1730 
1731     for(i = 0; i < sizeof(ctts) / sizeof(ctts[0]); i++) {
1732       size_t len2 = strlen(ctts[i].extension);
1733 
1734       if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension))
1735         return ctts[i].type;
1736     }
1737   }
1738   return NULL;
1739 }
1740 
content_type_match(const char * contenttype,const char * target,size_t len)1741 static bool content_type_match(const char *contenttype,
1742                                const char *target, size_t len)
1743 {
1744   if(contenttype && strncasecompare(contenttype, target, len))
1745     switch(contenttype[len]) {
1746     case '\0':
1747     case '\t':
1748     case '\r':
1749     case '\n':
1750     case ' ':
1751     case ';':
1752       return TRUE;
1753     }
1754   return FALSE;
1755 }
1756 
Curl_mime_prepare_headers(struct Curl_easy * data,curl_mimepart * part,const char * contenttype,const char * disposition,enum mimestrategy strategy)1757 CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
1758                                    curl_mimepart *part,
1759                                    const char *contenttype,
1760                                    const char *disposition,
1761                                    enum mimestrategy strategy)
1762 {
1763   curl_mime *mime = NULL;
1764   const char *boundary = NULL;
1765   char *customct;
1766   const char *cte = NULL;
1767   CURLcode ret = CURLE_OK;
1768 
1769   /* Get rid of previously prepared headers. */
1770   curl_slist_free_all(part->curlheaders);
1771   part->curlheaders = NULL;
1772 
1773   /* Be sure we won't access old headers later. */
1774   if(part->state.state == MIMESTATE_CURLHEADERS)
1775     mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
1776 
1777   /* Check if content type is specified. */
1778   customct = part->mimetype;
1779   if(!customct)
1780     customct = search_header(part->userheaders, STRCONST("Content-Type"));
1781   if(customct)
1782     contenttype = customct;
1783 
1784   /* If content type is not specified, try to determine it. */
1785   if(!contenttype) {
1786     switch(part->kind) {
1787     case MIMEKIND_MULTIPART:
1788       contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
1789       break;
1790     case MIMEKIND_FILE:
1791       contenttype = Curl_mime_contenttype(part->filename);
1792       if(!contenttype)
1793         contenttype = Curl_mime_contenttype(part->data);
1794       if(!contenttype && part->filename)
1795         contenttype = FILE_CONTENTTYPE_DEFAULT;
1796       break;
1797     default:
1798       contenttype = Curl_mime_contenttype(part->filename);
1799       break;
1800     }
1801   }
1802 
1803   if(part->kind == MIMEKIND_MULTIPART) {
1804     mime = (curl_mime *) part->arg;
1805     if(mime)
1806       boundary = mime->boundary;
1807   }
1808   else if(contenttype && !customct &&
1809           content_type_match(contenttype, STRCONST("text/plain")))
1810     if(strategy == MIMESTRATEGY_MAIL || !part->filename)
1811       contenttype = NULL;
1812 
1813   /* Issue content-disposition header only if not already set by caller. */
1814   if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
1815     if(!disposition)
1816       if(part->filename || part->name ||
1817         (contenttype && !strncasecompare(contenttype, "multipart/", 10)))
1818           disposition = DISPOSITION_DEFAULT;
1819     if(disposition && curl_strequal(disposition, "attachment") &&
1820      !part->name && !part->filename)
1821       disposition = NULL;
1822     if(disposition) {
1823       char *name = NULL;
1824       char *filename = NULL;
1825 
1826       if(part->name) {
1827         name = escape_string(data, part->name, strategy);
1828         if(!name)
1829           ret = CURLE_OUT_OF_MEMORY;
1830       }
1831       if(!ret && part->filename) {
1832         filename = escape_string(data, part->filename, strategy);
1833         if(!filename)
1834           ret = CURLE_OUT_OF_MEMORY;
1835       }
1836       if(!ret)
1837         ret = Curl_mime_add_header(&part->curlheaders,
1838                                    "Content-Disposition: %s%s%s%s%s%s%s",
1839                                    disposition,
1840                                    name? "; name=\"": "",
1841                                    name? name: "",
1842                                    name? "\"": "",
1843                                    filename? "; filename=\"": "",
1844                                    filename? filename: "",
1845                                    filename? "\"": "");
1846       Curl_safefree(name);
1847       Curl_safefree(filename);
1848       if(ret)
1849         return ret;
1850       }
1851     }
1852 
1853   /* Issue Content-Type header. */
1854   if(contenttype) {
1855     ret = add_content_type(&part->curlheaders, contenttype, boundary);
1856     if(ret)
1857       return ret;
1858   }
1859 
1860   /* Content-Transfer-Encoding header. */
1861   if(!search_header(part->userheaders,
1862                     STRCONST("Content-Transfer-Encoding"))) {
1863     if(part->encoder)
1864       cte = part->encoder->name;
1865     else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
1866      part->kind != MIMEKIND_MULTIPART)
1867       cte = "8bit";
1868     if(cte) {
1869       ret = Curl_mime_add_header(&part->curlheaders,
1870                                  "Content-Transfer-Encoding: %s", cte);
1871       if(ret)
1872         return ret;
1873     }
1874   }
1875 
1876   /* If we were reading curl-generated headers, restart with new ones (this
1877      should not occur). */
1878   if(part->state.state == MIMESTATE_CURLHEADERS)
1879     mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
1880 
1881   /* Process subparts. */
1882   if(part->kind == MIMEKIND_MULTIPART && mime) {
1883     curl_mimepart *subpart;
1884 
1885     disposition = NULL;
1886     if(content_type_match(contenttype, STRCONST("multipart/form-data")))
1887       disposition = "form-data";
1888     for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
1889       ret = Curl_mime_prepare_headers(data, subpart, NULL,
1890                                       disposition, strategy);
1891       if(ret)
1892         return ret;
1893     }
1894   }
1895   return ret;
1896 }
1897 
1898 /* Recursively reset paused status in the given part. */
mime_unpause(curl_mimepart * part)1899 static void mime_unpause(curl_mimepart *part)
1900 {
1901   if(part) {
1902     if(part->lastreadstatus == CURL_READFUNC_PAUSE)
1903       part->lastreadstatus = 1; /* Successful read status. */
1904     if(part->kind == MIMEKIND_MULTIPART) {
1905       curl_mime *mime = (curl_mime *) part->arg;
1906 
1907       if(mime) {
1908         curl_mimepart *subpart;
1909 
1910         for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart)
1911           mime_unpause(subpart);
1912       }
1913     }
1914   }
1915 }
1916 
1917 struct cr_mime_ctx {
1918   struct Curl_creader super;
1919   curl_mimepart *part;
1920   curl_off_t total_len;
1921   curl_off_t read_len;
1922   CURLcode error_result;
1923   BIT(seen_eos);
1924   BIT(errored);
1925 };
1926 
cr_mime_init(struct Curl_easy * data,struct Curl_creader * reader)1927 static CURLcode cr_mime_init(struct Curl_easy *data,
1928                              struct Curl_creader *reader)
1929 {
1930   struct cr_mime_ctx *ctx = reader->ctx;
1931   (void)data;
1932   ctx->total_len = -1;
1933   ctx->read_len = 0;
1934   return CURLE_OK;
1935 }
1936 
1937 /* Real client reader to installed client callbacks. */
cr_mime_read(struct Curl_easy * data,struct Curl_creader * reader,char * buf,size_t blen,size_t * pnread,bool * peos)1938 static CURLcode cr_mime_read(struct Curl_easy *data,
1939                              struct Curl_creader *reader,
1940                              char *buf, size_t blen,
1941                              size_t *pnread, bool *peos)
1942 {
1943   struct cr_mime_ctx *ctx = reader->ctx;
1944   size_t nread;
1945 
1946   /* Once we have errored, we will return the same error forever */
1947   if(ctx->errored) {
1948     *pnread = 0;
1949     *peos = FALSE;
1950     return ctx->error_result;
1951   }
1952   if(ctx->seen_eos) {
1953     *pnread = 0;
1954     *peos = TRUE;
1955     return CURLE_OK;
1956   }
1957   /* respect length limitations */
1958   if(ctx->total_len >= 0) {
1959     curl_off_t remain = ctx->total_len - ctx->read_len;
1960     if(remain <= 0)
1961       blen = 0;
1962     else if(remain < (curl_off_t)blen)
1963       blen = (size_t)remain;
1964   }
1965   nread = 0;
1966   if(blen) {
1967     nread = Curl_mime_read(buf, 1, blen, ctx->part);
1968   }
1969 
1970   switch(nread) {
1971   case 0:
1972     if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
1973       failf(data, "client mime read EOF fail, only "
1974             "only %"CURL_FORMAT_CURL_OFF_T"/%"CURL_FORMAT_CURL_OFF_T
1975             " of needed bytes read", ctx->read_len, ctx->total_len);
1976       return CURLE_READ_ERROR;
1977     }
1978     *pnread = 0;
1979     *peos = TRUE;
1980     ctx->seen_eos = TRUE;
1981     break;
1982 
1983   case CURL_READFUNC_ABORT:
1984     failf(data, "operation aborted by callback");
1985     *pnread = 0;
1986     *peos = FALSE;
1987     ctx->errored = TRUE;
1988     ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
1989     return CURLE_ABORTED_BY_CALLBACK;
1990 
1991   case CURL_READFUNC_PAUSE:
1992     /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
1993     data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
1994     *pnread = 0;
1995     *peos = FALSE;
1996     break; /* nothing was read */
1997 
1998   default:
1999     if(nread > blen) {
2000       /* the read function returned a too large value */
2001       failf(data, "read function returned funny value");
2002       *pnread = 0;
2003       *peos = FALSE;
2004       ctx->errored = TRUE;
2005       ctx->error_result = CURLE_READ_ERROR;
2006       return CURLE_READ_ERROR;
2007     }
2008     ctx->read_len += nread;
2009     if(ctx->total_len >= 0)
2010       ctx->seen_eos = (ctx->read_len >= ctx->total_len);
2011     *pnread = nread;
2012     *peos = ctx->seen_eos;
2013     break;
2014   }
2015   DEBUGF(infof(data, "cr_mime_read(len=%zu, total=%"CURL_FORMAT_CURL_OFF_T
2016          ", read=%"CURL_FORMAT_CURL_OFF_T") -> %d, %zu, %d",
2017          blen, ctx->total_len, ctx->read_len, CURLE_OK, *pnread, *peos));
2018   return CURLE_OK;
2019 }
2020 
cr_mime_needs_rewind(struct Curl_easy * data,struct Curl_creader * reader)2021 static bool cr_mime_needs_rewind(struct Curl_easy *data,
2022                                  struct Curl_creader *reader)
2023 {
2024   struct cr_mime_ctx *ctx = reader->ctx;
2025   (void)data;
2026   return ctx->read_len > 0;
2027 }
2028 
cr_mime_total_length(struct Curl_easy * data,struct Curl_creader * reader)2029 static curl_off_t cr_mime_total_length(struct Curl_easy *data,
2030                                        struct Curl_creader *reader)
2031 {
2032   struct cr_mime_ctx *ctx = reader->ctx;
2033   (void)data;
2034   return ctx->total_len;
2035 }
2036 
cr_mime_resume_from(struct Curl_easy * data,struct Curl_creader * reader,curl_off_t offset)2037 static CURLcode cr_mime_resume_from(struct Curl_easy *data,
2038                                     struct Curl_creader *reader,
2039                                     curl_off_t offset)
2040 {
2041   struct cr_mime_ctx *ctx = reader->ctx;
2042 
2043   if(offset > 0) {
2044     curl_off_t passed = 0;
2045 
2046     do {
2047       char scratch[4*1024];
2048       size_t readthisamountnow =
2049         (offset - passed > (curl_off_t)sizeof(scratch)) ?
2050         sizeof(scratch) :
2051         curlx_sotouz(offset - passed);
2052       size_t nread;
2053 
2054       nread = Curl_mime_read(scratch, 1, readthisamountnow, ctx->part);
2055       passed += (curl_off_t)nread;
2056       if((nread == 0) || (nread > readthisamountnow)) {
2057         /* this checks for greater-than only to make sure that the
2058            CURL_READFUNC_ABORT return code still aborts */
2059         failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T
2060               " bytes from the mime post", passed);
2061         return CURLE_READ_ERROR;
2062       }
2063     } while(passed < offset);
2064 
2065     /* now, decrease the size of the read */
2066     if(ctx->total_len > 0) {
2067       ctx->total_len -= offset;
2068 
2069       if(ctx->total_len <= 0) {
2070         failf(data, "Mime post already completely uploaded");
2071         return CURLE_PARTIAL_FILE;
2072       }
2073     }
2074     /* we've passed, proceed as normal */
2075   }
2076   return CURLE_OK;
2077 }
2078 
cr_mime_rewind(struct Curl_easy * data,struct Curl_creader * reader)2079 static CURLcode cr_mime_rewind(struct Curl_easy *data,
2080                                struct Curl_creader *reader)
2081 {
2082   struct cr_mime_ctx *ctx = reader->ctx;
2083   CURLcode result = mime_rewind(ctx->part);
2084   if(result)
2085     failf(data, "Cannot rewind mime/post data");
2086   return result;
2087 }
2088 
cr_mime_unpause(struct Curl_easy * data,struct Curl_creader * reader)2089 static CURLcode cr_mime_unpause(struct Curl_easy *data,
2090                                 struct Curl_creader *reader)
2091 {
2092   struct cr_mime_ctx *ctx = reader->ctx;
2093   (void)data;
2094   mime_unpause(ctx->part);
2095   return CURLE_OK;
2096 }
2097 
2098 static const struct Curl_crtype cr_mime = {
2099   "cr-mime",
2100   cr_mime_init,
2101   cr_mime_read,
2102   Curl_creader_def_close,
2103   cr_mime_needs_rewind,
2104   cr_mime_total_length,
2105   cr_mime_resume_from,
2106   cr_mime_rewind,
2107   cr_mime_unpause,
2108   Curl_creader_def_done,
2109   sizeof(struct cr_mime_ctx)
2110 };
2111 
Curl_creader_set_mime(struct Curl_easy * data,curl_mimepart * part)2112 CURLcode Curl_creader_set_mime(struct Curl_easy *data, curl_mimepart *part)
2113 {
2114   struct Curl_creader *r;
2115   struct cr_mime_ctx *ctx;
2116   CURLcode result;
2117 
2118   result = Curl_creader_create(&r, data, &cr_mime, CURL_CR_CLIENT);
2119   if(result)
2120     return result;
2121   ctx = r->ctx;
2122   ctx->part = part;
2123   /* Make sure we will read the entire mime structure. */
2124   result = mime_rewind(ctx->part);
2125   if(result) {
2126     Curl_creader_free(data, r);
2127     return result;
2128   }
2129   ctx->total_len = mime_size(ctx->part);
2130 
2131   return Curl_creader_set(data, r);
2132 }
2133 
2134 #else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP ||
2135                                 !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP) */
2136 
2137 /* Mime not compiled in: define stubs for externally-referenced functions. */
curl_mime_init(CURL * easy)2138 curl_mime *curl_mime_init(CURL *easy)
2139 {
2140   (void) easy;
2141   return NULL;
2142 }
2143 
curl_mime_free(curl_mime * mime)2144 void curl_mime_free(curl_mime *mime)
2145 {
2146   (void) mime;
2147 }
2148 
curl_mime_addpart(curl_mime * mime)2149 curl_mimepart *curl_mime_addpart(curl_mime *mime)
2150 {
2151   (void) mime;
2152   return NULL;
2153 }
2154 
curl_mime_name(curl_mimepart * part,const char * name)2155 CURLcode curl_mime_name(curl_mimepart *part, const char *name)
2156 {
2157   (void) part;
2158   (void) name;
2159   return CURLE_NOT_BUILT_IN;
2160 }
2161 
curl_mime_filename(curl_mimepart * part,const char * filename)2162 CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
2163 {
2164   (void) part;
2165   (void) filename;
2166   return CURLE_NOT_BUILT_IN;
2167 }
2168 
curl_mime_type(curl_mimepart * part,const char * mimetype)2169 CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
2170 {
2171   (void) part;
2172   (void) mimetype;
2173   return CURLE_NOT_BUILT_IN;
2174 }
2175 
curl_mime_encoder(curl_mimepart * part,const char * encoding)2176 CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
2177 {
2178   (void) part;
2179   (void) encoding;
2180   return CURLE_NOT_BUILT_IN;
2181 }
2182 
curl_mime_data(curl_mimepart * part,const char * data,size_t datasize)2183 CURLcode curl_mime_data(curl_mimepart *part,
2184                         const char *data, size_t datasize)
2185 {
2186   (void) part;
2187   (void) data;
2188   (void) datasize;
2189   return CURLE_NOT_BUILT_IN;
2190 }
2191 
curl_mime_filedata(curl_mimepart * part,const char * filename)2192 CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
2193 {
2194   (void) part;
2195   (void) filename;
2196   return CURLE_NOT_BUILT_IN;
2197 }
2198 
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)2199 CURLcode curl_mime_data_cb(curl_mimepart *part,
2200                            curl_off_t datasize,
2201                            curl_read_callback readfunc,
2202                            curl_seek_callback seekfunc,
2203                            curl_free_callback freefunc,
2204                            void *arg)
2205 {
2206   (void) part;
2207   (void) datasize;
2208   (void) readfunc;
2209   (void) seekfunc;
2210   (void) freefunc;
2211   (void) arg;
2212   return CURLE_NOT_BUILT_IN;
2213 }
2214 
curl_mime_subparts(curl_mimepart * part,curl_mime * subparts)2215 CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
2216 {
2217   (void) part;
2218   (void) subparts;
2219   return CURLE_NOT_BUILT_IN;
2220 }
2221 
curl_mime_headers(curl_mimepart * part,struct curl_slist * headers,int take_ownership)2222 CURLcode curl_mime_headers(curl_mimepart *part,
2223                            struct curl_slist *headers, int take_ownership)
2224 {
2225   (void) part;
2226   (void) headers;
2227   (void) take_ownership;
2228   return CURLE_NOT_BUILT_IN;
2229 }
2230 
Curl_mime_add_header(struct curl_slist ** slp,const char * fmt,...)2231 CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
2232 {
2233   (void)slp;
2234   (void)fmt;
2235   return CURLE_NOT_BUILT_IN;
2236 }
2237 
2238 #endif /* if disabled */
2239