Coverage Report

Created: 2026-09-14 07:06

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
                                 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
0
{
191
0
  state->state = tok;
192
0
  state->ptr = ptr;
193
0
  state->offset = 0;
194
0
}
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
0
{
200
0
  CURLcode result;
201
0
  struct dynbuf db;
202
0
  const char * const *table;
203
0
  const char * const *p;
204
  /* replace first character by rest of string. */
205
0
  static const char * const mimetable[] = {
206
0
    "\\\\\\",
207
0
    "\"\\\"",
208
0
    NULL
209
0
  };
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
0
  static const char * const formtable[] = {
217
0
    "\"%22",
218
0
    "\r%0D",
219
0
    "\n%0A",
220
0
    NULL
221
0
  };
222
223
0
  table = formtable;
224
  /* data can be NULL when this function is called indirectly from
225
     curl_formget(). */
226
0
  if(strategy == MIMESTRATEGY_MAIL || (data && data->set.mime_formescape))
227
0
    table = mimetable;
228
229
0
  curlx_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
230
231
0
  for(result = curlx_dyn_addn(&db, STRCONST("")); !result && *src; src++) {
232
0
    for(p = table; *p && **p != *src; p++)
233
0
      ;
234
235
0
    if(*p)
236
0
      result = curlx_dyn_add(&db, *p + 1);
237
0
    else
238
0
      result = curlx_dyn_addn(&db, src, 1);
239
0
  }
240
241
0
  return curlx_dyn_ptr(&db);
242
0
}
243
244
/* Check if header matches. */
245
static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
246
0
{
247
0
  char *value = NULL;
248
249
0
  if(curl_strnequal(hdr->data, lbl, len) && hdr->data[len] == ':')
250
0
    for(value = hdr->data + len + 1; *value == ' '; value++)
251
0
      ;
252
0
  return value;
253
0
}
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
0
{
259
0
  char *value = NULL;
260
261
0
  for(; !value && hdrlist; hdrlist = hdrlist->next)
262
0
    value = match_header(hdrlist, hdr, len);
263
264
0
  return value;
265
0
}
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
0
{
285
0
  p->pos = 0;
286
0
  p->bufbeg = 0;
287
0
  p->bufend = 0;
288
0
}
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
0
{
577
0
  curl_mimepart *part = (curl_mimepart *)instream;
578
0
  size_t sz = curlx_sotouz(part->datasize - part->state.offset);
579
0
  (void)size;  /* Always 1 */
580
581
0
  if(!nitems)
582
0
    return STOP_FILLING;
583
584
0
  if(sz > nitems)
585
0
    sz = nitems;
586
587
0
  if(sz)
588
0
    memcpy(buffer, part->data + curlx_sotouz(part->state.offset), sz);
589
590
0
  return sz;
591
0
}
592
593
static int mime_mem_seek(void *instream, curl_off_t offset, int whence)
594
0
{
595
0
  curl_mimepart *part = (curl_mimepart *)instream;
596
597
0
  switch(whence) {
598
0
  case SEEK_CUR:
599
0
    offset += part->state.offset;
600
0
    break;
601
0
  case SEEK_END:
602
0
    offset += part->datasize;
603
0
    break;
604
0
  }
605
606
0
  if(offset < 0 || offset > part->datasize)
607
0
    return CURL_SEEKFUNC_FAIL;
608
609
0
  part->state.offset = offset;
610
0
  return CURL_SEEKFUNC_OK;
611
0
}
612
613
static void mime_mem_free(void *ptr)
614
0
{
615
0
  curlx_safefree(((curl_mimepart *)ptr)->data);
616
0
}
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
0
{
678
0
  size_t sz;
679
0
  size_t offset = curlx_sotouz(state->offset);
680
681
0
  if(numbytes > offset) {
682
0
    sz = numbytes - offset;
683
0
    bytes += offset;
684
0
  }
685
0
  else {
686
0
    sz = offset - numbytes;
687
0
    if(sz >= traillen)
688
0
      return 0;
689
0
    bytes = trail + sz;
690
0
    sz = traillen - sz;
691
0
  }
692
693
0
  if(sz > bufsize)
694
0
    sz = bufsize;
695
696
0
  memcpy(buffer, bytes, sz);
697
0
  state->offset += sz;
698
0
  return sz;
699
0
}
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
0
{
707
0
  size_t sz = 0;
708
709
0
  if(++call_depth > MAX_MIME_LEVELS)
710
0
    return READ_ERROR;
711
712
0
  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
0
  default:
719
0
    break;
720
0
  }
721
722
  /* If we can determine we are at end of part data, spare a read. */
723
0
  if(part->datasize != (curl_off_t)-1 &&
724
0
     part->state.offset >= part->datasize) {
725
    /* sz is already zero. */
726
0
  }
727
0
  else {
728
0
    switch(part->kind) {
729
0
    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
0
      sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread,
735
0
                              call_depth);
736
0
      break;
737
0
    case MIMEKIND_FILE:
738
0
      if(part->fp && feof(part->fp))
739
0
        break;  /* At EOF. */
740
0
      FALLTHROUGH();
741
0
    default:
742
0
      if(part->readfunc) {
743
0
        if(!(part->flags & MIME_FAST_READ)) {
744
0
          if(*hasread)
745
0
            return STOP_FILLING;
746
0
          *hasread = TRUE;
747
0
        }
748
0
        sz = part->readfunc(buffer, 1, bufsize, part->arg);
749
0
      }
750
0
      break;
751
0
    }
752
0
  }
753
754
0
  switch(sz) {
755
0
  case STOP_FILLING:
756
0
    break;
757
0
  case 0:
758
0
  case CURL_READFUNC_ABORT:
759
0
  case CURL_READFUNC_PAUSE:
760
0
  case READ_ERROR:
761
0
    part->lastreadstatus = sz;
762
0
    break;
763
0
  default:
764
0
    part->state.offset += sz;
765
0
    part->lastreadstatus = sz;
766
0
    break;
767
0
  }
768
769
0
  return sz;
