Coverage Report

Created: 2024-02-25 06:14

/src/PROJ/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
0
#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
51
0
#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
52
0
#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
53
0
#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
54
0
#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
55
0
#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
56
0
#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
0
{
80
0
  struct curl_httppost *post;
81
0
  if(!namelength && name)
82
0
    namelength = strlen(name);
83
0
  if((bufferlength > LONG_MAX) || (namelength > LONG_MAX))
84
    /* avoid overflow in typecasts below */
85
0
    return NULL;
86
0
  post = calloc(1, sizeof(struct curl_httppost));
87
0
  if(post) {
88
0
    post->name = name;
89
0
    post->namelength = (long)namelength;
90
0
    post->contents = value;
91
0
    post->contentlen = contentslength;
92
0
    post->buffer = buffer;
93
0
    post->bufferlength = (long)bufferlength;
94
0
    post->contenttype = contenttype;
95
0
    post->contentheader = contentHeader;
96
0
    post->showfilename = showfilename;
97
0
    post->userp = userp;
98
0
    post->flags = flags | CURL_HTTPPOST_LARGE;
99
0
  }
100
0
  else
101
0
    return NULL;
102
103
0
  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
0
  else {
111
    /* make the previous point to this */
112
0
    if(*last_post)
113
0
      (*last_post)->next = post;
114
0
    else
115
0
      (*httppost) = post;
116
117
0
    (*last_post) = post;
118
0
  }
119
0
  return post;
120
0
}
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
0
{
211
0
  struct FormInfo *first_form, *current_form, *form = NULL;
212
0
  CURLFORMcode return_value = CURL_FORMADD_OK;
213
0
  const char *prevtype = NULL;
214
0
  struct curl_httppost *post = NULL;
215
0
  CURLformoption option;
216
0
  struct curl_forms *forms = NULL;
217
0
  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
0
  bool array_state = FALSE;
223
224
  /*
225
   * We need to allocate the first struct to fill in.
226
   */
227
0
  first_form = calloc(1, sizeof(struct FormInfo));
228
0
  if(!first_form)
229
0
    return CURL_FORMADD_MEMORY;
230
231
0
  current_form = first_form;
232
233
  /*
234
   * Loop through all the options set. Break if we have an error to report.
235
   */
236
0
  while(return_value == CURL_FORMADD_OK) {
237
238
    /* first see if we have more parts of the array param */
239
0
    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
0
    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
0
      option = (CURLformoption)va_arg(params, int);
256
0
      if(CURLFORM_END == option)
257
0
        break;
258
0
    }
259
260
0
    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
0
      FALLTHROUGH();
281
0
    case CURLFORM_COPYNAME:
282
0
      if(current_form->name)
283
0
        return_value = CURL_FORMADD_OPTION_TWICE;
284
0
      else {
285
0
        char *name = array_state?
286
0
          array_value:va_arg(params, char *);
287
0
        if(name)
288
0
          current_form->name = name; /* store for the moment */
289
0
        else
290
0
          return_value = CURL_FORMADD_NULL;
291
0
      }
292
0
      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
0
    case CURLFORM_PTRCONTENTS:
305
0
      current_form->flags |= HTTPPOST_PTRCONTENTS;
306
0
      FALLTHROUGH();
307
0
    case CURLFORM_COPYCONTENTS:
308
0
      if(current_form->value)
309
0
        return_value = CURL_FORMADD_OPTION_TWICE;
310
0
      else {
311
0
        char *value =
312
0
          array_state?array_value:va_arg(params, char *);
313
0
        if(value)
314
0
          current_form->value = value; /* store for the moment */
315
0
        else
316
0
          return_value = CURL_FORMADD_NULL;
317
0
      }
318
0
      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
0
    case CURLFORM_CONTENTLEN:
325
0
      current_form->flags |= CURL_HTTPPOST_LARGE;
326
0
      current_form->contentslength =
327
0
        array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
328
0
      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
0
      }
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
0
      }
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
0
      }
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
0
    }
