Coverage Report

Created: 2026-09-04 07:15

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
2.13M
#define MAX_MIME_LEVELS 40 /* avoid deep nesting */
48
49
1.38M
#define READ_ERROR   ((size_t)-1)
50
696k
#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
8.75M
{
191
8.75M
  state->state = tok;
192
8.75M
  state->ptr = ptr;
193
8.75M
  state->offset = 0;
194
8.75M
}
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
43.5k
{
200
43.5k
  CURLcode result;
201
43.5k
  struct dynbuf db;
202
43.5k
  const char * const *table;
203
43.5k
  const char * const *p;
204
  /* replace first character by rest of string. */
205
43.5k
  static const char * const mimetable[] = {
206
43.5k
    "\\\\\\",
207
43.5k
    "\"\\\"",
208
43.5k
    NULL
209
43.5k
  };
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
43.5k
  static const char * const formtable[] = {
217
43.5k
    "\"%22",
218
43.5k
    "\r%0D",
219
43.5k
    "\n%0A",
220
43.5k
    NULL
221
43.5k
  };
222
223
43.5k
  table = formtable;
224
  /* data can be NULL when this function is called indirectly from
225
     curl_formget(). */
226
43.5k
  if(strategy == MIMESTRATEGY_MAIL || (data && data->set.mime_formescape))
227
574
    table = mimetable;
228
229
43.5k
  curlx_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
230
231
93.4k
  for(result = curlx_dyn_addn(&db, STRCONST("")); !result && *src; src++) {
232
198k
    for(p = table; *p && **p != *src; p++)
233
148k
      ;
234
235
49.8k
    if(*p)
236
292
      result = curlx_dyn_add(&db, *p + 1);
237
49.5k
    else
238
49.5k
      result = curlx_dyn_addn(&db, src, 1);
239
49.8k
  }
240
241
43.5k
  return curlx_dyn_ptr(&db);
242
43.5k
}
243
244
/* Check if header matches. */
245
static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
246
121k
{
247
121k
  char *value = NULL;
248
249
121k
  if(curl_strnequal(hdr->data, lbl, len) && hdr->data[len] == ':')
250
2.34k
    for(value = hdr->data + len + 1; *value == ' '; value++)
251
1.82k
      ;
252
121k
  return value;
253
121k
}
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.70M
{
259
2.70M
  char *value = NULL;
260
261
2.82M
  for(; !value && hdrlist; hdrlist = hdrlist->next)
262
121k
    value = match_header(hdrlist, hdr, len);
263
264
2.70M
  return value;
265
2.70M
}
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.70M
{
285
1.70M
  p->pos = 0;
286
1.70M
  p->bufbeg = 0;
287
1.70M
  p->bufend = 0;
288
1.70M
}
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
41.4k
{
577
41.4k
  curl_mimepart *part = (curl_mimepart *)instream;
578
41.4k
  size_t sz = curlx_sotouz(part->datasize - part->state.offset);
579
41.4k
  (void)size;  /* Always 1 */
580
581
41.4k
  if(!nitems)
582
0
    return STOP_FILLING;
583
584
41.4k
  if(sz > nitems)
585
32
    sz = nitems;
586
587
41.4k
  if(sz)
588
41.4k
    memcpy(buffer, part->data + curlx_sotouz(part->state.offset), sz);
589
590
41.4k
  return sz;
591
41.4k
}
592
593
static int mime_mem_seek(void *instream, curl_off_t offset, int whence)
594
43.5k
{
595
43.5k
  curl_mimepart *part = (curl_mimepart *)instream;
596
597
43.5k
  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
43.5k
  }
605
606
43.5k
  if(offset < 0 || offset > part->datasize)
607
0
    return CURL_SEEKFUNC_FAIL;
608
609
43.5k
  part->state.offset = offset;
610
43.5k
  return CURL_SEEKFUNC_OK;
611
43.5k
}
612
613
static void mime_mem_free(void *ptr)
614
11.4k
{
615
11.4k
  curlx_safefree(((curl_mimepart *)ptr)->data);
616
11.4k
}
617
618
/* Named file callbacks. */
619
/* Argument is a pointer to the mime part. */
620
static bool mime_open_file(curl_mimepart *part)
621
0
{
622
  /* Open a MIMEKIND_FILE part. */
623
624
0
  if(part->fp)
625
0
    return FALSE;
626
0
  part->fp = fopen_read(part->data, "rb");
627
0
  return part->fp ? FALSE : TRUE;
628
0
}
629
630
static size_t mime_file_read(char *buffer, size_t size, size_t nitems,
631
                             void *instream)
632
0
{
633
0
  curl_mimepart *part = (curl_mimepart *)instream;
634
635
0
  if(!nitems)
636
0
    return STOP_FILLING;
637
638
0
  if(mime_open_file(part))
639
0
    return READ_ERROR;
640
641
0
  return fread(buffer, size, nitems, part->fp);
642
0
}
643
644
static int mime_file_seek(void *instream, curl_off_t offset, int whence)
645
0
{
646
0
  curl_mimepart *part = (curl_mimepart *)instream;
647
648
0
  if(whence == SEEK_SET && !offset && !part->fp)
649
0
    return CURL_SEEKFUNC_OK;   /* Not open: implicitly already at BOF. */
650
651
0
  if(mime_open_file(part))
652
0
    return CURL_SEEKFUNC_FAIL;
653
654
0
  return curlx_fseek(part->fp, offset, whence) ?
655
0
    CURL_SEEKFUNC_CANTSEEK : CURL_SEEKFUNC_OK;
656
0
}
657
658
static void mime_file_free(void *ptr)
659
0
{
660
0
  curl_mimepart *part = (curl_mimepart *)ptr;
661
662
0
  if(part->fp) {
663
0
    curlx_fclose(part->fp);
664
0
    part->fp = NULL;
665
0
  }
666
0
  curlx_safefree(part->data);
667
0
}
668
669
/* Subparts callbacks. */
670
/* Argument is a pointer to the mime structure. */
671
672
/* Readback a byte string segment. */
673
static size_t readback_bytes(struct mime_state *state,
674
                             char *buffer, size_t bufsize,
675
                             const char *bytes, size_t numbytes,
676
                             const char *trail, size_t traillen)
