libcurl half as fast as curl - c++

I am using libcurl to download files using the SFTP (protocol), it takes libcurl about twice as much times as it does using the curl executable.
This is the curl example I followed when designing this:
size_t my_fwrite(char* buffer, size_t size, size_t nmemb, File* file)
{
return size * nmemb; //Just return the size to prove that it's not the write
}
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL* curl = curl_easy_init();
/** Setup URL/PORT/USERNAME/PASSWORD*/
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
CURLcode res = curl_easy_perform(curl);
if (CURLE_OK != res) {
// we failed
std::cout << "we failed due to '" << curl_easy_strerror(res) << "'\n";
}
// Close the file
curl_global_cleanup();
When running, I measured the time using chrono steady_clock, and it used about 39 seconds to download 119mb. Whereas using the curl command it took 16 seconds. I tried with lager files as well, and the same applied. When downloading 500mb libcurl used around 3 minutes, where curl would use 1,5 minutes. The curl binary and the API is compiled using CMake.
The curl command was:
curl -k sftp://username:password#host.com:port/path/to/file.zip --output file.zip
Do note that I used the compiled curl and not the system downloaded curl, as that one did not support sftp
EDIT:
It is compiled as release.
Running the very sleepy profiler on a debug compile executable gave me that most of the time was spent in Curl_multi_wait screeshot
CMAKE flags:
set(CMAKE_USE_LIBSSH2 ON)
set(CURL_ZLIB ON)
set(CMAKE_USE_OPENSSL ON)
set(BUILD_CURL_EXE ON)
set(CURL_STATICLIB ON)
EDIT2:
I compiled my code on both Ubuntu and Windows (GCC 10.1.0 and VS 2019 16.6.3), and both of them suffer from the same issue that using Libcurl is twice as slow than using the Curl binary I compile.

Related

Empty Content-Type in curl_easy_perform GET request

Kindly disregard this issue, the problems seems to lie in werkzeug.
I believe I have detected a problem with Content-Type for GET requests sent using curl_easy_perform, in libcurl version 7.29 (CentOS 7).
The problem is that the HTTP header Content-Type is present (with empty value) in the request:
Content-Type:
In Ubuntu 18.04, with libcurl 7.58, this problem doesn't occur (as expected the header is not present in the request). I've searched Changlogs but without finding anything about this assumed fix. I did find some mention of the very same bug fixed in the PHP-curl library.
So, my question is simply: is it true that this behaviour has been fixed somewhere between 7.29 and 7.58 ?
I just made a test implementation, as short as possible, to see the problem.
This is the entire code:
#include <stdio.h> // fprintf, ...
#include <stdlib.h> // exit
#include <curl/curl.h> // curl
#include <curl/curlver.h> // VERSION
int main(int argC, char* argV[])
{
CURL* curlP;
CURLcode cc;
printf("curl version: %s\n", LIBCURL_VERSION);
curlP = curl_easy_init();
if (curlP == NULL)
{
fprintf(stderr, "curl_easy_init failed: %s\n", curl_easy_strerror(cc));
exit(1);
}
curl_easy_setopt(curlP, CURLOPT_URL, "localhost:1028/accumulate");
cc = curl_easy_perform(curlP);
if (cc != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(cc));
exit(2);
}
curl_easy_cleanup(curlP);
return 0;
}
The code is edited in a file called get.c and I compile it like this:
gcc get.c -o get -lcurl
The test runs in CentOS 7 with libcurl 7.58 (that I installed manually under /usr/local).
I have a simple test program, an accumulator, written in python, listening to port 1028, recording all requests that enters, and that spits it out on receiving a request with the URL path /dump.
Here is the entire sequence:
kz#centos7:curlTest> gcc get.c -o get -lcurl
kz#centos7:curlTest> ./get
curl version: 7.58.0
kz#centos7:curlTest> curl localhost:1028/dump
GET http://localhost:1028/accumulate
Content-Length:
Host: localhost:1028
Accept: */*
Content-Type:
=======================================
kz#centos7:curlTest>
As can be seen in this test, the GET request (sent by get to the accumulator) includes HTTP headers Content-Length and Content-Type without value.
The exact same test in Ubuntu 18.04 looks like this:
kz#xps:libcurlTest> gcc get.c -o get -lcurl
kz#xps:libcurlTest> ./get
curl version: 7.58.0
kz#xps:libcurlTest> curl localhost:1028/dump
GET http://localhost:1028/accumulate
Accept: */*
Host: localhost:1028
=======================================
kz#xps:libcurlTest>
Note the absence of Content-Lengthand Content-Type.
Before implementing this little test program, I made numerous attempts to avoid the Content-Type, by setting it in its slist to "Content-Type:", without space, with one space and with two spaces after the colon. I also tried without colon and of course without adding it to the slist (in which case it comes with the default content-type). I also tried to tell libcurl that the request is a GET, don't remember the details of that call right now.
Now, the error is probably mine, as I have very little experience using libcurl. It's just strange that all is OK in Ubuntu but not in CentOS ...

how to build, install, and run curllib in c++

I'm trying to build, install, and run curllib in c++ on Windows 10 but locks up when the run starts. Here are steps:
Download curl-7.59.0.zip from https://curl.haxx.se/download.html
Extract to c:\opt\curl-7.59.0
Start Menu>Visual Studio 2015>Developer Command Prompt for VS2015
cd C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64
vcvars64.bat
cd c:\opt\curl-7.59.0\winbuild
nmake /f Makefile.vc mode=dll MACHINE=x64 DEBUG=yes
In VS2015, Project>Properties>Configuration Properties>VC++ Directories>Include Directories, add C:\opt\curl-7.59.0\builds\libcurl-vc14-x64-debug-dll-ipv6-sspi-winssl\include\curl
In VS2015, Project>Properties>Configuration Properties>C/C++>General/Additional Include Directories, add C:\opt\curl-7.59.0\builds\libcurl-vc14-x64-debug-dll-ipv6-sspi-winssl\include\curl
In VS2015, Project>Properties>Configuration Properties>Linker>Additional Dependencies, add C:\opt\curl-7.59.0\builds\libcurl-vc14-x64-debug-dll-ipv6-sspi-winssl\lib\libcurl_debug.lib
In VS2015, Project>Properties>Configuration Properties>Linker>General>Additional Library Dependencies, add C:\opt\curl-7.59.0\builds\libcurl-vc14-x64-debug-dll-ipv6-sspi-winssl\lib\libcurl_debug.lib
In VS2015, Project>Properties>Configuration Properties>Linker>Input>Additional Dependencies, add C:\opt\curl-7.59.0\builds\libcurl-vc14-x64-debug-dll-ipv6-sspi-winssl\lib\libcurl_debug.lib
Project>Properties>Platform shows Active(x64). Configuration: shows Active(Debug)
In VS2015, Project>Properties>Configuration Properties>C/C++>Preprocessor, add CURL_STATICLIB
In VS2015, Build>Clean Solution
In VS2015, Build>Rebuild Solution
The program runs but locks up. No error messages are written to the log file. In fact, it isn't even touched. If I comment out this line:
curl = curl_easy_init();
Then it will run. But of course then I don't have any access to curl which is the whole point.
Here is some code:
#include <curl.h>
vector<string> getDrawingNames(const string &projectName) {
logFile << "starting getDrawingNames" << endl;
vector<string> drwNames;
CURL *curl;
CURLcode res;
string readBuffer;
curl = curl_easy_init(); //DOESN'T LIKE THIS LINE
/*
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://www.google.com");
//curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
logFile << readBuffer << endl;
}
*/
return drwNames;
}
Any suggestions?

TLS version not set correctly, can't pull session info

