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