677
6.93M
{
678
6.93M
  size_t sz;
679
6.93M
  size_t offset = curlx_sotouz(state->offset);
680
681
6.93M
  if(numbytes > offset) {
682
2.77M
    sz = numbytes - offset;
683
2.77M
    bytes += offset;
684
2.77M
  }
685
4.15M
  else {
686
4.15M
    sz = offset - numbytes;
687
4.15M
    if(sz >= traillen)
688
2.77M
      return 0;
689
1.38M
    bytes = trail + sz;
690
1.38M
    sz = traillen - sz;
691
1.38M
  }
692
693
4.16M
  if(sz > bufsize)
694
570
    sz = bufsize;
695
696
4.16M
  memcpy(buffer, bytes, sz);
697
4.16M
  state->offset += sz;
698
4.16M
  return sz;
699
6.93M
}
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
737k
{
707
737k
  size_t sz = 0;
708
709
737k
  if(++call_depth > MAX_MIME_LEVELS)
710
0
    return READ_ERROR;
711
712
737k
  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
737k
  default:
719
737k
    break;
720
737k
  }
721
722
  /* If we can determine we are at end of part data, spare a read. */
723
737k
  if(part->datasize != (curl_off_t)-1 &&
724
737k
     part->state.offset >= part->datasize) {
725
    /* sz is already zero. */
726
691k
  }
727
46.0k
  else {
728
46.0k
    switch(part->kind) {
729
4.61k
    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
4.61k
      sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread,
735
4.61k
                              call_depth);
736
4.61k
      break;
737
0
    case MIMEKIND_FILE:
738
0
      if(part->fp && feof(part->fp))
739
0
        break;  /* At EOF. */
740
0
      FALLTHROUGH();
741
41.4k
    default:
742
41.4k
      if(part->readfunc) {
743
41.4k
        if(!(part->flags & MIME_FAST_READ)) {
744
0
          if(*hasread)
745
0
            return STOP_FILLING;
746
0
          *hasread = TRUE;
747
0
        }
748
41.4k
        sz = part->readfunc(buffer, 1, bufsize, part->arg);
749
41.4k
      }
750
41.4k
      break;
751
46.0k
    }
752
46.0k
  }
753
754
737k
  switch(sz) {
755
0
  case STOP_FILLING:
756
0
    break;
757
691k
  case 0:
758
691k
  case CURL_READFUNC_ABORT:
759
691k
  case CURL_READFUNC_PAUSE:
760
691k
  case READ_ERROR:
761
691k
    part->lastreadstatus = sz;
762
691k
    break;
763
46.0k
  default:
764
46.0k
    part->state.offset += sz;
765
46.0k
    part->lastreadstatus = sz;
766
46.0k
    break;
767
737k
  }
768
769
737k
  return sz;
770
737k
}
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.38M
{
841
1.38M
  size_t cursize = 0;
842
843
1.38M
  if(++call_depth > MAX_MIME_LEVELS)
844
0
    return READ_ERROR;
845
846
  /* Readback from part. */
847
7.66M
  while(bufsize) {
848
7.65M
    size_t sz = 0;
849
7.65M
    struct curl_slist *hdr = (struct curl_slist *)part->state.ptr;
850
7.65M
    switch(part->state.state) {
851
691k
    case MIMESTATE_BEGIN:
852
691k
      mimesetstate(&part->state,
853
691k
                   (part->flags & MIME_BODY_ONLY) ?
854
691k
                   MIMESTATE_BODY : MIMESTATE_CURLHEADERS,
855
691k
                   part->curlheaders);
856
691k
      break;
857
691k
    case MIMESTATE_USERHEADERS:
858
691k
      if(!hdr) {
859
691k
        mimesetstate(&part->state, MIMESTATE_EOH, NULL);
860
691k
        break;
861
691k
      }
862
0
      if(match_header(hdr, "Content-Type", 12)) {
863
0
        mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next);
864
0
        break;
865
0
      }
866
0
      FALLTHROUGH();
867
2.76M
    case MIMESTATE_CURLHEADERS:
868
2.76M
      if(!hdr)
869
691k
        mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
870
2.07M
      else {
871
2.07M
        sz = readback_bytes(&part->state, buffer, bufsize,
872
2.07M
                            hdr->data, strlen(hdr->data), STRCONST("\r\n"));
873
2.07M
        if(!sz)
874
691k
          mimesetstate(&part->state, part->state.state, hdr->next);
875
2.07M
      }
876
2.76M
      break;
877
1.38M
    case MIMESTATE_EOH:
878
1.38M
      sz = readback_bytes(&part->state, buffer, bufsize, STRCONST("\r\n"),
879
1.38M
                          STRCONST(""));
880
1.38M
      if(!sz)
881
691k
        mimesetstate(&part->state, MIMESTATE_BODY, NULL);
882
1.38M
      break;
883
695k
    case MIMESTATE_BODY:
884
695k
      cleanup_encoder_state(&part->encstate);
885
695k
      mimesetstate(&part->state, MIMESTATE_CONTENT, NULL);
886
695k
      break;
887
737k
    case MIMESTATE_CONTENT:
888
737k
      if(part->encoder)
889
0
        sz = read_encoded_part_content(part, buffer, bufsize, hasread,
890
0
                                       call_depth);
891
737k
      else
892
737k
        sz = read_part_content(part, buffer, bufsize, hasread, call_depth);
893
737k
      switch(sz) {
894
691k
      case 0:
895
691k
        mimesetstate(&part->state, MIMESTATE_END, NULL);
896
        /* Try sparing open file descriptors. */
897
691k
        if(part->kind == MIMEKIND_FILE && part->fp) {
898
0
          curlx_fclose(part->fp);
899
0
          part->fp = NULL;
900
0
        }
901
691k
        FALLTHROUGH();
902
691k
      case CURL_READFUNC_ABORT:
903
691k
      case CURL_READFUNC_PAUSE:
904
691k
      case READ_ERROR:
905
691k
      case STOP_FILLING:
906
691k
        return cursize ? cursize : sz;
907
737k
      }
908
46.0k
      break;
909
691k
    case MIMESTATE_END:
910
691k
      return cursize;
911
0
    default:
912
0
      break;    /* Other values not in part state. */
913
7.65M
    }
914
915
    /* Bump buffer and counters according to read size. */
916
6.27M
    cursize += sz;
917
6.27M
    buffer += sz;
918
6.27M
    bufsize -= sz;
919
6.27M
  }
