Coverage Report

Created: 2023-12-08 06:48

/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_FORM_API)
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
58
#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
51
98
#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
52
87
#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
53
58
#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
54
29
#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
55
58
#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
56
87
#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
29
{
80
29
  struct curl_httppost *post;
81
29
  if(!namelength && name)
82
29
    namelength = strlen(name);
83
29
  if((bufferlength > LONG_MAX) || (namelength > LONG_MAX))
84
    /* avoid overflow in typecasts below */
85
0
    return NULL;
86
29
  post = calloc(1, sizeof(struct curl_httppost));
87
29
  if(post) {
88
29
    post->name = name;
89
29
    post->namelength = (long)namelength;
90
29
    post->contents = value;
91
29
    post->contentlen = contentslength;
92
29
    post->buffer = buffer;
93
29
    post->bufferlength = (long)bufferlength;
94
29
    post->contenttype = contenttype;
95
29
    post->contentheader = contentHeader;
96
29
    post->showfilename = showfilename;
97
29
    post->userp = userp;
98
29
    post->flags = flags | CURL_HTTPPOST_LARGE;
99
29
  }
100
0
  else
101
0
    return NULL;
102
103
29
  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
29
  else {
111
    /* make the previous point to this */
112
29
    if(*last_post)
113
0
      (*last_post)->next = post;
114
29
    else
115
29
      (*httppost) = post;
116
117
29
    (*last_post) = post;
118
29
  }
119
29
  return post;
120
29
}
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
29
{
211
29
  struct FormInfo *first_form, *current_form, *form = NULL;
212
29
  CURLFORMcode return_value = CURL_FORMADD_OK;
213
29
  const char *prevtype = NULL;
214
29
  struct curl_httppost *post = NULL;
215
29
  CURLformoption option;
216
29
  struct curl_forms *forms = NULL;
217
29
  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
29
  bool array_state = FALSE;
223
224
  /*
225
   * We need to allocate the first struct to fill in.
226
   */
227
29
  first_form = calloc(1, sizeof(struct FormInfo));
228
29
  if(!first_form)
229
0
    return CURL_FORMADD_MEMORY;
230
231
29
  current_form = first_form;
232
233
  /*
234
   * Loop through all the options set. Break if we have an error to report.
235
   */
236
116
  while(return_value == CURL_FORMADD_OK) {
237
238
    /* first see if we have more parts of the array param */
239
116
    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
116
    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
116
      option = (CURLformoption)va_arg(params, int);
256
116
      if(CURLFORM_END == option)
257
29
        break;
258
116
    }
259
260
87
    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
29
    case CURLFORM_COPYNAME:
282
29
      if(current_form->name)
283
0
        return_value = CURL_FORMADD_OPTION_TWICE;
284
29
      else {
285
29
        char *name = array_state?
286
0
          array_value:va_arg(params, char *);
287
29
        if(name)
288
29
          current_form->name = name; /* store for the moment */
289
0
        else
290
0
          return_value = CURL_FORMADD_NULL;
291
29
      }
292
29
      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
29
    case CURLFORM_PTRCONTENTS:
305
29
      current_form->flags |= HTTPPOST_PTRCONTENTS;
306
      /* FALLTHROUGH */
307
29
    case CURLFORM_COPYCONTENTS:
308
29
      if(current_form->value)
309
0
        return_value = CURL_FORMADD_OPTION_TWICE;
310
29
      else {
311
29
        char *value =
312
29
          array_state?array_value:va_arg(params, char *);
313
29
        if(value)
314
29
          current_form->value = value; /* store for the moment */
315
0
        else
316
0
          return_value = CURL_FORMADD_NULL;
317
29
      }
318
29
      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
29
    case CURLFORM_CONTENTLEN:
325
29
      current_form->flags |= CURL_HTTPPOST_LARGE;
326
29
      current_form->contentslength =
327
29
        array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
328
29
      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
29
      }
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
29
      }
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
29
      }
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
87
    }
519
87
  }
520
521
29
  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
29
  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
29
    post = NULL;
