Description
I'm using the new CURLOPT_CURLU feature to take advantage of curl's 'accumulative', relative url capabilities, but it appears that when also using CURLOPT_PORT, curl overwrites the port portion of the url in 'my' CURLU handle set by CURLOPT_CURLU. If I later use CURLOPT_PORT passing 0L to go back to the original port, curl instead remembers the port set by the previous CURLOPT_PORT call!
This behavior is different from using the classic 'CURLOPT_URL' way of passing the url to curl, where it correctly reverts back to the port indicated in the orginal url.
I figure the problem has to do with the way curl treats its internal CURLU handle as a 'scratch' area which is fine when used with a CURLOPT_URL url, which, I assume, resets the CURLU handle before every new transaction, but with CURLOPT_CURLU it clashes with 'my' CURLU handle, which I expect curl should leave alone and treat as read-only.
The following code illustrates the problem :
#include "curl/curl.h"
#include <stdio.h>
static char error_buffer[CURL_ERROR_SIZE] = "";
int main(void)
{
const char *url = "http://httpbin.org/get";
char *url_after;
CURLU *curlu = curl_url();
CURL *curl = curl_easy_init();
CURLcode curl_code;
printf("using curl version %s\n", curl_version_info(CURLVERSION_NOW)->version);
curl_url_set(curlu, CURLUPART_URL, url, CURLU_DEFAULT_SCHEME);
curl_easy_setopt(curl, CURLOPT_CURLU, curlu);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_PORT, 1234L); // should not work, that's ok
curl_code = curl_easy_perform(curl);
printf("failure expected, curl_easy_perform returned %ld: <%s>, <%s>\n",
(long) curl_code, curl_easy_strerror(curl_code), error_buffer);
// print url
curl_url_get(curlu, CURLUPART_URL, &url_after, 0);
printf("curlu now: <%s>\n", url_after);
curl_free(url_after);
// now reset port to go back to port 80 (not!)
curl_easy_setopt(curl, CURLOPT_PORT, 0L);
curl_code = curl_easy_perform(curl);
printf("success expected, curl_easy_perform returned %ld: <%s>, <%s>\n",
(long) curl_code, curl_easy_strerror(curl_code), error_buffer);
// print url
curl_url_get(curlu, CURLUPART_URL, &url_after, 0);
printf("curlu now: <%s>\n", url_after);
curl_free(url_after);
curl_easy_cleanup(curl);
curl_url_cleanup(curlu);
return 0;
}
It generates the following output, note how it appears stuck on port 1234:
using curl version 7.65.0-DEV
* Trying 52.71.234.219...
* TCP_NODELAY set
* connect to 52.71.234.219 port 1234 failed: Connection refused
* Trying 3.85.154.144...
* TCP_NODELAY set
* connect to 3.85.154.144 port 1234 failed: Connection refused
* Failed to connect to httpbin.org port 1234: Connection refused
* Closing connection 0
failure expected, curl_easy_perform returned 7: <Couldn't connect to
server>, <Failed to connect to httpbin.org port 1234: Connection refused>
curlu now: <http://httpbin.org:1234/get>
* Hostname httpbin.org was found in DNS cache
* Trying 52.71.234.219...
* TCP_NODELAY set
* connect to 52.71.234.219 port 1234 failed: Connection refused
* Trying 3.85.154.144...
* TCP_NODELAY set
* connect to 3.85.154.144 port 1234 failed: Connection refused
* Failed to connect to httpbin.org port 1234: Connection refused
* Closing connection 1
success expected, curl_easy_perform returned 7: <Couldn't connect to
server>, <Failed to connect to httpbin.org port 1234: Connection refused>
curlu now: <http://httpbin.org:1234/get>
curl/libcurl version
7.64.1 and 7.65.0-DEV (github master (as of April 8th 2019))
operating system
CentOS 7, but probably not OS specific