920
921
4.86k
  return cursize;
922
1.38M
}
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
4.61k
{
929
4.61k
  curl_mime *mime = (curl_mime *)instream;
930
4.61k
  size_t cursize = 0;
931
4.61k
  (void)size;  /* Always 1 */
932
933
4.61k
  if(++call_depth > MAX_MIME_LEVELS)
934
0
    return READ_ERROR;
935
936
4.86M
  while(nitems) {
937
4.86M
    size_t sz = 0;
938
4.86M
    curl_mimepart *part = mime->state.ptr;
939
4.86M
    switch(mime->state.state) {
940
4.14k
    case MIMESTATE_BEGIN:
941
4.14k
    case MIMESTATE_BODY:
942
4.14k
      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
4.14k
      mime->state.offset += 2;
947
4.14k
      break;
948
1.39M
    case MIMESTATE_BOUNDARY1:
949
1.39M
      sz = readback_bytes(&mime->state, buffer, nitems, STRCONST("\r\n--"),
950
1.39M
                          STRCONST(""));
951
1.39M
      if(!sz)
952
695k
        mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part);
953
1.39M
      break;
954
2.08M
    case MIMESTATE_BOUNDARY2:
955
2.08M
      if(part)
956
2.07M
        sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
957
2.07M
                            MIME_BOUNDARY_LEN, STRCONST("\r\n"));
958
8.05k
      else
959
8.05k
        sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
960
8.05k
                            MIME_BOUNDARY_LEN, STRCONST("--\r\n"));
961
2.08M
      if(!sz) {
962
691k
        mimesetstate(&mime->state, MIMESTATE_CONTENT, part);
963
691k
      }
964
2.08M
      break;
965
1.38M
    case MIMESTATE_CONTENT:
966
1.38M
      if(!part) {
967
46
        mimesetstate(&mime->state, MIMESTATE_END, NULL);
968
46
        break;
969
46
      }
970
1.38M
      sz = readback_part(part, buffer, nitems, hasread, call_depth);
971
1.38M
      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
691k
      case 0:
978
691k
        mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart);
979
691k
        break;
980
1.38M
      }
981
1.38M
      break;
982
1.38M
    case MIMESTATE_END:
983
46
      return cursize;
984
0
    default:
985
0
      break;    /* other values not used in mime state. */
986
4.86M
    }
987
988
    /* Bump buffer and counters according to read size. */
989
4.86M
    cursize += sz;
990
4.86M
    buffer += sz;
991
4.86M
    nitems -= sz;
992
4.86M
  }
993
994
4.56k
  return cursize;
