Coverage Report

Created: 2026-09-04 07:17

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
1.51M
#define MAX_MIME_LEVELS 40 /* avoid deep nesting */
48
49
1.00M
#define READ_ERROR   ((size_t)-1)
50
504k
#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
6.15M
{
191
6.15M
  state->state = tok;
192
6.15M
  state->ptr = ptr;
193
6.15M
  state->offset = 0;
194
6.15M
}
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
3.35k
{
200
3.35k
  CURLcode result;
201
3.35k
  struct dynbuf db;
202
3.35k
  const char * const *table;
203
3.35k
  const char * const *p;
204
  /* replace first character by rest of string. */
205
3.35k
  static const char * const mimetable[] = {
206
3.35k
    "\\\\\\",
207
3.35k
    "\"\\\"",
208
3.35k
    NULL
209
3.35k
  };
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
3.35k
  static const char * const formtable[] = {
217
3.35k
    "\"%22",
218
3.35k
    "\r%0D",
219
3.35k
    "\n%0A",
220
3.35k
    NULL
221
3.35k
  };
222
223
3.35k
  table = formtable;
224
  /* data can be NULL when this function is called indirectly from
225
     curl_formget(). */
226
3.35k
  if(strategy == MIMESTRATEGY_MAIL || (data && data->set.mime_formescape))
227
3.35k
    table = mimetable;
228
229
3.35k
  curlx_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
230
231
4.66k
  for(result = curlx_dyn_addn(&db, STRCONST("")); !result && *src; src++) {
232
3.47k
    for(p = table; *p && **p != *src; p++)
233
2.16k
      ;
234
235
1.30k
    if(*p)
236
230
      result = curlx_dyn_add(&db, *p + 1);
237
1.07k
    else
238
1.07k
      result = curlx_dyn_addn(&db, src, 1);
239
1.30k
  }
240
241
3.35k
  return curlx_dyn_ptr(&db);
242
3.35k
}
243
244
/* Check if header matches. */
245
static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
246
8.22k
{
247
8.22k
  char *value = NULL;
248
249
8.22k
  if(curl_strnequal(hdr->data, lbl, len) && hdr->data[len] == ':')
250
173
    for(value = hdr->data + len + 1; *value == ' '; value++)
251
16
      ;
252
8.22k
  return value;
253
8.22k
}
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
2.36M
{
259
2.36M
  char *value = NULL;
260
261
2.37M
  for(; !value && hdrlist; hdrlist = hdrlist->next)
262
4.19k
    value = match_header(hdrlist, hdr, len);
263
264
2.36M
  return value;
265
2.36M
}
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
1.31M
{
285
1.31M
  p->pos = 0;
286
1.31M
  p->bufbeg = 0;
287
1.31M
  p->bufend = 0;
288
1.31M
}
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
658
{
577
658
  curl_mimepart *part = (curl_mimepart *)instream;
578
658
  size_t sz = curlx_sotouz(part->datasize - part->state.offset);
579
658
  (void)size;  /* Always 1 */
580
581
658
  if(!nitems)
582
0
    return STOP_FILLING;
583
584
658
  if(sz > nitems)
585
8
    sz = nitems;
586
587
658
  if(sz)
588
658
    memcpy(buffer, part->data + curlx_sotouz(part->state.offset), sz);
589
590
658
  return sz;
591
658
}
592
593
static int mime_mem_seek(void *instream, curl_off_t offset, int whence)
594
0
{
595
0
  curl_mimepart *part = (curl_mimepart *)instream;
596
597
0
  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
0
  }
605
606
0
  if(offset < 0 || offset > part->datasize)
607
0
    return CURL_SEEKFUNC_FAIL;
608
609
0
  part->state.offset = offset;
610
0
  return CURL_SEEKFUNC_OK;
611
0
}
612
613
static void mime_mem_free(void *ptr)
614
1.65k
{
615
1.65k
  curlx_safefree(((curl_mimepart *)ptr)->data);
616
1.65k
}
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
3.53M
{
678
3.53M
  size_t sz;
679
3.53M
  size_t offset = curlx_sotouz(state->offset);
680
681
3.53M
  if(numbytes > offset) {
682
1.51M
    sz = numbytes - offset;
683
1.51M
    bytes += offset;
684
1.51M
  }
685
2.02M
  else {
686
2.02M
    sz = offset - numbytes;
687
2.02M
    if(sz >= traillen)
688
1.51M
      return 0;
689
507k
    bytes = trail + sz;
690
507k
    sz = traillen - sz;
691
507k
  }
692
693
2.02M
  if(sz > bufsize)
694
345
    sz = bufsize;
695
696
2.02M
  memcpy(buffer, bytes, sz);
697
2.02M
  state->offset += sz;
698
2.02M
  return sz;
699
3.53M
}
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
505k
{
707
505k
  size_t sz = 0;
708
709
505k
  if(++call_depth > MAX_MIME_LEVELS)
710
0
    return READ_ERROR;
711
712
505k
  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
505k
  default:
719
505k
    break;
720
505k
  }
721
722
  /* If we can determine we are at end of part data, spare a read. */
723
505k
  if(part->datasize != (curl_off_t)-1 &&
724
505k
     part->state.offset >= part->datasize) {
725
    /* sz is already zero. */
726
504k
  }
727
1.29k
  else {
728
1.29k
    switch(part->kind) {
729
640
    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
640
      sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread,
735
640
                              call_depth);
736
640
      break;
737
0
    case MIMEKIND_FILE:
738
0
      if(part->fp && feof(part->fp))
739
0
        break;  /* At EOF. */
740
0
      FALLTHROUGH();
741
658
    default:
742
658
      if(part->readfunc) {
743
658
        if(!(part->flags & MIME_FAST_READ)) {
744
0
          if(*hasread)
745
0
            return STOP_FILLING;
746
0
          *hasread = TRUE;
747
0
        }
748
658
        sz = part->readfunc(buffer, 1, bufsize, part->arg);
749
658
      }
750
658
      break;
751
1.29k
    }
752
1.29k
  }
753
754
505k
  switch(sz) {
755
0
  case STOP_FILLING:
756
0
    break;
757
504k
  case 0:
758
504k
  case CURL_READFUNC_ABORT:
759
504k
  case CURL_READFUNC_PAUSE:
760
504k
  case READ_ERROR:
761
504k
    part->lastreadstatus = sz;
762
504k
    break;
763
1.29k
  default:
764
1.29k
    part->state.offset += sz;
765
1.29k
    part->lastreadstatus = sz;
766
1.29k
    break;
767
505k
  }
