Georg Huettenegger's patch curl-7.8.1-pre5-patch-20010819

This commit is contained in:
Daniel Stenberg 2001-08-21 13:18:07 +00:00
parent 3e5dbac7a2
commit 08655d8d5d
18 changed files with 701 additions and 28 deletions

View File

@ -13,6 +13,7 @@ man_MANS = \
curl_easy_perform.3 \
curl_easy_setopt.3 \
curl_formparse.3 \
curl_formadd.3 \
curl_formfree.3 \
curl_getdate.3 \
curl_getenv.3 \
@ -38,6 +39,7 @@ HTMLPAGES = \
curl_easy_init.html \
curl_easy_perform.html \
curl_easy_setopt.html \
curl_formadd.html \
curl_formparse.html \
curl_formfree.html \
curl_getdate.html \
@ -56,7 +58,7 @@ HTMLPAGES = \
EXTRA_DIST = $(man_MANS) \
MANUAL BUGS CONTRIBUTE FAQ FEATURES INTERNALS \
LIBCURL README.win32 RESOURCES TODO TheArtOfHttpScripting THANKS \
README.win32 RESOURCES TODO TheArtOfHttpScripting THANKS \
$(HTMLPAGES)
MAN2HTML= gnroff -man $< | man2html >$@

View File

@ -275,7 +275,7 @@ instruct what data to pass on to the server. Pass a pointer to a linked list
of HTTP post structs as parameter. The linked list should be a fully valid
list of 'struct HttpPost' structs properly filled in. The best and most
elegant way to do this, is to use
.I curl_formparse(3)
.I curl_formadd(3)
as documented. The data in this list must remained intact until you close this
curl handle again with curl_easy_cleanup().
.TP

114
docs/curl_formadd.3 Normal file
View File

