Coverage Report

Created: 2026-10-22 06:49

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