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
curl_boundary_max_length()1277 size_t curl_boundary_max_length()
1278 {
1279 return MIME_BOUNDARY_LEN;
1280 }
1281
1282 /*
1283 * Mime build functions.
1284 */
1285
curl_mime_init_with_boundary(struct Curl_easy * easy,const char * boundary,size_t length)1286 curl_mime *curl_mime_init_with_boundary(struct Curl_easy *easy, const char *boundary, size_t length)
1287 {
1288 if (length > MIME_BOUNDARY_LEN) {
1289 length = MIME_BOUNDARY_LEN;
1290 }
1291 curl_mime *mime;
1292 mime = (curl_mime *) malloc(sizeof(struct curl_mime));
1293 if (mime) {
1294 mime->parent = NULL;
1295 mime->firstpart = NULL;
1296 mime->lastpart = NULL;
1297 memset(mime->boundary, 0, MIME_BOUNDARY_LEN + 1);
1298 memcpy(mime->boundary, boundary, length);
1299 mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1300 }
1301 return mime;
1302 }
1303
1304 /* Create a mime handle. */
curl_mime_init(struct Curl_easy * easy)1305 curl_mime *curl_mime_init(struct Curl_easy *easy)
1306 {
1307 curl_mime *mime;
1308
1309 mime = (curl_mime *) malloc(sizeof(*mime));
1310
1311 if(mime) {
1312 mime->parent = NULL;
1313 mime->firstpart = NULL;
1314 mime->lastpart = NULL;
1315
1316 memset(mime->boundary, '-', MIME_BOUNDARY_DASHES);
1317 if(Curl_rand_alnum(easy,
1318 (unsigned char *) &mime->boundary[MIME_BOUNDARY_DASHES],
1319 MIME_RAND_BOUNDARY_CHARS + 1)) {
1320 /* failed to get random separator, bail out */
1321 free(mime);
1322 return NULL;
1323 }
1324 mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1325 }
1326
1327 return mime;
1328 }
1329
1330 /* Initialize a mime part. */
Curl_mime_initpart(curl_mimepart * part)1331 void Curl_mime_initpart(curl_mimepart *part)
1332 {
1333 memset((char *) part, 0, sizeof(*part));
1334 part->lastreadstatus = 1; /* Successful read status. */
1335 mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
1336 }
1337
1338 /* Create a mime part and append it to a mime handle's part list. */
curl_mime_addpart(curl_mime * mime)1339 curl_mimepart *curl_mime_addpart(curl_mime *mime)
1340 {
1341 curl_mimepart *part;
1342
1343 if(!mime)
1344 return NULL;
1345
1346 part = (curl_mimepart *) malloc(sizeof(*part));
1347
1348 if(part) {
1349 Curl_mime_initpart(part);
1350 part->parent = mime;
1351
1352 if(mime->lastpart)
1353 mime->lastpart->nextpart = part;
1354 else
1355 mime->firstpart = part;
1356
1357 mime->lastpart = part;
1358 }
1359
1360 return part;
1361 }
1362
1363 /* Set mime part name. */
curl_mime_name(curl_mimepart * part,const char * name)1364 CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1365 {
1366 if(!part)
1367 return CURLE_BAD_FUNCTION_ARGUMENT;
1368
1369 Curl_safefree(part->name);
1370
1371 if(name) {
1372 part->name = strdup(name);
1373 if(!part->name)
1374 return CURLE_OUT_OF_MEMORY;
1375 }
1376
1377 return CURLE_OK;
1378 }
1379
1380 /* Set mime part remote file name. */
curl_mime_filename(curl_mimepart * part,const char * filename)1381 CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1382 {
1383 if(!part)
1384 return CURLE_BAD_FUNCTION_ARGUMENT;
1385
1386 Curl_safefree(part->filename);
1387
1388 if(filename) {
1389 part->filename = strdup(filename);
1390 if(!part->filename)
1391 return CURLE_OUT_OF_MEMORY;
1392 }
1393
1394 return CURLE_OK;
1395 }
1396
1397 /* Set mime part content from memory data. */
curl_mime_data(curl_mimepart * part,const char * ptr,size_t datasize)1398 CURLcode curl_mime_data(curl_mimepart *part,
1399 const char *ptr, size_t datasize)
1400 {
1401 if(!part)
1402 return CURLE_BAD_FUNCTION_ARGUMENT;
1403
1404 cleanup_part_content(part);
1405
1406 if(ptr) {
1407 if(datasize == CURL_ZERO_TERMINATED)
1408 datasize = strlen(ptr);
1409
1410 part->data = Curl_memdup0(ptr, datasize);
1411 if(!part->data)
1412 return CURLE_OUT_OF_MEMORY;
1413
1414 part->datasize = datasize;
1415 part->readfunc = mime_mem_read;
1416 part->seekfunc = mime_mem_seek;
1417 part->freefunc = mime_mem_free;
1418 part->flags |= MIME_FAST_READ;
1419 part->kind = MIMEKIND_DATA;
1420 }
1421
1422 return CURLE_OK;
1423 }
1424
1425 /* Set mime part content from named local file. */
curl_mime_filedata(curl_mimepart * part,const char * filename)1426 CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1427 {
1428 CURLcode result = CURLE_OK;
1429
1430 if(!part)
1431 return CURLE_BAD_FUNCTION_ARGUMENT;
1432
1433 cleanup_part_content(part);
1434
1435 if(filename) {
1436 char *base;
1437 struct_stat sbuf;
1438
1439 if(stat(filename, &sbuf) || access(filename, R_OK))
1440 result = CURLE_READ_ERROR;
1441
1442 part->data = strdup(filename);
1443 if (!part->data)
1444 result = CURLE_OUT_OF_MEMORY;
1445
1446 part->datasize = -1;
1447 if (!result && S_ISREG(sbuf.st_mode)) {
1448 part->datasize = filesize(filename, sbuf);
1449 part->seekfunc = mime_file_seek;
1450 }
1451
1452 part->readfunc = mime_file_read;
1453 part->freefunc = mime_file_free;
1454 part->kind = MIMEKIND_FILE;
1455
1456 /* As a side effect, set the filename to the current file's base name.
1457 It is possible to withdraw this by explicitly calling
1458 curl_mime_filename() with a NULL filename argument after the current
1459 call. */
1460 base = strippath(filename);
1461 if (!base)
1462 result = CURLE_OUT_OF_MEMORY;
1463 else {
1464 CURLcode res = curl_mime_filename(part, base);
1465
1466 if (res)
1467 result = res;
1468 free(base);
1469 }
1470 }
1471 return result;
1472 }
1473
1474 /* Set mime part type. */
curl_mime_type(curl_mimepart * part,const char * mimetype)1475 CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1476 {
1477 if(!part)
1478 return CURLE_BAD_FUNCTION_ARGUMENT;
1479
1480 Curl_safefree(part->mimetype);
1481
1482 if(mimetype) {
1483 part->mimetype = strdup(mimetype);
1484 if(!part->mimetype)
1485 return CURLE_OUT_OF_MEMORY;
1486 }
1487
1488 return CURLE_OK;
1489 }
1490
1491 /* Set mime data transfer encoder. */
curl_mime_encoder(curl_mimepart * part,const char * encoding)1492 CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1493 {
1494 CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
1495 const struct mime_encoder *mep;
1496
1497 if(!part)
1498 return result;
1499
1500 part->encoder = NULL;
1501
1502 if(!encoding)
1503 return CURLE_OK; /* Removing current encoder. */
1504
1505 for(mep = encoders; mep->name; mep++)
1506 if(strcasecompare(encoding, mep->name)) {
1507 part->encoder = mep;
1508 result = CURLE_OK;
1509 }
1510
1511 return result;
1512 }
1513
1514 /* Set mime part headers. */
curl_mime_headers(curl_mimepart * part,struct curl_slist * headers,int take_ownership)1515 CURLcode curl_mime_headers(curl_mimepart *part,
1516 struct curl_slist *headers, int take_ownership)
1517 {
1518 if(!part)
1519 return CURLE_BAD_FUNCTION_ARGUMENT;
1520
1521 if(part->flags & MIME_USERHEADERS_OWNER) {
1522 if(part->userheaders != headers) /* Allow setting twice the same list. */
1523 curl_slist_free_all(part->userheaders);
1524 part->flags &= ~MIME_USERHEADERS_OWNER;
1525 }
1526 part->userheaders = headers;
1527 if(headers && take_ownership)
1528 part->flags |= MIME_USERHEADERS_OWNER;
1529 return CURLE_OK;
1530 }
1531
1532 /* 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)1533 CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize,
1534 curl_read_callback readfunc,
1535 curl_seek_callback seekfunc,
1536 curl_free_callback freefunc, void *arg)
1537 {
1538 if(!part)
1539 return CURLE_BAD_FUNCTION_ARGUMENT;
1540
1541 cleanup_part_content(part);
1542
1543 if(readfunc) {
1544 part->readfunc = readfunc;
1545 part->seekfunc = seekfunc;
1546 part->freefunc = freefunc;
1547 part->arg = arg;
1548 part->datasize = datasize;
1549 part->kind = MIMEKIND_CALLBACK;
1550 }
1551
1552 return CURLE_OK;
1553 }
1554
1555 /* Set mime part content from subparts. */
Curl_mime_set_subparts(curl_mimepart * part,curl_mime * subparts,int take_ownership)1556 CURLcode Curl_mime_set_subparts(curl_mimepart *part,
1557 curl_mime *subparts, int take_ownership)
1558 {
1559 curl_mime *root;
1560
1561 if(!part)
1562 return CURLE_BAD_FUNCTION_ARGUMENT;
1563
1564 /* Accept setting twice the same subparts. */
1565 if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
1566 return CURLE_OK;
1567
1568 cleanup_part_content(part);
1569
1570 if(subparts) {
1571 /* Should not have been attached already. */
1572 if(subparts->parent)
1573 return CURLE_BAD_FUNCTION_ARGUMENT;
1574
1575 /* Should not be the part's root. */
1576 root = part->parent;
1577 if(root) {
1578 while(root->parent && root->parent->parent)
1579 root = root->parent->parent;
1580 if(subparts == root) {
1581 /* Can't add as a subpart of itself. */
1582 return CURLE_BAD_FUNCTION_ARGUMENT;
1583 }
1584 }
1585
1586 subparts->parent = part;
1587 /* Subparts are processed internally: no read callback. */
1588 part->seekfunc = mime_subparts_seek;
1589 part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind;
1590 part->arg = subparts;
1591 part->datasize = -1;
1592 part->kind = MIMEKIND_MULTIPART;
1593 }
1594
1595 return CURLE_OK;
1596 }
1597
curl_mime_subparts(curl_mimepart * part,curl_mime * subparts)1598 CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
1599 {
1600 return Curl_mime_set_subparts(part, subparts, TRUE);
1601 }
1602
1603
1604 /* Readback from top mime. */
1605 /* Argument is the dummy top part. */
Curl_mime_read(char * buffer,size_t size,size_t nitems,void * instream)1606 size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
1607 {
1608 curl_mimepart *part = (curl_mimepart *) instream;
1609 size_t ret;
1610 bool hasread;
1611
1612 (void) size; /* Always 1. */
1613
1614 do {
1615 hasread = FALSE;
1616 ret = readback_part(part, buffer, nitems, &hasread);
1617 /*
1618 * If this is not possible to get some data without calling more than
1619 * one read callback (probably because a content encoder is not able to
1620 * deliver a new bunch for the few data accumulated so far), force another
1621 * read until we get enough data or a special exit code.
1622 */
1623 } while(ret == STOP_FILLING);
1624
1625 return ret;
1626 }
1627
1628 /* Rewind mime stream. */
mime_rewind(curl_mimepart * part)1629 static CURLcode mime_rewind(curl_mimepart *part)
1630 {
1631 return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
1632 CURLE_OK: CURLE_SEND_FAIL_REWIND;
1633 }
1634
1635 /* Compute header list size. */
slist_size(struct curl_slist * s,size_t overhead,const char * skip,size_t skiplen)1636 static size_t slist_size(struct curl_slist *s,
1637 size_t overhead, const char *skip, size_t skiplen)
1638 {
1639 size_t size = 0;
1640
1641 for(; s; s = s->next)
1642 if(!skip || !match_header(s, skip, skiplen))
1643 size += strlen(s->data) + overhead;
1644 return size;
1645 }
1646
1647 /* Get/compute multipart size. */
multipart_size(curl_mime * mime)1648 static curl_off_t multipart_size(curl_mime *mime)
1649 {
1650 curl_off_t size;
1651 curl_off_t boundarysize;
1652 curl_mimepart *part;
1653
1654 if(!mime)
1655 return 0; /* Not present -> empty. */
1656
1657 boundarysize = 4 + MIME_BOUNDARY_LEN + 2;
1658 size = boundarysize; /* Final boundary - CRLF after headers. */
1659
1660 for(part = mime->firstpart; part; part = part->nextpart) {
1661 curl_off_t sz = mime_size(part);
1662
1663 if(sz < 0)
1664 size = sz;
1665
1666 if(size >= 0)
1667 size += boundarysize + sz;
1668 }
1669
1670 return size;
1671 }
1672
1673 /* Get/compute mime size. */
mime_size(curl_mimepart * part)1674 static curl_off_t mime_size(curl_mimepart *part)
1675 {
1676 curl_off_t size;
1677
1678 if(part->kind == MIMEKIND_MULTIPART)
1679 part->datasize = multipart_size(part->arg);
1680
1681 size = part->datasize;
1682
1683 if(part->encoder)
1684 size = part->encoder->sizefunc(part);
1685
1686 if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
1687 /* Compute total part size. */
1688 size += slist_size(part->curlheaders, 2, NULL, 0);
1689 size += slist_size(part->userheaders, 2, STRCONST("Content-Type"));
1690 size += 2; /* CRLF after headers. */
1691 }
1692 return size;
1693 }
1694
1695 /* Add a header. */
1696 /* VARARGS2 */
Curl_mime_add_header(struct curl_slist ** slp,const char * fmt,...)1697 CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
1698 {
1699 struct curl_slist *hdr = NULL;
1700 char *s = NULL;
1701 va_list ap;
1702
1703 va_start(ap, fmt);
1704 s = curl_mvaprintf(fmt, ap);
1705 va_end(ap);
1706
1707 if(s) {
1708 hdr = Curl_slist_append_nodup(*slp, s);
1709 if(hdr)
1710 *slp = hdr;
1711 else
1712 free(s);
1713 }
1714
1715 return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY;
1716 }
1717
1718 /* Add a content type header. */
add_content_type(struct curl_slist ** slp,const char * type,const char * boundary)1719 static CURLcode add_content_type(struct curl_slist **slp,
1720 const char *type, const char *boundary)
1721 {
1722 return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
1723 boundary? "; boundary=": "",
1724 boundary? boundary: "");
1725 }
1726
Curl_mime_contenttype(const char * filename)1727 const char *Curl_mime_contenttype(const char *filename)
1728 {
1729 /*
1730 * If no content type was specified, we scan through a few well-known
1731 * extensions and pick the first we match!
1732 */
1733 struct ContentType {
1734 const char *extension;
1735 const char *type;
1736 };
1737 static const struct ContentType ctts[] = {
1738 {".gif", "image/gif"},
1739 {".jpg", "image/jpeg"},
1740 {".jpeg", "image/jpeg"},
1741 {".png", "image/png"},
1742 {".svg", "image/svg+xml"},
1743 {".txt", "text/plain"},
1744 {".htm", "text/html"},
1745 {".html", "text/html"},
1746 {".pdf", "application/pdf"},
1747 {".xml", "application/xml"}
1748 };
1749
1750 if(filename) {
1751 size_t len1 = strlen(filename);
1752 const char *nameend = filename + len1;
1753 unsigned int i;
1754
1755 for(i = 0; i < sizeof(ctts) / sizeof(ctts[0]); i++) {
1756 size_t len2 = strlen(ctts[i].extension);
1757
1758 if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension))
1759 return ctts[i].type;
1760 }
1761 }
1762 return NULL;
1763 }
1764
content_type_match(const char * contenttype,const char * target,size_t len)1765 static bool content_type_match(const char *contenttype,
1766 const char *target, size_t len)
1767 {
1768 if(contenttype && strncasecompare(contenttype, target, len))
1769 switch(contenttype[len]) {
1770 case '\0':
1771 case '\t':
1772 case '\r':
1773 case '\n':
1774 case ' ':
1775 case ';':
1776 return TRUE;
1777 }
1778 return FALSE;
1779 }
1780
Curl_mime_prepare_headers(struct Curl_easy * data,curl_mimepart * part,const char * contenttype,const char * disposition,enum mimestrategy strategy)1781 CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
1782 curl_mimepart *part,
1783 const char *contenttype,
1784 const char *disposition,
1785 enum mimestrategy strategy)
1786 {
1787 curl_mime *mime = NULL;
1788 const char *boundary = NULL;
1789 char *customct;
1790 const char *cte = NULL;
1791 CURLcode ret = CURLE_OK;
1792
1793 /* Get rid of previously prepared headers. */
1794 curl_slist_free_all(part->curlheaders);
1795 part->curlheaders = NULL;
1796
1797 /* Be sure we won't access old headers later. */
1798 if(part->state.state == MIMESTATE_CURLHEADERS)
1799 mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
1800
1801 /* Check if content type is specified. */
1802 customct = part->mimetype;
1803 if(!customct)
1804 customct = search_header(part->userheaders, STRCONST("Content-Type"));
1805 if(customct)
1806 contenttype = customct;
1807
1808 /* If content type is not specified, try to determine it. */
1809 if(!contenttype) {
1810 switch(part->kind) {
1811 case MIMEKIND_MULTIPART:
1812 contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
1813 break;
1814 case MIMEKIND_FILE:
1815 contenttype = Curl_mime_contenttype(part->filename);
1816 if(!contenttype)
1817 contenttype = Curl_mime_contenttype(part->data);
1818 if(!contenttype && part->filename)
1819 contenttype = FILE_CONTENTTYPE_DEFAULT;
1820 break;
1821 default:
1822 contenttype = Curl_mime_contenttype(part->filename);
1823 break;
1824 }
1825 }
1826
1827 if(part->kind == MIMEKIND_MULTIPART) {
1828 mime = (curl_mime *) part->arg;
1829 if(mime)
1830 boundary = mime->boundary;
1831 }
1832 else if(contenttype && !customct &&
1833 content_type_match(contenttype, STRCONST("text/plain")))
1834 if(strategy == MIMESTRATEGY_MAIL || !part->filename)
1835 contenttype = NULL;
1836
1837 /* Issue content-disposition header only if not already set by caller. */
1838 if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
1839 if(!disposition)
1840 if(part->filename || part->name ||
1841 (contenttype && !strncasecompare(contenttype, "multipart/", 10)))
1842 disposition = DISPOSITION_DEFAULT;
1843 if(disposition && curl_strequal(disposition, "attachment") &&
1844 !part->name && !part->filename)
1845 disposition = NULL;
1846 if(disposition) {
1847 char *name = NULL;
1848 char *filename = NULL;
1849
1850 if(part->name) {
1851 name = escape_string(data, part->name, strategy);
1852 if(!name)
1853 ret = CURLE_OUT_OF_MEMORY;
1854 }
1855 if(!ret && part->filename) {
1856 filename = escape_string(data, part->filename, strategy);
1857 if(!filename)
1858 ret = CURLE_OUT_OF_MEMORY;
1859 }
1860 if(!ret)
1861 ret = Curl_mime_add_header(&part->curlheaders,
1862 "Content-Disposition: %s%s%s%s%s%s%s",
1863 disposition,
1864 name? "; name=\"": "",
1865 name? name: "",
1866 name? "\"": "",
1867 filename? "; filename=\"": "",
1868 filename? filename: "",
1869 filename? "\"": "");
1870 Curl_safefree(name);
1871 Curl_safefree(filename);
1872 if(ret)
1873 return ret;
1874 }
1875 }
1876
1877 /* Issue Content-Type header. */
1878 if(contenttype) {
1879 ret = add_content_type(&part->curlheaders, contenttype, boundary);
1880 if(ret)
1881 return ret;
1882 }
1883
1884 /* Content-Transfer-Encoding header. */
1885 if(!search_header(part->userheaders,
1886 STRCONST("Content-Transfer-Encoding"))) {
1887 if(part->encoder)
1888 cte = part->encoder->name;
1889 else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
1890 part->kind != MIMEKIND_MULTIPART)
1891 cte = "8bit";
1892 if(cte) {
1893 ret = Curl_mime_add_header(&part->curlheaders,
1894 "Content-Transfer-Encoding: %s", cte);
1895 if(ret)
1896 return ret;
1897 }
1898 }
1899
1900 /* If we were reading curl-generated headers, restart with new ones (this
1901 should not occur). */
1902 if(part->state.state == MIMESTATE_CURLHEADERS)
1903 mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
1904
1905 /* Process subparts. */
1906 if(part->kind == MIMEKIND_MULTIPART && mime) {
1907 curl_mimepart *subpart;
1908
1909 disposition = NULL;
1910 if(content_type_match(contenttype, STRCONST("multipart/form-data")))
1911 disposition = "form-data";
1912 for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
1913 ret = Curl_mime_prepare_headers(data, subpart, NULL,
1914 disposition, strategy);
1915 if(ret)
1916 return ret;
1917 }
1918 }
1919 return ret;
1920 }
1921
1922 /* Recursively reset paused status in the given part. */
mime_unpause(curl_mimepart * part)1923 static void mime_unpause(curl_mimepart *part)
1924 {
1925 if(part) {
1926 if(part->lastreadstatus == CURL_READFUNC_PAUSE)
1927 part->lastreadstatus = 1; /* Successful read status. */
1928 if(part->kind == MIMEKIND_MULTIPART) {
1929 curl_mime *mime = (curl_mime *) part->arg;
1930
1931 if(mime) {
1932 curl_mimepart *subpart;
1933
1934 for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart)
1935 mime_unpause(subpart);
1936 }
1937 }
1938 }
1939 }
1940
1941 struct cr_mime_ctx {
1942 struct Curl_creader super;
1943 curl_mimepart *part;
1944 curl_off_t total_len;
1945 curl_off_t read_len;
1946 CURLcode error_result;
1947 BIT(seen_eos);
1948 BIT(errored);
1949 };
1950
cr_mime_init(struct Curl_easy * data,struct Curl_creader * reader)1951 static CURLcode cr_mime_init(struct Curl_easy *data,
1952 struct Curl_creader *reader)
1953 {
1954 struct cr_mime_ctx *ctx = reader->ctx;
1955 (void)data;
1956 ctx->total_len = -1;
1957 ctx->read_len = 0;
1958 return CURLE_OK;
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
1970 /* Once we have errored, we will return the same error forever */
1971 if(ctx->errored) {
1972 *pnread = 0;
1973 *peos = FALSE;
1974 return ctx->error_result;
1975 }
1976 if(ctx->seen_eos) {
1977 *pnread = 0;
1978 *peos = TRUE;
1979 return CURLE_OK;
1980 }
1981 /* respect length limitations */
1982 if(ctx->total_len >= 0) {
1983 curl_off_t remain = ctx->total_len - ctx->read_len;
1984 if(remain <= 0)
1985 blen = 0;
1986 else if(remain < (curl_off_t)blen)
1987 blen = (size_t)remain;
1988 }
1989 nread = 0;
1990 if(blen) {
1991 nread = Curl_mime_read(buf, 1, blen, ctx->part);
1992 }
1993
1994 switch(nread) {
1995 case 0:
1996 if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
1997 failf(data, "client mime read EOF fail, "
1998 "only %"CURL_FORMAT_CURL_OFF_T"/%"CURL_FORMAT_CURL_OFF_T
1999 " of needed bytes read", ctx->read_len, ctx->total_len);
2000 return CURLE_READ_ERROR;
2001 }
2002 *pnread = 0;
2003 *peos = TRUE;
2004 ctx->seen_eos = TRUE;
2005 break;
2006
2007 case CURL_READFUNC_ABORT:
2008 failf(data, "operation aborted by callback");
2009 *pnread = 0;
2010 *peos = FALSE;
2011 ctx->errored = TRUE;
2012 ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
2013 return CURLE_ABORTED_BY_CALLBACK;
2014
2015 case CURL_READFUNC_PAUSE:
2016 /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
2017 data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
2018 *pnread = 0;
2019 *peos = FALSE;
2020 break; /* nothing was read */
2021
2022 default:
2023 if(nread > blen) {
2024 /* the read function returned a too large value */
2025 failf(data, "read function returned funny value");
2026 *pnread = 0;
2027 *peos = FALSE;
2028 ctx->errored = TRUE;
2029 ctx->error_result = CURLE_READ_ERROR;
2030 return CURLE_READ_ERROR;
2031 }
2032 ctx->read_len += nread;
2033 if(ctx->total_len >= 0)
2034 ctx->seen_eos = (ctx->read_len >= ctx->total_len);
2035 *pnread = nread;
2036 *peos = ctx->seen_eos;
2037 break;
2038 }
2039 DEBUGF(infof(data, "cr_mime_read(len=%zu, total=%"CURL_FORMAT_CURL_OFF_T
2040 ", read=%"CURL_FORMAT_CURL_OFF_T") -> %d, %zu, %d",
2041 blen, ctx->total_len, ctx->read_len, CURLE_OK, *pnread, *peos));
2042 return CURLE_OK;
2043 }
2044
cr_mime_needs_rewind(struct Curl_easy * data,struct Curl_creader * reader)2045 static bool cr_mime_needs_rewind(struct Curl_easy *data,
2046 struct Curl_creader *reader)
2047 {
2048 struct cr_mime_ctx *ctx = reader->ctx;
2049 (void)data;
2050 return ctx->read_len > 0;
2051 }
2052
cr_mime_total_length(struct Curl_easy * data,struct Curl_creader * reader)2053 static curl_off_t cr_mime_total_length(struct Curl_easy *data,
2054 struct Curl_creader *reader)
2055 {
2056 struct cr_mime_ctx *ctx = reader->ctx;
2057 (void)data;
2058 return ctx->total_len;
2059 }
2060
cr_mime_resume_from(struct Curl_easy * data,struct Curl_creader * reader,curl_off_t offset)2061 static CURLcode cr_mime_resume_from(struct Curl_easy *data,
2062 struct Curl_creader *reader,
2063 curl_off_t offset)
2064 {
2065 struct cr_mime_ctx *ctx = reader->ctx;
2066
2067 if(offset > 0) {
2068 curl_off_t passed = 0;
2069
2070 do {
2071 char scratch[4*1024];
2072 size_t readthisamountnow =
2073 (offset - passed > (curl_off_t)sizeof(scratch)) ?
2074 sizeof(scratch) :
2075 curlx_sotouz(offset - passed);
2076 size_t nread;
2077
2078 nread = Curl_mime_read(scratch, 1, readthisamountnow, ctx->part);
2079 passed += (curl_off_t)nread;
2080 if((nread == 0) || (nread > readthisamountnow)) {
2081 /* this checks for greater-than only to make sure that the
2082 CURL_READFUNC_ABORT return code still aborts */
2083 failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T
2084 " bytes from the mime post", passed);
2085 return CURLE_READ_ERROR;
2086 }
2087 } while(passed < offset);
2088
2089 /* now, decrease the size of the read */
2090 if(ctx->total_len > 0) {
2091 ctx->total_len -= offset;
2092
2093 if(ctx->total_len <= 0) {
2094 failf(data, "Mime post already completely uploaded");
2095 return CURLE_PARTIAL_FILE;
2096 }
2097 }
2098 /* we've passed, proceed as normal */
2099 }
2100 return CURLE_OK;
2101 }
2102
cr_mime_rewind(struct Curl_easy * data,struct Curl_creader * reader)2103 static CURLcode cr_mime_rewind(struct Curl_easy *data,
2104 struct Curl_creader *reader)
2105 {
2106 struct cr_mime_ctx *ctx = reader->ctx;
2107 CURLcode result = mime_rewind(ctx->part);
2108 if(result)
2109 failf(data, "Cannot rewind mime/post data");
2110 return result;
2111 }
2112
cr_mime_unpause(struct Curl_easy * data,struct Curl_creader * reader)2113 static CURLcode cr_mime_unpause(struct Curl_easy *data,
2114 struct Curl_creader *reader)
2115 {
2116 struct cr_mime_ctx *ctx = reader->ctx;
2117 (void)data;
2118 mime_unpause(ctx->part);
2119 return CURLE_OK;
2120 }
2121
2122 static const struct Curl_crtype cr_mime = {
2123 "cr-mime",
2124 cr_mime_init,
2125 cr_mime_read,
2126 Curl_creader_def_close,
2127 cr_mime_needs_rewind,
2128 cr_mime_total_length,
2129 cr_mime_resume_from,
2130 cr_mime_rewind,
2131 cr_mime_unpause,
2132 Curl_creader_def_done,
2133 sizeof(struct cr_mime_ctx)
2134 };
2135
Curl_creader_set_mime(struct Curl_easy * data,curl_mimepart * part)2136 CURLcode Curl_creader_set_mime(struct Curl_easy *data, curl_mimepart *part)
2137 {
2138 struct Curl_creader *r;
2139 struct cr_mime_ctx *ctx;
2140 CURLcode result;
2141
2142 result = Curl_creader_create(&r, data, &cr_mime, CURL_CR_CLIENT);
2143 if(result)
2144 return result;
2145 ctx = r->ctx;
2146 ctx->part = part;
2147 /* Make sure we will read the entire mime structure. */
2148 result = mime_rewind(ctx->part);
2149 if(result) {
2150 Curl_creader_free(data, r);
2151 return result;
2152 }
2153 ctx->total_len = mime_size(ctx->part);
2154
2155 return Curl_creader_set(data, r);
2156 }
2157
2158 #else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP ||
2159 !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP) */
2160
2161 /* Mime not compiled in: define stubs for externally-referenced functions. */
curl_mime_init(CURL * easy)2162 curl_mime *curl_mime_init(CURL *easy)
2163 {
2164 (void) easy;
2165 return NULL;
2166 }
2167
curl_mime_free(curl_mime * mime)2168 void curl_mime_free(curl_mime *mime)
2169 {
2170 (void) mime;
2171 }
2172
curl_mime_addpart(curl_mime * mime)2173 curl_mimepart *curl_mime_addpart(curl_mime *mime)
2174 {
2175 (void) mime;
2176 return NULL;
2177 }
2178
curl_mime_name(curl_mimepart * part,const char * name)2179 CURLcode curl_mime_name(curl_mimepart *part, const char *name)
2180 {
2181 (void) part;
2182 (void) name;
2183 return CURLE_NOT_BUILT_IN;
2184 }
2185
curl_mime_filename(curl_mimepart * part,const char * filename)2186 CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
2187 {
2188 (void) part;
2189 (void) filename;
2190 return CURLE_NOT_BUILT_IN;
2191 }
2192
curl_mime_type(curl_mimepart * part,const char * mimetype)2193 CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
2194 {
2195 (void) part;
2196 (void) mimetype;
2197 return CURLE_NOT_BUILT_IN;
2198 }
2199
curl_mime_encoder(curl_mimepart * part,const char * encoding)2200 CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
2201 {
2202 (void) part;
2203 (void) encoding;
2204 return CURLE_NOT_BUILT_IN;
2205 }
2206
curl_mime_data(curl_mimepart * part,const char * data,size_t datasize)2207 CURLcode curl_mime_data(curl_mimepart *part,
2208 const char *data, size_t datasize)
2209 {
2210 (void) part;
2211 (void) data;
2212 (void) datasize;
2213 return CURLE_NOT_BUILT_IN;
2214 }
2215
curl_mime_filedata(curl_mimepart * part,const char * filename)2216 CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
2217 {
2218 (void) part;
2219 (void) filename;
2220 return CURLE_NOT_BUILT_IN;
2221 }
2222
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)2223 CURLcode curl_mime_data_cb(curl_mimepart *part,
2224 curl_off_t datasize,
2225 curl_read_callback readfunc,
2226 curl_seek_callback seekfunc,
2227 curl_free_callback freefunc,
2228 void *arg)
2229 {
2230 (void) part;
2231 (void) datasize;
2232 (void) readfunc;
2233 (void) seekfunc;
2234 (void) freefunc;
2235 (void) arg;
2236 return CURLE_NOT_BUILT_IN;
2237 }
2238
curl_mime_subparts(curl_mimepart * part,curl_mime * subparts)2239 CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
2240 {
2241 (void) part;
2242 (void) subparts;
2243 return CURLE_NOT_BUILT_IN;
2244 }
2245
curl_mime_headers(curl_mimepart * part,struct curl_slist * headers,int take_ownership)2246 CURLcode curl_mime_headers(curl_mimepart *part,
2247 struct curl_slist *headers, int take_ownership)
2248 {
2249 (void) part;
2250 (void) headers;
2251 (void) take_ownership;
2252 return CURLE_NOT_BUILT_IN;
2253 }
2254
Curl_mime_add_header(struct curl_slist ** slp,const char * fmt,...)2255 CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
2256 {
2257 (void)slp;
2258 (void)fmt;
2259 return CURLE_NOT_BUILT_IN;
2260 }
2261
2262 #endif /* if disabled */
2263