Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Utilities / cmcurl / formdata.c
blob40fda3d1f59fa9812ffa51ea02dc1f7e1466a390
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: formdata.c,v 1.3 2007/03/15 19:22:13 andy Exp $
22 ***************************************************************************/
25 Debug the form generator stand-alone by compiling this source file with:
27 gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -DCURLDEBUG -o formdata -I../include formdata.c strequal.c memdebug.c mprintf.c strerror.c
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:
33 Content-Disposition: form-data; name="simple_COPYCONTENTS"
34 value for simple COPYCONTENTS
36 Content-Disposition: form-data; name="COPYCONTENTS_+_CONTENTTYPE"
37 Content-Type: image/gif
38 value for COPYCONTENTS + CONTENTTYPE
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)
44 Content-Disposition: form-data; name="simple_PTRCONTENTS"
45 value for simple PTRCONTENTS
47 Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH"
48 vlue for PTRCONTENTS + CONTENTSLENGTH
49 (or you might see v^@lue at the start)
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)
56 Content-Disposition: form-data; name="FILE1_+_CONTENTTYPE"; filename="inet_ntoa_r.h"
57 Content-Type: text/html
58 ...
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"
67 Content-Type: text/plain
68 ...
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"
77 Content-Type: text/plain
78 ...
79 Content-Disposition: attachment; filename="inet_ntoa_r.h"
80 Content-Type: text/plain
81 ...
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"
91 Content-Type: text/plain
92 ...
93 Content-Disposition: attachment; filename="inet_ntoa_r.h"
94 Content-Type: text/plain
95 ...
97 Content-Disposition: form-data; name="FILECONTENT"
98 ...
102 #include "setup.h"
103 #include <curl/curl.h>
105 /* Length of the random boundary string. */
106 #define BOUNDARY_LENGTH 40
108 #if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
110 #include <stdio.h>
111 #include <stdlib.h>
112 #include <string.h>
113 #include <stdarg.h>
114 #include <time.h>
115 #ifdef HAVE_SYS_STAT_H
116 #include <sys/stat.h>
117 #endif
118 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
119 #include <libgen.h>
120 #endif
121 #include "urldata.h" /* for struct SessionHandle */
122 #include "easyif.h" /* for Curl_convert_... prototypes */
123 #include "formdata.h"
124 #include "strequal.h"
125 #include "memory.h"
127 #define _MPRINTF_REPLACE /* use our functions only */
128 #include <curl/mprintf.h>
130 /* The last #include file should be: */
131 #include "memdebug.h"
133 #endif /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */
135 #ifndef CURL_DISABLE_HTTP
137 #if defined(HAVE_BASENAME) && defined(NEED_BASENAME_PROTO)
138 /* This system has a basename() but no prototype for it! */
139 char *basename(char *path);
140 #endif
142 static size_t readfromfile(struct Form *form, char *buffer, size_t size);
144 /* What kind of Content-Type to use on un-specified files with unrecognized
145 extensions. */
146 #define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
148 #define FORM_FILE_SEPARATOR ','
149 #define FORM_TYPE_SEPARATOR ';'
151 /***************************************************************************
153 * AddHttpPost()
155 * Adds a HttpPost structure to the list, if parent_post is given becomes
156 * a subpost of parent_post instead of a direct list element.
158 * Returns newly allocated HttpPost on success and NULL if malloc failed.
160 ***************************************************************************/
161 static struct curl_httppost *
162 AddHttpPost(char * name, size_t namelength,
163 char * value, size_t contentslength,
164 char * buffer, size_t bufferlength,
165 char *contenttype,
166 long flags,
167 struct curl_slist* contentHeader,
168 char *showfilename,
169 struct curl_httppost *parent_post,
170 struct curl_httppost **httppost,
171 struct curl_httppost **last_post)
173 struct curl_httppost *post;
174 post = (struct curl_httppost *)calloc(sizeof(struct curl_httppost), 1);
175 if(post) {
176 post->name = name;
177 post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
178 post->contents = value;
179 post->contentslength = (long)contentslength;
180 post->buffer = buffer;
181 post->bufferlength = (long)bufferlength;
182 post->contenttype = contenttype;
183 post->contentheader = contentHeader;
184 post->showfilename = showfilename;
185 post->flags = flags;
187 else
188 return NULL;
190 if (parent_post) {
191 /* now, point our 'more' to the original 'more' */
192 post->more = parent_post->more;
194 /* then move the original 'more' to point to ourselves */
195 parent_post->more = post;
197 else {
198 /* make the previous point to this */
199 if(*last_post)
200 (*last_post)->next = post;
201 else
202 (*httppost) = post;
204 (*last_post) = post;
206 return post;
209 /***************************************************************************
211 * AddFormInfo()
213 * Adds a FormInfo structure to the list presented by parent_form_info.
215 * Returns newly allocated FormInfo on success and NULL if malloc failed/
216 * parent_form_info is NULL.
218 ***************************************************************************/
219 static FormInfo * AddFormInfo(char *value,
220 char *contenttype,
221 FormInfo *parent_form_info)
223 FormInfo *form_info;
224 form_info = (FormInfo *)malloc(sizeof(FormInfo));
225 if(form_info) {
226 memset(form_info, 0, sizeof(FormInfo));
227 if (value)
228 form_info->value = value;
229 if (contenttype)
230 form_info->contenttype = contenttype;
231 form_info->flags = HTTPPOST_FILENAME;
233 else
234 return NULL;
236 if (parent_form_info) {
237 /* now, point our 'more' to the original 'more' */
238 form_info->more = parent_form_info->more;
240 /* then move the original 'more' to point to ourselves */
241 parent_form_info->more = form_info;
243 else
244 return NULL;
246 return form_info;
249 /***************************************************************************
251 * ContentTypeForFilename()
253 * Provides content type for filename if one of the known types (else
254 * (either the prevtype or the default is returned).
256 * Returns some valid contenttype for filename.
258 ***************************************************************************/
259 static const char * ContentTypeForFilename (const char *filename,
260 const char *prevtype)
262 const char *contenttype = NULL;
263 unsigned int i;
265 * No type was specified, we scan through a few well-known
266 * extensions and pick the first we match!
268 struct ContentType {
269 const char *extension;
270 const char *type;
272 static const struct ContentType ctts[]={
273 {".gif", "image/gif"},
274 {".jpg", "image/jpeg"},
275 {".jpeg", "image/jpeg"},
276 {".txt", "text/plain"},
277 {".html", "text/html"}
280 if(prevtype)
281 /* default to the previously set/used! */
282 contenttype = prevtype;
283 else
284 /* It seems RFC1867 defines no Content-Type to default to
285 text/plain so we don't actually need to set this: */
286 contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
288 for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
289 if(strlen(filename) >= strlen(ctts[i].extension)) {
290 if(strequal(filename +
291 strlen(filename) - strlen(ctts[i].extension),
292 ctts[i].extension)) {
293 contenttype = ctts[i].type;
294 break;
298 /* we have a contenttype by now */
299 return contenttype;
302 /***************************************************************************
304 * memdup()
306 * Copies the 'source' data to a newly allocated buffer buffer (that is
307 * returned). Uses buffer_length if not null, else uses strlen to determine
308 * the length of the buffer to be copied
310 * Returns the new pointer or NULL on failure.
312 ***************************************************************************/
313 static char *memdup(const char *src, size_t buffer_length)
315 size_t length;
316 bool add = FALSE;
317 char *buffer;
319 if (buffer_length)
320 length = buffer_length;
321 else {
322 length = strlen(src);
323 add = TRUE;
325 buffer = (char*)malloc(length+add);
326 if (!buffer)
327 return NULL; /* fail */
329 memcpy(buffer, src, length);
331 /* if length unknown do null termination */
332 if (add)
333 buffer[length] = '\0';
335 return buffer;
338 /***************************************************************************
340 * FormAdd()
342 * Stores a formpost parameter and builds the appropriate linked list.
344 * Has two principal functionalities: using files and byte arrays as
345 * post parts. Byte arrays are either copied or just the pointer is stored
346 * (as the user requests) while for files only the filename and not the
347 * content is stored.
349 * While you may have only one byte array for each name, multiple filenames
350 * are allowed (and because of this feature CURLFORM_END is needed after
351 * using CURLFORM_FILE).
353 * Examples:
355 * Simple name/value pair with copied contents:
356 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
357 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
359 * name/value pair where only the content pointer is remembered:
360 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
361 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
362 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
364 * storing a filename (CONTENTTYPE is optional!):
365 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
366 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
367 * CURLFORM_END);
369 * storing multiple filenames:
370 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
371 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
373 * Returns:
374 * CURL_FORMADD_OK on success
375 * CURL_FORMADD_MEMORY if the FormInfo allocation fails
376 * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
377 * CURL_FORMADD_NULL if a null pointer was given for a char
378 * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
379 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
380 * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or an error)
381 * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
382 * CURL_FORMADD_MEMORY if some allocation for string copying failed.
383 * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
385 ***************************************************************************/
387 static
388 CURLFORMcode FormAdd(struct curl_httppost **httppost,
389 struct curl_httppost **last_post,
390 va_list params)
392 FormInfo *first_form, *current_form, *form = NULL;
393 CURLFORMcode return_value = CURL_FORMADD_OK;
394 const char *prevtype = NULL;
395 struct curl_httppost *post = NULL;
396 CURLformoption option;
397 struct curl_forms *forms = NULL;
398 char *array_value=NULL; /* value read from an array */
400 /* This is a state variable, that if TRUE means that we're parsing an
401 array that we got passed to us. If FALSE we're parsing the input
402 va_list arguments. */
403 bool array_state = FALSE;
406 * We need to allocate the first struct to fill in.
408 first_form = (FormInfo *)calloc(sizeof(struct FormInfo), 1);
409 if(!first_form)
410 return CURL_FORMADD_MEMORY;
412 current_form = first_form;
415 * Loop through all the options set. Break if we have an error to report.
417 while (return_value == CURL_FORMADD_OK) {
419 /* first see if we have more parts of the array param */
420 if ( array_state ) {
421 /* get the upcoming option from the given array */
422 option = forms->option;
423 array_value = (char *)forms->value;
425 forms++; /* advance this to next entry */
426 if (CURLFORM_END == option) {
427 /* end of array state */
428 array_state = FALSE;
429 continue;
432 else {
433 /* This is not array-state, get next option */
434 option = va_arg(params, CURLformoption);
435 if (CURLFORM_END == option)
436 break;
439 switch (option) {
440 case CURLFORM_ARRAY:
441 if(array_state)
442 /* we don't support an array from within an array */
443 return_value = CURL_FORMADD_ILLEGAL_ARRAY;
444 else {
445 forms = va_arg(params, struct curl_forms *);
446 if (forms)
447 array_state = TRUE;
448 else
449 return_value = CURL_FORMADD_NULL;
451 break;
454 * Set the Name property.
456 case CURLFORM_PTRNAME:
457 #ifdef CURL_DOES_CONVERSIONS
458 /* treat CURLFORM_PTR like CURLFORM_COPYNAME so we'll
459 have safe memory for the eventual conversion */
460 #else
461 current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
462 #endif
463 case CURLFORM_COPYNAME:
464 if (current_form->name)
465 return_value = CURL_FORMADD_OPTION_TWICE;
466 else {
467 char *name = array_state?
468 array_value:va_arg(params, char *);
469 if (name)
470 current_form->name = name; /* store for the moment */
471 else
472 return_value = CURL_FORMADD_NULL;
474 break;
475 case CURLFORM_NAMELENGTH:
476 if (current_form->namelength)
477 return_value = CURL_FORMADD_OPTION_TWICE;
478 else
479 current_form->namelength =
480 array_state?(long)array_value:(long)va_arg(params, long);
481 break;
484 * Set the contents property.
486 case CURLFORM_PTRCONTENTS:
487 current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
488 case CURLFORM_COPYCONTENTS:
489 if (current_form->value)
490 return_value = CURL_FORMADD_OPTION_TWICE;
491 else {
492 char *value =
493 array_state?array_value:va_arg(params, char *);
494 if (value)
495 current_form->value = value; /* store for the moment */
496 else
497 return_value = CURL_FORMADD_NULL;
499 break;
500 case CURLFORM_CONTENTSLENGTH:
501 if (current_form->contentslength)
502 return_value = CURL_FORMADD_OPTION_TWICE;
503 else
504 current_form->contentslength =
505 array_state?(long)array_value:va_arg(params, long);
506 break;
508 /* Get contents from a given file name */
509 case CURLFORM_FILECONTENT:
510 if (current_form->flags != 0)
511 return_value = CURL_FORMADD_OPTION_TWICE;
512 else {
513 char *filename = array_state?
514 array_value:va_arg(params, char *);
515 if (filename) {
516 current_form->value = strdup(filename);
517 if(!current_form->value)
518 return_value = CURL_FORMADD_MEMORY;
519 else {
520 current_form->flags |= HTTPPOST_READFILE;
521 current_form->value_alloc = TRUE;
524 else
525 return_value = CURL_FORMADD_NULL;
527 break;
529 /* We upload a file */
530 case CURLFORM_FILE:
532 char *filename = array_state?array_value:
533 va_arg(params, char *);
535 if (current_form->value) {
536 if (current_form->flags & HTTPPOST_FILENAME) {
537 if (filename) {
538 if ((current_form = AddFormInfo(strdup(filename),
539 NULL, current_form)) == NULL)
540 return_value = CURL_FORMADD_MEMORY;
542 else
543 return_value = CURL_FORMADD_NULL;
545 else
546 return_value = CURL_FORMADD_OPTION_TWICE;
548 else {
549 if (filename) {
550 current_form->value = strdup(filename);
551 if(!current_form->value)
552 return_value = CURL_FORMADD_MEMORY;
553 else {
554 current_form->flags |= HTTPPOST_FILENAME;
555 current_form->value_alloc = TRUE;
558 else
559 return_value = CURL_FORMADD_NULL;
561 break;
564 case CURLFORM_BUFFER:
566 char *filename = array_state?array_value:
567 va_arg(params, char *);
569 if (current_form->value) {
570 if (current_form->flags & HTTPPOST_BUFFER) {
571 if (filename) {
572 if ((current_form = AddFormInfo(strdup(filename),
573 NULL, current_form)) == NULL)
574 return_value = CURL_FORMADD_MEMORY;
576 else
577 return_value = CURL_FORMADD_NULL;
579 else
580 return_value = CURL_FORMADD_OPTION_TWICE;
582 else {
583 if (filename) {
584 current_form->value = strdup(filename);
585 if(!current_form->value)
586 return_value = CURL_FORMADD_MEMORY;
588 else
589 return_value = CURL_FORMADD_NULL;
590 current_form->flags |= HTTPPOST_BUFFER;
592 break;
595 case CURLFORM_BUFFERPTR:
596 current_form->flags |= HTTPPOST_PTRBUFFER;
597 if (current_form->buffer)
598 return_value = CURL_FORMADD_OPTION_TWICE;
599 else {
600 char *buffer =
601 array_state?array_value:va_arg(params, char *);
602 if (buffer)
603 current_form->buffer = buffer; /* store for the moment */
604 else
605 return_value = CURL_FORMADD_NULL;
607 break;
609 case CURLFORM_BUFFERLENGTH:
610 if (current_form->bufferlength)
611 return_value = CURL_FORMADD_OPTION_TWICE;
612 else
613 current_form->bufferlength =
614 array_state?(long)array_value:va_arg(params, long);
615 break;
617 case CURLFORM_CONTENTTYPE:
619 char *contenttype =
620 array_state?array_value:va_arg(params, char *);
621 if (current_form->contenttype) {
622 if (current_form->flags & HTTPPOST_FILENAME) {
623 if (contenttype) {
624 if ((current_form = AddFormInfo(NULL,
625 strdup(contenttype),
626 current_form)) == NULL)
627 return_value = CURL_FORMADD_MEMORY;
629 else
630 return_value = CURL_FORMADD_NULL;
632 else
633 return_value = CURL_FORMADD_OPTION_TWICE;
635 else {
636 if (contenttype) {
637 current_form->contenttype = strdup(contenttype);
638 if(!current_form->contenttype)
639 return_value = CURL_FORMADD_MEMORY;
640 else
641 current_form->contenttype_alloc = TRUE;
643 else
644 return_value = CURL_FORMADD_NULL;
646 break;
648 case CURLFORM_CONTENTHEADER:
650 /* this "cast increases required alignment of target type" but
651 we consider it OK anyway */
652 struct curl_slist* list = array_state?
653 (struct curl_slist*)array_value:
654 va_arg(params, struct curl_slist*);
656 if( current_form->contentheader )
657 return_value = CURL_FORMADD_OPTION_TWICE;
658 else
659 current_form->contentheader = list;
661 break;
663 case CURLFORM_FILENAME:
665 char *filename = array_state?array_value:
666 va_arg(params, char *);
667 if( current_form->showfilename )
668 return_value = CURL_FORMADD_OPTION_TWICE;
669 else {
670 current_form->showfilename = strdup(filename);
671 if(!current_form->showfilename)
672 return_value = CURL_FORMADD_MEMORY;
673 else
674 current_form->showfilename_alloc = TRUE;
676 break;
678 default:
679 return_value = CURL_FORMADD_UNKNOWN_OPTION;
683 if(CURL_FORMADD_OK == return_value) {
684 /* go through the list, check for copleteness and if everything is
685 * alright add the HttpPost item otherwise set return_value accordingly */
687 post = NULL;
688 for(form = first_form;
689 form != NULL;
690 form = form->more) {
691 if ( ((!form->name || !form->value) && !post) ||
692 ( (form->contentslength) &&
693 (form->flags & HTTPPOST_FILENAME) ) ||
694 ( (form->flags & HTTPPOST_FILENAME) &&
695 (form->flags & HTTPPOST_PTRCONTENTS) ) ||
697 ( (!form->buffer) &&
698 (form->flags & HTTPPOST_BUFFER) &&
699 (form->flags & HTTPPOST_PTRBUFFER) ) ||
701 ( (form->flags & HTTPPOST_READFILE) &&
702 (form->flags & HTTPPOST_PTRCONTENTS) )
704 return_value = CURL_FORMADD_INCOMPLETE;
705 break;
707 else {
708 if ( ((form->flags & HTTPPOST_FILENAME) ||
709 (form->flags & HTTPPOST_BUFFER)) &&
710 !form->contenttype ) {
711 /* our contenttype is missing */
712 form->contenttype
713 = strdup(ContentTypeForFilename(form->value, prevtype));
714 if(!form->contenttype) {
715 return_value = CURL_FORMADD_MEMORY;
716 break;
718 form->contenttype_alloc = TRUE;
720 if ( !(form->flags & HTTPPOST_PTRNAME) &&
721 (form == first_form) ) {
722 /* copy name (without strdup; possibly contains null characters) */
723 form->name = memdup(form->name, form->namelength);
724 if (!form->name) {
725 return_value = CURL_FORMADD_MEMORY;
726 break;
728 form->name_alloc = TRUE;
730 if ( !(form->flags & HTTPPOST_FILENAME) &&
731 !(form->flags & HTTPPOST_READFILE) &&
732 !(form->flags & HTTPPOST_PTRCONTENTS) &&
733 !(form->flags & HTTPPOST_PTRBUFFER) ) {
734 /* copy value (without strdup; possibly contains null characters) */
735 form->value = memdup(form->value, form->contentslength);
736 if (!form->value) {
737 return_value = CURL_FORMADD_MEMORY;
738 break;
740 form->value_alloc = TRUE;
742 post = AddHttpPost(form->name, form->namelength,
743 form->value, form->contentslength,
744 form->buffer, form->bufferlength,
745 form->contenttype, form->flags,
746 form->contentheader, form->showfilename,
747 post, httppost,
748 last_post);
750 if(!post) {
751 return_value = CURL_FORMADD_MEMORY;
752 break;
755 if (form->contenttype)
756 prevtype = form->contenttype;
761 if(return_value) {
762 /* we return on error, free possibly allocated fields */
763 if(!form)
764 form = current_form;
765 if(form) {
766 if(form->name_alloc)
767 free(form->name);
768 if(form->value_alloc)
769 free(form->value);
770 if(form->contenttype_alloc)
771 free(form->contenttype);
772 if(form->showfilename_alloc)
773 free(form->showfilename);
777 /* always delete the allocated memory before returning */
778 form = first_form;
779 while (form != NULL) {
780 FormInfo *delete_form;
782 delete_form = form;
783 form = form->more;
784 free (delete_form);
787 return return_value;
791 * curl_formadd() is a public API to add a section to the multipart formpost.
794 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
795 struct curl_httppost **last_post,
796 ...)
798 va_list arg;
799 CURLFORMcode result;
800 va_start(arg, last_post);
801 result = FormAdd(httppost, last_post, arg);
802 va_end(arg);
803 return result;
807 * AddFormData() adds a chunk of data to the FormData linked list.
809 * size is incremented by the chunk length, unless it is NULL
811 static CURLcode AddFormData(struct FormData **formp,
812 enum formtype type,
813 const void *line,
814 size_t length,
815 curl_off_t *size)
817 struct FormData *newform = (struct FormData *)
818 malloc(sizeof(struct FormData));
819 if (!newform)
820 return CURLE_OUT_OF_MEMORY;
821 newform->next = NULL;
823 /* we make it easier for plain strings: */
824 if(!length)
825 length = strlen((char *)line);
827 newform->line = (char *)malloc(length+1);
828 if (!newform->line) {
829 free(newform);
830 return CURLE_OUT_OF_MEMORY;
832 memcpy(newform->line, line, length);
833 newform->length = length;
834 newform->line[length]=0; /* zero terminate for easier debugging */
835 newform->type = type;
837 if(*formp) {
838 (*formp)->next = newform;
839 *formp = newform;
841 else
842 *formp = newform;
844 if (size) {
845 if((type == FORM_DATA) || (type == FORM_CONTENT))
846 *size += length;
847 else {
848 /* Since this is a file to be uploaded here, add the size of the actual
849 file */
850 if(!strequal("-", newform->line)) {
851 struct_stat file;
852 if(!stat(newform->line, &file)) {
853 *size += file.st_size;
858 return CURLE_OK;
862 * AddFormDataf() adds printf()-style formatted data to the formdata chain.
865 static CURLcode AddFormDataf(struct FormData **formp,
866 curl_off_t *size,
867 const char *fmt, ...)
869 char s[4096];
870 va_list ap;
871 va_start(ap, fmt);
872 vsnprintf(s, sizeof(s), fmt, ap);
873 va_end(ap);
875 return AddFormData(formp, FORM_DATA, s, 0, size);
879 * Curl_formclean() is used from http.c, this cleans a built FormData linked
880 * list
882 void Curl_formclean(struct FormData **form_ptr)
884 struct FormData *next, *form;
886 form = *form_ptr;
887 if(!form)
888 return;
890 do {
891 next=form->next; /* the following form line */
892 free(form->line); /* free the line */
893 free(form); /* free the struct */
895 } while ((form = next) != NULL); /* continue */
897 *form_ptr = NULL;
900 #ifdef CURL_DOES_CONVERSIONS
902 * Curl_formcovert() is used from http.c, this converts any
903 form items that need to be sent in the network encoding.
904 Returns CURLE_OK on success.
906 CURLcode Curl_formconvert(struct SessionHandle *data, struct FormData *form)
908 struct FormData *next;
909 CURLcode rc;
911 if(!form)
912 return CURLE_OK;
914 if(!data)
915 return CURLE_BAD_FUNCTION_ARGUMENT;
917 do {
918 next=form->next; /* the following form line */
919 if (form->type == FORM_DATA) {
920 rc = Curl_convert_to_network(data, form->line, form->length);
921 /* Curl_convert_to_network calls failf if unsuccessful */
922 if (rc != CURLE_OK)
923 return rc;
925 } while ((form = next) != NULL); /* continue */
926 return CURLE_OK;
928 #endif /* CURL_DOES_CONVERSIONS */
931 * curl_formget()
932 * Serialize a curl_httppost struct.
933 * Returns 0 on success.
935 int curl_formget(struct curl_httppost *form, void *arg,
936 curl_formget_callback append)
938 CURLcode rc;
939 curl_off_t size;
940 struct FormData *data, *ptr;
942 rc = Curl_getFormData(&data, form, NULL, &size);
943 if (rc != CURLE_OK)
944 return (int)rc;
946 for (ptr = data; ptr; ptr = ptr->next) {
947 if (ptr->type == FORM_FILE) {
948 char buffer[8192];
949 size_t read;
950 struct Form temp;
952 Curl_FormInit(&temp, ptr);
954 do {
955 read = readfromfile(&temp, buffer, sizeof(buffer));
956 if ((read == (size_t) -1) || (read != append(arg, buffer, read))) {
957 if (temp.fp) {
958 fclose(temp.fp);
960 Curl_formclean(&data);
961 return -1;
963 } while (read == sizeof(buffer));
964 } else {
965 if (ptr->length != append(arg, ptr->line, ptr->length)) {
966 Curl_formclean(&data);
967 return -1;
971 Curl_formclean(&data);
972 return 0;
976 * curl_formfree() is an external function to free up a whole form post
977 * chain
979 void curl_formfree(struct curl_httppost *form)
981 struct curl_httppost *next;
983 if(!form)
984 /* no form to free, just get out of this */
985 return;
987 do {
988 next=form->next; /* the following form line */
990 /* recurse to sub-contents */
991 if(form->more)
992 curl_formfree(form->more);
994 if( !(form->flags & HTTPPOST_PTRNAME) && form->name)
995 free(form->name); /* free the name */
996 if( !(form->flags & HTTPPOST_PTRCONTENTS) && form->contents)
997 free(form->contents); /* free the contents */
998 if(form->contenttype)
999 free(form->contenttype); /* free the content type */
1000 if(form->showfilename)
1001 free(form->showfilename); /* free the faked file name */
1002 free(form); /* free the struct */
1004 } while ((form = next) != NULL); /* continue */
1007 #ifndef HAVE_BASENAME
1009 (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
1010 Edition)
1012 The basename() function shall take the pathname pointed to by path and
1013 return a pointer to the final component of the pathname, deleting any
1014 trailing '/' characters.
1016 If the string pointed to by path consists entirely of the '/' character,
1017 basename() shall return a pointer to the string "/". If the string pointed
1018 to by path is exactly "//", it is implementation-defined whether '/' or "//"
1019 is returned.
1021 If path is a null pointer or points to an empty string, basename() shall
1022 return a pointer to the string ".".
1024 The basename() function may modify the string pointed to by path, and may
1025 return a pointer to static storage that may then be overwritten by a
1026 subsequent call to basename().
1028 The basename() function need not be reentrant. A function that is not
1029 required to be reentrant is not required to be thread-safe.
1032 static char *basename(char *path)
1034 /* Ignore all the details above for now and make a quick and simple
1035 implementaion here */
1036 char *s1;
1037 char *s2;
1039 s1=strrchr(path, '/');
1040 s2=strrchr(path, '\\');
1042 if(s1 && s2) {
1043 path = (s1 > s2? s1 : s2)+1;
1045 else if(s1)
1046 path = s1 + 1;
1047 else if(s2)
1048 path = s2 + 1;
1050 return path;
1052 #endif
1054 static char *strippath(char *fullfile)
1056 char *filename;
1057 char *base;
1058 filename = strdup(fullfile); /* duplicate since basename() may ruin the
1059 buffer it works on */
1060 if(!filename)
1061 return NULL;
1062 base = strdup(basename(filename));
1064 free(filename); /* free temporary buffer */
1066 return base; /* returns an allocated string! */
1070 * Curl_getFormData() converts a linked list of "meta data" into a complete
1071 * (possibly huge) multipart formdata. The input list is in 'post', while the
1072 * output resulting linked lists gets stored in '*finalform'. *sizep will get
1073 * the total size of the whole POST.
1074 * A multipart/form_data content-type is built, unless a custom content-type
1075 * is passed in 'custom_content_type'.
1078 CURLcode Curl_getFormData(struct FormData **finalform,
1079 struct curl_httppost *post,
1080 const char *custom_content_type,
1081 curl_off_t *sizep)
1083 struct FormData *form = NULL;
1084 struct FormData *firstform;
1085 struct curl_httppost *file;
1086 CURLcode result = CURLE_OK;
1088 curl_off_t size=0; /* support potentially ENORMOUS formposts */
1089 char *boundary;
1090 char *fileboundary=NULL;
1091 struct curl_slist* curList;
1093 *finalform=NULL; /* default form is empty */
1095 if(!post)
1096 return result; /* no input => no output! */
1098 boundary = Curl_FormBoundary();
1099 if(!boundary)
1100 return CURLE_OUT_OF_MEMORY;
1102 /* Make the first line of the output */
1103 result = AddFormDataf(&form, NULL,
1104 "%s; boundary=%s\r\n",
1105 custom_content_type?custom_content_type:
1106 "Content-Type: multipart/form-data",
1107 boundary);
1109 if (result) {
1110 free(boundary);
1111 return result;
1113 /* we DO NOT include that line in the total size of the POST, since it'll be
1114 part of the header! */
1116 firstform = form;
1118 do {
1120 if(size) {
1121 result = AddFormDataf(&form, &size, "\r\n");
1122 if (result)
1123 break;
1126 /* boundary */
1127 result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
1128 if (result)
1129 break;
1131 /* Maybe later this should be disabled when a custom_content_type is
1132 passed, since Content-Disposition is not meaningful for all multipart
1133 types.
1135 result = AddFormDataf(&form, &size,
1136 "Content-Disposition: form-data; name=\"");
1137 if (result)
1138 break;
1140 result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
1141 &size);
1142 if (result)
1143 break;
1145 result = AddFormDataf(&form, &size, "\"");
1146 if (result)
1147 break;
1149 if(post->more) {
1150 /* If used, this is a link to more file names, we must then do
1151 the magic to include several files with the same field name */
1153 fileboundary = Curl_FormBoundary();
1155 result = AddFormDataf(&form, &size,
1156 "\r\nContent-Type: multipart/mixed,"
1157 " boundary=%s\r\n",
1158 fileboundary);
1159 if (result)
1160 break;
1163 file = post;
1165 do {
1167 /* If 'showfilename' is set, that is a faked name passed on to us
1168 to use to in the formpost. If that is not set, the actually used
1169 local file name should be added. */
1171 if(post->more) {
1172 /* if multiple-file */
1173 char *filebasename=
1174 (!file->showfilename)?strippath(file->contents):NULL;
1176 result = AddFormDataf(&form, &size,
1177 "\r\n--%s\r\nContent-Disposition: "
1178 "attachment; filename=\"%s\"",
1179 fileboundary,
1180 (file->showfilename?file->showfilename:
1181 filebasename));
1182 if (filebasename)
1183 free(filebasename);
1184 if (result)
1185 break;
1187 else if((post->flags & HTTPPOST_FILENAME) ||
1188 (post->flags & HTTPPOST_BUFFER)) {
1190 char *filebasename=
1191 (!post->showfilename)?strippath(post->contents):NULL;
1193 result = AddFormDataf(&form, &size,
1194 "; filename=\"%s\"",
1195 (post->showfilename?post->showfilename:
1196 filebasename));
1197 if (filebasename)
1198 free(filebasename);
1200 if (result)
1201 break;
1204 if(file->contenttype) {
1205 /* we have a specified type */
1206 result = AddFormDataf(&form, &size,
1207 "\r\nContent-Type: %s",
1208 file->contenttype);
1209 if (result)
1210 break;
1213 curList = file->contentheader;
1214 while( curList ) {
1215 /* Process the additional headers specified for this form */
1216 result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
1217 if (result)
1218 break;
1219 curList = curList->next;
1221 if (result) {
1222 Curl_formclean(&firstform);
1223 free(boundary);
1224 return result;
1227 #if 0
1228 /* The header Content-Transfer-Encoding: seems to confuse some receivers
1229 * (like the built-in PHP engine). While I can't see any reason why it
1230 * should, I can just as well skip this to the benefit of the users who
1231 * are using such confused receivers.
1234 if(file->contenttype &&
1235 !checkprefix("text/", file->contenttype)) {
1236 /* this is not a text content, mention our binary encoding */
1237 result = AddFormDataf(&form, &size,
1238 "\r\nContent-Transfer-Encoding: binary");
1239 if (result)
1240 break;
1242 #endif
1244 result = AddFormDataf(&form, &size, "\r\n\r\n");
1245 if (result)
1246 break;
1248 if((post->flags & HTTPPOST_FILENAME) ||
1249 (post->flags & HTTPPOST_READFILE)) {
1250 /* we should include the contents from the specified file */
1251 FILE *fileread;
1253 fileread = strequal("-", file->contents)?
1254 stdin:fopen(file->contents, "rb"); /* binary read for win32 */
1257 * VMS: This only allows for stream files on VMS. Stream files are
1258 * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
1259 * every record needs to have a \n appended & 1 added to SIZE
1262 if(fileread) {
1263 if(fileread != stdin) {
1264 /* close the file again */
1265 fclose(fileread);
1266 /* add the file name only - for later reading from this */
1267 result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
1269 else {
1270 /* When uploading from stdin, we can't know the size of the file,
1271 * thus must read the full file as before. We *could* use chunked
1272 * transfer-encoding, but that only works for HTTP 1.1 and we
1273 * can't be sure we work with such a server.
1275 size_t nread;
1276 char buffer[512];
1277 while ((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
1278 result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
1279 if (result)
1280 break;
1284 if (result) {
1285 Curl_formclean(&firstform);
1286 free(boundary);
1287 return result;
1291 else {
1292 #ifdef _FORM_DEBUG
1293 fprintf(stderr,
1294 "\n==> Curl_getFormData couldn't open/read \"%s\"\n",
1295 file->contents);
1296 #endif
1297 Curl_formclean(&firstform);
1298 free(boundary);
1299 *finalform = NULL;
1300 return CURLE_READ_ERROR;
1304 else if (post->flags & HTTPPOST_BUFFER) {
1305 /* include contents of buffer */
1306 result = AddFormData(&form, FORM_CONTENT, post->buffer,
1307 post->bufferlength, &size);
1308 if (result)
1309 break;
1312 else {
1313 /* include the contents we got */
1314 result = AddFormData(&form, FORM_CONTENT, post->contents,
1315 post->contentslength, &size);
1316 if (result)
1317 break;
1319 } while ((file = file->more) != NULL); /* for each specified file for this field */
1320 if (result) {
1321 Curl_formclean(&firstform);
1322 free(boundary);
1323 return result;
1326 if(post->more) {
1327 /* this was a multiple-file inclusion, make a termination file
1328 boundary: */
1329 result = AddFormDataf(&form, &size,
1330 "\r\n--%s--",
1331 fileboundary);
1332 free(fileboundary);
1333 if (result)
1334 break;
1337 } while ((post = post->next) != NULL); /* for each field */
1338 if (result) {
1339 Curl_formclean(&firstform);
1340 free(boundary);
1341 return result;
1344 /* end-boundary for everything */
1345 result = AddFormDataf(&form, &size,
1346 "\r\n--%s--\r\n",
1347 boundary);
1348 if (result) {
1349 Curl_formclean(&firstform);
1350 free(boundary);
1351 return result;
1354 *sizep = size;
1356 free(boundary);
1358 *finalform=firstform;
1360 return result;
1364 * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
1365 * and resets the 'sent' counter.
1367 int Curl_FormInit(struct Form *form, struct FormData *formdata )
1369 if(!formdata)
1370 return 1; /* error */
1372 form->data = formdata;
1373 form->sent = 0;
1374 form->fp = NULL;
1376 return 0;
1379 static size_t readfromfile(struct Form *form, char *buffer, size_t size)
1381 size_t nread;
1382 if(!form->fp) {
1383 /* this file hasn't yet been opened */
1384 form->fp = fopen(form->data->line, "rb"); /* b is for binary */
1385 if(!form->fp)
1386 return (size_t)-1; /* failure */
1388 nread = fread(buffer, 1, size, form->fp);
1390 if(nread != size) {
1391 /* this is the last chunk from the file, move on */
1392 fclose(form->fp);
1393 form->fp = NULL;
1394 form->data = form->data->next;
1397 return nread;
1401 * Curl_FormReader() is the fread() emulation function that will be used to
1402 * deliver the formdata to the transfer loop and then sent away to the peer.
1404 size_t Curl_FormReader(char *buffer,
1405 size_t size,
1406 size_t nitems,
1407 FILE *mydata)
1409 struct Form *form;
1410 size_t wantedsize;
1411 size_t gotsize = 0;
1413 form=(struct Form *)mydata;
1415 wantedsize = size * nitems;
1417 if(!form->data)
1418 return 0; /* nothing, error, empty */
1420 if(form->data->type == FORM_FILE) {
1421 gotsize = readfromfile(form, buffer, wantedsize);
1423 if(gotsize)
1424 /* If positive or -1, return. If zero, continue! */
1425 return gotsize;
1427 do {
1429 if( (form->data->length - form->sent ) > wantedsize - gotsize) {
1431 memcpy(buffer + gotsize , form->data->line + form->sent,
1432 wantedsize - gotsize);
1434 form->sent += wantedsize-gotsize;
1436 return wantedsize;
1439 memcpy(buffer+gotsize,
1440 form->data->line + form->sent,
1441 (form->data->length - form->sent) );
1442 gotsize += form->data->length - form->sent;
1444 form->sent = 0;
1446 form->data = form->data->next; /* advance */
1448 } while(form->data && (form->data->type != FORM_FILE));
1449 /* If we got an empty line and we have more data, we proceed to the next
1450 line immediately to avoid returning zero before we've reached the end.
1451 This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
1453 return gotsize;
1457 * Curl_formpostheader() returns the first line of the formpost, the
1458 * request-header part (which is not part of the request-body like the rest of
1459 * the post).
1461 char *Curl_formpostheader(void *formp, size_t *len)
1463 char *header;
1464 struct Form *form=(struct Form *)formp;
1466 if(!form->data)
1467 return 0; /* nothing, ERROR! */
1469 header = form->data->line;
1470 *len = form->data->length;
1472 form->data = form->data->next; /* advance */
1474 return header;
1478 #ifdef _FORM_DEBUG
1479 int FormAddTest(const char * errormsg,
1480 struct curl_httppost **httppost,
1481 struct curl_httppost **last_post,
1482 ...)
1484 int result;
1485 va_list arg;
1486 va_start(arg, last_post);
1487 if ((result = FormAdd(httppost, last_post, arg)))
1488 fprintf (stderr, "ERROR doing FormAdd ret: %d action: %s\n", result,
1489 errormsg);
1490 va_end(arg);
1491 return result;
1495 int main()
1497 char name1[] = "simple_COPYCONTENTS";
1498 char name2[] = "COPYCONTENTS_+_CONTENTTYPE";
1499 char name3[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH";
1500 char name4[] = "simple_PTRCONTENTS";
1501 char name5[] = "PTRCONTENTS_+_CONTENTSLENGTH";
1502 char name6[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE";
1503 char name7[] = "FILE1_+_CONTENTTYPE";
1504 char name8[] = "FILE1_+_FILE2";
1505 char name9[] = "FILE1_+_FILE2_+_FILE3";
1506 char name10[] = "ARRAY: FILE1_+_FILE2_+_FILE3";
1507 char name11[] = "FILECONTENT";
1508 char value1[] = "value for simple COPYCONTENTS";
1509 char value2[] = "value for COPYCONTENTS + CONTENTTYPE";
1510 char value3[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH";
1511 char value4[] = "value for simple PTRCONTENTS";
1512 char value5[] = "value for PTRCONTENTS + CONTENTSLENGTH";
1513 char value6[] = "value for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE";
1514 char value7[] = "inet_ntoa_r.h";
1515 char value8[] = "Makefile.b32";
1516 char type2[] = "image/gif";
1517 char type6[] = "text/plain";
1518 char type7[] = "text/html";
1519 int name3length = strlen(name3);
1520 int value3length = strlen(value3);
1521 int value5length = strlen(value4);
1522 int value6length = strlen(value5);
1523 int errors = 0;
1524 CURLcode rc;
1525 size_t size;
1526 size_t nread;
1527 char buffer[4096];
1528 struct curl_httppost *httppost=NULL;
1529 struct curl_httppost *last_post=NULL;
1530 struct curl_forms forms[4];
1532 struct FormData *form;
1533 struct Form formread;
1535 if (FormAddTest("simple COPYCONTENTS test", &httppost, &last_post,
1536 CURLFORM_COPYNAME, name1, CURLFORM_COPYCONTENTS, value1,
1537 CURLFORM_END))
1538 ++errors;
1539 if (FormAddTest("COPYCONTENTS + CONTENTTYPE test", &httppost, &last_post,
1540 CURLFORM_COPYNAME, name2, CURLFORM_COPYCONTENTS, value2,
1541 CURLFORM_CONTENTTYPE, type2, CURLFORM_END))
1542 ++errors;
1543 /* make null character at start to check that contentslength works
1544 correctly */
1545 name3[1] = '\0';
1546 value3[1] = '\0';
1547 if (FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test",
1548 &httppost, &last_post,
1549 CURLFORM_PTRNAME, name3, CURLFORM_COPYCONTENTS, value3,
1550 CURLFORM_CONTENTSLENGTH, value3length,
1551 CURLFORM_NAMELENGTH, name3length, CURLFORM_END))
1552 ++errors;
1553 if (FormAddTest("simple PTRCONTENTS test", &httppost, &last_post,
1554 CURLFORM_COPYNAME, name4, CURLFORM_PTRCONTENTS, value4,
1555 CURLFORM_END))
1556 ++errors;
1557 /* make null character at start to check that contentslength works
1558 correctly */
1559 value5[1] = '\0';
1560 if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost, &last_post,
1561 CURLFORM_COPYNAME, name5, CURLFORM_PTRCONTENTS, value5,
1562 CURLFORM_CONTENTSLENGTH, value5length, CURLFORM_END))
1563 ++errors;
1564 /* make null character at start to check that contentslength works
1565 correctly */
1566 value6[1] = '\0';
1567 if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test",
1568 &httppost, &last_post,
1569 CURLFORM_COPYNAME, name6, CURLFORM_PTRCONTENTS, value6,
1570 CURLFORM_CONTENTSLENGTH, value6length,
1571 CURLFORM_CONTENTTYPE, type6, CURLFORM_END))
1572 ++errors;
1573 if (FormAddTest("FILE + CONTENTTYPE test", &httppost, &last_post,
1574 CURLFORM_COPYNAME, name7, CURLFORM_FILE, value7,
1575 CURLFORM_CONTENTTYPE, type7, CURLFORM_END))
1576 ++errors;
1577 if (FormAddTest("FILE1 + FILE2 test", &httppost, &last_post,
1578 CURLFORM_COPYNAME, name8, CURLFORM_FILE, value7,
1579 CURLFORM_FILE, value8, CURLFORM_END))
1580 ++errors;
1581 if (FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost, &last_post,
1582 CURLFORM_COPYNAME, name9, CURLFORM_FILE, value7,
1583 CURLFORM_FILE, value8, CURLFORM_FILE, value7, CURLFORM_END))
1584 ++errors;
1585 forms[0].option = CURLFORM_FILE;
1586 forms[0].value = value7;
1587 forms[1].option = CURLFORM_FILE;
1588 forms[1].value = value8;
1589 forms[2].option = CURLFORM_FILE;
1590 forms[2].value = value7;
1591 forms[3].option = CURLFORM_END;
1592 if (FormAddTest("FILE1 + FILE2 + FILE3 ARRAY test", &httppost, &last_post,
1593 CURLFORM_COPYNAME, name10, CURLFORM_ARRAY, forms,
1594 CURLFORM_END))
1595 ++errors;
1596 if (FormAddTest("FILECONTENT test", &httppost, &last_post,
1597 CURLFORM_COPYNAME, name11, CURLFORM_FILECONTENT, value7,
1598 CURLFORM_END))
1599 ++errors;
1601 rc = Curl_getFormData(&form, httppost, NULL, &size);
1602 if(rc != CURLE_OK) {
1603 if(rc != CURLE_READ_ERROR) {
1604 const char *errortext = curl_easy_strerror(rc);
1605 fprintf(stdout, "\n==> Curl_getFormData error: %s\n", errortext);
1607 return 0;
1610 Curl_FormInit(&formread, form);
1612 do {
1613 nread = Curl_FormReader(buffer, 1, sizeof(buffer),
1614 (FILE *)&formread);
1616 if(nread < 1)
1617 break;
1618 fwrite(buffer, nread, 1, stdout);
1619 } while(1);
1621 fprintf(stdout, "size: %d\n", size);
1622 if (errors)
1623 fprintf(stdout, "\n==> %d Test(s) failed!\n", errors);
1624 else
1625 fprintf(stdout, "\nAll Tests seem to have worked (please check output)\n");
1627 return 0;
1630 #endif /* _FORM_DEBUG */
1632 #else /* CURL_DISABLE_HTTP */
1633 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
1634 struct curl_httppost **last_post,
1635 ...)
1637 (void)httppost;
1638 (void)last_post;
1639 return CURL_FORMADD_DISABLED;
1642 int curl_formget(struct curl_httppost *form, void *arg,
1643 curl_formget_callback append)
1645 (void) form;
1646 (void) arg;
1647 (void) append;
1648 return CURL_FORMADD_DISABLED;
1651 void curl_formfree(struct curl_httppost *form)
1653 (void)form;
1654 /* does nothing HTTP is disabled */
1657 #endif /* CURL_DISABLE_HTTP */
1659 #if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
1662 * Curl_FormBoundary() creates a suitable boundary string and returns an
1663 * allocated one. This is also used by SSL-code so it must be present even
1664 * if HTTP is disabled!
1666 char *Curl_FormBoundary(void)
1668 char *retstring;
1669 static int randomizer; /* this is just so that two boundaries within
1670 the same form won't be identical */
1671 size_t i;
1673 static const char table16[]="abcdef0123456789";
1675 retstring = (char *)malloc(BOUNDARY_LENGTH+1);
1677 if(!retstring)
1678 return NULL; /* failed */
1680 srand((unsigned int)time(NULL)+randomizer++); /* seed */
1682 strcpy(retstring, "----------------------------");
1684 for(i=strlen(retstring); i<BOUNDARY_LENGTH; i++)
1685 retstring[i] = table16[rand()%16];
1687 /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
1688 combinations */
1689 retstring[BOUNDARY_LENGTH]=0; /* zero terminate */
1691 return retstring;
1694 #endif /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */