How to pass variable with URL to libcurl - c++

I have this line:
curl_easy_setopt(curl, CURLOPT_URL, "https://bk-bestgamer.ru/get.php?get=hello");
it works fine. i send request and receive a line that contains text "hello" from my site.
but when i do like this
std::string url;
std::cin >> url;
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());`
after that, when i use
curl_easy_perform(curl);`
i have an error
"protocol https not supported or disabled in libcurl".
i tried to do following
char url[] = "https://bk-bestgamer.ru/get.php?get=hello";
curl_easy_setopt(curl, CURLOPT_URL, url);`
it doesn't work with the same error.
i really do not know what to do.
i found some recommendations there
URL Variable passing into Curl
you can see, i tried that, but it doesn't succeed.
i've tried to compile the same code in ubuntu, where i have libcurl with ssl. but it doesn't work with the same error. from linux command line it works correctly.

Related

C++ libcurl headers - not recognised by server

I'm working in C++ with libcurl writing a program to interact with some APIs and I'm stuck when it comes to adding authentication info in the headers. I am new to libcurl and APIs with a basic knowledge of C++. Authentication requires an API key and a nonce hashed with HMAC_SHA256, each of which is then placed in the headers. A very simple JSON message is then sent. I've tried searching through this site but most examples seem to be in javascript or command line, and I don't see any relevant answers in them.
When I send my POST message to the server, I get a response 402 - Invalid ApiKey. My API key is 100% correct so I suspect it's something to do with the formatting or the way I've included it in the header. The site is BlinkTrade and their documentation is here, which gives some info about the header requirements.
Code snippet below:
char* message="{\"MsgType\": \"U2\",\"BalanceReqID\": 1}";
curl_easy_setopt(curl, CURLOPT_URL, "https://api.blinktrade.com/tapi/v1/message");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, pFile2);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, message);
struct curl_slist *header = NULL;
header = curl_slist_append(header, "APIKey:0000000000000000000000000000000000000000");
header = curl_slist_append(header, "Nonce:1");
header = curl_slist_append(header, "Signature:1");
header = curl_slist_append(header, "Content-Type:application/json");
transfer = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
cout << transfer << endl;
transfer = curl_easy_perform(curl);
cout << transfer << endl;
And I get the return code 0 for curl_easy_setopt and curl_easy_perform. I've swapped the actual characters from the API key for a load of 0's, but otherwise everything is the same in terms of formatting etc. I've not actually used a hashed signature, I'll do that after I can sort out this error. I've tried adding a space after the colon and enclosing string and/or value in double quotes but I get the same response. What am I doing wrong that means my headers aren't actually recognised by the server?
Solved: the Blinktrade server returns "Invalid APIKey" not when your API key is incorrect, but when the signature is incorrect. A rather annoying mislabelling.

C++ curl could not resolve host if URL is provided as argument

I am building a small application which needs to do get requests to an API.
I use libcurl which works great if I provide the complete URL directly within the function, but if I do it inside of a function with the URL as a parameter it fails instantly with the error CURLE_COULDNT_RESOLVE_HOST(6).
So I know it's not a DNS problem since I can resolve it if I provide the URL directly.
Here is my current function.
std::string winget(std::string url)
{
CURL *curl;
CURLcode res;
std::string readBuffer;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
return readBuffer;
}
//and I call it like this :
winget("example.org");
Basically if I directly replace the url param in the function with "example.org" it works. So I don't really know what to do with it.
Thanks a lot in advance. :)
Found the solution here: URL Variable passing into Curl
Basically you need to provide the URL as a null-terminated string. So if the parameter is a string, use .c_str() or get a char* from that string.

C++ curl POST for LiFx Control

I'm using curl with c++ to list all the bulbs successfully
curl_easy_setopt(curl,CURLOPT_USERNAME, MY_API_key);
curl_easy_setopt(curl, CURLOPT_URL, "https://api.lifx.com/v1beta1/lights/all/");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &Data);
res = curl_easy_perform(curl);
To toggle power to all light the documentation http://developer.lifx.com/#toggle-power says to use
curl -u "c87c73a896b554367fac61f71dd3656af8d93a525a4e87df5952c6078a89d192:" -X POST "https://api.lifx.com/v1beta1/lights/all/toggle"
I've tested this via the pre-built curl binary it works fine. I can't figure out how to construct the POST format in the C++ code.
curl_easy_setopt(curl,CURLOPT_USERNAME, MY_API_key);
curl_easy_setopt(curl,CURLOPT_POST,"https://api.lifx.com/v1beta1/lights/all/toggle");
curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER, FALSE);
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl,CURLOPT_WRITEDATA, &Data);
res = curl_easy_perform(curl);
However, res returns CURLE_URL_MALFORMAT, I think this is because I haven't set the CURLOPT_URL property... but I'm not sure what it needs to be set to.
I tried using a similar format to this PHP question (PHP HTTP CURL PUT request for LIFX Power On/Off) but with no luck, it still returns CURLE_URL_MALFORMAT.
CURLOPT_POST is wrongly used there. It should be set to 0 or 1 only. You set the URL with CURLOPT_URL.
You could use --libcurl sample.c added to your (working) curl command line to get a good sample source code to start from.
To mimic that command line closer, you can probably skip CURLOPT_POST and just have CURLOPT_CUSTOMREQUEST set to "POST"

libcURL and Google Docs

I'm trying to download a file needed for my application off the internet (as part of installation) so that the first time the app starts up, the needed files get downloaded. For now I'm putting them on Google Drive and making them public, then I'm going to use libcURL to download them. The problem is, I just can't get the data.
I use the following link: https://docs.google.com/uc?id=documentID&export=download and replace documentID with the id. When I try connecting to the site though, it keeps giving me a small snippet of HTML code that basically says "Moved Temporarily" and gives me a link to the new URL. When I use the new link in my program, I get no output whatsoever. However, both links work just fine in my web browser, even when I'm not signed in. So Why don't they work in my program? Am I not setting up SSL options correctly, or is Google Drive simply not meant for this kind of thing?
Here's my code:
#include <curl/curl.h>
int main()
{
curl_global_init(CURL_GLOBAL_ALL);
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "https://docs.google.com/uc?id=documentID&export=download");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
}
curl_easy_cleanup(curl);
return 0;
}
Any help would be appreciated.
You'll need to set the CURLOPT_FOLLOWLOCATION option to tell cURL to follow redirects.
I do not know if this helps directly but I have always made the call
curl_global_init(CURL_GLOBAL_ALL);
which I see you don't use. I have seen this call made here in the threaded SSL code example http://curl.haxx.se/libcurl/c/threaded-ssl.html. This `curl_global_init() call will perform SSL initialisation amongst other things. It is discussed in this link http://curl.haxx.se/libcurl and also in the libcurl tutorial here http://curl.haxx.se/libcurl/c/libcurl-tutorial.html

