* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
*
***************************************************************************/
-#include "setup.h"
+#include "curl_setup.h"
#include <curl/curl.h>
-/* Length of the random boundary string. */
-#define BOUNDARY_LENGTH 40
-
#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
#include "urldata.h" /* for struct SessionHandle */
#include "formdata.h"
-#include "curl_rand.h"
+#include "vtls/vtls.h"
#include "strequal.h"
#include "curl_memory.h"
#include "sendf.h"
#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. */
/* then move the original 'more' to point to ourselves */
parent_form_info->more = form_info;
}
- else
- return NULL;
return form_info;
}
* Returns some valid contenttype for filename.
*
***************************************************************************/
-static const char * ContentTypeForFilename (const char *filename,
- const char *prevtype)
+static const char *ContentTypeForFilename(const char *filename,
+ const char *prevtype)
{
const char *contenttype = NULL;
unsigned int i;
* extensions and pick the first we match!
*/
struct ContentType {
- char extension[6];
+ const char *extension;
const char *type;
};
static const struct ContentType ctts[]={
/* Get contents from a given file name */
case CURLFORM_FILECONTENT:
- if(current_form->flags != 0)
+ if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
return_value = CURL_FORMADD_OPTION_TWICE;
else {
const char *filename = array_state?
if(current_form->value) {
if(current_form->flags & HTTPPOST_FILENAME) {
if(filename) {
- if((current_form = AddFormInfo(strdup(filename),
- NULL, current_form)) == NULL)
+ char *fname = strdup(filename);
+ if(!fname)
return_value = CURL_FORMADD_MEMORY;
+ else {
+ form = AddFormInfo(fname, NULL, current_form);
+ if(!form) {
+ Curl_safefree(fname);
+ return_value = CURL_FORMADD_MEMORY;
+ }
+ else {
+ form->value_alloc = TRUE;
+ current_form = form;
+ form = NULL;
+ }
+ }
}
else
return_value = CURL_FORMADD_NULL;
if(current_form->contenttype) {
if(current_form->flags & HTTPPOST_FILENAME) {
if(contenttype) {
- if((current_form = AddFormInfo(NULL,
- strdup(contenttype),
- current_form)) == NULL)
+ char *type = strdup(contenttype);
+ if(!type)
return_value = CURL_FORMADD_MEMORY;
+ else {
+ form = AddFormInfo(NULL, type, current_form);
+ if(!form) {
+ Curl_safefree(type);
+ return_value = CURL_FORMADD_MEMORY;
+ }
+ else {
+ form->contenttype_alloc = TRUE;
+ current_form = form;
+ form = NULL;
+ }
+ }
}
else
return_value = CURL_FORMADD_NULL;
}
}
+ 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 */
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(form->value, prevtype));
+ form->contenttype = strdup(ContentTypeForFilename(f, prevtype));
if(!form->contenttype) {
return_value = CURL_FORMADD_MEMORY;
break;
prevtype = form->contenttype;
}
}
- }
-
- if(return_value) {
- /* we return on error, free possibly allocated fields */
- if(!form)
- form = current_form;
- if(form) {
- if(form->name_alloc)
- free(form->name);
- if(form->value_alloc)
- free(form->value);
- if(form->contenttype_alloc)
- free(form->contenttype);
- if(form->showfilename_alloc)
- free(form->showfilename);
+ 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 delete the allocated memory before returning */
- form = first_form;
- while(form != NULL) {
- FormInfo *delete_form;
-
- delete_form = form;
- form = form->more;
- free (delete_form);
+ /* 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;
+ Curl_safefree(first_form);
+ first_form = ptr;
}
return return_value;
return result;
}
+#ifdef __VMS
+#include <fabdef.h>
+/*
+ * 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.
*
file */
if(!strequal("-", newform->line)) {
struct_stat file;
- if(!stat(newform->line, &file)) {
- *size += file.st_size;
- }
+ if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode))
+ *size += filesize(newform->line, file);
+ else
+ return CURLE_BAD_FUNCTION_ARGUMENT;
}
}
}
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) {
+ Curl_safefree(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);
+ Curl_safefree(filename_escaped);
+ Curl_safefree(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
struct curl_httppost *file;
CURLcode result = CURLE_OK;
- curl_off_t size=0; /* support potentially ENORMOUS formposts */
+ curl_off_t size = 0; /* support potentially ENORMOUS formposts */
char *boundary;
- char *fileboundary=NULL;
+ char *fileboundary = NULL;
struct curl_slist* curList;
- *finalform=NULL; /* default form is empty */
+ *finalform = NULL; /* default form is empty */
if(!post)
return result; /* no input => no output! */
- boundary = Curl_FormBoundary();
+ boundary = formboundary(data);
if(!boundary)
return CURLE_OUT_OF_MEMORY;
boundary);
if(result) {
- free(boundary);
+ Curl_safefree(boundary);
return result;
}
/* we DO NOT include that line in the total size of the POST, since it'll be
/* 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 */
- fileboundary = Curl_FormBoundary();
+ Curl_safefree(fileboundary);
+ fileboundary = formboundary(data);
+ if(!fileboundary) {
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
result = AddFormDataf(&form, &size,
- "\r\nContent-Type: multipart/mixed,"
+ "\r\nContent-Type: multipart/mixed;"
" boundary=%s\r\n",
fileboundary);
if(result)
if(post->more) {
/* if multiple-file */
- char *filebasename= NULL;
- if(!file->showfilename) {
- filebasename = strippath(file->contents);
- if(!filebasename) {
- Curl_formclean(&firstform);
- free(boundary);
- return CURLE_OUT_OF_MEMORY;
- }
- }
-
result = AddFormDataf(&form, &size,
"\r\n--%s\r\nContent-Disposition: "
- "attachment; filename=\"%s\"",
- fileboundary,
- (file->showfilename?file->showfilename:
- filebasename));
- if(filebasename)
- free(filebasename);
+ "attachment",
+ fileboundary);
+ if(result)
+ break;
+ result = formdata_add_filename(file, &form, &size);
if(result)
break;
}
HTTPPOST_CALLBACK cases the ->showfilename struct member is always
assigned at this point */
if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) {
- char *filebasename=
- (!post->showfilename)?strippath(post->contents):NULL;
-
- result = AddFormDataf(&form, &size,
- "; filename=\"%s\"",
- (post->showfilename?post->showfilename:
- filebasename));
- if(filebasename)
- free(filebasename);
+ result = formdata_add_filename(post, &form, &size);
}
if(result)
break;
curList = curList->next;
}
- if(result) {
- Curl_formclean(&firstform);
- free(boundary);
- return result;
- }
+ if(result)
+ break;
result = AddFormDataf(&form, &size, "\r\n\r\n");
if(result)
if(fileread) {
if(fileread != stdin) {
- /* close the file again */
+ /* 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 {
if(data)
- failf(data, "couldn't open file \"%s\"\n", file->contents);
+ failf(data, "couldn't open file \"%s\"", file->contents);
*finalform = NULL;
result = CURLE_READ_ERROR;
}
file = file->more;
} while(file && !result); /* for each specified file for this field */
- if(result) {
- Curl_formclean(&firstform);
- free(boundary);
- return result;
- }
+ if(result)
+ break;
if(post->more) {
/* this was a multiple-file inclusion, make a termination file
result = AddFormDataf(&form, &size,
"\r\n--%s--",
fileboundary);
- free(fileboundary);
if(result)
break;
}
} while((post = post->next) != NULL); /* for each field */
- if(result) {
- Curl_formclean(&firstform);
- free(boundary);
- return result;
- }
/* end-boundary for everything */
- result = AddFormDataf(&form, &size,
- "\r\n--%s--\r\n",
- boundary);
+ if(CURLE_OK == result)
+ result = AddFormDataf(&form, &size,
+ "\r\n--%s--\r\n",
+ boundary);
+
if(result) {
Curl_formclean(&firstform);
- free(boundary);
+ Curl_safefree(fileboundary);
+ Curl_safefree(boundary);
return result;
}
*sizep = size;
- free(boundary);
+ Curl_safefree(fileboundary);
+ Curl_safefree(boundary);
- *finalform=firstform;
+ *finalform = firstform;
return result;
}
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()
*
else {
if(!form->fp) {
/* this file hasn't yet been opened */
- form->fp = fopen(form->data->line, "rb"); /* b is for binary */
+ form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
if(!form->fp)
return (size_t)-1; /* failure */
}
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,
/* does nothing HTTP is disabled */
}
-#endif /* CURL_DISABLE_HTTP */
-
-#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
-
-/*
- * Curl_FormBoundary() creates a suitable boundary string and returns an
- * allocated one. This is also used by SSL-code so it must be present even
- * if HTTP is disabled!
- */
-char *Curl_FormBoundary(void)
-{
- char *retstring;
- size_t i;
-
- static const char table16[]="0123456789abcdef";
-
- retstring = malloc(BOUNDARY_LENGTH+1);
-
- if(!retstring)
- return NULL; /* failed */
-
- strcpy(retstring, "----------------------------");
- for(i=strlen(retstring); i<BOUNDARY_LENGTH; i++)
- retstring[i] = table16[Curl_rand()%16];
-
- /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
- combinations */
- retstring[BOUNDARY_LENGTH]=0; /* zero terminate */
-
- return retstring;
-}
-
-#endif /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */
+#endif /* !defined(CURL_DISABLE_HTTP) */