doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
formdata.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2004, 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  * $Id: formdata.c,v 1.56 2004/03/12 14:22:16 bagder Exp $
22  ***************************************************************************/
23 
24 /*
25  Debug the form generator stand-alone by compiling this source file with:
26 
27  gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -o formdata -I../include formdata.c strequal.c
28 
29  run the 'formdata' executable the output should end with:
30  All Tests seem to have worked ...
31  and the following parts should be there:
32 
33 Content-Disposition: form-data; name="simple_COPYCONTENTS"
34 value for simple COPYCONTENTS
35 
36 Content-Disposition: form-data; name="COPYCONTENTS_+_CONTENTTYPE"
37 Content-Type: image/gif
38 value for COPYCONTENTS + CONTENTTYPE
39 
40 Content-Disposition: form-data; name="PRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH"
41 vlue for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH
42 (or you might see P^@RNAME and v^@lue at the start)
43 
44 Content-Disposition: form-data; name="simple_PTRCONTENTS"
45 value for simple PTRCONTENTS
46 
47 Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH"
48 vlue for PTRCONTENTS + CONTENTSLENGTH
49 (or you might see v^@lue at the start)
50 
51 Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE"
52 Content-Type: text/plain
53 vlue for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE
54 (or you might see v^@lue at the start)
55 
56 Content-Disposition: form-data; name="FILE1_+_CONTENTTYPE"; filename="inet_ntoa_r.h"
57 Content-Type: text/html
58 ...
59 
60 Content-Disposition: form-data; name="FILE1_+_FILE2"
61 Content-Type: multipart/mixed, boundary=curlz1s0dkticx49MV1KGcYP5cvfSsz
62 ...
63 Content-Disposition: attachment; filename="inet_ntoa_r.h"
64 Content-Type: text/plain
65 ...
66 Content-Disposition: attachment; filename="Makefile.b32.resp"
67 Content-Type: text/plain
68 ...
69 
70 Content-Disposition: form-data; name="FILE1_+_FILE2_+_FILE3"
71 Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
72 ...
73 Content-Disposition: attachment; filename="inet_ntoa_r.h"
74 Content-Type: text/plain
75 ...
76 Content-Disposition: attachment; filename="Makefile.b32.resp"
77 Content-Type: text/plain
78 ...
79 Content-Disposition: attachment; filename="inet_ntoa_r.h"
80 Content-Type: text/plain
81 ...
82 
83 
84 Content-Disposition: form-data; name="ARRAY: FILE1_+_FILE2_+_FILE3"
85 Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
86 ...
87 Content-Disposition: attachment; filename="inet_ntoa_r.h"
88 Content-Type: text/plain
89 ...
90 Content-Disposition: attachment; filename="Makefile.b32.resp"
91 Content-Type: text/plain
92 ...
93 Content-Disposition: attachment; filename="inet_ntoa_r.h"
94 Content-Type: text/plain
95 ...
96 
97 Content-Disposition: form-data; name="FILECONTENT"
98 ...
99 
100  For the old FormParse used by curl_formparse use:
101 
102  gcc -DHAVE_CONFIG_H -I../ -g -D_OLD_FORM_DEBUG -o formdata -I../include formdata.c strequal.c
103 
104  run the 'formdata' executable and make sure the output is ok!
105 
106  try './formdata "name=Daniel" "poo=noo" "foo=bar"' and similarly
107 
108  */
109 
110 #include "setup.h"
111 
112 #ifndef CURL_DISABLE_HTTP
113 
114 #include <stdio.h>
115 #include <stdlib.h>
116 #include <string.h>
117 #include <stdarg.h>
118 
119 #include <time.h>
120 
121 #ifndef CURL_OLDSTYLE
122 #define CURL_OLDSTYLE 1 /* enable deprecated prototype for curl_formparse */
123 #endif
124 #include <curl/curl.h>
125 #include "formdata.h"
126 
127 #include "strequal.h"
128 
129 /* The last #include file should be: */
130 #ifdef CURLDEBUG
131 #include "memdebug.h"
132 #endif
133 
134 /* Length of the random boundary string. */
135 #define BOUNDARY_LENGTH 40
136 
137 /* What kind of Content-Type to use on un-specified files with unrecognized
138  extensions. */
139 #define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
140 
141 /* This is a silly duplicate of the function in main.c to enable this source
142  to compile stand-alone for better debugging */
143 static void GetStr(char **string,
144  const char *value)
145 {
146  if(*string)
147  free(*string);
148  *string = strdup(value);
149 }
150 
151 /***************************************************************************
152  *
153  * FormParse()
154  *
155  * Reads a 'name=value' paramter and builds the appropriate linked list.
156  *
157  * Specify files to upload with 'name=@filename'. Supports specified
158  * given Content-Type of the files. Such as ';type=<content-type>'.
159  *
160  * You may specify more than one file for a single name (field). Specify
161  * multiple files by writing it like:
162  *
163  * 'name=@filename,filename2,filename3'
164  *
165  * If you want content-types specified for each too, write them like:
166  *
167  * 'name=@filename;type=image/gif,filename2,filename3'
168  *
169  ***************************************************************************/
170 
171 #define FORM_FILE_SEPARATOR ','
172 #define FORM_TYPE_SEPARATOR ';'
173 
174 static
175 int FormParse(char *input,
176  struct curl_httppost **httppost,
177  struct curl_httppost **last_post)
178 {
179  /* nextarg MUST be a string in the format 'name=contents' and we'll
180  build a linked list with the info */
181  char name[256];
182  char *contents;
183  char major[128];
184  char minor[128];
185  long flags = 0;
186  char *contp;
187  const char *type = NULL;
188  char *prevtype = NULL;
189  char *sep;
190  char *sep2;
191  struct curl_httppost *post;
192  struct curl_httppost *subpost; /* a sub-node */
193  unsigned int i;
194 
195  /* Preallocate contents to the length of input to make sure we don't
196  overwrite anything. */
197  contents = malloc(strlen(input));
198  contents[0] = '\000';
199 
200  if(1 <= sscanf(input, "%255[^=]=%[^\n]", name, contents)) {
201  /* the input was using the correct format */
202  contp = contents;
203 
204  if('@' == contp[0]) {
205  /* we use the @-letter to indicate file name(s) */
206 
207  flags = HTTPPOST_FILENAME;
208  contp++;
209 
210  post=NULL;
211 
212  do {
213  /* since this was a file, it may have a content-type specifier
214  at the end too */
215 
216  sep=strchr(contp, FORM_TYPE_SEPARATOR);
217  sep2=strchr(contp, FORM_FILE_SEPARATOR);
218 
219  /* pick the closest */
220  if(sep2 && (sep2 < sep)) {
221  sep = sep2;
222 
223  /* no type was specified! */
224  }
225  if(sep) {
226 
227  /* if we got here on a comma, don't do much */
228  if(FORM_FILE_SEPARATOR != *sep)
229  type = strstr(sep+1, "type=");
230  else
231  type=NULL;
232 
233  *sep=0; /* terminate file name at separator */
234 
235  if(type) {
236  type += strlen("type=");
237 
238  if(2 != sscanf(type, "%127[^/]/%127[^,\n]",
239  major, minor)) {
240  free(contents);
241  return 2; /* illegal content-type syntax! */
242  }
243  /* now point beyond the content-type specifier */
244  sep = (char *)type + strlen(major)+strlen(minor)+1;
245 
246  /* find the following comma */
247  sep=strchr(sep, FORM_FILE_SEPARATOR);
248  }
249  }
250  else {
251  type=NULL;
252  sep=strchr(contp, FORM_FILE_SEPARATOR);
253  }
254  if(sep) {
255  /* the next file name starts here */
256  *sep =0;
257  sep++;
258  }
259  if(!type) {
260  /*
261  * No type was specified, we scan through a few well-known
262  * extensions and pick the first we match!
263  */
264  struct ContentType {
265  const char *extension;
266  const char *type;
267  };
268  static struct ContentType ctts[]={
269  {".gif", "image/gif"},
270  {".jpg", "image/jpeg"},
271  {".jpeg", "image/jpeg"},
272  {".txt", "text/plain"},
273  {".html", "text/html"}
274  };
275 
276  if(prevtype)
277  /* default to the previously set/used! */
278  type = prevtype;
279  else
280  /* It seems RFC1867 defines no Content-Type to default to
281  text/plain so we don't actually need to set this: */
283 
284  for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
285  if(strlen(contp) >= strlen(ctts[i].extension)) {
286  if(strequal(contp +
287  strlen(contp) - strlen(ctts[i].extension),
288  ctts[i].extension)) {
289  type = ctts[i].type;
290  break;
291  }
292  }
293  }
294  /* we have a type by now */
295  }
296 
297  if(NULL == post) {
298  /* For the first file name, we allocate and initiate the main list
299  node */
300 
301  post = (struct curl_httppost *)malloc(sizeof(struct curl_httppost));
302  if(post) {
303  memset(post, 0, sizeof(struct curl_httppost));
304  GetStr(&post->name, name); /* get the name */
305  GetStr(&post->contents, contp); /* get the contents */
306  post->contentslength = 0;
307  post->flags = flags;
308  if(type) {
309  GetStr(&post->contenttype, (char *)type); /* get type */
310  prevtype=post->contenttype; /* point to the allocated string! */
311  }
312  /* make the previous point to this */
313  if(*last_post)
314  (*last_post)->next = post;
315  else
316  (*httppost) = post;
317 
318  (*last_post) = post;
319  }
320 
321  }
322  else {
323  /* we add a file name to the previously allocated node, known as
324  'post' now */
325  subpost =(struct curl_httppost *)
326  malloc(sizeof(struct curl_httppost));
327  if(subpost) {
328  memset(subpost, 0, sizeof(struct curl_httppost));
329  GetStr(&subpost->name, name); /* get the name */
330  GetStr(&subpost->contents, contp); /* get the contents */
331  subpost->contentslength = 0;
332  subpost->flags = flags;
333  if(type) {
334  GetStr(&subpost->contenttype, (char *)type); /* get type */
335  prevtype=subpost->contenttype; /* point to allocated string! */
336  }
337  /* now, point our 'more' to the original 'more' */
338  subpost->more = post->more;
339 
340  /* then move the original 'more' to point to ourselves */
341  post->more = subpost;
342  }
343  }
344  contp = sep; /* move the contents pointer to after the separator */
345  } while(sep && *sep); /* loop if there's another file name */
346  }
347  else {
348  post = (struct curl_httppost *)malloc(sizeof(struct curl_httppost));
349  if(post) {
350  memset(post, 0, sizeof(struct curl_httppost));
351  GetStr(&post->name, name); /* get the name */
352  if( contp[0]=='<' ) {
353  GetStr(&post->contents, contp+1); /* get the contents */
354  post->contentslength = 0;
355  post->flags = HTTPPOST_READFILE;
356  }
357  else {
358  GetStr(&post->contents, contp); /* get the contents */
359  post->contentslength = 0;
360  post->flags = 0;
361  }
362 
363  /* make the previous point to this */
364  if(*last_post)
365  (*last_post)->next = post;
366  else
367  (*httppost) = post;
368 
369  (*last_post) = post;
370  }
371 
372  }
373 
374  }
375  else {
376  free(contents);
377  return 1;
378  }
379  free(contents);
380  return 0;
381 }
382 
384  struct curl_httppost **httppost,
385  struct curl_httppost **last_post)
386 {
387  return FormParse(input, httppost, last_post);
388 }
389 
390 /***************************************************************************
391  *
392  * AddHttpPost()
393  *
394  * Adds a HttpPost structure to the list, if parent_post is given becomes
395  * a subpost of parent_post instead of a direct list element.
396  *
397  * Returns newly allocated HttpPost on success and NULL if malloc failed.
398  *
399  ***************************************************************************/
400 static struct curl_httppost *
401 AddHttpPost(char * name, size_t namelength,
402  char * value, size_t contentslength,
403  char * buffer, size_t bufferlength,
404  char *contenttype,
405  long flags,
406  struct curl_slist* contentHeader,
407  char *showfilename,
408  struct curl_httppost *parent_post,
409  struct curl_httppost **httppost,
410  struct curl_httppost **last_post)
411 {
412  struct curl_httppost *post;
413  post = (struct curl_httppost *)malloc(sizeof(struct curl_httppost));
414  if(post) {
415  memset(post, 0, sizeof(struct curl_httppost));
416  post->name = name;
417  post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
418  post->contents = value;
419  post->contentslength = (long)contentslength;
420  post->buffer = buffer;
421  post->bufferlength = (long)bufferlength;
422  post->contenttype = contenttype;
423  post->contentheader = contentHeader;
424  post->showfilename = showfilename;
425  post->flags = flags;
426  }
427  else
428  return NULL;
429 
430  if (parent_post) {
431  /* now, point our 'more' to the original 'more' */
432  post->more = parent_post->more;
433 
434  /* then move the original 'more' to point to ourselves */
435  parent_post->more = post;
436  }
437  else {
438  /* make the previous point to this */
439  if(*last_post)
440  (*last_post)->next = post;
441  else
442  (*httppost) = post;
443 
444  (*last_post) = post;
445  }
446  return post;
447 }
448 
449 /***************************************************************************
450  *
451  * AddFormInfo()
452  *
453  * Adds a FormInfo structure to the list presented by parent_form_info.
454  *
455  * Returns newly allocated FormInfo on success and NULL if malloc failed/
456  * parent_form_info is NULL.
457  *
458  ***************************************************************************/
459 static FormInfo * AddFormInfo(char *value,
460  char *contenttype,
461  FormInfo *parent_form_info)
462 {
463  FormInfo *form_info;
464  form_info = (FormInfo *)malloc(sizeof(FormInfo));
465  if(form_info) {
466  memset(form_info, 0, sizeof(FormInfo));
467  if (value)
468  form_info->value = value;
469  if (contenttype)
470  form_info->contenttype = contenttype;
471  form_info->flags = HTTPPOST_FILENAME;
472  }
473  else
474  return NULL;
475 
476  if (parent_form_info) {
477  /* now, point our 'more' to the original 'more' */
478  form_info->more = parent_form_info->more;
479 
480  /* then move the original 'more' to point to ourselves */
481  parent_form_info->more = form_info;
482  }
483  else
484  return NULL;
485 
486  return form_info;
487 }
488 
489 /***************************************************************************
490  *
491  * ContentTypeForFilename()
492  *
493  * Provides content type for filename if one of the known types (else
494  * (either the prevtype or the default is returned).
495  *
496  * Returns some valid contenttype for filename.
497  *
498  ***************************************************************************/
499 static const char * ContentTypeForFilename (const char *filename,
500  const char *prevtype)
501 {
502  const char *contenttype = NULL;
503  unsigned int i;
504  /*
505  * No type was specified, we scan through a few well-known
506  * extensions and pick the first we match!
507  */
508  struct ContentType {
509  const char *extension;
510  const char *type;
511  };
512  static struct ContentType ctts[]={
513  {".gif", "image/gif"},
514  {".jpg", "image/jpeg"},
515  {".jpeg", "image/jpeg"},
516  {".txt", "text/plain"},
517  {".html", "text/html"}
518  };
519 
520  if(prevtype)
521  /* default to the previously set/used! */
522  contenttype = prevtype;
523  else
524  /* It seems RFC1867 defines no Content-Type to default to
525  text/plain so we don't actually need to set this: */
526  contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
527 
528  for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
529  if(strlen(filename) >= strlen(ctts[i].extension)) {
530  if(strequal(filename +
531  strlen(filename) - strlen(ctts[i].extension),
532  ctts[i].extension)) {
533  contenttype = ctts[i].type;
534  break;
535  }
536  }
537  }
538  /* we have a contenttype by now */
539  return contenttype;
540 }
541 
542 /***************************************************************************
543  *
544  * AllocAndCopy()
545  *
546  * Copies the data currently available under *buffer using newly allocated
547  * buffer (that becomes *buffer). Uses buffer_length if not null, else
548  * uses strlen to determine the length of the buffer to be copied
549  *
550  * Returns 0 on success and 1 if the malloc failed.
551  *
552  ***************************************************************************/
553 static int AllocAndCopy(char **buffer, size_t buffer_length)
554 {
555  const char *src = *buffer;
556  size_t length;
557  bool add = FALSE;
558  if (buffer_length)
559  length = buffer_length;
560  else {
561  length = strlen(*buffer);
562  add = TRUE;
563  }
564  *buffer = (char*)malloc(length+add);
565  if (!*buffer)
566  return 1;
567  memcpy(*buffer, src, length);
568  /* if length unknown do null termination */
569  if (add)
570  (*buffer)[length] = '\0';
571  return 0;
572 }
573 
574 /***************************************************************************
575  *
576  * FormAdd()
577  *
578  * Stores a 'name=value' formpost parameter and builds the appropriate
579  * linked list.
580  *
581  * Has two principal functionalities: using files and byte arrays as
582  * post parts. Byte arrays are either copied or just the pointer is stored
583  * (as the user requests) while for files only the filename and not the
584  * content is stored.
585  *
586  * While you may have only one byte array for each name, multiple filenames
587  * are allowed (and because of this feature CURLFORM_END is needed after
588  * using CURLFORM_FILE).
589  *
590  * Examples:
591  *
592  * Simple name/value pair with copied contents:
593  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
594  * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
595  *
596  * name/value pair where only the content pointer is remembered:
597  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
598  * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
599  * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
600  *
601  * storing a filename (CONTENTTYPE is optional!):
602  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
603  * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
604  * CURLFORM_END);
605  *
606  * storing multiple filenames:
607  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
608  * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
609  *
610  * Returns:
611  * CURL_FORMADD_OK on success
612  * CURL_FORMADD_MEMORY if the FormInfo allocation fails
613  * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
614  * CURL_FORMADD_NULL if a null pointer was given for a char
615  * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
616  * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
617  * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or an error)
618  * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
619  * CURL_FORMADD_MEMORY if some allocation for string copying failed.
620  * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
621  *
622  ***************************************************************************/
623 
624 static
625 CURLFORMcode FormAdd(struct curl_httppost **httppost,
626  struct curl_httppost **last_post,
627  va_list params)
628 {
629  FormInfo *first_form, *current_form, *form;
630  CURLFORMcode return_value = CURL_FORMADD_OK;
631  const char *prevtype = NULL;
632  struct curl_httppost *post = NULL;
633  CURLformoption option;
634  struct curl_forms *forms = NULL;
635  char *array_value=NULL; /* value read from an array */
636 
637  /* This is a state variable, that if TRUE means that we're parsing an
638  array that we got passed to us. If FALSE we're parsing the input
639  va_list arguments. */
640  bool array_state = FALSE;
641 
642  /*
643  * We need to allocate the first struct to fill in.
644  */
645  first_form = (FormInfo *)malloc(sizeof(struct FormInfo));
646  if(first_form) {
647  memset(first_form, 0, sizeof(FormInfo));
648  current_form = first_form;
649  }
650  else
651  return CURL_FORMADD_MEMORY;
652 
653  /*
654  * Loop through all the options set.
655  */
656  while (1) {
657 
658  /* break if we have an error to report */
659  if (return_value != CURL_FORMADD_OK)
660  break;
661 
662  /* first see if we have more parts of the array param */
663  if ( array_state ) {
664  /* get the upcoming option from the given array */
665  option = forms->option;
666  array_value = (char *)forms->value;
667 
668  forms++; /* advance this to next entry */
669  if (CURLFORM_END == option) {
670  /* end of array state */
671  array_state = FALSE;
672  continue;
673  }
674  }
675  else {
676  /* This is not array-state, get next option */
677  option = va_arg(params, CURLformoption);
678  if (CURLFORM_END == option)
679  break;
680  }
681 
682  switch (option) {
683  case CURLFORM_ARRAY:
684  if(array_state)
685  /* we don't support an array from within an array */
686  return_value = CURL_FORMADD_ILLEGAL_ARRAY;
687  else {
688  forms = va_arg(params, struct curl_forms *);
689  if (forms)
690  array_state = TRUE;
691  else
692  return_value = CURL_FORMADD_NULL;
693  }
694  break;
695 
696  /*
697  * Set the Name property.
698  */
699  case CURLFORM_PTRNAME:
700  current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
701  case CURLFORM_COPYNAME:
702  if (current_form->name)
703  return_value = CURL_FORMADD_OPTION_TWICE;
704  else {
705  char *name = array_state?
706  array_value:va_arg(params, char *);
707  if (name)
708  current_form->name = name; /* store for the moment */
709  else
710  return_value = CURL_FORMADD_NULL;
711  }
712  break;
713  case CURLFORM_NAMELENGTH:
714  if (current_form->namelength)
715  return_value = CURL_FORMADD_OPTION_TWICE;
716  else
717  current_form->namelength =
718  array_state?(long)array_value:va_arg(params, long);
719  break;
720 
721  /*
722  * Set the contents property.
723  */
724  case CURLFORM_PTRCONTENTS:
725  current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
726  case CURLFORM_COPYCONTENTS:
727  if (current_form->value)
728  return_value = CURL_FORMADD_OPTION_TWICE;
729  else {
730  char *value =
731  array_state?array_value:va_arg(params, char *);
732  if (value)
733  current_form->value = value; /* store for the moment */
734  else
735  return_value = CURL_FORMADD_NULL;
736  }
737  break;
738  case CURLFORM_CONTENTSLENGTH:
739  if (current_form->contentslength)
740  return_value = CURL_FORMADD_OPTION_TWICE;
741  else
742  current_form->contentslength =
743  array_state?(long)array_value:va_arg(params, long);
744  break;
745 
746  /* Get contents from a given file name */
747  case CURLFORM_FILECONTENT:
748  if (current_form->flags != 0)
749  return_value = CURL_FORMADD_OPTION_TWICE;
750  else {
751  char *filename = array_state?
752  array_value:va_arg(params, char *);
753  if (filename) {
754  current_form->value = strdup(filename);
755  current_form->flags |= HTTPPOST_READFILE;
756  }
757  else
758  return_value = CURL_FORMADD_NULL;
759  }
760  break;
761 
762  /* We upload a file */
763  case CURLFORM_FILE:
764  {
765  char *filename = array_state?array_value:
766  va_arg(params, char *);
767 
768  if (current_form->value) {
769  if (current_form->flags & HTTPPOST_FILENAME) {
770  if (filename) {
771  if (!(current_form = AddFormInfo(strdup(filename),
772  NULL, current_form)))
773  return_value = CURL_FORMADD_MEMORY;
774  }
775  else
776  return_value = CURL_FORMADD_NULL;
777  }
778  else
779  return_value = CURL_FORMADD_OPTION_TWICE;
780  }
781  else {
782  if (filename)
783  current_form->value = strdup(filename);
784  else
785  return_value = CURL_FORMADD_NULL;
786  current_form->flags |= HTTPPOST_FILENAME;
787  }
788  break;
789  }
790 
791  case CURLFORM_BUFFER:
792  {
793  char *filename = array_state?array_value:
794  va_arg(params, char *);
795 
796  if (current_form->value) {
797  if (current_form->flags & HTTPPOST_BUFFER) {
798  if (filename) {
799  if (!(current_form = AddFormInfo(strdup(filename),
800  NULL, current_form)))
801  return_value = CURL_FORMADD_MEMORY;
802  }
803  else
804  return_value = CURL_FORMADD_NULL;
805  }
806  else
807  return_value = CURL_FORMADD_OPTION_TWICE;
808  }
809  else {
810  if (filename)
811  current_form->value = strdup(filename);
812  else
813  return_value = CURL_FORMADD_NULL;
814  current_form->flags |= HTTPPOST_BUFFER;
815  }
816  break;
817  }
818 
819  case CURLFORM_BUFFERPTR:
820  current_form->flags |= HTTPPOST_PTRBUFFER;
821  if (current_form->buffer)
822  return_value = CURL_FORMADD_OPTION_TWICE;
823  else {
824  char *buffer =
825  array_state?array_value:va_arg(params, char *);
826  if (buffer)
827  current_form->buffer = buffer; /* store for the moment */
828  else
829  return_value = CURL_FORMADD_NULL;
830  }
831  break;
832 
833  case CURLFORM_BUFFERLENGTH:
834  if (current_form->bufferlength)
835  return_value = CURL_FORMADD_OPTION_TWICE;
836  else
837  current_form->bufferlength =
838  array_state?(long)array_value:va_arg(params, long);
839  break;
840 
841  case CURLFORM_CONTENTTYPE:
842  {
843  char *contenttype =
844  array_state?array_value:va_arg(params, char *);
845  if (current_form->contenttype) {
846  if (current_form->flags & HTTPPOST_FILENAME) {
847  if (contenttype) {
848  if (!(current_form = AddFormInfo(NULL,
849  strdup(contenttype),
850  current_form)))
851  return_value = CURL_FORMADD_MEMORY;
852  }
853  else
854  return_value = CURL_FORMADD_NULL;
855  }
856  else
857  return_value = CURL_FORMADD_OPTION_TWICE;
858  }
859  else {
860  if (contenttype)
861  current_form->contenttype = strdup(contenttype);
862  else
863  return_value = CURL_FORMADD_NULL;
864  }
865  break;
866  }
867  case CURLFORM_CONTENTHEADER:
868  {
869  /* this "cast increases required alignment of target type" but
870  we consider it OK anyway */
871  struct curl_slist* list = array_state?
872  (struct curl_slist*)array_value:
873  va_arg(params, struct curl_slist*);
874 
875  if( current_form->contentheader )
876  return_value = CURL_FORMADD_OPTION_TWICE;
877  else
878  current_form->contentheader = list;
879 
880  break;
881  }
882  case CURLFORM_FILENAME:
883  {
884  char *filename = array_state?array_value:
885  va_arg(params, char *);
886  if( current_form->showfilename )
887  return_value = CURL_FORMADD_OPTION_TWICE;
888  else
889  current_form->showfilename = strdup(filename);
890  break;
891  }
892  default:
893  return_value = CURL_FORMADD_UNKNOWN_OPTION;
894  }
895  }
896 
897  if(CURL_FORMADD_OK == return_value) {
898  /* go through the list, check for copleteness and if everything is
899  * alright add the HttpPost item otherwise set return_value accordingly */
900 
901  post = NULL;
902  for(form = first_form;
903  form != NULL;
904  form = form->more) {
905  if ( ((!form->name || !form->value) && !post) ||
906  ( (form->contentslength) &&
907  (form->flags & HTTPPOST_FILENAME) ) ||
908  ( (form->flags & HTTPPOST_FILENAME) &&
909  (form->flags & HTTPPOST_PTRCONTENTS) ) ||
910 
911  ( (!form->buffer) &&
912  (form->flags & HTTPPOST_BUFFER) &&
913  (form->flags & HTTPPOST_PTRBUFFER) ) ||
914 
915  ( (form->flags & HTTPPOST_READFILE) &&
916  (form->flags & HTTPPOST_PTRCONTENTS) )
917  ) {
918  return_value = CURL_FORMADD_INCOMPLETE;
919  break;
920  }
921  else {
922  if ( ((form->flags & HTTPPOST_FILENAME) ||
923  (form->flags & HTTPPOST_BUFFER)) &&
924  !form->contenttype ) {
925  /* our contenttype is missing */
926  form->contenttype
927  = strdup(ContentTypeForFilename(form->value, prevtype));
928  }
929  if ( !(form->flags & HTTPPOST_PTRNAME) &&
930  (form == first_form) ) {
931  /* copy name (without strdup; possibly contains null characters) */
932  if (AllocAndCopy(&form->name, form->namelength)) {
933  return_value = CURL_FORMADD_MEMORY;
934  break;
935  }
936  }
937  if ( !(form->flags & HTTPPOST_FILENAME) &&
938  !(form->flags & HTTPPOST_READFILE) &&
939  !(form->flags & HTTPPOST_PTRCONTENTS) &&
940  !(form->flags & HTTPPOST_PTRBUFFER) ) {
941 
942  /* copy value (without strdup; possibly contains null characters) */
943  if (AllocAndCopy(&form->value, form->contentslength)) {
944  return_value = CURL_FORMADD_MEMORY;
945  break;
946  }
947  }
948  post = AddHttpPost(form->name, form->namelength,
949  form->value, form->contentslength,
950  form->buffer, form->bufferlength,
951  form->contenttype, form->flags,
952  form->contentheader, form->showfilename,
953  post, httppost,
954  last_post);
955 
956  if(!post)
957  return_value = CURL_FORMADD_MEMORY;
958 
959  if (form->contenttype)
960  prevtype = form->contenttype;
961  }
962  }
963  }
964 
965  /* always delete the allocated memory before returning */
966  form = first_form;
967  while (form != NULL) {
968  FormInfo *delete_form;
969 
970  delete_form = form;
971  form = form->more;
972  free (delete_form);
973  }
974 
975  return return_value;
976 }
977 
979  struct curl_httppost **last_post,
980  ...)
981 {
982  va_list arg;
984  va_start(arg, last_post);
985  result = FormAdd(httppost, last_post, arg);
986  va_end(arg);
987  return result;
988 }
989 
990 static size_t AddFormData(struct FormData **formp,
991  const void *line,
992  size_t length)
993 {
994  struct FormData *newform = (struct FormData *)
995  malloc(sizeof(struct FormData));
996  newform->next = NULL;
997 
998  /* we make it easier for plain strings: */
999  if(!length)
1000  length = strlen((char *)line);
1001 
1002  newform->line = (char *)malloc(length+1);
1003  memcpy(newform->line, line, length);
1004  newform->length = length;
1005  newform->line[length]=0; /* zero terminate for easier debugging */
1006 
1007  if(*formp) {
1008  (*formp)->next = newform;
1009  *formp = newform;
1010  }
1011  else
1012  *formp = newform;
1013 
1014  return length;
1015 }
1016 
1017 
1018 static size_t AddFormDataf(struct FormData **formp,
1019  const char *fmt, ...)
1020 {
1021  char s[4096];
1022  va_list ap;
1023  va_start(ap, fmt);
1024  vsprintf(s, fmt, ap);
1025  va_end(ap);
1026 
1027  return AddFormData(formp, s, 0);
1028 }
1029 
1030 
1032 {
1033  char *retstring;
1034  static int randomizer=0; /* this is just so that two boundaries within
1035  the same form won't be identical */
1036  size_t i;
1037 
1038  static char table16[]="abcdef0123456789";
1039 
1040  retstring = (char *)malloc(BOUNDARY_LENGTH+1);
1041 
1042  if(!retstring)
1043  return NULL; /* failed */
1044 
1045  srand(time(NULL)+randomizer++); /* seed */
1046 
1047  strcpy(retstring, "----------------------------");
1048 
1049  for(i=strlen(retstring); i<BOUNDARY_LENGTH; i++)
1050  retstring[i] = table16[rand()%16];
1051 
1052  /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
1053  combinations */
1054  retstring[BOUNDARY_LENGTH]=0; /* zero terminate */
1055 
1056  return retstring;
1057 }
1058 
1059 /* Used from http.c, this cleans a built FormData linked list */
1060 void Curl_formclean(struct FormData *form)
1061 {
1062  struct FormData *next;
1063 
1064  do {
1065  next=form->next; /* the following form line */
1066  free(form->line); /* free the line */
1067  free(form); /* free the struct */
1068 
1069  } while((form=next)); /* continue */
1070 }
1071 
1072 /* external function to free up a whole form post chain */
1073 void curl_formfree(struct curl_httppost *form)
1074 {
1075  struct curl_httppost *next;
1076 
1077  if(!form)
1078  /* no form to free, just get out of this */
1079  return;
1080 
1081  do {
1082  next=form->next; /* the following form line */
1083 
1084  /* recurse to sub-contents */
1085  if(form->more)
1086  curl_formfree(form->more);
1087 
1088  if( !(form->flags & HTTPPOST_PTRNAME) && form->name)
1089  free(form->name); /* free the name */
1090  if( !(form->flags & HTTPPOST_PTRCONTENTS) && form->contents)
1091  free(form->contents); /* free the contents */
1092  if(form->contenttype)
1093  free(form->contenttype); /* free the content type */
1094  if(form->showfilename)
1095  free(form->showfilename); /* free the faked file name */
1096  free(form); /* free the struct */
1097 
1098  } while((form=next)); /* continue */
1099 }
1100 
1102  struct curl_httppost *post,
1103  curl_off_t *sizep)
1104 {
1105  struct FormData *form = NULL;
1106  struct FormData *firstform;
1107  struct curl_httppost *file;
1109 
1110  size_t size =0;
1111  char *boundary;
1112  char *fileboundary=NULL;
1113  struct curl_slist* curList;
1114 
1115  *finalform=NULL; /* default form is empty */
1116 
1117  if(!post)
1118  return result; /* no input => no output! */
1119 
1120  boundary = Curl_FormBoundary();
1121 
1122  /* Make the first line of the output */
1123  AddFormDataf(&form,
1124  "Content-Type: multipart/form-data;"
1125  " boundary=%s\r\n",
1126  boundary);
1127  /* we DO NOT count that line since that'll be part of the header! */
1128 
1129  firstform = form;
1130 
1131  do {
1132 
1133  if(size)
1134  size += AddFormDataf(&form, "\r\n");
1135 
1136  /* boundary */
1137  size += AddFormDataf(&form, "--%s\r\n", boundary);
1138 
1139  size += AddFormData(&form,
1140  "Content-Disposition: form-data; name=\"", 0);
1141 
1142  size += AddFormData(&form, post->name, post->namelength);
1143 
1144  size += AddFormData(&form, "\"", 0);
1145 
1146  if(post->more) {
1147  /* If used, this is a link to more file names, we must then do
1148  the magic to include several files with the same field name */
1149 
1150  fileboundary = Curl_FormBoundary();
1151 
1152  size += AddFormDataf(&form,
1153  "\r\nContent-Type: multipart/mixed,"
1154  " boundary=%s\r\n",
1155  fileboundary);
1156  }
1157 
1158  file = post;
1159 
1160  do {
1161 
1162  /* If 'showfilename' is set, that is a faked name passed on to us
1163  to use to in the formpost. If that is not set, the actually used
1164  local file name should be added. */
1165 
1166  if(post->more) {
1167  /* if multiple-file */
1168  size += AddFormDataf(&form,
1169  "\r\n--%s\r\nContent-Disposition: "
1170  "attachment; filename=\"%s\"",
1171  fileboundary,
1172  (file->showfilename?file->showfilename:
1173  file->contents));
1174  }
1175  else if((post->flags & HTTPPOST_FILENAME) ||
1176  (post->flags & HTTPPOST_BUFFER)) {
1177 
1178  size += AddFormDataf(&form,
1179  "; filename=\"%s\"",
1180  (post->showfilename?post->showfilename:
1181  post->contents));
1182  }
1183 
1184  if(file->contenttype) {
1185  /* we have a specified type */
1186  size += AddFormDataf(&form,
1187  "\r\nContent-Type: %s",
1188  file->contenttype);
1189  }
1190 
1191  curList = file->contentheader;
1192  while( curList ) {
1193  /* Process the additional headers specified for this form */
1194  size += AddFormDataf( &form, "\r\n%s", curList->data );
1195  curList = curList->next;
1196  }
1197 
1198 #if 0
1199  /* The header Content-Transfer-Encoding: seems to confuse some receivers
1200  * (like the built-in PHP engine). While I can't see any reason why it
1201  * should, I can just as well skip this to the benefit of the users who
1202  * are using such confused receivers.
1203  */
1204 
1205  if(file->contenttype &&
1206  !checkprefix("text/", file->contenttype)) {
1207  /* this is not a text content, mention our binary encoding */
1208  size += AddFormData(&form, "\r\nContent-Transfer-Encoding: binary", 0);
1209  }
1210 #endif
1211 
1212  size += AddFormData(&form, "\r\n\r\n", 0);
1213 
1214  if((post->flags & HTTPPOST_FILENAME) ||
1215  (post->flags & HTTPPOST_READFILE)) {
1216  /* we should include the contents from the specified file */
1217  FILE *fileread;
1218  char buffer[1024];
1219  size_t nread;
1220 
1221  fileread = strequal("-", file->contents)?stdin:
1222  /* binary read for win32 crap */
1223  /*VMS??*/ fopen(file->contents, "rb"); /* ONLY ALLOWS FOR STREAM FILES ON VMS */
1224  /*VMS?? Stream files are OK, as are FIXED & VAR files WITHOUT implied CC */
1225  /*VMS?? For implied CC, every record needs to have a \n appended & 1 added to SIZE */
1226  if(fileread) {
1227  while((nread = fread(buffer, 1, 1024, fileread)))
1228  size += AddFormData(&form, buffer, nread);
1229 
1230  if(fileread != stdin)
1231  fclose(fileread);
1232  }
1233  else {
1234 #if 0
1235  /* File wasn't found, add a nothing field! */
1236  size += AddFormData(&form, "", 0);
1237 #endif
1238  Curl_formclean(firstform);
1239  free(boundary);
1240  *finalform = NULL;
1241  return CURLE_READ_ERROR;
1242  }
1243 
1244  }
1245  else if (post->flags & HTTPPOST_BUFFER) {
1246  /* include contents of buffer */
1247  size += AddFormData(&form, post->buffer, post->bufferlength);
1248  }
1249 
1250  else {
1251  /* include the contents we got */
1252  size += AddFormData(&form, post->contents, post->contentslength);
1253  }
1254  } while((file = file->more)); /* for each specified file for this field */
1255 
1256  if(post->more) {
1257  /* this was a multiple-file inclusion, make a termination file
1258  boundary: */
1259  size += AddFormDataf(&form,
1260  "\r\n--%s--",
1261  fileboundary);
1262  free(fileboundary);
1263  }
1264 
1265  } while((post=post->next)); /* for each field */
1266 
1267  /* end-boundary for everything */
1268  size += AddFormDataf(&form,
1269  "\r\n--%s--\r\n",
1270  boundary);
1271 
1272  *sizep = size;
1273 
1274  free(boundary);
1275 
1276  *finalform=firstform;
1277 
1278  return result;
1279 }
1280 
1281 int Curl_FormInit(struct Form *form, struct FormData *formdata )
1282 {
1283  if(!formdata)
1284  return 1; /* error */
1285 
1286  form->data = formdata;
1287  form->sent = 0;
1288 
1289  return 0;
1290 }
1291 
1292 /* fread() emulation */
1293 size_t Curl_FormReader(char *buffer,
1294  size_t size,
1295  size_t nitems,
1296  FILE *mydata)
1297 {
1298  struct Form *form;
1299  size_t wantedsize;
1300  size_t gotsize = 0;
1301 
1302  form=(struct Form *)mydata;
1303 
1304  wantedsize = size * nitems;
1305 
1306  if(!form->data)
1307  return 0; /* nothing, error, empty */
1308 
1309  do {
1310 
1311  if( (form->data->length - form->sent ) > wantedsize - gotsize) {
1312 
1313  memcpy(buffer + gotsize , form->data->line + form->sent,
1314  wantedsize - gotsize);
1315 
1316  form->sent += wantedsize-gotsize;
1317 
1318  return wantedsize;
1319  }
1320 
1321  memcpy(buffer+gotsize,
1322  form->data->line + form->sent,
1323  (form->data->length - form->sent) );
1324  gotsize += form->data->length - form->sent;
1325 
1326  form->sent = 0;
1327 
1328  form->data = form->data->next; /* advance */
1329 
1330  } while(form->data);
1331  /* If we got an empty line and we have more data, we proceed to the next
1332  line immediately to avoid returning zero before we've reached the end.
1333  This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
1334 
1335  return gotsize;
1336 }
1337 
1338 /* possible (old) fread() emulation that copies at most one line */
1339 size_t Curl_FormReadOneLine(char *buffer,
1340  size_t size,
1341  size_t nitems,
1342  FILE *mydata)
1343 {
1344  struct Form *form;
1345  size_t wantedsize;
1346  size_t gotsize;
1347 
1348  form=(struct Form *)mydata;
1349 
1350  wantedsize = size * nitems;
1351 
1352  if(!form->data)
1353  return 0; /* nothing, error, empty */
1354 
1355  do {
1356 
1357  if( (form->data->length - form->sent ) > wantedsize ) {
1358 
1359  memcpy(buffer, form->data->line + form->sent, wantedsize);
1360 
1361  form->sent += wantedsize;
1362 
1363  return wantedsize;
1364  }
1365 
1366  memcpy(buffer,
1367  form->data->line + form->sent,
1368  gotsize = (form->data->length - form->sent) );
1369 
1370  form->sent = 0;
1371 
1372  form->data = form->data->next; /* advance */
1373 
1374  } while(!gotsize && form->data);
1375  /* If we got an empty line and we have more data, we proceed to the next
1376  line immediately to avoid returning zero before we've reached the end.
1377  This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
1378 
1379  return gotsize;
1380 }
1381 
1382 
1383 #ifdef _FORM_DEBUG
1384 int FormAddTest(const char * errormsg,
1385  struct curl_httppost **httppost,
1386  struct curl_httppost **last_post,
1387  ...)
1388 {
1389  int result;
1390  va_list arg;
1391  va_start(arg, last_post);
1392  if ((result = FormAdd(httppost, last_post, arg)))
1393  fprintf (stderr, "ERROR doing FormAdd ret: %d action: %s\n", result,
1394  errormsg);
1395  va_end(arg);
1396  return result;
1397 }
1398 
1399 
1400 int main()
1401 {
1402  char name1[] = "simple_COPYCONTENTS";
1403  char name2[] = "COPYCONTENTS_+_CONTENTTYPE";
1404  char name3[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH";
1405  char name4[] = "simple_PTRCONTENTS";
1406  char name5[] = "PTRCONTENTS_+_CONTENTSLENGTH";
1407  char name6[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE";
1408  char name7[] = "FILE1_+_CONTENTTYPE";
1409  char name8[] = "FILE1_+_FILE2";
1410  char name9[] = "FILE1_+_FILE2_+_FILE3";
1411  char name10[] = "ARRAY: FILE1_+_FILE2_+_FILE3";
1412  char name11[] = "FILECONTENT";
1413  char value1[] = "value for simple COPYCONTENTS";
1414  char value2[] = "value for COPYCONTENTS + CONTENTTYPE";
1415  char value3[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH";
1416  char value4[] = "value for simple PTRCONTENTS";
1417  char value5[] = "value for PTRCONTENTS + CONTENTSLENGTH";
1418  char value6[] = "value for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE";
1419  char value7[] = "inet_ntoa_r.h";
1420  char value8[] = "Makefile.b32.resp";
1421  char type2[] = "image/gif";
1422  char type6[] = "text/plain";
1423  char type7[] = "text/html";
1424  int name3length = strlen(name3);
1425  int value3length = strlen(value3);
1426  int value5length = strlen(value4);
1427  int value6length = strlen(value5);
1428  int errors = 0;
1429  int size;
1430  size_t nread;
1431  char buffer[4096];
1432  struct curl_httppost *httppost=NULL;
1433  struct curl_httppost *last_post=NULL;
1434  struct curl_forms forms[4];
1435 
1436  struct FormData *form;
1437  struct Form formread;
1438 
1439  if (FormAddTest("simple COPYCONTENTS test", &httppost, &last_post,
1440  CURLFORM_COPYNAME, name1, CURLFORM_COPYCONTENTS, value1,
1441  CURLFORM_END))
1442  ++errors;
1443  if (FormAddTest("COPYCONTENTS + CONTENTTYPE test", &httppost, &last_post,
1444  CURLFORM_COPYNAME, name2, CURLFORM_COPYCONTENTS, value2,
1445  CURLFORM_CONTENTTYPE, type2, CURLFORM_END))
1446  ++errors;
1447  /* make null character at start to check that contentslength works
1448  correctly */
1449  name3[1] = '\0';
1450  value3[1] = '\0';
1451  if (FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test",
1452  &httppost, &last_post,
1453  CURLFORM_PTRNAME, name3, CURLFORM_COPYCONTENTS, value3,
1454  CURLFORM_CONTENTSLENGTH, value3length,
1455  CURLFORM_NAMELENGTH, name3length, CURLFORM_END))
1456  ++errors;
1457  if (FormAddTest("simple PTRCONTENTS test", &httppost, &last_post,
1458  CURLFORM_COPYNAME, name4, CURLFORM_PTRCONTENTS, value4,
1459  CURLFORM_END))
1460  ++errors;
1461  /* make null character at start to check that contentslength works
1462  correctly */
1463  value5[1] = '\0';
1464  if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost, &last_post,
1465  CURLFORM_COPYNAME, name5, CURLFORM_PTRCONTENTS, value5,
1466  CURLFORM_CONTENTSLENGTH, value5length, CURLFORM_END))
1467  ++errors;
1468  /* make null character at start to check that contentslength works
1469  correctly */
1470  value6[1] = '\0';
1471  if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test",
1472  &httppost, &last_post,
1473  CURLFORM_COPYNAME, name6, CURLFORM_PTRCONTENTS, value6,
1474  CURLFORM_CONTENTSLENGTH, value6length,
1475  CURLFORM_CONTENTTYPE, type6, CURLFORM_END))
1476  ++errors;
1477  if (FormAddTest("FILE + CONTENTTYPE test", &httppost, &last_post,
1478  CURLFORM_COPYNAME, name7, CURLFORM_FILE, value7,
1479  CURLFORM_CONTENTTYPE, type7, CURLFORM_END))
1480  ++errors;
1481  if (FormAddTest("FILE1 + FILE2 test", &httppost, &last_post,
1482  CURLFORM_COPYNAME, name8, CURLFORM_FILE, value7,
1483  CURLFORM_FILE, value8, CURLFORM_END))
1484  ++errors;
1485  if (FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost, &last_post,
1486  CURLFORM_COPYNAME, name9, CURLFORM_FILE, value7,
1487  CURLFORM_FILE, value8, CURLFORM_FILE, value7, CURLFORM_END))
1488  ++errors;
1489  forms[0].option = CURLFORM_FILE;
1490  forms[0].value = value7;
1491  forms[1].option = CURLFORM_FILE;
1492  forms[1].value = value8;
1493  forms[2].option = CURLFORM_FILE;
1494  forms[2].value = value7;
1495  forms[3].option = CURLFORM_END;
1496  if (FormAddTest("FILE1 + FILE2 + FILE3 ARRAY test", &httppost, &last_post,
1497  CURLFORM_COPYNAME, name10, CURLFORM_ARRAY, forms,
1498  CURLFORM_END))
1499  ++errors;
1500  if (FormAddTest("FILECONTENT test", &httppost, &last_post,
1501  CURLFORM_COPYNAME, name11, CURLFORM_FILECONTENT, value7,
1502  CURLFORM_END))
1503  ++errors;
1504 
1505  form=Curl_getFormData(httppost, &size);
1506 
1507  Curl_FormInit(&formread, form);
1508 
1509  do {
1510  nread = Curl_FormReader(buffer, 1, sizeof(buffer),
1511  (FILE *)&formread);
1512 
1513  if(-1 == nread)
1514  break;
1515  fwrite(buffer, nread, 1, stdout);
1516  } while(1);
1517 
1518  fprintf(stdout, "size: %d\n", size);
1519  if (errors)
1520  fprintf(stdout, "\n==> %d Test(s) failed!\n", errors);
1521  else
1522  fprintf(stdout, "\nAll Tests seem to have worked (please check output)\n");
1523 
1524  return 0;
1525 }
1526 
1527 #endif
1528 
1529 #ifdef _OLD_FORM_DEBUG
1530 
1531 int main(int argc, char **argv)
1532 {
1533 #if 0
1534  char *testargs[]={
1535  "name1 = data in number one",
1536  "name2 = number two data",
1537  "test = @upload"
1538  };
1539 #endif
1540  int i;
1541  char *nextarg;
1542  struct curl_httppost *httppost=NULL;
1543  struct curl_httppost *last_post=NULL;
1544  struct curl_httppost *post;
1545  int size;
1546  int nread;
1547  char buffer[4096];
1548 
1549  struct FormData *form;
1550  struct Form formread;
1551 
1552  for(i=1; i<argc; i++) {
1553 
1554  if( FormParse( argv[i],
1555  &httppost,
1556  &last_post)) {
1557  fprintf(stderr, "Illegally formatted input field: '%s'!\n",
1558  argv[i]);
1559  return 1;
1560  }
1561  }
1562 
1563  form=Curl_getFormData(httppost, &size);
1564 
1565  Curl_FormInit(&formread, form);
1566 
1567  do {
1568  nread = Curl_FormReader(buffer, 1, sizeof(buffer),
1569  (FILE *)&formread);
1570 
1571  if(-1 == nread)
1572  break;
1573  fwrite(buffer, nread, 1, stderr);
1574  } while(1);
1575 
1576  fprintf(stderr, "size: %d\n", size);
1577 
1578  return 0;
1579 }
1580 
1581 #endif
1582 
1583 #endif /* CURL_DISABLE_HTTP */
CURLformoption option
Definition: curl.h:934
char * contenttype
Definition: formdata.h:45
void Curl_formclean(struct FormData *form)
Definition: formdata.c:1060
GLsizei const GLfloat * value
Definition: glext.h:3614
size_t length
Definition: formdata.h:30
struct FormData * data
Definition: formdata.h:34
#define strequal(a, b)
Definition: strequal.h:32
#define main(x, y)
Definition: config-mac.h:9
CURLformoption
Definition: curl.h:902
#define HTTPPOST_CONTENTTYPE_DEFAULT
Definition: formdata.c:139
int Curl_FormInit(struct Form *form, struct FormData *formdata)
Definition: formdata.c:1281
char * data
Definition: curl.h:1062
char * name
Definition: formdata.h:41
CURLcode
Definition: curl.h:209
#define HTTPPOST_READFILE
Definition: curl.h:146
long namelength
Definition: curl.h:134
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
char * line
Definition: formdata.h:29
GLdouble s
Definition: glext.h:2935
GLuint src
Definition: glext.h:5390
size_t Curl_FormReader(char *buffer, size_t size, size_t nitems, FILE *mydata)
Definition: formdata.c:1293
off_t curl_off_t
Definition: curl.h:96
char * showfilename
Definition: formdata.h:49
char * contenttype
Definition: curl.h:139
int i
Definition: process.py:33
Boolean result
#define FORM_FILE_SEPARATOR
Definition: formdata.c:171
struct curl_slist * contentheader
Definition: formdata.h:51
unsigned int sent
Definition: formdata.h:35
#define HTTPPOST_PTRCONTENTS
Definition: curl.h:149
#define HTTPPOST_FILENAME
Definition: curl.h:145
struct curl_httppost * more
Definition: curl.h:141
int curl_formparse(char *input, struct curl_httppost **httppost, struct curl_httppost **last_post)
Definition: formdata.c:383
char * showfilename
Definition: curl.h:154
long flags
Definition: formdata.h:46
#define HTTPPOST_PTRNAME
Definition: curl.h:147
char * buffer
Definition: curl.h:137
#define NULL
Definition: Lib.h:88
char * buffer
Definition: formdata.h:47
char * Curl_FormBoundary(void)
Definition: formdata.c:1031
struct curl_slist * next
Definition: curl.h:1063
GLuint buffer
Definition: glext.h:3108
#define FORM_TYPE_SEPARATOR
Definition: formdata.c:172
long flags
Definition: curl.h:144
CURLFORMcode
Definition: curl.h:954
GLenum GLenum GLenum input
Definition: glext.h:4803
#define HTTPPOST_BUFFER
Definition: curl.h:151
long bufferlength
Definition: curl.h:138
char * value
Definition: formdata.h:43
void curl_formfree(struct curl_httppost *form)
Definition: formdata.c:1073
Definition: curl.h:210
#define checkprefix(a, b)
Definition: strequal.h:37
long contentslength
Definition: curl.h:136
size_t Curl_FormReadOneLine(char *buffer, size_t size, size_t nitems, FILE *mydata)
Definition: formdata.c:1339
char * strdup(char *s1)
Definition: main.c:183
CURLFORMcode curl_formadd(struct curl_httppost **httppost, struct curl_httppost **last_post,...)
Definition: formdata.c:978
#define HTTPPOST_PTRBUFFER
Definition: curl.h:152
size_t fread(void *, size_t, size_t, FILE *)
CURLcode Curl_getFormData(struct FormData **finalform, struct curl_httppost *post, curl_off_t *sizep)
Definition: formdata.c:1101
char * name
Definition: curl.h:133
const GLcharARB * name
Definition: glext.h:3629
GLsizeiptr size
Definition: glext.h:3112
size_t namelength
Definition: formdata.h:42
const char * value
Definition: curl.h:935
#define BOUNDARY_LENGTH
Definition: formdata.c:135
struct curl_slist * contentheader
Definition: curl.h:140
GLsizei const GLcharARB const GLint * length
Definition: glext.h:3599
int vsprintf(idStr &string, const char *fmt, va_list argptr)
Definition: Str.cpp:1549
struct curl_httppost * next
Definition: curl.h:132
#define FALSE
Definition: mprintf.c:70
Definition: formdata.h:33
#define TRUE
Definition: mprintf.c:69
size_t bufferlength
Definition: formdata.h:48
if(!ValidDisplayID(prefInfo.prefDisplayID)) prefInfo.prefDisplayID
struct FormData * next
Definition: formdata.h:28
size_t contentslength
Definition: formdata.h:44
size_t fwrite(const void *, size_t, size_t, FILE *)
char * contents
Definition: curl.h:135
GLenum const GLfloat * params
Definition: glext.h:2847
struct FormInfo * more
Definition: formdata.h:52