easy: allow connect-only handle reuse with easy_perform

- Detach and disconnect an attached connection before performing.

Prior to this change it was not possible to safely reuse an easy handle
with an attached connection in a second call to curl_easy_perform. The
only known case of this is a connect-only type handle where the
connection was detached when curl_easy_perform returned, only to be
reattached by either curl_easy_send/recv.

This commit effectively reverts 2f8ecd5d and be82a360, the latter of
which treated the reuse as an error. Prior to that change undefined
behavior may occur in such a case.

Bug: https://curl.se/mail/lib-2025-01/0044.html
Reported-by: Aleksander Mazur

Closes https://github.com/curl/curl/pull/16008
This commit is contained in:
Jay Satiro 2025-01-15 03:56:11 -05:00
parent f25a807a7d
commit 4f99efb192
4 changed files with 55 additions and 23 deletions

View file

@ -7,7 +7,7 @@ HTTP GET
</info>
<reply>
<data>
<data nocheck="yes">
HTTP/1.1 200 OK swsclose
Server: test-server/fake
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
@ -38,15 +38,33 @@ http://%HOSTIP:%HTTPPORT
#
# Verify data after the test has been "shot"
<verify>
<stdout>
HTTP/1.1 200 OK swsclose
Server: test-server/fake
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
Content-Length: 6
Connection: close
-foo-
HTTP/1.1 200 OK swsclose
Server: test-server/fake
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
Content-Length: 6
Connection: close
-foo-
</stdout>
<protocol>
GET /556 HTTP/1.1
Host: ninja
GET /556 HTTP/1.1
Host: ninja
</protocol>
# 43 == CURLE_BAD_FUNCTION_ARGUMENT
<errorcode>
43
0
</errorcode>
</verify>
</testcase>

View file

@ -41,6 +41,9 @@ CURLcode test(char *URL)
{
CURLcode res;
CURL *curl;
#ifdef LIB696
int transfers = 0;
#endif
if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
fprintf(stderr, "curl_global_init() failed\n");
@ -58,6 +61,10 @@ CURLcode test(char *URL)
test_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
test_setopt(curl, CURLOPT_VERBOSE, 1L);
#ifdef LIB696
again:
#endif
res = curl_easy_perform(curl);
if(!res) {
@ -87,8 +94,12 @@ CURLcode test(char *URL)
if(nread) {
/* send received stuff to stdout */
if(!write(STDOUT_FILENO, buf, nread))
if((size_t)write(STDOUT_FILENO, buf, nread) != nread) {
fprintf(stderr, "write() failed: errno %d (%s)\n",
errno, strerror(errno));
res = TEST_ERR_FAILURE;
break;
}
}
} while((res == CURLE_OK && nread) || (res == CURLE_AGAIN));
@ -98,12 +109,10 @@ CURLcode test(char *URL)
}
#ifdef LIB696
/* attempt to use the handle again */
test_setopt(curl, CURLOPT_URL, URL);
test_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
test_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
++transfers;
/* perform the transfer a second time */
if(!res && transfers == 1)
goto again;
#endif
test_cleanup: