curl_easy_setopt(curl, CURLOPT_URL, "127.0.0.1:8081/get.php");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,"pulse=70 & temp=35" );
this above code run successfully but when I pass this
int pulsedata = 70;
int tempdata = 35;
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "pulse=pulsedata & temp = tempdata");
when I run this above line it give me error
how can I pass this pulsedata and tempdata ??
A possible C solution:
char sendbuffer[100];
snprintf(sendbuffer, sizeof(sendbuffer), "pulse=%d&temp=%d", pulsedate, tempdata);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, sendbuffer);
You can't use variable in strings like that, you have to format the string.
A possible C++ solution might be to use std::ostringstream like this:
std::ostringstream os;
os << "pulse=" << pulsedata << "&temp=" << tempdata;
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, os.str().c_sr());
With this solution, the std::ostringstream object (os in my example) needs to be alive until the CURL calls are all done.
Also note that the query-string I construct does not contain any spaces.
Related
I am using a portaudio callback where I receive periodically a buffer of audio and store it on main_buffer. I only set the settings bellow for curl and only use the CURLOPT_POSTFIELDS to set the float buffer before sending it with curl_easy_perform. On the server side I am using python django:
float main_buffer[256];
url_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, URL);
//portaudio periodic callback
callback(){
//...
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, main_buffer);
curl_easy_perform(curl);
}
The request received in server has no content inside body. How to send main_buffer the right way ?
Thank you !
What you need to do is to serialise the data that you send, and then deserialise what you receive. There is no "the right way". There are several ways with different advantages.
In your case, I recommend starting with a simple way. Simplest portable way to serialise floating point is to use textual encoding. A commonly used textual format that can represent arrays is JSON. For example, the array float[] main_buffer{1.0f, 1.5f, 2.0f} could be encoded as [1.0,1.5,2.0].
The reading part in Python is quite simple:
json.loads(request.body.decode('utf-8'));
The writing part in C++ is a bit more complex. There is no standard way to encode JSON in C++. You can use a full encoder based on the specification, or you could write an ad-hoc loop for this specific case:
std::stringstream ss;
ss << '[';
const char* separator = "";
for (float f : main_buffer) {
ss << separator << f;
separator = ",";
}
ss << ']';
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ss.str().c_str());
curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
What I want to do is to perform CURL request with parameters and values by using GET method but using JSON.
I'm trying to perform the following:
curl -X GET \
-H "X-Parse-Application-Id: 12345_Example" \
-H "X-Parse-REST-API-Key: abcde_Example" \
-G \
--data-urlencode "where={ \"pin\":\"A string\" }" \
https://urlExample/classes/Pins
as you can see the where URL parameter constraining the value for keys should be encoded JSON.
This is my code:
std::size_t callback(
const char* in,
std::size_t size,
std::size_t num,
char* out)
{
std::string data(in, (std::size_t) size * num);
*((std::stringstream*) out) << data;
return size * num;
}
public: Json::Value query(const char* serverAddress, const char* applicationId, const char* restAPIKey) {
CURL* curl = curl_easy_init();
curl_slist* headerlist = NULL;
headerlist = curl_slist_append(headerlist, applicationId);
headerlist = curl_slist_append(headerlist, restAPIKey);
// Set HEADER.
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
// Set remote URL.
curl_easy_setopt(curl, CURLOPT_URL, serverAddress);
// Don't bother trying IPv6, which would increase DNS resolution time.
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
// Don't wait forever, time out after 10 seconds.
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
// Follow HTTP redirects if necessary.
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
// Response information.
int httpCode(0);
std::stringstream httpData;
// Hook up data handling function.
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
// Hook up data container (will be passed as the last parameter to the
// callback handling function). Can be any pointer type, since it will
// internally be passed as a void pointer.
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &httpData);
// Run our HTTP GET command, capture the HTTP response code, and clean up.
curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
curl_easy_cleanup(curl);
if (httpCode == 200) {
// Response looks good - done using Curl now. Try to parse the results.
Json::Value jsonData;
Json::CharReaderBuilder jsonReader;
std::string errs;
if (Json::parseFromStream(jsonReader, httpData, &jsonData, &errs)) {
return jsonData["results"];
}
else {
std::cout << "Could not parse HTTP data as JSON" << std::endl;
std::cout << "HTTP data was:\n" << httpData.str() << std::endl;
return NULL;
}
}
else {
std::cout << "Couldn't GET from " << serverAddress << " - exiting" << std::endl;
return NULL;
}
}
What should I include in my code in order to perform the GET method with encoded JSON?
According to the documentation of the Server API I'm using, when reading objects, this is what it says for curl:
back4app API Reference
READING OBJECTS:
To retrieve an object, you'll need to send a GET request to its class
endpoint with your app's credentials in the headers and the query
parameters in the URL parameters. This task can be easily accomplished
just by calling the appropriated method of your preferred Parse SDK.
Please check how to do it in the right panel of this documentation.
Request URL https://parseapi.back4app.com/classes/Pins
Method GET
Headers X-Parse-Application-Id:
BCrUQVkk80pCdeImSXoKXL5ZCtyyEZwbN7mAb11f
X-Parse-REST-API-Key: swrFFIXJlFudtF3HkZPtfybDFRTmS7sPwvGUzQ9w
Parameters A where URL parameter constraining the value for keys. It
should be encoded JSON.
Success Response Status 200 OK
Headers content-type: application/json;
Body a JSON object that contains a results field with a JSON array
that lists the objects.
EDIT:
Based on: Daniel Stenberg's answer I tried the following:
std::string temp = "where={ \"pin\":\"A string\" }";
char* encoded = curl_easy_escape(curl, temp.c_str(), temp.length());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, std::strlen(encoded));
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, encoded);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
But no success. Should libcurl update their API and include such a feature for this case?
OK -- I am going to answer this one more time. This time correctly. I glossed over the fact that you posted the documentation in your question. Totally skipped it. No idea why my brain does that. Maybe it hates documentation and instinctively skips it.
So, the answer to your question is quite simple.
Keep your original code that's in your question (totally ignore the code that you posted in your Edit, it's totally wrong), but instead of doing this:
curl_easy_setopt(curl, CURLOPT_URL, serverAddress);
Do this:
const std::string whereQuery(curl_easy_escape(curl, "{ \"pin\":\"A string\" }", 0));
const std::string url("https://parseapi.back4app.com/classes/Pins?where=" + whereQuery);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
Sorry for dragging that out. I need to read questions better.
I'm trying to load the contents of this URL in order to send an SMS;
https://app2.simpletexting.com/v1/send?token=[api key]&phone=[phone number]&message=Weather%20Alert!
Using this bit of code implementing libcurl:
std::string sendSMS(std::string smsMessage, std::string usrID) {
std::string simplePath = "debugOld/libDoc.txt";
std::string preSmsURL = "https://app2.simpletexting.com/v1/send?token=";
std::cout << "\n" << getFile(simplePath) << "\n";
std::string fullSmsURL = preSmsURL + getFile(simplePath) + "&phone=" + usrID + "&message=" + smsMessage;
std::cout << fullSmsURL;
//Outputs URL contents into a file
CURL *curl;
FILE *fd;
CURLcode res;
char newFile[FILENAME_MAX] = "debugOld/noSuccess.md";
curl = curl_easy_init();
if (curl) {
fd = fopen(newFile, "wb");
curl_easy_setopt(curl, CURLOPT_URL, fullSmsURL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fd);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
fclose(fd);
}
}
I've used pretty much this exact code before to save the JSON contents of a URL to a file, although I'm trying something a bit different here.
This URL will actually send an SMS when visited. When using curl in a cli, I have no problem doing this. Although from C++, it doesn't treat anything as a error, just perhaps the actual function to send the sms isn't being actuated in the same way it would had I visited the URL physically.
I've scoured google for some kind of a solution to no avail. Perhaps I'm too novice to curl to know exactly what to search for.
Edit #1: getFile function
//Read given file
std::string getFile(std::string path) {
std::string nLine;
std::ifstream file_(path);
if (file_.is_open()) {
while (getline(file_, nLine)) {
return nLine;
}
file_.close();
}
else {
std::cout << "file is not open" << "\n";
return "Error 0x000001: inaccesable file location";
}
return "Unknown error in function 'getFile()'"; //This should never happen
}
This line is wrong:
curl_easy_setopt(curl, CURLOPT_URL, fullSmsURL);
CURLOPT_URL expects a char* pointer to null-terminated C string, not a std::string object. You need to use this instead:
curl_easy_setopt(curl, CURLOPT_URL, fullSmsURL.c_str());
Also, you are not performing any error checking on the return values of getFile(), fopen(), or curl_easy_perform() at all. So, your code could be failing in any one of those places and you would never know it.
Thanks to #Mat 's comment i got the solution:
I replaced
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, cQuery);
with
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(cQuery));
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, cQuery);
i am currently struggling at a more or less strange problem which drives me nuts.
I am using the following code to create the value i want to use for CURLOPT_POSTFIELDS to perform a CURL request.
string query;
map<string, string> parameters = resource->GetParameters();
typedef std::map<std::string, std::string>::iterator it_type;
int i = 0;
for (it_type iterator = parameters.begin(); iterator != parameters.end(); iterator++, i++) {
if (i > 0)
query.append("&");
query = query.append(iterator->first).append("=").append(iterator->second);
}
curl_easy_setopt(curl, CURLOPT_POST, true);
const char *cQuery = query.c_str();
cout << cQuery << endl;
cout << "grant_type=client_credentials&scope=default" << endl;
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, cQuery);
The output of both cout are:
grant_type=client_credentials&scope=default
grant_type=client_credentials&scope=default
If I am using the cQuery variable as the value, the server is responding that i didnt specify the grant type.
If I am replacing
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, cQuery);
with
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "grant_type=client_credentials&scope=default");
it works fine.
My background is more Java and C# related, so i am assuming i missunderstand some of the c++ basics. I am also a newbie on stackoverflow, so if i am doing sth. wrong please let me know.
I am looking forward to your answers. Thank you for your help.
Thanks to #Mat 's comment i got the solution:
I replaced
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, cQuery);
with
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(cQuery));
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, cQuery);
So I have a C++ application that takes a value from a key in a settings.INI file, uses libcurl to reach out to a PHP page, post that data, and it should return some different data.
And it actually works, aside from grabbing the data from the INI file. If I explicitely type in for the POSTFIELDS option for libcurl (e.i.: "Serial=454534" , instead of the variable storing the data that it retrived from my file).
Here's some code..
PHP:
<?
include("DBHeader.inc.php");
$Serial= $_POST['Serial'];
$sql = "SELECT * FROM `LockCodes` WHERE `sLockCode`=\"$Serial\"";
$RS=mysql_query($sql, $SQLConn);
$num_rows=mysql_num_rows($RS);
if ($num_rows>0)
{
while ($row = mysql_fetch_array($RS))
{
echo $row['iLockCodeID'];
}
}
else
{
echo "...";
}
?>
Snippet of C++ code:
TCHAR szKeyValue[36];
GetPrivateProfileString(_T("Test"), _T("LockCode"), _T(""), szKeyValue, 36, _T("C:\\Test\\Settings.INI"));
CString sLockCode = szKeyValue;
CURL *curl;
CURLcode res;
CString Serial = _T("Serial=") + sLockCode;
string LCID;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "http://regserver2.nyksys.com/GetLCID.php");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, Serial);
res = curl_easy_perform(curl);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeCallback);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
if (data == _T("..."))
{
data = "0";
AfxMessageBox("Invalid Serial Number");
exit(0);
}
My Settings.INI is in the standard format..
[Test]
LockCode=1D4553C7E7228E462DBAAE267977B7CDED8A
What happens is whenever I use the variable "Serial" instead of typing it in, the PHP page returns "..." instead of the desired result.
I feel like I'm missing something obvious. Any help would be TREMENDOUSLY appreciated.
I am guessing that you have _UNICODE defined, which means that TCHAR is wchar_t, CString is CStringT<wchar_t>, and the code:
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, Serial);
actually passes a wide char string to curl_easy_setopt() when the function is expecting a narrow char string. If your machine is little Endian, then curl_easy_setopt() interprets the parameter as the string "S\x00e\x00r\x00i\x00... (on a Big Endian machine, it's "\x00S\x00e\x00r\x00i...) and because curl_easy_setopt() will use strlen() when CURLOPT_POSTFIELDSIZE is not set, the entire POST request body on a little Endian machine is S. See, for example, http://codepad.org/JE2MYZfU
What you need to do is use narrow char strings:
#define ARRAY_LEN(arr_id) ((sizeof (arr_id))/(sizeof ((arr_id)[0])))
char szKeyValue[36];
GetPrivateProfileStringA("Test", "LockCode", "", szKeyValue, ARRAY_LEN(szKeyValue), "C:\\Test\\Settings.INI");
CURL *curl;
CURLcode res;
CStringT<char> Body = CStringT<char>("Serial=") + szKeyValue;
string LCID;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "http://regserver2.nyksys.com/GetLCID.php");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, Body);
res = curl_easy_perform(curl);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeCallback);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
//...
Also, your PHP script looks vulnerable to SQL injection.
EDIT: One more thing. Are you setting CURLOPT_POST to 1?
curl_easy_setopt(curl, CURLOPT_POST, 1);