@ -0,0 +1,114 @@
.\" You can view this file with:
.\" nroff -man [file]
.\" $Id$
.\"
.TH curl_formadd 3 "19 August 2001" "libcurl 7.9" "libcurl Manual"
.SH NAME
curl_formadd - add a section to a multipart/formdata HTTP POST
.SH SYNOPSIS
.B #include <curl/curl.h>
.sp
.BI "CURLcode curl_formadd(struct HttpPost ** " firstitem,
.BI "struct HttpPost ** " lastitem, " ...);"
.ad
.SH DESCRIPTION
curl_formadd() is used to append sections when building a multipart/formdata
HTTP POST (sometimes refered to as rfc1867-style posts). Append one section at
a time until you've added all the sections you want included and then you pass
the \fIfirstitem\fP pointer as parameter to \fBCURLOPT_HTTPPOST\fP.
\fIlastitem\fP is set after each call and on repeated invokes it should be
left as set to allow repeated invokes to find the end of the list in a faster
way.
After \fIlastitem\fP follow the real arguments that constitute the
new section (if the following description confuses you jump directly
to the examples):
The first is always CURLFORM_COPYNAME followed by a string used for
the name of the section.
Afterwards one may use one of three arguments: CURLFORM_COPYCONTENTS,
CURLFORM_PTRCONTENTS, or CURLFORM_FILE. followed by a char or void
pointer (allowed for PTRCONTENTS).
The next argument may be CURLFORM_CONTENTTYPE if the
user wishes to specify one (for FILE if no type is given the library
tries to provide the correct one; for CONTENTS no Content-Type is sent
in this case)
For CURLFORM_PTRCONTENTS the user may also add CURLFORM_CONTENTSLENGTH
followed by the length as a long (if not given the library will use
strlen to determine the length; for COPYCONTENTS this is always done).
For CURLFORM_FILE the user may send multiple files in one section by
providing multiple CURLFORM_FILE arguments each followed by the filename
(and each FILE is allowed to have a CONTENTTYPE).
The last argument always is CURLFORM_END.
The pointers \fI*firstitem\fP and \fI*lastitem\fP should both be pointing to
NULL in the first call to this function. All list-data will be allocated by
the function itself. You must call \fIcurl_formfree\fP after the form post has
been done to free the resources again.
This function will copy all input data except the data pointed to by
the argument after CURLFORM_PTRCONTENTS and keep its own
version of it allocated until you call \fIcurl_formfree\fP. When
you've passed the pointer to \fIcurl_easy_setopt\fP, you must not free
the list until after you've called \fIcurl_easy_cleanup\fP for the
curl handle. If you provide a pointer as an argument after
CURLFORM_PTRCONTENTS you must ensure that the pointer stays valid
until you call \fIcurl_form_free\fP and \fIcurl_easy_cleanup\fP.
See example below.
.SH RETURN VALUE
Returns non-zero if an error occurs.
.SH EXAMPLE
.nf
HttpPost* post = NULL;
HttpPost* last = NULL;
char buffer[] = "test buffer";
char htmlbuffer[] = "<HTML>test buffer</HTML>";
long htmlbufferlength = strlen(htmlbuffer);
/* add null character into htmlbuffer, to demonstrate that
transfers of buffers containing null characters actually work
*/
htmlbuffer[8] = '\\0';
/* Add simple name/content section */
curl_formadd(&post, &last, CURLFORM_COPYNAME, "name",
CURLFORM_COPYCONTENTS, "content", CURLFORM_END);
/* Add simple name/content/contenttype section */
curl_formadd(&post, &last, CURLFORM_COPYNAME, "htmlcode",
CURLFORM_COPYCONTENTS, "<HTML></HTML>",
CURLFORM_CONTENTTYPE, "text/html", CURLFORM_END);
/* Add name/ptrcontent section */
curl_formadd(&post, &past, CURLFORM_COPYNAME, "name_for_ptrcontent",
CURLFORM_PTRCONTENTS, buffer, CURLFORM_END);
/* Add name/ptrcontent/contenttype section */
curl_formadd(&post, &last, CURLFORM_COPYNAME, "html_code_with_hole",
CURLFORM_PTRCONTENTS, htmlbuffer,
CURLFORM_CONTENTSLENGTH, htmlbufferlength,
CURLFORM_CONTENTTYPE, "text/html", CURLFORM_END);
/* Add simple file section */
curl_formadd(&post, &last, CURLFORM_COPYNAME, "picture",
CURLFORM_FILE, "my-face.jpg", CURLFORM_END);
/* Add file/contenttype section */
curl_formadd(&post, &last, CURLFORM_COPYNAME, "picture",
CURLFORM_FILE, "my-face.jpg",
CURLFORM_CONTENTTYPE, "image/jpeg", CURLFORM_END);
/* Add two file section */
curl_formadd(&post, &last, CURLFORM_COPYNAME, "pictures",
CURLFORM_FILE, "my-face.jpg",
CURLFORM_FILE, "your-face.jpg", CURLFORM_END);
/* Set the form info */
curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
.SH "SEE ALSO"
.BR curl_easy_setopt "(3), "
.BR curl_formparse "(3) [deprecated], "
.BR curl_formfree "(3)
.SH BUGS
Surely there are some, you tell me!

View File

@ -12,12 +12,14 @@ curl_formfree - free a previously build multipart/formdata HTTP POST chain
.ad
.SH DESCRIPTION
curl_formfree() is used to clean up data previously built/appended with
curl_formparse(). This must be called when the data has been used, which
typically means after the curl_easy_perform() has been called.
curl_formadd()/curl_formparse(). This must be called when the data has
been used, which typically means after the curl_easy_perform() has
been called.
.SH RETURN VALUE
None
.SH "SEE ALSO"
.BR curl_formparse "(3) "
.BR curl_formparse "(3) [deprecated], "
.BR curl_formadd "(3) "
.SH BUGS
libcurl 7.7.1 and earlier versions does not allow a NULL pointer to be used as
argument.

View File