770
0
}
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
0
{
841
0
  size_t cursize = 0;
842
843
0
  if(++call_depth > MAX_MIME_LEVELS)
844
0
    return READ_ERROR;
845
846
  /* Readback from part. */
847
0
  while(bufsize) {
848
0
    size_t sz = 0;
849
0
    struct curl_slist *hdr = (struct curl_slist *)part->state.ptr;
850
0
    switch(part->state.state) {
851
0
    case MIMESTATE_BEGIN:
852
0
      mimesetstate(&part->state,
853
0
                   (part->flags & MIME_BODY_ONLY) ?
854
0
                   MIMESTATE_BODY : MIMESTATE_CURLHEADERS,
855
0
                   part->curlheaders);
856
0
      break;
857
0
    case MIMESTATE_USERHEADERS:
858
0
      if(!hdr) {
859
0
        mimesetstate(&part->state, MIMESTATE_EOH, NULL);
860
0
        break;
861
0
      }
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
0
    case MIMESTATE_CURLHEADERS:
868
0
      if(!hdr)
869
0
        mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
870
0
      else {
871
0
        sz = readback_bytes(&part->state, buffer, bufsize,
872
0
                            hdr->data, strlen(hdr->data), STRCONST("\r\n"));
873
0
        if(!sz)
874
0
          mimesetstate(&part->state, part->state.state, hdr->next);
875
0
      }
876
0
      break;
877
0
    case MIMESTATE_EOH:
878
0
      sz = readback_bytes(&part->state, buffer, bufsize, STRCONST("\r\n"),
879
0
                          STRCONST(""));
880
0
      if(!sz)
881
0
        mimesetstate(&part->state, MIMESTATE_BODY, NULL);
882
0
      break;
883
0
    case MIMESTATE_BODY:
884
0
      cleanup_encoder_state(&part->encstate);
885
0
      mimesetstate(&part->state, MIMESTATE_CONTENT, NULL);
886
0
      break;
887
0
    case MIMESTATE_CONTENT:
888
0
      if(part->encoder)
889
0
        sz = read_encoded_part_content(part, buffer, bufsize, hasread,
890
0
                                       call_depth);
891
0
      else
892
0
        sz = read_part_content(part, buffer, bufsize, hasread, call_depth);
893
0
      switch(sz) {
894
0
      case 0:
895
0
        mimesetstate(&part->state, MIMESTATE_END, NULL);
896
        /* Try sparing open file descriptors. */
897
0
        if(part->kind == MIMEKIND_FILE && part->fp) {
898
0
          curlx_fclose(part->fp);
899
0
          part->fp = NULL;
900
0
        }
901
0
        FALLTHROUGH();
902
0
      case CURL_READFUNC_ABORT:
903
0
      case CURL_READFUNC_PAUSE:
904
0
      case READ_ERROR:
905
0
      case STOP_FILLING:
906
0
        return cursize ? cursize : sz;
907
0
      }
908
0
      break;
909
0
    case MIMESTATE_END:
910
0
      return cursize;
911
0
    default:
912
0
      break;    /* Other values not in part state. */
913
0
    }
914
915
    /* Bump buffer and counters according to read size. */
916
0
    cursize += sz;
917
0
    buffer += sz;
918
0
    bufsize -= sz;
919
0
  }
920
921
0
  return cursize;
922
0
}
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
0
{
929
0
  curl_mime *mime = (curl_mime *)instream;
930
0
  size_t cursize = 0;
931
0
  (void)size;  /* Always 1 */
932
933
0
  if(++call_depth > MAX_MIME_LEVELS)
934
0
    return READ_ERROR;
935
936
0
  while(nitems) {
937
0
    size_t sz = 0;
938
0
    curl_mimepart *part = mime->state.ptr;
939
0
    switch(mime->state.state) {
940
0
    case MIMESTATE_BEGIN:
941
0
    case MIMESTATE_BODY:
942
0
      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
0
      mime->state.offset += 2;
947
0
      break;
948
0
    case MIMESTATE_BOUNDARY1:
949
0
      sz = readback_bytes(&mime->state, buffer, nitems, STRCONST("\r\n--"),
950
0
                          STRCONST(""));
951
0
      if(!sz)
952
0
        mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part);
953
0
      break;
954
0
    case MIMESTATE_BOUNDARY2:
955
0
      if(part)
956
0
        sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
957
0
                            MIME_BOUNDARY_LEN, STRCONST("\r\n"));
958
0
      else
959
0
        sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
960
0
                            MIME_BOUNDARY_LEN, STRCONST("--\r\n"));
961
0
      if(!sz) {
962
0
        mimesetstate(&mime->state, MIMESTATE_CONTENT, part);
963
0
      }
964
0
      break;
965
0
    case MIMESTATE_CONTENT:
966
0
      if(!part) {
967
0
        mimesetstate(&mime->state, MIMESTATE_END, NULL);
968
0
        break;
969
0
      }
970
0
      sz = readback_part(part, buffer, nitems, hasread, call_depth);
971
0
      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
0
      case 0:
978
0
        mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart);
979
0
        break;
980
0
      }
981
0
      break;
982
0
    case MIMESTATE_END:
983
0
      return cursize;
984
0
    default:
985
0
      break;    /* other values not used in mime state. */
986
0
    }
987
988
    /* Bump buffer and counters according to read size. */
989
0
    cursize += sz;
990
0
    buffer += sz;
991
0
    nitems -= sz;
992
0
  }
993
994
0
  return cursize;
995
0
}
996
997
static int mime_part_rewind(curl_mimepart *part)
998
0
{
999
0
  int res = CURL_SEEKFUNC_OK;
1000
0
  enum mimestate targetstate = MIMESTATE_BEGIN;
1001
1002
0
  if(part->flags & MIME_BODY_ONLY)
1003
0
    targetstate = MIMESTATE_BODY;
1004
0
  cleanup_encoder_state(&part->encstate);
1005
0
  if(part->state.state > targetstate) {
1006
0
    res = CURL_SEEKFUNC_CANTSEEK;
1007
0
    if(part->seekfunc) {
1008
0
      res = part->seekfunc(part->arg, (curl_off_t)0, SEEK_SET);
1009
0
      switch(res) {
1010
0
      case CURL_SEEKFUNC_OK:
1011
0
      case CURL_SEEKFUNC_FAIL:
1012
0
      case CURL_SEEKFUNC_CANTSEEK:
1013
0
        break;
1014
0
      case -1:    /* For fseek() error. */
1015
0
        res = CURL_SEEKFUNC_CANTSEEK;
1016
0
        break;
1017
0
      default:
1018
0
        res = CURL_SEEKFUNC_FAIL;
1019
0
        break;
1020
0
      }
1021
0
    }
1022
0
  }
1023
1024
0
  if(res == CURL_SEEKFUNC_OK)
1025
0
    mimesetstate(&part->state, targetstate, NULL);
1026
1027
0
  part->lastreadstatus = 1; /* Successful read status. */
1028
0
  return res;
1029
0
}
1030
1031
static int mime_subparts_seek(void *instream, curl_off_t offset, int whence)
1032
0
{
1033
0
  curl_mime *mime = (curl_mime *)instream;
1034
0
  curl_mimepart *part;
1035
0
  int rc = CURL_SEEKFUNC_OK;
1036
1037
0
  if(whence != SEEK_SET || offset)
1038
0
    return CURL_SEEKFUNC_CANTSEEK;    /* Only support full rewind. */
1039
1040
0
  if(mime->state.state == MIMESTATE_BEGIN)
1041
0
    return CURL_SEEKFUNC_OK;           /* Already rewound. */
1042
1043
0
  for(part = mime->firstpart; part; part = part->nextpart) {
1044
0
    int res = mime_part_rewind(part);
1045
0
    if(res != CURL_SEEKFUNC_OK)
1046
0
      rc = res;
1047
0
  }
1048
1049
0
  if(rc == CURL_SEEKFUNC_OK)
1050
0
    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1051
1052
0
  return rc;
1053
0
}
1054
1055
/* Release part content. */
1056
static void cleanup_part_content(curl_mimepart *part)
1057
0
{
1058
0
  if(part->freefunc)
1059
0
    part->freefunc(part->arg);
1060
1061
0
  part->readfunc = NULL;
1062
0
  part->seekfunc = NULL;
1063
0
  part->freefunc = NULL;
1064
0
  part->arg = (void *)part;           /* Defaults to part itself. */
1065
0
  part->data = NULL;
1066
0
  part->fp = NULL;
1067
0
  part->datasize = (curl_off_t)0;     /* No size yet. */
1068
0
  cleanup_encoder_state(&part->encstate);
1069
0
  part->kind = MIMEKIND_NONE;
1070
0
  part->flags &= ~(unsigned int)MIME_FAST_READ;
1071
0
  part->lastreadstatus = 1; /* Successful read status. */
1072
0
  part->state.state = MIMESTATE_BEGIN;
1073
0
}
1074
1075
static void mime_subparts_free(void *ptr)
1076
0
{
1077
0
  curl_mime *mime = (curl_mime *)ptr;
1078
1079
0
  if(mime && mime->parent) {
1080
0
    mime->parent->freefunc = NULL;  /* Be sure we will not be called again. */
1081
0
    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
1082
0
  }
1083
0
  curl_mime_free(mime);
1084
0
}
1085
1086
/* Do not free subparts: unbind them. This is used for the top level only. */
1087
static void mime_subparts_unbind(void *ptr)
1088
0
{
1089
0
  curl_mime *mime = (curl_mime *)ptr;
1090
1091
0
  if(mime && mime->parent) {
1092
0
    mime->parent->freefunc = NULL;  /* Be sure we will not be called again. */
1093
0
    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
1094
0
    mime->parent = NULL;
1095
0
  }
1096
0
}
1097
1098
void Curl_mime_cleanpart(curl_mimepart *part)
1099
1.50k
{
1100
1.50k
  if(part) {
1101
0
    cleanup_part_content(part);
1102
0
    curl_slist_free_all(part->curlheaders);
1103
0
    if(part->flags & MIME_USERHEADERS_OWNER)
1104
0
      curl_slist_free_all(part->userheaders);
1105
0
    curlx_safefree(part->mimetype);
1106
0
    curlx_safefree(part->name);
1107
0
    curlx_safefree(part->filename);
1108
0
    Curl_mime_initpart(part);
1109
0
  }
1110
1.50k
}
1111
1112
/* Non-recursively delete a mime handle and its parts. */
1113
void curl_mime_free(curl_mime *mime)
1114
0
{
1115
0
  curl_mimepart *part;
1116
1117
0
  if(!mime)
1118
0
    return;
1119
1120
0
  mime_subparts_unbind(mime);  /* Be sure it is not referenced anymore. */
1121
1122
0
  while(mime) {
1123
0
    part = mime->firstpart;
1124
0
    if(part) {
1125
0
      mime->firstpart = part->nextpart;
1126
0
      if(part->kind == MIMEKIND_MULTIPART && part->arg &&
1127
0
         part->freefunc == mime_subparts_free) {
1128
0
        curl_mime *subparts = (curl_mime *)part->arg;
1129
0
        part->freefunc = NULL;
1130
0
        cleanup_part_content(part);
1131
0
        subparts->parent = mime->parent;
1132
0
        mime->parent = (curl_mimepart *)subparts;
1133
0
      }
1134
0
      Curl_mime_cleanpart(part);
1135
0
      curlx_free(part);
1136
0
    }
1137
0
    else {
1138
0
      curl_mime *parent = (curl_mime *)mime->parent;
1139
0
      curlx_free(mime);
1140
0
      mime = parent;
1141
0
    }
1142
0
  }
1143
0
}
1144
1145
CURLcode Curl_mime_duppart(struct Curl_easy *data,
1146
                           curl_mimepart *dst, const curl_mimepart *src)
