multi: fix re-sending request on early connection close
This handling already works with the easy-interface code. When a request is sent on a re-used connection that gets closed by the server at the same time as the request is sent, the situation may occur so that we can send the request and we discover the broken connection as a RECV_ERROR in the PERFORM state and then the request needs to be retried on a fresh connection. Test 64 broke with 'multi-always-internally'.
This commit is contained in:
parent
3202cc6162
commit
8b02afd9a9
45
lib/multi.c
45
lib/multi.c
@ -1539,6 +1539,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
break;
|
||||
|
||||
case CURLM_STATE_PERFORM:
|
||||
{
|
||||
char *newurl = NULL;
|
||||
bool retry = FALSE;
|
||||
|
||||
/* check if over send speed */
|
||||
if((data->set.max_send_speed > 0) &&
|
||||
(data->progress.ulspeed > data->set.max_send_speed)) {
|
||||
@ -1586,13 +1590,29 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
easy->easy_conn->writechannel_inuse = FALSE;
|
||||
}
|
||||
|
||||
if(done || (easy->result == CURLE_RECV_ERROR)) {
|
||||
/* If CURLE_RECV_ERROR happens early enough, we assume it was a race
|
||||
* condition and the server closed the re-used connection exactly when
|
||||
* we wanted to use it, so figure out if that is indeed the case.
|
||||
*/
|
||||
CURLcode ret = Curl_retry_request(easy->easy_conn, &newurl);
|
||||
if(!ret)
|
||||
retry = (newurl)?TRUE:FALSE;
|
||||
|
||||
if(retry)
|
||||
/* if we are to retry, set the result to OK */
|
||||
easy->result = CURLE_OK;
|
||||
}
|
||||
|
||||
if(easy->result) {
|
||||
/* The transfer phase returned error, we mark the connection to get
|
||||
/*
|
||||
* The transfer phase returned error, we mark the connection to get
|
||||
* closed to prevent being re-used. This is because we can't possibly
|
||||
* know if the connection is in a good shape or not now. Unless it is
|
||||
* a protocol which uses two "channels" like FTP, as then the error
|
||||
* happened in the data connection.
|
||||
*/
|
||||
|
||||
if(!(easy->easy_conn->handler->flags & PROTOPT_DUAL))
|
||||
easy->easy_conn->bits.close = TRUE;
|
||||
|
||||
@ -1600,14 +1620,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
Curl_done(&easy->easy_conn, easy->result, FALSE);
|
||||
}
|
||||
else if(done) {
|
||||
char *newurl = NULL;
|
||||
bool retry = FALSE;
|
||||
followtype follow=FOLLOW_NONE;
|
||||
|
||||
easy->result = Curl_retry_request(easy->easy_conn, &newurl);
|
||||
if(!easy->result)
|
||||
retry = (newurl)?TRUE:FALSE;
|
||||
|
||||
/* call this even if the readwrite function returned error */
|
||||
Curl_posttransfer(data);
|
||||
|
||||
@ -1640,11 +1654,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
if(CURLE_OK == easy->result) {
|
||||
multistate(easy, CURLM_STATE_CONNECT);
|
||||
result = CURLM_CALL_MULTI_PERFORM;
|
||||
newurl = NULL; /* handed over the memory ownership to
|
||||
Curl_follow(), make sure we don't free() it
|
||||
here */
|
||||
}
|
||||
else if(newurl)
|
||||
/* Since we "took it", we are in charge of freeing this on
|
||||
failure */
|
||||
free(newurl);
|
||||
}
|
||||
else {
|
||||
/* after the transfer is done, go DONE */
|
||||
@ -1652,13 +1665,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
/* but first check to see if we got a location info even though we're
|
||||
not following redirects */
|
||||
if(data->req.location) {
|
||||
if(newurl)
|
||||
free(newurl);
|
||||
newurl = data->req.location;
|
||||
data->req.location = NULL;
|
||||
easy->result = Curl_follow(data, newurl, FOLLOW_FAKE);
|
||||
if(easy->result) {
|
||||
newurl = NULL; /* allocation was handed over */
|
||||
if(easy->result)
|
||||
disconnect_conn = TRUE;
|
||||
free(newurl);
|
||||
}
|
||||
}
|
||||
|
||||
multistate(easy, CURLM_STATE_DONE);
|
||||
@ -1666,7 +1680,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
}
|
||||
}
|
||||
|
||||
if(newurl)
|
||||
free(newurl);
|
||||
break;
|
||||
}
|
||||
|
||||
case CURLM_STATE_DONE:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user