Coverage Report

Created: 2026-10-15 06:24

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