Coverage Report

Created: 2023-06-07 07:02

/src/curl/lib/formdata.c
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
25
#include "curl_setup.h"
26
27
#include <curl/curl.h>
28
29
#include "formdata.h"
30
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)
31
32
#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
33
#include <libgen.h>
34
#endif
35
36
#include "urldata.h" /* for struct Curl_easy */
37
#include "mime.h"
38
#include "vtls/vtls.h"
39
#include "strcase.h"
40
#include "sendf.h"
41
#include "strdup.h"
42
#include "rand.h"
43
#include "warnless.h"
44
/* The last 3 #include files should be in this order */
45
#include "curl_printf.h"
46
#include "curl_memory.h"
47
#include "memdebug.h"
48
49
50
64
#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
51
113
#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
52
96
#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
53
64
#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
54
32
#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
55
64
#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
56
96
#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
57
58
/***************************************************************************
59
 *
60
 * AddHttpPost()
61
 *
62
 * Adds an HttpPost structure to the list, if parent_post is given becomes
63
 * a subpost of parent_post instead of a direct list element.
64
 *
65
 * Returns newly allocated HttpPost on success and NULL if malloc failed.
66
 *
67
 ***************************************************************************/
68
static struct curl_httppost *
69
AddHttpPost(char *name, size_t namelength,
70
            char *value, curl_off_t contentslength,
71
            char *buffer, size_t bufferlength,
72
            char *contenttype,
73
            long flags,
74
            struct curl_slist *contentHeader,
75
            char *showfilename, char *userp,
76
            struct curl_httppost *parent_post,
77
            struct curl_httppost **httppost,
78
            struct curl_httppost **last_post)
79
32
{
80
32
  struct curl_httppost *post;
81
32
  if(!namelength && name)
82
32
    namelength = strlen(name);
83
32
  if((bufferlength > LONG_MAX) || (namelength > LONG_MAX))
84
    /* avoid overflow in typecasts below */
85
0
    return NULL;
86
32
  post = calloc(1, sizeof(struct curl_httppost));
87
32
  if(post) {
88
32
    post->name = name;
89
32
    post->namelength = (long)namelength;
90
32
    post->contents = value;
91
32
    post->contentlen = contentslength;
92
32
    post->buffer = buffer;
93
32
    post->bufferlength = (long)bufferlength;
94
32
    post->contenttype = contenttype;
95
32
    post->contentheader = contentHeader;
96
32
    post->showfilename = showfilename;
97
32
    post->userp = userp;
98
32
    post->flags = flags | CURL_HTTPPOST_LARGE;
99
32
  }
100
0
  else
101
0
    return NULL;
102
103
32
  if(parent_post) {
104
    /* now, point our 'more' to the original 'more' */
105
0
    post->more = parent_post->more;
106
107
    /* then move the original 'more' to point to ourselves */
108
0
    parent_post->more = post;
109
0
  }
110
32
  else {
111
    /* make the previous point to this */
112
32
    if(*last_post)
113
0
      (*last_post)->next = post;
114
32
    else
115
32
      (*httppost) = post;
116
117
32
    (*last_post) = post;
118
32
  }
119
32
  return post;
120
32
}
121
122
/***************************************************************************
123
 *
124
 * AddFormInfo()
125
 *
126
 * Adds a FormInfo structure to the list presented by parent_form_info.
127
 *
128
 * Returns newly allocated FormInfo on success and NULL if malloc failed/
129
 * parent_form_info is NULL.
130
 *
131
 ***************************************************************************/
132
static struct FormInfo *AddFormInfo(char *value,
133
                                    char *contenttype,
134
                                    struct FormInfo *parent_form_info)
