diff options
Diffstat (limited to 'lib/sendf.c')
-rw-r--r-- | lib/sendf.c | 74 |
1 files changed, 71 insertions, 3 deletions
diff --git a/lib/sendf.c b/lib/sendf.c index b33277ac3..32a8655b2 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -376,6 +376,36 @@ CURLcode Curl_write(struct connectdata *conn, return retcode; } +static CURLcode pausewrite(struct SessionHandle *data, + int type, /* what type of data */ + char *ptr, + size_t len) +{ + /* signalled to pause sending on this connection, but since we have data + we want to send we need to dup it to save a copy for when the sending + is again enabled */ + struct SingleRequest *k = &data->req; + char *dupl = malloc(len); + if(!dupl) + return CURLE_OUT_OF_MEMORY; + + memcpy(dupl, ptr, len); + + /* store this information in the state struct for later use */ + data->state.tempwrite = dupl; + data->state.tempwritesize = len; + data->state.tempwritetype = type; + + /* mark the connection as RECV paused */ + k->keepon |= KEEP_READ_PAUSE; + + DEBUGF(infof(data, "Pausing with %d bytes in buffer for type %02x\n", + (int)len, type)); + + return CURLE_OK; +} + + /* client_write() sends data to the write callback(s) The bit pattern defines to what "streams" to write to. Body and/or header. @@ -390,8 +420,37 @@ CURLcode Curl_client_write(struct connectdata *conn, size_t wrote; if(data->state.cancelled) { - /* We just suck everything into a black hole */ - return CURLE_OK; + /* We just suck everything into a black hole */ + return CURLE_OK; + } + + /* If reading is actually paused, we're forced to append this chunk of data + to the already held data, but only if it is the same type as otherwise it + can't work and it'll return error instead. */ + if(data->req.keepon & KEEP_READ_PAUSE) { + size_t newlen; + char *newptr; + if(type != data->state.tempwritetype) + /* major internal confusion */ + return CURLE_RECV_ERROR; + + /* figure out the new size of the data to save */ + newlen = len + data->state.tempwritesize; + /* allocate the new memory area */ + newptr = malloc(newlen); + if(!newptr) + return CURLE_OUT_OF_MEMORY; + /* copy the previously held data to the new area */ + memcpy(newptr, data->state.tempwrite, data->state.tempwritesize); + /* copy the new data to the end of the new area */ + memcpy(newptr + data->state.tempwritesize, ptr, len); + /* free the old data */ + free(data->state.tempwrite); + /* update the pointer and the size */ + data->state.tempwrite = newptr; + data->state.tempwritesize = newlen; + + return CURLE_OK; } if(0 == len) @@ -422,8 +481,11 @@ CURLcode Curl_client_write(struct connectdata *conn, wrote = len; } + if(CURL_WRITEFUNC_PAUSE == wrote) + return pausewrite(data, type, ptr, len); + if(wrote != len) { - failf (data, "Failed writing body"); + failf(data, "Failed writing body (%d != %d)", (int)wrote, (int)len); return CURLE_WRITE_ERROR; } } @@ -441,6 +503,12 @@ CURLcode Curl_client_write(struct connectdata *conn, regardless of the ftp transfer mode (ASCII/Image) */ wrote = writeit(ptr, 1, len, data->set.writeheader); + if(CURL_WRITEFUNC_PAUSE == wrote) + /* here we pass in the HEADER bit only since if this was body as well + then it was passed already and clearly that didn't trigger the pause, + so this is saved for later with the HEADER bit only */ + return pausewrite(data, CLIENTWRITE_HEADER, ptr, len); + if(wrote != len) { failf (data, "Failed writing header"); return CURLE_WRITE_ERROR; |