Curl_client_write() & al.: chop long data, convert data only once.

This commit is contained in:
Patrick Monnerat
2014-12-09 15:43:51 +01:00
parent e63d18fbd1
commit 6ea4ee94f9
3 changed files with 102 additions and 133 deletions

View File

@@ -1026,73 +1026,15 @@ CURLcode curl_easy_pause(CURL *curl, int action)
/* we have a buffer for sending that we now seem to be able to deliver
since the receive pausing is lifted! */
/* get the pointer, type and length in local copies since the function may
return PAUSE again and then we'll get a new copy allocted and stored in
/* get the pointer in local copy since the function may return PAUSE
again and then we'll get a new copy allocted and stored in
the tempwrite variables */
char *tempwrite = data->state.tempwrite;
char *freewrite = tempwrite; /* store this pointer to free it later */
size_t tempsize = data->state.tempwritesize;
int temptype = data->state.tempwritetype;
size_t chunklen;
/* clear tempwrite here just to make sure it gets cleared if there's no
further use of it, and make sure we don't clear it after the function
invoke as it may have been set to a new value by then */
data->state.tempwrite = NULL;
/* since the write callback API is define to never exceed
CURL_MAX_WRITE_SIZE bytes in a single call, and since we may in fact
have more data than that in our buffer here, we must loop sending the
data in multiple calls until there's no data left or we get another
pause returned.
A tricky part is that the function we call will "buffer" the data
itself when it pauses on a particular buffer, so we may need to do some
extra trickery if we get a pause return here.
*/
do {
chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize;
result = Curl_client_write(data->easy_conn,
temptype, tempwrite, chunklen);
if(result)
/* failures abort the loop at once */
break;
if(data->state.tempwrite && (tempsize - chunklen)) {
/* Ouch, the reading is again paused and the block we send is now
"cached". If this is the final chunk we can leave it like this, but
if we have more chunks that are cached after this, we need to free
the newly cached one and put back a version that is truly the entire
contents that is saved for later
*/
char *newptr;
/* note that tempsize is still the size as before the callback was
used, and thus the whole piece of data to keep */
newptr = realloc(data->state.tempwrite, tempsize);
if(!newptr) {
free(data->state.tempwrite); /* free old area */
data->state.tempwrite = NULL;
result = CURLE_OUT_OF_MEMORY;
/* tempwrite will be freed further down */
break;
}
data->state.tempwrite = newptr; /* store new pointer */
memcpy(newptr, tempwrite, tempsize);
data->state.tempwritesize = tempsize; /* store new size */
/* tempwrite will be freed further down */
break; /* go back to pausing until further notice */
}
else {
tempsize -= chunklen; /* left after the call above */
tempwrite += chunklen; /* advance the pointer */
}
} while(!result && tempsize);
free(freewrite); /* this is unconditionally no longer used */
result = Curl_client_chop_write(data->easy_conn, data->state.tempwritetype,
tempwrite, data->state.tempwritesize);
free(tempwrite);
}
/* if there's no error and we're not pausing both directions, we want