135
0
{
136
0
  struct FormInfo *form_info;
137
0
  form_info = calloc(1, sizeof(struct FormInfo));
138
0
  if(!form_info)
139
0
    return NULL;
140
0
  if(value)
141
0
    form_info->value = value;
142
0
  if(contenttype)
143
0
    form_info->contenttype = contenttype;
144
0
  form_info->flags = HTTPPOST_FILENAME;
145
146
0
  if(parent_form_info) {
147
    /* now, point our 'more' to the original 'more' */
148
0
    form_info->more = parent_form_info->more;
149
150
    /* then move the original 'more' to point to ourselves */
151
0
    parent_form_info->more = form_info;
152
0
  }
153
154
0
  return form_info;
155
0
}
156
157
/***************************************************************************
158
 *
159
 * FormAdd()
160
 *
161
 * Stores a formpost parameter and builds the appropriate linked list.
162
 *
163
 * Has two principal functionalities: using files and byte arrays as
164
 * post parts. Byte arrays are either copied or just the pointer is stored
165
 * (as the user requests) while for files only the filename and not the
166
 * content is stored.
167
 *
168
 * While you may have only one byte array for each name, multiple filenames
169
 * are allowed (and because of this feature CURLFORM_END is needed after
170
 * using CURLFORM_FILE).
171
 *
172
 * Examples:
173
 *
174
 * Simple name/value pair with copied contents:
175
 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
176
 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
177
 *
178
 * name/value pair where only the content pointer is remembered:
179
 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
180
 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
181
 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
182
 *
183
 * storing a filename (CONTENTTYPE is optional!):
184
 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
185
 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
186
 * CURLFORM_END);
187
 *
188
 * storing multiple filenames:
189
 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
190
 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
191
 *
192
 * Returns:
193
 * CURL_FORMADD_OK             on success
194
 * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
195
 * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
196
 * CURL_FORMADD_NULL           if a null pointer was given for a char
197
 * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
198
 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
199
 * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
200
 * CURL_FORMADD_MEMORY         if an HttpPost struct cannot be allocated
201
 * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
202
 * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
203
 *
204
 ***************************************************************************/
205
206
static
207
CURLFORMcode FormAdd(struct curl_httppost **httppost,
208
                     struct curl_httppost **last_post,
209
                     va_list params)