1147
0
{
1148
0
  curl_mime *mime;
1149
0
  curl_mimepart *d;
1150
0
  const curl_mimepart *s;
1151
0
  CURLcode result = CURLE_OK;
1152
1153
0
  DEBUGASSERT(dst);
1154
1155
  /* Duplicate content. */
1156
0
  switch(src->kind) {
1157
0
  case MIMEKIND_NONE:
1158
0
    break;
1159
0
  case MIMEKIND_DATA:
1160
0
    result = curl_mime_data(dst, src->data, (size_t)src->datasize);
1161
0
    break;
1162
0
  case MIMEKIND_FILE:
1163
0
    result = curl_mime_filedata(dst, src->data);
1164
    /* Do not abort duplication if file is not readable. */
1165
0
    if(result == CURLE_READ_ERROR)
1166
0
      result = CURLE_OK;
1167
0
    break;
1168
0
  case MIMEKIND_CALLBACK:
1169
0
    result = curl_mime_data_cb(dst, src->datasize, src->readfunc,
1170
0
                               src->seekfunc, src->freefunc, src->arg);
1171
0
    break;
1172
0
  case MIMEKIND_MULTIPART:
1173
    /* No one knows about the cloned subparts, thus always attach ownership
1174
       to the part. */
1175
0
    mime = curl_mime_init(data);
1176
0
    result = mime ? curl_mime_subparts(dst, mime) : CURLE_OUT_OF_MEMORY;
1177
1178
    /* Duplicate subparts. */
1179
0
    for(s = ((curl_mime *)src->arg)->firstpart; !result && s;
1180
0
        s = s->nextpart) {
1181
0
      d = curl_mime_addpart(mime);
1182
0
      result = d ? Curl_mime_duppart(data, d, s) : CURLE_OUT_OF_MEMORY;
1183
0
    }
1184
0
    break;
1185
0
  default:  /* Invalid kind: should not occur. */
1186
0
    DEBUGF(infof(data, "invalid MIMEKIND* attempt"));
1187
0
    result = CURLE_BAD_FUNCTION_ARGUMENT;  /* Internal error? */
1188
0
    break;
1189
0
  }
1190
1191
  /* Duplicate headers. */
1192
0
  if(!result && src->userheaders) {
1193
0
    struct curl_slist *hdrs = Curl_slist_duplicate(src->userheaders);
1194
1195
0
    if(!hdrs)
1196
0
      result = CURLE_OUT_OF_MEMORY;
1197
0
    else {
1198
      /* No one but this procedure knows about the new header list,
1199
         so always take ownership. */
1200
0
      result = curl_mime_headers(dst, hdrs, TRUE);
1201
0
      if(result)
1202
0
        curl_slist_free_all(hdrs);
1203
0
    }
1204
0
  }
1205
1206
0
  if(!result) {
1207
    /* Duplicate other fields. */
1208
0
    dst->encoder = src->encoder;
1209
0
    result = curl_mime_type(dst, src->mimetype);
1210
0
  }
1211
0
  if(!result)
1212
0
    result = curl_mime_name(dst, src->name);
1213
0
  if(!result)
1214
0
    result = curl_mime_filename(dst, src->filename);
1215
1216
  /* If an error occurred, rollback. */
1217
0
  if(result)
1218
0
    Curl_mime_cleanpart(dst);
1219
1220
0
  return result;
1221
0
}
1222
1223
/*
1224
 * Mime build functions.
1225
 */
