Coverage Report

Created: 2026-04-29 07:01

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