multi: init_do(): check result

Calls to `Curl_init_do()` did not check on result and missed failures to
properly and completely initialize a transfer request.

The main cause of such an init failure is the need to rewind the
READFUNCTION without a SEEKFUNCTION registered. Check the failure to
"rewind" the upload data immediately make test cases 1576 and friends
fail.

Reported-by: Travis Lane
Fixes #17139
Closes #17150
This commit is contained in:
Stefan Eissing 2025-04-23 11:24:45 +02:00 committed by Daniel Stenberg
parent 39f5e7cb69
commit 5e95556fc2
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
4 changed files with 33 additions and 17 deletions

View File

@ -1560,10 +1560,15 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
rc = curl_multi_add_handle(multi, data); rc = curl_multi_add_handle(multi, data);
if(!rc) { if(!rc) {
struct SingleRequest *k = &data->req; struct SingleRequest *k = &data->req;
CURLcode result;
/* pass in NULL for 'conn' here since we do not want to init the /* pass in NULL for 'conn' here since we do not want to init the
connection, only this transfer */ connection, only this transfer */
Curl_init_do(data, NULL); result = Curl_init_do(data, NULL);
if(result) {
curl_multi_remove_handle(multi, data);
return CURLM_INTERNAL_ERROR;
}
/* take this handle to the perform state right away */ /* take this handle to the perform state right away */
multistate(data, MSTATE_PERFORMING); multistate(data, MSTATE_PERFORMING);

View File

@ -3533,28 +3533,26 @@ static CURLcode create_conn(struct Curl_easy *data,
/* conn_protocol can only provide "old" protocols */ /* conn_protocol can only provide "old" protocols */
data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK; data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
result = conn->handler->connect_it(data, &done); result = conn->handler->connect_it(data, &done);
if(result)
goto out;
/* Setup a "faked" transfer that will do nothing */ /* Setup a "faked" transfer that will do nothing */
Curl_attach_connection(data, conn);
result = Curl_cpool_add(data, conn);
if(!result) { if(!result) {
Curl_attach_connection(data, conn); /* Setup whatever necessary for a resumed transfer */
result = Curl_cpool_add(data, conn); result = setup_range(data);
if(!result) { if(!result) {
/* Setup whatever necessary for a resumed transfer */ Curl_xfer_setup_nop(data);
result = setup_range(data); result = Curl_init_do(data, conn);
} }
if(result) {
DEBUGASSERT(conn->handler->done);
/* we ignore the return code for the protocol-specific DONE */
(void)conn->handler->done(data, result, FALSE);
goto out;
}
Curl_xfer_setup_nop(data);
} }
/* since we skip do_init() */ if(result) {
Curl_init_do(data, conn); DEBUGASSERT(conn->handler->done);
/* we ignore the return code for the protocol-specific DONE */
(void)conn->handler->done(data, result, FALSE);
}
goto out; goto out;
} }
#endif #endif
@ -3704,7 +3702,9 @@ static CURLcode create_conn(struct Curl_easy *data,
} }
/* Setup and init stuff before DO starts, in preparing for the transfer. */ /* Setup and init stuff before DO starts, in preparing for the transfer. */
Curl_init_do(data, conn); result = Curl_init_do(data, conn);
if(result)
goto out;
/* /*
* Setup whatever necessary for a resumed transfer * Setup whatever necessary for a resumed transfer

View File

@ -38,6 +38,15 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *stream)
return strlen(testdata); return strlen(testdata);
} }
static int seek_callback(void *ptr, curl_off_t offset, int origin)
{
(void)ptr;
(void)offset;
if(origin != SEEK_SET)
return CURL_SEEKFUNC_FAIL;
return CURL_SEEKFUNC_OK;
}
CURLcode test(char *URL) CURLcode test(char *URL)
{ {
CURLcode res; CURLcode res;
@ -62,6 +71,7 @@ CURLcode test(char *URL)
test_setopt(curl, CURLOPT_URL, URL); test_setopt(curl, CURLOPT_URL, URL);
test_setopt(curl, CURLOPT_UPLOAD, 1L); test_setopt(curl, CURLOPT_UPLOAD, 1L);
test_setopt(curl, CURLOPT_READFUNCTION, read_callback); test_setopt(curl, CURLOPT_READFUNCTION, read_callback);
test_setopt(curl, CURLOPT_SEEKFUNCTION, seek_callback);
test_setopt(curl, CURLOPT_INFILESIZE, (long)strlen(testdata)); test_setopt(curl, CURLOPT_INFILESIZE, (long)strlen(testdata));
test_setopt(curl, CURLOPT_CUSTOMREQUEST, "CURL"); test_setopt(curl, CURLOPT_CUSTOMREQUEST, "CURL");

View File

@ -78,6 +78,7 @@ my @reused_symbols = (
"removeFd", "removeFd",
"rlim2str", "rlim2str",
"run_thread", "run_thread",
"seek_callback",
"send_ping", "send_ping",
"showem", "showem",
"store_errmsg", "store_errmsg",