RESOLVED
Build configuration error.
The officially "blessed" implementations of curl and OpenSSL on our system are woefully out of date (OpenSSL 0.9.8). All the applications I communicate with won't accept anything below TLS v1.2, so I had downloaded and built OpenSSL 1.1 and Curl 7.48 under my home directory.
However, even though I specified --with-ssl=/my/tools/ssl in the configure command for building Curl, it was still picking up the old version of libssl under /etc/lib.
I had to do the following to get everything to build Curl properly:
#
# make sure prefix in /my/tools/lib/pkgconfig/libcurl.pc is set to
# /my/tools
#
CFG_PACKAGE_PATH=/my/tools/lib/pkgconfig:$CFG_PACKAGE_PATH
CPPFLAGS="-I/my/tools/include"
LDFLAGS="-L/my/tools/lib/"
./configure --prefix=/my/local --with-ssl
After that, Curl properly linked against my local OpenSSL build and worked correctly.
ORIGINAL
Particulars-
OS: SLES 10
Compiler: g++ 4.1.2
libcurl: 7.48.0
OpenSSL: 1.0.21
We have a C++ application that's using libcurl to connect to a URL through OpenSSL. I'm getting an SSL connect error because, according to the admin of the remote site, we're trying to connect with TLS 1.0, which they have disabled. However, I'm explicitly setting the protocol to TLS version 1.2 in my code as follows:
if ( curl_easy_setopt( m_curlHandle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2 ) != CURLE_OK)
m_log.logv( LOG_ERR, "%s - Cannot set SSL version to TLS 1.2!", __PRETTY_FUNCTION__ );
I don't get the error message, so the SSL version should be set to TLS 1.2, but for some reason it gets sent out as TLS 1.0.
I'm trying to pull session information to try to verify that things are set the way I think, so I'm using the curl_easy_getinfo function, but it's returning an error code of CURLE_BAD_FUNCTION_ARGUMENT. I've gone over my call against the CURL documentation, and as far as I can tell I'm passing the things it expects.
Here's the meat of the code (not the exact code, but the order of operations and calls themselves reflect it accurately):
CURL *m_curlHandle;
...
curl_global_init( CURL_GLOBAL_ALL );
m_curlHandle = curl_easy_init( ) ;
curl_easy_setopt( m_curlHandle, CURLOPT_USERAGENT, "libcurl-agent/1.0" );
curl_easy_setopt( m_curlHandle, CURLOPT_SSL_VERIFYPEER, 1 );
curl_easy_setopt( m_curlHandle, CURLOPT_SSL_VERIFYHOST, 2 );
curl_easy_setopt( m_curlHandle, CURLOPT_POST, 1L );
curl_easy_setopt( m_curlHandle, CURLOPT_TIMEOUT, 60 );
curl_easy_setopt( m_curlHandle, CURLOPT_NOPROGRESS, 1L );
curl_easy_setopt( m_curlHandle, CURLOPT_ERRORBUFFER, &m_curlErrBuffer );
curl_easy_setopt( m_curlHandle, CURLOPT_WRITEFUNCTION, write_data );
curl_easy_setopt( m_curlHandle, CURLOPT_READFUNCTION, read_data );
curl_easy_setopt( m_curlHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1 );
...
if ( curl_easy_setopt( m_curlHandle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2 ) != CURLE_OK)
m_log.logv( LOG_ERR, "%s - Cannot set SSL version to TLS 1.2!", __PRETTY_FUNCTION__ );
...
struct curl_tlssessioninfo *session;
CURLcode result;
result = curl_easy_getinfo( m_curlHandle, CURLINFO_TLS_SSL_PTR, &session );
Based on the documentation here, I'm passing the right arguments to curl_easy_getinfo, so this is becoming especially frustrating.
Anyone have any ideas on a) how I can verify that I'm using TLS 1.2 or not on outgoing messages, and 2) how I can pull session information correctly?
Thanks in advance.

Getting cURL to work with Visual Studios 2017