768
769
505k
  return sz;
770
505k
}
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
1.00M
{
841
1.00M
  size_t cursize = 0;
842
843
1.00M
  if(++call_depth > MAX_MIME_LEVELS)
844
0
    return READ_ERROR;
845
846
  /* Readback from part. */
847
4.04M
  while(bufsize) {
848
4.04M
    size_t sz = 0;
849
4.04M
    struct curl_slist *hdr = (struct curl_slist *)part->state.ptr;
850
4.04M
    switch(part->state.state) {
851
504k
    case MIMESTATE_BEGIN:
852
504k
      mimesetstate(&part->state,
853
504k
                   (part->flags & MIME_BODY_ONLY) ?
854
504k
                   MIMESTATE_BODY : MIMESTATE_CURLHEADERS,
855
504k
                   part->curlheaders);
856
504k
      break;
857
507k
    case MIMESTATE_USERHEADERS:
858
507k
      if(!hdr) {
859
504k
        mimesetstate(&part->state, MIMESTATE_EOH, NULL);
860
504k
        break;
861
504k
      }
862
2.61k
      if(match_header(hdr, "Content-Type", 12)) {
863
70
        mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next);
864
70
        break;
865
70
      }
866
2.54k
      FALLTHROUGH();
867
512k
    case MIMESTATE_CURLHEADERS:
868
512k
      if(!hdr)
869
504k
        mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
870
8.41k
      else {
871
8.41k
        sz = readback_bytes(&part->state, buffer, bufsize,
872
8.41k
                            hdr->data, strlen(hdr->data), STRCONST("\r\n"));
873
8.41k
        if(!sz)
874
3.10k
          mimesetstate(&part->state, part->state.state, hdr->next);
875
8.41k
      }
876
512k
      break;
877
1.00M
    case MIMESTATE_EOH:
878
1.00M
      sz = readback_bytes(&part->state, buffer, bufsize, STRCONST("\r\n"),
879
1.00M
                          STRCONST(""));
880
1.00M
      if(!sz)
881
504k
        mimesetstate(&part->state, MIMESTATE_BODY, NULL);
882
1.00M
      break;
883
504k
    case MIMESTATE_BODY:
884
504k
      cleanup_encoder_state(&part->encstate);
885
504k
      mimesetstate(&part->state, MIMESTATE_CONTENT, NULL);
886
504k
      break;
887
505k
    case MIMESTATE_CONTENT:
888
505k
      if(part->encoder)
889
0
        sz = read_encoded_part_content(part, buffer, bufsize, hasread,
890
0
                                       call_depth);
891
505k
      else
892
505k
        sz = read_part_content(part, buffer, bufsize, hasread, call_depth);
893
505k
      switch(sz) {
894
504k
      case 0:
895
504k
        mimesetstate(&part->state, MIMESTATE_END, NULL);
896
        /* Try sparing open file descriptors. */
897
504k
        if(part->kind == MIMEKIND_FILE && part->fp) {
898
0
          curlx_fclose(part->fp);
899
0
          part->fp = NULL;
900
0
        }
901
504k
        FALLTHROUGH();
902
504k
      case CURL_READFUNC_ABORT:
903
504k
      case CURL_READFUNC_PAUSE:
904
504k
      case READ_ERROR:
905
504k
      case STOP_FILLING:
906
504k
        return cursize ? cursize : sz;
907
505k
      }
908
1.29k
      break;
909
504k
    case MIMESTATE_END:
910
504k
      return cursize;
911
0
    default:
912
0
      break;    /* Other values not in part state. */
913
4.04M
    }
914
915
    /* Bump buffer and counters according to read size. */
916
3.03M
    cursize += sz;
917
3.03M
    buffer += sz;
918
3.03M
    bufsize -= sz;
919
3.03M
  }
920
921
682
  return cursize;
922
1.00M
}
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
640
{
929
640
  curl_mime *mime = (curl_mime *)instream;
930
640
  size_t cursize = 0;
931
640
  (void)size;  /* Always 1 */
932
933
640
  if(++call_depth > MAX_MIME_LEVELS)
934
0
    return READ_ERROR;
935
936
3.53M
  while(nitems) {
937
3.53M
    size_t sz = 0;
938
3.53M
    curl_mimepart *part = mime->state.ptr;
939
3.53M
    switch(mime->state.state) {
940
352
    case MIMESTATE_BEGIN:
941
352
    case MIMESTATE_BODY:
942
352
      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
352
      mime->state.offset += 2;
947
352
      break;
948
1.00M
    case MIMESTATE_BOUNDARY1:
949
1.00M
      sz = readback_bytes(&mime->state, buffer, nitems, STRCONST("\r\n--"),
950
1.00M
                          STRCONST(""));
951
1.00M
      if(!sz)
952
504k
        mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part);
953
1.00M
      break;
954
1.51M
    case MIMESTATE_BOUNDARY2:
955
1.51M
      if(part)
956
1.51M
        sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
957
1.51M
                            MIME_BOUNDARY_LEN, STRCONST("\r\n"));
958
648
      else
959
648
        sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
960
648
                            MIME_BOUNDARY_LEN, STRCONST("--\r\n"));
961
1.51M
      if(!sz) {
962
504k
        mimesetstate(&mime->state, MIMESTATE_CONTENT, part);
963
504k
      }
964
1.51M
      break;
965
1.00M
    case MIMESTATE_CONTENT:
966
1.00M
      if(!part) {
967
5
        mimesetstate(&mime->state, MIMESTATE_END, NULL);
968
5
        break;
969
5
      }
970
1.00M
      sz = readback_part(part, buffer, nitems, hasread, call_depth);
971
1.00M
      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
504k
      case 0:
978
504k
        mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart);
979
504k
        break;
980
1.00M
      }
981
1.00M
      break;
982
1.00M
    case MIMESTATE_END:
983
5
      return cursize;
984
0
    default:
985
0
      break;    /* other values not used in mime state. */
986
3.53M
    }
987
988
    /* Bump buffer and counters according to read size. */
989
3.53M
    cursize += sz;
990
3.53M
    buffer += sz;
991
3.53M
    nitems -= sz;
992
3.53M
  }
993
994
635
  return cursize;