210
32
{
211
32
  struct FormInfo *first_form, *current_form, *form = NULL;
212
32
  CURLFORMcode return_value = CURL_FORMADD_OK;
213
32
  const char *prevtype = NULL;
214
32
  struct curl_httppost *post = NULL;
215
32
  CURLformoption option;
216
32
  struct curl_forms *forms = NULL;
217
32
  char *array_value = NULL; /* value read from an array */
218
219
  /* This is a state variable, that if TRUE means that we're parsing an
220
     array that we got passed to us. If FALSE we're parsing the input
221
     va_list arguments. */
222
32
  bool array_state = FALSE;
223
224
  /*
225
   * We need to allocate the first struct to fill in.
226
   */
227
32
  first_form = calloc(1, sizeof(struct FormInfo));
228
32
  if(!first_form)
229
0
    return CURL_FORMADD_MEMORY;
230
231
32
  current_form = first_form;
232
233
  /*
234
   * Loop through all the options set. Break if we have an error to report.
235
   */
236
128
  while(return_value == CURL_FORMADD_OK) {
237
238
    /* first see if we have more parts of the array param */
239
128
    if(array_state && forms) {
240
      /* get the upcoming option from the given array */
241
0
      option = forms->option;
242
0
      array_value = (char *)forms->value;
243
244
0
      forms++; /* advance this to next entry */
245
0
      if(CURLFORM_END == option) {
246
        /* end of array state */
247
0
        array_state = FALSE;
248
0
        continue;
249
0
      }
250
0
    }
251
128
    else {
252
      /* This is not array-state, get next option. This gets an 'int' with
253
         va_arg() because CURLformoption might be a smaller type than int and
254
         might cause compiler warnings and wrong behavior. */
255
128
      option = (CURLformoption)va_arg(params, int);
256
128
      if(CURLFORM_END == option)
257
32
        break;
258
128
    }
259
260
96
    switch(option) {
261
0
    case CURLFORM_ARRAY:
262
0
      if(array_state)
263
        /* we don't support an array from within an array */
264
0
        return_value = CURL_FORMADD_ILLEGAL_ARRAY;
265
0
      else {
266
0
        forms = va_arg(params, struct curl_forms *);
267
0
        if(forms)
268
0
          array_state = TRUE;
269
0
        else
270
0
          return_value = CURL_FORMADD_NULL;
271
0
      }
272
0
      break;
273
274
      /*
275
       * Set the Name property.
276
       */
277
0
    case CURLFORM_PTRNAME:
278
0
      current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
279
280
      /* FALLTHROUGH */
281
32
    case CURLFORM_COPYNAME:
282
32
      if(current_form->name)
283
0
        return_value = CURL_FORMADD_OPTION_TWICE;
284
32
      else {
285
32
        char *name = array_state?
286
0
          array_value:va_arg(params, char *);
287
32
        if(name)
288
32
          current_form->name = name; /* store for the moment */
289
0
        else
290
0
          return_value = CURL_FORMADD_NULL;
291
32
      }
292
32
      break;
293
0
    case CURLFORM_NAMELENGTH:
294
0
      if(current_form->namelength)
295
0
        return_value = CURL_FORMADD_OPTION_TWICE;
296
0
      else
297
0
        current_form->namelength =
298
0
          array_state?(size_t)array_value:(size_t)va_arg(params, long);
299
0
      break;
300
301
      /*
302
       * Set the contents property.
303
       */
304
32
    case CURLFORM_PTRCONTENTS:
305
32
      current_form->flags |= HTTPPOST_PTRCONTENTS;
306
      /* FALLTHROUGH */
307
32
    case CURLFORM_COPYCONTENTS:
308
32
      if(current_form->value)
309
0
        return_value = CURL_FORMADD_OPTION_TWICE;
310
32
      else {
311
32
        char *value =
312
32
          array_state?array_value:va_arg(params, char *);
313
32
        if(value)
314
32
          current_form->value = value; /* store for the moment */
315
0
        else
316
0
          return_value = CURL_FORMADD_NULL;
317
32
      }
318
32
      break;
319
0
    case CURLFORM_CONTENTSLENGTH:
320
0
      current_form->contentslength =
321
0
        array_state?(size_t)array_value:(size_t)va_arg(params, long);
322
0
      break;
323
324
32
    case CURLFORM_CONTENTLEN:
325
32
      current_form->flags |= CURL_HTTPPOST_LARGE;
326
32
      current_form->contentslength =
327
32
        array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
328
32
      break;
329
330
      /* Get contents from a given file name */
331
0
    case CURLFORM_FILECONTENT:
332
0
      if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
333
0
        return_value = CURL_FORMADD_OPTION_TWICE;
334
0
      else {
335
0
        const char *filename = array_state?
336
0
          array_value:va_arg(params, char *);
337
0
        if(filename) {
338
0
          current_form->value = strdup(filename);
339
0
          if(!current_form->value)
340
0
            return_value = CURL_FORMADD_MEMORY;
341
0
          else {
342
0
            current_form->flags |= HTTPPOST_READFILE;
343
0
            current_form->value_alloc = TRUE;
344
0
          }
345
0
        }
346
0
        else
347
0
          return_value = CURL_FORMADD_NULL;
348
0
      }
349
0
      break;
350
351
      /* We upload a file */
352
0
    case CURLFORM_FILE:
353
0
      {
354
0
        const char *filename = array_state?array_value:
355
0
          va_arg(params, char *);
356
357
0
        if(current_form->value) {
358
0
          if(current_form->flags & HTTPPOST_FILENAME) {
359
0
            if(filename) {
360
0
              char *fname = strdup(filename);
361
0
              if(!fname)
362
0
                return_value = CURL_FORMADD_MEMORY;
363
0
              else {
364
0
                form = AddFormInfo(fname, NULL, current_form);
365
0
                if(!form) {
366
0
                  free(fname);
367
0
                  return_value = CURL_FORMADD_MEMORY;
368
0
                }
369
0
                else {
370
0
                  form->value_alloc = TRUE;
371
0
                  current_form = form;
372
0
                  form = NULL;
373
0
                }
374
0
              }
375
0
            }
376
0
            else
377
0
              return_value = CURL_FORMADD_NULL;
378
0
          }
379
0
          else
380
0
            return_value = CURL_FORMADD_OPTION_TWICE;
381
0
        }
382
0
        else {
383
0
          if(filename) {
384
0
            current_form->value = strdup(filename);
385
0
            if(!current_form->value)
386
0
              return_value = CURL_FORMADD_MEMORY;
387
0
            else {
388
0
              current_form->flags |= HTTPPOST_FILENAME;
389
0
              current_form->value_alloc = TRUE;
390
0
            }
391
0
          }
392
0
          else
393
0
            return_value = CURL_FORMADD_NULL;
394
0
        }
395
0
        break;
396
32
      }
397
398
0
    case CURLFORM_BUFFERPTR:
399
0
      current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
400
0
      if(current_form->buffer)
401
0
        return_value = CURL_FORMADD_OPTION_TWICE;
402
0
      else {
403
0
        char *buffer =
404
0
          array_state?array_value:va_arg(params, char *);
405
0
        if(buffer) {
406
0
          current_form->buffer = buffer; /* store for the moment */
407
0
          current_form->value = buffer; /* make it non-NULL to be accepted
408
                                           as fine */
409
0
        }
410
0
        else
411
0
          return_value = CURL_FORMADD_NULL;
412
0
      }
413
0
      break;
414
415
0
    case CURLFORM_BUFFERLENGTH:
416
0
      if(current_form->bufferlength)
417
0
        return_value = CURL_FORMADD_OPTION_TWICE;
418
0
      else
419
0
        current_form->bufferlength =
420
0
          array_state?(size_t)array_value:(size_t)va_arg(params, long);
421
0
      break;
422
423
0
    case CURLFORM_STREAM:
424
0
      current_form->flags |= HTTPPOST_CALLBACK;
425
0
      if(current_form->userp)
426
0
        return_value = CURL_FORMADD_OPTION_TWICE;
427
0
      else {
428
0
        char *userp =
429
0
          array_state?array_value:va_arg(params, char *);
430
0
        if(userp) {
431
0
          current_form->userp = userp;
432
0
          current_form->value = userp; /* this isn't strictly true but we
433
                                          derive a value from this later on
434
                                          and we need this non-NULL to be
435
                                          accepted as a fine form part */
436
0
        }
437
0
        else
438
0
          return_value = CURL_FORMADD_NULL;
439
0
      }
440
0
      break;
441
442
0
    case CURLFORM_CONTENTTYPE:
443
0
      {
444
0
        const char *contenttype =
445
0
          array_state?array_value:va_arg(params, char *);
446
0
        if(current_form->contenttype) {
447
0
          if(current_form->flags & HTTPPOST_FILENAME) {
448
0
            if(contenttype) {
449
0
              char *type = strdup(contenttype);
450
0
              if(!type)
451
0
                return_value = CURL_FORMADD_MEMORY;
452
0
              else {
453
0
                form = AddFormInfo(NULL, type, current_form);
454
0
                if(!form) {
455
0
                  free(type);
456
0
                  return_value = CURL_FORMADD_MEMORY;
457
0
                }
458
0
                else {
459
0
                  form->contenttype_alloc = TRUE;
460
0
                  current_form = form;
461
0
                  form = NULL;
462
0
                }
463
0
              }
464
0
            }
465
0
            else
466
0
              return_value = CURL_FORMADD_NULL;
467
0
          }
468
0
          else
469
0
            return_value = CURL_FORMADD_OPTION_TWICE;
470
0
        }
471
0
        else {
472
0
          if(contenttype) {
473
0
            current_form->contenttype = strdup(contenttype);
474
0
            if(!current_form->contenttype)
475
0
              return_value = CURL_FORMADD_MEMORY;
476
0
            else
477
0
              current_form->contenttype_alloc = TRUE;
478
0
          }
479
0
          else
480
0
            return_value = CURL_FORMADD_NULL;
481
0
        }
482
0
        break;
483
32
      }
484
0
    case CURLFORM_CONTENTHEADER:
485
0
      {
486
        /* this "cast increases required alignment of target type" but
487
           we consider it OK anyway */
488
0
        struct curl_slist *list = array_state?
489
0
          (struct curl_slist *)(void *)array_value:
490
0
          va_arg(params, struct curl_slist *);
491
492
0
        if(current_form->contentheader)
493
0
          return_value = CURL_FORMADD_OPTION_TWICE;
494
0
        else
495
0
          current_form->contentheader = list;
496
497
0
        break;
498
32
      }
499
0
    case CURLFORM_FILENAME:
500
0
    case CURLFORM_BUFFER:
501
0
      {
502
0
        const char *filename = array_state?array_value:
503
0
          va_arg(params, char *);
504
0
        if(current_form->showfilename)
505
0
          return_value = CURL_FORMADD_OPTION_TWICE;
506
0
        else {
507
0
          current_form->showfilename = strdup(filename);
508
0
          if(!current_form->showfilename)
509
0
            return_value = CURL_FORMADD_MEMORY;
510
0
          else
511
0
            current_form->showfilename_alloc = TRUE;
512
0
        }
513
0
        break;
514
0
      }
515
0
    default:
516
0
      return_value = CURL_FORMADD_UNKNOWN_OPTION;
517
0
      break;
518
96
    }
519
96
  }
520
521
32
  if(CURL_FORMADD_OK != return_value) {
522
    /* On error, free allocated fields for all nodes of the FormInfo linked
523
       list without deallocating nodes. List nodes are deallocated later on */
524
0
    struct FormInfo *ptr;
525
0
    for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
526
0
      if(ptr->name_alloc) {
527
0
        Curl_safefree(ptr->name);
528
0
        ptr->name_alloc = FALSE;
529
0
      }
530
0
      if(ptr->value_alloc) {
531
0
        Curl_safefree(ptr->value);
532
0
        ptr->value_alloc = FALSE;
533
0
      }
534
0
      if(ptr->contenttype_alloc) {
535
0
        Curl_safefree(ptr->contenttype);
536
0
        ptr->contenttype_alloc = FALSE;
537
0
      }
538
0
      if(ptr->showfilename_alloc) {
539
0
        Curl_safefree(ptr->showfilename);
540
0
        ptr->showfilename_alloc = FALSE;
541
0
      }
542
0
    }
543
0
  }