995
4.61k
}
996
997
static int mime_part_rewind(curl_mimepart *part)
998
130k
{
999
130k
  int res = CURL_SEEKFUNC_OK;
1000
130k
  enum mimestate targetstate = MIMESTATE_BEGIN;
1001
1002
130k
  if(part->flags & MIME_BODY_ONLY)
1003
7.08k
    targetstate = MIMESTATE_BODY;
1004
130k
  cleanup_encoder_state(&part->encstate);
1005
130k
  if(part->state.state > targetstate) {
1006
67.1k
    res = CURL_SEEKFUNC_CANTSEEK;
1007
67.1k
    if(part->seekfunc) {
1008
46.3k
      res = part->seekfunc(part->arg, (curl_off_t)0, SEEK_SET);
1009
46.3k
      switch(res) {
1010
46.2k
      case CURL_SEEKFUNC_OK:
1011
46.2k
      case CURL_SEEKFUNC_FAIL:
1012
46.3k
      case CURL_SEEKFUNC_CANTSEEK:
1013
46.3k
        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
46.3k
      }
1021
46.3k
    }
1022
67.1k
  }
1023
1024
130k
  if(res == CURL_SEEKFUNC_OK)
1025
109k
    mimesetstate(&part->state, targetstate, NULL);
1026
1027
130k
  part->lastreadstatus = 1; /* Successful read status. */
1028
130k
  return res;
1029
130k
}
1030
1031
static int mime_subparts_seek(void *instream, curl_off_t offset, int whence)
1032
5.10k
{
1033
5.10k
  curl_mime *mime = (curl_mime *)instream;
1034
5.10k
  curl_mimepart *part;
1035
5.10k
  int rc = CURL_SEEKFUNC_OK;
1036
1037
5.10k
  if(whence != SEEK_SET || offset)
1038
0
    return CURL_SEEKFUNC_CANTSEEK;    /* Only support full rewind. */
1039
1040
5.10k
  if(mime->state.state == MIMESTATE_BEGIN)
1041
2.34k
    return CURL_SEEKFUNC_OK;           /* Already rewound. */
1042
1043
125k
  for(part = mime->firstpart; part; part = part->nextpart) {
1044
123k
    int res = mime_part_rewind(part);
1045
123k
    if(res != CURL_SEEKFUNC_OK)
1046
20.7k
      rc = res;
1047
123k
  }
1048
1049
2.76k
  if(rc == CURL_SEEKFUNC_OK)
1050
2.68k
    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1051
1052
2.76k
  return rc;
1053
5.10k
}
1054
1055
/* Release part content. */
1056
static void cleanup_part_content(curl_mimepart *part)
1057
874k
{
1058
874k
  if(part->freefunc)
1059
12.0k
    part->freefunc(part->arg);
1060
1061
874k
  part->readfunc = NULL;
1062
874k
  part->seekfunc = NULL;
1063
874k
  part->freefunc = NULL;
1064
874k
  part->arg = (void *)part;           /* Defaults to part itself. */
1065
874k
  part->data = NULL;
1066
874k
  part->fp = NULL;
1067
874k
  part->datasize = (curl_off_t)0;     /* No size yet. */
1068
874k
  cleanup_encoder_state(&part->encstate);
1069
874k
  part->kind = MIMEKIND_NONE;
1070
874k
  part->flags &= ~(unsigned int)MIME_FAST_READ;
1071
874k
  part->lastreadstatus = 1; /* Successful read status. */
1072
874k
  part->state.state = MIMESTATE_BEGIN;
1073
874k
}
1074
1075
static void mime_subparts_free(void *ptr)
1076
599
{
1077
599
  curl_mime *mime = (curl_mime *)ptr;
1078
1079
599
  if(mime && mime->parent) {
1080
599
    mime->parent->freefunc = NULL;  /* Be sure we will not be called again. */
1081
599
    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
1082
599
  }
1083
599
  curl_mime_free(mime);
1084
599
}
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
2.36k
{
1089
2.36k
  curl_mime *mime = (curl_mime *)ptr;
1090
1091
2.36k
  if(mime && mime->parent) {
1092
2.34k
    mime->parent->freefunc = NULL;  /* Be sure we will not be called again. */
1093
2.34k
    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
1094
2.34k
    mime->parent = NULL;
1095
2.34k
  }
1096
2.36k
}
1097
1098
void Curl_mime_cleanpart(curl_mimepart *part)
1099
945k
{
1100
945k
  if(part) {
1101
858k
    cleanup_part_content(part);
1102
858k
    curl_slist_free_all(part->curlheaders);
1103
858k
    if(part->flags & MIME_USERHEADERS_OWNER)
1104
0
      curl_slist_free_all(part->userheaders);
1105
858k
    curlx_safefree(part->mimetype);
1106
858k
    curlx_safefree(part->name);
1107
858k
    curlx_safefree(part->filename);
1108
858k
    Curl_mime_initpart(part);
1109
858k
  }
1110
945k
}
1111
1112
/* Recursively delete a mime handle and its parts. */
1113
void curl_mime_free(curl_mime *mime)
1114
2.36k
{
1115
2.36k
  curl_mimepart *part;
1116
1117
2.36k
  if(mime) {
1118
2.36k
    mime_subparts_unbind(mime);  /* Be sure it is not referenced anymore. */
1119
857k
    while(mime->firstpart) {
1120
854k
      part = mime->firstpart;
1121
854k
      mime->firstpart = part->nextpart;
1122
854k
      Curl_mime_cleanpart(part);
1123
854k
      curlx_free(part);
1124
854k
    }
1125
2.36k
    curlx_free(mime);
1126
2.36k
  }
1127
2.36k
}
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
2.36k
{
1214
2.36k
  curl_mime *mime = curlx_malloc(sizeof(*mime));
1215
1216
2.36k
  if(mime) {
1217
2.36k
    mime->parent = NULL;
1218
2.36k
    mime->firstpart = NULL;
1219
2.36k
    mime->lastpart = NULL;
1220
1221
2.36k
    memset(mime->boundary, '-', MIME_BOUNDARY_DASHES);
1222
2.36k
    if(Curl_rand_alnum(easy,
1223
2.36k
                       (unsigned char *)&mime->boundary[MIME_BOUNDARY_DASHES],
1224
2.36k
                       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
2.36k
    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1230
2.36k
  }
1231
1232
2.36k
  return mime;
1233
2.36k
}
1234
1235
/* Initialize a mime part. */
1236
void Curl_mime_initpart(curl_mimepart *part)
1237
1.71M
{
1238
1.71M
  memset(part, 0, sizeof(*part));
1239
1.71M
  part->lastreadstatus = 1; /* Successful read status. */
1240
1.71M
  mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
1241
1.71M
}
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
854k
{
1246
854k
  curl_mimepart *part;
1247
1248
854k
  if(!mime)
1249
0
    return NULL;
1250
1251
854k
  part = curlx_malloc(sizeof(*part));
1252
1253
854k
  if(part) {
1254
854k
    Curl_mime_initpart(part);
1255
854k
    part->parent = mime;
1256
1257
854k
    if(mime->lastpart)
1258
852k
      mime->lastpart->nextpart = part;
1259
2.36k
    else
1260
2.36k
      mime->firstpart = part;
1261
1262
854k
    mime->lastpart = part;
1263
854k
  }
1264
1265
854k
  return part;
1266
854k
}
1267
1268
/* Set mime part name. */
1269
CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1270
10.0k
{
1271
10.0k
  if(!part)
1272
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1273
1274
10.0k
  curlx_safefree(part->name);
1275
1276
10.0k
  if(name) {
1277
10.0k
    part->name = curlx_strdup(name);
1278
10.0k
    if(!part->name)
1279
0
      return CURLE_OUT_OF_MEMORY;
1280
10.0k
  }
1281
1282
10.0k
  return CURLE_OK;
1283
10.0k
}
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
11.4k
{
1305
11.4k
  if(!part)
1306
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1307
1308
11.4k
  cleanup_part_content(part);
1309
1310
11.4k
  if(data) {
1311
11.4k
    if(datasize == CURL_ZERO_TERMINATED)
1312
168
      datasize = strlen(data);
1313
1314
11.4k
    part->data = curlx_memdup0(data, datasize);
1315
11.4k
    if(!part->data)
1316
0
      return CURLE_OUT_OF_MEMORY;
1317
1318
11.4k
    part->datasize = datasize;
1319
11.4k
    part->readfunc = mime_mem_read;
1320
11.4k
    part->seekfunc = mime_mem_seek;
1321
11.4k
    part->freefunc = mime_mem_free;
1322
11.4k
    part->flags |= MIME_FAST_READ;
1323
11.4k
    part->kind = MIMEKIND_DATA;
1324
11.4k
  }
1325
1326
11.4k
  return CURLE_OK;
1327
11.4k
}
1328
1329
/* Set mime part content from named local file. */
1330
CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1331
0
{
1332
0
  CURLcode result = CURLE_OK;
1333
1334
0
  if(!part)
1335
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1336
1337
0
  cleanup_part_content(part);
1338
1339
0
  if(filename) {
1340
0
    char *base;
1341
0
    curlx_struct_stat sbuf;
1342
1343
0
    if(curlx_stat(filename, &sbuf))
1344
0
      result = CURLE_READ_ERROR;
1345
0
    else {
1346
0
      part->data = curlx_strdup(filename);
1347
0
      if(!part->data)
1348
0
        result = CURLE_OUT_OF_MEMORY;
1349
0
      else {
1350
0
        part->datasize = -1;
1351
0
        if(S_ISREG(sbuf.st_mode)) {
1352
0
          part->datasize = filesize(filename, sbuf);
1353
0
          part->seekfunc = mime_file_seek;
1354
0
        }
1355
1356
0
        part->readfunc = mime_file_read;
1357
0
        part->freefunc = mime_file_free;
1358
0
        part->kind = MIMEKIND_FILE;
1359
1360
        /* As a side effect, set the filename to the current file's base name.
1361
           It is possible to withdraw this by explicitly calling
1362
           curl_mime_filename() with a NULL filename argument after the current
1363
           call. */
1364
0
        base = strippath(filename);
1365
0
        if(!base)
1366
0
          result = CURLE_OUT_OF_MEMORY;
1367
0
        else {
1368
0
          result = curl_mime_filename(part, base);
1369
0
          curlx_free(base);
1370
0
        }
1371
0
      }
1372
0
    }
1373
0
  }
1374
0
  return result;
1375
0
}
1376
1377
/* Set mime part type. */
1378
CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1379
0
{
1380
0
  if(!part)
1381
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1382
1383
0
  curlx_safefree(part->mimetype);
1384
1385
0
  if(mimetype) {
1386
0
    part->mimetype = curlx_strdup(mimetype);
1387
0
    if(!part->mimetype)
1388
0
      return CURLE_OUT_OF_MEMORY;
1389
0
  }
1390
1391
0
  return CURLE_OK;
1392
0
}
1393
1394
static const struct mime_encoder encoders[] = {
1395
  { "binary", encoder_nop_read, encoder_nop_size },
1396
  { "8bit", encoder_nop_read, encoder_nop_size },
1397
  { "7bit", encoder_7bit_read, encoder_nop_size },
1398
  { "base64", encoder_base64_read, encoder_base64_size },
1399
  { "quoted-printable", encoder_qp_read, encoder_qp_size },
1400
  { ZERO_NULL, ZERO_NULL, ZERO_NULL }
1401
};
1402
1403
/* Set mime data transfer encoder. */
1404
CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1405
0
{
1406
0
  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
1407
0
  const struct mime_encoder *mep;
1408
1409
0
  if(!part)
1410
0
    return result;
1411
1412
0
  part->encoder = NULL;
1413
1414
0
  if(!encoding)
1415
0
    return CURLE_OK;    /* Removing current encoder. */
1416
1417
0
  for(mep = encoders; mep->name; mep++)
1418
0
    if(curl_strequal(encoding, mep->name)) {
1419
0
      part->encoder = mep;
1420
0
      result = CURLE_OK;
1421
0
    }
1422
1423
0
  return result;
1424
0
}
1425
1426
/* Set mime part headers. */
1427
CURLcode curl_mime_headers(curl_mimepart *part,
1428
                           struct curl_slist *headers, int take_ownership)
1429
9.25k
{
1430
9.25k
  if(!part)
1431
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1432
1433
9.25k
  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
9.25k
  part->userheaders = headers;
1439
9.25k
  if(headers && take_ownership)
1440
0
    part->flags |= MIME_USERHEADERS_OWNER;
1441
9.25k
  return CURLE_OK;
1442
9.25k
}
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
2.34k
{
1471
2.34k
  curl_mime *root;
1472
1473
2.34k
  if(!part)
1474
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1475
1476
  /* Accept setting twice the same subparts. */
1477
2.34k
  if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
1478
0
    return CURLE_OK;
1479
1480
2.34k
  cleanup_part_content(part);
1481
1482
2.34k
  if(subparts) {
1483
    /* Should not have been attached already. */
1484
2.34k
    if(subparts->parent)
1485
0
      return CURLE_BAD_FUNCTION_ARGUMENT;
1486
1487
    /* Should not be the part's root. */
1488
2.34k
    root = part->parent;
1489
2.34k
    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
2.34k
    if(mime_subparts_seek(subparts, (curl_off_t)0, SEEK_SET) !=
1503
2.34k
       CURL_SEEKFUNC_OK)
1504
0
      return CURLE_SEND_FAIL_REWIND;
1505
1506
2.34k
    subparts->parent = part;
1507
    /* Subparts are processed internally: no read callback. */
1508
2.34k
    part->seekfunc = mime_subparts_seek;
1509
2.34k
    part->freefunc = take_ownership ? mime_subparts_free :
1510
2.34k
      mime_subparts_unbind;
1511
2.34k
    part->arg = subparts;
1512
2.34k
    part->datasize = -1;
1513
2.34k
    part->kind = MIMEKIND_MULTIPART;
1514
2.34k
  }
1515
1516
2.34k
  return CURLE_OK;
1517
2.34k
}
1518
1519
CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
1520
599
{
1521
599
  return Curl_mime_set_subparts(part, subparts, TRUE);
1522
599
}
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
4.61k
{
1528
4.61k
  curl_mimepart *part = (curl_mimepart *)instream;
1529
4.61k
  size_t ret;
1530
4.61k
  bool hasread;
1531
1532
4.61k
  (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
4.61k
  do {
1537
4.61k
    hasread = FALSE;
1538
4.61k
    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
4.61k
  } while(ret == STOP_FILLING);
1546
1547
4.61k
  return ret;
1548
4.61k
}
1549
1550
/* Rewind mime stream. */
1551
static CURLcode mime_rewind(curl_mimepart *part)
1552
7.08k
{
1553
7.08k
  return mime_part_rewind(part) == CURL_SEEKFUNC_OK ?
1554
7.01k
         CURLE_OK : CURLE_SEND_FAIL_REWIND;
1555
7.08k
}
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.79M
{
1561
1.79M
  size_t size = 0;
1562
1563
2.68M
  for(; s; s = s->next)
1564
895k
    if(!skip || !match_header(s, skip, skiplen))
1565
895k
      size += strlen(s->data) + overhead;
1566
1.79M
  return size;
1567
1.79M
}
1568
1569
/* Get/compute multipart size. */
1570
static curl_off_t multipart_size(curl_mime *mime)
1571
4.30k
{
1572
4.30k
  curl_off_t size;
1573
4.30k
  curl_off_t boundarysize;
1574
4.30k
  curl_mimepart *part;
1575
1576
4.30k
  if(!mime)
1577
0
    return 0;           /* Not present -> empty. */
1578
1579
4.30k
  boundarysize = 4 + MIME_BOUNDARY_LEN + 2;
1580
4.30k
  size = boundarysize;  /* Final boundary - CRLF after headers. */
1581
1582
900k
  for(part = mime->firstpart; part; part = part->nextpart) {
1583
896k
    curl_off_t sz = mime_size(part);
1584
1585
896k
    if(sz < 0)
1586
0
      size = sz;
1587
1588
896k
    if(size >= 0)
1589
896k
      size += boundarysize + sz;
1590
896k
  }
1591
1592
4.30k
  return size;
1593
4.30k
}
1594
1595
/* Get/compute mime size. */
1596
static curl_off_t mime_size(curl_mimepart *part)
1597
900k
{
1598
900k
  curl_off_t size;
1599
1600
900k
  if(part->kind == MIMEKIND_MULTIPART)
1601
4.30k
    part->datasize = multipart_size(part->arg);
1602
1603
900k
  size = part->datasize;
1604
1605
900k
  if(part->encoder)
1606
0
    size = part->encoder->sizefunc(part);
1607
1608
900k
  if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
1609
    /* Compute total part size. */
1610
896k
    size += slist_size(part->curlheaders, 2, NULL, 0);
1611
896k
    size += slist_size(part->userheaders, 2, STRCONST("Content-Type"));
1612
896k
    size += 2;    /* CRLF after headers. */
1613
896k
  }
1614
900k
  return size;
1615
900k
}
1616
1617
/* Add a header. */
1618
/* VARARGS2 */
1619
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
1620
900k
{
1621
900k
  struct curl_slist *hdr = NULL;
1622
900k
  char *s = NULL;
1623
900k
  va_list ap;
1624
1625
900k
  va_start(ap, fmt);
1626
900k
  s = curl_mvaprintf(fmt, ap);
1627
900k
  va_end(ap);
1628
1629
900k
  if(s) {
1630
900k
    hdr = Curl_slist_append_nodup(*slp, s);
1631
900k
    if(hdr)
1632
900k
      *slp = hdr;
1633
0
    else
1634
0
      curlx_free(s);
1635
900k
  }
1636
1637
900k
  return hdr ? CURLE_OK : CURLE_OUT_OF_MEMORY;
1638
900k
}
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
4.33k
{
1644
4.33k
  return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
1645
4.33k
                              boundary ? "; boundary=" : "",
1646
4.33k
                              boundary ? boundary : "");
1647
4.33k
}
1648
1649
const char *Curl_mime_contenttype(const char *filename)
1650
897k
{
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
897k
  struct ContentType {
1656
897k
    const char *extension;
1657
897k
    const char *type;
1658
897k
  };
1659
897k
  static const struct ContentType ctts[] = {
1660
897k
    { ".gif",  "image/gif" },
1661
897k
    { ".jpg",  "image/jpeg" },
1662
897k
    { ".jpeg", "image/jpeg" },
1663
897k
    { ".png",  "image/png" },
1664
897k
    { ".svg",  "image/svg+xml" },
1665
897k
    { ".txt",  "text/plain" },
1666
897k
    { ".htm",  "text/html" },
1667
897k
    { ".html", "text/html" },
1668
897k
    { ".pdf",  "application/pdf" },
1669
897k
    { ".xml",  "application/xml" }
1670
897k
  };
1671
1672
897k
  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
897k
  return NULL;
1685
897k
}
1686
1687
static bool content_type_match(const char *contenttype,
1688
                               const char *target, size_t len)
1689
4.33k
{
1690
4.33k
  if(contenttype && curl_strnequal(contenttype, target, len))
1691
3.87k
    switch(contenttype[len]) {
1692
3.87k
    case '\0':
1693
3.87k
    case '\t':
1694
3.87k
    case '\r':
1695
3.87k
    case '\n':
1696
3.87k
    case ' ':
1697
3.87k
    case ';':
1698
3.87k
      return TRUE;
1699
3.87k
    }
1700
457
  return FALSE;
1701
4.33k
}
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
901k
{
1709
901k
  if(!disposition &&
1710
6.27k
     (part->filename || part->name ||
1711
4.84k
      (contenttype && !curl_strnequal(contenttype, "multipart/", 10))))
1712
1.89k
    disposition = DISPOSITION_DEFAULT;
1713
1714
901k
  if(disposition && curl_strequal(disposition, "attachment") &&
1715
1.89k
     !part->name && !part->filename)
1716
457
    disposition = NULL;
1717
1718
901k
  if(disposition) {
1719
896k
    CURLcode result = CURLE_OK;
1720
896k
    char *name = NULL;
1721
896k
    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
896k
    bool backslash = (strategy == MIMESTRATEGY_MAIL) ||
1727
896k
                     (data && data->set.mime_formescape);
1728
896k
    if(backslash &&
1729
1.17k
       ((part->name && part->name[strcspn(part->name, "\r\n")]) ||
1730
1.17k
        (part->filename && part->filename[strcspn(part->filename, "\r\n")])))
1731
1
      return CURLE_BAD_FUNCTION_ARGUMENT;
1732
1733
896k
    if(part->name) {
1734
43.5k
      name = escape_string(data, part->name, strategy);
1735
43.5k
      if(!name)
1736
0
        return CURLE_OUT_OF_MEMORY;
1737
43.5k
    }
1738
896k
    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
896k
    if(!result)
1744
896k
      result = Curl_mime_add_header(&part->curlheaders,
1745
896k
                                    "Content-Disposition: %s%s%s%s%s%s%s",
1746
896k
                                    disposition,
1747
896k
                                    name ? "; name=\"" : "",
1748
896k
                                    name ? name : "",
1749
896k
                                    name ? "\"" : "",
1750
896k
                                    filename ? "; filename=\"" : "",
1751
896k
                                    filename ? filename : "",
1752
896k
                                    filename ? "\"" : "");
1753
896k
    curlx_safefree(name);
1754
896k
    curlx_safefree(filename);
1755
896k
    if(result)
1756
0
      return result;
1757
896k
  }
1758
901k
  return CURLE_OK;
1759
901k
}
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
901k
{
1767
901k
  curl_mime *mime = NULL;
1768
901k
  const char *boundary = NULL;
1769
901k
  char *customct;
1770
901k
  const char *cte = NULL;
1771
901k
  CURLcode result = CURLE_OK;
1772
1773
  /* Get rid of previously prepared headers. */
1774
901k
  curl_slist_free_all(part->curlheaders);
1775
901k
  part->curlheaders = NULL;
1776
1777
  /* Be sure we will not access old headers later. */
1778
901k
  if(part->state.state == MIMESTATE_CURLHEADERS)
1779
1
    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
1780
1781
  /* Check if content type is specified. */
1782
901k
  customct = part->mimetype;
1783
901k
  if(!customct)
1784
901k
    customct = search_header(part->userheaders, STRCONST("Content-Type"));
1785
901k
  if(customct)
1786
457
    contenttype = customct;
1787
1788
  /* If content type is not specified, try to determine it. */
1789
901k
  if(!contenttype) {
1790
897k
    switch(part->kind) {
1791
0
    case MIMEKIND_MULTIPART:
1792
0
      contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
1793
0
      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
897k
    default:
1802
897k
      contenttype = Curl_mime_contenttype(part->filename);
1803
897k
      break;
1804
897k
    }
1805
897k
  }
1806
1807
901k
  if(part->kind == MIMEKIND_MULTIPART) {
1808
4.33k
    mime = (curl_mime *)part->arg;
1809
4.33k
    if(mime)
1810
4.33k
      boundary = mime->boundary;
1811
4.33k
  }
1812
897k
  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
901k
  if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
1819
901k
    result = add_content_disposition(data, part, disposition,
1820
901k
                                     contenttype, strategy);
1821
901k
    if(result)
1822
1
      return result;
1823
901k
  }
1824
1825
  /* Issue Content-Type header. */
1826
901k
  if(contenttype) {
1827
4.33k
    result = add_content_type(&part->curlheaders, contenttype, boundary);
1828
4.33k
    if(result)
1829
0
      return result;
1830
4.33k
  }
1831
1832
  /* Content-Transfer-Encoding header. */
1833
901k
  if(!search_header(part->userheaders,
1834
901k
                    STRCONST("Content-Transfer-Encoding"))) {
1835
901k
    if(part->encoder)
1836
0
      cte = part->encoder->name;
1837
901k
    else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
1838
0
            part->kind != MIMEKIND_MULTIPART)
1839
0
      cte = "8bit";
1840
901k
    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
901k
  }