*Edit: I got CURL working in VS 2017 on a 64 bit machine following these steps (see below for original problem):
First install vcpkg:
Clone vcpkg using gitbash into C:\Program Files
In a command prompt navigate to C:\Program Files\vcpkg
Run in the command prompt: .\bootstrap-vcpkg.bat
Run in the command prompt: vcpkg integrate install
Then use vcpkg and Visual Studios 2017 command prompt to install cURL:
Open a VS 2017 Command prompt and navigate to the vcpkg folder (where the vcpkg.exe is)
Run: vcpkg install curl[*]:x64-windows (note this can take around a half hour to download and run, don't worry if it looks like it is "stuck" at parts).
*Edit: previously my instructions said to run vcpkg install curl:x64-windows but I added on the [*] at the behest of #i7clock to enable sftp and scp protocols.
After this step, you should check to make sure that curl installed correctly. To do this you should create a new project in VS 2017 and try and include #include curl/curl.h without adding any additional include directories. If you cannot do this then something went wrong with your install of curl. You should remove curl (and perhaps even the vcpkg folder and do a clean install) until you can include curl/curl.h.
*Important Note: this will only work if you are using x64 debugger/compiling in x64! If you cannot include the curl directory check to make sure your debug is set to the correct version of Windows.
You may need to disable SSL peer verification as well:
Place the code curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE); before the request (see below). Note this is only necessary because I could not figure how to get certificates to work with curl. I have an as-of-yet unanswered stackoverflow post regarding this problem here.
Here are some other steps you may need to try to get things running, but I ended up finding them not necessary:
Navigate to vcpkg\packages\curl_x64-windows\lib to find the libcurl.lib file.
Include the path to libcurl.lib in Additional Library Directories under Properties -> Linker
Included libcurl.lib in Additional Dependencies under Linker -> Input -> Additional Dependencies
Place CURL_STATICLIB in Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions
Here is my now working code:
#include "curl/curl.h"
void testCurl() {
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
#ifdef SKIP_PEER_VERIFICATION
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
#endif
#ifdef SKIP_HOSTNAME_VERIFICATION
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
#endif
res = curl_easy_perform(curl);
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
curl_global_cleanup();
}
int main(){
testCurl();
return 0;
}
*Edit: Here is the rest of the explanation of my old problem before it was fixed:
I am trying to use cURL to make an API call so I can start getting real time stock data, but I am running into difficulties getting it to function in VS 2017. I have attempted an install using vcpckg using the following steps:
According to vcpkg documentation I should be able to now simply #include , but it can't find the folder. If I try including the "include" directory from vcpkg\packages\curl_x86\include and #include I can build my project. I can also access some of the classes, but if I try and set the curl_global_init(CURL_GLOBAL_DEFAULT) as in this example I get linker errors.
You've installed the x86 version of curl with vcpkg (That's the x86 in vcpkg\packages\curl_x86\include). You need to install the x64 version to match your project:
>vcpkg install curl:x64-windows
Here in 2021, on windows 10, using the current Visual Studio. vcpkg install curl[*]:x64-windows does not work. I get a BUILD_FAILED error. vcpkg install curl does work for me, and only takes ~30 seconds

c++ decrypt file downloaded from server

I'm new to this, so please bear with me..
I'm using the following function to download files from a web server.
This seems to work well without any major issues.
void downloadFile(const char* url, const char* fname) {
CURL *curl;
FILE *fp;
CURLcode res;
curl = curl_easy_init();
if (curl){
fp = fopen(fname, "wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
fclose(fp);
}
}
downloadFile("http://servera.com/file.txt", "filename.txt");
Some of the files that are on the server have been encrypted (by me) using openssl using a command similar to:
openssl aes-256-cbc -a -salt -in secrets.txt -out secrets.txt.enc
These files download fine, but I'd like to have them download and be written to their locations decrypted all by the download function.
Is that possible ? If so can someone help me work out how.
The password to decrypt the files will be saved in an array along with several other entries.
Any ideas ?
Thanks
Of course that's possible. The openssl command line tool just uses the libssl library internally to do the crypto.
You can do the same; I won't give an introduction to libssl here. I trust you can find the openssl homepage and read the relevant man pages yourself :).