1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2014, 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 ***************************************************************************/
23 #include "curl_setup.h"
25 #include <curl/curl.h>
27 #ifndef CURL_DISABLE_HTTP
29 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
33 #include "urldata.h" /* for struct SessionHandle */
35 #include "vtls/vtls.h"
37 #include "curl_memory.h"
41 #define _MPRINTF_REPLACE /* use our functions only */
42 #include <curl/mprintf.h>
44 /* The last #include file should be: */
48 static char *Curl_basename(char *path);
49 #define basename(x) Curl_basename((x))
52 static size_t readfromfile(struct Form *form, char *buffer, size_t size);
53 static char *formboundary(struct SessionHandle *data);
55 /* What kind of Content-Type to use on un-specified files with unrecognized
57 #define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
59 #define FORM_FILE_SEPARATOR ','
60 #define FORM_TYPE_SEPARATOR ';'
62 /***************************************************************************
66 * Adds a HttpPost structure to the list, if parent_post is given becomes
67 * a subpost of parent_post instead of a direct list element.
69 * Returns newly allocated HttpPost on success and NULL if malloc failed.
71 ***************************************************************************/
72 static struct curl_httppost *
73 AddHttpPost(char *name, size_t namelength,
74 char *value, size_t contentslength,
75 char *buffer, size_t bufferlength,
78 struct curl_slist* contentHeader,
79 char *showfilename, char *userp,
80 struct curl_httppost *parent_post,
81 struct curl_httppost **httppost,
82 struct curl_httppost **last_post)
84 struct curl_httppost *post;
85 post = calloc(1, sizeof(struct curl_httppost));
88 post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
89 post->contents = value;
90 post->contentslength = (long)contentslength;
91 post->buffer = buffer;
92 post->bufferlength = (long)bufferlength;
93 post->contenttype = contenttype;
94 post->contentheader = contentHeader;
95 post->showfilename = showfilename;
103 /* now, point our 'more' to the original 'more' */
104 post->more = parent_post->more;
106 /* then move the original 'more' to point to ourselves */
107 parent_post->more = post;
110 /* make the previous point to this */
112 (*last_post)->next = post;
121 /***************************************************************************
125 * Adds a FormInfo structure to the list presented by parent_form_info.
127 * Returns newly allocated FormInfo on success and NULL if malloc failed/
128 * parent_form_info is NULL.
130 ***************************************************************************/
131 static FormInfo * AddFormInfo(char *value,
133 FormInfo *parent_form_info)
136 form_info = calloc(1, sizeof(struct FormInfo));
139 form_info->value = value;
141 form_info->contenttype = contenttype;
142 form_info->flags = HTTPPOST_FILENAME;
147 if(parent_form_info) {
148 /* now, point our 'more' to the original 'more' */
149 form_info->more = parent_form_info->more;
151 /* then move the original 'more' to point to ourselves */
152 parent_form_info->more = form_info;
158 /***************************************************************************
160 * ContentTypeForFilename()
162 * Provides content type for filename if one of the known types (else
163 * (either the prevtype or the default is returned).
165 * Returns some valid contenttype for filename.
167 ***************************************************************************/
168 static const char *ContentTypeForFilename(const char *filename,
169 const char *prevtype)
171 const char *contenttype = NULL;
174 * No type was specified, we scan through a few well-known
175 * extensions and pick the first we match!
178 const char *extension;
181 static const struct ContentType ctts[]={
182 {".gif", "image/gif"},
183 {".jpg", "image/jpeg"},
184 {".jpeg", "image/jpeg"},
185 {".txt", "text/plain"},
186 {".html", "text/html"},
187 {".xml", "application/xml"}
191 /* default to the previously set/used! */
192 contenttype = prevtype;
194 contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
196 if(filename) { /* in case a NULL was passed in */
197 for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
198 if(strlen(filename) >= strlen(ctts[i].extension)) {
199 if(strequal(filename +
200 strlen(filename) - strlen(ctts[i].extension),
201 ctts[i].extension)) {
202 contenttype = ctts[i].type;
208 /* we have a contenttype by now */
212 /***************************************************************************
216 * Stores a formpost parameter and builds the appropriate linked list.
218 * Has two principal functionalities: using files and byte arrays as
219 * post parts. Byte arrays are either copied or just the pointer is stored
220 * (as the user requests) while for files only the filename and not the
223 * While you may have only one byte array for each name, multiple filenames
224 * are allowed (and because of this feature CURLFORM_END is needed after
225 * using CURLFORM_FILE).
229 * Simple name/value pair with copied contents:
230 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
231 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
233 * name/value pair where only the content pointer is remembered:
234 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
235 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
236 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
238 * storing a filename (CONTENTTYPE is optional!):
239 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
240 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
243 * storing multiple filenames:
244 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
245 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
248 * CURL_FORMADD_OK on success
249 * CURL_FORMADD_MEMORY if the FormInfo allocation fails
250 * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
251 * CURL_FORMADD_NULL if a null pointer was given for a char
252 * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
253 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
254 * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error)
255 * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
256 * CURL_FORMADD_MEMORY if some allocation for string copying failed.
257 * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
259 ***************************************************************************/
262 CURLFORMcode FormAdd(struct curl_httppost **httppost,
263 struct curl_httppost **last_post,
266 FormInfo *first_form, *current_form, *form = NULL;
267 CURLFORMcode return_value = CURL_FORMADD_OK;
268 const char *prevtype = NULL;
269 struct curl_httppost *post = NULL;
270 CURLformoption option;
271 struct curl_forms *forms = NULL;
272 char *array_value=NULL; /* value read from an array */
274 /* This is a state variable, that if TRUE means that we're parsing an
275 array that we got passed to us. If FALSE we're parsing the input
276 va_list arguments. */
277 bool array_state = FALSE;
280 * We need to allocate the first struct to fill in.
282 first_form = calloc(1, sizeof(struct FormInfo));
284 return CURL_FORMADD_MEMORY;
286 current_form = first_form;
289 * Loop through all the options set. Break if we have an error to report.
291 while(return_value == CURL_FORMADD_OK) {
293 /* first see if we have more parts of the array param */
294 if(array_state && forms) {
295 /* get the upcoming option from the given array */
296 option = forms->option;
297 array_value = (char *)forms->value;
299 forms++; /* advance this to next entry */
300 if(CURLFORM_END == option) {
301 /* end of array state */
307 /* This is not array-state, get next option */
308 option = va_arg(params, CURLformoption);
309 if(CURLFORM_END == option)
316 /* we don't support an array from within an array */
317 return_value = CURL_FORMADD_ILLEGAL_ARRAY;
319 forms = va_arg(params, struct curl_forms *);
323 return_value = CURL_FORMADD_NULL;
328 * Set the Name property.
330 case CURLFORM_PTRNAME:
331 #ifdef CURL_DOES_CONVERSIONS
332 /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
333 * the data in all cases so that we'll have safe memory for the eventual
337 current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
339 case CURLFORM_COPYNAME:
340 if(current_form->name)
341 return_value = CURL_FORMADD_OPTION_TWICE;
343 char *name = array_state?
344 array_value:va_arg(params, char *);
346 current_form->name = name; /* store for the moment */
348 return_value = CURL_FORMADD_NULL;
351 case CURLFORM_NAMELENGTH:
352 if(current_form->namelength)
353 return_value = CURL_FORMADD_OPTION_TWICE;
355 current_form->namelength =
356 array_state?(size_t)array_value:(size_t)va_arg(params, long);
360 * Set the contents property.
362 case CURLFORM_PTRCONTENTS:
363 current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
364 case CURLFORM_COPYCONTENTS:
365 if(current_form->value)
366 return_value = CURL_FORMADD_OPTION_TWICE;
369 array_state?array_value:va_arg(params, char *);
371 current_form->value = value; /* store for the moment */
373 return_value = CURL_FORMADD_NULL;
376 case CURLFORM_CONTENTSLENGTH:
377 if(current_form->contentslength)
378 return_value = CURL_FORMADD_OPTION_TWICE;
380 current_form->contentslength =
381 array_state?(size_t)array_value:(size_t)va_arg(params, long);
384 /* Get contents from a given file name */
385 case CURLFORM_FILECONTENT:
386 if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
387 return_value = CURL_FORMADD_OPTION_TWICE;
389 const char *filename = array_state?
390 array_value:va_arg(params, char *);
392 current_form->value = strdup(filename);
393 if(!current_form->value)
394 return_value = CURL_FORMADD_MEMORY;
396 current_form->flags |= HTTPPOST_READFILE;
397 current_form->value_alloc = TRUE;
401 return_value = CURL_FORMADD_NULL;
405 /* We upload a file */
408 const char *filename = array_state?array_value:
409 va_arg(params, char *);
411 if(current_form->value) {
412 if(current_form->flags & HTTPPOST_FILENAME) {
414 char *fname = strdup(filename);
416 return_value = CURL_FORMADD_MEMORY;
418 form = AddFormInfo(fname, NULL, current_form);
420 Curl_safefree(fname);
421 return_value = CURL_FORMADD_MEMORY;
424 form->value_alloc = TRUE;
431 return_value = CURL_FORMADD_NULL;
434 return_value = CURL_FORMADD_OPTION_TWICE;
438 current_form->value = strdup(filename);
439 if(!current_form->value)
440 return_value = CURL_FORMADD_MEMORY;
442 current_form->flags |= HTTPPOST_FILENAME;
443 current_form->value_alloc = TRUE;
447 return_value = CURL_FORMADD_NULL;
452 case CURLFORM_BUFFERPTR:
453 current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
454 if(current_form->buffer)
455 return_value = CURL_FORMADD_OPTION_TWICE;
458 array_state?array_value:va_arg(params, char *);
460 current_form->buffer = buffer; /* store for the moment */
461 current_form->value = buffer; /* make it non-NULL to be accepted
465 return_value = CURL_FORMADD_NULL;
469 case CURLFORM_BUFFERLENGTH:
470 if(current_form->bufferlength)
471 return_value = CURL_FORMADD_OPTION_TWICE;
473 current_form->bufferlength =
474 array_state?(size_t)array_value:(size_t)va_arg(params, long);
477 case CURLFORM_STREAM:
478 current_form->flags |= HTTPPOST_CALLBACK;
479 if(current_form->userp)
480 return_value = CURL_FORMADD_OPTION_TWICE;
483 array_state?array_value:va_arg(params, char *);
485 current_form->userp = userp;
486 current_form->value = userp; /* this isn't strictly true but we
487 derive a value from this later on
488 and we need this non-NULL to be
489 accepted as a fine form part */
492 return_value = CURL_FORMADD_NULL;
496 case CURLFORM_CONTENTTYPE:
498 const char *contenttype =
499 array_state?array_value:va_arg(params, char *);
500 if(current_form->contenttype) {
501 if(current_form->flags & HTTPPOST_FILENAME) {
503 char *type = strdup(contenttype);
505 return_value = CURL_FORMADD_MEMORY;
507 form = AddFormInfo(NULL, type, current_form);
510 return_value = CURL_FORMADD_MEMORY;
513 form->contenttype_alloc = TRUE;
520 return_value = CURL_FORMADD_NULL;
523 return_value = CURL_FORMADD_OPTION_TWICE;
527 current_form->contenttype = strdup(contenttype);
528 if(!current_form->contenttype)
529 return_value = CURL_FORMADD_MEMORY;
531 current_form->contenttype_alloc = TRUE;
534 return_value = CURL_FORMADD_NULL;
538 case CURLFORM_CONTENTHEADER:
540 /* this "cast increases required alignment of target type" but
541 we consider it OK anyway */
542 struct curl_slist* list = array_state?
543 (struct curl_slist*)array_value:
544 va_arg(params, struct curl_slist*);
546 if(current_form->contentheader)
547 return_value = CURL_FORMADD_OPTION_TWICE;
549 current_form->contentheader = list;
553 case CURLFORM_FILENAME:
554 case CURLFORM_BUFFER:
556 const char *filename = array_state?array_value:
557 va_arg(params, char *);
558 if(current_form->showfilename)
559 return_value = CURL_FORMADD_OPTION_TWICE;
561 current_form->showfilename = strdup(filename);
562 if(!current_form->showfilename)
563 return_value = CURL_FORMADD_MEMORY;
565 current_form->showfilename_alloc = TRUE;
570 return_value = CURL_FORMADD_UNKNOWN_OPTION;
575 if(CURL_FORMADD_OK != return_value) {
576 /* On error, free allocated fields for all nodes of the FormInfo linked
577 list without deallocating nodes. List nodes are deallocated later on */
579 for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
580 if(ptr->name_alloc) {
581 Curl_safefree(ptr->name);
582 ptr->name_alloc = FALSE;
584 if(ptr->value_alloc) {
585 Curl_safefree(ptr->value);
586 ptr->value_alloc = FALSE;
588 if(ptr->contenttype_alloc) {
589 Curl_safefree(ptr->contenttype);
590 ptr->contenttype_alloc = FALSE;
592 if(ptr->showfilename_alloc) {
593 Curl_safefree(ptr->showfilename);
594 ptr->showfilename_alloc = FALSE;
599 if(CURL_FORMADD_OK == return_value) {
600 /* go through the list, check for completeness and if everything is
601 * alright add the HttpPost item otherwise set return_value accordingly */
604 for(form = first_form;
607 if(((!form->name || !form->value) && !post) ||
608 ( (form->contentslength) &&
609 (form->flags & HTTPPOST_FILENAME) ) ||
610 ( (form->flags & HTTPPOST_FILENAME) &&
611 (form->flags & HTTPPOST_PTRCONTENTS) ) ||
614 (form->flags & HTTPPOST_BUFFER) &&
615 (form->flags & HTTPPOST_PTRBUFFER) ) ||
617 ( (form->flags & HTTPPOST_READFILE) &&
618 (form->flags & HTTPPOST_PTRCONTENTS) )
620 return_value = CURL_FORMADD_INCOMPLETE;
624 if(((form->flags & HTTPPOST_FILENAME) ||
625 (form->flags & HTTPPOST_BUFFER)) &&
626 !form->contenttype ) {
627 char *f = form->flags & HTTPPOST_BUFFER?
628 form->showfilename : form->value;
630 /* our contenttype is missing */
631 form->contenttype = strdup(ContentTypeForFilename(f, prevtype));
632 if(!form->contenttype) {
633 return_value = CURL_FORMADD_MEMORY;
636 form->contenttype_alloc = TRUE;
638 if(!(form->flags & HTTPPOST_PTRNAME) &&
639 (form == first_form) ) {
640 /* Note that there's small risk that form->name is NULL here if the
641 app passed in a bad combo, so we better check for that first. */
643 /* copy name (without strdup; possibly contains null characters) */
644 form->name = Curl_memdup(form->name, form->namelength?
646 strlen(form->name)+1);
649 return_value = CURL_FORMADD_MEMORY;
652 form->name_alloc = TRUE;
654 if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
655 HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
656 HTTPPOST_CALLBACK)) && form->value) {
657 /* copy value (without strdup; possibly contains null characters) */
658 form->value = Curl_memdup(form->value, form->contentslength?
659 form->contentslength:
660 strlen(form->value)+1);
662 return_value = CURL_FORMADD_MEMORY;
665 form->value_alloc = TRUE;
667 post = AddHttpPost(form->name, form->namelength,
668 form->value, form->contentslength,
669 form->buffer, form->bufferlength,
670 form->contenttype, form->flags,
671 form->contentheader, form->showfilename,
677 return_value = CURL_FORMADD_MEMORY;
681 if(form->contenttype)
682 prevtype = form->contenttype;
685 if(CURL_FORMADD_OK != return_value) {
686 /* On error, free allocated fields for nodes of the FormInfo linked
687 list which are not already owned by the httppost linked list
688 without deallocating nodes. List nodes are deallocated later on */
690 for(ptr = form; ptr != NULL; ptr = ptr->more) {
691 if(ptr->name_alloc) {
692 Curl_safefree(ptr->name);
693 ptr->name_alloc = FALSE;
695 if(ptr->value_alloc) {
696 Curl_safefree(ptr->value);
697 ptr->value_alloc = FALSE;
699 if(ptr->contenttype_alloc) {
700 Curl_safefree(ptr->contenttype);
701 ptr->contenttype_alloc = FALSE;
703 if(ptr->showfilename_alloc) {
704 Curl_safefree(ptr->showfilename);
705 ptr->showfilename_alloc = FALSE;
711 /* Always deallocate FormInfo linked list nodes without touching node
712 fields given that these have either been deallocated or are owned
713 now by the httppost linked list */
715 FormInfo *ptr = first_form->more;
716 Curl_safefree(first_form);
724 * curl_formadd() is a public API to add a section to the multipart formpost.
729 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
730 struct curl_httppost **last_post,
735 va_start(arg, last_post);
736 result = FormAdd(httppost, last_post, arg);
744 * get_vms_file_size does what it takes to get the real size of the file
746 * For fixed files, find out the size of the EOF block and adjust.
748 * For all others, have to read the entire file in, discarding the contents.
749 * Most posted text files will be small, and binary files like zlib archives
750 * and CD/DVD images should be either a STREAM_LF format or a fixed format.
753 curl_off_t VmsRealFileSize(const char * name,
754 const struct_stat * stat_buf)
761 file = fopen(name, "r");
767 while(ret_stat > 0) {
768 ret_stat = fread(buffer, 1, sizeof(buffer), file);
779 * VmsSpecialSize checks to see if the stat st_size can be trusted and
780 * if not to call a routine to get the correct size.
783 static curl_off_t VmsSpecialSize(const char * name,
784 const struct_stat * stat_buf)
786 switch(stat_buf->st_fab_rfm) {
789 return VmsRealFileSize(name, stat_buf);
792 return stat_buf->st_size;
799 #define filesize(name, stat_data) (stat_data.st_size)
801 /* Getting the expected file size needs help on VMS */
802 #define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
806 * AddFormData() adds a chunk of data to the FormData linked list.
808 * size is incremented by the chunk length, unless it is NULL
810 static CURLcode AddFormData(struct FormData **formp,
816 struct FormData *newform = malloc(sizeof(struct FormData));
818 return CURLE_OUT_OF_MEMORY;
819 newform->next = NULL;
821 if(type <= FORM_CONTENT) {
822 /* we make it easier for plain strings: */
824 length = strlen((char *)line);
826 newform->line = malloc(length+1);
829 return CURLE_OUT_OF_MEMORY;
831 memcpy(newform->line, line, length);
832 newform->length = length;
833 newform->line[length]=0; /* zero terminate for easier debugging */
836 /* For callbacks and files we don't have any actual data so we just keep a
837 pointer to whatever this points to */
838 newform->line = (char *)line;
840 newform->type = type;
843 (*formp)->next = newform;
850 if(type != FORM_FILE)
851 /* for static content as well as callback data we add the size given
855 /* Since this is a file to be uploaded here, add the size of the actual
857 if(!strequal("-", newform->line)) {
859 if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode))
860 *size += filesize(newform->line, file);
862 return CURLE_BAD_FUNCTION_ARGUMENT;
870 * AddFormDataf() adds printf()-style formatted data to the formdata chain.
873 static CURLcode AddFormDataf(struct FormData **formp,
875 const char *fmt, ...)
880 vsnprintf(s, sizeof(s), fmt, ap);
883 return AddFormData(formp, FORM_DATA, s, 0, size);
887 * Curl_formclean() is used from http.c, this cleans a built FormData linked
890 void Curl_formclean(struct FormData **form_ptr)
892 struct FormData *next, *form;
899 next=form->next; /* the following form line */
900 if(form->type <= FORM_CONTENT)
901 free(form->line); /* free the line */
902 free(form); /* free the struct */
904 } while((form = next) != NULL); /* continue */
911 * Serialize a curl_httppost struct.
912 * Returns 0 on success.
916 int curl_formget(struct curl_httppost *form, void *arg,
917 curl_formget_callback append)
921 struct FormData *data, *ptr;
923 result = Curl_getformdata(NULL, &data, form, NULL, &size);
927 for(ptr = data; ptr; ptr = ptr->next) {
928 if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) {
933 Curl_FormInit(&temp, ptr);
936 nread = readfromfile(&temp, buffer, sizeof(buffer));
937 if((nread == (size_t) -1) ||
938 (nread > sizeof(buffer)) ||
939 (nread != append(arg, buffer, nread))) {
942 Curl_formclean(&data);
948 if(ptr->length != append(arg, ptr->line, ptr->length)) {
949 Curl_formclean(&data);
954 Curl_formclean(&data);
959 * curl_formfree() is an external function to free up a whole form post
962 void curl_formfree(struct curl_httppost *form)
964 struct curl_httppost *next;
967 /* no form to free, just get out of this */
971 next=form->next; /* the following form line */
973 /* recurse to sub-contents */
975 curl_formfree(form->more);
977 if(!(form->flags & HTTPPOST_PTRNAME) && form->name)
978 free(form->name); /* free the name */
980 (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK)) &&
982 free(form->contents); /* free the contents */
983 if(form->contenttype)
984 free(form->contenttype); /* free the content type */
985 if(form->showfilename)
986 free(form->showfilename); /* free the faked file name */
987 free(form); /* free the struct */
989 } while((form = next) != NULL); /* continue */
992 #ifndef HAVE_BASENAME
994 (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
997 The basename() function shall take the pathname pointed to by path and
998 return a pointer to the final component of the pathname, deleting any
999 trailing '/' characters.
1001 If the string pointed to by path consists entirely of the '/' character,
1002 basename() shall return a pointer to the string "/". If the string pointed
1003 to by path is exactly "//", it is implementation-defined whether '/' or "//"
1006 If path is a null pointer or points to an empty string, basename() shall
1007 return a pointer to the string ".".
1009 The basename() function may modify the string pointed to by path, and may
1010 return a pointer to static storage that may then be overwritten by a
1011 subsequent call to basename().
1013 The basename() function need not be reentrant. A function that is not
1014 required to be reentrant is not required to be thread-safe.
1017 static char *Curl_basename(char *path)
1019 /* Ignore all the details above for now and make a quick and simple
1020 implementaion here */
1024 s1=strrchr(path, '/');
1025 s2=strrchr(path, '\\');
1028 path = (s1 > s2? s1 : s2)+1;
1039 static char *strippath(const char *fullfile)
1043 filename = strdup(fullfile); /* duplicate since basename() may ruin the
1044 buffer it works on */
1047 base = strdup(basename(filename));
1049 free(filename); /* free temporary buffer */
1051 return base; /* returns an allocated string or NULL ! */
1054 static CURLcode formdata_add_filename(const struct curl_httppost *file,
1055 struct FormData **form,
1058 CURLcode result = CURLE_OK;
1059 char *filename = file->showfilename;
1060 char *filebasename = NULL;
1061 char *filename_escaped = NULL;
1064 filebasename = strippath(file->contents);
1066 return CURLE_OUT_OF_MEMORY;
1067 filename = filebasename;
1070 if(strchr(filename, '\\') || strchr(filename, '"')) {
1073 /* filename need be escaped */
1074 filename_escaped = malloc(strlen(filename)*2+1);
1075 if(!filename_escaped) {
1076 Curl_safefree(filebasename);
1077 return CURLE_OUT_OF_MEMORY;
1079 p0 = filename_escaped;
1082 if(*p1 == '\\' || *p1 == '"')
1087 filename = filename_escaped;
1089 result = AddFormDataf(form, size,
1090 "; filename=\"%s\"",
1092 Curl_safefree(filename_escaped);
1093 Curl_safefree(filebasename);
1098 * Curl_getformdata() converts a linked list of "meta data" into a complete
1099 * (possibly huge) multipart formdata. The input list is in 'post', while the
1100 * output resulting linked lists gets stored in '*finalform'. *sizep will get
1101 * the total size of the whole POST.
1102 * A multipart/form_data content-type is built, unless a custom content-type
1103 * is passed in 'custom_content_type'.
1105 * This function will not do a failf() for the potential memory failures but
1106 * should for all other errors it spots. Just note that this function MAY get
1107 * a NULL pointer in the 'data' argument.
1110 CURLcode Curl_getformdata(struct SessionHandle *data,
1111 struct FormData **finalform,
1112 struct curl_httppost *post,
1113 const char *custom_content_type,
1116 struct FormData *form = NULL;
1117 struct FormData *firstform;
1118 struct curl_httppost *file;
1119 CURLcode result = CURLE_OK;
1121 curl_off_t size = 0; /* support potentially ENORMOUS formposts */
1123 char *fileboundary = NULL;
1124 struct curl_slist* curList;
1126 *finalform = NULL; /* default form is empty */
1129 return result; /* no input => no output! */
1131 boundary = formboundary(data);
1133 return CURLE_OUT_OF_MEMORY;
1135 /* Make the first line of the output */
1136 result = AddFormDataf(&form, NULL,
1137 "%s; boundary=%s\r\n",
1138 custom_content_type?custom_content_type:
1139 "Content-Type: multipart/form-data",
1143 Curl_safefree(boundary);
1146 /* we DO NOT include that line in the total size of the POST, since it'll be
1147 part of the header! */
1154 result = AddFormDataf(&form, &size, "\r\n");
1160 result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
1164 /* Maybe later this should be disabled when a custom_content_type is
1165 passed, since Content-Disposition is not meaningful for all multipart
1168 result = AddFormDataf(&form, &size,
1169 "Content-Disposition: form-data; name=\"");
1173 result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
1178 result = AddFormDataf(&form, &size, "\"");
1183 /* If used, this is a link to more file names, we must then do
1184 the magic to include several files with the same field name */
1186 Curl_safefree(fileboundary);
1187 fileboundary = formboundary(data);
1189 result = CURLE_OUT_OF_MEMORY;
1193 result = AddFormDataf(&form, &size,
1194 "\r\nContent-Type: multipart/mixed;"
1205 /* If 'showfilename' is set, that is a faked name passed on to us
1206 to use to in the formpost. If that is not set, the actually used
1207 local file name should be added. */
1210 /* if multiple-file */
1211 result = AddFormDataf(&form, &size,
1212 "\r\n--%s\r\nContent-Disposition: "
1217 result = formdata_add_filename(file, &form, &size);
1221 else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
1222 HTTPPOST_CALLBACK)) {
1223 /* it should be noted that for the HTTPPOST_FILENAME and
1224 HTTPPOST_CALLBACK cases the ->showfilename struct member is always
1225 assigned at this point */
1226 if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) {
1227 result = formdata_add_filename(post, &form, &size);
1234 if(file->contenttype) {
1235 /* we have a specified type */
1236 result = AddFormDataf(&form, &size,
1237 "\r\nContent-Type: %s",
1243 curList = file->contentheader;
1245 /* Process the additional headers specified for this form */
1246 result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
1249 curList = curList->next;
1254 result = AddFormDataf(&form, &size, "\r\n\r\n");
1258 if((post->flags & HTTPPOST_FILENAME) ||
1259 (post->flags & HTTPPOST_READFILE)) {
1260 /* we should include the contents from the specified file */
1263 fileread = strequal("-", file->contents)?
1264 stdin:fopen(file->contents, "rb"); /* binary read for win32 */
1267 * VMS: This only allows for stream files on VMS. Stream files are
1268 * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
1269 * every record needs to have a \n appended & 1 added to SIZE
1273 if(fileread != stdin) {
1274 /* close the file */
1276 /* add the file name only - for later reading from this */
1277 result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
1280 /* When uploading from stdin, we can't know the size of the file,
1281 * thus must read the full file as before. We *could* use chunked
1282 * transfer-encoding, but that only works for HTTP 1.1 and we
1283 * can't be sure we work with such a server.
1287 while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
1288 result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
1296 failf(data, "couldn't open file \"%s\"", file->contents);
1298 result = CURLE_READ_ERROR;
1301 else if(post->flags & HTTPPOST_BUFFER)
1302 /* include contents of buffer */
1303 result = AddFormData(&form, FORM_CONTENT, post->buffer,
1304 post->bufferlength, &size);
1305 else if(post->flags & HTTPPOST_CALLBACK)
1306 /* the contents should be read with the callback and the size
1307 is set with the contentslength */
1308 result = AddFormData(&form, FORM_CALLBACK, post->userp,
1309 post->contentslength, &size);
1311 /* include the contents we got */
1312 result = AddFormData(&form, FORM_CONTENT, post->contents,
1313 post->contentslength, &size);
1316 } while(file && !result); /* for each specified file for this field */
1322 /* this was a multiple-file inclusion, make a termination file
1324 result = AddFormDataf(&form, &size,
1331 } while((post = post->next) != NULL); /* for each field */
1333 /* end-boundary for everything */
1335 result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary);
1338 Curl_formclean(&firstform);
1339 Curl_safefree(fileboundary);
1340 Curl_safefree(boundary);
1346 Curl_safefree(fileboundary);
1347 Curl_safefree(boundary);
1349 *finalform = firstform;
1355 * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
1356 * and resets the 'sent' counter.
1358 int Curl_FormInit(struct Form *form, struct FormData *formdata )
1361 return 1; /* error */
1363 form->data = formdata;
1366 form->fread_func = ZERO_NULL;
1372 # define fopen_read fopen
1377 * For upload to work as expected on VMS, different optional
1378 * parameters must be added to the fopen command based on
1379 * record format of the file.
1382 # define fopen_read vmsfopenread
1383 static FILE * vmsfopenread(const char *file, const char *mode) {
1384 struct_stat statbuf;
1387 result = stat(file, &statbuf);
1389 switch (statbuf.st_fab_rfm) {
1393 return fopen(file, "r");
1396 return fopen(file, "r", "rfm=stmlf", "ctx=stm");
1404 * The read callback that this function may use can return a value larger than
1405 * 'size' (which then this function returns) that indicates a problem and it
1406 * must be properly dealt with
1408 static size_t readfromfile(struct Form *form, char *buffer,
1412 bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE;
1415 if(form->fread_func == ZERO_NULL)
1418 nread = form->fread_func(buffer, 1, size, form->data->line);
1422 /* this file hasn't yet been opened */
1423 form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
1425 return (size_t)-1; /* failure */
1427 nread = fread(buffer, 1, size, form->fp);
1430 /* this is the last chunk from the file, move on */
1435 form->data = form->data->next;
1442 * Curl_FormReader() is the fread() emulation function that will be used to
1443 * deliver the formdata to the transfer loop and then sent away to the peer.
1445 size_t Curl_FormReader(char *buffer,
1454 form=(struct Form *)mydata;
1456 wantedsize = size * nitems;
1459 return 0; /* nothing, error, empty */
1461 if((form->data->type == FORM_FILE) ||
1462 (form->data->type == FORM_CALLBACK)) {
1463 gotsize = readfromfile(form, buffer, wantedsize);
1466 /* If positive or -1, return. If zero, continue! */
1471 if((form->data->length - form->sent ) > wantedsize - gotsize) {
1473 memcpy(buffer + gotsize , form->data->line + form->sent,
1474 wantedsize - gotsize);
1476 form->sent += wantedsize-gotsize;
1481 memcpy(buffer+gotsize,
1482 form->data->line + form->sent,
1483 (form->data->length - form->sent) );
1484 gotsize += form->data->length - form->sent;
1488 form->data = form->data->next; /* advance */
1490 } while(form->data && (form->data->type < FORM_CALLBACK));
1491 /* If we got an empty line and we have more data, we proceed to the next
1492 line immediately to avoid returning zero before we've reached the end. */
1498 * Curl_formpostheader() returns the first line of the formpost, the
1499 * request-header part (which is not part of the request-body like the rest of
1502 char *Curl_formpostheader(void *formp, size_t *len)
1505 struct Form *form=(struct Form *)formp;
1508 return 0; /* nothing, ERROR! */
1510 header = form->data->line;
1511 *len = form->data->length;
1513 form->data = form->data->next; /* advance */
1519 * formboundary() creates a suitable boundary string and returns an allocated
1522 static char *formboundary(struct SessionHandle *data)
1524 /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
1526 return aprintf("------------------------%08x%08x",
1527 Curl_rand(data), Curl_rand(data));
1530 #else /* CURL_DISABLE_HTTP */
1531 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
1532 struct curl_httppost **last_post,
1537 return CURL_FORMADD_DISABLED;
1540 int curl_formget(struct curl_httppost *form, void *arg,
1541 curl_formget_callback append)
1546 return CURL_FORMADD_DISABLED;
1549 void curl_formfree(struct curl_httppost *form)
1552 /* does nothing HTTP is disabled */
1556 #endif /* !defined(CURL_DISABLE_HTTP) */