1847
1848
  /* If we were reading curl-generated headers, restart with new ones (this
1849
     should not occur). */
1850
901k
  if(part->state.state == MIMESTATE_CURLHEADERS)
1851
1
    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
1852
1853
  /* Process subparts. */
1854
901k
  if(part->kind == MIMEKIND_MULTIPART && mime) {
1855
4.33k
    curl_mimepart *subpart;
1856
1857
4.33k
    disposition = NULL;
1858
4.33k
    if(content_type_match(contenttype, STRCONST("multipart/form-data")))
1859
3.87k
      disposition = "form-data";
1860
901k
    for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
1861
897k
      result = Curl_mime_prepare_headers(data, subpart, NULL,
1862
897k
                                         disposition, strategy);
1863
897k
      if(result)
1864
1
        return result;
1865
897k
    }
1866
4.33k
  }
1867
901k
  return result;
1868
901k
}
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
4.32k
{
1903
4.32k
  struct cr_mime_ctx *ctx = reader->ctx;
1904
4.32k
  (void)data;
1905
4.32k
  ctx->total_len = -1;
1906
4.32k
  ctx->read_len = 0;
1907
4.32k
  Curl_bufq_init2(&ctx->tmpbuf, 1024, 1, BUFQ_OPT_NO_SPARES);
1908
4.32k
  return CURLE_OK;
1909
4.32k
}
1910
1911
static void cr_mime_close(struct Curl_easy *data,
1912
                          struct Curl_creader *reader)
