Coverage Report

Created: 2026-05-30 06:06

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