1226
1227
/* Create a mime handle. */
1228
curl_mime *curl_mime_init(void *easy)
1229
0
{
1230
0
  curl_mime *mime = curlx_malloc(sizeof(*mime));
1231
1232
0
  if(mime) {
1233
0
    mime->parent = NULL;
1234
0
    mime->firstpart = NULL;
1235
0
    mime->lastpart = NULL;
1236
1237
0
    memset(mime->boundary, '-', MIME_BOUNDARY_DASHES);
1238
0
    if(Curl_rand_alnum(easy,
1239
0
                       (unsigned char *)&mime->boundary[MIME_BOUNDARY_DASHES],
1240
0
                       MIME_RAND_BOUNDARY_CHARS + 1)) {
1241
      /* failed to get random separator, bail out */
1242
0
      curlx_free(mime);
1243
0
      return NULL;
1244
0
    }
1245
0
    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1246
0
  }
1247
1248
0
  return mime;
1249
0
}
1250
1251
/* Initialize a mime part. */
1252
void Curl_mime_initpart(curl_mimepart *part)
1253
0
{
1254
0
  memset(part, 0, sizeof(*part));
1255
0
  part->lastreadstatus = 1; /* Successful read status. */
1256
0
  mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
1257
0
}
1258
1259
/* Create a mime part and append it to a mime handle's part list. */
1260
curl_mimepart *curl_mime_addpart(curl_mime *mime)
1261
0
{
1262
0
  curl_mimepart *part;
1263
1264
0
  if(!mime)
1265
0
    return NULL;
1266
1267
0
  part = curlx_malloc(sizeof(*part));
1268
1269
0
  if(part) {
1270
0
    Curl_mime_initpart(part);
1271
0
    part->parent = mime;
1272
1273
0
    if(mime->lastpart)
1274
0
      mime->lastpart->nextpart = part;
1275
0
    else
1276
0
      mime->firstpart = part;
1277
1278
0
    mime->lastpart = part;
1279
0
  }
1280
1281
0
  return part;
1282
0
}
1283
1284
/* Set mime part name. */
1285
CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1286
0
{
1287
0
  if(!part)
1288
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1289
1290
0
  curlx_safefree(part->name);
1291
1292
0
  if(name) {
1293
0
    part->name = curlx_strdup(name);
1294
0
    if(!part->name)
1295
0
      return CURLE_OUT_OF_MEMORY;
1296
0
  }
1297
1298
0
  return CURLE_OK;
1299
0
}
1300
1301
/* Set mime part remote filename. */
1302
CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1303
0
{
1304
0
  if(!part)
1305
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1306
1307
0
  curlx_safefree(part->filename);
1308
1309
0
  if(filename) {
1310
0
    part->filename = curlx_strdup(filename);
1311
0
    if(!part->filename)
1312
0
      return CURLE_OUT_OF_MEMORY;
1313
0
  }
1314
1315
0
  return CURLE_OK;
1316
0
}
1317
1318
/* Set mime part content from memory data. */
1319
CURLcode curl_mime_data(curl_mimepart *part, const char *data, size_t datasize)
1320
0
{
1321
0
  if(!part)
1322
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1323
1324
0
  cleanup_part_content(part);
1325
1326
0
  if(data) {
1327
0
    if(datasize == CURL_ZERO_TERMINATED)
1328
0
      datasize = strlen(data);
1329
1330
0
    part->data = curlx_memdup0(data, datasize);
1331
0
    if(!part->data)
1332
0
      return CURLE_OUT_OF_MEMORY;
1333
1334
0
    part->datasize = datasize;
1335
0
    part->readfunc = mime_mem_read;
1336
0
    part->seekfunc = mime_mem_seek;
1337
0
    part->freefunc = mime_mem_free;
1338
0
    part->flags |= MIME_FAST_READ;
1339
0
    part->kind = MIMEKIND_DATA;
1340
0
  }
1341
1342
0
  return CURLE_OK;
1343
0
}
1344
1345
/* Set mime part content from named local file. */
1346
CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1347
0
{
1348
0
  CURLcode result = CURLE_OK;
1349
1350
0
  if(!part)
1351
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1352
1353
0
  cleanup_part_content(part);
1354
1355
0
  if(filename) {
1356
0
    char *base;
1357
0
    curlx_struct_stat sbuf;
1358
1359
0
    if(curlx_stat(filename, &sbuf))
1360
0
      result = CURLE_READ_ERROR;
1361
0
    else {
1362
0
      part->data = curlx_strdup(filename);
1363
0
      if(!part->data)
1364
0
        result = CURLE_OUT_OF_MEMORY;
1365
0
      else {
1366
0
        part->datasize = -1;
1367
0
        if(S_ISREG(sbuf.st_mode)) {
1368
0
          part->datasize = filesize(filename, sbuf);
1369
0
          part->seekfunc = mime_file_seek;
1370
0
        }
1371
1372
0
        part->readfunc = mime_file_read;
1373
0
        part->freefunc = mime_file_free;
1374
0
        part->kind = MIMEKIND_FILE;
1375
1376
        /* As a side effect, set the filename to the current file's base name.
1377
           It is possible to withdraw this by explicitly calling
1378
           curl_mime_filename() with a NULL filename argument after the current
1379
           call. */
1380
0
        base = strippath(filename);
1381
0
        if(!base)
1382
0
          result = CURLE_OUT_OF_MEMORY;
1383
0
        else {
1384
0
          result = curl_mime_filename(part, base);
1385
0
          curlx_free(base);
1386
0
        }
1387
0
      }
1388
0
    }
1389
0
  }
1390
0
  return result;
1391
0
}
1392
1393
/* Set mime part type. */
1394
CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1395
0
{
1396
0
  if(!part)
1397
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1398
1399
0
  curlx_safefree(part->mimetype);
1400
1401
0
  if(mimetype) {
1402
0
    part->mimetype = curlx_strdup(mimetype);
1403
0
    if(!part->mimetype)
1404
0
      return CURLE_OUT_OF_MEMORY;
1405
0
  }
1406
1407
0
  return CURLE_OK;
1408
0
}
1409
1410
static const struct mime_encoder encoders[] = {
1411
  { "binary", encoder_nop_read, encoder_nop_size },
1412
  { "8bit", encoder_nop_read, encoder_nop_size },
1413
  { "7bit", encoder_7bit_read, encoder_nop_size },
1414
  { "base64", encoder_base64_read, encoder_base64_size },
1415
  { "quoted-printable", encoder_qp_read, encoder_qp_size },
1416
  { ZERO_NULL, ZERO_NULL, ZERO_NULL }
1417
};
1418
1419
/* Set mime data transfer encoder. */
1420
CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1421
0
{
1422
0
  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
1423
0
  const struct mime_encoder *mep;
1424
1425
0
  if(!part)
1426
0
    return result;
1427
1428
0
  part->encoder = NULL;
1429
1430
0
  if(!encoding)
1431
0
    return CURLE_OK;    /* Removing current encoder. */
1432
1433
0
  for(mep = encoders; mep->name; mep++)
1434
0
    if(curl_strequal(encoding, mep->name)) {
1435
0
      part->encoder = mep;
1436
0
      result = CURLE_OK;
1437
0
    }
1438
1439
0
  return result;
1440
0
}
1441
1442
/* Set mime part headers. */
1443
CURLcode curl_mime_headers(curl_mimepart *part,
1444
                           struct curl_slist *headers, int take_ownership)
1445
0
{
1446
0
  if(!part)
1447
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1448
1449
0
  if(part->flags & MIME_USERHEADERS_OWNER) {
1450
0
    if(part->userheaders != headers)  /* Allow setting twice the same list. */
1451
0
      curl_slist_free_all(part->userheaders);
1452
0
    part->flags &= ~(unsigned int)MIME_USERHEADERS_OWNER;
1453
0
  }
1454
0
  part->userheaders = headers;
1455
0
  if(headers && take_ownership)
1456
0
    part->flags |= MIME_USERHEADERS_OWNER;
1457
0
  return CURLE_OK;
1458
0
}
1459
1460
/* Set mime part content from callback. */
1461
CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize,
1462
                           curl_read_callback readfunc,
1463
                           curl_seek_callback seekfunc,
1464
                           curl_free_callback freefunc, void *arg)
1465
0
{
1466
0
  if(!part)
1467
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1468
1469
0
  cleanup_part_content(part);
1470
1471
0
  if(readfunc) {
1472
0
    part->readfunc = readfunc;
1473
0
    part->seekfunc = seekfunc;
1474
0
    part->freefunc = freefunc;
1475
0
    part->arg = arg;
1476
0
    part->datasize = datasize;
1477
0
    part->kind = MIMEKIND_CALLBACK;
1478
0
  }
1479
1480
0
  return CURLE_OK;
1481
0
}
1482
1483
/* Set mime part content from subparts. */
1484
CURLcode Curl_mime_set_subparts(curl_mimepart *part,
1485
                                curl_mime *subparts, int take_ownership)
