Coverage Report

Created: 2026-08-13 07:42

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