Coverage Report

Created: 2023-12-08 06:48

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