550
29
    for(form = first_form;
551
58
        form != NULL;
552
29
        form = form->more) {
553
29
      if(((!form->name || !form->value) && !post) ||
554
29
         ( (form->contentslength) &&
555
29
           (form->flags & HTTPPOST_FILENAME) ) ||
556
29
         ( (form->flags & HTTPPOST_FILENAME) &&
557
29
           (form->flags & HTTPPOST_PTRCONTENTS) ) ||
558
559
29
         ( (!form->buffer) &&
560
29
           (form->flags & HTTPPOST_BUFFER) &&
561
29
           (form->flags & HTTPPOST_PTRBUFFER) ) ||
562
563
29
         ( (form->flags & HTTPPOST_READFILE) &&
564
29
           (form->flags & HTTPPOST_PTRCONTENTS) )
565
29
        ) {
566
0
        return_value = CURL_FORMADD_INCOMPLETE;
567
0
        break;
568
0
      }
569
29
      if(((form->flags & HTTPPOST_FILENAME) ||
570
29
          (form->flags & HTTPPOST_BUFFER)) &&
571
29
         !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
29
      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
29
      if(!(form->flags & HTTPPOST_PTRNAME) &&
601
29
         (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
29
        if(form->name) {
605
          /* copy name (without strdup; possibly not null-terminated) */
606
29
          form->name = Curl_strndup(form->name, form->namelength?
607
0
                                    form->namelength:
608
29
                                    strlen(form->name));
609
29
        }
610
29
        if(!form->name) {
611
0
          return_value = CURL_FORMADD_MEMORY;
612
0
          break;
613
0
        }
614
29
        form->name_alloc = TRUE;
615
29
      }
616
29
      if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
617
29
                          HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
618
29
                          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
29
      post = AddHttpPost(form->name, form->namelength,
633
29
                         form->value, form->contentslength,
634
29
                         form->buffer, form->bufferlength,
635
29
                         form->contenttype, form->flags,
636
29
                         form->contentheader, form->showfilename,
637
29
                         form->userp,
638
29
                         post, httppost,
639
29
                         last_post);
640
641
29
      if(!post) {
642
0
        return_value = CURL_FORMADD_MEMORY;
643
0
        break;
644
0
      }
645
646
29
      if(form->contenttype)
647
0
        prevtype = form->contenttype;
648
29
    }
649
29
    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
29
  }
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
58
  while(first_form) {
679
29
    struct FormInfo *ptr = first_form->more;
680
29
    free(first_form);
681
29
    first_form = ptr;
682
29
  }
683
684
29
  return return_value;
685
29
}
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
29
{
697
29
  va_list arg;
698
29
  CURLFORMcode result;
699
29
  va_start(arg, last_post);
700
29
  result = FormAdd(httppost, last_post, arg);
701
29
  va_end(arg);
702
29
  return result;
703
29
}
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
58
{
748
58
  struct curl_httppost *next;
749
750
58
  if(!form)
751
    /* no form to free, just get out of this */
752
29
    return;
753
754
29
  do {
755
29
    next = form->next;  /* the following form line */
756
757
    /* recurse to sub-contents */
758
29
    curl_formfree(form->more);
759
760
29
    if(!(form->flags & HTTPPOST_PTRNAME))
761
29
      free(form->name); /* free the name */
762
29
    if(!(form->flags &
763
29
         (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
764
29
      )
765
0
      free(form->contents); /* free the contents */
766
29
    free(form->contenttype); /* free the content type */
767
29
    free(form->showfilename); /* free the faked file name */
768
29
    free(form);       /* free the struct */
769
29
    form = next;
770
29
  } while(form); /* continue */
771
29
}
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 = Curl_strndup(name, len);
783
0
  if(!zname)
784
0
    return CURLE_OUT_OF_MEMORY;
785
0
  res = curl_mime_name(part, zname);
786
0
  free(zname);
787
0
  return res;
788
0
}
789
790
/* wrap call to fseeko so it matches the calling convention of callback */
791
static int fseeko_wrapper(void *stream, curl_off_t offset, int whence)
792
0
{
793
0
#if defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO)
794
0
  return fseeko(stream, (off_t)offset, whence);
795
#elif defined(HAVE__FSEEKI64)
796
  return _fseeki64(stream, (__int64)offset, whence);
797
#else
798
  if(offset > LONG_MAX)
799
    return -1;
800
  return fseek(stream, (long)offset, whence);
801
#endif
802
0
}
803
804
/*
805
 * Curl_getformdata() converts a linked list of "meta data" into a mime
806
 * structure. The input list is in 'post', while the output is stored in
807
 * mime part at '*finalform'.
808
 *
809
 * This function will not do a failf() for the potential memory failures but
810
 * should for all other errors it spots. Just note that this function MAY get
811
 * a NULL pointer in the 'data' argument.
812
 */
813
814
CURLcode Curl_getformdata(struct Curl_easy *data,
815
                          curl_mimepart *finalform,
816
                          struct curl_httppost *post,
817
                          curl_read_callback fread_func)
818
0
{
819
0
  CURLcode result = CURLE_OK;
820
0
  curl_mime *form = NULL;
821
0
  curl_mimepart *part;
822
0
  struct curl_httppost *file;
823
824
0
  Curl_mime_cleanpart(finalform); /* default form is empty */
825
826
0
  if(!post)
827
0
    return result; /* no input => no output! */
828
829
0
  form = curl_mime_init(data);
830
0
  if(!form)
831
0
    result = CURLE_OUT_OF_MEMORY;
832
833
0
  if(!result)
834
0
    result = curl_mime_subparts(finalform, form);
835
836
  /* Process each top part. */
837
0
  for(; !result && post; post = post->next) {
838
    /* If we have more than a file here, create a mime subpart and fill it. */
839
0
    curl_mime *multipart = form;
840
0
    if(post->more) {
841
0
      part = curl_mime_addpart(form);
842
0
      if(!part)
843
0
        result = CURLE_OUT_OF_MEMORY;
844
0
      if(!result)
845
0
        result = setname(part, post->name, post->namelength);
846
0
      if(!result) {
847
0
        multipart = curl_mime_init(data);
848
0
        if(!multipart)
849
0
          result = CURLE_OUT_OF_MEMORY;
850
0
      }
851
0
      if(!result)
852
0
        result = curl_mime_subparts(part, multipart);
853
0
    }
854
855
    /* Generate all the part contents. */
856
0
    for(file = post; !result && file; file = file->more) {
857
      /* Create the part. */
858
0
      part = curl_mime_addpart(multipart);
859
0
      if(!part)
860
0
        result = CURLE_OUT_OF_MEMORY;
861
862
      /* Set the headers. */
863
0
      if(!result)
864
0
        result = curl_mime_headers(part, file->contentheader, 0);
865
866
      /* Set the content type. */
867
0
      if(!result && file->contenttype)
868
0
        result = curl_mime_type(part, file->contenttype);
869
870
      /* Set field name. */
871
0
      if(!result && !post->more)
872
0
        result = setname(part, post->name, post->namelength);
873
874
      /* Process contents. */
875
0
      if(!result) {
876
0
        curl_off_t clen = post->contentslength;
877
878
0
        if(post->flags & CURL_HTTPPOST_LARGE)
879
0
          clen = post->contentlen;
880
881
0
        if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
882
0
          if(!strcmp(file->contents, "-")) {
883
            /* There are a few cases where the code below won't work; in
884
               particular, freopen(stdin) by the caller is not guaranteed
885
               to result as expected. This feature has been kept for backward
886
               compatibility: use of "-" pseudo file name should be avoided. */
887
0
            result = curl_mime_data_cb(part, (curl_off_t) -1,
888
0
                                       (curl_read_callback) fread,
889
0
                                       fseeko_wrapper,
890
0
                                       NULL, (void *) stdin);
891
0
          }
892
0
          else
893
0
            result = curl_mime_filedata(part, file->contents);
894
0
          if(!result && (post->flags & HTTPPOST_READFILE))
895
0
            result = curl_mime_filename(part, NULL);
896
0
        }
897
0
        else if(post->flags & HTTPPOST_BUFFER)
898
0
          result = curl_mime_data(part, post->buffer,
899
0
                                  post->bufferlength? post->bufferlength: -1);
900
0
        else if(post->flags & HTTPPOST_CALLBACK) {
901
          /* the contents should be read with the callback and the size is set
902
             with the contentslength */
903
0
          if(!clen)
904
0
            clen = -1;
905
0
          result = curl_mime_data_cb(part, clen,
906
0
                                     fread_func, NULL, NULL, post->userp);
907
0
        }
908
0
        else {
909
0
          size_t uclen;
910
0
          if(!clen)
911
0
            uclen = CURL_ZERO_TERMINATED;
912
0
          else
913
0
            uclen = (size_t)clen;
914
0
          result = curl_mime_data(part, post->contents, uclen);
915
0
        }
916
0
      }
917
918
      /* Set fake file name. */
919
0
      if(!result && post->showfilename)
920
0
        if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
921
0
                                        HTTPPOST_CALLBACK)))
922
0
          result = curl_mime_filename(part, post->showfilename);
923
0
    }
924
0
  }
925
926
0
  if(result)
927
0
    Curl_mime_cleanpart(finalform);
928
929
0
  return result;
930
0
}
931
932
#else
933
/* if disabled */
934
CURLFORMcode curl_formadd(struct curl_httppost **httppost,
935
                          struct curl_httppost **last_post,
936
                          ...)
937
{
938
  (void)httppost;
939
  (void)last_post;
940
  return CURL_FORMADD_DISABLED;
941
}
942
943
int curl_formget(struct curl_httppost *form, void *arg,
944
                 curl_formget_callback append)
945
{
946
  (void) form;
947
  (void) arg;
948
  (void) append;
949
  return CURL_FORMADD_DISABLED;
950
}
951
952
void curl_formfree(struct curl_httppost *form)
953
{
954
  (void)form;
955
  /* Nothing to do. */
956
}
957
958
#endif  /* if disabled */