aboutsummaryrefslogtreecommitdiff
path: root/lib/http.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/http.c')
-rw-r--r--lib/http.c141
1 files changed, 102 insertions, 39 deletions
diff --git a/lib/http.c b/lib/http.c
index f9f0a819b..49ba70f36 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -98,12 +98,65 @@
#include "memdebug.h"
#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
* from repeated function invokes. Used so that the entire HTTP request can
* 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
add_buffer(send_buffer *in, const void *inptr, size_t size);
@@ -136,33 +189,52 @@ CURLcode add_buffer_send(send_buffer *in,
CURLcode res;
char *ptr;
int size;
+ struct HTTP *http = conn->proto.http;
/* 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 */
ptr = in->buffer;
size = in->size_used;
- do {
- res = Curl_write(conn, sockfd, ptr, size, &amount);
- if(CURLE_OK != res)
- break;
+ res = Curl_write(conn, sockfd, ptr, size, &amount);
+
+ if(CURLE_OK == res) {
if(conn->data->set.verbose)
/* this data _may_ contain binary stuff */
Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, amount);
*bytes_written += amount;
-
+
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;
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)
free(in->buffer);
free(in);
@@ -519,6 +591,13 @@ CURLcode Curl_http_done(struct connectdata *conn)
conn->fread = data->set.fread; /* 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) {
conn->bytecount = http->readbytecount + http->writebytecount;
@@ -537,33 +616,6 @@ CURLcode Curl_http_done(struct connectdata *conn)
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)
{
struct SessionHandle *data=conn->data;
@@ -957,6 +1009,8 @@ CURLcode Curl_http(struct connectdata *conn)
conn->fread = (curl_read_callback)Curl_FormReader;
conn->fread_in = &http->form;
+ http->sending = HTTPSEND_BODY;
+
if(!conn->bits.upload_chunky)
/* only add Content-Length if not uploading chunked */
add_bufferf(req_buffer,
@@ -1076,9 +1130,17 @@ CURLcode Curl_http(struct connectdata *conn)
http->postsize = strlen(data->set.postfields);
http->postdata = data->set.postfields;
- conn->fread = (curl_read_callback)POSTReader;
- conn->fread_in = (void *)http;
+ http->sending = HTTPSEND_BODY;
+
+ 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 */
result = add_buffer_send(req_buffer, conn->firstsocket, conn,
@@ -1107,7 +1169,8 @@ CURLcode Curl_http(struct connectdata *conn)
/* HTTP GET/HEAD download: */
result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
&http->readbytecount,
- -1, NULL); /* nothing to upload */
+ http->postdata?conn->firstsocket:-1,
+ http->postdata?&http->writebytecount:NULL);
}
if(result)
return result;