From 02f5c2ed34d16c9809b488b5a5082c40bb0f3188 Mon Sep 17 00:00:00 2001 From: Michał Cichoń Date: Thu, 27 Aug 2015 21:12:00 +0200 Subject: Remove libcurl as it was replaced by WinHTTP. --- libcurl/src/lib/formdata.c | 1551 -------------------------------------------- 1 file changed, 1551 deletions(-) delete mode 100644 libcurl/src/lib/formdata.c (limited to 'libcurl/src/lib/formdata.c') diff --git a/libcurl/src/lib/formdata.c b/libcurl/src/lib/formdata.c deleted file mode 100644 index 3e97830..0000000 --- a/libcurl/src/lib/formdata.c +++ /dev/null @@ -1,1551 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include - -#ifndef CURL_DISABLE_HTTP - -#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) -#include -#endif - -#include "urldata.h" /* for struct SessionHandle */ -#include "formdata.h" -#include "vtls/vtls.h" -#include "strequal.h" -#include "sendf.h" -#include "strdup.h" -#include "curl_printf.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -#ifndef HAVE_BASENAME -static char *Curl_basename(char *path); -#define basename(x) Curl_basename((x)) -#endif - -static size_t readfromfile(struct Form *form, char *buffer, size_t size); -static char *formboundary(struct SessionHandle *data); - -/* What kind of Content-Type to use on un-specified files with unrecognized - extensions. */ -#define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream" - -#define FORM_FILE_SEPARATOR ',' -#define FORM_TYPE_SEPARATOR ';' - -/*************************************************************************** - * - * AddHttpPost() - * - * Adds a HttpPost structure to the list, if parent_post is given becomes - * a subpost of parent_post instead of a direct list element. - * - * Returns newly allocated HttpPost on success and NULL if malloc failed. - * - ***************************************************************************/ -static struct curl_httppost * -AddHttpPost(char *name, size_t namelength, - char *value, size_t contentslength, - char *buffer, size_t bufferlength, - char *contenttype, - long flags, - struct curl_slist* contentHeader, - char *showfilename, char *userp, - struct curl_httppost *parent_post, - struct curl_httppost **httppost, - struct curl_httppost **last_post) -{ - struct curl_httppost *post; - post = calloc(1, sizeof(struct curl_httppost)); - if(post) { - post->name = name; - post->namelength = (long)(name?(namelength?namelength:strlen(name)):0); - post->contents = value; - post->contentslength = (long)contentslength; - post->buffer = buffer; - post->bufferlength = (long)bufferlength; - post->contenttype = contenttype; - post->contentheader = contentHeader; - post->showfilename = showfilename; - post->userp = userp, - post->flags = flags; - } - else - return NULL; - - if(parent_post) { - /* now, point our 'more' to the original 'more' */ - post->more = parent_post->more; - - /* then move the original 'more' to point to ourselves */ - parent_post->more = post; - } - else { - /* make the previous point to this */ - if(*last_post) - (*last_post)->next = post; - else - (*httppost) = post; - - (*last_post) = post; - } - return post; -} - -/*************************************************************************** - * - * AddFormInfo() - * - * Adds a FormInfo structure to the list presented by parent_form_info. - * - * Returns newly allocated FormInfo on success and NULL if malloc failed/ - * parent_form_info is NULL. - * - ***************************************************************************/ -static FormInfo * AddFormInfo(char *value, - char *contenttype, - FormInfo *parent_form_info) -{ - FormInfo *form_info; - form_info = calloc(1, sizeof(struct FormInfo)); - if(form_info) { - if(value) - form_info->value = value; - if(contenttype) - form_info->contenttype = contenttype; - form_info->flags = HTTPPOST_FILENAME; - } - else - return NULL; - - if(parent_form_info) { - /* now, point our 'more' to the original 'more' */ - form_info->more = parent_form_info->more; - - /* then move the original 'more' to point to ourselves */ - parent_form_info->more = form_info; - } - - return form_info; -} - -/*************************************************************************** - * - * ContentTypeForFilename() - * - * Provides content type for filename if one of the known types (else - * (either the prevtype or the default is returned). - * - * Returns some valid contenttype for filename. - * - ***************************************************************************/ -static const char *ContentTypeForFilename(const char *filename, - const char *prevtype) -{ - const char *contenttype = NULL; - unsigned int i; - /* - * No type was specified, we scan through a few well-known - * extensions and pick the first we match! - */ - struct ContentType { - const char *extension; - const char *type; - }; - static const struct ContentType ctts[]={ - {".gif", "image/gif"}, - {".jpg", "image/jpeg"}, - {".jpeg", "image/jpeg"}, - {".txt", "text/plain"}, - {".html", "text/html"}, - {".xml", "application/xml"} - }; - - if(prevtype) - /* default to the previously set/used! */ - contenttype = prevtype; - else - contenttype = HTTPPOST_CONTENTTYPE_DEFAULT; - - if(filename) { /* in case a NULL was passed in */ - for(i=0; i= strlen(ctts[i].extension)) { - if(strequal(filename + - strlen(filename) - strlen(ctts[i].extension), - ctts[i].extension)) { - contenttype = ctts[i].type; - break; - } - } - } - } - /* we have a contenttype by now */ - return contenttype; -} - -/*************************************************************************** - * - * FormAdd() - * - * Stores a formpost parameter and builds the appropriate linked list. - * - * Has two principal functionalities: using files and byte arrays as - * post parts. Byte arrays are either copied or just the pointer is stored - * (as the user requests) while for files only the filename and not the - * content is stored. - * - * While you may have only one byte array for each name, multiple filenames - * are allowed (and because of this feature CURLFORM_END is needed after - * using CURLFORM_FILE). - * - * Examples: - * - * Simple name/value pair with copied contents: - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_COPYCONTENTS, "value", CURLFORM_END); - * - * name/value pair where only the content pointer is remembered: - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END); - * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used) - * - * storing a filename (CONTENTTYPE is optional!): - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text", - * CURLFORM_END); - * - * storing multiple filenames: - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END); - * - * Returns: - * CURL_FORMADD_OK on success - * CURL_FORMADD_MEMORY if the FormInfo allocation fails - * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form - * CURL_FORMADD_NULL if a null pointer was given for a char - * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed - * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used - * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) - * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated - * CURL_FORMADD_MEMORY if some allocation for string copying failed. - * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array - * - ***************************************************************************/ - -static -CURLFORMcode FormAdd(struct curl_httppost **httppost, - struct curl_httppost **last_post, - va_list params) -{ - FormInfo *first_form, *current_form, *form = NULL; - CURLFORMcode return_value = CURL_FORMADD_OK; - const char *prevtype = NULL; - struct curl_httppost *post = NULL; - CURLformoption option; - struct curl_forms *forms = NULL; - char *array_value=NULL; /* value read from an array */ - - /* This is a state variable, that if TRUE means that we're parsing an - array that we got passed to us. If FALSE we're parsing the input - va_list arguments. */ - bool array_state = FALSE; - - /* - * We need to allocate the first struct to fill in. - */ - first_form = calloc(1, sizeof(struct FormInfo)); - if(!first_form) - return CURL_FORMADD_MEMORY; - - current_form = first_form; - - /* - * Loop through all the options set. Break if we have an error to report. - */ - while(return_value == CURL_FORMADD_OK) { - - /* first see if we have more parts of the array param */ - if(array_state && forms) { - /* get the upcoming option from the given array */ - option = forms->option; - array_value = (char *)forms->value; - - forms++; /* advance this to next entry */ - if(CURLFORM_END == option) { - /* end of array state */ - array_state = FALSE; - continue; - } - } - else { - /* This is not array-state, get next option */ - option = va_arg(params, CURLformoption); - if(CURLFORM_END == option) - break; - } - - switch (option) { - case CURLFORM_ARRAY: - if(array_state) - /* we don't support an array from within an array */ - return_value = CURL_FORMADD_ILLEGAL_ARRAY; - else { - forms = va_arg(params, struct curl_forms *); - if(forms) - array_state = TRUE; - else - return_value = CURL_FORMADD_NULL; - } - break; - - /* - * Set the Name property. - */ - case CURLFORM_PTRNAME: -#ifdef CURL_DOES_CONVERSIONS - /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy - * the data in all cases so that we'll have safe memory for the eventual - * conversion. - */ -#else - current_form->flags |= HTTPPOST_PTRNAME; /* fall through */ -#endif - case CURLFORM_COPYNAME: - if(current_form->name) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - char *name = array_state? - array_value:va_arg(params, char *); - if(name) - current_form->name = name; /* store for the moment */ - else - return_value = CURL_FORMADD_NULL; - } - break; - case CURLFORM_NAMELENGTH: - if(current_form->namelength) - return_value = CURL_FORMADD_OPTION_TWICE; - else - current_form->namelength = - array_state?(size_t)array_value:(size_t)va_arg(params, long); - break; - - /* - * Set the contents property. - */ - case CURLFORM_PTRCONTENTS: - current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */ - case CURLFORM_COPYCONTENTS: - if(current_form->value) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - char *value = - array_state?array_value:va_arg(params, char *); - if(value) - current_form->value = value; /* store for the moment */ - else - return_value = CURL_FORMADD_NULL; - } - break; - case CURLFORM_CONTENTSLENGTH: - if(current_form->contentslength) - return_value = CURL_FORMADD_OPTION_TWICE; - else - current_form->contentslength = - array_state?(size_t)array_value:(size_t)va_arg(params, long); - break; - - /* Get contents from a given file name */ - case CURLFORM_FILECONTENT: - if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE)) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - const char *filename = array_state? - array_value:va_arg(params, char *); - if(filename) { - current_form->value = strdup(filename); - if(!current_form->value) - return_value = CURL_FORMADD_MEMORY; - else { - current_form->flags |= HTTPPOST_READFILE; - current_form->value_alloc = TRUE; - } - } - else - return_value = CURL_FORMADD_NULL; - } - break; - - /* We upload a file */ - case CURLFORM_FILE: - { - const char *filename = array_state?array_value: - va_arg(params, char *); - - if(current_form->value) { - if(current_form->flags & HTTPPOST_FILENAME) { - if(filename) { - char *fname = strdup(filename); - if(!fname) - return_value = CURL_FORMADD_MEMORY; - else { - form = AddFormInfo(fname, NULL, current_form); - if(!form) { - free(fname); - return_value = CURL_FORMADD_MEMORY; - } - else { - form->value_alloc = TRUE; - current_form = form; - form = NULL; - } - } - } - else - return_value = CURL_FORMADD_NULL; - } - else - return_value = CURL_FORMADD_OPTION_TWICE; - } - else { - if(filename) { - current_form->value = strdup(filename); - if(!current_form->value) - return_value = CURL_FORMADD_MEMORY; - else { - current_form->flags |= HTTPPOST_FILENAME; - current_form->value_alloc = TRUE; - } - } - else - return_value = CURL_FORMADD_NULL; - } - break; - } - - case CURLFORM_BUFFERPTR: - current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER; - if(current_form->buffer) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - char *buffer = - array_state?array_value:va_arg(params, char *); - if(buffer) { - current_form->buffer = buffer; /* store for the moment */ - current_form->value = buffer; /* make it non-NULL to be accepted - as fine */ - } - else - return_value = CURL_FORMADD_NULL; - } - break; - - case CURLFORM_BUFFERLENGTH: - if(current_form->bufferlength) - return_value = CURL_FORMADD_OPTION_TWICE; - else - current_form->bufferlength = - array_state?(size_t)array_value:(size_t)va_arg(params, long); - break; - - case CURLFORM_STREAM: - current_form->flags |= HTTPPOST_CALLBACK; - if(current_form->userp) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - char *userp = - array_state?array_value:va_arg(params, char *); - if(userp) { - current_form->userp = userp; - current_form->value = userp; /* this isn't strictly true but we - derive a value from this later on - and we need this non-NULL to be - accepted as a fine form part */ - } - else - return_value = CURL_FORMADD_NULL; - } - break; - - case CURLFORM_CONTENTTYPE: - { - const char *contenttype = - array_state?array_value:va_arg(params, char *); - if(current_form->contenttype) { - if(current_form->flags & HTTPPOST_FILENAME) { - if(contenttype) { - char *type = strdup(contenttype); - if(!type) - return_value = CURL_FORMADD_MEMORY; - else { - form = AddFormInfo(NULL, type, current_form); - if(!form) { - free(type); - return_value = CURL_FORMADD_MEMORY; - } - else { - form->contenttype_alloc = TRUE; - current_form = form; - form = NULL; - } - } - } - else - return_value = CURL_FORMADD_NULL; - } - else - return_value = CURL_FORMADD_OPTION_TWICE; - } - else { - if(contenttype) { - current_form->contenttype = strdup(contenttype); - if(!current_form->contenttype) - return_value = CURL_FORMADD_MEMORY; - else - current_form->contenttype_alloc = TRUE; - } - else - return_value = CURL_FORMADD_NULL; - } - break; - } - case CURLFORM_CONTENTHEADER: - { - /* this "cast increases required alignment of target type" but - we consider it OK anyway */ - struct curl_slist* list = array_state? - (struct curl_slist*)array_value: - va_arg(params, struct curl_slist*); - - if(current_form->contentheader) - return_value = CURL_FORMADD_OPTION_TWICE; - else - current_form->contentheader = list; - - break; - } - case CURLFORM_FILENAME: - case CURLFORM_BUFFER: - { - const char *filename = array_state?array_value: - va_arg(params, char *); - if(current_form->showfilename) - return_value = CURL_FORMADD_OPTION_TWICE; - else { - current_form->showfilename = strdup(filename); - if(!current_form->showfilename) - return_value = CURL_FORMADD_MEMORY; - else - current_form->showfilename_alloc = TRUE; - } - break; - } - default: - return_value = CURL_FORMADD_UNKNOWN_OPTION; - break; - } - } - - if(CURL_FORMADD_OK != return_value) { - /* On error, free allocated fields for all nodes of the FormInfo linked - list without deallocating nodes. List nodes are deallocated later on */ - FormInfo *ptr; - for(ptr = first_form; ptr != NULL; ptr = ptr->more) { - if(ptr->name_alloc) { - Curl_safefree(ptr->name); - ptr->name_alloc = FALSE; - } - if(ptr->value_alloc) { - Curl_safefree(ptr->value); - ptr->value_alloc = FALSE; - } - if(ptr->contenttype_alloc) { - Curl_safefree(ptr->contenttype); - ptr->contenttype_alloc = FALSE; - } - if(ptr->showfilename_alloc) { - Curl_safefree(ptr->showfilename); - ptr->showfilename_alloc = FALSE; - } - } - } - - if(CURL_FORMADD_OK == return_value) { - /* go through the list, check for completeness and if everything is - * alright add the HttpPost item otherwise set return_value accordingly */ - - post = NULL; - for(form = first_form; - form != NULL; - form = form->more) { - if(((!form->name || !form->value) && !post) || - ( (form->contentslength) && - (form->flags & HTTPPOST_FILENAME) ) || - ( (form->flags & HTTPPOST_FILENAME) && - (form->flags & HTTPPOST_PTRCONTENTS) ) || - - ( (!form->buffer) && - (form->flags & HTTPPOST_BUFFER) && - (form->flags & HTTPPOST_PTRBUFFER) ) || - - ( (form->flags & HTTPPOST_READFILE) && - (form->flags & HTTPPOST_PTRCONTENTS) ) - ) { - return_value = CURL_FORMADD_INCOMPLETE; - break; - } - else { - if(((form->flags & HTTPPOST_FILENAME) || - (form->flags & HTTPPOST_BUFFER)) && - !form->contenttype ) { - char *f = form->flags & HTTPPOST_BUFFER? - form->showfilename : form->value; - - /* our contenttype is missing */ - form->contenttype = strdup(ContentTypeForFilename(f, prevtype)); - if(!form->contenttype) { - return_value = CURL_FORMADD_MEMORY; - break; - } - form->contenttype_alloc = TRUE; - } - if(!(form->flags & HTTPPOST_PTRNAME) && - (form == first_form) ) { - /* Note that there's small risk that form->name is NULL here if the - app passed in a bad combo, so we better check for that first. */ - if(form->name) { - /* copy name (without strdup; possibly contains null characters) */ - form->name = Curl_memdup(form->name, form->namelength? - form->namelength: - strlen(form->name)+1); - } - if(!form->name) { - return_value = CURL_FORMADD_MEMORY; - break; - } - form->name_alloc = TRUE; - } - if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE | - HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER | - HTTPPOST_CALLBACK)) && form->value) { - /* copy value (without strdup; possibly contains null characters) */ - form->value = Curl_memdup(form->value, form->contentslength? - form->contentslength: - strlen(form->value)+1); - if(!form->value) { - return_value = CURL_FORMADD_MEMORY; - break; - } - form->value_alloc = TRUE; - } - post = AddHttpPost(form->name, form->namelength, - form->value, form->contentslength, - form->buffer, form->bufferlength, - form->contenttype, form->flags, - form->contentheader, form->showfilename, - form->userp, - post, httppost, - last_post); - - if(!post) { - return_value = CURL_FORMADD_MEMORY; - break; - } - - if(form->contenttype) - prevtype = form->contenttype; - } - } - if(CURL_FORMADD_OK != return_value) { - /* On error, free allocated fields for nodes of the FormInfo linked - list which are not already owned by the httppost linked list - without deallocating nodes. List nodes are deallocated later on */ - FormInfo *ptr; - for(ptr = form; ptr != NULL; ptr = ptr->more) { - if(ptr->name_alloc) { - Curl_safefree(ptr->name); - ptr->name_alloc = FALSE; - } - if(ptr->value_alloc) { - Curl_safefree(ptr->value); - ptr->value_alloc = FALSE; - } - if(ptr->contenttype_alloc) { - Curl_safefree(ptr->contenttype); - ptr->contenttype_alloc = FALSE; - } - if(ptr->showfilename_alloc) { - Curl_safefree(ptr->showfilename); - ptr->showfilename_alloc = FALSE; - } - } - } - } - - /* Always deallocate FormInfo linked list nodes without touching node - fields given that these have either been deallocated or are owned - now by the httppost linked list */ - while(first_form) { - FormInfo *ptr = first_form->more; - free(first_form); - first_form = ptr; - } - - return return_value; -} - -/* - * curl_formadd() is a public API to add a section to the multipart formpost. - * - * @unittest: 1308 - */ - -CURLFORMcode curl_formadd(struct curl_httppost **httppost, - struct curl_httppost **last_post, - ...) -{ - va_list arg; - CURLFORMcode result; - va_start(arg, last_post); - result = FormAdd(httppost, last_post, arg); - va_end(arg); - return result; -} - -#ifdef __VMS -#include -/* - * get_vms_file_size does what it takes to get the real size of the file - * - * For fixed files, find out the size of the EOF block and adjust. - * - * For all others, have to read the entire file in, discarding the contents. - * Most posted text files will be small, and binary files like zlib archives - * and CD/DVD images should be either a STREAM_LF format or a fixed format. - * - */ -curl_off_t VmsRealFileSize(const char * name, - const struct_stat * stat_buf) -{ - char buffer[8192]; - curl_off_t count; - int ret_stat; - FILE * file; - - file = fopen(name, "r"); - if(file == NULL) - return 0; - - count = 0; - ret_stat = 1; - while(ret_stat > 0) { - ret_stat = fread(buffer, 1, sizeof(buffer), file); - if(ret_stat != 0) - count += ret_stat; - } - fclose(file); - - return count; -} - -/* - * - * VmsSpecialSize checks to see if the stat st_size can be trusted and - * if not to call a routine to get the correct size. - * - */ -static curl_off_t VmsSpecialSize(const char * name, - const struct_stat * stat_buf) -{ - switch(stat_buf->st_fab_rfm) { - case FAB$C_VAR: - case FAB$C_VFC: - return VmsRealFileSize(name, stat_buf); - break; - default: - return stat_buf->st_size; - } -} - -#endif - -#ifndef __VMS -#define filesize(name, stat_data) (stat_data.st_size) -#else - /* Getting the expected file size needs help on VMS */ -#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data) -#endif - -/* - * AddFormData() adds a chunk of data to the FormData linked list. - * - * size is incremented by the chunk length, unless it is NULL - */ -static CURLcode AddFormData(struct FormData **formp, - enum formtype type, - const void *line, - size_t length, - curl_off_t *size) -{ - struct FormData *newform = malloc(sizeof(struct FormData)); - if(!newform) - return CURLE_OUT_OF_MEMORY; - newform->next = NULL; - - if(type <= FORM_CONTENT) { - /* we make it easier for plain strings: */ - if(!length) - length = strlen((char *)line); - - newform->line = malloc(length+1); - if(!newform->line) { - free(newform); - return CURLE_OUT_OF_MEMORY; - } - memcpy(newform->line, line, length); - newform->length = length; - newform->line[length]=0; /* zero terminate for easier debugging */ - } - else - /* For callbacks and files we don't have any actual data so we just keep a - pointer to whatever this points to */ - newform->line = (char *)line; - - newform->type = type; - - if(*formp) { - (*formp)->next = newform; - *formp = newform; - } - else - *formp = newform; - - if(size) { - if(type != FORM_FILE) - /* for static content as well as callback data we add the size given - as input argument */ - *size += length; - else { - /* Since this is a file to be uploaded here, add the size of the actual - file */ - if(!strequal("-", newform->line)) { - struct_stat file; - if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode)) - *size += filesize(newform->line, file); - else - return CURLE_BAD_FUNCTION_ARGUMENT; - } - } - } - return CURLE_OK; -} - -/* - * AddFormDataf() adds printf()-style formatted data to the formdata chain. - */ - -static CURLcode AddFormDataf(struct FormData **formp, - curl_off_t *size, - const char *fmt, ...) -{ - char s[4096]; - va_list ap; - va_start(ap, fmt); - vsnprintf(s, sizeof(s), fmt, ap); - va_end(ap); - - return AddFormData(formp, FORM_DATA, s, 0, size); -} - -/* - * Curl_formclean() is used from http.c, this cleans a built FormData linked - * list - */ -CURL_STATIC void Curl_formclean(struct FormData **form_ptr) -{ - struct FormData *next, *form; - - form = *form_ptr; - if(!form) - return; - - do { - next=form->next; /* the following form line */ - if(form->type <= FORM_CONTENT) - free(form->line); /* free the line */ - free(form); /* free the struct */ - - } while((form = next) != NULL); /* continue */ - - *form_ptr = NULL; -} - -/* - * curl_formget() - * Serialize a curl_httppost struct. - * Returns 0 on success. - * - * @unittest: 1308 - */ -int curl_formget(struct curl_httppost *form, void *arg, - curl_formget_callback append) -{ - CURLcode result; - curl_off_t size; - struct FormData *data, *ptr; - - result = Curl_getformdata(NULL, &data, form, NULL, &size); - if(result) - return (int)result; - - for(ptr = data; ptr; ptr = ptr->next) { - if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) { - char buffer[8192]; - size_t nread; - struct Form temp; - - Curl_FormInit(&temp, ptr); - - do { - nread = readfromfile(&temp, buffer, sizeof(buffer)); - if((nread == (size_t) -1) || - (nread > sizeof(buffer)) || - (nread != append(arg, buffer, nread))) { - if(temp.fp) - fclose(temp.fp); - Curl_formclean(&data); - return -1; - } - } while(nread); - } - else { - if(ptr->length != append(arg, ptr->line, ptr->length)) { - Curl_formclean(&data); - return -1; - } - } - } - Curl_formclean(&data); - return 0; -} - -/* - * curl_formfree() is an external function to free up a whole form post - * chain - */ -void curl_formfree(struct curl_httppost *form) -{ - struct curl_httppost *next; - - if(!form) - /* no form to free, just get out of this */ - return; - - do { - next=form->next; /* the following form line */ - - /* recurse to sub-contents */ - curl_formfree(form->more); - - if(!(form->flags & HTTPPOST_PTRNAME)) - free(form->name); /* free the name */ - if(!(form->flags & - (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK)) - ) - free(form->contents); /* free the contents */ - free(form->contenttype); /* free the content type */ - free(form->showfilename); /* free the faked file name */ - free(form); /* free the struct */ - - } while((form = next) != NULL); /* continue */ -} - -#ifndef HAVE_BASENAME -/* - (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 - Edition) - - The basename() function shall take the pathname pointed to by path and - return a pointer to the final component of the pathname, deleting any - trailing '/' characters. - - If the string pointed to by path consists entirely of the '/' character, - basename() shall return a pointer to the string "/". If the string pointed - to by path is exactly "//", it is implementation-defined whether '/' or "//" - is returned. - - If path is a null pointer or points to an empty string, basename() shall - return a pointer to the string ".". - - The basename() function may modify the string pointed to by path, and may - return a pointer to static storage that may then be overwritten by a - subsequent call to basename(). - - The basename() function need not be reentrant. A function that is not - required to be reentrant is not required to be thread-safe. - -*/ -static char *Curl_basename(char *path) -{ - /* Ignore all the details above for now and make a quick and simple - implementaion here */ - char *s1; - char *s2; - - s1=strrchr(path, '/'); - s2=strrchr(path, '\\'); - - if(s1 && s2) { - path = (s1 > s2? s1 : s2)+1; - } - else if(s1) - path = s1 + 1; - else if(s2) - path = s2 + 1; - - return path; -} -#endif - -static char *strippath(const char *fullfile) -{ - char *filename; - char *base; - filename = strdup(fullfile); /* duplicate since basename() may ruin the - buffer it works on */ - if(!filename) - return NULL; - base = strdup(basename(filename)); - - free(filename); /* free temporary buffer */ - - return base; /* returns an allocated string or NULL ! */ -} - -static CURLcode formdata_add_filename(const struct curl_httppost *file, - struct FormData **form, - curl_off_t *size) -{ - CURLcode result = CURLE_OK; - char *filename = file->showfilename; - char *filebasename = NULL; - char *filename_escaped = NULL; - - if(!filename) { - filebasename = strippath(file->contents); - if(!filebasename) - return CURLE_OUT_OF_MEMORY; - filename = filebasename; - } - - if(strchr(filename, '\\') || strchr(filename, '"')) { - char *p0, *p1; - - /* filename need be escaped */ - filename_escaped = malloc(strlen(filename)*2+1); - if(!filename_escaped) { - free(filebasename); - return CURLE_OUT_OF_MEMORY; - } - p0 = filename_escaped; - p1 = filename; - while(*p1) { - if(*p1 == '\\' || *p1 == '"') - *p0++ = '\\'; - *p0++ = *p1++; - } - *p0 = '\0'; - filename = filename_escaped; - } - result = AddFormDataf(form, size, - "; filename=\"%s\"", - filename); - free(filename_escaped); - free(filebasename); - return result; -} - -/* - * Curl_getformdata() converts a linked list of "meta data" into a complete - * (possibly huge) multipart formdata. The input list is in 'post', while the - * output resulting linked lists gets stored in '*finalform'. *sizep will get - * the total size of the whole POST. - * A multipart/form_data content-type is built, unless a custom content-type - * is passed in 'custom_content_type'. - * - * This function will not do a failf() for the potential memory failures but - * should for all other errors it spots. Just note that this function MAY get - * a NULL pointer in the 'data' argument. - */ - -CURL_STATIC CURLcode Curl_getformdata(struct SessionHandle *data, - struct FormData **finalform, - struct curl_httppost *post, - const char *custom_content_type, - curl_off_t *sizep) -{ - struct FormData *form = NULL; - struct FormData *firstform; - struct curl_httppost *file; - CURLcode result = CURLE_OK; - - curl_off_t size = 0; /* support potentially ENORMOUS formposts */ - char *boundary; - char *fileboundary = NULL; - struct curl_slist* curList; - - *finalform = NULL; /* default form is empty */ - - if(!post) - return result; /* no input => no output! */ - - boundary = formboundary(data); - if(!boundary) - return CURLE_OUT_OF_MEMORY; - - /* Make the first line of the output */ - result = AddFormDataf(&form, NULL, - "%s; boundary=%s\r\n", - custom_content_type?custom_content_type: - "Content-Type: multipart/form-data", - boundary); - - if(result) { - free(boundary); - return result; - } - /* we DO NOT include that line in the total size of the POST, since it'll be - part of the header! */ - - firstform = form; - - do { - - if(size) { - result = AddFormDataf(&form, &size, "\r\n"); - if(result) - break; - } - - /* boundary */ - result = AddFormDataf(&form, &size, "--%s\r\n", boundary); - if(result) - break; - - /* Maybe later this should be disabled when a custom_content_type is - passed, since Content-Disposition is not meaningful for all multipart - types. - */ - result = AddFormDataf(&form, &size, - "Content-Disposition: form-data; name=\""); - if(result) - break; - - result = AddFormData(&form, FORM_DATA, post->name, post->namelength, - &size); - if(result) - break; - - result = AddFormDataf(&form, &size, "\""); - if(result) - break; - - if(post->more) { - /* If used, this is a link to more file names, we must then do - the magic to include several files with the same field name */ - - free(fileboundary); - fileboundary = formboundary(data); - if(!fileboundary) { - result = CURLE_OUT_OF_MEMORY; - break; - } - - result = AddFormDataf(&form, &size, - "\r\nContent-Type: multipart/mixed;" - " boundary=%s\r\n", - fileboundary); - if(result) - break; - } - - file = post; - - do { - - /* If 'showfilename' is set, that is a faked name passed on to us - to use to in the formpost. If that is not set, the actually used - local file name should be added. */ - - if(post->more) { - /* if multiple-file */ - result = AddFormDataf(&form, &size, - "\r\n--%s\r\nContent-Disposition: " - "attachment", - fileboundary); - if(result) - break; - result = formdata_add_filename(file, &form, &size); - if(result) - break; - } - else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER| - HTTPPOST_CALLBACK)) { - /* it should be noted that for the HTTPPOST_FILENAME and - HTTPPOST_CALLBACK cases the ->showfilename struct member is always - assigned at this point */ - if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) { - result = formdata_add_filename(post, &form, &size); - } - - if(result) - break; - } - - if(file->contenttype) { - /* we have a specified type */ - result = AddFormDataf(&form, &size, - "\r\nContent-Type: %s", - file->contenttype); - if(result) - break; - } - - curList = file->contentheader; - while(curList) { - /* Process the additional headers specified for this form */ - result = AddFormDataf( &form, &size, "\r\n%s", curList->data ); - if(result) - break; - curList = curList->next; - } - if(result) - break; - - result = AddFormDataf(&form, &size, "\r\n\r\n"); - if(result) - break; - - if((post->flags & HTTPPOST_FILENAME) || - (post->flags & HTTPPOST_READFILE)) { - /* we should include the contents from the specified file */ - FILE *fileread; - - fileread = strequal("-", file->contents)? - stdin:fopen(file->contents, "rb"); /* binary read for win32 */ - - /* - * VMS: This only allows for stream files on VMS. Stream files are - * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC, - * every record needs to have a \n appended & 1 added to SIZE - */ - - if(fileread) { - if(fileread != stdin) { - /* close the file */ - fclose(fileread); - /* add the file name only - for later reading from this */ - result = AddFormData(&form, FORM_FILE, file->contents, 0, &size); - } - else { - /* When uploading from stdin, we can't know the size of the file, - * thus must read the full file as before. We *could* use chunked - * transfer-encoding, but that only works for HTTP 1.1 and we - * can't be sure we work with such a server. - */ - size_t nread; - char buffer[512]; - while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) { - result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size); - if(result) - break; - } - } - } - else { - if(data) - failf(data, "couldn't open file \"%s\"", file->contents); - *finalform = NULL; - result = CURLE_READ_ERROR; - } - } - else if(post->flags & HTTPPOST_BUFFER) - /* include contents of buffer */ - result = AddFormData(&form, FORM_CONTENT, post->buffer, - post->bufferlength, &size); - else if(post->flags & HTTPPOST_CALLBACK) - /* the contents should be read with the callback and the size - is set with the contentslength */ - result = AddFormData(&form, FORM_CALLBACK, post->userp, - post->contentslength, &size); - else - /* include the contents we got */ - result = AddFormData(&form, FORM_CONTENT, post->contents, - post->contentslength, &size); - - file = file->more; - } while(file && !result); /* for each specified file for this field */ - - if(result) - break; - - if(post->more) { - /* this was a multiple-file inclusion, make a termination file - boundary: */ - result = AddFormDataf(&form, &size, - "\r\n--%s--", - fileboundary); - if(result) - break; - } - - } while((post = post->next) != NULL); /* for each field */ - - /* end-boundary for everything */ - if(!result) - result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary); - - if(result) { - Curl_formclean(&firstform); - free(fileboundary); - free(boundary); - return result; - } - - *sizep = size; - - free(fileboundary); - free(boundary); - - *finalform = firstform; - - return result; -} - -/* - * Curl_FormInit() inits the struct 'form' points to with the 'formdata' - * and resets the 'sent' counter. - */ -CURL_STATIC int Curl_FormInit(struct Form *form, struct FormData *formdata ) -{ - if(!formdata) - return 1; /* error */ - - form->data = formdata; - form->sent = 0; - form->fp = NULL; - form->fread_func = ZERO_NULL; - - return 0; -} - -#ifndef __VMS -# define fopen_read fopen -#else - /* - * vmsfopenread - * - * For upload to work as expected on VMS, different optional - * parameters must be added to the fopen command based on - * record format of the file. - * - */ -# define fopen_read vmsfopenread -static FILE * vmsfopenread(const char *file, const char *mode) { - struct_stat statbuf; - int result; - - result = stat(file, &statbuf); - - switch (statbuf.st_fab_rfm) { - case FAB$C_VAR: - case FAB$C_VFC: - case FAB$C_STMCR: - return fopen(file, "r"); - break; - default: - return fopen(file, "r", "rfm=stmlf", "ctx=stm"); - } -} -#endif - -/* - * readfromfile() - * - * The read callback that this function may use can return a value larger than - * 'size' (which then this function returns) that indicates a problem and it - * must be properly dealt with - */ -static size_t readfromfile(struct Form *form, char *buffer, - size_t size) -{ - size_t nread; - bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE; - - if(callback) { - if(form->fread_func == ZERO_NULL) - return 0; - else - nread = form->fread_func(buffer, 1, size, form->data->line); - } - else { - if(!form->fp) { - /* this file hasn't yet been opened */ - form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */ - if(!form->fp) - return (size_t)-1; /* failure */ - } - nread = fread(buffer, 1, size, form->fp); - } - if(!nread) { - /* this is the last chunk from the file, move on */ - if(form->fp) { - fclose(form->fp); - form->fp = NULL; - } - form->data = form->data->next; - } - - return nread; -} - -/* - * Curl_FormReader() is the fread() emulation function that will be used to - * deliver the formdata to the transfer loop and then sent away to the peer. - */ -CURL_STATIC size_t Curl_FormReader(char *buffer, - size_t size, - size_t nitems, - FILE *mydata) -{ - struct Form *form; - size_t wantedsize; - size_t gotsize = 0; - - form=(struct Form *)mydata; - - wantedsize = size * nitems; - - if(!form->data) - return 0; /* nothing, error, empty */ - - if((form->data->type == FORM_FILE) || - (form->data->type == FORM_CALLBACK)) { - gotsize = readfromfile(form, buffer, wantedsize); - - if(gotsize) - /* If positive or -1, return. If zero, continue! */ - return gotsize; - } - do { - - if((form->data->length - form->sent ) > wantedsize - gotsize) { - - memcpy(buffer + gotsize , form->data->line + form->sent, - wantedsize - gotsize); - - form->sent += wantedsize-gotsize; - - return wantedsize; - } - - memcpy(buffer+gotsize, - form->data->line + form->sent, - (form->data->length - form->sent) ); - gotsize += form->data->length - form->sent; - - form->sent = 0; - - form->data = form->data->next; /* advance */ - - } while(form->data && (form->data->type < FORM_CALLBACK)); - /* If we got an empty line and we have more data, we proceed to the next - line immediately to avoid returning zero before we've reached the end. */ - - return gotsize; -} - -/* - * Curl_formpostheader() returns the first line of the formpost, the - * request-header part (which is not part of the request-body like the rest of - * the post). - */ -CURL_STATIC char *Curl_formpostheader(void *formp, size_t *len) -{ - char *header; - struct Form *form=(struct Form *)formp; - - if(!form->data) - return 0; /* nothing, ERROR! */ - - header = form->data->line; - *len = form->data->length; - - form->data = form->data->next; /* advance */ - - return header; -} - -/* - * formboundary() creates a suitable boundary string and returns an allocated - * one. - */ -static char *formboundary(struct SessionHandle *data) -{ - /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615) - combinations */ - return aprintf("------------------------%08x%08x", - Curl_rand(data), Curl_rand(data)); -} - -#else /* CURL_DISABLE_HTTP */ -CURLFORMcode curl_formadd(struct curl_httppost **httppost, - struct curl_httppost **last_post, - ...) -{ - (void)httppost; - (void)last_post; - return CURL_FORMADD_DISABLED; -} - -int curl_formget(struct curl_httppost *form, void *arg, - curl_formget_callback append) -{ - (void) form; - (void) arg; - (void) append; - return CURL_FORMADD_DISABLED; -} - -void curl_formfree(struct curl_httppost *form) -{ - (void)form; - /* does nothing HTTP is disabled */ -} - - -#endif /* !defined(CURL_DISABLE_HTTP) */ -- cgit v1.2.3