Coverage Report

Created: 2026-03-12 06:35

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