-
-
Notifications
You must be signed in to change notification settings - Fork 7.1k
Description
I did this
We noticed the following behavior during our test cases using libcurl:
We use libcurl to make a request against a local HTTP server using a self-signed cert.
libcurl does not know about this certificate, so we expect a CURLE_PEER_FAILED_VERIFICATION upon running curl_easy_perform(). This works as intended. However, we also read the contents inside of curl's error buffer and display that as well. Since curl 8.17.0, the most recent error message stored within the buffer is failed to open socket: Address family not supported by protocol instead of SSL certificate problem: self-signed certificate.
We only noticed this behavior on our Linux machines (we also tested macOS and Windows), though I don't know if this is just a side-effect of OS-specifics or configuration.
I am unsure as to whether this is to be expected though, which is why I wrote "potential regression". Feel free to close the issue if this is expected behavior. If so, I'd guess we are meant to just always use curl_easy_strerror(CURL_error_code) instead, or is there something I'm missing here?
Reproducible example:
#include <memory>
extern "C" {
#include <curl/curl.h>
}
namespace playground {
class CurlHelper {
public:
explicit CurlHelper();
auto perform(const std::string &url) -> long;
private:
std::array<char, CURL_ERROR_SIZE> errorBuffer;
auto checkCurlError(CURLcode res, const std::string &url) -> void;
auto checkPointer() -> void const;
std::unique_ptr<CURL, decltype(&curl_easy_cleanup)> curl;
};
} // namespace playground
#include "openssl/crypto.h"
#include "openssl/ssl.h"
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
namespace playground {
CurlHelper::CurlHelper() : curl(curl_easy_init(), curl_easy_cleanup), errorBuffer() {
if (!curl) {
throw std::runtime_error("Failed to initialize CURL");
}
curl_easy_setopt(this->curl.get(), CURLOPT_ERRORBUFFER, this->errorBuffer.data());
}
auto CurlHelper::checkCurlError(CURLcode res, const std::string &url) -> void {
if (res != CURLE_OK) {
std::stringstream ss;
ss << "CURL error: ";
if (this->errorBuffer.empty()) {
ss << curl_easy_strerror(res);
} else {
ss << this->errorBuffer.data();
}
ss << " for URL: " << url << " (CURLcode: " << res << ")" << std::endl;
throw std::runtime_error(ss.str());
}
}
auto CurlHelper::checkPointer() -> void const {
if (!this->curl) {
throw std::runtime_error("CURL pointer is null");
}
}
auto CurlHelper::perform(const std::string &url) -> long {
this->checkPointer();
curl_easy_setopt(this->curl.get(), CURLOPT_URL, url.c_str());
curl_easy_setopt(this->curl.get(), CURLOPT_SSL_VERIFYHOST, true);
curl_easy_setopt(this->curl.get(), CURLOPT_SSL_VERIFYPEER, true);
std::cout << "Performing CURL request to URL: " << url << std::endl;
auto res = curl_easy_perform(this->curl.get());
this->checkCurlError(res, url);
long statusCode;
curl_easy_getinfo(this->curl.get(), CURLINFO_RESPONSE_CODE, &statusCode);
return statusCode;
}
} // namespace playground
int main(int argc, char** argv) {
auto helper = std::make_unique<playground::CurlHelper>();
std::cout << helper->perform("https://localhost:" + std::string(argv[1])) << "\n";
return 0;
}Then just make sure to have a webserver running at the address specified.
I expected the following
I expected the most recent error to be related to a self-signed cert error.
curl/libcurl version
WARNING: this libcurl is Debug-enabled, do not use in production
curl 8.18.0 (x86_64-pc-linux-gnu) libcurl/8.18.0 OpenSSL/3.6.1 zlib/1.3.1.2-audit
Release-Date: 2026-01-07
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS Debug HSTS HTTPS-proxy IPv6 Largefile libz NTLM SSL threadsafe TLS-SRP TrackMemory UnixSockets
and
WARNING: this libcurl is Debug-enabled, do not use in production
curl 8.17.0 (x86_64-pc-linux-gnu) libcurl/8.17.0 OpenSSL/3.6.1 zlib/1.3.1.2-audit
Release-Date: 2025-11-05
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS Debug HSTS HTTPS-proxy IPv6 Largefile libz NTLM SSL threadsafe TLS-SRP TrackMemory UnixSockets
operating system
Linux 9a71d92e8ff4 5.15.0-139-generic #149~20.04.1-Ubuntu SMP Wed Apr 16 08:29:56 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
and
macOS 17 (Apple toolchain, apple-clang 16 and 17)
and
Windows Server 2019 (MSVC 193)