Libcurl - cookie authentication - c++

I want to avoid using the file system when using cookies with Libcurl...is that possible? It seems the documentation and examples all require the use of writing and reading cookies from files...maybe I'm wrong.
So far I'm doing something like this:
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postfield);
curl_easy_setopt(curl, CURL_HTTPAUTH, CURLAUTH_BASIC);
curl_easy_setopt(curl, CURLOPT_USERPWD, userpass);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
//writes the cookie to file sent from server
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, COOKIE_FILENAME);
curl_easy_perform(curl);
curl_easy_cleanup(curl);

http://curl.haxx.se/libcurl/c/cookie_interface.html That prints cookies and edits them as well without the use of the file system.
I've used that example myself to do the whole cookie modification thing.
Also useful that's not in the example:
curl_easy_setopt(curl, CURLOPT_COOKIE, "name=xxx; name2=xxx;");

Related

Issue trying to set up TTS service of IBM Watson using libcurl

I am trying to implement TTS service of IBM Watson using libcurl. I am sending the text "Hello World" and the voice to be synthesized will be "D:\log\Output.aac"
Setting up the CURLOPT_HTTPHEADER, CURLOPT_POSTFIELDS and CURLOPT_FILE is a bit of an issue for me as I am new to libcurl. How do I correctly set these fields? IBM Cloud service also reported error authenticating to my Watson service due use of deprecated of legacy credentials. I am lost, please help.
#include <curl/curl.h>
void Curl_Perform_TTS() {
CURL* curl;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "<url>/v1/synthesize?text=Hello%20world");
curl_easy_setopt(curl, CURLOPT_USERNAME, "Text to Speech-ej"); //not sure, I use service name here
curl_easy_setopt(curl, CURLOPT_PASSWORD, "<API key>");
//curl_easy_setopt(curl, CURLOPT_RETURNTRANSFER, true); //Don't work
curl_easy_setopt(curl, CURLOPT_POST, true);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "{\"Content-Type\":\"audio/flac\", \"Transfer-Encoding: chunked\"}");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"path\":\"D:\\log\"}");
curl_easy_setopt(curl, CURLOPT_FILE, "{\"Output.mp3\"}");
CURLcode result = curl_easy_perform(curl);
if (result != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(result));
}
curl_easy_cleanup(curl);
}
}
int main()
{
Curl_Perform_TTS();
return 0;
}
The main problem, I think, is that you are not forming the header properly.
Looking into libcurl documentation you can notice that for adding an HTTP Header
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HTTPHEADER, struct curl_slist *headers);
You must create first a struct curl_slist, and pass it as the argument for curl_easy_setopt. For example:
struct curl_slist *headerslist = NULL;
// .....
//and later when you need to add a header, do it in this way
headerlist = curl_slist_append(headerslist, "Content-Type: audio/flac");
//When you are done, clean the memory used by the linked list
//This should be done after performing the request of course
curl_slist_free_all(headerslist);
This could be one of your issues, the other one is related to CURLOPT_POSTFIELDS. Which have this interface to deal with it:
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_POSTFIELDS, char *postdata);
The documentation for this one is here. An example could be as simple as this
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "name=daniel&project=curl");
I think in general, this examples from the official documentation should help you to for the request correctly:
custom header
http post
simple post
And the list goes on. In case you need more examples, you could read all of them in here also

Using CURL in C++/C to issue a GET HTTP Request with a data file

Using the CURL at the command line:
curl -d #%1 -X GET https://blah-blah
This is in a Windows batch file and I pass the name of the file on the command line. Using this, I can issue a service call sending in a file with a whole lot of input parameters and I receive a substantial output.
For the life of me, when I try pro \grammatically, I can't make it work. It must be possible, since it can be done on the command. However, when I set
curl_easy_setopt(m_Curl, CURLOPT_HTTPGET, 1);
I can't upload a file, even if I set the callback
If I use:
curl_easy_setopt(m_Curl, CURLOPT_UPLOAD, 1L);
the call becomes 'PUT', even though I try and force the header to be a GET. I follow the documentation and can see that this is the documented behavior. However, what is the pathway for avoiding this default?
Any guidance would be most appreciated.
Thanks,
Stan
AFAIK it's not strictly forbidden but you shouldn't send a body with a GET request. On the other side a server should be able to handle a GET request with body but the response shouldn't be dependent of the content of the body.
If you really need to send a request containing a body with GET you can change the value of the method with CURLOPT_CUSTOMREQUEST. This won't change the behavior of curl. This snippet will upload data with GET:
CURL* curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_PORT, port);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
const auto* file = fopen(filename.c_str(), "r");
curl_easy_setopt(curl, CURLOPT_READDATA, file);
curl_easy_setopt(
curl, CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(filesize));
curl_easy_perform(curl);
}
You can also use the CURLOPT_POSTFIELDS command, to paste the body as a string. Afterwards you change the request to GET like in #Thomas Sablik s answer.
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
// Set target URL
curl_easy_setopt(curl, CURLOPT_URL, requestURL.c_str());
// Set HTTP version
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, (long) CURL_HTTP_VERSION_3);
// Set POST fields
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, requestBody.c_str());
// Set request to get
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
// Set response target
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
// Perform CURL request
CURLcode res = curl_easy_perform(curl);

