Coverage Report

Created: 2026-10-22 06:56

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
3.63M
#define MAX_MIME_LEVELS 40 /* avoid deep nesting */
48
49
6.04M
#define READ_ERROR   ((size_t)-1)
50
14.1M
#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
192M
#define QP_OK           1       /* Can be represented by itself. */
61
6.77M
#define QP_SP           2       /* Space or tab. */
62
50.9M
#define QP_CR           3       /* Carriage return. */
63
12.5M
#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
2
#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
36.2M
{
190
36.2M
  state->state = tok;
191
36.2M
  state->ptr = ptr;
192
36.2M
  state->offset = 0;
193
36.2M
}
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
289k
{
199
289k
  CURLcode result;
200
289k
  struct dynbuf db;
201
289k
  const char * const *table;
202
289k
  const char * const *p;
203
  /* replace first character by rest of string. */
204
289k
  static const char * const mimetable[] = {
205
289k
    "\\\\\\",
206
289k
    "\"\\\"",
207
289k
    NULL
208
289k
  };
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
289k
  static const char * const formtable[] = {
216
289k
    "\"%22",
217
289k
    "\r%0D",
218
289k
    "\n%0A",
219
289k
    NULL
220
289k
  };
221
222
289k
  table = formtable;
223
  /* data can be NULL when this function is called indirectly from
224
     curl_formget(). */
225
289k
  if(strategy == MIMESTRATEGY_MAIL || (data && data->set.mime_formescape))
226
34.3k
    table = mimetable;
227
228
289k
  curlx_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
229
230
3.97M
  for(result = curlx_dyn_addn(&db, STRCONST("")); !result && *src; src++) {
231
14.2M
    for(p = table; *p && **p != *src; p++)
232
10.5M
      ;
233
234
3.68M
    if(*p)
235
252k
      result = curlx_dyn_add(&db, *p + 1);
236
3.43M
    else
237
3.43M
      result = curlx_dyn_addn(&db, src, 1);
238
3.68M
  }
239
240
289k
  return curlx_dyn_ptr(&db);
241
289k
}
242
243
/* Check if header matches. */
244
static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
245
1.44M
{
246
1.44M
  char *value = NULL;
247
248
1.44M
  if(curl_strnequal(hdr->data, lbl, len) && hdr->data[len] == ':')
249
21.9k
    for(value = hdr->data + len + 1; *value == ' '; value++)
250
11.6k
      ;
251
1.44M
  return value;
252
1.44M
}
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
10.7M
{
258
10.7M
  char *value = NULL;
259
260
11.8M
  for(; !value && hdrlist; hdrlist = hdrlist->next)
261
1.04M
    value = match_header(hdrlist, hdr, len);
262
263
10.7M
  return value;
264
10.7M
}
265
266
static char *strippath(const char *fullfile)
267
2
{
268
2
  char *filename;
269
2
  char *base;
270
2
  filename = curlx_strdup(fullfile); /* duplicate since basename() may ruin
271
                                        the buffer it works on */
272
2
  if(!filename)
273
0
    return NULL;
274
2
  base = curlx_strdup(curlx_basename(filename));
275
276
2
  curlx_free(filename); /* free temporary buffer */
277
278
2
  return base; /* returns an allocated string or NULL ! */
279
2
}
280
281
/* Initialize data encoder state. */
282
static void cleanup_encoder_state(struct mime_encoder_state *p)
283
7.41M
{
284
7.41M
  p->pos = 0;
285
7.41M
  p->bufbeg = 0;
286
7.41M
  p->bufend = 0;
287
7.41M
}
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
730k
{
293
730k
  struct mime_encoder_state *st = &part->encstate;
294
730k
  size_t insize = st->bufend - st->bufbeg;
295
296
730k
  (void)ateof;
297
298
730k
  if(!size)
299
68.7k
    return STOP_FILLING;
300
301
661k
  if(size > insize)
302
593k
    size = insize;
303
304
661k
  if(size)
305
607k
    memcpy(buffer, st->buf + st->bufbeg, size);
306
307
661k
  st->bufbeg += size;
308
661k
  return size;
309
730k
}
310
311
static curl_off_t encoder_nop_size(curl_mimepart *part)
312
63.2k
{
313
63.2k
  return part->datasize;
314
63.2k
}
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
352k
{
320
352k
  struct mime_encoder_state *st = &part->encstate;
321
352k
  size_t cursize = st->bufend - st->bufbeg;
322
323
352k
  (void)ateof;
324
325
352k
  if(!size)
326
33.0k
    return STOP_FILLING;
327
328
319k
  if(size > cursize)
329
286k
    size = cursize;
330
331
63.3M
  for(cursize = 0; cursize < size; cursize++) {
332
63.0M
    *buffer = st->buf[st->bufbeg];
333
63.0M
    if(*buffer++ & 0x80)
334
5.72k
      return cursize ? cursize : READ_ERROR;
335
63.0M
    st->bufbeg++;
336
63.0M
  }
337
338
314k
  return cursize;
339
319k
}
340
341
/* Base64 content encoder. */
342
static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
343
                                  curl_mimepart *part)
344
5.57M
{
345
5.57M
  struct mime_encoder_state *st = &part->encstate;
346
5.57M
  size_t cursize = 0;
347
5.57M
  int i;
348
5.57M
  char *ptr = buffer;
349
350
162M
  while(st->bufbeg < st->bufend) {
351
    /* Line full ? */
352
162M
    if(st->pos > MAX_ENCODED_LINE_LENGTH - 4) {
353
      /* Yes, we need 2 characters for CRLF. */
354
8.35M
      if(size < 2) {
355
113k
        if(!cursize)
356
56.9k
          return STOP_FILLING;
357
56.4k
        break;
358
113k
      }
359
8.24M
      *ptr++ = '\r';
360
8.24M
      *ptr++ = '\n';
361
8.24M
      st->pos = 0;
362
8.24M
      cursize += 2;
363
8.24M
      size -= 2;
364
8.24M
    }
365
366
    /* Be sure there is enough space and input data for a base64 group. */
367
162M
    if(size < 4) {
368
1.78M
      if(!cursize)
369
1.29M
        return STOP_FILLING;
370
485k
      break;
371
1.78M
    }
372
160M
    if(st->bufend - st->bufbeg < 3)
373
3.43M
      break;
374
375
    /* Encode three bytes as four characters. */
376
156M
    i = st->buf[st->bufbeg++] & 0xFF;
377
156M
    i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
378
156M
    i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
379
156M
    *ptr++ = curlx_base64encdec[(i >> 18) & 0x3F];
380
156M
    *ptr++ = curlx_base64encdec[(i >> 12) & 0x3F];
381
156M
    *ptr++ = curlx_base64encdec[(i >> 6) & 0x3F];
382
156M
    *ptr++ = curlx_base64encdec[i & 0x3F];
383
156M
    cursize += 4;
384
156M
    st->pos += 4;
385
156M
    size -= 4;
386
156M
  }
387
388
  /* If at eof, we have to flush the buffered data. */
389
4.21M
  if(ateof) {
390
106k
    if(size < 4) {
391
2.60k
      if(!cursize)
392
2.60k
        return STOP_FILLING;
393
2.60k
    }
394
103k
    else {
395
      /* Buffered data size can only be 0, 1 or 2. */
396
103k
      ptr[2] = ptr[3] = '=';
397
103k
      i = 0;
398
399
      /* If there is buffered data */
400
103k
      if(st->bufend != st->bufbeg) {
401
402
23.6k
        if(st->bufend - st->bufbeg == 2)
403
8.11k
          i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
404
405
23.6k
        i |= (st->buf[st->bufbeg] & 0xFF) << 16;
406
23.6k
        ptr[0] = curlx_base64encdec[(i >> 18) & 0x3F];
407
23.6k
        ptr[1] = curlx_base64encdec[(i >> 12) & 0x3F];
408
23.6k
        if(++st->bufbeg != st->bufend) {
409
8.11k
          ptr[2] = curlx_base64encdec[(i >> 6) & 0x3F];
410
8.11k
          st->bufbeg++;
411
8.11k
        }
412
23.6k
        cursize += 4;
413
23.6k
        st->pos += 4;
414
23.6k
      }
415
103k
    }
416
106k
  }
417
418
4.21M
  return cursize;
419
4.21M
}
420
421
/* The maximum input size that does not cause an overflow. */
422
#define BASE64_MAX_INPUT_SIZE                                           \
423
31.9k
  (((CURL_OFF_T_MAX / (MAX_ENCODED_LINE_LENGTH + 2)) *                  \
424
31.9k
    MAX_ENCODED_LINE_LENGTH / 4) * 3 - 3)
