I did this
This test program fails with CURLE_SEND_ERROR if the https url in the file in argv[1] is longer than ~u16 max.
CURLE_SEND_ERROR curl_easy_perform() failed: Failed sending data to the peer
SSL_write() error: error:0A00010F:SSL routines::bad length
(Please excuse the C++)
#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
#include <curl/curl.h>
size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <url_file>" << std::endl;
return 1;
}
std::ifstream urlFile(argv[1]);
if (!urlFile.is_open()) {
std::cerr << "Failed to open file: " << argv[1] << std::endl;
return 1;
}
std::string url;
std::getline(urlFile, url);
urlFile.close();
CURL* curl;
CURLcode res;
std::string response;
curl = curl_easy_init();
assert(curl && "Failed to initialize CURL.");
char* err = (char*)malloc(CURL_ERROR_SIZE);
assert(err && "Failed to alloc err buf");
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, err);
res = curl_easy_perform(curl);
if (res == CURLE_SEND_ERROR) {
std::cerr << "CURLE_SEND_ERROR curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
std::cerr << err << std::endl;
} else if (res != CURLE_OK) {
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
std::cerr << std::string(err) << std::endl;
} else {
std::cout << "Successful" << std::endl;
}
curl_easy_cleanup(curl);
free(err);
return 0;
}
I think this is an issue with how openssl SSL_write is used, where it errors with SSL_ERROR_WANT_WRITE and expects to be presented with the same buffer again until it succeeds, but curl's openssl integration does something that is not exactly that.
I tried a hacky workaround to confirm if this could be the issue, and it seems to work.
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index 6ded5f3c0..712c70657 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -5086,9 +5086,22 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
rc = SSL_write(octx->ssl, mem, memlen);
- if(rc <= 0) {
+ while (rc <= 0) {
err = SSL_get_error(octx->ssl, rc);
+ if (err == SSL_ERROR_WANT_WRITE) {
+ // HACK: when erroring with SSL_ERROR_WANT_WRITE openssl wants you to
+ // present the same buffer again once the underlying socket is ready.
+ // Here we just try in a loop instead of polling the socket.
+ //
+ // This works around an issue with curl and https and _very_ long urls
+ // (u16 max seems to be the breaking point for the size of the headers).
+ rc = SSL_write(octx->ssl, mem, memlen);
+ } else {
+ break;
+ }
+ }
+ if(rc <= 0) {
switch(err) {
case SSL_ERROR_WANT_READ:
connssl->io_need = CURL_SSL_IO_NEED_RECV;
I expected the following
No response
curl/libcurl version
libcurl 8.12.1 & libcurl 8.15.0
openssl 3.4.1
operating system
Windows 10
I did this
This test program fails with
CURLE_SEND_ERRORif the https url in the file inargv[1]is longer than ~u16 max.(Please excuse the C++)
I think this is an issue with how openssl
SSL_writeis used, where it errors withSSL_ERROR_WANT_WRITEand expects to be presented with the same buffer again until it succeeds, but curl's openssl integration does something that is not exactly that.I tried a hacky workaround to confirm if this could be the issue, and it seems to work.
I expected the following
No response
curl/libcurl version
libcurl 8.12.1 & libcurl 8.15.0
openssl 3.4.1
operating system
Windows 10