1913
4.32k
{
1914
4.32k
  struct cr_mime_ctx *ctx = reader->ctx;
1915
4.32k
  (void)data;
1916
4.32k
  Curl_bufq_free(&ctx->tmpbuf);
1917
4.32k
}
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
4.63k
{
1925
4.63k
  struct cr_mime_ctx *ctx = reader->ctx;
1926
4.63k
  CURLcode result = CURLE_OK;
1927
4.63k
  size_t nread;
1928
4.63k
  char tmp[256];
1929
1930
  /* Once we have errored, we will return the same error forever */
1931
4.63k
  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
4.63k
  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
4.63k
  if(ctx->total_len >= 0) {
1946
4.63k
    curl_off_t remain = ctx->total_len - ctx->read_len;
1947
4.63k
    if(remain <= 0)
1948
0
      blen = 0;
1949
4.63k
    else if(remain < (curl_off_t)blen)
1950
3.95k
      blen = (size_t)remain;
1951
4.63k
  }
1952
1953
4.63k
  if(!Curl_bufq_is_empty(&ctx->tmpbuf)) {
1954
22
    result = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen, &nread);
1955
22
    if(result) {
1956
0
      ctx->errored = TRUE;
1957
0
      ctx->error_result = result;
1958
0
      return result;
1959
0
    }
1960
22
  }