425
426
static curl_off_t encoder_base64_size(curl_mimepart *part)
427
53.2k
{
428
53.2k
  curl_off_t size = part->datasize;
429
430
53.2k
  if(size <= 0)
431
21.3k
    return size;    /* Unknown size or no data. */
432
433
  /* Prevent integer overflows */
434
31.9k
  if(size > BASE64_MAX_INPUT_SIZE)
435
0
    return -1;
436
437
  /* Compute base64 character count. */
438
31.9k
  size = 4 * (1 + ((size - 1) / 3));
439
440
  /* Effective character count must include CRLFs. */
441
31.9k
  return size + (2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH));
442
31.9k
}
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
20.1M
{
451
20.1M
  n += st->bufbeg;
452
20.1M
  if(n >= st->bufend && ateof)
453
4.09k
    return 1;
454
20.1M
  if(n + 2 > st->bufend)
455
206k
    return ateof ? 0 : -1;
456
19.9M
  if(qp_class[st->buf[n] & 0xFF] == QP_CR &&
457
12.5M
     qp_class[st->buf[n + 1] & 0xFF] == QP_LF)
458
3.92M
    return 1;
459
16.0M
  return 0;
460
19.9M
}
461
462
/* Quoted-printable encoder. */
463
static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
464
                              curl_mimepart *part)
465
5.26M
{
466
5.26M
  struct mime_encoder_state *st = &part->encstate;
467
5.26M
  char *ptr = buffer;
468
5.26M
  size_t cursize = 0;
469
5.26M
  int softlinebreak;
470
5.26M
  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
486M
  while(st->bufbeg < st->bufend) {
477
484M
    size_t len = 1;
478
484M
    size_t consumed = 1;
479
484M
    int i = (unsigned char)st->buf[st->bufbeg];
480
484M
    buf[0] = (char)i;
481
484M
    buf[1] = aschex[(i >> 4) & 0xF];
482
484M
    buf[2] = aschex[i & 0xF];
483
484
484M
    switch(qp_class[st->buf[st->bufbeg] & 0xFF]) {
485
192M
    case QP_OK:          /* Not a special character. */
486
192M
      break;
487
6.77M
    case QP_SP:          /* Space or tab. */
488
      /* Spacing must be escaped if followed by CRLF. */
489
6.77M
      switch(qp_lookahead_eol(st, ateof, 1)) {
490
94.0k
      case -1:          /* More input data needed. */
491
94.0k
        return cursize;
492
6.55M
      case 0:           /* No encoding needed. */
493
6.55M
        break;
494
129k
      default:          /* CRLF after space or tab. */
495
129k
        buf[0] = '\x3D';    /* '=' */
496
129k
        len = 3;
497
129k
        break;
498
6.77M
      }
499
6.68M
      break;
500
11.1M
    case QP_CR:         /* Carriage return. */
501
      /* If followed by a line-feed, output the CRLF pair.
502
         Else escape it. */
503
11.1M
      switch(qp_lookahead_eol(st, ateof, 0)) {
504
57.8k
      case -1:          /* Need more data. */
505
57.8k
        return cursize;
506
3.74M
      case 1:           /* CRLF found. */
507
3.74M
        buf[len++] = '\x0A';    /* Append '\n'. */
508
3.74M
        consumed = 2;
509
3.74M
        break;
510
7.33M
      default:          /* Not followed by LF: escape. */
511
7.33M
        buf[0] = '\x3D';    /* '=' */
512
7.33M
        len = 3;
513
7.33M
        break;
514
11.1M
      }
515
11.0M
      break;
516
274M
    default:            /* Character must be escaped. */
517
274M
      buf[0] = '\x3D';    /* '=' */
518
274M
      len = 3;
519
274M
      break;
520
484M
    }
521
522
    /* Be sure the encoded character fits within maximum line length. */
523
484M
    if(buf[len - 1] != '\x0A') {    /* '\n' */
524
480M
      softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH;
525
480M
      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
2.22M
        switch(qp_lookahead_eol(st, ateof, consumed)) {
529
53.1k
        case -1:        /* Need more data. */
530
53.1k
          return cursize;
531
2.10M
        case 0:         /* Not followed by a CRLF. */
532
2.10M
          softlinebreak = 1;
533
2.10M
          break;
534
2.22M
        }
535
2.22M
      }
536
480M
      if(softlinebreak) {
537
11.7M
        curlx_strcopy(buf, sizeof(buf), STRCONST("\x3D\x0D\x0A")); /* =\r\n */
538
11.7M
        len = 3;
539
11.7M
        consumed = 0;
540
11.7M
      }
541
480M
    }
542
543
    /* If the output buffer would overflow, do not store. */
544
484M
    if(len > size) {
545
3.23M
      if(!cursize)
546
2.33M
        return STOP_FILLING;
547
898k
      break;
548
3.23M
    }
549
550
    /* Append to output buffer. */
551
481M
    memcpy(ptr, buf, len);
552
481M
    cursize += len;
553
481M
    ptr += len;
554
481M
    size -= len;
555
481M
    st->pos += len;
556
481M
    if(buf[len - 1] == '\x0A')    /* '\n' */
557
15.3M
      st->pos = 0;
558
481M
    st->bufbeg += consumed;
559
481M
  }
560
561
2.71M
  return cursize;
562
5.26M
}
563
564
static curl_off_t encoder_qp_size(curl_mimepart *part)
565
41.1k
{
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
41.1k
  return part->datasize ? -1 : 0;
569
41.1k
}
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
3.01M
{
576
3.01M
  curl_mimepart *part = (curl_mimepart *)instream;
577
3.01M
  size_t sz = curlx_sotouz(part->datasize - part->state.offset);
578
3.01M
  (void)size;  /* Always 1 */
579
580
3.01M
  if(!nitems)
581
0
    return STOP_FILLING;
582
583
3.01M
  if(sz > nitems)
584
2.89M
    sz = nitems;
585
586
3.01M
  if(sz)
587
3.01M
    memcpy(buffer, part->data + curlx_sotouz(part->state.offset), sz);
588
589
3.01M
  return sz;
590
3.01M
}
591
592
static int mime_mem_seek(void *instream, curl_off_t offset, int whence)
593
316k
{
594
316k
  curl_mimepart *part = (curl_mimepart *)instream;
595
596
316k
  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
316k
  }
604
605
316k
  if(offset < 0 || offset > part->datasize)
606
0
    return CURL_SEEKFUNC_FAIL;
607
608
316k
  part->state.offset = offset;
609
316k
  return CURL_SEEKFUNC_OK;
610
316k
}
611
612
static void mime_mem_free(void *ptr)
613
191k
{
614
191k
  curlx_safefree(((curl_mimepart *)ptr)->data);
615
191k
}
616
617
/* Named file callbacks. */
618
/* Argument is a pointer to the mime part. */
619
static bool mime_open_file(curl_mimepart *part)
620
2
{
621
  /* Open a MIMEKIND_FILE part. */
622
623
2
  if(part->fp)
624
0
    return FALSE;
625
2
  part->fp = fopen_read(part->data, "rb");
626
2
  return part->fp ? FALSE : TRUE;
627
2
}
628
629
static size_t mime_file_read(char *buffer, size_t size, size_t nitems,
630
                             void *instream)