1486
0
{
1487
0
  curl_mime *root;
1488
1489
0
  if(!part)
1490
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1491
1492
  /* Accept setting twice the same subparts. */
1493
0
  if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
1494
0
    return CURLE_OK;
1495
1496
0
  cleanup_part_content(part);
1497
1498
0
  if(subparts) {
1499
    /* Should not have been attached already. */
1500
0
    if(subparts->parent)
1501
0
      return CURLE_BAD_FUNCTION_ARGUMENT;
1502
1503
    /* Should not be the part's root. */
1504
0
    root = part->parent;
1505
0
    if(root) {
1506
0
      while(root->parent && root->parent->parent)
1507
0
        root = root->parent->parent;
1508
0
      if(subparts == root) {
1509
        /* cannot add as a subpart of itself. */
1510
0
        return CURLE_BAD_FUNCTION_ARGUMENT;
1511
0
      }
1512
0
    }
1513
1514
    /* If subparts have already been used as a top-level MIMEPOST,
1515
       they might not be positioned at start. Rewind them now, as
1516
       a future check while rewinding the parent may cause this
1517
       content to be skipped. */
1518
0
    if(mime_subparts_seek(subparts, (curl_off_t)0, SEEK_SET) !=
1519
0
       CURL_SEEKFUNC_OK)
1520
0
      return CURLE_SEND_FAIL_REWIND;
1521
1522
0
    subparts->parent = part;
1523
    /* Subparts are processed internally: no read callback. */
1524
0
    part->seekfunc = mime_subparts_seek;
1525
0
    part->freefunc = take_ownership ? mime_subparts_free :
1526
0
      mime_subparts_unbind;
1527
0
    part->arg = subparts;
1528
0
    part->datasize = -1;
1529
0
    part->kind = MIMEKIND_MULTIPART;
1530
0
  }
1531
1532
0
  return CURLE_OK;
1533
0
}
1534
1535
CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
1536
0
{
1537
0
  return Curl_mime_set_subparts(part, subparts, TRUE);
1538
0
}
1539
1540
/* Readback from top mime. */
1541
/* Argument is the dummy top part. */
1542
size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
1543
0
{
1544
0
  curl_mimepart *part = (curl_mimepart *)instream;
1545
0
  size_t ret;
1546
0
  bool hasread;
1547
1548
0
  (void)size;  /* Always 1 */
1549
1550
  /* If `nitems` is <= 4, some encoders will return STOP_FILLING without
1551
   * adding any data and this loops infinitely. */
1552
0
  do {
1553
0
    hasread = FALSE;
1554
0
    ret = readback_part(part, buffer, nitems, &hasread, 0);
1555
    /*
1556
     * If this is not possible to get some data without calling more than
1557
     * one read callback (probably because a content encoder is not able to
1558
     * deliver a new bunch for the few data accumulated so far), force another
1559
     * read until we get enough data or a special exit code.
1560
     */
1561
0
  } while(ret == STOP_FILLING);
1562
1563
0
  return ret;
1564
0
}
1565
1566
/* Rewind mime stream. */
1567
static CURLcode mime_rewind(curl_mimepart *part)
1568
0
{
1569
0
  return mime_part_rewind(part) == CURL_SEEKFUNC_OK ?
1570
0
         CURLE_OK : CURLE_SEND_FAIL_REWIND;
1571
0
}
1572
1573
/* Compute header list size. */
1574
static size_t slist_size(struct curl_slist *s,
1575
                         size_t overhead, const char *skip, size_t skiplen)
1576
0
{
1577
0
  size_t size = 0;
1578
1579
0
  for(; s; s = s->next)
1580
0
    if(!skip || !match_header(s, skip, skiplen))
1581
0
      size += strlen(s->data) + overhead;
1582
0
  return size;
1583
0
}
1584
1585
/* Get/compute multipart size. */
1586
static curl_off_t multipart_size(curl_mime *mime)
1587
0
{
1588
0
  curl_off_t size;
1589
0
  curl_off_t boundarysize;
1590
0
  curl_mimepart *part;
1591
1592
0
  if(!mime)
1593
0
    return 0;           /* Not present -> empty. */
1594
1595
0
  boundarysize = 4 + MIME_BOUNDARY_LEN + 2;
1596
0
  size = boundarysize;  /* Final boundary - CRLF after headers. */
1597
1598
0
  for(part = mime->firstpart; part; part = part->nextpart) {
1599
0
    curl_off_t sz = mime_size(part);
1600
1601
0
    if(sz < 0)
1602
0
      size = sz;
1603
1604
0
    if(size >= 0)
1605
0
      size += boundarysize + sz;
1606
0
  }
1607
1608
0
  return size;
1609
0
}
1610
1611
/* Get/compute mime size. */
1612
static curl_off_t mime_size(curl_mimepart *part)
1613
0
{
1614
0
  curl_off_t size;
1615
1616
0
  if(part->kind == MIMEKIND_MULTIPART)
1617
0
    part->datasize = multipart_size(part->arg);
1618
1619
0
  size = part->datasize;
1620
1621
0
  if(part->encoder)
1622
0
    size = part->encoder->sizefunc(part);
1623
1624
0
  if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
1625
    /* Compute total part size. */
1626
0
    size += slist_size(part->curlheaders, 2, NULL, 0);
1627
0
    size += slist_size(part->userheaders, 2, STRCONST("Content-Type"));
1628
0
    size += 2;    /* CRLF after headers. */
1629
0
  }
1630
0
  return size;
1631
0
}
1632
1633
/* Add a header. */
1634
/* VARARGS2 */
1635
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
1636
0
{
1637
0
  struct curl_slist *hdr = NULL;
1638
0
  char *s = NULL;
1639
0
  va_list ap;
1640
1641
0
  va_start(ap, fmt);
1642
0
  s = curl_mvaprintf(fmt, ap);
1643
0
  va_end(ap);
1644
1645
0
  if(s) {
1646
0
    hdr = Curl_slist_append_nodup(*slp, s);
1647
0
    if(hdr)
1648
0
      *slp = hdr;
1649
0
    else
1650
0
      curlx_free(s);
1651
0
  }
1652
1653
0
  return hdr ? CURLE_OK : CURLE_OUT_OF_MEMORY;
1654
0
}
1655
1656
/* Add a content type header. */
1657
static CURLcode add_content_type(struct curl_slist **slp,
1658
                                 const char *type, const char *boundary)
1659
0
{
1660
0
  return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
1661
0
                              boundary ? "; boundary=" : "",
1662
0
                              boundary ? boundary : "");
1663
0
}
1664
1665
const char *Curl_mime_contenttype(const char *filename)
1666
0
{
1667
  /*
1668
   * If no content type was specified, we scan through a few well-known
1669
   * extensions and pick the first we match!
1670
   */
1671
0
  struct ContentType {
1672
0
    const char *extension;
1673
0
    const char *type;
1674
0
  };
1675
0
  static const struct ContentType ctts[] = {
1676
0
    { ".gif",  "image/gif" },
1677
0
    { ".jpg",  "image/jpeg" },
1678
0
    { ".jpeg", "image/jpeg" },
1679
0
    { ".png",  "image/png" },
1680
0
    { ".svg",  "image/svg+xml" },
1681
0
    { ".txt",  "text/plain" },
1682
0
    { ".htm",  "text/html" },
1683
0
    { ".html", "text/html" },
1684
0
    { ".pdf",  "application/pdf" },
1685
0
    { ".xml",  "application/xml" }
1686
0
  };
1687
1688
0
  if(filename) {
1689
0
    size_t len1 = strlen(filename);
1690
0
    const char *nameend = filename + len1;
1691
0
    unsigned int i;
1692
1693
0
    for(i = 0; i < CURL_ARRAYSIZE(ctts); i++) {
1694
0
      size_t len2 = strlen(ctts[i].extension);
1695
1696
0
      if(len1 >= len2 && curl_strequal(nameend - len2, ctts[i].extension))
1697
0
        return ctts[i].type;
1698
0
    }
1699
0
  }
1700
0
  return NULL;
1701
0
}
1702
1703
static bool content_type_match(const char *contenttype,
1704
                               const char *target, size_t len)
1705
0
{
1706
0
  if(contenttype && curl_strnequal(contenttype, target, len))
1707
0
    switch(contenttype[len]) {
1708
0
    case '\0':
1709
0
    case '\t':
1710
0
    case '\r':
1711
0
    case '\n':
1712
0
    case ' ':
1713
0
    case ';':
1714
0
      return TRUE;
1715
0
    }
1716
0
  return FALSE;
1717
0
}
1718
1719
static CURLcode add_content_disposition(struct Curl_easy *data,
1720
                                        curl_mimepart *part,
1721
                                        const char *disposition,
1722
                                        const char *contenttype,
1723
                                        enum mimestrategy strategy)
