1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-21 23:58:49 -05:00

The initial HTTP request can now be sent in multiple parts, as part of the

regular transfer process. This required some new tweaks, like for example
we need to be able to tell the tranfer loop to not chunky-encode uploads
while we're transferring the rest of the request...
This commit is contained in:
Daniel Stenberg 2002-12-10 13:10:00 +00:00
parent b3c7cd61f3
commit db6ff224f8
3 changed files with 171 additions and 76 deletions

View File

@ -98,12 +98,65 @@
#include "memdebug.h" #include "memdebug.h"
#endif #endif
/* fread() emulation to provide POST and/or request data */
static int readmoredata(char *buffer,
size_t size,
size_t nitems,
void *userp)
{
struct connectdata *conn = (struct connectdata *)userp;
struct HTTP *http = conn->proto.http;
int fullsize = size * nitems;
if(0 == http->postsize)
/* nothing to return */
return 0;
/* make sure that a HTTP request is never sent away chunked! */
conn->bits.forbidchunk= (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
if(http->postsize <= fullsize) {
memcpy(buffer, http->postdata, http->postsize);
fullsize = http->postsize;
if(http->backup.postsize) {
/* move backup data into focus and continue on that */
http->postdata = http->backup.postdata;
http->postsize = http->backup.postsize;
conn->fread = http->backup.fread;
conn->fread_in = http->backup.fread_in;
http->sending++; /* move one step up */
http->backup.postsize=0;
}
else
http->postsize = 0;
return fullsize;
}
memcpy(buffer, http->postdata, fullsize);
http->postdata += fullsize;
http->postsize -= fullsize;
return fullsize;
}
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* /*
* The add_buffer series of functions are used to build one large memory chunk * The add_buffer series of functions are used to build one large memory chunk
* from repeated function invokes. Used so that the entire HTTP request can * from repeated function invokes. Used so that the entire HTTP request can
* be sent in one go. * be sent in one go.
*/ */
struct send_buffer {
char *buffer;
size_t size_max;
size_t size_used;
};
typedef struct send_buffer send_buffer;
static CURLcode static CURLcode
add_buffer(send_buffer *in, const void *inptr, size_t size); add_buffer(send_buffer *in, const void *inptr, size_t size);
@ -136,17 +189,17 @@ CURLcode add_buffer_send(send_buffer *in,
CURLcode res; CURLcode res;
char *ptr; char *ptr;
int size; int size;
struct HTTP *http = conn->proto.http;
/* The looping below is required since we use non-blocking sockets, but due /* The looping below is required since we use non-blocking sockets, but due
to the circumstances we will just loop and try again and again etc */ to the circumstances we will just loop and try again and again etc */
ptr = in->buffer; ptr = in->buffer;
size = in->size_used; size = in->size_used;
do {
res = Curl_write(conn, sockfd, ptr, size, &amount); res = Curl_write(conn, sockfd, ptr, size, &amount);
if(CURLE_OK != res) if(CURLE_OK == res) {
break;
if(conn->data->set.verbose) if(conn->data->set.verbose)
/* this data _may_ contain binary stuff */ /* this data _may_ contain binary stuff */
@ -155,14 +208,33 @@ CURLcode add_buffer_send(send_buffer *in,
*bytes_written += amount; *bytes_written += amount;
if(amount != size) { if(amount != size) {
/* The whole request could not be sent in one system call. We must queue
it up and send it later when we get the chance. We must not loop here
and wait until it might work again. */
size -= amount; size -= amount;
ptr += amount; ptr += amount;
/* backup the currently set pointers */
http->backup.fread = conn->fread;
http->backup.fread_in = conn->fread_in;
http->backup.postdata = http->postdata;
http->backup.postsize = http->postsize;
/* set the new pointers for the request-sending */
conn->fread = (curl_read_callback)readmoredata;
conn->fread_in = (void *)conn;
http->postdata = ptr;
http->postsize = size;
http->send_buffer = in;
http->sending = HTTPSEND_REQUEST;
return CURLE_OK;
} }
else
break;
} while(1);
/* the full buffer was sent, clean up and return */
}
if(in->buffer) if(in->buffer)
free(in->buffer); free(in->buffer);
free(in); free(in);
@ -519,6 +591,13 @@ CURLcode Curl_http_done(struct connectdata *conn)
conn->fread = data->set.fread; /* restore */ conn->fread = data->set.fread; /* restore */
conn->fread_in = data->set.in; /* restore */ conn->fread_in = data->set.in; /* restore */
if(http->send_buffer) {
send_buffer *buff = http->send_buffer;
free(buff->buffer);
free(buff);
}
if(HTTPREQ_POST_FORM == data->set.httpreq) { if(HTTPREQ_POST_FORM == data->set.httpreq) {
conn->bytecount = http->readbytecount + http->writebytecount; conn->bytecount = http->readbytecount + http->writebytecount;
@ -537,33 +616,6 @@ CURLcode Curl_http_done(struct connectdata *conn)
return CURLE_OK; return CURLE_OK;
} }
/* fread() emulation to provide POST data */
static int POSTReader(char *buffer,
size_t size,
size_t nitems,
void *userp)
{
struct HTTP *http = (struct HTTP *)userp;
int fullsize = size * nitems;
if(0 == http->postsize)
/* nothing to return */
return 0;
if(http->postsize <= fullsize) {
memcpy(buffer, http->postdata, http->postsize);
fullsize = http->postsize;
http->postsize = 0;
return fullsize;
}
memcpy(buffer, http->postdata, fullsize);
http->postdata += fullsize;
http->postsize -= fullsize;
return fullsize;
}
CURLcode Curl_http(struct connectdata *conn) CURLcode Curl_http(struct connectdata *conn)
{ {
struct SessionHandle *data=conn->data; struct SessionHandle *data=conn->data;
@ -957,6 +1009,8 @@ CURLcode Curl_http(struct connectdata *conn)
conn->fread = (curl_read_callback)Curl_FormReader; conn->fread = (curl_read_callback)Curl_FormReader;
conn->fread_in = &http->form; conn->fread_in = &http->form;
http->sending = HTTPSEND_BODY;
if(!conn->bits.upload_chunky) if(!conn->bits.upload_chunky)
/* only add Content-Length if not uploading chunked */ /* only add Content-Length if not uploading chunked */
add_bufferf(req_buffer, add_bufferf(req_buffer,
@ -1076,9 +1130,17 @@ CURLcode Curl_http(struct connectdata *conn)
http->postsize = strlen(data->set.postfields); http->postsize = strlen(data->set.postfields);
http->postdata = data->set.postfields; http->postdata = data->set.postfields;
conn->fread = (curl_read_callback)POSTReader; http->sending = HTTPSEND_BODY;
conn->fread_in = (void *)http;
conn->fread = (curl_read_callback)readmoredata;
conn->fread_in = (void *)conn;
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, http->postsize);
} }
else
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, data->set.infilesize);
/* issue the request, headers-only */ /* issue the request, headers-only */
result = add_buffer_send(req_buffer, conn->firstsocket, conn, result = add_buffer_send(req_buffer, conn->firstsocket, conn,
@ -1107,7 +1169,8 @@ CURLcode Curl_http(struct connectdata *conn)
/* HTTP GET/HEAD download: */ /* HTTP GET/HEAD download: */
result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
&http->readbytecount, &http->readbytecount,
-1, NULL); /* nothing to upload */ http->postdata?conn->firstsocket:-1,
http->postdata?&http->writebytecount:NULL);
} }
if(result) if(result)
return result; return result;

View File

@ -118,6 +118,51 @@ enum {
changed. It should just remain a blanked-out timeout value. */ changed. It should just remain a blanked-out timeout value. */
static struct timeval notimeout={0,0}; static struct timeval notimeout={0,0};
/*
* This function will call the read callback to fill our buffer with data
* to upload.
*/
static int fillbuffer(struct connectdata *conn,
int bytes)
{
int buffersize = bytes;
int nread;
if(conn->bits.upload_chunky) {
/* if chunked Transfer-Encoding */
buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */
conn->upload_fromhere += 10; /* 32bit hex + CRLF */
}
nread = conn->fread(conn->upload_fromhere, 1,
buffersize, conn->fread_in);
if(!conn->bits.forbidchunk && conn->bits.upload_chunky) {
/* if chunked Transfer-Encoding */
char hexbuffer[11];
int hexlen = snprintf(hexbuffer, sizeof(hexbuffer),
"%x\r\n", nread);
/* move buffer pointer */
conn->upload_fromhere -= hexlen;
nread += hexlen;
/* copy the prefix to the buffer */
memcpy(conn->upload_fromhere, hexbuffer, hexlen);
if(nread>hexlen) {
/* append CRLF to the data */
memcpy(conn->upload_fromhere +
nread, "\r\n", 2);
nread+=2;
}
else {
/* mark this as done once this chunk is transfered */
conn->keep.upload_done = TRUE;
}
}
return nread;
}
CURLcode Curl_readwrite(struct connectdata *conn, CURLcode Curl_readwrite(struct connectdata *conn,
bool *done) bool *done)
{ {
@ -862,44 +907,11 @@ CURLcode Curl_readwrite(struct connectdata *conn,
/* only read more data if there's no upload data already /* only read more data if there's no upload data already
present in the upload buffer */ present in the upload buffer */
if(0 == conn->upload_present) { if(0 == conn->upload_present) {
size_t buffersize = BUFSIZE;
/* init the "upload from here" pointer */ /* init the "upload from here" pointer */
conn->upload_fromhere = k->uploadbuf; conn->upload_fromhere = k->uploadbuf;
if(!k->upload_done) { if(!k->upload_done)
nread = fillbuffer(conn, BUFSIZE);
if(conn->bits.upload_chunky) {
/* if chunked Transfer-Encoding */
buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */
conn->upload_fromhere += 10; /* 32bit hex + CRLF */
}
nread = conn->fread(conn->upload_fromhere, 1,
buffersize, conn->fread_in);
if(conn->bits.upload_chunky) {
/* if chunked Transfer-Encoding */
char hexbuffer[9];
int hexlen = snprintf(hexbuffer, sizeof(hexbuffer),
"%x\r\n", nread);
/* move buffer pointer */
conn->upload_fromhere -= hexlen;
nread += hexlen;
/* copy the prefix to the buffer */
memcpy(conn->upload_fromhere, hexbuffer, hexlen);
if(nread>hexlen) {
/* append CRLF to the data */
memcpy(conn->upload_fromhere +
nread, "\r\n", 2);
nread+=2;
}
else {
/* mark this as done once this chunk is transfered */
k->upload_done = TRUE;
}
}
}
else else
nread = 0; /* we're done uploading/reading */ nread = 0; /* we're done uploading/reading */

View File

@ -157,6 +157,8 @@ struct ssl_config_data {
struct HTTP { struct HTTP {
struct FormData *sendit; struct FormData *sendit;
int postsize; int postsize;
char *postdata;
const char *p_pragma; /* Pragma: string */ const char *p_pragma; /* Pragma: string */
const char *p_accept; /* Accept: string */ const char *p_accept; /* Accept: string */
long readbytecount; long readbytecount;
@ -166,7 +168,22 @@ struct HTTP {
struct Form form; struct Form form;
struct Curl_chunker chunk; struct Curl_chunker chunk;
char *postdata; /* for regular POSTs */ struct back {
curl_read_callback fread; /* backup storage for fread pointer */
void *fread_in; /* backup storage for fread_in pointer */
char *postdata;
int postsize;
} backup;
enum {
HTTPSEND_NADA, /* init */
HTTPSEND_REQUEST, /* sending a request */
HTTPSEND_BODY, /* sending body */
HTTPSEND_LAST /* never use this */
} sending;
void *send_buffer; /* used if the request couldn't be sent in one chunk,
points to an allocated send_buffer struct */
}; };
/**************************************************************************** /****************************************************************************
@ -221,8 +238,11 @@ struct ConnectBits {
bool upload_chunky; /* set TRUE if we are doing chunked transfer-encoding bool upload_chunky; /* set TRUE if we are doing chunked transfer-encoding
on upload */ on upload */
bool getheader; /* TRUE if header parsing is wanted */ bool getheader; /* TRUE if header parsing is wanted */
bool forbidchunk; /* used only to explicitly forbid chunk-upload for
specific upload buffers. See readmoredata() in
http.c for details. */
}; };
/* /*