631
2
{
632
2
  curl_mimepart *part = (curl_mimepart *)instream;
633
634
2
  if(!nitems)
635
0
    return STOP_FILLING;
636
637
2
  if(mime_open_file(part))
638
0
    return READ_ERROR;
639
640
2
  return fread(buffer, size, nitems, part->fp);
641
2
}
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
2
{
659
2
  curl_mimepart *part = (curl_mimepart *)ptr;
660
661
2
  if(part->fp) {
662
0
    curlx_fclose(part->fp);
663
0
    part->fp = NULL;
664
0
  }
665
2
  curlx_safefree(part->data);
666
2
}
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
26.4M
{
677
26.4M
  size_t sz;
678
26.4M
  size_t offset = curlx_sotouz(state->offset);
679
680
26.4M
  if(numbytes > offset) {
681
10.8M
    sz = numbytes - offset;
682
10.8M
    bytes += offset;
683
10.8M
  }
684
15.5M
  else {
685
15.5M
    sz = offset - numbytes;
686
15.5M
    if(sz >= traillen)
687
10.7M
      return 0;
688
4.78M
    bytes = trail + sz;
689
4.78M
    sz = traillen - sz;
690
4.78M
  }
691
692
15.6M
  if(sz > bufsize)
693
43.8k
    sz = bufsize;
694
695
15.6M
  memcpy(buffer, bytes, sz);
696
15.6M
  state->offset += sz;
697
15.6M
  return sz;
698
26.4M
}
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
7.96M
{
705
7.96M
  size_t sz = 0;
706
707
7.96M
  switch(part->lastreadstatus) {
708
80.5k
  case 0:
709
80.5k
  case CURL_READFUNC_ABORT:
710
80.5k
  case CURL_READFUNC_PAUSE:
711
81.9k
  case READ_ERROR:
712
81.9k
    return part->lastreadstatus;
713
7.88M
  default:
714
7.88M
    break;
715
7.96M
  }
716
717
  /* If we can determine we are at end of part data, spare a read. */
718
7.88M
  if(part->datasize != (curl_off_t)-1 &&
719
6.91M
     part->state.offset >= part->datasize) {
720
    /* sz is already zero. */
721
2.95M
  }
722
4.93M
  else {
723
4.93M
    switch(part->kind) {
724
1.91M
    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
1.91M
      sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread);
730
1.91M
      break;
731
7
    case MIMEKIND_FILE:
732
7
      if(part->fp && feof(part->fp))
733
0
        break;  /* At EOF. */
734
7
      FALLTHROUGH();
735
3.01M
    default:
736
3.01M
      if(part->readfunc) {
737
3.01M
        if(!(part->flags & MIME_FAST_READ)) {
738
7
          if(*hasread)
739
5
            return STOP_FILLING;
740
2
          *hasread = TRUE;
741
2
        }
742
3.01M
        sz = part->readfunc(buffer, 1, bufsize, part->arg);
743
3.01M
      }
744
3.01M
      break;
745
4.93M
    }
746
4.93M
  }
747
748
7.88M
  switch(sz) {
749
16.8k
  case STOP_FILLING:
750
16.8k
    break;
751
2.96M
  case 0:
752
2.96M
  case CURL_READFUNC_ABORT:
753
2.96M
  case CURL_READFUNC_PAUSE:
754
2.96M
  case READ_ERROR:
755
2.96M
    part->lastreadstatus = sz;
756
2.96M
    break;
757
4.89M
  default:
758
4.89M
    part->state.offset += sz;
759
4.89M
    part->lastreadstatus = sz;
760
4.89M
    break;
761
7.88M
  }
762
763
7.88M
  return sz;
764
7.88M
}
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
4.01M
{
770
4.01M
  struct mime_encoder_state *st = &part->encstate;
771
4.01M
  size_t cursize = 0;
772
4.01M
  size_t sz;
773
4.01M
  bool ateof = FALSE;
774
775
14.8M
  for(;;) {
776
14.8M
    if(st->bufbeg < st->bufend || ateof) {
777
      /* Encode buffered data. */
778
11.9M
      sz = part->encoder->encodefunc(buffer, bufsize, ateof, part);
779
11.9M
      switch(sz) {
780
2.03M
      case 0:
781
2.03M
        if(ateof)
782
216k
          return cursize;
783
1.81M
        break;
784
1.81M
      case READ_ERROR:
785
3.80M
      case STOP_FILLING:
786
3.80M
        return cursize ? cursize : sz;
787
6.08M
      default:
788
6.08M
        cursize += sz;
789
6.08M
        buffer += sz;
790
6.08M
        bufsize -= sz;
791
6.08M
        continue;
792
11.9M
      }
793
11.9M
    }
794
795
    /* We need more data in input buffer. */
796
4.75M
    if(st->bufbeg) {
797
4.54M
      size_t len = st->bufend - st->bufbeg;
798
799
4.54M
      if(len)
800
1.80M
        memmove(st->buf, st->buf + st->bufbeg, len);
801
4.54M
      st->bufbeg = 0;
802
4.54M
      st->bufend = len;
803
4.54M
    }
804
4.75M
    if(st->bufend >= sizeof(st->buf))
805
0
      return cursize ? cursize : READ_ERROR;    /* Buffer full. */
806
4.75M
    sz = read_part_content(part, st->buf + st->bufend,
807
4.75M
                           sizeof(st->buf) - st->bufend, hasread);
808
4.75M
    switch(sz) {
809
220k
    case 0:
810
220k
      ateof = TRUE;
811
220k
      break;
812
0
    case CURL_READFUNC_ABORT:
813
0
    case CURL_READFUNC_PAUSE:
814
916
    case READ_ERROR:
815
916
    case STOP_FILLING:
816
916
      return cursize ? cursize : sz;
817
4.53M
    default:
818
4.53M
      st->bufend += sz;
819
4.53M
      break;
820
4.75M
    }
821
4.75M
  }
822
823
  /* NOTREACHED */
824
4.01M
}
825
826
/* Readback a mime part. */
827
static size_t readback_part(curl_mimepart *part,
828
                            char *buffer, size_t bufsize, bool *hasread)
829
8.87M
{
830
8.87M
  size_t cursize = 0;
831
832
  /* Readback from part. */
833
33.6M
  while(bufsize) {
834
33.0M
    size_t sz = 0;
835
33.0M
    struct curl_slist *hdr = (struct curl_slist *)part->state.ptr;
836
33.0M
    switch(part->state.state) {
837
2.96M
    case MIMESTATE_BEGIN:
838
2.96M
      mimesetstate(&part->state,
839
2.96M
                   (part->flags & MIME_BODY_ONLY) ?
840
2.96M
                   MIMESTATE_BODY : MIMESTATE_CURLHEADERS,
841
2.96M
                   part->curlheaders);
842
2.96M
      break;
843
3.25M
    case MIMESTATE_USERHEADERS:
844
3.25M
      if(!hdr) {
845
2.96M
        mimesetstate(&part->state, MIMESTATE_EOH, NULL);
846
2.96M
        break;
847
2.96M
      }
848
286k
      if(match_header(hdr, "Content-Type", 12)) {
849
2.64k
        mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next);
850
2.64k
        break;
851
2.64k
      }
852
283k
      FALLTHROUGH();
853
7.89M
    case MIMESTATE_CURLHEADERS:
854
7.89M
      if(!hdr)
855
2.96M
        mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
856
4.93M
      else {
857
4.93M
        sz = readback_bytes(&part->state, buffer, bufsize,
858
4.93M
                            hdr->data, strlen(hdr->data), STRCONST("\r\n"));
859
4.93M
        if(!sz)
860
1.64M
          mimesetstate(&part->state, part->state.state, hdr->next);
861
4.93M
      }
862
7.89M
      break;
863
5.92M
    case MIMESTATE_EOH:
864
5.92M
      sz = readback_bytes(&part->state, buffer, bufsize, STRCONST("\r\n"),
865
5.92M
                          STRCONST(""));
866
5.92M
      if(!sz)
867
2.96M
        mimesetstate(&part->state, MIMESTATE_BODY, NULL);
868
5.92M
      break;
869
3.06M
    case MIMESTATE_BODY:
870
3.06M
      cleanup_encoder_state(&part->encstate);
871
3.06M
      mimesetstate(&part->state, MIMESTATE_CONTENT, NULL);
872
3.06M
      break;
873
7.23M
    case MIMESTATE_CONTENT:
874
7.23M
      if(part->encoder)
875
4.01M
        sz = read_encoded_part_content(part, buffer, bufsize, hasread);
876
3.21M
      else
877
3.21M
        sz = read_part_content(part, buffer, bufsize, hasread);
878
7.23M
      switch(sz) {
879
2.96M
      case 0:
880
2.96M
        mimesetstate(&part->state, MIMESTATE_END, NULL);
881
        /* Try sparing open file descriptors. */
882
2.96M
        if(part->kind == MIMEKIND_FILE && part->fp) {
883
2
          curlx_fclose(part->fp);
884
2
          part->fp = NULL;
885
2
        }
886
2.96M
        FALLTHROUGH();
887
2.96M
      case CURL_READFUNC_ABORT:
888
2.96M
      case CURL_READFUNC_PAUSE:
889
2.97M
      case READ_ERROR:
890
5.24M
      case STOP_FILLING:
891
5.24M
        return cursize ? cursize : sz;
892
7.23M
      }
893
1.98M
      break;
894
2.96M
    case MIMESTATE_END:
895
2.96M
      return cursize;
896
0
    default:
897
0
      break;    /* Other values not in part state. */
898
33.0M
    }
899
900
    /* Bump buffer and counters according to read size. */
901
24.8M
    cursize += sz;
902
24.8M
    buffer += sz;
903
24.8M
    bufsize -= sz;
904
24.8M
  }