995
640
}
996
997
static int mime_part_rewind(curl_mimepart *part)
998
477
{
999
477
  int res = CURL_SEEKFUNC_OK;
1000
477
  enum mimestate targetstate = MIMESTATE_BEGIN;
1001
1002
477
  if(part->flags & MIME_BODY_ONLY)
1003
0
    targetstate = MIMESTATE_BODY;
1004
477
  cleanup_encoder_state(&part->encstate);
1005
477
  if(part->state.state > targetstate) {
1006
0
    res = CURL_SEEKFUNC_CANTSEEK;
1007
0
    if(part->seekfunc) {
1008
0
      res = part->seekfunc(part->arg, (curl_off_t)0, SEEK_SET);
1009
0
      switch(res) {
1010
0
      case CURL_SEEKFUNC_OK:
1011
0
      case CURL_SEEKFUNC_FAIL:
1012
0
      case CURL_SEEKFUNC_CANTSEEK:
1013
0
        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
0
      }
1021
0
    }
1022
0
  }
1023
1024
477
  if(res == CURL_SEEKFUNC_OK)
1025
477
    mimesetstate(&part->state, targetstate, NULL);
1026
1027
477
  part->lastreadstatus = 1; /* Successful read status. */
1028
477
  return res;
1029
477
}
1030
1031
static int mime_subparts_seek(void *instream, curl_off_t offset, int whence)
1032
757
{
1033
757
  curl_mime *mime = (curl_mime *)instream;
1034
757
  curl_mimepart *part;
1035
757
  int rc = CURL_SEEKFUNC_OK;
1036
1037
757
  if(whence != SEEK_SET || offset)
1038
0
    return CURL_SEEKFUNC_CANTSEEK;    /* Only support full rewind. */
1039
1040
757
  if(mime->state.state == MIMESTATE_BEGIN)
1041
757
    return CURL_SEEKFUNC_OK;           /* Already rewound. */
1042
1043
0
  for(part = mime->firstpart; part; part = part->nextpart) {
1044
0
    int res = mime_part_rewind(part);
1045
0
    if(res != CURL_SEEKFUNC_OK)
1046
0
      rc = res;
1047
0
  }
1048
1049
0
  if(rc == CURL_SEEKFUNC_OK)
1050
0
    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1051
1052
0
  return rc;
1053
757
}
1054
1055
/* Release part content. */
1056
static void cleanup_part_content(curl_mimepart *part)
1057
810k
{
1058
810k
  if(part->freefunc)
1059
1.65k
    part->freefunc(part->arg);
1060
1061
810k
  part->readfunc = NULL;
1062
810k
  part->seekfunc = NULL;
1063
810k
  part->freefunc = NULL;
1064
810k
  part->arg = (void *)part;           /* Defaults to part itself. */
1065
810k
  part->data = NULL;
1066
810k
  part->fp = NULL;
1067
810k
  part->datasize = (curl_off_t)0;     /* No size yet. */
1068
810k
  cleanup_encoder_state(&part->encstate);
1069
810k
  part->kind = MIMEKIND_NONE;
1070
810k
  part->flags &= ~(unsigned int)MIME_FAST_READ;
1071
810k
  part->lastreadstatus = 1; /* Successful read status. */
1072
810k
  part->state.state = MIMESTATE_BEGIN;
1073
810k
}
1074
1075
static void mime_subparts_free(void *ptr)
1076
0
{
1077
0
  curl_mime *mime = (curl_mime *)ptr;
1078
1079
0
  if(mime && mime->parent) {
1080
0
    mime->parent->freefunc = NULL;  /* Be sure we will not be called again. */
1081
0
    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
1082
0
  }
1083
0
  curl_mime_free(mime);
1084
0
}
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
775
{
1089
775
  curl_mime *mime = (curl_mime *)ptr;
1090
1091
775
  if(mime && mime->parent) {
1092
757
    mime->parent->freefunc = NULL;  /* Be sure we will not be called again. */
1093
757
    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
1094
757
    mime->parent = NULL;
1095
757
  }
1096
775
}
1097
1098
void Curl_mime_cleanpart(curl_mimepart *part)
1099
858k
{
1100
858k
  if(part) {
1101
807k
    cleanup_part_content(part);
1102
807k
    curl_slist_free_all(part->curlheaders);
1103
807k
    if(part->flags & MIME_USERHEADERS_OWNER)
1104
0
      curl_slist_free_all(part->userheaders);
1105
807k
    curlx_safefree(part->mimetype);
1106
807k
    curlx_safefree(part->name);
1107
807k
    curlx_safefree(part->filename);
1108
807k
    Curl_mime_initpart(part);
1109
807k
  }
1110
858k
}
1111
1112
/* Recursively delete a mime handle and its parts. */
1113
void curl_mime_free(curl_mime *mime)
1114
775
{
1115
775
  curl_mimepart *part;
1116
1117
775
  if(mime) {
1118
775
    mime_subparts_unbind(mime);  /* Be sure it is not referenced anymore. */
1119
807k
    while(mime->firstpart) {
1120
806k
      part = mime->firstpart;
1121
806k
      mime->firstpart = part->nextpart;
1122
806k
      Curl_mime_cleanpart(part);
1123
806k
      curlx_free(part);
1124
806k
    }
1125
775
    curlx_free(mime);
1126
775
  }
1127
775
}
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
775
{
1214
775
  curl_mime *mime = curlx_malloc(sizeof(*mime));
1215
1216
775
  if(mime) {
1217
775
    mime->parent = NULL;
1218
775
    mime->firstpart = NULL;
1219
775
    mime->lastpart = NULL;
1220
1221
775
    memset(mime->boundary, '-', MIME_BOUNDARY_DASHES);
1222
775
    if(Curl_rand_alnum(easy,
1223
775
                       (unsigned char *)&mime->boundary[MIME_BOUNDARY_DASHES],
1224
775
                       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
775
    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1230
775
  }
1231
1232
775
  return mime;
1233
775
}
1234
1235
/* Initialize a mime part. */
1236
void Curl_mime_initpart(curl_mimepart *part)
1237
1.61M
{
1238
1.61M
  memset(part, 0, sizeof(*part));
1239
1.61M
  part->lastreadstatus = 1; /* Successful read status. */
1240
1.61M
  mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
1241
1.61M
}
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
806k
{
1246
806k
  curl_mimepart *part;
1247
1248
806k
  if(!mime)
1249
0
    return NULL;
1250
1251
806k
  part = curlx_malloc(sizeof(*part));
1252
1253
806k
  if(part) {
1254
806k
    Curl_mime_initpart(part);
1255
806k
    part->parent = mime;
1256
1257
806k
    if(mime->lastpart)
1258
805k
      mime->lastpart->nextpart = part;
1259
775
    else
1260
775
      mime->firstpart = part;
1261
1262
806k
    mime->lastpart = part;
1263
806k
  }
1264
1265
806k
  return part;
1266
806k
}
1267
1268
/* Set mime part name. */
1269
CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1270
4.93k
{
1271
4.93k
  if(!part)
1272
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1273
1274
4.93k
  curlx_safefree(part->name);
1275
1276
4.93k
  if(name) {
1277
4.93k
    part->name = curlx_strdup(name);
1278
4.93k
    if(!part->name)
1279
0
      return CURLE_OUT_OF_MEMORY;
1280
4.93k
  }
1281
1282
4.93k
  return CURLE_OK;
1283
4.93k
}
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
1.65k
{
1305
1.65k
  if(!part)
1306
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1307
1308
1.65k
  cleanup_part_content(part);
1309
1310
1.65k
  if(data) {
1311
1.65k
    if(datasize == CURL_ZERO_TERMINATED)
1312
0
      datasize = strlen(data);
1313
1314
1.65k
    part->data = curlx_memdup0(data, datasize);
1315
1.65k
    if(!part->data)
1316
0
      return CURLE_OUT_OF_MEMORY;
1317
1318
1.65k
    part->datasize = datasize;
1319
1.65k
    part->readfunc = mime_mem_read;
1320
1.65k
    part->seekfunc = mime_mem_seek;
1321
1.65k
    part->freefunc = mime_mem_free;
1322
1.65k
    part->flags |= MIME_FAST_READ;
1323
1.65k
    part->kind = MIMEKIND_DATA;
1324
1.65k
  }
1325
1326
1.65k
  return CURLE_OK;
1327
1.65k
}
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
478
{
1430
478
  if(!part)
1431
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1432
1433
478
  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
478
  part->userheaders = headers;
1439
478
  if(headers && take_ownership)
1440
0
    part->flags |= MIME_USERHEADERS_OWNER;
1441
478
  return CURLE_OK;
1442
478
}
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
757
{
1471
757
  curl_mime *root;
1472
1473
757
  if(!part)
1474
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1475
1476
  /* Accept setting twice the same subparts. */
1477
757
  if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
1478
0
    return CURLE_OK;
1479
1480
757
  cleanup_part_content(part);
1481
1482
757
  if(subparts) {
1483
    /* Should not have been attached already. */
1484
757
    if(subparts->parent)
1485
0
      return CURLE_BAD_FUNCTION_ARGUMENT;
1486
1487
    /* Should not be the part's root. */
1488
757
    root = part->parent;
1489
757
    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
757
    if(mime_subparts_seek(subparts, (curl_off_t)0, SEEK_SET) !=
1503
757
       CURL_SEEKFUNC_OK)
1504
0
      return CURLE_SEND_FAIL_REWIND;
1505
1506
757
    subparts->parent = part;
1507
    /* Subparts are processed internally: no read callback. */
1508
757
    part->seekfunc = mime_subparts_seek;
1509
757
    part->freefunc = take_ownership ? mime_subparts_free :
1510
757
      mime_subparts_unbind;
1511
757
    part->arg = subparts;
1512
757
    part->datasize = -1;
1513
757
    part->kind = MIMEKIND_MULTIPART;
1514
757
  }
1515
1516
757
  return CURLE_OK;
1517
757
}
1518
1519
CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
1520
0
{
1521
0
  return Curl_mime_set_subparts(part, subparts, TRUE);
1522
0
}
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
669
{
1528
669
  curl_mimepart *part = (curl_mimepart *)instream;
1529
669
  size_t ret;
1530
669
  bool hasread;
1531
1532
669
  (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
669
  do {
1537
669
    hasread = FALSE;
1538
669
    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
669
  } while(ret == STOP_FILLING);
1546
1547
669
  return ret;
1548
669
}
1549
1550
/* Rewind mime stream. */
1551
static CURLcode mime_rewind(curl_mimepart *part)
1552
477
{
1553
477
  return mime_part_rewind(part) == CURL_SEEKFUNC_OK ?
1554
477
         CURLE_OK : CURLE_SEND_FAIL_REWIND;
1555
477
}
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
1.57M
{
1561
1.57M
  size_t size = 0;
1562
1563
1.58M
  for(; s; s = s->next)
1564
5.73k
    if(!skip || !match_header(s, skip, skiplen))
1565
5.65k
      size += strlen(s->data) + overhead;
1566
1.57M
  return size;
1567
1.57M
}
1568
1569
/* Get/compute multipart size. */
1570
static curl_off_t multipart_size(curl_mime *mime)
1571
477
{
1572
477
  curl_off_t size;
1573
477
  curl_off_t boundarysize;
1574
477
  curl_mimepart *part;
1575
1576
477
  if(!mime)
1577
0
    return 0;           /* Not present -> empty. */
1578
1579
477
  boundarysize = 4 + MIME_BOUNDARY_LEN + 2;
1580
477
  size = boundarysize;  /* Final boundary - CRLF after headers. */
1581
1582
789k
  for(part = mime->firstpart; part; part = part->nextpart) {
1583
788k
    curl_off_t sz = mime_size(part);
1584
1585
788k
    if(sz < 0)
1586
0
      size = sz;
1587
1588
788k
    if(size >= 0)
1589
788k
      size += boundarysize + sz;
1590
788k
  }
1591
1592
477
  return size;
1593
477
}
1594
1595
/* Get/compute mime size. */
1596
static curl_off_t mime_size(curl_mimepart *part)
1597
789k
{
1598
789k
  curl_off_t size;
1599
1600
789k
  if(part->kind == MIMEKIND_MULTIPART)
1601
477
    part->datasize = multipart_size(part->arg);
1602
1603
789k
  size = part->datasize;
1604
1605
789k
  if(part->encoder)
1606
0
    size = part->encoder->sizefunc(part);
1607
1608
789k
  if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
1609
    /* Compute total part size. */
1610
789k
    size += slist_size(part->curlheaders, 2, NULL, 0);
1611
789k
    size += slist_size(part->userheaders, 2, STRCONST("Content-Type"));
1612
789k
    size += 2;    /* CRLF after headers. */
1613
789k
  }
1614
789k
  return size;
1615
789k
}
1616
1617
/* Add a header. */
1618
/* VARARGS2 */
1619
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
1620
4.31k
{
1621
4.31k
  struct curl_slist *hdr = NULL;
1622
4.31k
  char *s = NULL;
1623
4.31k
  va_list ap;
1624
1625
4.31k
  va_start(ap, fmt);
1626
4.31k
  s = curl_mvaprintf(fmt, ap);
1627
4.31k
  va_end(ap);
1628
1629
4.31k
  if(s) {
1630
4.31k
    hdr = Curl_slist_append_nodup(*slp, s);
1631
4.31k
    if(hdr)
1632
4.31k
      *slp = hdr;
1633
0
    else
1634
0
      curlx_free(s);
1635
4.31k
  }
1636
1637
4.31k
  return hdr ? CURLE_OK : CURLE_OUT_OF_MEMORY;
1638
4.31k
}
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
478
{
1644
478
  return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
1645
478
                              boundary ? "; boundary=" : "",
1646
478
                              boundary ? boundary : "");
1647
478
}
1648
1649
const char *Curl_mime_contenttype(const char *filename)
1650
788k
{
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
788k
  struct ContentType {
1656
788k
    const char *extension;
1657
788k
    const char *type;
1658
788k
  };
1659
788k
  static const struct ContentType ctts[] = {
1660
788k
    { ".gif",  "image/gif" },
1661
788k
    { ".jpg",  "image/jpeg" },
1662
788k
    { ".jpeg", "image/jpeg" },
1663
788k
    { ".png",  "image/png" },
1664
788k
    { ".svg",  "image/svg+xml" },
1665
788k
    { ".txt",  "text/plain" },
1666
788k
    { ".htm",  "text/html" },
1667
788k
    { ".html", "text/html" },
1668
788k
    { ".pdf",  "application/pdf" },
1669
788k
    { ".xml",  "application/xml" }
1670
788k
  };
1671
1672
788k
  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
788k
  return NULL;
1685
788k
}
1686
1687
static bool content_type_match(const char *contenttype,
1688
                               const char *target, size_t len)
1689
478
{
1690
478
  if(contenttype && curl_strnequal(contenttype, target, len))
1691
0
    switch(contenttype[len]) {
1692
0
    case '\0':
1693
0
    case '\t':
1694
0
    case '\r':
1695
0
    case '\n':
1696
0
    case ' ':
1697
0
    case ';':
1698
0
      return TRUE;
1699
0
    }
1700
478
  return FALSE;
1701
478
}
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
789k
{
1709
789k
  if(!disposition &&
1710
789k
     (part->filename || part->name ||
1711
785k
      (contenttype && !curl_strnequal(contenttype, "multipart/", 10))))
1712
3.37k
    disposition = DISPOSITION_DEFAULT;
1713
1714
789k
  if(disposition && curl_strequal(disposition, "attachment") &&
1715
3.37k
     !part->name && !part->filename)
1716
13
    disposition = NULL;
1717
1718
789k
  if(disposition) {
1719
3.35k
    CURLcode result = CURLE_OK;
1720
3.35k
    char *name = NULL;
1721
3.35k
    char *filename = NULL;
1722
    /* The mail (and legacy mime_formescape) strategy quotes the name and
1723
       filename with a backslash and has no in-band way to represent a CR or
1724
       LF, so one embedded in the value would split the generated header. The
1725
       form strategy percent-encodes CR/LF (see escape_string) and is safe. */
1726
3.35k
    bool backslash = (strategy == MIMESTRATEGY_MAIL) ||
1727
0
                     (data && data->set.mime_formescape);
1728
3.35k
    if(backslash &&
1729
3.35k
       ((part->name && part->name[strcspn(part->name, "\r\n")]) ||
1730
3.35k
        (part->filename && part->filename[strcspn(part->filename, "\r\n")])))
1731
1
      return CURLE_BAD_FUNCTION_ARGUMENT;
1732
1733
3.35k
    if(part->name) {
1734
3.35k
      name = escape_string(data, part->name, strategy);
1735
3.35k
      if(!name)
1736
0
        return CURLE_OUT_OF_MEMORY;
1737
3.35k
    }
1738
3.35k
    if(part->filename) {
1739
0
      filename = escape_string(data, part->filename, strategy);
1740
0
      if(!filename)
1741
0
        result = CURLE_OUT_OF_MEMORY;
1742
0
    }
1743
3.35k
    if(!result)
1744
3.35k
      result = Curl_mime_add_header(&part->curlheaders,
1745
3.35k
                                    "Content-Disposition: %s%s%s%s%s%s%s",
1746
3.35k
                                    disposition,
1747
3.35k
                                    name ? "; name=\"" : "",
1748
3.35k
                                    name ? name : "",
1749
3.35k
                                    name ? "\"" : "",
1750
3.35k
                                    filename ? "; filename=\"" : "",
1751
3.35k
                                    filename ? filename : "",
1752
3.35k
                                    filename ? "\"" : "");
1753
3.35k
    curlx_safefree(name);
1754
3.35k
    curlx_safefree(filename);
1755
3.35k
    if(result)
1756
0
      return result;
1757
3.35k
  }
1758
789k
  return CURLE_OK;
1759
789k
}
1760
1761
CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
1762
                                   curl_mimepart *part,
1763
                                   const char *contenttype,
1764
                                   const char *disposition,
1765
                                   enum mimestrategy strategy)
