Related
I have a program that returns a long string from a curl request, the code is as follows:
#include <iostream>
#include <string>
#include <curl/curl.h>
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 main(void)
{
std::string s;
CURL* curl;
CURLcode res;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_URL, "www.ecobliss.co.za/run_student_query.php?query=Select%20*%20FROM%20data%20WHERE%20ID%20%3C%2030");
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
std::cout << s << std::endl;
struct curl_slist* headers = NULL;
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
res = curl_easy_perform(curl);
}
curl_easy_cleanup(curl);
//std::cout << s;
std::string arr[10000];
int i = s.find_first_of("ID");
//std::cout << i<<std::endl;
int ic = 0;
while (i>0) {
std::cout << i;
if (i > 0) {
arr[ic] = s.substr(i, i + 6);
s.erase(i,i+1);
int i = s.find_first_of("ID");
std::cout << i;
}
if (i < 0) {
break;
}
ic++;
}
for (ic = 0; ic < std::size(arr); ic++) {
std::cout << arr[ic];
}
return 0;
}
the output of the request in postman is:
<p>Results from your query:</p>
<br>{"ID":"26","datetime":"2022-03-13 03:21:07","temperature":"25.3","humidity":"80.9","pressure":"1020.2"}<br>{"ID":"27","datetime":"2022-03-13 05:12:47","temperature":"24.8","humidity":"82.1","pressure":"1020.5"}<br>{"ID":"28","datetime":"2022-03-13 05:29:05","temperature":"24.9","humidity":"83.6","pressure":"1020.5"}<br>{"ID":"29","datetime":"2022-03-13 05:29:07","temperature":"24.9","humidity":"83.8","pressure":"1020.5"}
I have tried to use string handling and extract the value the ID part holds, but it does not work at all, can someone please help.
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 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'm trying to upload a file to an http server. I'm getting the 200 OK from the server, but the code below is only transmitting 4 bytes.
size_t myclass::read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
{
handler->read(buffer, buffer_size); // buffer_size is 100000
size_t res = handler->gcount();
if( res == 0 )
return 0;
ptr = buffer; // buffer is array of char, defined in myclass
size = res;
nmemb = sizeof(char);
return 1;
}
void myclass::upload_function(const std::string& url)
{
CURL *curl;
CURLcode res;
std::ifstream if_file;
if_file.open("/path_to_file", std::ios::binary);
handler = &if_file; // handler is defined in myclass
/* In windows, this will init the winsock stuff */
res = curl_global_init(CURL_GLOBAL_DEFAULT);
/* Check for errors */
if(res != CURLE_OK) {
// failure
return;
}
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "hostname");
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, myclass::read_callback);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
struct curl_slist *chunk = NULL;
chunk = curl_slist_append(chunk, "Transfer-Encoding: chunked");
chunk = curl_slist_append(chunk, "Content-Type: application/x-mpegURL");
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK) {
// failed
}
else
{
double speed_upload, total_time;
curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &speed_upload);
curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
fprintf(stderr, "Speed: %0.3f b/sec during %.3f seconds\n",
speed_upload, total_time);
}
/* always cleanup */
curl_easy_cleanup(curl);
}
curl_global_cleanup();
if_file.close();
}
The callback doesn't seem to copy data to the buffer. It just assigns the local pointer, quite without any effect.
The callback looks like to be a C++ method that can't be used like that as a callback in a C API that doesn't know about C++ objects...
I have used the following code to get to download all the files from the FTP Server
Steps followed are:
1. Creating a FTP list of File
getFTPList(string sHost, string sUser, string sPass, string sUri)
{
CURL *curl;
CURLcode res;
FILE *ftplister;
string host = "ftp://";
host += sHost;
host += "/sample/";
string furl = host + sUri;
string usrpwd = sUser;
usrpwd += ":";
usrpwd += sPass;
/* local file name to store the file as */
ftplister = fopen("ftp-list", "wb"); /* b is binary, needed on win32 */
curl = curl_easy_init();
if(curl) {
/* Get a file listing from sunet */
curl_easy_setopt(curl, CURLOPT_URL, furl.c_str() );
curl_easy_setopt(curl, CURLOPT_USERPWD, usrpwd.c_str());
curl_easy_setopt(curl, CURLOPT_FTPLISTONLY, TRUE);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_list);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, ftplister);
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
fclose(ftplister); /* close the local file */
}
Use this list to download the files calling the download functions recursively
int main(){
FILE *ftpfile;
string line;
ftpfile = fopen("ftp-list", "r");
ifstream infile("ftp-list");
while ( getline(infile, line) )
{
string url, ofname, surl = "ftp://myhost/uploader/", sfname = "C:\\CNAP\\";
url = surl + line;
ofname = sfname +line;
cout<<url<<" "<<ofname<<endl;
char* theVal ;
char* theStr ;
theVal = new char [url.size()+1];
theStr = new char [ofname.size()+1];
strcpy(theVal, url.c_str());
strcpy(theStr, ofname.c_str());
downloadFile(theVal, theStr);
}
return 0;
}
Now the download function:
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t written;
written = fwrite(ptr, size, nmemb, stream);
return written;
}
void downloadFile(const char* url, const char* ofname)
{
CURL *curl;
FILE *fp;
CURLcode res;
curl = curl_easy_init();
if (curl){
fp = fopen(ofname,"wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_USERPWD, "user:pass");
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);
}
}
It works well when implemented but only to download text files or some files with texts, if I download an image or a docx or a a zip or rar or for that matter any file which is not text it fails, it fails to open after downloading (says invalid file).
I am not sure what am I missing, any help would be appreciated.
I know this is an inefficient way of coding, but I just need the downloads to be right (any file). Working on the efficiency is my next agenda.
PS: Used this method used here
Downloading multiple files with libcurl in C++
Thank you
The file when downloading needs to be opened as a binary file
fp = fopen(ofname,"wb");
Thank you for the help Rob
This is a guess.:
Try clearing the options CURLOPT_TRANSFERTEXT and CURLOPT_CRLF.
Refernce:
http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
#include <stdio.h>
#include <curl/curl.h>
#include <curl/easy.h>
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream);
void getFileList(
const string &strHost,
const string &strUri,
const string &strUser,
const string &strPassWord,
const string &strTargetFile
);
void downloadAllFiles(
const string &strFtpListFile,
const string &strHost,
const string &strUri,
const string &strUser,
const string &strPassWord,
const string &strSaveTargetFolder
);
int main(void)
{
string strHost = "ftp://192.168.0.1:22";
string strUri = "/cobus/test/";
string strUser = "cobus";
string strPassWord = "password";
string strTargetFile = "c:\\cobus\\ftpList.txt";
string strSaveDestFolder = "c:\\cobus\\";
getFileList(strHost, strUri, strUser, strPassWord, strTargetFile);
downloadAllFiles(
strTargetFile,
strHost,
strUri,
strUser,
strPassWord,
strSaveDestFolder
);
}
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
size_t written = fwrite(ptr, size, nmemb, stream);
return written;
}
void getFileList(const string &strHost, const string &strUri,
const string &strUser, const string &strPassWord, const string &strTargetFile)
{
CURL *curl;
CURLcode res;
FILE *ftplister;
string strSourceFullUri = strHost + strUri;
string strUserPwInfo = strUser + ":" + strPassWord;
/* local file name to store the file as */
ftplister = fopen(strTargetFile.c_str(), "wb"); /* b is binary, needed on win32 */
curl = curl_easy_init();
if(curl)
{
/* Get a file listing from sunet */
curl_easy_setopt(curl, CURLOPT_URL, strSourceFullUri.c_str() );
curl_easy_setopt(curl, CURLOPT_USERPWD, strUserPwInfo.c_str());
curl_easy_setopt(curl, CURLOPT_FTPLISTONLY, TRUE);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, ftplister);
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
fclose(ftplister); /* close the local file */
}
void downloadAllFiles(const string &strFtpListFile, const string &strHost,
const string &strUri, const string &strUser, const string &strPassWord,
const string &strSaveDestFolder)
{
FILE *ftpFile = NULL;
string strFileName = "";
ifstream infile(strFtpListFile.c_str());
if(!infile.is_open())
{
cerr << "can not open ftpList.txt" << endl;
return ;
}
/* ftpList.txt get data, line by line, processing */
while(getline(infile, strFileName))
{
CURL *curl;
FILE *destFilePath;
CURLcode res;
curl = curl_easy_init();
if (curl)
{
destFilePath = fopen((strSaveDestFolder+strFileName).c_str(),"wb");
curl_easy_setopt(curl, CURLOPT_URL, (strHost+strUri+strFileName).c_str());
curl_easy_setopt(curl, CURLOPT_USERPWD, (strUser+":"+strPassWord).c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, destFilePath);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
fclose(destFilePath);
}
}// end while
}
I expressed as much as possible to see at once the contents of the Vivian Lobo.
I tried to test to make statements Vivian Lobo. It is good working.
stackOverFlow is hard to write code.
And how can I comment to Vivian lobo article?