905
906
674k
  return cursize;
907
8.87M
}
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
1.91M
{
913
1.91M
  curl_mime *mime = (curl_mime *)instream;
914
1.91M
  size_t cursize = 0;
915
1.91M
  (void)size;  /* Always 1 */
916
917
25.3M
  while(nitems) {
918
24.7M
    size_t sz = 0;
919
24.7M
    curl_mimepart *part = mime->state.ptr;
920
24.7M
    switch(mime->state.state) {
921
176k
    case MIMESTATE_BEGIN:
922
176k
    case MIMESTATE_BODY:
923
176k
      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
176k
      mime->state.offset += 2;
928
176k
      break;
929
6.26M
    case MIMESTATE_BOUNDARY1:
930
6.26M
      sz = readback_bytes(&mime->state, buffer, nitems, STRCONST("\r\n--"),
931
6.26M
                          STRCONST(""));
932
6.26M
      if(!sz)
933
3.13M
        mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part);
934
6.26M
      break;
935
9.33M
    case MIMESTATE_BOUNDARY2:
936
9.33M
      if(part)
937
8.90M
        sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
938
8.90M
                            MIME_BOUNDARY_LEN, STRCONST("\r\n"));
939
429k
      else
940
429k
        sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
941
429k
                            MIME_BOUNDARY_LEN, STRCONST("--\r\n"));
942
9.33M
      if(!sz) {
943
3.05M
        mimesetstate(&mime->state, MIMESTATE_CONTENT, part);
944
3.05M
      }
945
9.33M
      break;
946
8.82M
    case MIMESTATE_CONTENT:
947
8.82M
      if(!part) {
948
86.8k
        mimesetstate(&mime->state, MIMESTATE_END, NULL);
949
86.8k
        break;
950
86.8k
      }
951
8.74M
      sz = readback_part(part, buffer, nitems, hasread);
952
8.74M
      switch(sz) {
953
0
      case CURL_READFUNC_ABORT:
954
0
      case CURL_READFUNC_PAUSE:
955
3.35k
      case READ_ERROR:
956
1.13M
      case STOP_FILLING:
957
1.13M
        return cursize ? cursize : sz;
958
2.95M
      case 0:
959
2.95M
        mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart);
960
2.95M
        break;
961
8.74M
      }
962
7.60M
      break;
963
7.60M
    case MIMESTATE_END:
964
102k
      return cursize;
965
0
    default:
966
0
      break;    /* other values not used in mime state. */
967
24.7M
    }
968
969
    /* Bump buffer and counters according to read size. */
970
23.4M
    cursize += sz;
971
23.4M
    buffer += sz;
972
23.4M
    nitems -= sz;
973
23.4M
  }
974
975
673k
  return cursize;
976
1.91M
}
977
978
static int mime_part_rewind(curl_mimepart *part)
979
653k
{
980
653k
  int res = CURL_SEEKFUNC_OK;
981
653k
  enum mimestate targetstate = MIMESTATE_BEGIN;
982
983
653k
  if(part->flags & MIME_BODY_ONLY)
984
161k
    targetstate = MIMESTATE_BODY;
985
653k
  cleanup_encoder_state(&part->encstate);
986
653k
  if(part->state.state > targetstate) {
987
486k
    res = CURL_SEEKFUNC_CANTSEEK;
988
486k
    if(part->seekfunc) {
989
428k
      res = part->seekfunc(part->arg, (curl_off_t)0, SEEK_SET);
990
428k
      switch(res) {
991
427k
      case CURL_SEEKFUNC_OK:
992
427k
      case CURL_SEEKFUNC_FAIL:
993
428k
      case CURL_SEEKFUNC_CANTSEEK:
994
428k
        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
428k
      }
1002
428k
    }
1003
486k
  }
1004
1005
653k
  if(res == CURL_SEEKFUNC_OK)
1006
593k
    mimesetstate(&part->state, targetstate, NULL);
1007
1008
653k
  part->lastreadstatus = 1; /* Successful read status. */
1009
653k
  return res;
1010
653k
}
1011
1012
static int mime_subparts_seek(void *instream, curl_off_t offset, int whence)
1013
214k
{
1014
214k
  curl_mime *mime = (curl_mime *)instream;
1015
214k
  curl_mimepart *part;
1016
214k
  int rc = CURL_SEEKFUNC_OK;
1017
1018
214k
  if(whence != SEEK_SET || offset)
1019
0
    return CURL_SEEKFUNC_CANTSEEK;    /* Only support full rewind. */
1020
1021
214k
  if(mime->state.state == MIMESTATE_BEGIN)
1022
102k
    return CURL_SEEKFUNC_OK;           /* Already rewound. */
1023
1024
602k
  for(part = mime->firstpart; part; part = part->nextpart) {
1025
490k
    int res = mime_part_rewind(part);
1026
490k
    if(res != CURL_SEEKFUNC_OK)
1027
58.4k
      rc = res;
1028
490k
  }
1029
1030
112k
  if(rc == CURL_SEEKFUNC_OK)
1031
110k
    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1032
1033
112k
  return rc;
1034
214k
}
1035
1036
/* Release part content. */
1037
static void cleanup_part_content(curl_mimepart *part)
1038
3.69M
{
1039
3.69M
  if(part->freefunc)
1040
244k
    part->freefunc(part->arg);
1041
1042
3.69M
  part->readfunc = NULL;
1043
3.69M
  part->seekfunc = NULL;
1044
3.69M
  part->freefunc = NULL;
1045
3.69M
  part->arg = (void *)part;           /* Defaults to part itself. */
1046
3.69M
  part->data = NULL;
1047
3.69M
  part->fp = NULL;
1048
3.69M
  part->datasize = (curl_off_t)0;     /* No size yet. */
1049
3.69M
  cleanup_encoder_state(&part->encstate);
1050
3.69M
  part->kind = MIMEKIND_NONE;
1051
3.69M
  part->flags &= ~(unsigned int)MIME_FAST_READ;
1052
3.69M
  part->lastreadstatus = 1; /* Successful read status. */
1053
3.69M
  part->state.state = MIMESTATE_BEGIN;
1054
3.69M
}
1055
1056
static void mime_subparts_free(void *ptr)
1057
4.06k
{
1058
4.06k
  curl_mime *mime = (curl_mime *)ptr;
1059
1060
4.06k
  if(mime && mime->parent) {
1061
4.06k
    mime->parent->freefunc = NULL;  /* Be sure we will not be called again. */
1062
4.06k
    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
1063
4.06k
  }
1064
4.06k
  curl_mime_free(mime);
1065
4.06k
}
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
115k
{
1070
115k
  curl_mime *mime = (curl_mime *)ptr;
1071
1072
115k
  if(mime && mime->parent) {
1073
66.1k
    mime->parent->freefunc = NULL;  /* Be sure we will not be called again. */
1074
66.1k
    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
1075
66.1k
    mime->parent = NULL;
1076
66.1k
  }
1077
115k
}
1078
1079
void Curl_mime_cleanpart(curl_mimepart *part)
1080
5.87M
{
1081
5.87M
  if(part) {
1082
3.24M
    cleanup_part_content(part);
1083
3.24M
    curl_slist_free_all(part->curlheaders);
1084
3.24M
    if(part->flags & MIME_USERHEADERS_OWNER)
1085
28.7k
      curl_slist_free_all(part->userheaders);
1086
3.24M
    curlx_safefree(part->mimetype);
1087
3.24M
    curlx_safefree(part->name);
1088
3.24M
    curlx_safefree(part->filename);
1089
3.24M
    Curl_mime_initpart(part);
1090
3.24M
  }
1091
5.87M
}
1092
1093
/* Non-recursively delete a mime handle and its parts. */
1094
void curl_mime_free(curl_mime *mime)
1095
66.4k
{
1096
66.4k
  curl_mimepart *part;
1097
1098
66.4k
  if(!mime)
1099
0
    return;
1100
1101
66.4k
  mime_subparts_unbind(mime);  /* Be sure it is not referenced anymore. */
1102
1103
3.34M
  while(mime) {
1104
3.28M
    part = mime->firstpart;
1105
3.28M
    if(part) {
1106
3.17M
      mime->firstpart = part->nextpart;
1107
3.17M
      if(part->kind == MIMEKIND_MULTIPART && part->arg &&
1108
36.2k
         part->freefunc == mime_subparts_free) {
1109
36.2k
        curl_mime *subparts = (curl_mime *)part->arg;
1110
36.2k
        part->freefunc = NULL;
1111
36.2k
        cleanup_part_content(part);
1112
36.2k
        subparts->parent = mime->parent;
1113
36.2k
        mime->parent = (curl_mimepart *)subparts;
1114
36.2k
      }
1115
3.17M
      Curl_mime_cleanpart(part);
1116
3.17M
      curlx_free(part);
1117
3.17M
    }
1118
102k
    else {
1119
102k
      curl_mime *parent = (curl_mime *)mime->parent;
1120
102k
      curlx_free(mime);
1121
102k
      mime = parent;
1122
102k
    }
1123
3.28M
  }
1124
66.4k
}
1125
1126
static bool mime_is_too_deep(const curl_mimepart *part, size_t call_depth)
1127
11.2k
{
1128
11.2k
  DEBUGASSERT(part);
1129
1130
11.2k
  if(++call_depth > MAX_MIME_LEVELS)
1131
0
    return TRUE;
1132
1133
11.2k
  if(part->kind == MIMEKIND_MULTIPART && part->arg) {
1134
4.17k
    const curl_mime *mime = (const curl_mime *)part->arg;
1135
4.17k
    const curl_mimepart *s;
1136
1137
13.5k
    for(s = mime->firstpart; s; s = s->nextpart) {
1138
9.42k
      if(mime_is_too_deep(s, call_depth))
1139
0
        return TRUE;
1140
9.42k
    }
1141
4.17k
  }
1142
1143
11.2k
  return FALSE;
1144
11.2k
}
1145
1146
static CURLcode mime_duppart(struct Curl_easy *data,
1147
                             curl_mimepart *dst, const curl_mimepart *src,
1148
                             size_t call_depth)
