VirtualBox

source: vbox/trunk/src/libs/curl-7.83.1/lib/mime.c@ 97138

最後變更 在這個檔案從97138是 95312,由 vboxsync 提交於 3 年 前

libs/{curl,libxml2}: OSE export fixes, bugref:8515

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

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