Coverage Report

Created: 2025-12-04 07:04

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