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