VirtualBox

source: vbox/trunk/src/libs/curl-7.87.0/lib/mime.c@ 98334

Last change on this file since 98334 was 98326, checked in by vboxsync, 2 years ago

curl-7.87.0: Applied and adjusted our curl changes to 7.83.1. bugref:10356

  • Property svn:eol-style set to native
File size: 53.3 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, 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
34#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \
35 !defined(CURL_DISABLE_SMTP) || \
36 !defined(CURL_DISABLE_IMAP))
37
38#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
39#include <libgen.h>
40#endif
41
42#include "rand.h"
43#include "slist.h"
44#include "strcase.h"
45#include "dynbuf.h"
46/* The last 3 #include files should be in this order */
47#include "curl_printf.h"
48#include "curl_memory.h"
49#include "memdebug.h"
50
51#ifdef WIN32
52# ifndef R_OK
53# define R_OK 4
54# endif
55#endif
56
57
58#define READ_ERROR ((size_t) -1)
59#define STOP_FILLING ((size_t) -2)
60
61static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
62 void *instream, bool *hasread);
63
64/* Encoders. */
65static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
66 curl_mimepart *part);
67static curl_off_t encoder_nop_size(curl_mimepart *part);
68static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
69 curl_mimepart *part);
70static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
71 curl_mimepart *part);
72static curl_off_t encoder_base64_size(curl_mimepart *part);
73static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
74 curl_mimepart *part);
75static curl_off_t encoder_qp_size(curl_mimepart *part);
76
77static const struct mime_encoder encoders[] = {
78 {"binary", encoder_nop_read, encoder_nop_size},
79 {"8bit", encoder_nop_read, encoder_nop_size},
80 {"7bit", encoder_7bit_read, encoder_nop_size},
81 {"base64", encoder_base64_read, encoder_base64_size},
82 {"quoted-printable", encoder_qp_read, encoder_qp_size},
83 {ZERO_NULL, ZERO_NULL, ZERO_NULL}
84};
85
86/* Base64 encoding table */
87static const char base64[] =
88 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
89
90/* Quoted-printable character class table.
91 *
92 * We cannot rely on ctype functions since quoted-printable input data
93 * is assumed to be ascii-compatible, even on non-ascii platforms. */
94#define QP_OK 1 /* Can be represented by itself. */
95#define QP_SP 2 /* Space or tab. */
96#define QP_CR 3 /* Carriage return. */
97#define QP_LF 4 /* Line-feed. */
98static const unsigned char qp_class[] = {
99 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */
100 0, QP_SP, QP_LF, 0, 0, QP_CR, 0, 0, /* 08 - 0F */
101 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */
102 0, 0, 0, 0, 0, 0, 0, 0, /* 18 - 1F */
103 QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 20 - 27 */
104 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 28 - 2F */
105 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 30 - 37 */
106 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0 , QP_OK, QP_OK, /* 38 - 3F */
107 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 40 - 47 */
108 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 48 - 4F */
109 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 50 - 57 */
110 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 58 - 5F */
111 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 60 - 67 */
112 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 68 - 6F */
113 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 70 - 77 */
114 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0, /* 78 - 7F */
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
122 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */
123};
124
125
126/* Binary --> hexadecimal ASCII table. */
127static const char aschex[] =
128 "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46";
129
130
131
132#ifndef __VMS
133#define filesize(name, stat_data) (stat_data.st_size)
134#define fopen_read fopen
135
136#else
137
138#include <fabdef.h>
139/*
140 * get_vms_file_size does what it takes to get the real size of the file
141 *
142 * For fixed files, find out the size of the EOF block and adjust.
143 *
144 * For all others, have to read the entire file in, discarding the contents.
145 * Most posted text files will be small, and binary files like zlib archives
146 * and CD/DVD images should be either a STREAM_LF format or a fixed format.
147 *
148 */
149curl_off_t VmsRealFileSize(const char *name,
150 const struct_stat *stat_buf)
151{
152 char buffer[8192];
153 curl_off_t count;
154 int ret_stat;
155 FILE * file;
156
157 file = fopen(name, FOPEN_READTEXT); /* VMS */
158 if(!file)
159 return 0;
160
161 count = 0;
162 ret_stat = 1;
163 while(ret_stat > 0) {
164 ret_stat = fread(buffer, 1, sizeof(buffer), file);
165 if(ret_stat)
166 count += ret_stat;
167 }
168 fclose(file);
169
170 return count;
171}
172
173/*
174 *
175 * VmsSpecialSize checks to see if the stat st_size can be trusted and
176 * if not to call a routine to get the correct size.
177 *
178 */
179static curl_off_t VmsSpecialSize(const char *name,
180 const struct_stat *stat_buf)
181{
182 switch(stat_buf->st_fab_rfm) {
183 case FAB$C_VAR:
184 case FAB$C_VFC:
185 return VmsRealFileSize(name, stat_buf);
186 break;
187 default:
188 return stat_buf->st_size;
189 }
190}
191
192#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
193
194/*
195 * vmsfopenread
196 *
197 * For upload to work as expected on VMS, different optional
198 * parameters must be added to the fopen command based on
199 * record format of the file.
200 *
201 */
202static FILE * vmsfopenread(const char *file, const char *mode)
203{
204 struct_stat statbuf;
205 int result;
206
207 result = stat(file, &statbuf);
208
209 switch(statbuf.st_fab_rfm) {
210 case FAB$C_VAR:
211 case FAB$C_VFC:
212 case FAB$C_STMCR:
213 return fopen(file, FOPEN_READTEXT); /* VMS */
214 break;
215 default:
216 return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
217 }
218}
219
220#define fopen_read vmsfopenread
221#endif
222
223
224#ifndef HAVE_BASENAME
225/*
226 (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
227 Edition)
228
229 The basename() function shall take the pathname pointed to by path and
230 return a pointer to the final component of the pathname, deleting any
231 trailing '/' characters.
232
233 If the string pointed to by path consists entirely of the '/' character,
234 basename() shall return a pointer to the string "/". If the string pointed
235 to by path is exactly "//", it is implementation-defined whether '/' or "//"
236 is returned.
237
238 If path is a null pointer or points to an empty string, basename() shall
239 return a pointer to the string ".".
240
241 The basename() function may modify the string pointed to by path, and may
242 return a pointer to static storage that may then be overwritten by a
243 subsequent call to basename().
244
245 The basename() function need not be reentrant. A function that is not
246 required to be reentrant is not required to be thread-safe.
247
248*/
249static char *Curl_basename(char *path)
250{
251 /* Ignore all the details above for now and make a quick and simple
252 implementation here */
253 char *s1;
254 char *s2;
255
256 s1 = strrchr(path, '/');
257 s2 = strrchr(path, '\\');
258
259 if(s1 && s2) {
260 path = (s1 > s2? s1 : s2) + 1;
261 }
262 else if(s1)
263 path = s1 + 1;
264 else if(s2)
265 path = s2 + 1;
266
267 return path;
268}
269
270#define basename(x) Curl_basename((x))
271#endif
272
273
274/* Set readback state. */
275static void mimesetstate(struct mime_state *state,
276 enum mimestate tok, void *ptr)
277{
278 state->state = tok;
279 state->ptr = ptr;
280 state->offset = 0;
281}
282
283
284/* Escape header string into allocated memory. */
285static char *escape_string(struct Curl_easy *data,
286 const char *src, enum mimestrategy strategy)
287{
288 CURLcode result;
289 struct dynbuf db;
290 const char * const *table;
291 const char * const *p;
292 /* replace first character by rest of string. */
293 static const char * const mimetable[] = {
294 "\\\\\\",
295 "\"\\\"",
296 NULL
297 };
298 /* WHATWG HTML living standard 4.10.21.8 2 specifies:
299 For field names and filenames for file fields, the result of the
300 encoding in the previous bullet point must be escaped by replacing
301 any 0x0A (LF) bytes with the byte sequence `%0A`, 0x0D (CR) with `%0D`
302 and 0x22 (") with `%22`.
303 The user agent must not perform any other escapes. */
304 static const char * const formtable[] = {
305 "\"%22",
306 "\r%0D",
307 "\n%0A",
308 NULL
309 };
310
311 table = formtable;
312 /* data can be NULL when this function is called indirectly from
313 curl_formget(). */
314 if(strategy == MIMESTRATEGY_MAIL ||
315 (data && (data->set.mime_options & CURLMIMEOPT_FORMESCAPE)))
316 table = mimetable;
317
318 Curl_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
319
320 for(result = Curl_dyn_addn(&db, STRCONST("")); !result && *src; src++) {
321 for(p = table; *p && **p != *src; p++)
322 ;
323
324 if(*p)
325 result = Curl_dyn_add(&db, *p + 1);
326 else
327 result = Curl_dyn_addn(&db, src, 1);
328 }
329
330 return Curl_dyn_ptr(&db);
331}
332
333/* Check if header matches. */
334static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
335{
336 char *value = NULL;
337
338 if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':')
339 for(value = hdr->data + len + 1; *value == ' '; value++)
340 ;
341 return value;
342}
343
344/* Get a header from an slist. */
345static char *search_header(struct curl_slist *hdrlist,
346 const char *hdr, size_t len)
347{
348 char *value = NULL;
349
350 for(; !value && hdrlist; hdrlist = hdrlist->next)
351 value = match_header(hdrlist, hdr, len);
352
353 return value;
354}
355
356static char *strippath(const char *fullfile)
357{
358 char *filename;
359 char *base;
360 filename = strdup(fullfile); /* duplicate since basename() may ruin the
361 buffer it works on */
362 if(!filename)
363 return NULL;
364 base = strdup(basename(filename));
365
366 free(filename); /* free temporary buffer */
367
368 return base; /* returns an allocated string or NULL ! */
369}
370
371/* Initialize data encoder state. */
372static void cleanup_encoder_state(struct mime_encoder_state *p)
373{
374 p->pos = 0;
375 p->bufbeg = 0;
376 p->bufend = 0;
377}
378
379
380/* Dummy encoder. This is used for 8bit and binary content encodings. */
381static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
382 struct curl_mimepart *part)
383{
384 struct mime_encoder_state *st = &part->encstate;
385 size_t insize = st->bufend - st->bufbeg;
386
387 (void) ateof;
388
389 if(!size)
390 return STOP_FILLING;
391
392 if(size > insize)
393 size = insize;
394
395 if(size)
396 memcpy(buffer, st->buf + st->bufbeg, size);
397
398 st->bufbeg += size;
399 return size;
400}
401
402static curl_off_t encoder_nop_size(curl_mimepart *part)
403{
404 return part->datasize;
405}
406
407
408/* 7bit encoder: the encoder is just a data validity check. */
409static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
410 curl_mimepart *part)
411{
412 struct mime_encoder_state *st = &part->encstate;
413 size_t cursize = st->bufend - st->bufbeg;
414
415 (void) ateof;
416
417 if(!size)
418 return STOP_FILLING;
419
420 if(size > cursize)
421 size = cursize;
422
423 for(cursize = 0; cursize < size; cursize++) {
424 *buffer = st->buf[st->bufbeg];
425 if(*buffer++ & 0x80)
426 return cursize? cursize: READ_ERROR;
427 st->bufbeg++;
428 }
429
430 return cursize;
431}
432
433
434/* Base64 content encoder. */
435static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
436 curl_mimepart *part)
437{
438 struct mime_encoder_state *st = &part->encstate;
439 size_t cursize = 0;
440 int i;
441 char *ptr = buffer;
442
443 while(st->bufbeg < st->bufend) {
444 /* Line full ? */
445 if(st->pos > MAX_ENCODED_LINE_LENGTH - 4) {
446 /* Yes, we need 2 characters for CRLF. */
447 if(size < 2) {
448 if(!cursize)
449 return STOP_FILLING;
450 break;
451 }
452 *ptr++ = '\r';
453 *ptr++ = '\n';
454 st->pos = 0;
455 cursize += 2;
456 size -= 2;
457 }
458
459 /* Be sure there is enough space and input data for a base64 group. */
460 if(size < 4) {
461 if(!cursize)
462 return STOP_FILLING;
463 break;
464 }
465 if(st->bufend - st->bufbeg < 3)
466 break;
467
468 /* Encode three bytes as four characters. */
469 i = st->buf[st->bufbeg++] & 0xFF;
470 i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
471 i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
472 *ptr++ = base64[(i >> 18) & 0x3F];
473 *ptr++ = base64[(i >> 12) & 0x3F];
474 *ptr++ = base64[(i >> 6) & 0x3F];
475 *ptr++ = base64[i & 0x3F];
476 cursize += 4;
477 st->pos += 4;
478 size -= 4;
479 }
480
481 /* If at eof, we have to flush the buffered data. */
482 if(ateof) {
483 if(size < 4) {
484 if(!cursize)
485 return STOP_FILLING;
486 }
487 else {
488 /* Buffered data size can only be 0, 1 or 2. */
489 ptr[2] = ptr[3] = '=';
490 i = 0;
491
492 /* If there is buffered data */
493 if(st->bufend != st->bufbeg) {
494
495 if(st->bufend - st->bufbeg == 2)
496 i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
497
498 i |= (st->buf[st->bufbeg] & 0xFF) << 16;
499 ptr[0] = base64[(i >> 18) & 0x3F];
500 ptr[1] = base64[(i >> 12) & 0x3F];
501 if(++st->bufbeg != st->bufend) {
502 ptr[2] = base64[(i >> 6) & 0x3F];
503 st->bufbeg++;
504 }
505 cursize += 4;
506 st->pos += 4;
507 }
508 }
509 }
510
511 return cursize;
512}
513
514static curl_off_t encoder_base64_size(curl_mimepart *part)
515{
516 curl_off_t size = part->datasize;
517
518 if(size <= 0)
519 return size; /* Unknown size or no data. */
520
521 /* Compute base64 character count. */
522 size = 4 * (1 + (size - 1) / 3);
523
524 /* Effective character count must include CRLFs. */
525 return size + 2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH);
526}
527
528
529/* Quoted-printable lookahead.
530 *
531 * Check if a CRLF or end of data is in input buffer at current position + n.
532 * Return -1 if more data needed, 1 if CRLF or end of data, else 0.
533 */
534static int qp_lookahead_eol(struct mime_encoder_state *st, int ateof, size_t n)
535{
536 n += st->bufbeg;
537 if(n >= st->bufend && ateof)
538 return 1;
539 if(n + 2 > st->bufend)
540 return ateof? 0: -1;
541 if(qp_class[st->buf[n] & 0xFF] == QP_CR &&
542 qp_class[st->buf[n + 1] & 0xFF] == QP_LF)
543 return 1;
544 return 0;
545}
546
547/* Quoted-printable encoder. */
548static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
549 curl_mimepart *part)
550{
551 struct mime_encoder_state *st = &part->encstate;
552 char *ptr = buffer;
553 size_t cursize = 0;
554 int softlinebreak;
555 char buf[4];
556
557 /* On all platforms, input is supposed to be ASCII compatible: for this
558 reason, we use hexadecimal ASCII codes in this function rather than
559 character constants that can be interpreted as non-ascii on some
560 platforms. Preserve ASCII encoding on output too. */
561 while(st->bufbeg < st->bufend) {
562 size_t len = 1;
563 size_t consumed = 1;
564 int i = st->buf[st->bufbeg];
565 buf[0] = (char) i;
566 buf[1] = aschex[(i >> 4) & 0xF];
567 buf[2] = aschex[i & 0xF];
568
569 switch(qp_class[st->buf[st->bufbeg] & 0xFF]) {
570 case QP_OK: /* Not a special character. */
571 break;
572 case QP_SP: /* Space or tab. */
573 /* Spacing must be escaped if followed by CRLF. */
574 switch(qp_lookahead_eol(st, ateof, 1)) {
575 case -1: /* More input data needed. */
576 return cursize;
577 case 0: /* No encoding needed. */
578 break;
579 default: /* CRLF after space or tab. */
580 buf[0] = '\x3D'; /* '=' */
581 len = 3;
582 break;
583 }
584 break;
585 case QP_CR: /* Carriage return. */
586 /* If followed by a line-feed, output the CRLF pair.
587 Else escape it. */
588 switch(qp_lookahead_eol(st, ateof, 0)) {
589 case -1: /* Need more data. */
590 return cursize;
591 case 1: /* CRLF found. */
592 buf[len++] = '\x0A'; /* Append '\n'. */
593 consumed = 2;
594 break;
595 default: /* Not followed by LF: escape. */
596 buf[0] = '\x3D'; /* '=' */
597 len = 3;
598 break;
599 }
600 break;
601 default: /* Character must be escaped. */
602 buf[0] = '\x3D'; /* '=' */
603 len = 3;
604 break;
605 }
606
607 /* Be sure the encoded character fits within maximum line length. */
608 if(buf[len - 1] != '\x0A') { /* '\n' */
609 softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH;
610 if(!softlinebreak && st->pos + len == MAX_ENCODED_LINE_LENGTH) {
611 /* We may use the current line only if end of data or followed by
612 a CRLF. */
613 switch(qp_lookahead_eol(st, ateof, consumed)) {
614 case -1: /* Need more data. */
615 return cursize;
616 case 0: /* Not followed by a CRLF. */
617 softlinebreak = 1;
618 break;
619 }
620 }
621 if(softlinebreak) {
622 strcpy(buf, "\x3D\x0D\x0A"); /* "=\r\n" */
623 len = 3;
624 consumed = 0;
625 }
626 }
627
628 /* If the output buffer would overflow, do not store. */
629 if(len > size) {
630 if(!cursize)
631 return STOP_FILLING;
632 break;
633 }
634
635 /* Append to output buffer. */
636 memcpy(ptr, buf, len);
637 cursize += len;
638 ptr += len;
639 size -= len;
640 st->pos += len;
641 if(buf[len - 1] == '\x0A') /* '\n' */
642 st->pos = 0;
643 st->bufbeg += consumed;
644 }
645
646 return cursize;
647}
648
649static curl_off_t encoder_qp_size(curl_mimepart *part)
650{
651 /* Determining the size can only be done by reading the data: unless the
652 data size is 0, we return it as unknown (-1). */
653 return part->datasize? -1: 0;
654}
655
656
657/* In-memory data callbacks. */
658/* Argument is a pointer to the mime part. */
659static size_t mime_mem_read(char *buffer, size_t size, size_t nitems,
660 void *instream)
661{
662 curl_mimepart *part = (curl_mimepart *) instream;
663 size_t sz = curlx_sotouz(part->datasize - part->state.offset);
664 (void) size; /* Always 1.*/
665
666 if(!nitems)
667 return STOP_FILLING;
668
669 if(sz > nitems)
670 sz = nitems;
671
672 if(sz)
673 memcpy(buffer, part->data + curlx_sotouz(part->state.offset), sz);
674
675 return sz;
676}
677
678static int mime_mem_seek(void *instream, curl_off_t offset, int whence)
679{
680 curl_mimepart *part = (curl_mimepart *) instream;
681
682 switch(whence) {
683 case SEEK_CUR:
684 offset += part->state.offset;
685 break;
686 case SEEK_END:
687 offset += part->datasize;
688 break;
689 }
690
691 if(offset < 0 || offset > part->datasize)
692 return CURL_SEEKFUNC_FAIL;
693
694 part->state.offset = offset;
695 return CURL_SEEKFUNC_OK;
696}
697
698static void mime_mem_free(void *ptr)
699{
700 Curl_safefree(((curl_mimepart *) ptr)->data);
701}
702
703
704/* Named file callbacks. */
705/* Argument is a pointer to the mime part. */
706static int mime_open_file(curl_mimepart *part)
707{
708 /* Open a MIMEKIND_FILE part. */
709
710 if(part->fp)
711 return 0;
712 part->fp = fopen_read(part->data, "rb");
713 return part->fp? 0: -1;
714}
715
716static size_t mime_file_read(char *buffer, size_t size, size_t nitems,
717 void *instream)
718{
719 curl_mimepart *part = (curl_mimepart *) instream;
720
721 if(!nitems)
722 return STOP_FILLING;
723
724 if(mime_open_file(part))
725 return READ_ERROR;
726
727 return fread(buffer, size, nitems, part->fp);
728}
729
730static int mime_file_seek(void *instream, curl_off_t offset, int whence)
731{
732 curl_mimepart *part = (curl_mimepart *) instream;
733
734 if(whence == SEEK_SET && !offset && !part->fp)
735 return CURL_SEEKFUNC_OK; /* Not open: implicitly already at BOF. */
736
737 if(mime_open_file(part))
738 return CURL_SEEKFUNC_FAIL;
739
740 return fseek(part->fp, (long) offset, whence)?
741 CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK;
742}
743
744static void mime_file_free(void *ptr)
745{
746 curl_mimepart *part = (curl_mimepart *) ptr;
747
748 if(part->fp) {
749 fclose(part->fp);
750 part->fp = NULL;
751 }
752 Curl_safefree(part->data);
753 part->data = NULL;
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 cleanup_part_content(part);
1172 curl_slist_free_all(part->curlheaders);
1173 if(part->flags & MIME_USERHEADERS_OWNER)
1174 curl_slist_free_all(part->userheaders);
1175 Curl_safefree(part->mimetype);
1176 Curl_safefree(part->name);
1177 Curl_safefree(part->filename);
1178 Curl_mime_initpart(part);
1179}
1180
1181/* Recursively delete a mime handle and its parts. */
1182void curl_mime_free(curl_mime *mime)
1183{
1184 curl_mimepart *part;
1185
1186 if(mime) {
1187 mime_subparts_unbind(mime); /* Be sure it's not referenced anymore. */
1188 while(mime->firstpart) {
1189 part = mime->firstpart;
1190 mime->firstpart = part->nextpart;
1191 Curl_mime_cleanpart(part);
1192 free(part);
1193 }
1194 free(mime);
1195 }
1196}
1197
1198CURLcode Curl_mime_duppart(struct Curl_easy *data,
1199 curl_mimepart *dst, const curl_mimepart *src)
1200{
1201 curl_mime *mime;
1202 curl_mimepart *d;
1203 const curl_mimepart *s;
1204 CURLcode res = CURLE_OK;
1205
1206 DEBUGASSERT(dst);
1207
1208 /* Duplicate content. */
1209 switch(src->kind) {
1210 case MIMEKIND_NONE:
1211 break;
1212 case MIMEKIND_DATA:
1213 res = curl_mime_data(dst, src->data, (size_t) src->datasize);
1214 break;
1215 case MIMEKIND_FILE:
1216 res = curl_mime_filedata(dst, src->data);
1217 /* Do not abort duplication if file is not readable. */
1218 if(res == CURLE_READ_ERROR)
1219 res = CURLE_OK;
1220 break;
1221 case MIMEKIND_CALLBACK:
1222 res = curl_mime_data_cb(dst, src->datasize, src->readfunc,
1223 src->seekfunc, src->freefunc, src->arg);
1224 break;
1225 case MIMEKIND_MULTIPART:
1226 /* No one knows about the cloned subparts, thus always attach ownership
1227 to the part. */
1228 mime = curl_mime_init(data);
1229 res = mime? curl_mime_subparts(dst, mime): CURLE_OUT_OF_MEMORY;
1230
1231 /* Duplicate subparts. */
1232 for(s = ((curl_mime *) src->arg)->firstpart; !res && s; s = s->nextpart) {
1233 d = curl_mime_addpart(mime);
1234 res = d? Curl_mime_duppart(data, d, s): CURLE_OUT_OF_MEMORY;
1235 }
1236 break;
1237 default: /* Invalid kind: should not occur. */
1238 res = CURLE_BAD_FUNCTION_ARGUMENT; /* Internal error? */
1239 break;
1240 }
1241
1242 /* Duplicate headers. */
1243 if(!res && src->userheaders) {
1244 struct curl_slist *hdrs = Curl_slist_duplicate(src->userheaders);
1245
1246 if(!hdrs)
1247 res = CURLE_OUT_OF_MEMORY;
1248 else {
1249 /* No one but this procedure knows about the new header list,
1250 so always take ownership. */
1251 res = curl_mime_headers(dst, hdrs, TRUE);
1252 if(res)
1253 curl_slist_free_all(hdrs);
1254 }
1255 }
1256
1257 if(!res) {
1258 /* Duplicate other fields. */
1259 dst->encoder = src->encoder;
1260 res = curl_mime_type(dst, src->mimetype);
1261 }
1262 if(!res)
1263 res = curl_mime_name(dst, src->name);
1264 if(!res)
1265 res = curl_mime_filename(dst, src->filename);
1266
1267 /* If an error occurred, rollback. */
1268 if(res)
1269 Curl_mime_cleanpart(dst);
1270
1271 return res;
1272}
1273
1274/*
1275 * Mime build functions.
1276 */
1277
1278/* Create a mime handle. */
1279curl_mime *curl_mime_init(struct Curl_easy *easy)
1280{
1281 curl_mime *mime;
1282
1283 mime = (curl_mime *) malloc(sizeof(*mime));
1284
1285 if(mime) {
1286 mime->parent = NULL;
1287 mime->firstpart = NULL;
1288 mime->lastpart = NULL;
1289
1290 memset(mime->boundary, '-', MIME_BOUNDARY_DASHES);
1291 if(Curl_rand_hex(easy,
1292 (unsigned char *) &mime->boundary[MIME_BOUNDARY_DASHES],
1293 MIME_RAND_BOUNDARY_CHARS + 1)) {
1294 /* failed to get random separator, bail out */
1295 free(mime);
1296 return NULL;
1297 }
1298 mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1299 }
1300
1301 return mime;
1302}
1303
1304/* Initialize a mime part. */
1305void Curl_mime_initpart(curl_mimepart *part)
1306{
1307 memset((char *) part, 0, sizeof(*part));
1308 part->lastreadstatus = 1; /* Successful read status. */
1309 mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
1310}
1311
1312/* Create a mime part and append it to a mime handle's part list. */
1313curl_mimepart *curl_mime_addpart(curl_mime *mime)
1314{
1315 curl_mimepart *part;
1316
1317 if(!mime)
1318 return NULL;
1319
1320 part = (curl_mimepart *) malloc(sizeof(*part));
1321
1322 if(part) {
1323 Curl_mime_initpart(part);
1324 part->parent = mime;
1325
1326 if(mime->lastpart)
1327 mime->lastpart->nextpart = part;
1328 else
1329 mime->firstpart = part;
1330
1331 mime->lastpart = part;
1332 }
1333
1334 return part;
1335}
1336
1337/* Set mime part name. */
1338CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1339{
1340 if(!part)
1341 return CURLE_BAD_FUNCTION_ARGUMENT;
1342
1343 Curl_safefree(part->name);
1344 part->name = NULL;
1345
1346 if(name) {
1347 part->name = strdup(name);
1348 if(!part->name)
1349 return CURLE_OUT_OF_MEMORY;
1350 }
1351
1352 return CURLE_OK;
1353}
1354
1355/* Set mime part remote file name. */
1356CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1357{
1358 if(!part)
1359 return CURLE_BAD_FUNCTION_ARGUMENT;
1360
1361 Curl_safefree(part->filename);
1362 part->filename = NULL;
1363
1364 if(filename) {
1365 part->filename = strdup(filename);
1366 if(!part->filename)
1367 return CURLE_OUT_OF_MEMORY;
1368 }
1369
1370 return CURLE_OK;
1371}
1372
1373/* Set mime part content from memory data. */
1374CURLcode curl_mime_data(curl_mimepart *part,
1375 const char *data, size_t datasize)
1376{
1377 if(!part)
1378 return CURLE_BAD_FUNCTION_ARGUMENT;
1379
1380 cleanup_part_content(part);
1381
1382 if(data) {
1383 if(datasize == CURL_ZERO_TERMINATED)
1384 datasize = strlen(data);
1385
1386 part->data = malloc(datasize + 1);
1387 if(!part->data)
1388 return CURLE_OUT_OF_MEMORY;
1389
1390 part->datasize = datasize;
1391
1392 if(datasize)
1393 memcpy(part->data, data, datasize);
1394 part->data[datasize] = '\0'; /* Set a null terminator as sentinel. */
1395
1396 part->readfunc = mime_mem_read;
1397 part->seekfunc = mime_mem_seek;
1398 part->freefunc = mime_mem_free;
1399 part->flags |= MIME_FAST_READ;
1400 part->kind = MIMEKIND_DATA;
1401 }
1402
1403 return CURLE_OK;
1404}
1405
1406/* Set mime part content from named local file. */
1407CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1408{
1409 CURLcode result = CURLE_OK;
1410
1411 if(!part)
1412 return CURLE_BAD_FUNCTION_ARGUMENT;
1413
1414 cleanup_part_content(part);
1415
1416 if(filename) {
1417 char *base;
1418 struct_stat sbuf;
1419
1420 if(stat(filename, &sbuf) || access(filename, R_OK))
1421 result = CURLE_READ_ERROR;
1422
1423 part->data = strdup(filename);
1424 if(!part->data)
1425 result = CURLE_OUT_OF_MEMORY;
1426
1427 part->datasize = -1;
1428 if(!result && S_ISREG(sbuf.st_mode)) {
1429 part->datasize = filesize(filename, sbuf);
1430 part->seekfunc = mime_file_seek;
1431 }
1432
1433 part->readfunc = mime_file_read;
1434 part->freefunc = mime_file_free;
1435 part->kind = MIMEKIND_FILE;
1436
1437 /* As a side effect, set the filename to the current file's base name.
1438 It is possible to withdraw this by explicitly calling
1439 curl_mime_filename() with a NULL filename argument after the current
1440 call. */
1441 base = strippath(filename);
1442 if(!base)
1443 result = CURLE_OUT_OF_MEMORY;
1444 else {
1445 CURLcode res = curl_mime_filename(part, base);
1446
1447 if(res)
1448 result = res;
1449 free(base);
1450 }
1451 }
1452 return result;
1453}
1454
1455/* Set mime part type. */
1456CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1457{
1458 if(!part)
1459 return CURLE_BAD_FUNCTION_ARGUMENT;
1460
1461 Curl_safefree(part->mimetype);
1462 part->mimetype = NULL;
1463
1464 if(mimetype) {
1465 part->mimetype = strdup(mimetype);
1466 if(!part->mimetype)
1467 return CURLE_OUT_OF_MEMORY;
1468 }
1469
1470 return CURLE_OK;
1471}
1472
1473/* Set mime data transfer encoder. */
1474CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1475{
1476 CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
1477 const struct mime_encoder *mep;
1478
1479 if(!part)
1480 return result;
1481
1482 part->encoder = NULL;
1483
1484 if(!encoding)
1485 return CURLE_OK; /* Removing current encoder. */
1486
1487 for(mep = encoders; mep->name; mep++)
1488 if(strcasecompare(encoding, mep->name)) {
1489 part->encoder = mep;
1490 result = CURLE_OK;
1491 }
1492
1493 return result;
1494}
1495
1496/* Set mime part headers. */
1497CURLcode curl_mime_headers(curl_mimepart *part,
1498 struct curl_slist *headers, int take_ownership)
1499{
1500 if(!part)
1501 return CURLE_BAD_FUNCTION_ARGUMENT;
1502
1503 if(part->flags & MIME_USERHEADERS_OWNER) {
1504 if(part->userheaders != headers) /* Allow setting twice the same list. */
1505 curl_slist_free_all(part->userheaders);
1506 part->flags &= ~MIME_USERHEADERS_OWNER;
1507 }
1508 part->userheaders = headers;
1509 if(headers && take_ownership)
1510 part->flags |= MIME_USERHEADERS_OWNER;
1511 return CURLE_OK;
1512}
1513
1514/* Set mime part content from callback. */
1515CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize,
1516 curl_read_callback readfunc,
1517 curl_seek_callback seekfunc,
1518 curl_free_callback freefunc, void *arg)
1519{
1520 if(!part)
1521 return CURLE_BAD_FUNCTION_ARGUMENT;
1522
1523 cleanup_part_content(part);
1524
1525 if(readfunc) {
1526 part->readfunc = readfunc;
1527 part->seekfunc = seekfunc;
1528 part->freefunc = freefunc;
1529 part->arg = arg;
1530 part->datasize = datasize;
1531 part->kind = MIMEKIND_CALLBACK;
1532 }
1533
1534 return CURLE_OK;
1535}
1536
1537/* Set mime part content from subparts. */
1538CURLcode Curl_mime_set_subparts(curl_mimepart *part,
1539 curl_mime *subparts, int take_ownership)
1540{
1541 curl_mime *root;
1542
1543 if(!part)
1544 return CURLE_BAD_FUNCTION_ARGUMENT;
1545
1546 /* Accept setting twice the same subparts. */
1547 if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
1548 return CURLE_OK;
1549
1550 cleanup_part_content(part);
1551
1552 if(subparts) {
1553 /* Should not have been attached already. */
1554 if(subparts->parent)
1555 return CURLE_BAD_FUNCTION_ARGUMENT;
1556
1557 /* Should not be the part's root. */
1558 root = part->parent;
1559 if(root) {
1560 while(root->parent && root->parent->parent)
1561 root = root->parent->parent;
1562 if(subparts == root) {
1563 /* Can't add as a subpart of itself. */
1564 return CURLE_BAD_FUNCTION_ARGUMENT;
1565 }
1566 }
1567
1568 subparts->parent = part;
1569 /* Subparts are processed internally: no read callback. */
1570 part->seekfunc = mime_subparts_seek;
1571 part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind;
1572 part->arg = subparts;
1573 part->datasize = -1;
1574 part->kind = MIMEKIND_MULTIPART;
1575 }
1576
1577 return CURLE_OK;
1578}
1579
1580CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
1581{
1582 return Curl_mime_set_subparts(part, subparts, TRUE);
1583}
1584
1585
1586/* Readback from top mime. */
1587/* Argument is the dummy top part. */
1588size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
1589{
1590 curl_mimepart *part = (curl_mimepart *) instream;
1591 size_t ret;
1592 bool hasread;
1593
1594 (void) size; /* Always 1. */
1595
1596 do {
1597 hasread = FALSE;
1598 ret = readback_part(part, buffer, nitems, &hasread);
1599 /*
1600 * If this is not possible to get some data without calling more than
1601 * one read callback (probably because a content encoder is not able to
1602 * deliver a new bunch for the few data accumulated so far), force another
1603 * read until we get enough data or a special exit code.
1604 */
1605 } while(ret == STOP_FILLING);
1606
1607 return ret;
1608}
1609
1610/* Rewind mime stream. */
1611CURLcode Curl_mime_rewind(curl_mimepart *part)
1612{
1613 return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
1614 CURLE_OK: CURLE_SEND_FAIL_REWIND;
1615}
1616
1617/* Compute header list size. */
1618static size_t slist_size(struct curl_slist *s,
1619 size_t overhead, const char *skip, size_t skiplen)
1620{
1621 size_t size = 0;
1622
1623 for(; s; s = s->next)
1624 if(!skip || !match_header(s, skip, skiplen))
1625 size += strlen(s->data) + overhead;
1626 return size;
1627}
1628
1629/* Get/compute multipart size. */
1630static curl_off_t multipart_size(curl_mime *mime)
1631{
1632 curl_off_t size;
1633 curl_off_t boundarysize;
1634 curl_mimepart *part;
1635
1636 if(!mime)
1637 return 0; /* Not present -> empty. */
1638
1639 boundarysize = 4 + MIME_BOUNDARY_LEN + 2;
1640 size = boundarysize; /* Final boundary - CRLF after headers. */
1641
1642 for(part = mime->firstpart; part; part = part->nextpart) {
1643 curl_off_t sz = Curl_mime_size(part);
1644
1645 if(sz < 0)
1646 size = sz;
1647
1648 if(size >= 0)
1649 size += boundarysize + sz;
1650 }
1651
1652 return size;
1653}
1654
1655/* Get/compute mime size. */
1656curl_off_t Curl_mime_size(curl_mimepart *part)
1657{
1658 curl_off_t size;
1659
1660 if(part->kind == MIMEKIND_MULTIPART)
1661 part->datasize = multipart_size(part->arg);
1662
1663 size = part->datasize;
1664
1665 if(part->encoder)
1666 size = part->encoder->sizefunc(part);
1667
1668 if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
1669 /* Compute total part size. */
1670 size += slist_size(part->curlheaders, 2, NULL, 0);
1671 size += slist_size(part->userheaders, 2, 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 = curl_mvaprintf(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 won't 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. */
1905void Curl_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 Curl_mime_unpause(subpart);
1918 }
1919 }
1920 }
1921}
1922
1923
1924#else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP ||
1925 !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP) */
1926
1927/* Mime not compiled in: define stubs for externally-referenced functions. */
1928curl_mime *curl_mime_init(CURL *easy)
1929{
1930 (void) easy;
1931 return NULL;
1932}
1933
1934void curl_mime_free(curl_mime *mime)
1935{
1936 (void) mime;
1937}
1938
1939curl_mimepart *curl_mime_addpart(curl_mime *mime)
1940{
1941 (void) mime;
1942 return NULL;
1943}
1944
1945CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1946{
1947 (void) part;
1948 (void) name;
1949 return CURLE_NOT_BUILT_IN;
1950}
1951
1952CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1953{
1954 (void) part;
1955 (void) filename;
1956 return CURLE_NOT_BUILT_IN;
1957}
1958
1959CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1960{
1961 (void) part;
1962 (void) mimetype;
1963 return CURLE_NOT_BUILT_IN;
1964}
1965
1966CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1967{
1968 (void) part;
1969 (void) encoding;
1970 return CURLE_NOT_BUILT_IN;
1971}
1972
1973CURLcode curl_mime_data(curl_mimepart *part,
1974 const char *data, size_t datasize)
1975{
1976 (void) part;
1977 (void) data;
1978 (void) datasize;
1979 return CURLE_NOT_BUILT_IN;
1980}
1981
1982CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1983{
1984 (void) part;
1985 (void) filename;
1986 return CURLE_NOT_BUILT_IN;
1987}
1988
1989CURLcode curl_mime_data_cb(curl_mimepart *part,
1990 curl_off_t datasize,
1991 curl_read_callback readfunc,
1992 curl_seek_callback seekfunc,
1993 curl_free_callback freefunc,
1994 void *arg)
1995{
1996 (void) part;
1997 (void) datasize;
1998 (void) readfunc;
1999 (void) seekfunc;
2000 (void) freefunc;
2001 (void) arg;
2002 return CURLE_NOT_BUILT_IN;
2003}
2004
2005CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
2006{
2007 (void) part;
2008 (void) subparts;
2009 return CURLE_NOT_BUILT_IN;
2010}
2011
2012CURLcode curl_mime_headers(curl_mimepart *part,
2013 struct curl_slist *headers, int take_ownership)
2014{
2015 (void) part;
2016 (void) headers;
2017 (void) take_ownership;
2018 return CURLE_NOT_BUILT_IN;
2019}
2020
2021CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
2022{
2023 (void)slp;
2024 (void)fmt;
2025 return CURLE_NOT_BUILT_IN;
2026}
2027
2028#endif /* if disabled */
Note: See TracBrowser for help on using the repository browser.

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