1724
0
{
1725
0
  if(!disposition &&
1726
0
     (part->filename || part->name ||
1727
0
      (contenttype && !curl_strnequal(contenttype, "multipart/", 10))))
1728
0
    disposition = DISPOSITION_DEFAULT;
1729
1730
0
  if(disposition && curl_strequal(disposition, "attachment") &&
1731
0
     !part->name && !part->filename)
1732
0
    disposition = NULL;
1733
1734
0
  if(disposition) {
1735
0
    CURLcode result = CURLE_OK;
1736
0
    char *name = NULL;
1737
0
    char *filename = NULL;
1738
    /* The mail (and legacy mime_formescape) strategy quotes the name and
1739
       filename with a backslash and has no in-band way to represent a CR or
1740
       LF, so one embedded in the value would split the generated header. The
1741
       form strategy percent-encodes CR/LF (see escape_string) and is safe. */
1742
0
    bool backslash = (strategy == MIMESTRATEGY_MAIL) ||
1743
0
                     (data && data->set.mime_formescape);
1744
0
    if(backslash &&
1745
0
       ((part->name && part->name[strcspn(part->name, "\r\n")]) ||
1746
0
        (part->filename && part->filename[strcspn(part->filename, "\r\n")])))
1747
0
      return CURLE_BAD_FUNCTION_ARGUMENT;
1748
1749
0
    if(part->name) {
1750
0
      name = escape_string(data, part->name, strategy);
1751
0
      if(!name)
1752
0
        return CURLE_OUT_OF_MEMORY;
1753
0
    }
1754
0
    if(part->filename) {
1755
0
      filename = escape_string(data, part->filename, strategy);
1756
0
      if(!filename)
1757
0
        result = CURLE_OUT_OF_MEMORY;
1758
0
    }
1759
0
    if(!result)
1760
0
      result = Curl_mime_add_header(&part->curlheaders,
1761
0
                                    "Content-Disposition: %s%s%s%s%s%s%s",
1762
0
                                    disposition,
1763
0
                                    name ? "; name=\"" : "",
1764
0
                                    name ? name : "",
1765
0
                                    name ? "\"" : "",
1766
0
                                    filename ? "; filename=\"" : "",
1767
0
                                    filename ? filename : "",
1768
0
                                    filename ? "\"" : "");
1769
0
    curlx_safefree(name);
1770
0
    curlx_safefree(filename);
1771
0
    if(result)
1772
0
      return result;
1773
0
  }
1774
0
  return CURLE_OK;
1775
0
}
1776
1777
CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
1778
                                   curl_mimepart *part,
1779
                                   const char *contenttype,
1780
                                   const char *disposition,
1781
                                   enum mimestrategy strategy)
1782
0
{
1783
0
  curl_mime *mime = NULL;
1784
0
  const char *boundary = NULL;
1785
0
  char *customct;
1786
0
  const char *cte = NULL;
1787
0
  CURLcode result = CURLE_OK;
1788
1789
  /* Get rid of previously prepared headers. */
1790
0
  curl_slist_free_all(part->curlheaders);
1791
0
  part->curlheaders = NULL;
1792
1793
  /* Be sure we will not access old headers later. */
1794
0
  if(part->state.state == MIMESTATE_CURLHEADERS)
1795
0
    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
1796
1797
  /* Check if content type is specified. */
1798
0
  customct = part->mimetype;
1799
0
  if(!customct)
1800
0
    customct = search_header(part->userheaders, STRCONST("Content-Type"));
1801
0
  if(customct)
1802
0
    contenttype = customct;
1803
1804
  /* If content type is not specified, try to determine it. */
1805
0
  if(!contenttype) {
1806
0
    switch(part->kind) {
1807
0
    case MIMEKIND_MULTIPART:
1808
0
      contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
1809
0
      break;
1810
0
    case MIMEKIND_FILE:
1811
0
      contenttype = Curl_mime_contenttype(part->filename);
1812
0
      if(!contenttype)
1813
0
        contenttype = Curl_mime_contenttype(part->data);
1814
0
      if(!contenttype && part->filename)
1815
0
        contenttype = FILE_CONTENTTYPE_DEFAULT;
1816
0
      break;
1817
0
    default:
1818
0
      contenttype = Curl_mime_contenttype(part->filename);
1819
0
      break;
1820
0
    }
1821
0
  }
1822
1823
0
  if(part->kind == MIMEKIND_MULTIPART) {
1824
0
    mime = (curl_mime *)part->arg;
1825
0
    if(mime)
1826
0
      boundary = mime->boundary;
1827
0
  }
1828
0
  else if(contenttype && !customct &&
1829
0
          content_type_match(contenttype, STRCONST("text/plain")) &&
1830
0
          (strategy == MIMESTRATEGY_MAIL || !part->filename))
1831
0
    contenttype = NULL;
1832
1833
  /* Issue content-disposition header only if not already set by caller. */
1834
0
  if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
1835
0
    result = add_content_disposition(data, part, disposition,
1836
0
                                     contenttype, strategy);
1837
0
    if(result)
1838
0
      return result;
1839
0
  }
1840
1841
  /* Issue Content-Type header. */
1842
0
  if(contenttype) {
1843
0
    result = add_content_type(&part->curlheaders, contenttype, boundary);
1844
0
    if(result)
1845
0
      return result;
1846
0
  }
1847
1848
  /* Content-Transfer-Encoding header. */
1849
0
  if(!search_header(part->userheaders,
1850
0
                    STRCONST("Content-Transfer-Encoding"))) {
1851
0
    if(part->encoder)
1852
0
      cte = part->encoder->name;
1853
0
    else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
1854
0
            part->kind != MIMEKIND_MULTIPART)
1855
0
      cte = "8bit";
1856
0
    if(cte) {
1857
0
      result = Curl_mime_add_header(&part->curlheaders,
1858
0
                                    "Content-Transfer-Encoding: %s", cte);
1859
0
      if(result)
1860
0
        return result;
1861
0
    }
1862
0
  }
1863
1864
  /* If we were reading curl-generated headers, restart with new ones (this
1865
     should not occur). */
1866
0
  if(part->state.state == MIMESTATE_CURLHEADERS)
1867
0
    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
1868
1869
  /* Process subparts. */
1870
0
  if(part->kind == MIMEKIND_MULTIPART && mime) {
1871
0
    curl_mimepart *subpart;
1872
1873
0
    disposition = NULL;
1874
0
    if(content_type_match(contenttype, STRCONST("multipart/form-data")))
1875
0
      disposition = "form-data";
1876
0
    for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
1877
0
      result = Curl_mime_prepare_headers(data, subpart, NULL,
1878
0
                                         disposition, strategy);
1879
0
      if(result)
1880
0
        return result;
1881
0
    }
1882
0
  }
1883
0
  return result;
1884
0
}
1885
1886
/* Recursively reset paused status in the given part. */
1887
static void mime_unpause(curl_mimepart *part)
1888
0
{
1889
0
  if(part) {
1890
0
    if(part->lastreadstatus == CURL_READFUNC_PAUSE)
1891
0
      part->lastreadstatus = 1; /* Successful read status. */
1892
0
    if(part->kind == MIMEKIND_MULTIPART) {
1893
0
      curl_mime *mime = (curl_mime *)part->arg;
1894
1895
0
      if(mime) {
1896
0
        curl_mimepart *subpart;
1897
1898
0
        for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart)
1899
0
          mime_unpause(subpart);
1900
0
      }
1901
0
    }
1902
0
  }