1149
10.9k
{
1150
10.9k
  curl_mime *mime;
1151
10.9k
  curl_mimepart *d;
1152
10.9k
  const curl_mimepart *s;
1153
10.9k
  CURLcode result = CURLE_OK;
1154
1155
10.9k
  DEBUGASSERT(dst);
1156
10.9k
  DEBUGASSERT(src);
1157
1158
10.9k
  if(++call_depth > MAX_MIME_LEVELS)
1159
0
    return CURLE_TOO_LARGE;
1160
1161
  /* Duplicate content. */
1162
10.9k
  switch(src->kind) {
1163
3.13k
  case MIMEKIND_NONE:
1164
3.13k
    break;
1165
3.68k
  case MIMEKIND_DATA:
1166
3.68k
    result = curl_mime_data(dst, src->data, (size_t)src->datasize);
1167
3.68k
    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
4.12k
  case MIMEKIND_MULTIPART:
1179
    /* No one knows about the cloned subparts, thus always attach ownership
1180
       to the part. */
1181
4.12k
    mime = curl_mime_init(data);
1182
4.12k
    result = mime ? curl_mime_subparts(dst, mime) : CURLE_OUT_OF_MEMORY;
1183
1184
    /* Duplicate subparts. */
1185
13.2k
    for(s = ((curl_mime *)src->arg)->firstpart; !result && s;
1186
9.13k
        s = s->nextpart) {
1187
9.13k
      d = curl_mime_addpart(mime);
1188
9.13k
      result = d ? mime_duppart(data, d, s, call_depth) : CURLE_OUT_OF_MEMORY;
1189
9.13k
    }
1190
4.12k
    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
10.9k
  }
1196
1197
  /* Duplicate headers. */
1198
10.9k
  if(!result && src->userheaders) {
1199
2.22k
    struct curl_slist *hdrs = Curl_slist_duplicate(src->userheaders);
1200
1201
2.22k
    if(!hdrs)
1202
38
      result = CURLE_OUT_OF_MEMORY;
1203
2.18k
    else {
1204
      /* No one but this procedure knows about the new header list,
1205
         so always take ownership. */
1206
2.18k
      result = curl_mime_headers(dst, hdrs, TRUE);
1207
2.18k
      if(result)
1208
0
        curl_slist_free_all(hdrs);
1209
2.18k
    }
1210
2.22k
  }
1211
1212
10.9k
  if(!result) {
1213
    /* Duplicate other fields. */
1214
10.7k
    dst->encoder = src->encoder;
1215
10.7k
    result = curl_mime_type(dst, src->mimetype);
1216
10.7k
  }
1217
10.9k
  if(!result)
1218
10.7k
    result = curl_mime_name(dst, src->name);
1219
10.9k
  if(!result)
1220
10.7k
    result = curl_mime_filename(dst, src->filename);
1221
1222
  /* If an error occurred, rollback. */
1223
10.9k
  if(result)
1224
214
    Curl_mime_cleanpart(dst);
1225
1226
10.9k
  return result;
1227
10.9k
}
1228
1229
CURLcode Curl_mime_duppart(struct Curl_easy *data,
1230
                           curl_mimepart *dst, const curl_mimepart *src)
1231
1.83k
{
1232
1.83k
  if(!dst || !src)
1233
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1234
1235
1.83k
  if(mime_is_too_deep(src, 0))
1236
0
    return CURLE_TOO_LARGE;
1237
1238
1.83k
  return mime_duppart(data, dst, src, 0);
1239
1.83k
}
1240
1241
/*
1242
 * Mime build functions.
1243
 */