1961
4.61k
  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
50
    CURL_TRC_READ(data, "cr_mime_read(len=%zu), small read, using tmp", blen);
1967
50
    nread = Curl_mime_read(tmp, 1, sizeof(tmp), ctx->part);
1968
50
    if(nread <= sizeof(tmp)) {
1969
50
      size_t n;
1970
50
      result = Curl_bufq_write(&ctx->tmpbuf, (unsigned char *)tmp, nread, &n);
1971
50
      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
50
      result = Curl_bufq_cread(&ctx->tmpbuf, buf, blen, &nread);
1978
50
      if(result) {
1979
0
        ctx->errored = TRUE;
1980
0
        ctx->error_result = result;
1981
0
        return result;
1982
0
      }
1983
50
    }
1984
50
  }
1985
4.56k
  else
1986
4.56k
    nread = Curl_mime_read(buf, 1, blen, ctx->part);
1987
1988
4.63k
  CURL_TRC_READ(data, "cr_mime_read(len=%zu), mime_read() -> %zu",
1989
4.63k
                blen, nread);
1990
1991
4.63k
  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
4.63k
  default:
2032
4.63k
    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
4.63k
    ctx->read_len += nread;
2042
4.63k
    if(ctx->total_len >= 0)
2043
4.63k
      ctx->seen_eos = (ctx->read_len >= ctx->total_len);