1766
789k
{
1767
789k
  curl_mime *mime = NULL;
1768
789k
  const char *boundary = NULL;
1769
789k
  char *customct;
1770
789k
  const char *cte = NULL;
1771
789k
  CURLcode result = CURLE_OK;
1772
1773
  /* Get rid of previously prepared headers. */
1774
789k
  curl_slist_free_all(part->curlheaders);
1775
789k
  part->curlheaders = NULL;
1776
1777
  /* Be sure we will not access old headers later. */
1778
789k
  if(part->state.state == MIMESTATE_CURLHEADERS)
1779
0
    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
1780
1781
  /* Check if content type is specified. */
1782
789k
  customct = part->mimetype;
1783
789k
  if(!customct)
1784
789k
    customct = search_header(part->userheaders, STRCONST("Content-Type"));
1785
789k
  if(customct)
1786
13
    contenttype = customct;
1787
1788
  /* If content type is not specified, try to determine it. */
1789
789k
  if(!contenttype) {
1790
788k
    switch(part->kind) {
1791
465
    case MIMEKIND_MULTIPART:
1792
465
      contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
1793
465
      break;
1794
0
    case MIMEKIND_FILE:
1795
0
      contenttype = Curl_mime_contenttype(part->filename);
1796
0
      if(!contenttype)
1797
0
        contenttype = Curl_mime_contenttype(part->data);
1798
0
      if(!contenttype && part->filename)
1799
0
        contenttype = FILE_CONTENTTYPE_DEFAULT;
1800
0
      break;
1801
788k
    default:
1802
788k
      contenttype = Curl_mime_contenttype(part->filename);
1803
788k
      break;
1804
788k
    }
1805
788k
  }
1806
1807
789k
  if(part->kind == MIMEKIND_MULTIPART) {
1808
478
    mime = (curl_mime *)part->arg;
1809
478
    if(mime)
1810
478
      boundary = mime->boundary;
1811
478
  }
1812
788k
  else if(contenttype && !customct &&
1813
0
          content_type_match(contenttype, STRCONST("text/plain")) &&
1814
0
          (strategy == MIMESTRATEGY_MAIL || !part->filename))
1815
0
    contenttype = NULL;
1816
1817
  /* Issue content-disposition header only if not already set by caller. */
1818
789k
  if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
1819
789k
    result = add_content_disposition(data, part, disposition,
1820
789k
                                     contenttype, strategy);
1821
789k
    if(result)
1822
1
      return result;
1823
789k
  }