1903
0
}
1904
1905
struct cr_mime_ctx {
1906
  struct Curl_creader super;
1907
  curl_mimepart *part;
1908
  curl_off_t total_len;
1909
  curl_off_t read_len;
1910
  CURLcode error_result;
1911
  struct bufq tmpbuf;
1912
  BIT(seen_eos);
1913
  BIT(errored);
1914
};
1915
1916
static CURLcode cr_mime_init(struct Curl_easy *data,
1917
                             struct Curl_creader *reader)
1918
0
{
1919
0
  struct cr_mime_ctx *ctx = reader->ctx;
1920
0
  (void)data;
1921
0
  ctx->total_len = -1;
1922
0
  ctx->read_len = 0;
1923
0
  Curl_bufq_init2(&ctx->tmpbuf, 1024, 1, BUFQ_OPT_NO_SPARES);
1924
0
  return CURLE_OK;
1925
0
}
1926
1927
static void cr_mime_close(struct Curl_easy *data,
1928
                          struct Curl_creader *reader)
1929
0
{
1930
0
  struct cr_mime_ctx *ctx = reader->ctx;
1931
0
  (void)data;
1932
0
  Curl_bufq_free(&ctx->tmpbuf);
1933
0
}
1934
1935
/* Real client reader to installed client callbacks. */
1936
static CURLcode cr_mime_read(struct Curl_easy *data,
1937
                             struct Curl_creader *reader,
1938
                             char *buf, size_t blen,
1939
                             size_t *pnread, bool *peos)
1940
0
{
1941
0
  struct cr_mime_ctx *ctx = reader->ctx;
1942
0
  CURLcode result = CURLE_OK;
1943
0
  size_t nread;
1944
0
  char tmp[256];
1945
1946
  /* Once we have errored, we will return the same error forever */
1947
0
  if(ctx->errored) {
1948
0
    CURL_TRC_READ(data, "cr_mime_read(len=%zu) is errored -> %d, eos=0",
1949
0
                  blen, (int)ctx->error_result);
1950
0
    *pnread = 0;
1951
0
    *peos = FALSE;
1952
0
    return ctx->error_result;
1953
0
  }
1954
0
  if(ctx->seen_eos) {
1955
0
    CURL_TRC_READ(data, "cr_mime_read(len=%zu) seen eos -> 0, eos=1", blen);
1956
0
    *pnread = 0;
1957
0
    *peos = TRUE;
1958
0
    return CURLE_OK;
1959
0
  }
1960
  /* respect length limitations */
1961
0
  if(ctx->total_len >= 0) {
1962
0
    curl_off_t remain = ctx->total_len - ctx->read_len;
1963
0
    if(remain <= 0)
1964
0
      blen = 0;
1965
0
    else if(remain < (curl_off_t)blen)
1966
0
      blen = (size_t)remain;
1967
0
  }
1968
1969
0
  if(!Curl_bufq_is_empty(&ctx->tmpbuf)) {
1970
0
    result = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen, &nread);
1971
0
    if(result) {
1972
0
      ctx->errored = TRUE;
1973
0
      ctx->error_result = result;
1974
0
      return result;
1975
0
    }
1976
0
  }
1977
0
  else if(blen <= 4) {
1978
    /* Curl_mime_read() may go into an infinite loop when reading
1979
     * via a base64 encoder, as it stalls when the read buffer is too small
1980
     * to contain a complete 3-byte encoding. Read into a larger buffer
1981
     * and use that until empty. */
1982
0
    CURL_TRC_READ(data, "cr_mime_read(len=%zu), small read, using tmp", blen);
1983
0
    nread = Curl_mime_read(tmp, 1, sizeof(tmp), ctx->part);
1984
0
    if(nread <= sizeof(tmp)) {
1985
0
      size_t n;
1986
0
      result = Curl_bufq_write(&ctx->tmpbuf, (unsigned char *)tmp, nread, &n);
1987
0
      if(result) {
1988
0
        ctx->errored = TRUE;
1989
0
        ctx->error_result = result;
1990
0
        return result;
1991
0
      }
1992
      /* stored it, read again */
1993
0
      result = Curl_bufq_cread(&ctx->tmpbuf, buf, blen, &nread);
1994
0
      if(result) {
1995
0
        ctx->errored = TRUE;
1996
0
        ctx->error_result = result;
1997
0
        return result;
1998
0
      }
1999
0
    }
2000
0
  }
2001
0
  else
2002
0
    nread = Curl_mime_read(buf, 1, blen, ctx->part);
2003
2004
0
  CURL_TRC_READ(data, "cr_mime_read(len=%zu), mime_read() -> %zu",
2005
0
                blen, nread);
2006
2007
0
  switch(nread) {
2008
0
  case 0:
2009
0
    if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
2010
0
      failf(data, "client mime read EOF fail, "
2011
0
            "only %" FMT_OFF_T "/%" FMT_OFF_T
2012
0
            " of needed bytes read", ctx->read_len, ctx->total_len);
2013
0
      return CURLE_READ_ERROR;
2014
0
    }
2015
0
    *pnread = 0;
2016
0
    *peos = TRUE;
2017
0
    ctx->seen_eos = TRUE;
2018
0
    break;
2019
2020
0
  case CURL_READFUNC_ABORT:
2021
0
    failf(data, "operation aborted by callback");
2022
0
    *pnread = 0;
2023
0
    *peos = FALSE;
2024
0
    ctx->errored = TRUE;
2025
0
    ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
2026
0
    result = CURLE_ABORTED_BY_CALLBACK;
2027
0
    break;
2028
2029
0
  case CURL_READFUNC_PAUSE:
2030
    /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
2031
0
    CURL_TRC_READ(data, "cr_mime_read(len=%zu), paused by callback", blen);
2032
0
    *pnread = 0;
2033
0
    *peos = FALSE;
2034
0
    result = Curl_xfer_pause_send(data, TRUE);
2035
0
    break; /* nothing was read */
2036
2037
0
  case STOP_FILLING:
2038
0
  case READ_ERROR:
2039
0
    failf(data, "read error getting mime data");
2040
0
    *pnread = 0;
2041
0
    *peos = FALSE;
2042
0
    ctx->errored = TRUE;
2043
0
    ctx->error_result = CURLE_READ_ERROR;
2044
0
    result = CURLE_READ_ERROR;
2045
0
    break;
2046
2047
0
  default:
2048
0
    if(nread > blen) {
2049
      /* the read function returned a too large value */
2050
0
      failf(data, "read function returned funny value");
2051
0
      *pnread = 0;
2052
0
      *peos = FALSE;
2053
0
      ctx->errored = TRUE;
2054
0
      ctx->error_result = CURLE_READ_ERROR;
2055
0
      return CURLE_READ_ERROR;
2056
0
    }
2057
0
    ctx->read_len += nread;
2058
0
    if(ctx->total_len >= 0)
2059
0
      ctx->seen_eos = (ctx->read_len >= ctx->total_len);
2060
0
    *pnread = nread;
2061
0
    *peos = (bool)ctx->seen_eos;
2062
0
    break;
2063
0
  }
2064
2065
0
  CURL_TRC_READ(data, "cr_mime_read(len=%zu, total=%" FMT_OFF_T
2066
0
                ", read=%" FMT_OFF_T ") -> %d, %zu, %d", blen,
2067
0
                ctx->total_len, ctx->read_len, (int)result, *pnread, *peos);
2068
0
  return result;
2069
0
}
2070
2071
static bool cr_mime_needs_rewind(struct Curl_easy *data,
2072
                                 struct Curl_creader *reader)
2073
0
{
2074
0
  struct cr_mime_ctx *ctx = reader->ctx;
2075
0
  (void)data;
2076
0
  return ctx->read_len > 0;
2077
0
}
2078
2079
static curl_off_t cr_mime_total_length(struct Curl_easy *data,
2080
                                       struct Curl_creader *reader)
