formdata.c revision e6cd738ed3716c02557fb3a47515244e949ade39
1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2015, 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 http://curl.haxx.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 ***************************************************************************/
22
23#include "curl_setup.h"
24
25#include <curl/curl.h>
26
27#ifndef CURL_DISABLE_HTTP
28
29#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
30#include <libgen.h>
31#endif
32
33#include "urldata.h" /* for struct SessionHandle */
34#include "formdata.h"
35#include "vtls/vtls.h"
36#include "strequal.h"
37#include "sendf.h"
38#include "strdup.h"
39#include "curl_printf.h"
40
41/* The last #include files should be: */
42#include "curl_memory.h"
43#include "memdebug.h"
44
45#ifndef HAVE_BASENAME
46static char *Curl_basename(char *path);
47#define basename(x)  Curl_basename((x))
48#endif
49
50static size_t readfromfile(struct Form *form, char *buffer, size_t size);
51static char *formboundary(struct SessionHandle *data);
52
53/* What kind of Content-Type to use on un-specified files with unrecognized
54   extensions. */
55#define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
56
57#define FORM_FILE_SEPARATOR ','
58#define FORM_TYPE_SEPARATOR ';'
59
60/***************************************************************************
61 *
62 * AddHttpPost()
63 *
64 * Adds a HttpPost structure to the list, if parent_post is given becomes
65 * a subpost of parent_post instead of a direct list element.
66 *
67 * Returns newly allocated HttpPost on success and NULL if malloc failed.
68 *
69 ***************************************************************************/
70static struct curl_httppost *
71AddHttpPost(char *name, size_t namelength,
72            char *value, size_t contentslength,
73            char *buffer, size_t bufferlength,
74            char *contenttype,
75            long flags,
76            struct curl_slist* contentHeader,
77            char *showfilename, char *userp,
78            struct curl_httppost *parent_post,
79            struct curl_httppost **httppost,
80            struct curl_httppost **last_post)
81{
82  struct curl_httppost *post;
83  post = calloc(1, sizeof(struct curl_httppost));
84  if(post) {
85    post->name = name;
86    post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
87    post->contents = value;
88    post->contentslength = (long)contentslength;
89    post->buffer = buffer;
90    post->bufferlength = (long)bufferlength;
91    post->contenttype = contenttype;
92    post->contentheader = contentHeader;
93    post->showfilename = showfilename;
94    post->userp = userp,
95    post->flags = flags;
96  }
97  else
98    return NULL;
99
100  if(parent_post) {
101    /* now, point our 'more' to the original 'more' */
102    post->more = parent_post->more;
103
104    /* then move the original 'more' to point to ourselves */
105    parent_post->more = post;
106  }
107  else {
108    /* make the previous point to this */
109    if(*last_post)
110      (*last_post)->next = post;
111    else
112      (*httppost) = post;
113
114    (*last_post) = post;
115  }
116  return post;
117}
118
119/***************************************************************************
120 *
121 * AddFormInfo()
122 *
123 * Adds a FormInfo structure to the list presented by parent_form_info.
124 *
125 * Returns newly allocated FormInfo on success and NULL if malloc failed/
126 * parent_form_info is NULL.
127 *
128 ***************************************************************************/
129static FormInfo * AddFormInfo(char *value,
130                              char *contenttype,
131                              FormInfo *parent_form_info)
132{
133  FormInfo *form_info;
134  form_info = calloc(1, sizeof(struct FormInfo));
135  if(form_info) {
136    if(value)
137      form_info->value = value;
138    if(contenttype)
139      form_info->contenttype = contenttype;
140    form_info->flags = HTTPPOST_FILENAME;
141  }
142  else
143    return NULL;
144
145  if(parent_form_info) {
146    /* now, point our 'more' to the original 'more' */
147    form_info->more = parent_form_info->more;
148
149    /* then move the original 'more' to point to ourselves */
150    parent_form_info->more = form_info;
151  }
152
153  return form_info;
154}
155
156/***************************************************************************
157 *
158 * ContentTypeForFilename()
159 *
160 * Provides content type for filename if one of the known types (else
161 * (either the prevtype or the default is returned).
162 *
163 * Returns some valid contenttype for filename.
164 *
165 ***************************************************************************/
166static const char *ContentTypeForFilename(const char *filename,
167                                          const char *prevtype)
168{
169  const char *contenttype = NULL;
170  unsigned int i;
171  /*
172   * No type was specified, we scan through a few well-known
173   * extensions and pick the first we match!
174   */
175  struct ContentType {
176    const char *extension;
177    const char *type;
178  };
179  static const struct ContentType ctts[]={
180    {".gif",  "image/gif"},
181    {".jpg",  "image/jpeg"},
182    {".jpeg", "image/jpeg"},
183    {".txt",  "text/plain"},
184    {".html", "text/html"},
185    {".xml", "application/xml"}
186  };
187
188  if(prevtype)
189    /* default to the previously set/used! */
190    contenttype = prevtype;
191  else
192    contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
193
194  if(filename) { /* in case a NULL was passed in */
195    for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
196      if(strlen(filename) >= strlen(ctts[i].extension)) {
197        if(strequal(filename +
198                    strlen(filename) - strlen(ctts[i].extension),
199                    ctts[i].extension)) {
200          contenttype = ctts[i].type;
201          break;
202        }
203      }
204    }
205  }
206  /* we have a contenttype by now */
207  return contenttype;
208}
209
210/***************************************************************************
211 *
212 * FormAdd()
213 *
214 * Stores a formpost parameter and builds the appropriate linked list.
215 *
216 * Has two principal functionalities: using files and byte arrays as
217 * post parts. Byte arrays are either copied or just the pointer is stored
218 * (as the user requests) while for files only the filename and not the
219 * content is stored.
220 *
221 * While you may have only one byte array for each name, multiple filenames
222 * are allowed (and because of this feature CURLFORM_END is needed after
223 * using CURLFORM_FILE).
224 *
225 * Examples:
226 *
227 * Simple name/value pair with copied contents:
228 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
229 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
230 *
231 * name/value pair where only the content pointer is remembered:
232 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
233 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
234 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
235 *
236 * storing a filename (CONTENTTYPE is optional!):
237 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
238 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
239 * CURLFORM_END);
240 *
241 * storing multiple filenames:
242 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
243 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
244 *
245 * Returns:
246 * CURL_FORMADD_OK             on success
247 * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
248 * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
249 * CURL_FORMADD_NULL           if a null pointer was given for a char
250 * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
251 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
252 * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
253 * CURL_FORMADD_MEMORY         if a HttpPost struct cannot be allocated
254 * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
255 * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
256 *
257 ***************************************************************************/
258
259static
260CURLFORMcode FormAdd(struct curl_httppost **httppost,
261                     struct curl_httppost **last_post,
262                     va_list params)
263{
264  FormInfo *first_form, *current_form, *form = NULL;
265  CURLFORMcode return_value = CURL_FORMADD_OK;
266  const char *prevtype = NULL;
267  struct curl_httppost *post = NULL;
268  CURLformoption option;
269  struct curl_forms *forms = NULL;
270  char *array_value=NULL; /* value read from an array */
271
272  /* This is a state variable, that if TRUE means that we're parsing an
273     array that we got passed to us. If FALSE we're parsing the input
274     va_list arguments. */
275  bool array_state = FALSE;
276
277  /*
278   * We need to allocate the first struct to fill in.
279   */
280  first_form = calloc(1, sizeof(struct FormInfo));
281  if(!first_form)
282    return CURL_FORMADD_MEMORY;
283
284  current_form = first_form;
285
286  /*
287   * Loop through all the options set. Break if we have an error to report.
288   */
289  while(return_value == CURL_FORMADD_OK) {
290
291    /* first see if we have more parts of the array param */
292    if(array_state && forms) {
293      /* get the upcoming option from the given array */
294      option = forms->option;
295      array_value = (char *)forms->value;
296
297      forms++; /* advance this to next entry */
298      if(CURLFORM_END == option) {
299        /* end of array state */
300        array_state = FALSE;
301        continue;
302      }
303    }
304    else {
305      /* This is not array-state, get next option */
306      option = va_arg(params, CURLformoption);
307      if(CURLFORM_END == option)
308        break;
309    }
310
311    switch (option) {
312    case CURLFORM_ARRAY:
313      if(array_state)
314        /* we don't support an array from within an array */
315        return_value = CURL_FORMADD_ILLEGAL_ARRAY;
316      else {
317        forms = va_arg(params, struct curl_forms *);
318        if(forms)
319          array_state = TRUE;
320        else
321          return_value = CURL_FORMADD_NULL;
322      }
323      break;
324
325      /*
326       * Set the Name property.
327       */
328    case CURLFORM_PTRNAME:
329#ifdef CURL_DOES_CONVERSIONS
330      /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
331       * the data in all cases so that we'll have safe memory for the eventual
332       * conversion.
333       */
334#else
335      current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
336#endif
337    case CURLFORM_COPYNAME:
338      if(current_form->name)
339        return_value = CURL_FORMADD_OPTION_TWICE;
340      else {
341        char *name = array_state?
342          array_value:va_arg(params, char *);
343        if(name)
344          current_form->name = name; /* store for the moment */
345        else
346          return_value = CURL_FORMADD_NULL;
347      }
348      break;
349    case CURLFORM_NAMELENGTH:
350      if(current_form->namelength)
351        return_value = CURL_FORMADD_OPTION_TWICE;
352      else
353        current_form->namelength =
354          array_state?(size_t)array_value:(size_t)va_arg(params, long);
355      break;
356
357      /*
358       * Set the contents property.
359       */
360    case CURLFORM_PTRCONTENTS:
361      current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
362    case CURLFORM_COPYCONTENTS:
363      if(current_form->value)
364        return_value = CURL_FORMADD_OPTION_TWICE;
365      else {
366        char *value =
367          array_state?array_value:va_arg(params, char *);
368        if(value)
369          current_form->value = value; /* store for the moment */
370        else
371          return_value = CURL_FORMADD_NULL;
372      }
373      break;
374    case CURLFORM_CONTENTSLENGTH:
375      if(current_form->contentslength)
376        return_value = CURL_FORMADD_OPTION_TWICE;
377      else
378        current_form->contentslength =
379          array_state?(size_t)array_value:(size_t)va_arg(params, long);
380      break;
381
382      /* Get contents from a given file name */
383    case CURLFORM_FILECONTENT:
384      if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
385        return_value = CURL_FORMADD_OPTION_TWICE;
386      else {
387        const char *filename = array_state?
388          array_value:va_arg(params, char *);
389        if(filename) {
390          current_form->value = strdup(filename);
391          if(!current_form->value)
392            return_value = CURL_FORMADD_MEMORY;
393          else {
394            current_form->flags |= HTTPPOST_READFILE;
395            current_form->value_alloc = TRUE;
396          }
397        }
398        else
399          return_value = CURL_FORMADD_NULL;
400      }
401      break;
402
403      /* We upload a file */
404    case CURLFORM_FILE:
405      {
406        const char *filename = array_state?array_value:
407          va_arg(params, char *);
408
409        if(current_form->value) {
410          if(current_form->flags & HTTPPOST_FILENAME) {
411            if(filename) {
412              char *fname = strdup(filename);
413              if(!fname)
414                return_value = CURL_FORMADD_MEMORY;
415              else {
416                form = AddFormInfo(fname, NULL, current_form);
417                if(!form) {
418                  free(fname);
419                  return_value = CURL_FORMADD_MEMORY;
420                }
421                else {
422                  form->value_alloc = TRUE;
423                  current_form = form;
424                  form = NULL;
425                }
426              }
427            }
428            else
429              return_value = CURL_FORMADD_NULL;
430          }
431          else
432            return_value = CURL_FORMADD_OPTION_TWICE;
433        }
434        else {
435          if(filename) {
436            current_form->value = strdup(filename);
437            if(!current_form->value)
438              return_value = CURL_FORMADD_MEMORY;
439            else {
440              current_form->flags |= HTTPPOST_FILENAME;
441              current_form->value_alloc = TRUE;
442            }
443          }
444          else
445            return_value = CURL_FORMADD_NULL;
446        }
447        break;
448      }
449
450    case CURLFORM_BUFFERPTR:
451      current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
452      if(current_form->buffer)
453        return_value = CURL_FORMADD_OPTION_TWICE;
454      else {
455        char *buffer =
456          array_state?array_value:va_arg(params, char *);
457        if(buffer) {
458          current_form->buffer = buffer; /* store for the moment */
459          current_form->value = buffer; /* make it non-NULL to be accepted
460                                           as fine */
461        }
462        else
463          return_value = CURL_FORMADD_NULL;
464      }
465      break;
466
467    case CURLFORM_BUFFERLENGTH:
468      if(current_form->bufferlength)
469        return_value = CURL_FORMADD_OPTION_TWICE;
470      else
471        current_form->bufferlength =
472          array_state?(size_t)array_value:(size_t)va_arg(params, long);
473      break;
474
475    case CURLFORM_STREAM:
476      current_form->flags |= HTTPPOST_CALLBACK;
477      if(current_form->userp)
478        return_value = CURL_FORMADD_OPTION_TWICE;
479      else {
480        char *userp =
481          array_state?array_value:va_arg(params, char *);
482        if(userp) {
483          current_form->userp = userp;
484          current_form->value = userp; /* this isn't strictly true but we
485                                          derive a value from this later on
486                                          and we need this non-NULL to be
487                                          accepted as a fine form part */
488        }
489        else
490          return_value = CURL_FORMADD_NULL;
491      }
492      break;
493
494    case CURLFORM_CONTENTTYPE:
495      {
496        const char *contenttype =
497          array_state?array_value:va_arg(params, char *);
498        if(current_form->contenttype) {
499          if(current_form->flags & HTTPPOST_FILENAME) {
500            if(contenttype) {
501              char *type = strdup(contenttype);
502              if(!type)
503                return_value = CURL_FORMADD_MEMORY;
504              else {
505                form = AddFormInfo(NULL, type, current_form);
506                if(!form) {
507                  free(type);
508                  return_value = CURL_FORMADD_MEMORY;
509                }
510                else {
511                  form->contenttype_alloc = TRUE;
512                  current_form = form;
513                  form = NULL;
514                }
515              }
516            }
517            else
518              return_value = CURL_FORMADD_NULL;
519          }
520          else
521            return_value = CURL_FORMADD_OPTION_TWICE;
522        }
523        else {
524          if(contenttype) {
525            current_form->contenttype = strdup(contenttype);
526            if(!current_form->contenttype)
527              return_value = CURL_FORMADD_MEMORY;
528            else
529              current_form->contenttype_alloc = TRUE;
530          }
531          else
532            return_value = CURL_FORMADD_NULL;
533        }
534        break;
535      }
536    case CURLFORM_CONTENTHEADER:
537      {
538        /* this "cast increases required alignment of target type" but
539           we consider it OK anyway */
540        struct curl_slist* list = array_state?
541          (struct curl_slist*)array_value:
542          va_arg(params, struct curl_slist*);
543
544        if(current_form->contentheader)
545          return_value = CURL_FORMADD_OPTION_TWICE;
546        else
547          current_form->contentheader = list;
548
549        break;
550      }
551    case CURLFORM_FILENAME:
552    case CURLFORM_BUFFER:
553      {
554        const char *filename = array_state?array_value:
555          va_arg(params, char *);
556        if(current_form->showfilename)
557          return_value = CURL_FORMADD_OPTION_TWICE;
558        else {
559          current_form->showfilename = strdup(filename);
560          if(!current_form->showfilename)
561            return_value = CURL_FORMADD_MEMORY;
562          else
563            current_form->showfilename_alloc = TRUE;
564        }
565        break;
566      }
567    default:
568      return_value = CURL_FORMADD_UNKNOWN_OPTION;
569      break;
570    }
571  }
572
573  if(CURL_FORMADD_OK != return_value) {
574    /* On error, free allocated fields for all nodes of the FormInfo linked
575       list without deallocating nodes. List nodes are deallocated later on */
576    FormInfo *ptr;
577    for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
578      if(ptr->name_alloc) {
579        Curl_safefree(ptr->name);
580        ptr->name_alloc = FALSE;
581      }
582      if(ptr->value_alloc) {
583        Curl_safefree(ptr->value);
584        ptr->value_alloc = FALSE;
585      }
586      if(ptr->contenttype_alloc) {
587        Curl_safefree(ptr->contenttype);
588        ptr->contenttype_alloc = FALSE;
589      }
590      if(ptr->showfilename_alloc) {
591        Curl_safefree(ptr->showfilename);
592        ptr->showfilename_alloc = FALSE;
593      }
594    }
595  }
596
597  if(CURL_FORMADD_OK == return_value) {
598    /* go through the list, check for completeness and if everything is
599     * alright add the HttpPost item otherwise set return_value accordingly */
600
601    post = NULL;
602    for(form = first_form;
603        form != NULL;
604        form = form->more) {
605      if(((!form->name || !form->value) && !post) ||
606         ( (form->contentslength) &&
607           (form->flags & HTTPPOST_FILENAME) ) ||
608         ( (form->flags & HTTPPOST_FILENAME) &&
609           (form->flags & HTTPPOST_PTRCONTENTS) ) ||
610
611         ( (!form->buffer) &&
612           (form->flags & HTTPPOST_BUFFER) &&
613           (form->flags & HTTPPOST_PTRBUFFER) ) ||
614
615         ( (form->flags & HTTPPOST_READFILE) &&
616           (form->flags & HTTPPOST_PTRCONTENTS) )
617        ) {
618        return_value = CURL_FORMADD_INCOMPLETE;
619        break;
620      }
621      else {
622        if(((form->flags & HTTPPOST_FILENAME) ||
623            (form->flags & HTTPPOST_BUFFER)) &&
624           !form->contenttype ) {
625          char *f = form->flags & HTTPPOST_BUFFER?
626            form->showfilename : form->value;
627
628          /* our contenttype is missing */
629          form->contenttype = strdup(ContentTypeForFilename(f, prevtype));
630          if(!form->contenttype) {
631            return_value = CURL_FORMADD_MEMORY;
632            break;
633          }
634          form->contenttype_alloc = TRUE;
635        }
636        if(!(form->flags & HTTPPOST_PTRNAME) &&
637           (form == first_form) ) {
638          /* Note that there's small risk that form->name is NULL here if the
639             app passed in a bad combo, so we better check for that first. */
640          if(form->name) {
641            /* copy name (without strdup; possibly contains null characters) */
642            form->name = Curl_memdup(form->name, form->namelength?
643                                     form->namelength:
644                                     strlen(form->name)+1);
645          }
646          if(!form->name) {
647            return_value = CURL_FORMADD_MEMORY;
648            break;
649          }
650          form->name_alloc = TRUE;
651        }
652        if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
653                            HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
654                            HTTPPOST_CALLBACK)) && form->value) {
655          /* copy value (without strdup; possibly contains null characters) */
656          form->value = Curl_memdup(form->value, form->contentslength?
657                                    form->contentslength:
658                                    strlen(form->value)+1);
659          if(!form->value) {
660            return_value = CURL_FORMADD_MEMORY;
661            break;
662          }
663          form->value_alloc = TRUE;
664        }
665        post = AddHttpPost(form->name, form->namelength,
666                           form->value, form->contentslength,
667                           form->buffer, form->bufferlength,
668                           form->contenttype, form->flags,
669                           form->contentheader, form->showfilename,
670                           form->userp,
671                           post, httppost,
672                           last_post);
673
674        if(!post) {
675          return_value = CURL_FORMADD_MEMORY;
676          break;
677        }
678
679        if(form->contenttype)
680          prevtype = form->contenttype;
681      }
682    }
683    if(CURL_FORMADD_OK != return_value) {
684      /* On error, free allocated fields for nodes of the FormInfo linked
685         list which are not already owned by the httppost linked list
686         without deallocating nodes. List nodes are deallocated later on */
687      FormInfo *ptr;
688      for(ptr = form; ptr != NULL; ptr = ptr->more) {
689        if(ptr->name_alloc) {
690          Curl_safefree(ptr->name);
691          ptr->name_alloc = FALSE;
692        }
693        if(ptr->value_alloc) {
694          Curl_safefree(ptr->value);
695          ptr->value_alloc = FALSE;
696        }
697        if(ptr->contenttype_alloc) {
698          Curl_safefree(ptr->contenttype);
699          ptr->contenttype_alloc = FALSE;
700        }
701        if(ptr->showfilename_alloc) {
702          Curl_safefree(ptr->showfilename);
703          ptr->showfilename_alloc = FALSE;
704        }
705      }
706    }
707  }
708
709  /* Always deallocate FormInfo linked list nodes without touching node
710     fields given that these have either been deallocated or are owned
711     now by the httppost linked list */
712  while(first_form) {
713    FormInfo *ptr = first_form->more;
714    free(first_form);
715    first_form = ptr;
716  }
717
718  return return_value;
719}
720
721/*
722 * curl_formadd() is a public API to add a section to the multipart formpost.
723 *
724 * @unittest: 1308
725 */
726
727CURLFORMcode curl_formadd(struct curl_httppost **httppost,
728                          struct curl_httppost **last_post,
729                          ...)
730{
731  va_list arg;
732  CURLFORMcode result;
733  va_start(arg, last_post);
734  result = FormAdd(httppost, last_post, arg);
735  va_end(arg);
736  return result;
737}
738
739#ifdef __VMS
740#include <fabdef.h>
741/*
742 * get_vms_file_size does what it takes to get the real size of the file
743 *
744 * For fixed files, find out the size of the EOF block and adjust.
745 *
746 * For all others, have to read the entire file in, discarding the contents.
747 * Most posted text files will be small, and binary files like zlib archives
748 * and CD/DVD images should be either a STREAM_LF format or a fixed format.
749 *
750 */
751curl_off_t VmsRealFileSize(const char * name,
752                           const struct_stat * stat_buf)
753{
754  char buffer[8192];
755  curl_off_t count;
756  int ret_stat;
757  FILE * file;
758
759  file = fopen(name, "r"); /* VMS */
760  if(file == NULL)
761    return 0;
762
763  count = 0;
764  ret_stat = 1;
765  while(ret_stat > 0) {
766    ret_stat = fread(buffer, 1, sizeof(buffer), file);
767    if(ret_stat != 0)
768      count += ret_stat;
769  }
770  fclose(file);
771
772  return count;
773}
774
775/*
776 *
777 *  VmsSpecialSize checks to see if the stat st_size can be trusted and
778 *  if not to call a routine to get the correct size.
779 *
780 */
781static curl_off_t VmsSpecialSize(const char * name,
782                                 const struct_stat * stat_buf)
783{
784  switch(stat_buf->st_fab_rfm) {
785  case FAB$C_VAR:
786  case FAB$C_VFC:
787    return VmsRealFileSize(name, stat_buf);
788    break;
789  default:
790    return stat_buf->st_size;
791  }
792}
793
794#endif
795
796#ifndef __VMS
797#define filesize(name, stat_data) (stat_data.st_size)
798#else
799    /* Getting the expected file size needs help on VMS */
800#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
801#endif
802
803/*
804 * AddFormData() adds a chunk of data to the FormData linked list.
805 *
806 * size is incremented by the chunk length, unless it is NULL
807 */
808static CURLcode AddFormData(struct FormData **formp,
809                            enum formtype type,
810                            const void *line,
811                            size_t length,
812                            curl_off_t *size)
813{
814  struct FormData *newform = malloc(sizeof(struct FormData));
815  if(!newform)
816    return CURLE_OUT_OF_MEMORY;
817  newform->next = NULL;
818
819  if(type <= FORM_CONTENT) {
820    /* we make it easier for plain strings: */
821    if(!length)
822      length = strlen((char *)line);
823
824    newform->line = malloc(length+1);
825    if(!newform->line) {
826      free(newform);
827      return CURLE_OUT_OF_MEMORY;
828    }
829    memcpy(newform->line, line, length);
830    newform->length = length;
831    newform->line[length]=0; /* zero terminate for easier debugging */
832  }
833  else
834    /* For callbacks and files we don't have any actual data so we just keep a
835       pointer to whatever this points to */
836    newform->line = (char *)line;
837
838  newform->type = type;
839
840  if(*formp) {
841    (*formp)->next = newform;
842    *formp = newform;
843  }
844  else
845    *formp = newform;
846
847  if(size) {
848    if(type != FORM_FILE)
849      /* for static content as well as callback data we add the size given
850         as input argument */
851      *size += length;
852    else {
853      /* Since this is a file to be uploaded here, add the size of the actual
854         file */
855      if(!strequal("-", newform->line)) {
856        struct_stat file;
857        if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode))
858          *size += filesize(newform->line, file);
859        else
860          return CURLE_BAD_FUNCTION_ARGUMENT;
861      }
862    }
863  }
864  return CURLE_OK;
865}
866
867/*
868 * AddFormDataf() adds printf()-style formatted data to the formdata chain.
869 */
870
871static CURLcode AddFormDataf(struct FormData **formp,
872                             curl_off_t *size,
873                             const char *fmt, ...)
874{
875  char s[4096];
876  va_list ap;
877  va_start(ap, fmt);
878  vsnprintf(s, sizeof(s), fmt, ap);
879  va_end(ap);
880
881  return AddFormData(formp, FORM_DATA, s, 0, size);
882}
883
884/*
885 * Curl_formclean() is used from http.c, this cleans a built FormData linked
886 * list
887 */
888void Curl_formclean(struct FormData **form_ptr)
889{
890  struct FormData *next, *form;
891
892  form = *form_ptr;
893  if(!form)
894    return;
895
896  do {
897    next=form->next;  /* the following form line */
898    if(form->type <= FORM_CONTENT)
899      free(form->line); /* free the line */
900    free(form);       /* free the struct */
901
902  } while((form = next) != NULL); /* continue */
903
904  *form_ptr = NULL;
905}
906
907/*
908 * curl_formget()
909 * Serialize a curl_httppost struct.
910 * Returns 0 on success.
911 *
912 * @unittest: 1308
913 */
914int curl_formget(struct curl_httppost *form, void *arg,
915                 curl_formget_callback append)
916{
917  CURLcode result;
918  curl_off_t size;
919  struct FormData *data, *ptr;
920
921  result = Curl_getformdata(NULL, &data, form, NULL, &size);
922  if(result)
923    return (int)result;
924
925  for(ptr = data; ptr; ptr = ptr->next) {
926    if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) {
927      char buffer[8192];
928      size_t nread;
929      struct Form temp;
930
931      Curl_FormInit(&temp, ptr);
932
933      do {
934        nread = readfromfile(&temp, buffer, sizeof(buffer));
935        if((nread == (size_t) -1) ||
936           (nread > sizeof(buffer)) ||
937           (nread != append(arg, buffer, nread))) {
938          if(temp.fp)
939            fclose(temp.fp);
940          Curl_formclean(&data);
941          return -1;
942        }
943      } while(nread);
944    }
945    else {
946      if(ptr->length != append(arg, ptr->line, ptr->length)) {
947        Curl_formclean(&data);
948        return -1;
949      }
950    }
951  }
952  Curl_formclean(&data);
953  return 0;
954}
955
956/*
957 * curl_formfree() is an external function to free up a whole form post
958 * chain
959 */
960void curl_formfree(struct curl_httppost *form)
961{
962  struct curl_httppost *next;
963
964  if(!form)
965    /* no form to free, just get out of this */
966    return;
967
968  do {
969    next=form->next;  /* the following form line */
970
971    /* recurse to sub-contents */
972    curl_formfree(form->more);
973
974    if(!(form->flags & HTTPPOST_PTRNAME))
975      free(form->name); /* free the name */
976    if(!(form->flags &
977         (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
978      )
979      free(form->contents); /* free the contents */
980    free(form->contenttype); /* free the content type */
981    free(form->showfilename); /* free the faked file name */
982    free(form);       /* free the struct */
983
984  } while((form = next) != NULL); /* continue */
985}
986
987#ifndef HAVE_BASENAME
988/*
989  (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
990  Edition)
991
992  The basename() function shall take the pathname pointed to by path and
993  return a pointer to the final component of the pathname, deleting any
994  trailing '/' characters.
995
996  If the string pointed to by path consists entirely of the '/' character,
997  basename() shall return a pointer to the string "/". If the string pointed
998  to by path is exactly "//", it is implementation-defined whether '/' or "//"
999  is returned.
1000
1001  If path is a null pointer or points to an empty string, basename() shall
1002  return a pointer to the string ".".
1003
1004  The basename() function may modify the string pointed to by path, and may
1005  return a pointer to static storage that may then be overwritten by a
1006  subsequent call to basename().
1007
1008  The basename() function need not be reentrant. A function that is not
1009  required to be reentrant is not required to be thread-safe.
1010
1011*/
1012static char *Curl_basename(char *path)
1013{
1014  /* Ignore all the details above for now and make a quick and simple
1015     implementaion here */
1016  char *s1;
1017  char *s2;
1018
1019  s1=strrchr(path, '/');
1020  s2=strrchr(path, '\\');
1021
1022  if(s1 && s2) {
1023    path = (s1 > s2? s1 : s2)+1;
1024  }
1025  else if(s1)
1026    path = s1 + 1;
1027  else if(s2)
1028    path = s2 + 1;
1029
1030  return path;
1031}
1032#endif
1033
1034static char *strippath(const char *fullfile)
1035{
1036  char *filename;
1037  char *base;
1038  filename = strdup(fullfile); /* duplicate since basename() may ruin the
1039                                  buffer it works on */
1040  if(!filename)
1041    return NULL;
1042  base = strdup(basename(filename));
1043
1044  free(filename); /* free temporary buffer */
1045
1046  return base; /* returns an allocated string or NULL ! */
1047}
1048
1049static CURLcode formdata_add_filename(const struct curl_httppost *file,
1050                                      struct FormData **form,
1051                                      curl_off_t *size)
1052{
1053  CURLcode result = CURLE_OK;
1054  char *filename = file->showfilename;
1055  char *filebasename = NULL;
1056  char *filename_escaped = NULL;
1057
1058  if(!filename) {
1059    filebasename = strippath(file->contents);
1060    if(!filebasename)
1061      return CURLE_OUT_OF_MEMORY;
1062    filename = filebasename;
1063  }
1064
1065  if(strchr(filename, '\\') || strchr(filename, '"')) {
1066    char *p0, *p1;
1067
1068    /* filename need be escaped */
1069    filename_escaped = malloc(strlen(filename)*2+1);
1070    if(!filename_escaped) {
1071      free(filebasename);
1072      return CURLE_OUT_OF_MEMORY;
1073    }
1074    p0 = filename_escaped;
1075    p1 = filename;
1076    while(*p1) {
1077      if(*p1 == '\\' || *p1 == '"')
1078        *p0++ = '\\';
1079      *p0++ = *p1++;
1080    }
1081    *p0 = '\0';
1082    filename = filename_escaped;
1083  }
1084  result = AddFormDataf(form, size,
1085                        "; filename=\"%s\"",
1086                        filename);
1087  free(filename_escaped);
1088  free(filebasename);
1089  return result;
1090}
1091
1092/*
1093 * Curl_getformdata() converts a linked list of "meta data" into a complete
1094 * (possibly huge) multipart formdata. The input list is in 'post', while the
1095 * output resulting linked lists gets stored in '*finalform'. *sizep will get
1096 * the total size of the whole POST.
1097 * A multipart/form_data content-type is built, unless a custom content-type
1098 * is passed in 'custom_content_type'.
1099 *
1100 * This function will not do a failf() for the potential memory failures but
1101 * should for all other errors it spots. Just note that this function MAY get
1102 * a NULL pointer in the 'data' argument.
1103 */
1104
1105CURLcode Curl_getformdata(struct SessionHandle *data,
1106                          struct FormData **finalform,
1107                          struct curl_httppost *post,
1108                          const char *custom_content_type,
1109                          curl_off_t *sizep)
1110{
1111  struct FormData *form = NULL;
1112  struct FormData *firstform;
1113  struct curl_httppost *file;
1114  CURLcode result = CURLE_OK;
1115
1116  curl_off_t size = 0; /* support potentially ENORMOUS formposts */
1117  char *boundary;
1118  char *fileboundary = NULL;
1119  struct curl_slist* curList;
1120
1121  *finalform = NULL; /* default form is empty */
1122
1123  if(!post)
1124    return result; /* no input => no output! */
1125
1126  boundary = formboundary(data);
1127  if(!boundary)
1128    return CURLE_OUT_OF_MEMORY;
1129
1130  /* Make the first line of the output */
1131  result = AddFormDataf(&form, NULL,
1132                        "%s; boundary=%s\r\n",
1133                        custom_content_type?custom_content_type:
1134                        "Content-Type: multipart/form-data",
1135                        boundary);
1136
1137  if(result) {
1138    free(boundary);
1139    return result;
1140  }
1141  /* we DO NOT include that line in the total size of the POST, since it'll be
1142     part of the header! */
1143
1144  firstform = form;
1145
1146  do {
1147
1148    if(size) {
1149      result = AddFormDataf(&form, &size, "\r\n");
1150      if(result)
1151        break;
1152    }
1153
1154    /* boundary */
1155    result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
1156    if(result)
1157      break;
1158
1159    /* Maybe later this should be disabled when a custom_content_type is
1160       passed, since Content-Disposition is not meaningful for all multipart
1161       types.
1162    */
1163    result = AddFormDataf(&form, &size,
1164                          "Content-Disposition: form-data; name=\"");
1165    if(result)
1166      break;
1167
1168    result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
1169                         &size);
1170    if(result)
1171      break;
1172
1173    result = AddFormDataf(&form, &size, "\"");
1174    if(result)
1175      break;
1176
1177    if(post->more) {
1178      /* If used, this is a link to more file names, we must then do
1179         the magic to include several files with the same field name */
1180
1181      free(fileboundary);
1182      fileboundary = formboundary(data);
1183      if(!fileboundary) {
1184        result = CURLE_OUT_OF_MEMORY;
1185        break;
1186      }
1187
1188      result = AddFormDataf(&form, &size,
1189                            "\r\nContent-Type: multipart/mixed;"
1190                            " boundary=%s\r\n",
1191                            fileboundary);
1192      if(result)
1193        break;
1194    }
1195
1196    file = post;
1197
1198    do {
1199
1200      /* If 'showfilename' is set, that is a faked name passed on to us
1201         to use to in the formpost. If that is not set, the actually used
1202         local file name should be added. */
1203
1204      if(post->more) {
1205        /* if multiple-file */
1206        result = AddFormDataf(&form, &size,
1207                              "\r\n--%s\r\nContent-Disposition: "
1208                              "attachment",
1209                              fileboundary);
1210        if(result)
1211          break;
1212        result = formdata_add_filename(file, &form, &size);
1213        if(result)
1214          break;
1215      }
1216      else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
1217                             HTTPPOST_CALLBACK)) {
1218        /* it should be noted that for the HTTPPOST_FILENAME and
1219           HTTPPOST_CALLBACK cases the ->showfilename struct member is always
1220           assigned at this point */
1221        if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) {
1222          result = formdata_add_filename(post, &form, &size);
1223        }
1224
1225        if(result)
1226          break;
1227      }
1228
1229      if(file->contenttype) {
1230        /* we have a specified type */
1231        result = AddFormDataf(&form, &size,
1232                              "\r\nContent-Type: %s",
1233                              file->contenttype);
1234        if(result)
1235          break;
1236      }
1237
1238      curList = file->contentheader;
1239      while(curList) {
1240        /* Process the additional headers specified for this form */
1241        result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
1242        if(result)
1243          break;
1244        curList = curList->next;
1245      }
1246      if(result)
1247        break;
1248
1249      result = AddFormDataf(&form, &size, "\r\n\r\n");
1250      if(result)
1251        break;
1252
1253      if((post->flags & HTTPPOST_FILENAME) ||
1254         (post->flags & HTTPPOST_READFILE)) {
1255        /* we should include the contents from the specified file */
1256        FILE *fileread;
1257
1258        fileread = strequal("-", file->contents)?
1259          stdin:fopen(file->contents, "rb"); /* binary read for win32  */
1260
1261        /*
1262         * VMS: This only allows for stream files on VMS.  Stream files are
1263         * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
1264         * every record needs to have a \n appended & 1 added to SIZE
1265         */
1266
1267        if(fileread) {
1268          if(fileread != stdin) {
1269            /* close the file */
1270            fclose(fileread);
1271            /* add the file name only - for later reading from this */
1272            result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
1273          }
1274          else {
1275            /* When uploading from stdin, we can't know the size of the file,
1276             * thus must read the full file as before. We *could* use chunked
1277             * transfer-encoding, but that only works for HTTP 1.1 and we
1278             * can't be sure we work with such a server.
1279             */
1280            size_t nread;
1281            char buffer[512];
1282            while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
1283              result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
1284              if(result)
1285                break;
1286            }
1287          }
1288        }
1289        else {
1290          if(data)
1291            failf(data, "couldn't open file \"%s\"", file->contents);
1292          *finalform = NULL;
1293          result = CURLE_READ_ERROR;
1294        }
1295      }
1296      else if(post->flags & HTTPPOST_BUFFER)
1297        /* include contents of buffer */
1298        result = AddFormData(&form, FORM_CONTENT, post->buffer,
1299                             post->bufferlength, &size);
1300      else if(post->flags & HTTPPOST_CALLBACK)
1301        /* the contents should be read with the callback and the size
1302           is set with the contentslength */
1303        result = AddFormData(&form, FORM_CALLBACK, post->userp,
1304                             post->contentslength, &size);
1305      else
1306        /* include the contents we got */
1307        result = AddFormData(&form, FORM_CONTENT, post->contents,
1308                             post->contentslength, &size);
1309
1310      file = file->more;
1311    } while(file && !result); /* for each specified file for this field */
1312
1313    if(result)
1314      break;
1315
1316    if(post->more) {
1317      /* this was a multiple-file inclusion, make a termination file
1318         boundary: */
1319      result = AddFormDataf(&form, &size,
1320                           "\r\n--%s--",
1321                           fileboundary);
1322      if(result)
1323        break;
1324    }
1325
1326  } while((post = post->next) != NULL); /* for each field */
1327
1328  /* end-boundary for everything */
1329  if(!result)
1330    result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary);
1331
1332  if(result) {
1333    Curl_formclean(&firstform);
1334    free(fileboundary);
1335    free(boundary);
1336    return result;
1337  }
1338
1339  *sizep = size;
1340
1341  free(fileboundary);
1342  free(boundary);
1343
1344  *finalform = firstform;
1345
1346  return result;
1347}
1348
1349/*
1350 * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
1351 * and resets the 'sent' counter.
1352 */
1353int Curl_FormInit(struct Form *form, struct FormData *formdata )
1354{
1355  if(!formdata)
1356    return 1; /* error */
1357
1358  form->data = formdata;
1359  form->sent = 0;
1360  form->fp = NULL;
1361  form->fread_func = ZERO_NULL;
1362
1363  return 0;
1364}
1365
1366#ifndef __VMS
1367# define fopen_read fopen
1368#else
1369  /*
1370   * vmsfopenread
1371   *
1372   * For upload to work as expected on VMS, different optional
1373   * parameters must be added to the fopen command based on
1374   * record format of the file.
1375   *
1376   */
1377# define fopen_read vmsfopenread
1378static FILE * vmsfopenread(const char *file, const char *mode) {
1379  struct_stat statbuf;
1380  int result;
1381
1382  result = stat(file, &statbuf);
1383
1384  switch (statbuf.st_fab_rfm) {
1385  case FAB$C_VAR:
1386  case FAB$C_VFC:
1387  case FAB$C_STMCR:
1388    return fopen(file, "r"); /* VMS */
1389    break;
1390  default:
1391    return fopen(file, "r", "rfm=stmlf", "ctx=stm");
1392  }
1393}
1394#endif
1395
1396/*
1397 * readfromfile()
1398 *
1399 * The read callback that this function may use can return a value larger than
1400 * 'size' (which then this function returns) that indicates a problem and it
1401 * must be properly dealt with
1402 */
1403static size_t readfromfile(struct Form *form, char *buffer,
1404                           size_t size)
1405{
1406  size_t nread;
1407  bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE;
1408
1409  if(callback) {
1410    if(form->fread_func == ZERO_NULL)
1411      return 0;
1412    else
1413      nread = form->fread_func(buffer, 1, size, form->data->line);
1414  }
1415  else {
1416    if(!form->fp) {
1417      /* this file hasn't yet been opened */
1418      form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
1419      if(!form->fp)
1420        return (size_t)-1; /* failure */
1421    }
1422    nread = fread(buffer, 1, size, form->fp);
1423  }
1424  if(!nread) {
1425    /* this is the last chunk from the file, move on */
1426    if(form->fp) {
1427      fclose(form->fp);
1428      form->fp = NULL;
1429    }
1430    form->data = form->data->next;
1431  }
1432
1433  return nread;
1434}
1435
1436/*
1437 * Curl_FormReader() is the fread() emulation function that will be used to
1438 * deliver the formdata to the transfer loop and then sent away to the peer.
1439 */
1440size_t Curl_FormReader(char *buffer,
1441                       size_t size,
1442                       size_t nitems,
1443                       FILE *mydata)
1444{
1445  struct Form *form;
1446  size_t wantedsize;
1447  size_t gotsize = 0;
1448
1449  form=(struct Form *)mydata;
1450
1451  wantedsize = size * nitems;
1452
1453  if(!form->data)
1454    return 0; /* nothing, error, empty */
1455
1456  if((form->data->type == FORM_FILE) ||
1457     (form->data->type == FORM_CALLBACK)) {
1458    gotsize = readfromfile(form, buffer, wantedsize);
1459
1460    if(gotsize)
1461      /* If positive or -1, return. If zero, continue! */
1462      return gotsize;
1463  }
1464  do {
1465
1466    if((form->data->length - form->sent ) > wantedsize - gotsize) {
1467
1468      memcpy(buffer + gotsize , form->data->line + form->sent,
1469             wantedsize - gotsize);
1470
1471      form->sent += wantedsize-gotsize;
1472
1473      return wantedsize;
1474    }
1475
1476    memcpy(buffer+gotsize,
1477           form->data->line + form->sent,
1478           (form->data->length - form->sent) );
1479    gotsize += form->data->length - form->sent;
1480
1481    form->sent = 0;
1482
1483    form->data = form->data->next; /* advance */
1484
1485  } while(form->data && (form->data->type < FORM_CALLBACK));
1486  /* If we got an empty line and we have more data, we proceed to the next
1487     line immediately to avoid returning zero before we've reached the end. */
1488
1489  return gotsize;
1490}
1491
1492/*
1493 * Curl_formpostheader() returns the first line of the formpost, the
1494 * request-header part (which is not part of the request-body like the rest of
1495 * the post).
1496 */
1497char *Curl_formpostheader(void *formp, size_t *len)
1498{
1499  char *header;
1500  struct Form *form=(struct Form *)formp;
1501
1502  if(!form->data)
1503    return 0; /* nothing, ERROR! */
1504
1505  header = form->data->line;
1506  *len = form->data->length;
1507
1508  form->data = form->data->next; /* advance */
1509
1510  return header;
1511}
1512
1513/*
1514 * formboundary() creates a suitable boundary string and returns an allocated
1515 * one.
1516 */
1517static char *formboundary(struct SessionHandle *data)
1518{
1519  /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
1520     combinations */
1521  return aprintf("------------------------%08x%08x",
1522                 Curl_rand(data), Curl_rand(data));
1523}
1524
1525#else  /* CURL_DISABLE_HTTP */
1526CURLFORMcode curl_formadd(struct curl_httppost **httppost,
1527                          struct curl_httppost **last_post,
1528                          ...)
1529{
1530  (void)httppost;
1531  (void)last_post;
1532  return CURL_FORMADD_DISABLED;
1533}
1534
1535int curl_formget(struct curl_httppost *form, void *arg,
1536                 curl_formget_callback append)
1537{
1538  (void) form;
1539  (void) arg;
1540  (void) append;
1541  return CURL_FORMADD_DISABLED;
1542}
1543
1544void curl_formfree(struct curl_httppost *form)
1545{
1546  (void)form;
1547  /* does nothing HTTP is disabled */
1548}
1549
1550
1551#endif  /* !defined(CURL_DISABLE_HTTP) */
1552