1824
1825
  /* Issue Content-Type header. */
1826
789k
  if(contenttype) {
1827
478
    result = add_content_type(&part->curlheaders, contenttype, boundary);
1828
478
    if(result)
1829
0
      return result;
1830
478
  }
1831
1832
  /* Content-Transfer-Encoding header. */
1833
789k
  if(!search_header(part->userheaders,
1834
789k
                    STRCONST("Content-Transfer-Encoding"))) {
1835
789k
    if(part->encoder)
1836
0
      cte = part->encoder->name;
1837
789k
    else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
1838
478
            part->kind != MIMEKIND_MULTIPART)
1839
0
      cte = "8bit";
1840
789k
    if(cte) {
1841
0
      result = Curl_mime_add_header(&part->curlheaders,
1842
0
                                    "Content-Transfer-Encoding: %s", cte);
1843
0
      if(result)
1844
0
        return result;
1845
0
    }
1846
789k
  }
1847
1848
  /* If we were reading curl-generated headers, restart with new ones (this
1849
     should not occur). */
1850
789k
  if(part->state.state == MIMESTATE_CURLHEADERS)
1851
0
    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
1852
1853
  /* Process subparts. */
1854
789k
  if(part->kind == MIMEKIND_MULTIPART && mime) {
1855
478
    curl_mimepart *subpart;
1856
1857
478
    disposition = NULL;
1858
478
    if(content_type_match(contenttype, STRCONST("multipart/form-data")))
1859
0
      disposition = "form-data";
1860
789k
    for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
1861
788k
      result = Curl_mime_prepare_headers(data, subpart, NULL,
1862
788k
                                         disposition, strategy);
1863
788k
      if(result)
1864
1
        return result;
1865
788k
    }