2081
0
{
2082
0
  struct cr_mime_ctx *ctx = reader->ctx;
2083
0
  (void)data;
2084
0
  return ctx->total_len;
2085
0
}
2086
2087
static CURLcode cr_mime_resume_from(struct Curl_easy *data,
2088
                                    struct Curl_creader *reader,
2089
                                    curl_off_t offset)
2090
0
{
2091
0
  struct cr_mime_ctx *ctx = reader->ctx;
2092
2093
0
  if(offset > 0) {
2094
0
    curl_off_t passed = 0;
2095
2096
0
    do {
2097
0
      char scratch[4 * 1024];
2098
0
      size_t readthisamountnow =
2099
0
        (offset - passed > (curl_off_t)sizeof(scratch)) ?
2100
0
        sizeof(scratch) :
2101
0
        curlx_sotouz(offset - passed);
2102
0
      size_t nread;
2103
2104
0
      nread = Curl_mime_read(scratch, 1, readthisamountnow, ctx->part);
2105
0
      passed += (curl_off_t)nread;
2106
0
      if((nread == 0) || (nread > readthisamountnow)) {
2107
        /* this checks for greater-than only to make sure that the
2108
           CURL_READFUNC_ABORT return code still aborts */
2109
0
        failf(data, "Could only read %" FMT_OFF_T
2110
0
              " bytes from the mime post", passed);
2111
0
        return CURLE_READ_ERROR;
2112
0
      }
2113
0
    } while(passed < offset);
2114
2115
    /* now, decrease the size of the read */
2116
0
    if(ctx->total_len > 0) {
2117
0
      ctx->total_len -= offset;
2118
2119
0
      if(ctx->total_len <= 0) {
2120
0
        failf(data, "Mime post already completely uploaded");
2121
0
        return CURLE_PARTIAL_FILE;
2122
0
      }
2123
0
    }
2124
    /* we have passed, proceed as normal */
2125
0
  }
2126
0
  return CURLE_OK;
2127
0
}
2128
2129
static CURLcode cr_mime_cntrl(struct Curl_easy *data,
2130
                              struct Curl_creader *reader,
2131
                              Curl_creader_cntrl opcode)
2132
0
{
2133
0
  struct cr_mime_ctx *ctx = reader->ctx;
2134
0
  switch(opcode) {
2135
0
  case CURL_CRCNTRL_REWIND: {
2136
0
    CURLcode result = mime_rewind(ctx->part);
2137
0
    if(result)
2138
0
      failf(data, "Cannot rewind mime/post data");
2139
0
    return result;
2140
0
  }
2141
0
  case CURL_CRCNTRL_UNPAUSE:
2142
0
    mime_unpause(ctx->part);
2143
0
    break;
2144
0
  case CURL_CRCNTRL_CLEAR_EOS:
2145
0
    ctx->seen_eos = FALSE;
2146
0
    break;
2147
0
  default:
2148
0
    break;
2149
0
  }
2150
0
  return CURLE_OK;
2151
0
}
2152
2153
static bool cr_mime_is_paused(struct Curl_easy *data,
2154
                              struct Curl_creader *reader)
2155
0
{
2156
0
  struct cr_mime_ctx *ctx = reader->ctx;
2157
0
  (void)data;
2158
0
  return ctx->part && ctx->part->lastreadstatus == CURL_READFUNC_PAUSE;
2159
0
}
2160
2161
static const struct Curl_crtype cr_mime = {
2162
  "cr-mime",
2163
  cr_mime_init,
2164
  cr_mime_read,
2165
  cr_mime_close,
2166
  cr_mime_needs_rewind,
2167
  cr_mime_total_length,
2168
  cr_mime_resume_from,
2169
  cr_mime_cntrl,
2170
  cr_mime_is_paused,
2171
  Curl_creader_def_done,
2172
  sizeof(struct cr_mime_ctx)
2173
};
2174
2175
CURLcode Curl_creader_set_mime(struct Curl_easy *data, curl_mimepart *part)
2176
0
{
2177
0
  struct Curl_creader *r;
2178
0
  struct cr_mime_ctx *ctx;
2179
0
  CURLcode result;
2180
2181
0
  result = Curl_creader_create(&r, data, &cr_mime, CURL_CR_CLIENT);
2182
0
  if(result)
2183
0
    return result;
2184
0
  ctx = r->ctx;
2185
0
  ctx->part = part;
2186
  /* Make sure we will read the entire mime structure. */
2187
0
  result = mime_rewind(ctx->part);
2188
0
  if(result) {
2189
0
    Curl_creader_free(data, r);
2190
0
    return result;
2191
0
  }
2192
0
  ctx->total_len = mime_size(ctx->part);
2193
2194
0
  return Curl_creader_set(data, r);
2195
0
}
2196
2197
#else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP ||
2198
                                !CURL_DISABLE_SMTP ||
2199
                                !CURL_DISABLE_IMAP) */
2200
2201
/* Mime not compiled in: define stubs for externally-referenced functions. */
2202
curl_mime *curl_mime_init(CURL *easy)
2203
{
2204
  (void)easy;
2205
  return NULL;
2206
}
2207
2208
void curl_mime_free(curl_mime *mime)
2209
{
2210
  (void)mime;
2211
}
2212
2213
curl_mimepart *curl_mime_addpart(curl_mime *mime)
2214
{
2215
  (void)mime;
2216
  return NULL;
2217
}
2218
2219
CURLcode curl_mime_name(curl_mimepart *part, const char *name)
2220
{
2221
  (void)part;
2222
  (void)name;
2223
  return CURLE_NOT_BUILT_IN;
2224
}
2225
2226
CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
2227
{
2228
  (void)part;
2229
  (void)filename;
2230
  return CURLE_NOT_BUILT_IN;
2231
}
2232
2233
CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
2234
{
2235
  (void)part;
2236
  (void)mimetype;
2237
  return CURLE_NOT_BUILT_IN;
2238
}
2239
2240
CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
2241
{
2242
  (void)part;
2243
  (void)encoding;
2244
  return CURLE_NOT_BUILT_IN;
2245
}
2246
2247
CURLcode curl_mime_data(curl_mimepart *part, const char *data, size_t datasize)
2248
{
2249
  (void)part;
2250
  (void)data;
2251
  (void)datasize;
2252
  return CURLE_NOT_BUILT_IN;
2253
}
2254
2255
CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
2256
{
2257
  (void)part;
2258
  (void)filename;
2259
  return CURLE_NOT_BUILT_IN;
2260
}
2261
2262
CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize,
2263
                           curl_read_callback readfunc,
2264
                           curl_seek_callback seekfunc,
2265
                           curl_free_callback freefunc,
2266
                           void *arg)
2267
{
2268
  (void)part;
2269
  (void)datasize;
2270
  (void)readfunc;
2271
  (void)seekfunc;
2272
  (void)freefunc;
2273
  (void)arg;
2274
  return CURLE_NOT_BUILT_IN;
2275
}
2276
2277
CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
2278
{
2279
  (void)part;
2280
  (void)subparts;
2281
  return CURLE_NOT_BUILT_IN;
2282
}
2283
2284
CURLcode curl_mime_headers(curl_mimepart *part,
2285
                           struct curl_slist *headers, int take_ownership)
2286
{
2287
  (void)part;
2288
  (void)headers;
2289
  (void)take_ownership;
2290
  return CURLE_NOT_BUILT_IN;
2291
}
2292
2293
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
2294
{
2295
  (void)slp;
2296
  (void)fmt;
2297
  return CURLE_NOT_BUILT_IN;
2298
}
2299
2300
#endif /* if disabled */