formadd: support >2GB files on windows

Closes #425
This commit is contained in:
Daniel Stenberg 2015-10-24 00:52:25 +02:00
parent 49a991346e
commit ca5f9341ef
7 changed files with 133 additions and 35 deletions

View File

@ -83,7 +83,18 @@ to send away. libcurl will use the pointer and refer to the data in your
application, so you must make sure it remains until curl no longer needs it.
If the data isn't NUL-terminated, or if you'd like it to contain zero bytes,
you must set its length with \fBCURLFORM_CONTENTSLENGTH\fP.
.IP CURLFORM_CONTENTLEN
followed by a curl_off_t value giving the length of the contents. Note that
for \fICURLFORM_STREAM\fP contents, this option is mandatory.
If you pass a 0 (zero) for this option, libcurl will instead do a strlen() on
the contents to figure out the size. If you really want to send a zero byte
content then you must make sure strlen() on the data pointer returns zero.
(Option added in 7.46.0)
.IP CURLFORM_CONTENTSLENGTH
(This option is deprecated. Use \fICURLFORM_CONTENTLEN\fP instead!)
followed by a long giving the length of the contents. Note that for
\fICURLFORM_STREAM\fP contents, this option is mandatory.

View File

@ -164,6 +164,7 @@ CURLFORM_BUFFER 7.9.8
CURLFORM_BUFFERLENGTH 7.9.8
CURLFORM_BUFFERPTR 7.9.8
CURLFORM_CONTENTHEADER 7.9.3
CURLFORM_CONTENTLEN 7.46.0
CURLFORM_CONTENTSLENGTH 7.9
CURLFORM_CONTENTTYPE 7.9
CURLFORM_COPYCONTENTS 7.9
@ -678,6 +679,7 @@ CURL_GLOBAL_DEFAULT 7.8
CURL_GLOBAL_NOTHING 7.8
CURL_GLOBAL_SSL 7.8
CURL_GLOBAL_WIN32 7.8.1
CURL_HTTPPOST_LARGE 7.46.0
CURL_HTTP_VERSION_1_0 7.9.1
CURL_HTTP_VERSION_1_1 7.9.1
CURL_HTTP_VERSION_2 7.43.0

View File