544
545
32
  if(CURL_FORMADD_OK == return_value) {
546
    /* go through the list, check for completeness and if everything is
547
     * alright add the HttpPost item otherwise set return_value accordingly */
548
549
32
    post = NULL;
550
32
    for(form = first_form;
551
64
        form != NULL;
552
32
        form = form->more) {
553
32
      if(((!form->name || !form->value) && !post) ||
554
32
         ( (form->contentslength) &&
555
32
           (form->flags & HTTPPOST_FILENAME) ) ||
556
32
         ( (form->flags & HTTPPOST_FILENAME) &&
557
32
           (form->flags & HTTPPOST_PTRCONTENTS) ) ||
558
559
32
         ( (!form->buffer) &&
560
32
           (form->flags & HTTPPOST_BUFFER) &&
561
32
           (form->flags & HTTPPOST_PTRBUFFER) ) ||
562
563
32
         ( (form->flags & HTTPPOST_READFILE) &&
564
32
           (form->flags & HTTPPOST_PTRCONTENTS) )
565
32
        ) {
566
0
        return_value = CURL_FORMADD_INCOMPLETE;
567
0
        break;
568
0
      }
569
32
      if(((form->flags & HTTPPOST_FILENAME) ||
570
32
          (form->flags & HTTPPOST_BUFFER)) &&
571
32
         !form->contenttype) {
572
0
        char *f = (form->flags & HTTPPOST_BUFFER)?
573
0
          form->showfilename : form->value;
574
0
        char const *type;
575
0
        type = Curl_mime_contenttype(f);
576
0
        if(!type)
577
0
          type = prevtype;
578
0
        if(!type)
579
0
          type = FILE_CONTENTTYPE_DEFAULT;
580
581
        /* our contenttype is missing */
582
0
        form->contenttype = strdup(type);
583
0
        if(!form->contenttype) {
584
0
          return_value = CURL_FORMADD_MEMORY;
585
0
          break;
586
0
        }
587
0
        form->contenttype_alloc = TRUE;
588
0
      }
589
32
      if(form->name && form->namelength) {
590
        /* Name should not contain nul bytes. */
591
0
        size_t i;
592
0
        for(i = 0; i < form->namelength; i++)
593
0
          if(!form->name[i]) {
594
0
            return_value = CURL_FORMADD_NULL;
595
0
            break;
596
0
          }
597
0
        if(return_value != CURL_FORMADD_OK)
598
0
          break;
599
0
      }
600
32
      if(!(form->flags & HTTPPOST_PTRNAME) &&
601
32
         (form == first_form) ) {
602
        /* Note that there's small risk that form->name is NULL here if the
603
           app passed in a bad combo, so we better check for that first. */
604
32
        if(form->name) {
605
          /* copy name (without strdup; possibly not null-terminated) */
606
32
          form->name = Curl_memdup(form->name, form->namelength?
607
0
                                   form->namelength:
608
32
                                   strlen(form->name) + 1);
609
32
        }
610
32
        if(!form->name) {
611
0
          return_value = CURL_FORMADD_MEMORY;
612
0
          break;
613
0
        }
614
32
        form->name_alloc = TRUE;
615
32
      }
616
32
      if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
617
32
                          HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
618
32
                          HTTPPOST_CALLBACK)) && form->value) {
619
        /* copy value (without strdup; possibly contains null characters) */
620
0
        size_t clen  = (size_t) form->contentslength;
621
0
        if(!clen)
622
0
          clen = strlen(form->value) + 1;
623
624
0
        form->value = Curl_memdup(form->value, clen);
625
626
0
        if(!form->value) {
627
0
          return_value = CURL_FORMADD_MEMORY;
628
0
          break;
629
0
        }
630
0
        form->value_alloc = TRUE;
631
0
      }
