Coverage Report

Created: 2026-10-15 06:24

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