VirtualBox

source: vbox/trunk/src/libs/curl-8.11.1/lib/mime.c@ 108048

Last change on this file since 108048 was 108048, checked in by vboxsync, 7 weeks ago

curl-8.11.1: Applied and adjusted our curl changes to 8.7.1. jiraref:VBP-1535

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette