diff options
Diffstat (limited to 'lib/transfer.c')
-rw-r--r-- | lib/transfer.c | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/lib/transfer.c b/lib/transfer.c index b52e40ef1..5e8333538 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -193,6 +193,55 @@ checkhttpprefix(struct SessionHandle *data, return FALSE; } +/* + * Curl_readrewind() rewinds the read stream. This typically (so far) only + * used for HTTP POST/PUT with multi-pass authentication when a sending was + * denied and a resend is necessary. + */ +CURLcode Curl_readrewind(struct connectdata *conn) +{ + struct SessionHandle *data = conn->data; + + conn->bits.rewindaftersend = FALSE; /* we rewind now */ + + /* We have sent away data. If not using CURLOPT_POSTFIELDS or + CURLOPT_HTTPPOST, call app to rewind + */ + if(data->set.postfields || + (data->set.httpreq == HTTPREQ_POST_FORM)) + ; /* do nothing */ + else { + if(data->set.ioctl) { + curlioerr err; + + err = data->set.ioctl(data, CURLIOCMD_RESTARTREAD, + data->set.ioctl_client); + infof(data, "the ioctl callback returned %d\n", (int)err); + + if(err) { + /* FIXME: convert to a human readable error message */ + failf(data, "ioctl callback returned error %d\n", (int)err); + return CURLE_SEND_FAIL_REWIND; + } + } + else { + /* If no CURLOPT_READFUNCTION is used, we know that we operate on a + given FILE * stream and we can actually attempt to rewind that + ourself with fseek() */ + if(data->set.fread == (curl_read_callback)fread) { + if(-1 != fseek(data->set.in, 0, SEEK_SET)) + /* successful rewind */ + return CURLE_OK; + } + + /* no callback set or failure aboe, makes us fail at once */ + failf(data, "necessary data rewind wasn't possible\n"); + return CURLE_SEND_FAIL_REWIND; + } + } + return CURLE_OK; +} + /* * Curl_readwrite() is the low-level function to be called when data is to @@ -1163,6 +1212,12 @@ CURLcode Curl_readwrite(struct connectdata *conn, /* done */ k->keepon &= ~KEEP_WRITE; /* we're done writing */ writedone = TRUE; + + if(conn->bits.rewindaftersend) { + result = Curl_readrewind(conn); + if(result) + return result; + } break; } |