@ -127,7 +127,8 @@ struct curl_httppost {
char *name; /* pointer to allocated name */
long namelength; /* length of name length */
char *contents; /* pointer to allocated data contents */
long contentslength; /* length of contents field */
long contentslength; /* length of contents field, see also
CURL_HTTPPOST_LARGE */
char *buffer; /* pointer to allocated buffer contents */
long bufferlength; /* length of buffer field */
char *contenttype; /* Content-Type */
@ -152,12 +153,17 @@ struct curl_httppost {
/* upload file contents by using the regular read callback to get the data and
pass the given pointer as custom pointer */
#define CURL_HTTPPOST_CALLBACK (1<<6)
/* use size in 'contentlen', added in 7.46.0 */
#define CURL_HTTPPOST_LARGE (1<<7)
char *showfilename; /* The file name to show. If not set, the
actual file name will be used (if this
is a file part) */
void *userp; /* custom pointer used for
HTTPPOST_CALLBACK posts */
curl_off_t contentlen; /* alternative length of contents
field. Used if CURL_HTTPPOST_LARGE is
set. Added in 7.46.0 */
};
/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered
@ -1835,6 +1841,7 @@ typedef enum {
CFINIT(OBSOLETE2),
CFINIT(STREAM),
CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */
CURLFORM_LASTENTRY /* the last unused */
} CURLformoption;

View File

@ -77,7 +77,7 @@ static char *formboundary(struct SessionHandle *data);
***************************************************************************/
static struct curl_httppost *
AddHttpPost(char *name, size_t namelength,
char *value, size_t contentslength,
char *value, curl_off_t contentslength,
char *buffer, size_t bufferlength,
char *contenttype,
long flags,
@ -93,14 +93,14 @@ AddHttpPost(char *name, size_t namelength,
post->name = name;
post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
post->contents = value;
post->contentslength = (long)contentslength;
post->contentlen = contentslength;
post->buffer = buffer;
post->bufferlength = (long)bufferlength;
post->contenttype = contenttype;
post->contentheader = contentHeader;
post->showfilename = showfilename;
post->userp = userp,
post->flags = flags;
post->flags = flags | CURL_HTTPPOST_LARGE;
}
else
return NULL;
@ -380,11 +380,14 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
}
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);
current_form->contentslength =
array_state?(size_t)array_value:(size_t)va_arg(params, long);
break;
case CURLFORM_CONTENTLEN:
current_form->flags |= CURL_HTTPPOST_LARGE;
current_form->contentslength =
array_state?(curl_off_t)array_value:va_arg(params, curl_off_t);
break;
/* Get contents from a given file name */
@ -661,9 +664,12 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
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);
size_t clen = (size_t) form->contentslength;
if(!clen)
clen = strlen(form->value)+1;
form->value = Curl_memdup(form->value, clen);
if(!form->value) {
return_value = CURL_FORMADD_MEMORY;
break;
@ -816,7 +822,7 @@ static curl_off_t VmsSpecialSize(const char * name,
static CURLcode AddFormData(struct FormData **formp,
enum formtype type,
const void *line,
size_t length,
curl_off_t length,
curl_off_t *size)
{
struct FormData *newform = malloc(sizeof(struct FormData));
@ -1306,15 +1312,16 @@ CURLcode Curl_getformdata(struct SessionHandle *data,
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 */
/* 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);
post->flags&CURL_HTTPPOST_LARGE?
post->contentlen:post->contentslength, &size);
else
/* include the contents we got */
result = AddFormData(&form, FORM_CONTENT, post->contents,
post->contentslength, &size);
post->flags&CURL_HTTPPOST_LARGE?
post->contentlen:post->contentslength, &size);
file = file->more;
} while(file && !result); /* for each specified file for this field */

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2015, 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
@ -54,7 +54,7 @@ typedef struct FormInfo {
size_t namelength;
char *value;
bool value_alloc;
size_t contentslength;
curl_off_t contentslength;
char *contenttype;
bool contenttype_alloc;
long flags;

View File

@ -18,6 +18,22 @@ Content-Type: text/html
hello
</data>
<datacheck>
HTTP/1.1 200 OK
Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake swsclose
Connection: close
Content-Type: text/html
hello
HTTP/1.1 200 OK
Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake swsclose
Connection: close
Content-Type: text/html
hello
</datacheck>
</reply>
# Client-side
@ -78,6 +94,37 @@ send
Content-Disposition: form-data; name="somename"; filename="somefile.txt"
Content-Type: text/plain
blah blah
--------------------------------
POST /554 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
Content-Length: 732
Expect: 100-continue
Content-Type: multipart/form-data; boundary=----------------------------
------------------------------
Content-Disposition: form-data; name="sendfile alternative"; filename="file name 2"
this is what we post to the silly web server
------------------------------
Content-Disposition: form-data; name="callbackdata"
this is what we post to the silly web server
------------------------------
Content-Disposition: form-data; name="filename"
postit2.c
------------------------------
Content-Disposition: form-data; name="submit"
send
------------------------------
Content-Disposition: form-data; name="somename"; filename="somefile.txt"
Content-Type: text/plain
blah blah
--------------------------------
</protocol>

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2015, 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
@ -64,7 +64,7 @@ static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
#endif
}
int test(char *URL)
static int once(char *URL, bool oldstyle)
{
CURL *curl;
CURLcode res=CURLE_OK;
@ -75,22 +75,29 @@ int test(char *URL)
struct WriteThis pooh;
struct WriteThis pooh2;
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
fprintf(stderr, "curl_global_init() failed\n");
return TEST_ERR_MAJOR_BAD;
}
pooh.readptr = data;
pooh.sizeleft = strlen(data);
/* Fill in the file upload field */
formrc = curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "sendfile",
CURLFORM_STREAM, &pooh,
CURLFORM_CONTENTSLENGTH, (long)pooh.sizeleft,
CURLFORM_FILENAME, "postit2.c",
CURLFORM_END);
if(oldstyle) {
formrc = curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "sendfile",
CURLFORM_STREAM, &pooh,
CURLFORM_CONTENTSLENGTH, (long)pooh.sizeleft,
CURLFORM_FILENAME, "postit2.c",
CURLFORM_END);
}
else {
/* new style */
formrc = curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "sendfile alternative",
CURLFORM_STREAM, &pooh,
CURLFORM_CONTENTLEN, (curl_off_t)pooh.sizeleft,
CURLFORM_FILENAME, "file name 2",
CURLFORM_END);
}
if(formrc)
printf("curl_formadd(1) = %d\n", (int)formrc);
@ -190,10 +197,27 @@ test_cleanup:
/* always cleanup */
curl_easy_cleanup(curl);
curl_global_cleanup();
/* now cleanup the formpost chain */
curl_formfree(formpost);
return res;
}
int test(char *URL)
{
int res;
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
fprintf(stderr, "curl_global_init() failed\n");
return TEST_ERR_MAJOR_BAD;
}
res = once(URL, TRUE); /* old */
if(!res)
res = once(URL, FALSE); /* new */
curl_global_cleanup();
return res;
}