VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/mime.c@ 106165

最後變更 在這個檔案從106165是 104083,由 vboxsync 提交於 8 月 前

curl-8.7.1: Applied and adjusted our curl changes to 8.4.0. bugref:10639

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

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