@ -4,7 +4,8 @@
.\"
.TH curl_formparse 3 "21 May 2001" "libcurl 7.7.4" "libcurl Manual"
.SH NAME
curl_formparse - add a section to a multipart/formdata HTTP POST
curl_formparse - add a section to a multipart/formdata HTTP POST:
deprecated (use curl_formadd instead)
.SH SYNOPSIS
.B #include <curl/curl.h>
.sp
@ -79,6 +80,7 @@ Returns non-zero if an error occurs.
.SH "SEE ALSO"
.BR curl_easy_setopt "(3), "
.BR curl_formadd "(3), "
.BR curl_formfree "(3)
.SH BUGS
Surely there are some, you tell me!

View File

@ -8,7 +8,7 @@ curl_slist_append - add a string to an slist
.SH SYNOPSIS
.B #include <curl/curl.h>
.sp
.BI "struct curl_slist *curl_slist_append(struct curl_slit *" list,
.BI "struct curl_slist *curl_slist_append(struct curl_slist *" list,
.BI "const char * "string ");"
.ad
.SH DESCRIPTION

View File

@ -4,7 +4,7 @@
AUTOMAKE_OPTIONS = foreign no-dependencies
EXTRA_DIST = README curlgtk.c sepheaders.c simple.c postit.c \
EXTRA_DIST = README curlgtk.c sepheaders.c simple.c postit.c postit2.c \
win32sockets.c persistant.c ftpget.c Makefile.example \
multithread.c getinmemory.c

View File

@ -53,11 +53,14 @@ portable environment variable reader
.B curl_easy_getinfo()
get information about a performed transfer
.TP
.B curl_formparse()
.B curl_formadd()
helps building a HTTP form POST
.TP
.B curl_formparse()
helps building a HTTP form POST (deprecated since 7.9 use curl_formadd()!)
.TP
.B curl_formfree()
free a list built with curl_formparse()
free a list built with curl_formparse()/curl_formadd()
.TP
.B curl_slist_append()
builds a linked list

View File