1244
1245
/* Create a mime handle. */
1246
curl_mime *curl_mime_init(void *easy)
1247
102k
{
1248
102k
  curl_mime *mime = curlx_malloc(sizeof(*mime));
1249
1250
102k
  if(mime) {
1251
102k
    mime->parent = NULL;
1252
102k
    mime->firstpart = NULL;
1253
102k
    mime->lastpart = NULL;
1254
1255
102k
    memset(mime->boundary, '-', MIME_BOUNDARY_DASHES);
1256
102k
    if(Curl_rand_alnum(easy,
1257
102k
                       (unsigned char *)&mime->boundary[MIME_BOUNDARY_DASHES],
1258
102k
                       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
102k
    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1264
102k
  }
1265
1266
102k
  return mime;
1267
102k
}
1268
1269
/* Initialize a mime part. */
1270
void Curl_mime_initpart(curl_mimepart *part)
1271
6.49M
{
1272
6.49M
  memset(part, 0, sizeof(*part));
1273
6.49M
  part->lastreadstatus = 1; /* Successful read status. */
1274
6.49M
  mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
1275
6.49M
}
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
3.17M
{
1280
3.17M
  curl_mimepart *part;
1281
1282
3.17M
  if(!mime)
1283
0
    return NULL;
1284
1285
3.17M
  part = curlx_malloc(sizeof(*part));
1286
1287
3.17M
  if(part) {
1288
3.17M
    Curl_mime_initpart(part);
1289
3.17M
    part->parent = mime;
1290
1291
3.17M
    if(mime->lastpart)
1292
3.10M
      mime->lastpart->nextpart = part;
1293
73.0k
    else
1294
73.0k
      mime->firstpart = part;
1295
1296
3.17M
    mime->lastpart = part;
1297
3.17M
  }
1298
1299
3.17M
  return part;
1300
3.17M
}
1301
1302
/* Set mime part name. */
1303
CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1304
107k
{
1305
107k
  if(!part)
1306
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1307
1308
107k
  curlx_safefree(part->name);
1309
1310
107k
  if(name) {
1311
98.7k
    part->name = curlx_strdup(name);
1312
98.7k
    if(!part->name)
1313
110
      return CURLE_OUT_OF_MEMORY;
1314
98.7k
  }
1315
1316
107k
  return CURLE_OK;
1317
107k
}
1318
1319
/* Set mime part remote filename. */
1320
CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1321
45.2k
{
1322
45.2k
  if(!part)
1323
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1324
1325
45.2k
  curlx_safefree(part->filename);
1326
1327
45.2k
  if(filename) {
1328
36.5k
    part->filename = curlx_strdup(filename);
1329
36.5k
    if(!part->filename)
1330
92
      return CURLE_OUT_OF_MEMORY;
1331
36.5k
  }
1332
1333
45.1k
  return CURLE_OK;
1334
45.2k
}
1335
1336
/* Set mime part content from memory data. */
1337
CURLcode curl_mime_data(curl_mimepart *part, const char *data, size_t datasize)
1338
192k
{
1339
192k
  if(!part)
1340
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1341
1342
192k
  cleanup_part_content(part);
1343
1344
192k
  if(data) {
1345
192k
    if(datasize == CURL_ZERO_TERMINATED)
1346
361
      datasize = strlen(data);
1347
1348
192k
    part->data = curlx_memdup0(data, datasize);
1349
192k
    if(!part->data)
1350
170
      return CURLE_OUT_OF_MEMORY;
1351
1352
191k
    part->datasize = datasize;
1353
191k
    part->readfunc = mime_mem_read;
1354
191k
    part->seekfunc = mime_mem_seek;
1355
191k
    part->freefunc = mime_mem_free;
1356
191k
    part->flags |= MIME_FAST_READ;
1357
191k
    part->kind = MIMEKIND_DATA;
1358
191k
  }
1359
1360
191k
  return CURLE_OK;
1361
192k
}
1362
1363
/* Set mime part content from named local file. */
1364
CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1365
2
{
1366
2
  CURLcode result = CURLE_OK;
1367
1368
2
  if(!part)
1369
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1370
1371
2
  cleanup_part_content(part);
1372
1373
2
  if(filename) {
1374
2
    char *base;
1375
2
    curlx_struct_stat sbuf;
1376
1377
2
    if(curlx_stat(filename, &sbuf))
1378
0
      result = CURLE_READ_ERROR;
1379
2
    else {
1380
2
      part->data = curlx_strdup(filename);
1381
2
      if(!part->data)
1382
0
        result = CURLE_OUT_OF_MEMORY;
1383
2
      else {
1384
2
        part->datasize = -1;
1385
2
        if(S_ISREG(sbuf.st_mode)) {
1386
0
          part->datasize = filesize(filename, sbuf);
1387
0
          part->seekfunc = mime_file_seek;
1388
0
        }
1389
1390
2
        part->readfunc = mime_file_read;
1391
2
        part->freefunc = mime_file_free;
1392
2
        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
2
        base = strippath(filename);
1399
2
        if(!base)
1400
0
          result = CURLE_OUT_OF_MEMORY;
1401
2
        else {
1402
2
          result = curl_mime_filename(part, base);
1403
2
          curlx_free(base);
1404
2
        }
1405
2
      }
1406
2
    }
1407
2
  }
1408
2
  return result;
1409
2
}
1410
1411
/* Set mime part type. */
1412
CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1413
41.3k
{
1414
41.3k
  if(!part)
1415
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1416
1417
41.3k
  curlx_safefree(part->mimetype);
1418
1419
41.3k
  if(mimetype) {
1420
32.6k
    part->mimetype = curlx_strdup(mimetype);
1421
32.6k
    if(!part->mimetype)
1422
89
      return CURLE_OUT_OF_MEMORY;
1423
32.6k
  }
1424
1425
41.2k
  return CURLE_OK;
1426
41.3k
}
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
62.3k
{
1440
62.3k
  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
1441
62.3k
  const struct mime_encoder *mep;
1442
1443
62.3k
  if(!part)
1444
0
    return result;
1445
1446
62.3k
  part->encoder = NULL;
1447
1448
62.3k
  if(!encoding)
1449
0
    return CURLE_OK;    /* Removing current encoder. */
1450
1451
373k
  for(mep = encoders; mep->name; mep++)
1452
311k
    if(curl_strequal(encoding, mep->name)) {
1453
62.3k
      part->encoder = mep;
1454
62.3k
      result = CURLE_OK;
1455
62.3k
    }
1456
1457
62.3k
  return result;
1458
62.3k
}
1459
1460
/* Set mime part headers. */
1461
CURLcode curl_mime_headers(curl_mimepart *part,
1462
                           struct curl_slist *headers, int take_ownership)
1463
244k
{
1464
244k
  if(!part)
1465
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1466
1467
244k
  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
244k
  part->userheaders = headers;
1473
244k
  if(headers && take_ownership)
1474
28.7k
    part->flags |= MIME_USERHEADERS_OWNER;
1475
244k
  return CURLE_OK;
1476
244k
}
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
151k
{
1505
151k
  curl_mime *root;
1506
1507
151k
  if(!part)
1508
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1509
1510
  /* Accept setting twice the same subparts. */
1511
151k
  if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
1512
0
    return CURLE_OK;
1513
1514
151k
  cleanup_part_content(part);
1515
1516
151k
  if(subparts) {
1517
    /* Should not have been attached already. */
1518
102k
    if(subparts->parent)
1519
0
      return CURLE_BAD_FUNCTION_ARGUMENT;
1520
1521
    /* Should not be the part's root. */
1522
102k
    root = part->parent;
1523
102k
    if(root) {
1524
36.2k
      while(root->parent && root->parent->parent)
1525
0
        root = root->parent->parent;
1526
36.2k
      if(subparts == root) {
1527
        /* cannot add as a subpart of itself. */
1528
0
        return CURLE_BAD_FUNCTION_ARGUMENT;
1529
0
      }
1530
36.2k
    }
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
102k
    if(mime_subparts_seek(subparts, (curl_off_t)0, SEEK_SET) !=
1537
102k
       CURL_SEEKFUNC_OK)
1538
0
      return CURLE_SEND_FAIL_REWIND;
1539
1540
102k
    subparts->parent = part;
1541
    /* Subparts are processed internally: no read callback. */
1542
102k
    part->seekfunc = mime_subparts_seek;
1543
102k
    part->freefunc = take_ownership ? mime_subparts_free :
1544
102k
      mime_subparts_unbind;
1545
102k
    part->arg = subparts;
1546
102k
    part->datasize = -1;
1547
102k
    part->kind = MIMEKIND_MULTIPART;
1548
102k
  }
1549
1550
151k
  return CURLE_OK;
1551
151k
}
1552
1553
CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
1554
40.2k
{
1555
40.2k
  return Curl_mime_set_subparts(part, subparts, TRUE);
1556
40.2k
}
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
137k
{
1562
137k
  curl_mimepart *part = (curl_mimepart *)instream;
1563
137k
  size_t ret;
1564
137k
  bool hasread;
1565
1566
137k
  (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
137k
  do {
1571
137k
    hasread = FALSE;
1572
137k
    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
137k
  } while(ret == STOP_FILLING);
1580
1581
137k
  return ret;
1582
137k
}
1583
1584
/* Rewind mime stream. */
1585
static CURLcode mime_rewind(curl_mimepart *part)
1586
163k
{
1587
163k
  return mime_part_rewind(part) == CURL_SEEKFUNC_OK ?
1588
161k
         CURLE_OK : CURLE_SEND_FAIL_REWIND;
1589
163k
}
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
6.91M
{
1595
6.91M
  size_t size = 0;
1596
1597
8.86M
  for(; s; s = s->next)
1598
1.95M
    if(!skip || !match_header(s, skip, skiplen))
1599
1.94M
      size += strlen(s->data) + overhead;
1600
6.91M
  return size;
1601
6.91M
}
1602
1603
/* Get/compute multipart size. */
1604
static curl_off_t multipart_size(curl_mime *mime)
1605
190k
{
1606
190k
  curl_off_t size;
1607
190k
  curl_off_t boundarysize;
1608
190k
  curl_mimepart *part;
1609
1610
190k
  if(!mime)
1611
0
    return 0;           /* Not present -> empty. */
1612
1613
190k
  boundarysize = 4 + MIME_BOUNDARY_LEN + 2;
1614
190k
  size = boundarysize;  /* Final boundary - CRLF after headers. */
1615
1616
3.67M
  for(part = mime->firstpart; part; part = part->nextpart) {
1617
3.48M
    curl_off_t sz = mime_size(part);
1618
1619
3.48M
    if(sz < 0)
1620
29.9k
      size = sz;
1621
1622
3.48M
    if(size >= 0)
1623
3.43M
      size += boundarysize + sz;
1624
3.48M
  }
1625
1626
190k
  return size;
1627
190k
}
1628
1629
/* Get/compute mime size. */
1630
static curl_off_t mime_size(curl_mimepart *part)
1631
3.59M
{
1632
3.59M
  curl_off_t size;
1633
1634
3.59M
  if(part->kind == MIMEKIND_MULTIPART)
1635
190k
    part->datasize = multipart_size(part->arg);
1636
1637
3.59M
  size = part->datasize;
1638
1639
3.59M
  if(part->encoder)
1640
157k
    size = part->encoder->sizefunc(part);
1641
1642
3.59M
  if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
1643
    /* Compute total part size. */
1644
3.45M
    size += slist_size(part->curlheaders, 2, NULL, 0);
1645
3.45M
    size += slist_size(part->userheaders, 2, STRCONST("Content-Type"));
1646
3.45M
    size += 2;    /* CRLF after headers. */
1647
3.45M
  }
1648
3.59M
  return size;
1649
3.59M
}
1650
1651
/* Add a header. */
1652
/* VARARGS2 */
1653
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
1654
2.04M
{
1655
2.04M
  struct curl_slist *hdr = NULL;
1656
2.04M
  char *s = NULL;
1657
2.04M
  va_list ap;
1658
1659
2.04M
  va_start(ap, fmt);
1660
2.04M
  s = curl_mvaprintf(fmt, ap);
1661
2.04M
  va_end(ap);
1662
1663
2.04M
  if(s) {
1664
2.04M
    hdr = Curl_slist_append_nodup(*slp, s);
1665
2.04M
    if(hdr)
1666
2.04M
      *slp = hdr;
1667
46
    else
1668
46
      curlx_free(s);
1669
2.04M
  }
1670
1671
2.04M
  return hdr ? CURLE_OK : CURLE_OUT_OF_MEMORY;
1672
2.04M
}
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
261k
{
1678
261k
  return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
1679
261k
                              boundary ? "; boundary=" : "",
1680
261k
                              boundary ? boundary : "");
1681
261k
}
1682
1683
const char *Curl_mime_contenttype(const char *filename)
1684
3.35M
{
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
3.35M
  struct ContentType {
1690
3.35M
    const char *extension;
1691
3.35M
    const char *type;
1692
3.35M
  };
1693
3.35M
  static const struct ContentType ctts[] = {
1694
3.35M
    { ".gif",  "image/gif" },
1695
3.35M
    { ".jpg",  "image/jpeg" },
1696
3.35M
    { ".jpeg", "image/jpeg" },
1697
3.35M
    { ".png",  "image/png" },
1698
3.35M
    { ".svg",  "image/svg+xml" },
1699
3.35M
    { ".txt",  "text/plain" },
1700
3.35M
    { ".htm",  "text/html" },
1701
3.35M
    { ".html", "text/html" },
1702
3.35M
    { ".pdf",  "application/pdf" },
1703
3.35M
    { ".xml",  "application/xml" }
1704
3.35M
  };
1705
1706
3.35M
  if(filename) {
1707
51.3k
    size_t len1 = strlen(filename);
1708
51.3k
    const char *nameend = filename + len1;
1709
51.3k
    unsigned int i;
1710
1711
551k
    for(i = 0; i < CURL_ARRAYSIZE(ctts); i++) {
1712
503k
      size_t len2 = strlen(ctts[i].extension);
1713
1714
503k
      if(len1 >= len2 && curl_strequal(nameend - len2, ctts[i].extension))
1715
3.42k
        return ctts[i].type;
1716
503k
    }
1717
51.3k
  }
1718
3.35M
  return NULL;
1719
3.35M
}
1720
1721
static bool content_type_match(const char *contenttype,
1722
                               const char *target, size_t len)
1723
194k
{
1724
194k
  if(contenttype && curl_strnequal(contenttype, target, len))
1725
105k
    switch(contenttype[len]) {
1726
105k
    case '\0':
1727
105k
    case '\t':
1728
105k
    case '\r':
1729
105k
    case '\n':
1730
105k
    case ' ':
1731
105k
    case ';':
1732
105k
      return TRUE;
1733
105k
    }
1734
89.0k
  return FALSE;
1735
194k
}
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
3.61M
{
1743
3.61M
  if(!disposition &&
1744
2.10M
     (part->filename || part->name ||
1745
1.98M
      (contenttype && !curl_strnequal(contenttype, "multipart/", 10))))
1746
134k
    disposition = DISPOSITION_DEFAULT;
1747
1748
3.61M
  if(disposition && curl_strequal(disposition, "attachment") &&
1749
134k
     !part->name && !part->filename)
1750
19.5k
    disposition = NULL;
1751
1752
3.61M
  if(disposition) {
1753
1.62M
    CURLcode result = CURLE_OK;
1754
1.62M
    char *name = NULL;
1755
1.62M
    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
1.62M
    bool backslash = (strategy == MIMESTRATEGY_MAIL) ||
1761
1.60M
                     (data && data->set.mime_formescape);
1762
1.62M
    if(backslash &&
1763
41.5k
       ((part->name && part->name[strcspn(part->name, "\r\n")]) ||
1764
41.5k
        (part->filename && part->filename[strcspn(part->filename, "\r\n")])))
1765
95
      return CURLE_BAD_FUNCTION_ARGUMENT;
1766
1767
1.62M
    if(part->name) {
1768
187k
      name = escape_string(data, part->name, strategy);
1769
187k
      if(!name)
1770
16
        return CURLE_OUT_OF_MEMORY;
1771
187k
    }
1772
1.62M
    if(part->filename) {
1773
102k
      filename = escape_string(data, part->filename, strategy);
1774
102k
      if(!filename)
1775
20
        result = CURLE_OUT_OF_MEMORY;
1776
102k
    }
1777
1.62M
    if(!result)
1778
1.62M
      result = Curl_mime_add_header(&part->curlheaders,
1779
1.62M
                                    "Content-Disposition: %s%s%s%s%s%s%s",
1780
1.62M
                                    disposition,
1781
1.62M
                                    name ? "; name=\"" : "",
1782
1.62M
                                    name ? name : "",
1783
1.62M
                                    name ? "\"" : "",
1784
1.62M
                                    filename ? "; filename=\"" : "",
1785
1.62M
                                    filename ? filename : "",
1786
1.62M
                                    filename ? "\"" : "");
1787
1.62M
    curlx_safefree(name);
1788
1.62M
    curlx_safefree(filename);
1789
1.62M
    if(result)
1790
45
      return result;
1791
1.62M
  }
1792
3.61M
  return CURLE_OK;
1793
3.61M
}
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
3.61M
{
1802
3.61M
  curl_mime *mime = NULL;
1803
3.61M
  const char *boundary = NULL;
1804
3.61M
  char *customct;
1805
3.61M
  const char *cte = NULL;
1806
3.61M
  CURLcode result = CURLE_OK;
1807
1808
3.61M
  if(++call_depth > MAX_MIME_LEVELS)
1809
0
    return CURLE_TOO_LARGE;
1810
1811
  /* Get rid of previously prepared headers. */
1812
3.61M
  curl_slist_free_all(part->curlheaders);
1813
3.61M
  part->curlheaders = NULL;
1814
1815
  /* Be sure we will not access old headers later. */
1816
3.61M
  if(part->state.state == MIMESTATE_CURLHEADERS)
1817
42
    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
1818
1819
  /* Check if content type is specified. */
1820
3.61M
  customct = part->mimetype;
1821
3.61M
  if(!customct)
1822
3.52M
    customct = search_header(part->userheaders, STRCONST("Content-Type"));
1823
3.61M
  if(customct)
1824
90.3k
    contenttype = customct;
1825
1826
  /* If content type is not specified, try to determine it. */
1827
3.61M
  if(!contenttype) {
1828
3.42M
    switch(part->kind) {
1829
63.8k
    case MIMEKIND_MULTIPART:
1830
63.8k
      contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
1831
63.8k
      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
3.35M
    default:
1840
3.35M
      contenttype = Curl_mime_contenttype(part->filename);
1841
3.35M
      break;
1842
3.42M
    }
1843
3.42M
  }
1844
1845
3.61M
  if(part->kind == MIMEKIND_MULTIPART) {
1846
190k
    mime = (curl_mime *)part->arg;
1847
190k
    if(mime)
1848
190k
      boundary = mime->boundary;
1849
190k
  }
1850
3.42M
  else if(contenttype && !customct &&
1851
3.42k
          content_type_match(contenttype, STRCONST("text/plain")) &&
1852
1.24k
          (strategy == MIMESTRATEGY_MAIL || !part->filename))
1853
0
    contenttype = NULL;
1854
1855
  /* Issue content-disposition header only if not already set by caller. */
1856
3.61M
  if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
1857
3.61M
    result = add_content_disposition(data, part, disposition,
1858
3.61M
                                     contenttype, strategy);
1859
3.61M
    if(result)
1860
156
      return result;
1861
3.61M
  }
1862
1863
  /* Issue Content-Type header. */
1864
3.61M
  if(contenttype) {
1865
261k
    result = add_content_type(&part->curlheaders, contenttype, boundary);
1866
261k
    if(result)
1867
45
      return result;
1868
261k
  }
1869
1870
  /* Content-Transfer-Encoding header. */
1871
3.61M
  if(!search_header(part->userheaders,
1872
3.61M
                    STRCONST("Content-Transfer-Encoding"))) {
1873
3.61M
    if(part->encoder)
1874
157k
      cte = part->encoder->name;
1875
3.45M
    else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
1876
1.58k
            part->kind != MIMEKIND_MULTIPART)
1877
0
      cte = "8bit";
1878
3.61M
    if(cte) {
1879
157k
      result = Curl_mime_add_header(&part->curlheaders,
1880
157k
                                    "Content-Transfer-Encoding: %s", cte);
1881
157k
      if(result)
1882
22
        return result;
1883
157k
    }
1884
3.61M
  }