632
32
      post = AddHttpPost(form->name, form->namelength,
633
32
                         form->value, form->contentslength,
634
32
                         form->buffer, form->bufferlength,
635
32
                         form->contenttype, form->flags,
636
32
                         form->contentheader, form->showfilename,
637
32
                         form->userp,
638
32
                         post, httppost,
639
32
                         last_post);
640
641
32
      if(!post) {
642
0
        return_value = CURL_FORMADD_MEMORY;
643
0
        break;
644
0
      }
645
646
32
      if(form->contenttype)
647
0
        prevtype = form->contenttype;
648
32
    }
649
32
    if(CURL_FORMADD_OK != return_value) {
650
      /* On error, free allocated fields for nodes of the FormInfo linked
651
         list which are not already owned by the httppost linked list
652
         without deallocating nodes. List nodes are deallocated later on */
653
0
      struct FormInfo *ptr;
654
0
      for(ptr = form; ptr != NULL; ptr = ptr->more) {
655
0
        if(ptr->name_alloc) {
656
0
          Curl_safefree(ptr->name);
657
0
          ptr->name_alloc = FALSE;
658
0
        }
659
0
        if(ptr->value_alloc) {
660
0
          Curl_safefree(ptr->value);
661
0
          ptr->value_alloc = FALSE;
662
0
        }
663
0
        if(ptr->contenttype_alloc) {
664
0
          Curl_safefree(ptr->contenttype);
665
0
          ptr->contenttype_alloc = FALSE;
666
0
        }
667
0
        if(ptr->showfilename_alloc) {
668
0
          Curl_safefree(ptr->showfilename);
669
0
          ptr->showfilename_alloc = FALSE;
670
0
        }
671
0
      }
672
0
    }