@ -59,12 +59,15 @@ struct HttpPost {
struct HttpPost *next; /* next entry in the list */
char *name; /* pointer to allocated name */
char *contents; /* pointer to allocated data contents */
long contentslength; /* length of contents field */
char *contenttype; /* Content-Type */
struct HttpPost *more; /* if one field name has more than one file, this
link should link to following files */
long flags; /* as defined below */
#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */
#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */
#define HTTPPOST_PTRCONTENTS (1<<2) /* contents is only stored pointer
do not free in formfree */
};
typedef int (*curl_progress_callback)(void *clientp,
@ -483,6 +486,32 @@ int curl_formparse(char *string,
struct HttpPost **httppost,
struct HttpPost **last_post);
/* name is uppercase CURLFORM_<name> */
#ifdef CFINIT
#undef CFINIT
#endif
#define CFINIT(name) CURLFORM_ ## name
typedef enum {
CFINIT(NOTHING), /********* the first one is unused ************/
/* */
CFINIT(COPYNAME),
CFINIT(COPYCONTENTS),
CFINIT(PTRCONTENTS),
CFINIT(CONTENTSLENGTH),
CFINIT(FILE),
CFINIT(CONTENTTYPE),
CFINIT(END),
CURLFORM_LASTENTRY /* the last unusued */
} CURLformoption;
/* new external form function */
int curl_formadd(struct HttpPost **httppost,
struct HttpPost **last_post,
...);
/* cleanup a form: */
void curl_formfree(struct HttpPost *form);
@ -495,8 +524,8 @@ char *curl_version(void);
/* Escape and unescape URL encoding in strings. The functions return a new
* allocated string or NULL if an error occurred. */
char *curl_escape(char *string, int length);
char *curl_unescape(char *string, int length);
char *curl_escape(const char *string, int length);
char *curl_unescape(const char *string, int length);
/* curl_global_init() should be invoked exactly once for each application that
uses libcurl */
@ -507,8 +536,8 @@ CURLcode curl_global_init(long flags);
void curl_global_cleanup(void);
/* This is the version number */
#define LIBCURL_VERSION "7.8.1"
#define LIBCURL_VERSION_NUM 0x070801
#define LIBCURL_VERSION "7.8.2-pre1"
#define LIBCURL_VERSION_NUM 0x070802
/* linked-list structure for the CURLOPT_QUOTE option (and other) */
struct curl_slist {

View File

@ -37,7 +37,7 @@
#include "memdebug.h"
#endif
char *curl_escape(char *string, int length)
char *curl_escape(const char *string, int length)
{
int alloc = (length?length:(int)strlen(string))+1;
char *ns = malloc(alloc);
@ -75,7 +75,7 @@ char *curl_escape(char *string, int length)
return ns;
}
char *curl_unescape(char *string, int length)
char *curl_unescape(const char *string, int length)
{
int alloc = (length?length:(int)strlen(string))+1;
char *ns = malloc(alloc);

View File

@ -26,7 +26,7 @@
/* Escape and unescape URL encoding in strings. The functions return a new
* allocated string or NULL if an error occurred. */
char *curl_escape(char *string, int length);
char *curl_unescape(char *string, int length);
char *curl_escape(const char *string, int length);
char *curl_unescape(const char *string, int length);
#endif

View File

@ -24,7 +24,46 @@
/*
Debug the form generator stand-alone by compiling this source file with:
gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -o formdata -I../include formdata.c
gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -o formdata -I../include formdata.c strequal.c
run the 'formdata' executable the output should end with:
All Tests seem to have worked ...
and the following parts should be there:
Content-Disposition: form-data; name="simple_COPYCONTENTS"
value for simple COPYCONTENTS
Content-Disposition: form-data; name="COPYCONTENTS_+_CONTENTTYPE"
Content-Type: image/gif
value for COPYCONTENTS + CONTENTTYPE
Content-Disposition: form-data; name="simple_PTRCONTENTS"
value for simple PTRCONTENTS
Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH"
vlue for PTRCONTENTS + CONTENTSLENGTH
(or you might see v^@lue at the start)
Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE"
Content-Type: text/plain
vlue for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE
Content-Disposition: form-data; name="FILE1_+_CONTENTTYPE"; filename="inet_ntoa_r.h"
Content-Type: text/html
...
Content-Disposition: form-data; name="FILE1_+_FILE2"
Content-Type: multipart/mixed, boundary=curlz1s0dkticx49MV1KGcYP5cvfSsz
Content-Disposition: attachment; filename="inet_ntoa_r.h"
Content-Type: text/plain
...
Content-Disposition: attachment; filename="Makefile.b32.resp"
Content-Type: text/plain
...
For the old FormParse used by curl_formparse use:
gcc -DHAVE_CONFIG_H -I../ -g -D_OLD_FORM_DEBUG -o formdata -I../include formdata.c strequal.c
run the 'formdata' executable and make sure the output is ok!
@ -64,7 +103,7 @@
/* This is a silly duplicate of the function in main.c to enable this source
to compile stand-alone for better debugging */
static void GetStr(char **string,
char *value)
const char *value)
{
if(*string)
free(*string);
@ -227,6 +266,7 @@ int FormParse(char *input,
memset(post, 0, sizeof(struct HttpPost));
GetStr(&post->name, name); /* get the name */
GetStr(&post->contents, contp); /* get the contents */
post->contentslength = 0;
post->flags = flags;
if(type) {
GetStr(&post->contenttype, (char *)type); /* get type */
@ -250,6 +290,7 @@ int FormParse(char *input,
memset(subpost, 0, sizeof(struct HttpPost));
GetStr(&subpost->name, name); /* get the name */
GetStr(&subpost->contents, contp); /* get the contents */
subpost->contentslength = 0;
subpost->flags = flags;
if(type) {
GetStr(&subpost->contenttype, (char *)type); /* get type */
@ -272,10 +313,12 @@ int FormParse(char *input,
GetStr(&post->name, name); /* get the name */
if( contp[0]=='<' ) {
GetStr(&post->contents, contp+1); /* get the contents */
post->contentslength = 0;
post->flags = HTTPPOST_READFILE;
}
else {
GetStr(&post->contents, contp); /* get the contents */
post->contentslength = 0;
post->flags = 0;
}
@ -307,6 +350,264 @@ int curl_formparse(char *input,
return FormParse(input, httppost, last_post);
}
/***************************************************************************
*
* 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 0 on success and 1 if malloc failed.
*
***************************************************************************/
static struct HttpPost * AddHttpPost (char * name,
char * value,
long contentslength,
long flags,
struct HttpPost *parent_post,
struct HttpPost **httppost,
struct HttpPost **last_post)
{
struct HttpPost *post;
post = (struct HttpPost *)malloc(sizeof(struct HttpPost));
if(post) {
memset(post, 0, sizeof(struct HttpPost));
post->name = name;
post->contents = value;
post->contentslength = contentslength;
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;
}
/***************************************************************************
*
* FormAdd()
*
* Stores a 'name=value' 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");
*
* name/value pair where only the content pointer is remembered:
* curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
* CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10);
* (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 0 on success, 1 if the first option is not CURLFORM_COPYNAME,
* 2 if AddHttpPost failes, and 3 if an unknown option is encountered
*
***************************************************************************/
static
int FormAdd(struct HttpPost **httppost,
struct HttpPost **last_post,
va_list params)
{
int go_on = TRUE;
int read_argument = TRUE;
unsigned int i;
char *name;
char *value;
const char *prevtype = NULL;
struct HttpPost *post = NULL;
CURLformoption next_option;
/* We always expect CURLFORM_COPYNAME first for the moment. */
next_option = va_arg(params, CURLformoption);
if (next_option != CURLFORM_COPYNAME)
return 1;
name = va_arg(params, char *);
do
{
/* if not already read read next argument */
if (read_argument)
next_option = va_arg(params, CURLformoption);
else
read_argument = TRUE;
switch (next_option)
{
case CURLFORM_COPYCONTENTS:
{ /* simple name/value storage of duplicated data */
const char * contenttype = NULL;
value = va_arg(params, char *);
next_option = va_arg(params, CURLformoption);
if (next_option == CURLFORM_CONTENTTYPE)
contenttype = va_arg(params, char *);
else
read_argument = FALSE;
if ((post = AddHttpPost(strdup(name), strdup(value), 0, 0, NULL,
httppost, last_post)) == NULL) {
return 2;
}
if (contenttype)
post->contenttype = strdup(contenttype);
/* at the moment no more options are allowd in this case */
go_on = FALSE;
break;
}
case CURLFORM_PTRCONTENTS:
{ /* name/value storage with value stored as a pointer */
const char * contenttype = NULL;
void * ptr_contents = va_arg(params, void *);
long contentslength;
int got_contentslength = FALSE;
/* either use provided length or use strlen () to get it */
next_option = va_arg(params, CURLformoption);
while ( (next_option == CURLFORM_CONTENTSLENGTH) ||
(next_option == CURLFORM_CONTENTTYPE) ) {
if (next_option == CURLFORM_CONTENTSLENGTH) {
contentslength = va_arg(params, long);
got_contentslength = TRUE;
}
else { /* CURLFORM_CONTENTTYPE */
contenttype = va_arg(params, char *);
}
next_option = va_arg(params, CURLformoption);
};
/* we already read the next CURLformoption */
read_argument = FALSE;
if (!got_contentslength)
/* no length given, use strlen to find out */
contentslength = strlen (ptr_contents);
if ((post = AddHttpPost(strdup(name), ptr_contents, contentslength,
HTTPPOST_PTRCONTENTS, NULL, httppost,
last_post))
== NULL) {
return 2;
}
if (contenttype)
post->contenttype = strdup(contenttype);
/* at the moment no more options are allowd in this case */
go_on = FALSE;
break;
}
case CURLFORM_FILE:
{
const char * contenttype = NULL;
value = va_arg(params, char *);
next_option = va_arg(params, CURLformoption);
/* if contenttype was provided retrieve it */
if (next_option == CURLFORM_CONTENTTYPE) {
contenttype = va_arg(params, char *);
}
else {
/*
* 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 struct ContentType ctts[]={
{".gif", "image/gif"},
{".jpg", "image/jpeg"},
{".jpeg", "image/jpeg"},
{".txt", "text/plain"},
{".html", "text/plain"}
};
if(prevtype)
/* default to the previously set/used! */
contenttype = prevtype;
else
/* It seems RFC1867 defines no Content-Type to default to
text/plain so we don't actually need to set this: */
contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
if(strlen(value) >= strlen(ctts[i].extension)) {
if(strequal(value +
strlen(value) - strlen(ctts[i].extension),
ctts[i].extension)) {
contenttype = ctts[i].type;
break;
}
}
}
/* we have a contenttype by now */
/* do not try to read the next option we already did that */
read_argument = FALSE;
}
if ( (post = AddHttpPost (strdup(name), strdup(value), 0,
HTTPPOST_FILENAME, post, httppost,
last_post)) == NULL) {
return 2;
}
post->contenttype = strdup (contenttype);
prevtype = post->contenttype;
/* we do not set go_on to false as multiple files are allowed */
break;
}
case CURLFORM_END:
/* this ends our loop */
break;
default:
fprintf (stderr, "got: %d\n", next_option);
return 3;
};
} while (go_on && next_option != CURLFORM_END);
return 0;
}
int curl_formadd(struct HttpPost **httppost,
struct HttpPost **last_post,
...)
{
va_list arg;
int result;
va_start(arg, last_post);
result = FormAdd(httppost, last_post, arg);
va_end(arg);
return result;
}
static int AddFormData(struct FormData **formp,
const void *line,
long length)
@ -406,7 +707,7 @@ void curl_formfree(struct HttpPost *form)
if(form->name)
free(form->name); /* free the name */
if(form->contents)
if( !(form->flags & HTTPPOST_PTRCONTENTS) && form->contents)
free(form->contents); /* free the contents */
if(form->contenttype)
free(form->contenttype); /* free the content type */
@ -525,7 +826,7 @@ struct FormData *Curl_getFormData(struct HttpPost *post,
}
} else {
/* include the contents we got */
size += AddFormData(&form, post->contents, 0);
size += AddFormData(&form, post->contents, post->contentslength);
}
} while((file = file->more)); /* for each specified file for this field */
@ -568,6 +869,52 @@ int Curl_FormReader(char *buffer,
size_t size,
size_t nitems,
FILE *mydata)
{
struct Form *form;
int wantedsize;
int gotsize = 0;
form=(struct Form *)mydata;
wantedsize = size * nitems;
if(!form->data)
return -1; /* nothing, error, empty */
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);
/* 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.
This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
return gotsize;
}
/* possible (old) fread() emulation that copies at most one line */
int Curl_FormReadOneLine(char *buffer,
size_t size,
size_t nitems,
FILE *mydata)
{
struct Form *form;
int wantedsize;
@ -609,6 +956,118 @@ int Curl_FormReader(char *buffer,
#ifdef _FORM_DEBUG
int FormAddTest(const char * errormsg,
struct HttpPost **httppost,
struct HttpPost **last_post,
...)
{
int result;
va_list arg;
CURLformoption next_option;
char * value;
va_start(arg, last_post);
if ((result = FormAdd(httppost, last_post, arg)))
fprintf (stderr, "ERROR doing FormAdd ret: %d action: %s\n", result,
errormsg);
va_end(arg);
return result;
}
int main()
{
char name1[] = "simple_COPYCONTENTS";
char name2[] = "COPYCONTENTS_+_CONTENTTYPE";
char name3[] = "simple_PTRCONTENTS";
char name4[] = "PTRCONTENTS_+_CONTENTSLENGTH";
char name5[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE";
char name6[] = "FILE1_+_CONTENTTYPE";
char name7[] = "FILE1_+_FILE2";
char value1[] = "value for simple COPYCONTENTS";
char value2[] = "value for COPYCONTENTS + CONTENTTYPE";
char value3[] = "value for simple PTRCONTENTS";
char value4[] = "value for PTRCONTENTS + CONTENTSLENGTH";
char value5[] = "value for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE";
char value6[] = "inet_ntoa_r.h";
char value7[] = "Makefile.b32.resp";
char type2[] = "image/gif";
char type5[] = "text/plain";
char type6[] = "text/html";
int value4length = strlen(value4);
int value5length = strlen(value5);
int errors = 0;
int size;
int nread;
char buffer[4096];
struct HttpPost *httppost=NULL;
struct HttpPost *last_post=NULL;
struct HttpPost *post;
struct FormData *form;
struct Form formread;
if (FormAddTest("simple COPYCONTENTS test", &httppost, &last_post,
CURLFORM_COPYNAME, name1, CURLFORM_COPYCONTENTS, value1,
CURLFORM_END))
++errors;
if (FormAddTest("COPYCONTENTS + CONTENTTYPE test", &httppost, &last_post,
CURLFORM_COPYNAME, name2, CURLFORM_COPYCONTENTS, value2,
CURLFORM_CONTENTTYPE, type2, CURLFORM_END))
++errors;
if (FormAddTest("simple PTRCONTENTS test", &httppost, &last_post,
CURLFORM_COPYNAME, name3, CURLFORM_PTRCONTENTS, value3,
CURLFORM_END))
++errors;
/* make null character at start to check that contentslength works
correctly */
value4[1] = '\0';
if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost, &last_post,
CURLFORM_COPYNAME, name4, CURLFORM_PTRCONTENTS, value4,
CURLFORM_CONTENTSLENGTH, value4length, CURLFORM_END))
++errors;
/* make null character at start to check that contentslength works
correctly */
value5[1] = '\0';
if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test",
&httppost, &last_post,
CURLFORM_COPYNAME, name5, CURLFORM_PTRCONTENTS, value5,
CURLFORM_CONTENTSLENGTH, value5length,
CURLFORM_CONTENTTYPE, type5, CURLFORM_END))
++errors;
if (FormAddTest("FILE + CONTENTTYPE test", &httppost, &last_post,
CURLFORM_COPYNAME, name6, CURLFORM_FILE, value6,
CURLFORM_CONTENTTYPE, type6, CURLFORM_END))
++errors;
if (FormAddTest("FILE1 + FILE2 test", &httppost, &last_post,
CURLFORM_COPYNAME, name7, CURLFORM_FILE, value6,
CURLFORM_FILE, value7, CURLFORM_END))
++errors;
form=Curl_getFormData(httppost, &size);
Curl_FormInit(&formread, form);
do {
nread = Curl_FormReader(buffer, 1, sizeof(buffer),
(FILE *)&formread);
if(-1 == nread)
break;
fwrite(buffer, nread, 1, stderr);
} while(1);
fprintf(stderr, "size: %d\n", size);
if (errors)
fprintf(stderr, "\n==> %d Test(s) failed!\n", errors);
else
fprintf(stdout, "\nAll Tests seem to have worked (please check output)\n");
return 0;
}
#endif
#ifdef _OLD_FORM_DEBUG
int main(int argc, char **argv)
{

View File

@ -47,8 +47,15 @@ int Curl_FormReader(char *buffer,
size_t nitems,
FILE *mydata);
/* possible (old) fread() emulation that copies at most one line */
int Curl_FormReadOneLine(char *buffer,
size_t size,
size_t nitems,
FILE *mydata);
char *Curl_FormBoundary(void);
void Curl_formclean(struct FormData *);
#endif

View File

@ -703,6 +703,8 @@ CURLcode Curl_http(struct connectdata *conn)
}
if(HTTPREQ_POST_FORM == data->httpreq) {
char contentType[256];
int linelength=0;
if(Curl_FormInit(&http->form, http->sendit)) {
failf(data, "Internal HTTP POST error!\n");
return CURLE_HTTP_POST_ERROR;
@ -719,15 +721,40 @@ CURLcode Curl_http(struct connectdata *conn)
add_bufferf(req_buffer,
"Content-Length: %d\r\n", http->postsize-2);
if(!checkheaders(data, "Expect:")) {
/* if not disabled explicitly we add a Expect: 100-continue
to the headers which actually speeds up post operations (as
there is one packet coming back from the web server) */
add_bufferf(req_buffer,
"Expect: 100-continue\r\n");
data->bits.expect100header = TRUE;
/* Get Content-Type: line from Curl_FormReadOneLine, which happens
to always be the first line. We can know this for sure since
we always build the formpost linked list the same way! */
linelength = Curl_FormReadOneLine (contentType,
sizeof(contentType),
1,
(FILE *)&http->form);
if(linelength == -1) {
failf(data, "Could not get Content-Type header line!\n");
return CURLE_HTTP_POST_ERROR;
}
add_buffer(req_buffer, contentType, linelength);
}
/* set upload size to the progress meter */
Curl_pgrsSetUploadSize(data, http->postsize);
/* fire away the whole request to the server */
data->request_size =
add_buffer_send(conn->firstsocket, conn, req_buffer);
/* setup variables for the upcoming transfer */
result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
&http->readbytecount,
conn->firstsocket,
&http->writebytecount);
&http->readbytecount,
conn->firstsocket,
&http->writebytecount);
if(result) {
Curl_formclean(http->sendit); /* free that whole lot */
return result;

View File

@ -197,6 +197,9 @@ Transfer(struct connectdata *c_conn)
Content-Range: header */
int httpcode = 0; /* error code from the 'HTTP/1.? XXX' line */
int httpversion = -1; /* the HTTP version*10 */
bool write_after_100_header = FALSE; /* should we enable the write after
we received a 100-continue/timeout
or directly */
/* for the low speed checks: */
CURLcode urg;
@ -263,8 +266,13 @@ Transfer(struct connectdata *c_conn)
FD_ZERO (&writefd); /* clear it */
if(conn->writesockfd != -1) {
FD_SET (conn->writesockfd, &writefd); /* write socket */
keepon |= KEEP_WRITE;
if (data->bits.expect100header)
/* wait with write until we either got 100-continue or a timeout */
write_after_100_header = TRUE;
else {
FD_SET (conn->writesockfd, &writefd); /* write socket */
keepon |= KEEP_WRITE;
}
}
/* get these in backup variables to be able to restore them on each lap in
@ -290,6 +298,12 @@ Transfer(struct connectdata *c_conn)
keepon = 0; /* no more read or write */
continue;
case 0: /* timeout */
if (write_after_100_header) {
write_after_100_header = FALSE;
FD_SET (conn->writesockfd, &writefd); /* write socket */
keepon |= KEEP_WRITE;
wkeepfd = writefd;
}
break;
default:
if((keepon & KEEP_READ) && FD_ISSET(conn->sockfd, &readfd)) {
@ -408,6 +422,13 @@ Transfer(struct connectdata *c_conn)
*/
header = TRUE;
headerline = 0; /* we restart the header line counter */
/* if we did wait for this do enable write now! */
if (write_after_100_header) {
write_after_100_header = FALSE;
FD_SET (conn->writesockfd, &writefd); /* write socket */
keepon |= KEEP_WRITE;
wkeepfd = writefd;
}
}
else
header = FALSE; /* no more header to parse! */

View File

@ -413,6 +413,8 @@ struct Configbits {
after use */
bool reuse_fresh; /* do not re-use an existing connection for this
transfer */
bool expect100header; /* TRUE if we added Expect: 100-continue to the
HTTP header */
};
/*

View File

@ -1,3 +1,3 @@
#define CURL_NAME "curl"
#define CURL_VERSION "7.8.1"
#define CURL_VERSION "7.8.2-pre1"
#define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") "

View File

@ -741,6 +741,11 @@ do {
# verbose output
$verbose=1;
}
elsif ($ARGV[0] eq "-c") {
# use this path to curl instead of default
$CURL=$ARGV[1];
shift @ARGV;
}
elsif ($ARGV[0] eq "-d") {
# have the servers display protocol output
$debugprotocol=1;