2044
4.63k
    *pnread = nread;
2045
4.63k
    *peos = (bool)ctx->seen_eos;
2046
4.63k
    break;
2047
4.63k
  }
2048
2049
4.63k
  CURL_TRC_READ(data, "cr_mime_read(len=%zu, total=%" FMT_OFF_T
2050
4.63k
                ", read=%" FMT_OFF_T ") -> %d, %zu, %d", blen,
2051
4.63k
                ctx->total_len, ctx->read_len, (int)result, *pnread, *peos);
2052
4.63k
  return result;
2053
4.63k
}
2054
2055
static bool cr_mime_needs_rewind(struct Curl_easy *data,
2056
                                 struct Curl_creader *reader)
2057
2.03k
{
2058
2.03k
  struct cr_mime_ctx *ctx = reader->ctx;
2059
2.03k
  (void)data;
2060
2.03k
  return ctx->read_len > 0;
2061
2.03k
}
2062
2063
static curl_off_t cr_mime_total_length(struct Curl_easy *data,
2064
                                       struct Curl_creader *reader)
2065
24.5k
{
2066
24.5k
  struct cr_mime_ctx *ctx = reader->ctx;
2067
24.5k
  (void)data;
2068
24.5k
  return ctx->total_len;
2069
24.5k
}
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
2.75k
{
2117
2.75k
  struct cr_mime_ctx *ctx = reader->ctx;
2118
2.75k
  switch(opcode) {
2119
2.75k
  case CURL_CRCNTRL_REWIND: {
2120
2.75k
    CURLcode result = mime_rewind(ctx->part);
2121
2.75k
    if(result)
2122
54
      failf(data, "Cannot rewind mime/post data");
2123
2.75k
    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
2.75k
  }
2134
0
  return CURLE_OK;
2135
2.75k
}
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
4.32k
{
2161
4.32k
  struct Curl_creader *r;
2162
4.32k
  struct cr_mime_ctx *ctx;
2163
4.32k
  CURLcode result;
2164
2165
4.32k
  result = Curl_creader_create(&r, data, &cr_mime, CURL_CR_CLIENT);
2166
4.32k
  if(result)
2167
0
    return result;
2168
4.32k
  ctx = r->ctx;
2169
4.32k
  ctx->part = part;
2170
  /* Make sure we will read the entire mime structure. */
2171
4.32k
  result = mime_rewind(ctx->part);
2172
4.32k
  if(result) {
2173
24
    Curl_creader_free(data, r);
2174
24
    return result;
2175
24
  }
2176
4.30k
  ctx->total_len = mime_size(ctx->part);
2177
2178
4.30k
  return Curl_creader_set(data, r);
2179
4.32k
}
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 */