Coverage Report

Created: 2023-06-07 07:02

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