673
32
  }
674
675
  /* Always deallocate FormInfo linked list nodes without touching node
676
     fields given that these have either been deallocated or are owned
677
     now by the httppost linked list */
678
64
  while(first_form) {
679
32
    struct FormInfo *ptr = first_form->more;
680
32
    free(first_form);
681
32
    first_form = ptr;
682
32
  }
683
684
32
  return return_value;
685
32
}
686
687
/*
688
 * curl_formadd() is a public API to add a section to the multipart formpost.
689
 *
690
 * @unittest: 1308
691
 */
692
693
CURLFORMcode curl_formadd(struct curl_httppost **httppost,
694
                          struct curl_httppost **last_post,
695
                          ...)
696
32
{
697
32
  va_list arg;
698
32
  CURLFORMcode result;
699
32
  va_start(arg, last_post);
700
32
  result = FormAdd(httppost, last_post, arg);
701
32
  va_end(arg);
702
32
  return result;
703
32
}
704
705
/*
706
 * curl_formget()
707
 * Serialize a curl_httppost struct.
708
 * Returns 0 on success.
709
 *
710
 * @unittest: 1308
711
 */
712
int curl_formget(struct curl_httppost *form, void *arg,
713
                 curl_formget_callback append)
714
0
{
715
0
  CURLcode result;
716
0
  curl_mimepart toppart;
717
718
0
  Curl_mime_initpart(&toppart); /* default form is empty */
719
0
  result = Curl_getformdata(NULL, &toppart, form, NULL);
720
0
  if(!result)
721
0
    result = Curl_mime_prepare_headers(NULL, &toppart, "multipart/form-data",
722
0
                                       NULL, MIMESTRATEGY_FORM);
723
724
0
  while(!result) {
725
0
    char buffer[8192];
726
0
    size_t nread = Curl_mime_read(buffer, 1, sizeof(buffer), &toppart);
727
728
0
    if(!nread)
729
0
      break;
730
731
0
    if(nread > sizeof(buffer) || append(arg, buffer, nread) != nread) {
732
0
      result = CURLE_READ_ERROR;
733
0
      if(nread == CURL_READFUNC_ABORT)
734
0
        result = CURLE_ABORTED_BY_CALLBACK;
735
0
    }
736
0
  }
737
738
0
  Curl_mime_cleanpart(&toppart);
739
0
  return (int) result;
740
0
}
741
742
/*
743
 * curl_formfree() is an external function to free up a whole form post
744
 * chain
745
 */