1866
478
  }
1867
789k
  return result;
1868
789k
}
1869
1870
/* Recursively reset paused status in the given part. */
1871
static void mime_unpause(curl_mimepart *part)
1872
0
{
1873
0
  if(part) {
1874
0
    if(part->lastreadstatus == CURL_READFUNC_PAUSE)
1875
0
      part->lastreadstatus = 1; /* Successful read status. */
1876
0
    if(part->kind == MIMEKIND_MULTIPART) {
1877
0
      curl_mime *mime = (curl_mime *)part->arg;
1878
1879
0
      if(mime) {
1880
0
        curl_mimepart *subpart;
1881
1882
0
        for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart)
1883
0
          mime_unpause(subpart);
1884
0
      }
1885
0
    }
1886
0
  }
1887
0
}
1888
1889
struct cr_mime_ctx {
1890
  struct Curl_creader super;
1891
  curl_mimepart *part;
1892
  curl_off_t total_len;
1893
  curl_off_t read_len;
1894
  CURLcode error_result;
1895
  struct bufq tmpbuf;
1896
  BIT(seen_eos);
1897
  BIT(errored);
1898
};
1899
1900
static CURLcode cr_mime_init(struct Curl_easy *data,
1901
                             struct Curl_creader *reader)
1902
477
{
1903
477
  struct cr_mime_ctx *ctx = reader->ctx;
1904
477
  (void)data;
1905
477
  ctx->total_len = -1;
1906
477
  ctx->read_len = 0;
1907
477
  Curl_bufq_init2(&ctx->tmpbuf, 1024, 1, BUFQ_OPT_NO_SPARES);
1908
477
  return CURLE_OK;
1909
477
}
1910
1911
static void cr_mime_close(struct Curl_easy *data,
1912
                          struct Curl_creader *reader)
1913
477
{
1914
477
  struct cr_mime_ctx *ctx = reader->ctx;
1915
477
  (void)data;
1916
477
  Curl_bufq_free(&ctx->tmpbuf);
1917
477
}
1918
1919
/* Real client reader to installed client callbacks. */
1920
static CURLcode cr_mime_read(struct Curl_easy *data,
1921
                             struct Curl_creader *reader,
1922
                             char *buf, size_t blen,
1923
                             size_t *pnread, bool *peos)
1924
669
{
1925
669
  struct cr_mime_ctx *ctx = reader->ctx;
1926
669
  CURLcode result = CURLE_OK;
1927
669
  size_t nread;
1928
669
  char tmp[256];
1929
1930
  /* Once we have errored, we will return the same error forever */
1931
669
  if(ctx->errored) {
1932
0
    CURL_TRC_READ(data, "cr_mime_read(len=%zu) is errored -> %d, eos=0",
1933
0
                  blen, (int)ctx->error_result);
1934
0
    *pnread = 0;
1935
0
    *peos = FALSE;
1936
0
    return ctx->error_result;
1937
0
  }
1938
669
  if(ctx->seen_eos) {
1939
0
    CURL_TRC_READ(data, "cr_mime_read(len=%zu) seen eos -> 0, eos=1", blen);
1940
0
    *pnread = 0;
1941
0
    *peos = TRUE;
1942
0
    return CURLE_OK;
1943
0
  }
1944
  /* respect length limitations */
1945
669
  if(ctx->total_len >= 0) {
1946
669
    curl_off_t remain = ctx->total_len - ctx->read_len;
1947
669
    if(remain <= 0)
1948
0
      blen = 0;
1949
669
    else if(remain < (curl_off_t)blen)
1950
309
      blen = (size_t)remain;
1951
669
  }
1952
1953
669
  if(!Curl_bufq_is_empty(&ctx->tmpbuf)) {
1954
0
    result = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen, &nread);
1955
0
    if(result) {
1956
0
      ctx->errored = TRUE;
1957
0
      ctx->error_result = result;
1958
0
      return result;
1959
0
    }
1960
0
  }