519
0
  }
520
521
0
  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
0
  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
0
    post = NULL;
550
0
    for(form = first_form;
551
0
        form != NULL;
552
0
        form = form->more) {
553
0
      if(((!form->name || !form->value) && !post) ||
554
0
         ( (form->contentslength) &&
555
0
           (form->flags & HTTPPOST_FILENAME) ) ||
556
0
         ( (form->flags & HTTPPOST_FILENAME) &&
557
0
           (form->flags & HTTPPOST_PTRCONTENTS) ) ||
558
559
0
         ( (!form->buffer) &&
560
0
           (form->flags & HTTPPOST_BUFFER) &&
561
0
           (form->flags & HTTPPOST_PTRBUFFER) ) ||
562
563
0
         ( (form->flags & HTTPPOST_READFILE) &&
564
0
           (form->flags & HTTPPOST_PTRCONTENTS) )
565
0
        ) {
566
0
        return_value = CURL_FORMADD_INCOMPLETE;
567
0
        break;
568
0
      }
569
0
      if(((form->flags & HTTPPOST_FILENAME) ||
570
0
          (form->flags & HTTPPOST_BUFFER)) &&
571
0
         !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
0
      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
0
      if(!(form->flags & HTTPPOST_PTRNAME) &&
601
0
         (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
0
        if(form->name) {
605
          /* copy name (without strdup; possibly not null-terminated) */
606
0
          form->name = Curl_memdup0(form->name, form->namelength?
607
0
                                    form->namelength:
608
0
                                    strlen(form->name));
609
0
        }
610
0
        if(!form->name) {
611
0
          return_value = CURL_FORMADD_MEMORY;
612
0
          break;
613
0
        }
614
0
        form->name_alloc = TRUE;
615
0
      }
616
0
      if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
617
0
                          HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
618
0
                          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
0
      post = AddHttpPost(form->name, form->namelength,
633
0
                         form->value, form->contentslength,
634
0
                         form->buffer, form->bufferlength,
635
0
                         form->contenttype, form->flags,
636
0
                         form->contentheader, form->showfilename,
637
0
                         form->userp,
638
0
                         post, httppost,
639
0
                         last_post);
640
641
0
      if(!post) {
642
0
        return_value = CURL_FORMADD_MEMORY;
643
0
        break;
644
0
      }
645
646
0
      if(form->contenttype)
647
0
        prevtype = form->contenttype;
648
0
    }
649
0
    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
0
  }
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
0
  while(first_form) {
679
0
    struct FormInfo *ptr = first_form->more;
680
0
    free(first_form);
681
0
    first_form = ptr;
682
0
  }
683
684
0
  return return_value;
685
0
}
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
0
{
697
0
  va_list arg;
698
0
  CURLFORMcode result;
699
0
  va_start(arg, last_post);
700
0
  result = FormAdd(httppost, last_post, arg);
701
0
  va_end(arg);
702
0
  return result;
703
0
}
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
0
{
748
0
  struct curl_httppost *next;
749
750
0
  if(!form)
751
    /* no form to free, just get out of this */
752
0
    return;
753
754
0
  do {
755
0
    next = form->next;  /* the following form line */
756
757
    /* recurse to sub-contents */
758
0
    curl_formfree(form->more);
759
760
0
    if(!(form->flags & HTTPPOST_PTRNAME))
761
0
      free(form->name); /* free the name */
762
0
    if(!(form->flags &
763
0
         (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
764
0
      )
765
0
      free(form->contents); /* free the contents */
766
0
    free(form->contenttype); /* free the content type */
767
0
    free(form->showfilename); /* free the faked file name */
768
0
    free(form);       /* free the struct */
769
0
    form = next;
770
0
  } while(form); /* continue */
771
0
}
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_memdup0(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 */