1885
1886
  /* If we were reading curl-generated headers, restart with new ones (this
1887
     should not occur). */
1888
3.61M
  if(part->state.state == MIMESTATE_CURLHEADERS)
1889
42
    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
1890
1891
  /* Process subparts. */
1892
3.61M
  if(part->kind == MIMEKIND_MULTIPART && mime) {
1893
190k
    curl_mimepart *subpart;
1894
1895
190k
    disposition = NULL;
1896
190k
    if(content_type_match(contenttype, STRCONST("multipart/form-data")))
1897
104k
      disposition = "form-data";
1898
3.69M
    for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
1899
3.50M
      result = mime_prepare_headers(data, subpart, NULL,
1900
3.50M
                                    disposition, strategy, call_depth);
1901
3.50M
      if(result)
1902
234
        return result;
1903
3.50M
    }
1904
190k
  }
1905
3.61M
  return result;
1906
3.61M
}
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
107k
{
1914
107k
  return mime_prepare_headers(data, part, contenttype, disposition,
1915
107k
                              strategy, 0);
1916
107k
}
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
107k
{
1951
107k
  struct cr_mime_ctx *ctx = reader->ctx;
1952
107k
  (void)data;
1953
107k
  ctx->total_len = -1;
1954
107k
  ctx->read_len = 0;
1955
107k
  Curl_bufq_init2(&ctx->tmpbuf, 1024, 1, BUFQ_OPT_NO_SPARES);
1956
107k
  return CURLE_OK;
1957
107k
}
1958
1959
static void cr_mime_close(struct Curl_easy *data,
1960
                          struct Curl_creader *reader)
