Coverage Report

Created: 2025-06-09 08:44

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