1961
669
  else if(blen <= 4) {
1962
    /* Curl_mime_read() may go into an infinite loop when reading
1963
     * via a base64 encoder, as it stalls when the read buffer is too small
1964
     * to contain a complete 3-byte encoding. Read into a larger buffer
1965
     * and use that until empty. */
1966
10
    CURL_TRC_READ(data, "cr_mime_read(len=%zu), small read, using tmp", blen);
1967
10
    nread = Curl_mime_read(tmp, 1, sizeof(tmp), ctx->part);
1968
10
    if(nread <= sizeof(tmp)) {
1969
10
      size_t n;
1970
10
      result = Curl_bufq_write(&ctx->tmpbuf, (unsigned char *)tmp, nread, &n);
1971
10
      if(result) {
1972
0
        ctx->errored = TRUE;
1973
0
        ctx->error_result = result;
1974
0
        return result;
1975
0
      }
1976
      /* stored it, read again */
1977
10
      result = Curl_bufq_cread(&ctx->tmpbuf, buf, blen, &nread);
1978
10
      if(result) {
1979
0
        ctx->errored = TRUE;
1980
0
        ctx->error_result = result;
1981
0
        return result;
1982
0
      }
1983
10
    }
1984
10
  }
1985
659
  else
1986
659
    nread = Curl_mime_read(buf, 1, blen, ctx->part);
1987
1988
669
  CURL_TRC_READ(data, "cr_mime_read(len=%zu), mime_read() -> %zu",
1989
669
                blen, nread);
1990
1991
669
  switch(nread) {
1992
0
  case 0:
1993
0
    if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
1994
0
      failf(data, "client mime read EOF fail, "
1995
0
            "only %" FMT_OFF_T "/%" FMT_OFF_T
1996
0
            " of needed bytes read", ctx->read_len, ctx->total_len);
1997
0
      return CURLE_READ_ERROR;
1998
0
    }
1999
0
    *pnread = 0;
2000
0
    *peos = TRUE;
2001
0
    ctx->seen_eos = TRUE;
2002
0
    break;
2003
2004
0
  case CURL_READFUNC_ABORT:
2005
0
    failf(data, "operation aborted by callback");
2006
0
    *pnread = 0;
2007
0
    *peos = FALSE;
2008
0
    ctx->errored = TRUE;
2009
0
    ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
2010
0
    result = CURLE_ABORTED_BY_CALLBACK;
2011
0
    break;
2012
2013
0
  case CURL_READFUNC_PAUSE:
2014
    /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
2015
0
    CURL_TRC_READ(data, "cr_mime_read(len=%zu), paused by callback", blen);
2016
0
    *pnread = 0;
2017
0
    *peos = FALSE;
2018
0
    result = Curl_xfer_pause_send(data, TRUE);
2019
0
    break; /* nothing was read */
2020
2021
0
  case STOP_FILLING:
2022
0
  case READ_ERROR:
2023
0
    failf(data, "read error getting mime data");
2024
0
    *pnread = 0;
2025
0
    *peos = FALSE;
2026
0
    ctx->errored = TRUE;
2027
0
    ctx->error_result = CURLE_READ_ERROR;
2028
0
    result = CURLE_READ_ERROR;
2029
0
    break;
2030
2031
669
  default:
2032
669
    if(nread > blen) {
2033
      /* the read function returned a too large value */
2034
0
      failf(data, "read function returned funny value");
2035
0
      *pnread = 0;
2036
0
      *peos = FALSE;
2037
0
      ctx->errored = TRUE;
2038
0
      ctx->error_result = CURLE_READ_ERROR;
2039
0
      return CURLE_READ_ERROR;
2040
0
    }
2041
669
    ctx->read_len += nread;
2042
669
    if(ctx->total_len >= 0)
2043
669
      ctx->seen_eos = (ctx->read_len >= ctx->total_len);
2044
669
    *pnread = nread;
2045
669
    *peos = (bool)ctx->seen_eos;
2046
669
    break;
2047
669
  }
2048
2049
669
  CURL_TRC_READ(data, "cr_mime_read(len=%zu, total=%" FMT_OFF_T
2050
669
                ", read=%" FMT_OFF_T ") -> %d, %zu, %d", blen,
2051
669
                ctx->total_len, ctx->read_len, (int)result, *pnread, *peos);
2052
669
  return result;
2053
669
}
2054
2055
static bool cr_mime_needs_rewind(struct Curl_easy *data,
2056
                                 struct Curl_creader *reader)
2057
0
{
2058
0
  struct cr_mime_ctx *ctx = reader->ctx;
2059
0
  (void)data;
2060
0
  return ctx->read_len > 0;
2061
0
}
2062
2063
static curl_off_t cr_mime_total_length(struct Curl_easy *data,
2064
                                       struct Curl_creader *reader)
2065
950
{
2066
950
  struct cr_mime_ctx *ctx = reader->ctx;
2067
950
  (void)data;
2068
950
  return ctx->total_len;
2069
950
}
2070
2071
static CURLcode cr_mime_resume_from(struct Curl_easy *data,
2072
                                    struct Curl_creader *reader,
2073
                                    curl_off_t offset)