746
void curl_formfree(struct curl_httppost *form)
747
64
{
748
64
  struct curl_httppost *next;
749
750
64
  if(!form)
751
    /* no form to free, just get out of this */
752
32
    return;
753
754
32
  do {
755
32
    next = form->next;  /* the following form line */
756
757
    /* recurse to sub-contents */
758
32
    curl_formfree(form->more);
759
760
32
    if(!(form->flags & HTTPPOST_PTRNAME))
761
32
      free(form->name); /* free the name */
762
32
    if(!(form->flags &
763
32
         (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
764
32
      )
765
0
      free(form->contents); /* free the contents */
766
32
    free(form->contenttype); /* free the content type */
767
32
    free(form->showfilename); /* free the faked file name */
768
32
    free(form);       /* free the struct */
769
32
    form = next;
770
32
  } while(form); /* continue */
771
32
}
772
773
774
/* Set mime part name, taking care of non null-terminated name string. */
775
static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
776
0
{
777
0
  char *zname;
778
0
  CURLcode res;
779
780
0
  if(!name || !len)
781
0
    return curl_mime_name(part, name);
782
0
  zname = malloc(len + 1);
783
0
  if(!zname)
784
0
    return CURLE_OUT_OF_MEMORY;
785
0
  memcpy(zname, name, len);
786
0
  zname[len] = '\0';
787
0
  res = curl_mime_name(part, zname);
788
0
  free(zname);
789
0
  return res;
790
0
}
791
792
/*
793
 * Curl_getformdata() converts a linked list of "meta data" into a mime
794
 * structure. The input list is in 'post', while the output is stored in
795
 * mime part at '*finalform'.
796
 *
797
 * This function will not do a failf() for the potential memory failures but
798
 * should for all other errors it spots. Just note that this function MAY get
799
 * a NULL pointer in the 'data' argument.
800
 */
801
802
CURLcode Curl_getformdata(struct Curl_easy *data,
803
                          curl_mimepart *finalform,
804
                          struct curl_httppost *post,
805
                          curl_read_callback fread_func)
806
0
{
807
0
  CURLcode result = CURLE_OK;
808
0
  curl_mime *form = NULL;
809
0
  curl_mimepart *part;
810
0
  struct curl_httppost *file;
811
812
0
  Curl_mime_cleanpart(finalform); /* default form is empty */
813
814
0
  if(!post)
815
0
    return result; /* no input => no output! */
816
817
0
  form = curl_mime_init(data);
818
0
  if(!form)
819
0
    result = CURLE_OUT_OF_MEMORY;
820
821
0
  if(!result)
822
0
    result = curl_mime_subparts(finalform, form);
823
824
  /* Process each top part. */
825
0
  for(; !result && post; post = post->next) {
826
    /* If we have more than a file here, create a mime subpart and fill it. */
827
0
    curl_mime *multipart = form;
828
0
    if(post->more) {
829
0
      part = curl_mime_addpart(form);
830
0
      if(!part)
831
0
        result = CURLE_OUT_OF_MEMORY;
832
0
      if(!result)
833
0
        result = setname(part, post->name, post->namelength);
834
0
      if(!result) {
835
0
        multipart = curl_mime_init(data);
836
0
        if(!multipart)
837
0
          result = CURLE_OUT_OF_MEMORY;
838
0
      }
839
0
      if(!result)
840
0
        result = curl_mime_subparts(part, multipart);
841
0
    }
842
843
    /* Generate all the part contents. */
844
0
    for(file = post; !result && file; file = file->more) {
845
      /* Create the part. */
846
0
      part = curl_mime_addpart(multipart);
847
0
      if(!part)
848
0
        result = CURLE_OUT_OF_MEMORY;
849
850
      /* Set the headers. */
851
0
      if(!result)
852
0
        result = curl_mime_headers(part, file->contentheader, 0);
853
854
      /* Set the content type. */
855
0
      if(!result && file->contenttype)
856
0
        result = curl_mime_type(part, file->contenttype);
857
858
      /* Set field name. */
859
0
      if(!result && !post->more)
860
0
        result = setname(part, post->name, post->namelength);
861
862
      /* Process contents. */
863
0
      if(!result) {
864
0
        curl_off_t clen = post->contentslength;
865
866
0
        if(post->flags & CURL_HTTPPOST_LARGE)
867
0
          clen = post->contentlen;
868
869
0
        if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
870
0
          if(!strcmp(file->contents, "-")) {
871
            /* There are a few cases where the code below won't work; in
872
               particular, freopen(stdin) by the caller is not guaranteed
873
               to result as expected. This feature has been kept for backward
874
               compatibility: use of "-" pseudo file name should be avoided. */
875
0
            result = curl_mime_data_cb(part, (curl_off_t) -1,
876
0
                                       (curl_read_callback) fread,
877
0
                                       CURLX_FUNCTION_CAST(curl_seek_callback,
878
0
                                                           fseek),
879
0
                                       NULL, (void *) stdin);
880
0
          }
881
0
          else
882
0
            result = curl_mime_filedata(part, file->contents);
883
0
          if(!result && (post->flags & HTTPPOST_READFILE))
884
0
            result = curl_mime_filename(part, NULL);
885
0
        }
886
0
        else if(post->flags & HTTPPOST_BUFFER)
887
0
          result = curl_mime_data(part, post->buffer,
888
0
                                  post->bufferlength? post->bufferlength: -1);
889
0
        else if(post->flags & HTTPPOST_CALLBACK) {
890
          /* the contents should be read with the callback and the size is set
891
             with the contentslength */
892
0
          if(!clen)
893
0
            clen = -1;
894
0
          result = curl_mime_data_cb(part, clen,
895
0
                                     fread_func, NULL, NULL, post->userp);
896
0
        }
897
0
        else {
898
0
          size_t uclen;
899
0
          if(!clen)
900
0
            uclen = CURL_ZERO_TERMINATED;
901
0
          else
902
0
            uclen = (size_t)clen;
903
0
          result = curl_mime_data(part, post->contents, uclen);
904
0
        }
905
0
      }
906
907
      /* Set fake file name. */
908
0
      if(!result && post->showfilename)
909
0
        if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
910
0
                                        HTTPPOST_CALLBACK)))
911
0
          result = curl_mime_filename(part, post->showfilename);
912
0
    }
913
0
  }
914
915
0
  if(result)
916
0
    Curl_mime_cleanpart(finalform);
917
918
0
  return result;
919
0
}
920
921
#else
922
/* if disabled */
923
CURLFORMcode curl_formadd(struct curl_httppost **httppost,
924
                          struct curl_httppost **last_post,
925
                          ...)
926
{
927
  (void)httppost;
928
  (void)last_post;
929
  return CURL_FORMADD_DISABLED;
930
}
931
932
int curl_formget(struct curl_httppost *form, void *arg,
933
                 curl_formget_callback append)
934
{
935
  (void) form;
936
  (void) arg;
937
  (void) append;
938
  return CURL_FORMADD_DISABLED;
939
}
940
941
void curl_formfree(struct curl_httppost *form)
942
{
943
  (void)form;
944
  /* does nothing HTTP is disabled */
945
}
946
947
#endif  /* if disabled */