Coverage Report

Created: 2026-10-15 06:19

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