2074
0
{
2075
0
  struct cr_mime_ctx *ctx = reader->ctx;
2076
2077
0
  if(offset > 0) {
2078
0
    curl_off_t passed = 0;
2079
2080
0
    do {
2081
0
      char scratch[4 * 1024];
2082
0
      size_t readthisamountnow =
2083
0
        (offset - passed > (curl_off_t)sizeof(scratch)) ?
2084
0
        sizeof(scratch) :
2085
0
        curlx_sotouz(offset - passed);
2086
0
      size_t nread;
2087
2088
0
      nread = Curl_mime_read(scratch, 1, readthisamountnow, ctx->part);
2089
0
      passed += (curl_off_t)nread;
2090
0
      if((nread == 0) || (nread > readthisamountnow)) {
2091
        /* this checks for greater-than only to make sure that the
2092
           CURL_READFUNC_ABORT return code still aborts */
2093
0
        failf(data, "Could only read %" FMT_OFF_T
2094
0
              " bytes from the mime post", passed);
2095
0
        return CURLE_READ_ERROR;
2096
0
      }
2097
0
    } while(passed < offset);
2098
2099
    /* now, decrease the size of the read */
2100
0
    if(ctx->total_len > 0) {
2101
0
      ctx->total_len -= offset;
2102
2103
0
      if(ctx->total_len <= 0) {
2104
0
        failf(data, "Mime post already completely uploaded");
2105
0
        return CURLE_PARTIAL_FILE;
2106
0
      }
2107
0
    }
2108
    /* we have passed, proceed as normal */
2109
0
  }
2110
0
  return CURLE_OK;
2111
0
}
2112
2113
static CURLcode cr_mime_cntrl(struct Curl_easy *data,
2114
                              struct Curl_creader *reader,
2115
                              Curl_creader_cntrl opcode)
2116
0
{
2117
0
  struct cr_mime_ctx *ctx = reader->ctx;
2118
0
  switch(opcode) {
2119
0
  case CURL_CRCNTRL_REWIND: {
2120
0
    CURLcode result = mime_rewind(ctx->part);
2121
0
    if(result)
2122
0
      failf(data, "Cannot rewind mime/post data");
2123
0
    return result;
2124
0
  }
2125
0
  case CURL_CRCNTRL_UNPAUSE:
2126
0
    mime_unpause(ctx->part);
2127
0
    break;
2128
0
  case CURL_CRCNTRL_CLEAR_EOS:
2129
0
    ctx->seen_eos = FALSE;
2130
0
    break;
2131
0
  default:
2132
0
    break;
2133
0
  }
2134
0
  return CURLE_OK;
2135
0
}
2136
2137
static bool cr_mime_is_paused(struct Curl_easy *data,
2138
                              struct Curl_creader *reader)
2139
0
{
2140
0
  struct cr_mime_ctx *ctx = reader->ctx;
2141
0
  (void)data;
2142
0
  return ctx->part && ctx->part->lastreadstatus == CURL_READFUNC_PAUSE;
2143
0
}
2144
2145
static const struct Curl_crtype cr_mime = {
2146
  "cr-mime",
2147
  cr_mime_init,
2148
  cr_mime_read,
2149
  cr_mime_close,
2150
  cr_mime_needs_rewind,
2151
  cr_mime_total_length,
2152
  cr_mime_resume_from,
2153
  cr_mime_cntrl,
2154
  cr_mime_is_paused,
2155
  Curl_creader_def_done,
2156
  sizeof(struct cr_mime_ctx)
2157
};
2158
2159
CURLcode Curl_creader_set_mime(struct Curl_easy *data, curl_mimepart *part)
2160
477
{
2161
477
  struct Curl_creader *r;
2162
477
  struct cr_mime_ctx *ctx;
2163
477
  CURLcode result;
2164
2165
477
  result = Curl_creader_create(&r, data, &cr_mime, CURL_CR_CLIENT);
2166
477
  if(result)
2167
0
    return result;
2168
477
  ctx = r->ctx;
2169
477
  ctx->part = part;
2170
  /* Make sure we will read the entire mime structure. */
2171
477
  result = mime_rewind(ctx->part);
2172
477
  if(result) {
2173
0
    Curl_creader_free(data, r);
2174
0
    return result;
2175
0
  }
2176
477
  ctx->total_len = mime_size(ctx->part);
2177
2178
477
  return Curl_creader_set(data, r);
2179
477
}
2180
2181
#else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP ||
2182
                                !CURL_DISABLE_SMTP ||
2183
                                !CURL_DISABLE_IMAP) */
2184
2185
/* Mime not compiled in: define stubs for externally-referenced functions. */
2186
curl_mime *curl_mime_init(CURL *easy)
2187
{
2188
  (void)easy;
2189
  return NULL;
2190
}
2191
2192
void curl_mime_free(curl_mime *mime)
2193
{
2194
  (void)mime;
2195
}
2196
2197
curl_mimepart *curl_mime_addpart(curl_mime *mime)
2198
{
2199
  (void)mime;
2200
  return NULL;
2201
}
2202
2203
CURLcode curl_mime_name(curl_mimepart *part, const char *name)
2204
{
2205
  (void)part;
2206
  (void)name;
2207
  return CURLE_NOT_BUILT_IN;
2208
}
2209
2210
CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
2211
{
2212
  (void)part;
2213
  (void)filename;
2214
  return CURLE_NOT_BUILT_IN;
2215
}
2216
2217
CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
2218
{
2219
  (void)part;
2220
  (void)mimetype;
2221
  return CURLE_NOT_BUILT_IN;
2222
}
2223
2224
CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
2225
{
2226
  (void)part;
2227
  (void)encoding;
2228
  return CURLE_NOT_BUILT_IN;
2229
}
2230
2231
CURLcode curl_mime_data(curl_mimepart *part, const char *data, size_t datasize)
2232
{
2233
  (void)part;
2234
  (void)data;
2235
  (void)datasize;
2236
  return CURLE_NOT_BUILT_IN;
2237
}
2238
2239
CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
2240
{
2241
  (void)part;
2242
  (void)filename;
2243
  return CURLE_NOT_BUILT_IN;
2244
}
2245
2246
CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize,
2247
                           curl_read_callback readfunc,
2248
                           curl_seek_callback seekfunc,
2249
                           curl_free_callback freefunc,
2250
                           void *arg)
2251
{
2252
  (void)part;
2253
  (void)datasize;
2254
  (void)readfunc;
2255
  (void)seekfunc;
2256
  (void)freefunc;
2257
  (void)arg;
2258
  return CURLE_NOT_BUILT_IN;
2259
}
2260
2261
CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
2262
{
2263
  (void)part;
2264
  (void)subparts;
2265
  return CURLE_NOT_BUILT_IN;
2266
}
2267
2268
CURLcode curl_mime_headers(curl_mimepart *part,
2269
                           struct curl_slist *headers, int take_ownership)
2270
{
2271
  (void)part;
2272
  (void)headers;
2273
  (void)take_ownership;
2274
  return CURLE_NOT_BUILT_IN;
2275
}
2276
2277
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
2278
{
2279
  (void)slp;
2280
  (void)fmt;
2281
  return CURLE_NOT_BUILT_IN;
2282
}
2283
2284
#endif /* if disabled */