HTTP POST with LibCurl

Sending POST request using libcurl C++. I have tried almost all combination except the right one which I could not figure out.
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE); /*Not Recommended to use but since certificates are not available this is a workaround added*/
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, FALSE); /*Not Recommended to use but since certificates are not available this is a workaround added*/
curl_easy_setopt(curl, CURLOPT_HTTPPOST, TRUE); //CURLOPT_POST does not work as well
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, sJson);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, bytesCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, bytesCallback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headBuffer);
sJson is a std::string which has the body that is created by pb2json.
I cannot figure out why the body is not sent ?
Is there some API i am missing if libcurl, any lead is appreciated !
I would prefer using custom request here CURLOPT_CUSTOMREQUEST below is the code snippet that works fine!
When you use custom requests nothing implies and you have to explicitly define the CURLOPT_HTTPHEADER
Use a list here, for brevity I have used the minimal code here.
Also when you pass sJson pass it as a c type string using c_str() and remember to use +1 while passing the content length (which I somehow missed initially) as in C, strings are just char arrays which, by convention, end with a NULL byte.
struct curl_slist* slist = NULL;
slist = curl_slist_append(slist, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, sJson.c_str()); /* data goes here */
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sJson.length() + 1); /* data goes here */
EDIT: Use of curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); might create problems in redirection, use it according to your use case.

curl_easy_perform: Couldn't resolve host name

I'm having a bit of an odd issue with libcurl - it's refusing to resolve a particular URL, returning the error message "Couldn't resolve host name." It has no issues resolving other hosts. I suspect the reason is that the URL which fails returns a 302 redirect, but I've set appropriate options for it to be followed.
The URL in question: http://servermods.cursecdn.com/files/922/48/worldedit-bukkit-6.1.3.jar
The relevant code:
CURL* curl;
FILE* data;
std::string url;
// ...
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_FILE, data);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
CURLcode res = curl_easy_perform(curl);
libcurl expects a char* for CURLOPT_URL. My code was passing a string. This essentially causes the library to misinterpret the string and fail to resolve the host.

C++ libcurl http response code issues

This issue/quirk/side-effect is driving me crazy. Near the bottom the code, the response code of the HTTP interaction is passed by reference into responseCode_. However it often comes out as 0 even though the site can otherwise be accessed, and returns too quickly to be a timeout...
All variables are defined, the code below is just a snippet of a C++ method in a class. Any var_ variables are instance based. It runs on several threads, but that should not be a problem. Each class that uses libcurl has its own instance on the respective threads.
Thanks in advance for any ideas or advice...
CURL *curl;
curl = curl_easy_init();
//The URL
curl_easy_setopt(curl, CURLOPT_URL, url.getURLString().c_str());
//Timeout
curl_easy_setopt(curl, CURLOPT_TIMEOUT, &timeout_);
//disable signals to use with threads
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
//Redirecting
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
//Writing callback
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &writerh);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &head_);
//Writing callback
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writerb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &body_);
//Headers
struct curl_slist *headers = NULL;
for (std::map<std::string, std::string>::iterator itr = requestHeaders_.begin(); itr != requestHeaders_.end(); itr++) {
std::stringstream header;
header << itr->first << ": " << itr->second;
headers = curl_slist_append(headers, header.str().c_str());
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
//UA
curl_easy_setopt(curl, CURLOPT_USERAGENT, "RDFaS-Bot/1.0 (+http://www.rdfas.com/bot)");
curl_easy_perform(curl); /* ignores error */
//Response code
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode_);
//clean headers
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
Update:
curl_easy_perform was not returning CURLE_OK when the response code was 0, as the marked answer explains. However debug hooks are very useful too and an excellent suggestion
The response code is only going to be set if curl_easy_perform() returns CURLE_OK so you should check that first to make sure curl actually performed the request successfully. Are you sure the callback functions for writing the header and body are set up correctly?
Also, make sure curl_global_init(CURL_GLOBAL_ALL) is called before these easy_perform threads start.
Assuming nothing in the curl handle returned by curl_easy_init() is shared across threads, then the code looks correct.
Use the debugging hooks built into libcurl.
Seriously. libcurl is a "C" nightmare of void*s and error codes. Everything can go wrong when using libcurl. Write your libcurl debugging hooks once and don't remove them from your code. You'll need them again, and again,... and again.