mirror of
https://github.com/curl/curl.git
synced 2026-08-25 16:33:38 +03:00
lib: enhance client reader resume + rewind
- update client reader documentation
- client reader, add rewind capabilities
- tell creader to rewind on next start
- Curl_client_reset() will keep reader for future rewind if requested
- add Curl_client_cleanup() for freeing all resources independent of
rewinds
- add Curl_client_start() to trigger rewinds
- move rewind code from multi.c to sendf.c and make part of
"cr-in"'s implementation
- http, move the "resume_from" handling into the client readers
- the setup of a HTTP request is reshuffled to follow:
* determine method, target, auth negotiation
* install the client reader(s) for the request, including crlf
conversions and "chunked" encoding
* apply ranges to client reader
* concat request headers, upgrades, cookies, etc.
* complete request by determining Content-Length of installed
readers in combination with method
* send
- add methods for client readers to
* return the overall length they will generate (or -1 when unknown)
* return the amount of data on the CLIENT level, so that
expect-100 can decide if it want to apply itself
* set a "resume_from" offset or fail if unsupported
- struct HTTP has become largely empty now
- rename `Client_reader_*` to `Curl_creader_*`
Closes #13026
This commit is contained in:
parent
9c7768cd88
commit
14bcea074a
15 changed files with 752 additions and 474 deletions
90
lib/multi.c
90
lib/multi.c
|
|
@ -1816,93 +1816,6 @@ static CURLcode protocol_connect(struct Curl_easy *data,
|
|||
return result; /* pass back status */
|
||||
}
|
||||
|
||||
/*
|
||||
* readrewind() rewinds the read stream. This is typically used for HTTP
|
||||
* POST/PUT with multi-pass authentication when a sending was denied and a
|
||||
* resend is necessary.
|
||||
*/
|
||||
static CURLcode readrewind(struct Curl_easy *data)
|
||||
{
|
||||
#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
|
||||
curl_mimepart *mimepart = &data->set.mimepost;
|
||||
#endif
|
||||
DEBUGASSERT(data->conn);
|
||||
|
||||
data->state.rewindbeforesend = FALSE; /* we rewind now */
|
||||
|
||||
/* explicitly switch off sending data on this connection now since we are
|
||||
about to restart a new transfer and thus we want to avoid inadvertently
|
||||
sending more data on the existing connection until the next transfer
|
||||
starts */
|
||||
data->req.keepon &= ~KEEP_SEND;
|
||||
|
||||
/* We have sent away data. If not using CURLOPT_POSTFIELDS or
|
||||
CURLOPT_HTTPPOST, call app to rewind
|
||||
*/
|
||||
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)
|
||||
if(data->conn->handler->protocol & PROTO_FAMILY_HTTP) {
|
||||
if(data->state.mimepost)
|
||||
mimepart = data->state.mimepost;
|
||||
}
|
||||
#endif
|
||||
if(data->set.postfields ||
|
||||
(data->state.httpreq == HTTPREQ_GET) ||
|
||||
(data->state.httpreq == HTTPREQ_HEAD))
|
||||
; /* no need to rewind */
|
||||
#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
|
||||
else if(data->state.httpreq == HTTPREQ_POST_MIME ||
|
||||
data->state.httpreq == HTTPREQ_POST_FORM) {
|
||||
CURLcode result = Curl_mime_rewind(mimepart);
|
||||
if(result) {
|
||||
failf(data, "Cannot rewind mime/post data");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
if(data->set.seek_func) {
|
||||
int err;
|
||||
|
||||
Curl_set_in_callback(data, true);
|
||||
err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(err) {
|
||||
failf(data, "seek callback returned error %d", (int)err);
|
||||
return CURLE_SEND_FAIL_REWIND;
|
||||
}
|
||||
}
|
||||
else if(data->set.ioctl_func) {
|
||||
curlioerr err;
|
||||
|
||||
Curl_set_in_callback(data, true);
|
||||
err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
|
||||
data->set.ioctl_client);
|
||||
Curl_set_in_callback(data, false);
|
||||
infof(data, "the ioctl callback returned %d", (int)err);
|
||||
|
||||
if(err) {
|
||||
failf(data, "ioctl callback returned error %d", (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
|
||||
ourselves with fseek() */
|
||||
if(data->state.fread_func == (curl_read_callback)fread) {
|
||||
if(-1 != fseek(data->state.in, 0, SEEK_SET))
|
||||
/* successful rewind */
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* no callback set or failure above, makes us fail at once */
|
||||
failf(data, "necessary data rewind wasn't possible");
|
||||
return CURLE_SEND_FAIL_REWIND;
|
||||
}
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_preconnect() is called immediately before a connect starts. When a
|
||||
* redirect is followed, this is then called multiple times during a single
|
||||
|
|
@ -2169,9 +2082,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||
break;
|
||||
|
||||
case MSTATE_PROTOCONNECT:
|
||||
if(data->state.rewindbeforesend)
|
||||
result = readrewind(data);
|
||||
|
||||
if(!result && data->conn->bits.reuse) {
|
||||
/* ftp seems to hang when protoconnect on reused connection
|
||||
* since we handle PROTOCONNECT in general inside the filers, it
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue