aboutsummaryrefslogtreecommitdiff
path: root/lib/easy.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/easy.c')
-rw-r--r--lib/easy.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/lib/easy.c b/lib/easy.c
index adc88ec2f..991a25573 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -744,6 +744,107 @@ void curl_easy_reset(CURL *curl)
data->set.new_directory_perms = 0755; /* Default permissions */
}
+/*
+ * curl_easy_pause() allows an application to pause or unpause a specific
+ * transfer and direction. This function sets the full new state for the
+ * current connection this easy handle operates on.
+ *
+ * NOTE: if you have the receiving paused and you call this function to remove
+ * the pausing, you may get your write callback called at this point.
+ *
+ * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
+ */
+CURLcode curl_easy_pause(CURL *curl, int action)
+{
+ struct SessionHandle *data = (struct SessionHandle *)curl;
+ struct SingleRequest *k = &data->req;
+ CURLcode result = CURLE_OK;
+
+ /* first switch off both pause bits */
+ int newstate = k->keepon &~ (KEEP_READ_PAUSE| KEEP_WRITE_PAUSE);
+
+ /* set the new desired pause bits */
+ newstate |= ((action & CURLPAUSE_RECV)?KEEP_READ_PAUSE:0) |
+ ((action & CURLPAUSE_SEND)?KEEP_WRITE_PAUSE:0);
+
+ /* put it back in the keepon */
+ k->keepon = newstate;
+
+ if(!(newstate & KEEP_READ_PAUSE) && data->state.tempwrite) {
+ /* we have a buffer for writing 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
+ the tempwrite variables */
+ char *tempwrite = data->state.tempwrite;
+ 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->state.current_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 is 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;
+
+ free(data->state.tempwrite); /* free the one just cached as it isn't
+ enough */
+
+ /* note that tempsize is still the size as before the callback was
+ used, and thus the whole piece of data to keep */
+ newptr = malloc(tempsize);
+ if(!newptr) {
+ 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 == CURLE_OK) && tempsize);
+
+ free(tempwrite); /* this is unconditionally no longer used */
+ }
+
+ return result;
+}
+
#ifdef CURL_DOES_CONVERSIONS
/*
* Curl_convert_to_network() is an internal function