I'm trying to use C++ cURL library for sending Json data via PUT method and my code looks something like this
CURL* m_curlHandle;
CURLcode m_returnValue;
//function1 start
curl_global_init(CURL_GLOBAL_ALL);
struct curl_slist* headers = NULL;
std::ostringstream oss;
struct curl_slist* slist = NULL;
slist = curl_slist_append(headers, "Accept: application/json");
slist = curl_slist_append(headers, "Content-Type: application/json");
slist = curl_slist_append(headers, "charsets: utf-8");
m_curlHandle = curl_easy_init();
if (!m_curlHandle)
// throw exception
curl_easy_setopt(m_curlHandle, CURLOPT_HTTPHEADER, headers);
//function1 end
//function2 start
std::string url = "some URL"; // my url
curl_easy_setopt(m_curlHandle, CURLOPT_URL, url.c_str());
unsigned int timeout = 5;
curl_easy_setopt(m_curlHandle, CURLOPT_TIMEOUT, timeout);
std::string localIp = "some IP"; // my IP address
curl_easy_setopt(m_curlHandle, CURLOPT_INTERFACE, localIp.c_str());
curl_easy_setopt(m_curlHandle, CURLOPT_CUSTOMREQUEST, "PUT");
std::string json = "some json struct"; //my json struct
curl_easy_setopt(m_curlHandle, CURLOPT_POSTFIELDS, json.c_str());
curl_easy_setopt(m_curlHandle, CURLOPT_WRITEFUNCTION, callbackWriter); //static size_t callbackWriter(char* buffer, size_t size, size_t nmemb, void* userp);
m_returnValue = curl_easy_perform(m_curlHandle);
//function2 end
I call function1 then function2 and the problem is that for all curl_easy_setopt calls I get error code 1685083487 and error description "Unknown error". So what may cause to a such result and how to fix this?
Thank you in advance!
I would use CURLOPT_POSTFIELDS instead, my func was something like this
void poolStr(const std::vector<unsigned char> &data, const std::string &url)
{
curl_global_init(CURL_GLOBAL_DEFAULT);
mCurl = curl_easy_init();
if(mCurl)
{
curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str());
curl_easy_setopt(mCurl, CURLOPT_POST, 1L);
curl_easy_setopt(mCurl, CURLOPT_POSTFIELDSIZE, data.size());
curl_easy_setopt(mCurl, CURLOPT_POSTFIELDS, &data[0]);
mChunk = curl_slist_append(mChunk, "Content-Type: application/binary");
mChunk = curl_slist_append(mChunk, "Expect:");
curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, mChunk);
CURLcode res = curl_easy_perform(mCurl);
if(res != CURLE_OK)
{
LOGERROR << "curl_easy_perform() failed: " << curl_easy_strerror(res) << "\n Attepmt number: " << attempt;
}
else
{
LOGINFO << "Data being sent.";
}
}
}
}
and calling like poolStr(data, mHost);
Related
I am working on a C++ program that uses cURL to "sign" into my Valorant account. The code works just fine in debug mode (Visual Studio 2019) but has an Invalid Parameter error when I switch to release mode. After doing some research I found that it was because of libcurl, but there were no fixes online. I am also using json and a small code snippet for base64 decoding, but I believe those are irrelevant. My project properties are whatever the default properties are, I even tried making a new project and copying my code over but got the same result.
Code:
#include <iostream>
#include "json.hpp"
#include <curl/curl.h>
#include <string>
#include <sstream>
#include "base64.hpp"
#include <stdio.h>
using json = nlohmann::json;
CURL* hnd = curl_easy_init();
size_t WriteCallback(char* contents, size_t size, size_t nmemb, void* userp)
{
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
void authCookies()
{
curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(hnd, CURLOPT_URL, "https://auth.riotgames.com/api/v1/authorization");
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "{\"client_id\":\"play-valorant-web-prod\",\"nonce\":\"1\",\"redirect_uri\":\"https://playvalorant.com/opt_in\",\"response_type\":\"token id_token\"}");
CURLcode ret = curl_easy_perform(hnd);
}
std::string getAuthToken(std::string username, std::string password)
{
std::string token = "";
curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "PUT");
curl_easy_setopt(hnd, CURLOPT_URL, "https://auth.riotgames.com/api/v1/authorization");
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);
std::string response;
json toSend = {
{"type", "auth"},
{"username", username},
{"password", password},
{"remember", false},
{"language", "en_US"}
};
std::string sendText = toSend.dump(4);
curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, sendText.c_str());
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &response);
CURLcode ret = curl_easy_perform(hnd);
json resp = json::parse(response);
//parse the uri and look for a token
std::string uri = std::string(resp["response"]["parameters"]["uri"]);
size_t loc = uri.find("#access_token=");
for (int i = loc + 14; i < uri.length(); i++)
{
if (uri[i] != '&') { token += uri[i]; }
else { break; }
}
return token;
}
void cookieReauth()
{
std::string response;
curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "GET");
curl_easy_setopt(hnd, CURLOPT_URL, "https://auth.riotgames.com/authorize?redirect_uri=https%3A%2F%2Fplayvalorant.com%2Fopt_in&client_id=play-valorant-web-prod&response_type=token%20id_token");
curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "");
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &response);
CURLcode ret = curl_easy_perform(hnd);
}
std::string getEntitlement(std::string token)
{
std::string out = "";
curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(hnd, CURLOPT_URL, "https://entitlements.auth.riotgames.com/api/token/v1");
struct curl_slist* headers = NULL;
std::string auth = "Authorization: Bearer " + token;
headers = curl_slist_append(headers, auth.c_str());
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "");
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &out);
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);
CURLcode ret = curl_easy_perform(hnd);
json resp = json::parse(out);
return std::string(resp["entitlements_token"]);
}
struct valorantUser
{
std::string displayName;
std::string puuid;
std::string name;
std::string tag;
};
std::vector<valorantUser> getUsersByPuuid(std::string token, std::string entitlement, json puuidList, std::string region)
{
std::vector<valorantUser> userList;
std::string response;
curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "PUT");
curl_easy_setopt(hnd, CURLOPT_URL, std::string("https://pd." + region + ".a.pvp.net/name-service/v2/players").c_str());
struct curl_slist* headers = NULL;
std::string auth = "Authorization: Bearer " + token;
std::string ent = "Entitlements: " + entitlement;
headers = curl_slist_append(headers, auth.c_str());
headers = curl_slist_append(headers, ent.c_str());
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);
std::string toSend = puuidList.dump();
curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, toSend.c_str());
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &response);
CURLcode ret = curl_easy_perform(hnd);
json resData = json::parse(response);
for (int i = 0; i < resData.size(); i++)
{
valorantUser dat;
dat.displayName = std::string(resData[i]["DisplayName"]);
dat.puuid = std::string(resData[i]["Subject"]);
dat.name = std::string(resData[i]["GameName"]);
dat.tag = std::string(resData[i]["TagLine"]);
userList.push_back(dat);
}
return userList;
}
std::string getTokenPuuid(std::string token)
{
std::vector<std::string> toks;
std::stringstream test(token);
std::string cur;
while (std::getline(test, cur, '.'))
{
toks.push_back(cur);
}
json decoded = json::parse(base64_decode(toks[1]));
return decoded["sub"];
}
int main()
{
curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(hnd, CURLOPT_COOKIEJAR, "");
authCookies(); //get auth cookies
std::string token = getAuthToken("username", "password"); //get auth token
cookieReauth(); //get more auth cookies
std::string entitlement = getEntitlement(token); //get entitlement token
std::string puuid = getTokenPuuid(token); //get user puuid from token
json puuidList = json::array({puuid});
valorantUser botData = getUsersByPuuid(token, entitlement, puuidList, "na")[0]; //get user name from puuid
std::cout << "Signed in as " << botData.name << "#" << botData.tag;
}
Thanks
Edit:
By commenting out all of my functions, the error stopped. If I remove the comment from even the authCookies() function, the error comes back. It is also very strange that the error does not appear until the end of the code.
int main()
{
curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(hnd, CURLOPT_COOKIEJAR, "");
/*
authCookies(); //get auth cookies
std::string token = getAuthToken("username", "password"); //get auth token
cookieReauth(); //get more auth cookies
std::string entitlement = getEntitlement(token); //get entitlement token
std::string puuid = getTokenPuuid(token); //get user puuid from token
json puuidList = json::array({ puuid });
valorantUser botData = getUsersByPuuid(token, entitlement, puuidList, "na")[0]; //get user name from puuid
std::cout << "Signed in as " << botData.name << "#" << botData.tag;*/
curl_easy_cleanup(hnd);
return 0;
}
When authCookies() is called, WriteCallback gets userp set to something that is (void*)stdout (default value if CURLOPT_WRITEDATA is not assigned). ((std::string*)userp)->append((char*)contents, size * nmemb); dereferences FILE* as std::string*.
Why do you cast char* contents to char*?
I would like to know how to get a JSON response with cURL. My current code doesn't work, it just returns an empty string. Any help would be greatly appreciated! I've included my current code below.
static 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 ipCheck(std::string ip)
{
nlohmann::json j;
CURL* curl;
CURLcode res;
std::string response;
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "Accept: application/json");
headers = curl_slist_append(headers, "Content-Type: application/json");
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://api.ipstack.com/" + ip + "?access_key=SECRET_KEY");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, response);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
if (response.empty()) {
std::cout << "\n\nInvalid request!";
_getch();
}
std::cout << response;
}
you have an error here :
curl_easy_setopt(curl, CURLOPT_WRITEDATA, response);
you are passing a temporary copy of std::string here instead of a pointer to the variable you expect to be passed to the callback so the original variable isn't touched ! worse : the callback is passed a dangling pointer which is the casted to std::string and operated on (undefined behavior) so expect to see strange things (usually crash)
I written a simple little code based around libcurl that sends a email to myself:
#include <cstdio>
#include <cstring>
#include <curl/curl.h>
static const char* payload_text[] = {
"To: " "<myemail#web.de>" "\r\n",
"From: " "<myemail#web.de>" " (Example User)\r\n",
"Cc: " "<myemail#web.de>" " (Another example User)\r\n",
"Message-ID: <dcd7cb36-11db-487a-9f3a-e652a9458efd#"
"rfcpedant.example.org>\r\n",
"Subject: Hello\r\n",
"\r\n",
"The body of the message starts here.\r\n",
"\r\n",
"Test.\r\n",
nullptr
};
struct upload_status {
int lines_read;
};
static size_t payload_source(void* ptr, const size_t size, const size_t nmemb, void* userp)
{
auto* const upload_ctx = static_cast<struct upload_status*>(userp);
if (size == 0 || nmemb == 0 || size * nmemb < 1) {
return 0;
}
const auto* const data = payload_text[upload_ctx->lines_read];
if (data) {
const auto len = strlen(data);
memcpy(ptr, data, len);
upload_ctx->lines_read++;
return len;
}
return 0;
}
int _stdcall WinMain(struct HINSTANCE__* hinstance, struct HINSTANCE__* hprevinstance, char* cmdline, int cmdshow)
{
auto res = CURLE_OK;
struct curl_slist* recipients = nullptr;
struct upload_status upload_ctx;
upload_ctx.lines_read = 0;
auto* const curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_USERNAME, "myemail#web.de");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret");
curl_easy_setopt(curl, CURLOPT_URL, "smtp://smtp.web.de:587");
curl_easy_setopt(curl, CURLOPT_USE_SSL, static_cast<long>(CURLUSESSL_ALL));
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, "<myemail#web.de>");
recipients = curl_slist_append(recipients, "<myemail#web.de>");
recipients = curl_slist_append(recipients, "<myemail#web.de>");
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
curl_slist_free_all(recipients);
curl_easy_cleanup(curl);
}
return static_cast<int>(res);
}
NOTE: thats not my password there in curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret");
The above code works. but i needs libcurl.dll and zlib1.dll
I would like it in a single .exe file
My question is.. Is that possible in c++, i know its possible in c# with using System.Net.Mail or something, or is there are alternative to my code that doesn't require external .dlls
I have POST request on python with a lot of settings, and I don't uderstand how their look like in curl.
data_str = '{' + '"username": "{}", "domain_id": {}, "password": {}'.format(login, domain_id, password) + '}'
try:
data = requests.post("https://example.com/v/session",
proxies=proxy,
verify=False,
data=data_str,
headers={"Content-Type": "application/json;charset=UTF-8",
"Accept": "application/json"})
if is_json(data.text):
print(data)
I find that url set parament CURLOPT_URL, headers - CURLOPT_HTTPHEADER. But how set proxy, verify, data ? How get json as in python ?
how to complete the code that it have the same result as in python:
CURL *curl = curl_easy_init();
struct curl_slist *list = NULL;
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
list = curl_slist_append(list, "Shoesize: 10");
list = curl_slist_append(list, "Accept:");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_perform(curl);
curl_slist_free_all(list); /* free the list again */
}
In order to get the return data from the curl request, we need a callback function for the CURLOPT_WRITEFUNCTION option.
The proxy, data, verify parameters should be set as following :
#include <iostream>
#include <string>
#include <curl/curl.h>
size_t curlWriter(void *contents, size_t size, size_t nmemb, std::string *s)
{
size_t newLength = size*nmemb;
try
{
s->append((char*)contents, newLength);
}
catch(std::bad_alloc &e)
{
//memory problem
return 0;
}
return newLength;
}
int main()
{
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(curl)
{
std::string strResponse;
std::string strPostData = "my data post";
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/v/session");
curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L);
//set the proxy
curl_easy_setopt(curl, CURLOPT_PROXY, "http://proxy.net");
curl_easy_setopt(curl, CURLOPT_PROXYPORT, 8080L);
//verify=False. SSL checking disabled
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
//set the callback function
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriter);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &strResponse);
/* size of the POST data */
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strPostData.length() );
/* pass in a pointer to the data - libcurl will not copy */
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPostData.c_str() );
/* Execute the request */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
{
std::cerr << "CURL error : " << curl_easy_strerror(res) << std::endl;
}else {
std::cout << "CURL result : " << strResponse << std::endl;
}
curl_easy_cleanup(curl);
}
}
I have the following code:
#define FROM "<example#gmail.com>"
#define TO "<example2#gmail.com>"
const char *payload_text[] = {
"Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n",
"To: " TO "\r\n",
"From: " FROM "(Example User)\r\n",
"Subject: SMTP TLS example message\r\n",
"MIME-Version: 1.0\r\n",
"Content-Type: multipart/mixed; boundary=\"KkK170891tpbkKk__FV_KKKkkkjjwq\"\r\n",
"\r\n",
"This is a multipart message in MIME format.",
"\r\n",
"--KkK170891tpbkKk__FV_KKKkkkjjwq\r\n",
"Content-Type: text/plain",
"\r\n",
"here goes the text message\r\n",
"\r\n",
"--KkK170891tpbkKk__FV_KKKkkkjjwq\r\n",
"Content-Type: image/jpeg; name=\"test.jpg\"\r\n",
"Content-Transfer-Encoding: base64\r\n",
"Content-Disposition: attachment; filename=\"test.jpg\"\r\n",
"\r\n",
NULL, /*19*/
"\r\n",
"--KkK170891tpbkKk__FV_KKKkkkjjwq--\r\n",
NULL
};
struct upload_status {
int lines_read;
};
static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp) {
struct upload_status *upload_ctx = (struct upload_status *)userp;
const char *data;
if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) {
return 0;
}
data = payload_text[upload_ctx->lines_read];
if(data) {
size_t len = strlen(data);
memcpy(ptr, data, len);
upload_ctx->lines_read++;
return len;
}
return 0;
}
std::string readFileToBase64(const char* filename) {
/* converts binary file to base64 */
}
std::string split76(std::string in) {
int lines = in.length() / 76;
for(int i=0;i<lines;i++) {
in.insert((i+1)*76+i*2, "\r\n");
}
return in;
}
int main(void) {
payload_text[19] = split76(readFileToBase64("C:\\Users\\thrymgjol\\code\\emailtest\\bin\\Release\\test.jpg")).c_str();
CURL *curl;
CURLcode res = CURLE_OK;
struct curl_slist *recipients = NULL;
struct upload_status upload_ctx;
upload_ctx.lines_read = 0;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_USERNAME, "example2#gmail.com");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "legitpassword");
curl_easy_setopt(curl, CURLOPT_URL, "smtp://smtp.gmail.com:587");
curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
recipients = curl_slist_append(recipients, TO);
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
curl_slist_free_all(recipients);
curl_easy_cleanup(curl);
}
return (int)res;
}
However, when I compile and run, payload_source() stops reading payload_text after the 18th indice. This completely cuts off my attachment, which I assign to payload_text[19]. Any ideas on why it does this?
The problem is the value returned from split76 is temporary and is destroyed after the assignment has completed. Any attempt to access it after that results in undefined behavior. If you need to store a pointer to the string buffer you can create local std::string to hold it an ensure it lives long enough to be used.
std::string encodedFile(split76(readFileToBase64("C:\\Users\\thrymgjol\\code\\emailtest\\bin\\Release\\test.jpg")));
payload_text[19] = encodedFile.c_str();