Using libcurl & SSL

I've found there is really very little information around on this topic. I already have a dll making successful posts using libcurl.
I've compiled libcurl with openssl for ssl functionality.
Here is an exert of my original curl setup.
curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errorBuffer);
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER , 1);
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST , 1);
//curl_easy_setopt(curl, CURLOPT_CAINFO , "./ca.cert");
curl_easy_setopt(handle, CURLOPT_POSTFIELDS, cParam);
curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, strlen(cParam));
curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, Request::writer);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &buffer);
curl_easy_setopt(handle, CURLOPT_URL, cURL);
My question to those who've done this before, is it as easy as just adding those lines above to get SSL to work (as long as the certificate exists)? Or is it more complicated?
The funny thing is I'm not completely sure how SSL works. I've never worked with it before. Do I need to store a key in my application and send it with each request? Anyway my main question was the first. Thank you in advance.
Yes, it is that simple. Just make sure that the "ca.cert" file you have is a true CA cert that can verify your server's certificate.
All you need to do to use SSL with libcurl is give an https url instead of an http url. The only option you need to set with curl_easy_setopt is CURLOPT_URL, although it will just print the received data to stdout if you don't specify a write callback.
CURL *handle = curl_easy_init();
char url[] = "https://google.com";
curl_easy_setopt(handle, CURLOPT_URL, url);
curl_easy_perform(handle);
Make sure that when using CURLOPT_SSL_VERIFYHOST you set the actual value to 2L (which is the default) instead of 1 (as shown as a comment in that example), if you really want to check the hostname matches, otherwise it would just check for the existence of a "Common name" (CN) in the certificate.