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