1961
107k
{
1962
107k
  struct cr_mime_ctx *ctx = reader->ctx;
1963
107k
  (void)data;
1964
107k
  Curl_bufq_free(&ctx->tmpbuf);
1965
107k
}
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
146k
{
1973
146k
  struct cr_mime_ctx *ctx = reader->ctx;
1974
146k
  CURLcode result = CURLE_OK;
1975
146k
  size_t nread;
1976
146k
  char tmp[256];
1977
1978
  /* Once we have errored, we will return the same error forever */
1979
146k
  if(ctx->errored) {
1980
8.14k
    CURL_TRC_READ(data, "cr_mime_read(len=%zu) is errored -> %d, eos=0",
1981
8.14k
                  blen, (int)ctx->error_result);
1982
8.14k
    *pnread = 0;
1983
8.14k
    *peos = FALSE;
1984
8.14k
    return ctx->error_result;
1985
8.14k
  }
1986
137k
  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
137k
  if(ctx->total_len >= 0) {
1994
101k
    curl_off_t remain = ctx->total_len - ctx->read_len;
1995
101k
    if(remain <= 0)
1996
0
      blen = 0;
1997
101k
    else if(remain < (curl_off_t)blen)
1998
83.6k
      blen = (size_t)remain;
1999
101k
  }
2000
2001
137k
  if(!Curl_bufq_is_empty(&ctx->tmpbuf)) {
2002
674
    result = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen, &nread);
2003
674
    if(result) {
2004
0
      ctx->errored = TRUE;
2005
0
      ctx->error_result = result;
2006
0
      return result;
2007
0
    }
2008
674
  }
2009
137k
  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
2.85k
    CURL_TRC_READ(data, "cr_mime_read(len=%zu), small read, using tmp", blen);
2015
2.85k
    nread = Curl_mime_read(tmp, 1, sizeof(tmp), ctx->part);
2016
2.85k
    if(nread <= sizeof(tmp)) {
2017
2.83k
      size_t n;
2018
2.83k
      result = Curl_bufq_write(&ctx->tmpbuf, (unsigned char *)tmp, nread, &n);
2019
2.83k
      if(result) {
2020
10
        ctx->errored = TRUE;
2021
10
        ctx->error_result = result;
2022
10
        return result;
2023
10
      }
2024
      /* stored it, read again */
2025
2.82k
      result = Curl_bufq_cread(&ctx->tmpbuf, buf, blen, &nread);
2026
2.82k
      if(result) {
2027
325
        ctx->errored = TRUE;
2028
325
        ctx->error_result = result;
2029
325
        return result;
2030
325
      }
2031
2.82k
    }
2032
2.85k
  }
2033
134k
  else
2034
134k
    nread = Curl_mime_read(buf, 1, blen, ctx->part);
2035
2036
137k
  CURL_TRC_READ(data, "cr_mime_read(len=%zu), mime_read() -> %zu",
2037
137k
                blen, nread);
2038
2039
137k
  switch(nread) {
2040
8.19k
  case 0:
2041
8.19k
    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
8.19k
    *pnread = 0;
2048
8.19k
    *peos = TRUE;
2049
8.19k
    ctx->seen_eos = TRUE;
2050
8.19k
    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
545
  case READ_ERROR:
2071
545
    failf(data, "read error getting mime data");
2072
545
    *pnread = 0;
2073
545
    *peos = FALSE;
2074
545
    ctx->errored = TRUE;
2075
545
    ctx->error_result = CURLE_READ_ERROR;
2076
545
    result = CURLE_READ_ERROR;
2077
545
    break;
2078
2079
128k
  default:
2080
128k
    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
128k
    ctx->read_len += nread;
2090
128k
    if(ctx->total_len >= 0)
2091
100k
      ctx->seen_eos = (ctx->read_len >= ctx->total_len);
2092
128k
    *pnread = nread;
2093
128k
    *peos = (bool)ctx->seen_eos;
2094
128k
    break;
2095
137k
  }
2096
2097
137k
  CURL_TRC_READ(data, "cr_mime_read(len=%zu, total=%" FMT_OFF_T
2098
137k
                ", read=%" FMT_OFF_T ") -> %d, %zu, %d", blen,
2099
137k
                ctx->total_len, ctx->read_len, (int)result, *pnread, *peos);
2100
137k
  return result;
2101
137k
}
2102
2103
static bool cr_mime_needs_rewind(struct Curl_easy *data,
2104
                                 struct Curl_creader *reader)
2105
46.4k
{
2106
46.4k
  struct cr_mime_ctx *ctx = reader->ctx;
2107
46.4k
  (void)data;
2108
46.4k
  return ctx->read_len > 0;
2109
46.4k
}
2110
2111
static curl_off_t cr_mime_total_length(struct Curl_easy *data,
2112
                                       struct Curl_creader *reader)
2113
580k
{
2114
580k
  struct cr_mime_ctx *ctx = reader->ctx;
2115
580k
  (void)data;
2116
580k
  return ctx->total_len;
2117
580k
}
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
55.9k
{
2165
55.9k
  struct cr_mime_ctx *ctx = reader->ctx;
2166
55.9k
  switch(opcode) {
2167
55.9k
  case CURL_CRCNTRL_REWIND: {
2168
55.9k
    CURLcode result = mime_rewind(ctx->part);
2169
55.9k
    if(result)
2170
1.06k
      failf(data, "Cannot rewind mime/post data");
2171
55.9k
    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
55.9k
  }
2182
0
  return CURLE_OK;
2183
55.9k
}
2184
2185
static bool cr_mime_is_paused(struct Curl_easy *data,
2186
                              struct Curl_creader *reader)
2187
3.85k
{
2188
3.85k
  struct cr_mime_ctx *ctx = reader->ctx;
2189
3.85k
  (void)data;
2190
3.85k
  return ctx->part && ctx->part->lastreadstatus == CURL_READFUNC_PAUSE;
2191
3.85k
}
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
107k
{
2209
107k
  struct Curl_creader *r;
2210
107k
  struct cr_mime_ctx *ctx;
2211
107k
  CURLcode result;
2212
2213
107k
  result = Curl_creader_create(&r, data, &cr_mime, CURL_CR_CLIENT);
2214
107k
  if(result)
2215
17
    return result;
2216
107k
  ctx = r->ctx;
2217
107k
  ctx->part = part;
2218
  /* Make sure we will read the entire mime structure. */
2219
107k
  result = mime_rewind(ctx->part);
2220
107k
  if(result) {
2221
283
    Curl_creader_free(data, r);
2222
283
    return result;
2223
283
  }
2224
106k
  ctx->total_len = mime_size(ctx->part);
2225
2226
106k
  return Curl_creader_set(data, r);
2227
107k
}
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 */