For the life of me I cannot get this to work. I have not been able to find example code for v3 of the Bittrex API so I have patched together what I've found for v1.1 and v3 in other programming languages.
I am using curl and openssl libraries.
I am getting a "URL using bad/illegal format or missing URL" error.
#include "../curl/curl.h"
#include <sha512.hh>
#include "hmac.h"
#include "sha.h"
string bittKey, bittSecret;
string timeStamp, hTTPMethod, uRI, requestBody, contentHash;
CURL *curl;
CURLcode res;
curl = curl_easy_init();
bittKey = "...";
bittSecret = "...";
timeStamp = std::to_string(time(nullptr));
uRI = "https://api.bittrex.com/v3/balances";
hTTPMethod = "GET";
requestBody = "";
contentHash = sw::sha512::calculate(requestBody);
string preSign = timeStamp + uRI + hTTPMethod + contentHash;
string apiSign = hmac_sha512(preSign, bittSecret);
struct curl_slist* headerList = NULL;
headerList = curl_slist_append(headerList, "Accept: application/json");
headerList = curl_slist_append(headerList, "Content-Type: application/json");
headerList = curl_slist_append(headerList, ("Api-Key: " + bittKey).c_str());
headerList = curl_slist_append(headerList, ("Api - Signature: " + apiSign).c_str());
headerList = curl_slist_append(headerList, ("Api-Timestamp: " + timeStamp).c_str());
headerList = curl_slist_append(headerList, ("Api-Content-Hash: " + contentHash).c_str());
curl_easy_setopt(curl, CURLOPT_URL, uRI);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerList);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
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(headerList);
curl_easy_cleanup(curl);
After quite a long time of searching and debugging through the curl libraries the solution was quite simple.
curl_easy_setopt(curl, CURLOPT_URL, uRI.c_str());
Oh and the timestamp doesn't work the way I have it above. It works as follows:
using namespace std::chrono;
milliseconds ms = duration_cast<milliseconds>(
system_clock::now().time_since_epoch()
);
timeStamp = std::to_string(ms.count());
The API is working now.
Related
Recently I want to PUT an object with c++ curl.
Terminal command like this:
PUT /ObjectName HTTP/1.1
Content-Length:ContentLength
Content-Type: ContentType
Host: BucketName.oss-cn-hangzhou.aliyuncs.com
Date: GMT Date
Authorization: SignatureValue
My code:
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_URL, "https://tva******.oss*****.aliyuncs.com");
curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
auto size = to_string(file_info.st_size);
curl_slist* headerList = NULL;
headerList = curl_slist_append(headerList, ("Authorization: " + Authorization).c_str());
headerList = curl_slist_append(headerList, ("Date: " + finalTime).c_str());
headerList = curl_slist_append(headerList, ("Content-Type: application/octet-stream"));
headerList = curl_slist_append(headerList, ("Content-Length: " + size).c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerList);
res = curl_easy_perform(curl);
But its effect is PUT HTTP/1.1 not PUT /ObjectName HTTP/1.1
I want to put an object ,but there is no object, so it puts a bucket.
How to make a request like PUT /ObjectName HTTP/1.1.
I'm trying to solve it for many hours but nothing going better...
int main() {
CURL *curl_handle = curl_easy_init();
if(curl_handle) {
string post_data="";
struct curl_slist *headers=NULL;
string command = "command=returnBalances&nonce=" + to_string(time(0));
cout<<command<<endl;
string Secret = "mySecretCode";
string Sign = "Sign: "+ hmac::get_hmac(Secret, command, hmac::TypeHash::SHA512);
cout<<Sign<<endl;
post_data += command;
headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
headers = curl_slist_append(headers, "Key: myKey");
headers = curl_slist_append(headers, Sign.c_str());
curl_easy_setopt(curl_handle, CURLOPT_URL, "https://poloniex.com/tradingApi");
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, post_data.length()+1);
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, post_data.c_str());
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
}
curl_easy_perform(curl_handle);
curl_easy_cleanup(curl_handle);
return 0;
}
This returns to me
{"error":"Invalid command."}
I checked hmac function result threw website and they are equal.
Some people said that adding
"Content-Type: application/x-www-form-urlencoded"
can solve this, but not at this time.
Console output:
> POST /tradingApi HTTP/2
Host: poloniex.com
accept: */*
content-type: application/x-www-form-urlencoded
key: myKey
sign: resultOfHmacFunc
content-length: 40
Solution was to change from CURLOPT_POSTFIELDS to CURLOPT_COPYPOSTFIELDS
I have a Unity application that uses a c++ plugin that I wrote for making http requests. This plugin uses curl libraries.
As per curl documentation, they recommend using curl_easy_cleanup(curl) as the last command, in order to free the handle and clean up all the resources.
Here's my code that makes a simple http POST request:
struct curl_slist *headers = NULL;
CURL *curl = NULL;
curl = curl_easy_init();
int httpCode(0);
if(curl)
{
headers = curl_slist_append(headers, "Accept: application/json");
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "charsets: utf-8");
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
//Set remote URL
curl_easy_setopt(curl, CURLOPT_URL, endpoint.c_str());
std::string params;
for(std::unordered_map<std::string,std::string>::iterator it = parameters.begin(); it != parameters.end(); ++it)
{
params = it->first + ": " + it->second + " ";
headers = curl_slist_append(headers, (const char *)params.c_str());
}
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObject.c_str());
CURLcode res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ResponseRecievedCallback);
res = curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
//Uncommenting this line makes my application crash
//curl_easy_cleanup(curl);
}
However when I add this line, my unity app crashes with this following exception:
Receiving unhandled NULL exception
Obtained 13 stack frames.
#0 0x000001207a4438 in Curl_expire_clear
#1 0x00000120790e25 in Curl_close
I've spent the past couple of days online searching for some solution, read curl documentation but couldn't find any help. I'd appreciate if someone can explain why this might crash?
Thanks much!
Fixed the issue by making httpCode a long instead of an int (per documentation). I must've overlooked it before!
I'm trying to make an http post with libcurl library to create an InfluxDB database, as indicated in their website:
curl -i -XPOST http://localhost:8086/query --data-urlencode "q=CREATE DATABASE mydb"
It looks like my code is not working. It doesnt give me any errors but db is not created. But instead if i try to add some points to an existing database, with the same function, it works. I think i miss the correct way of adding "q=CREATE DATABASE mydb" part. How should i change my code?
int main(int argc, char *argv[]){
char *url = "http://localhost:8086/query";
char *data = "q=CREATE DATABASE mydb";
/* should i change data string to json?
data = "{\"q\":\"CREATE DATABASE mydb\" }" */
bool res = createInfluxDB(url, data);
/*control result*/
return(0);
}
bool createInfluxDB(char *url, char *data) {
CURL *curl;
curl = curl_easy_init();
if(curl) {
CURLcode res;
/* What Content-type should i use?*/
struct curl_slist* headers = curl_slist_append(headers, "Content-Type: application/json");
/*--data-urlencode*/
char *urlencoded = curl_easy_escape(curl, data, int(strlen(data)));
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, urlencoded);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(urlencoded));
res = curl_easy_perform(curl);
/*omitted controls*/
curl_free(urlencoded);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
return(true);
}
After analyzing packets with http post request (which was returning Bad Request) i arrived to the point that i shouldn't add query parameters as data. But instead it should be part of url. So after changing code like that, it works!
int main(int argc, char *argv[]){
char *url = "http://localhost:8086/query?q=CREATE+DATABASE+mydb";
bool res = createInfluxDB(url);
/*control result*/
return(0);
}
bool createInfluxDB(char *url) {
CURL *curl;
curl = curl_easy_init();
if(curl) {
CURLcode res;
struct curl_slist* headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
res = curl_easy_perform(curl);
/*omitted controls*/
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
return(true);
}
EDITED ANSWER:
You still got a missnamed var in a if statment:
if (urlencode) free(...
That should be
if (urlencoded) free(...
Then in your headers you set the application type as json and I don't think that's what you want.
Something like "application/x-www-form-urlencoded" may be better.
struct curl_slist* headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
ORIGNIAL ANSWER:
A workaround could be in your
char *data = curl_easy_escape(curl, json, int(strlen(json)));
That overload data with a json var that doesn't exist ?
Something like this may work better:
data = curl_easy_escape(curl, data, int(strlen(data)));
I have a raspberry pi that is running a c++ program. It now needs to talk to the Parse.com cloud so it seems the REST API is the best choice. I've been programming for a year and have truly hit a wall here.
EDIT: I've been able to get the code below to run. It successfully posts "south" in a new row under the "direction" column. I had to link my compiler to -lcurl.
My remaining question is how can I in this syntax add conditions to the query? For me the limiting query is
WHERE hardwareType = 2.
I can also GET all the results of my parse table if I comment out the CURLOPT_POSTFIELDS line inside curl_easy_init. How can I limit this request with the same query quoted above?
#include <iostream>
#include <curl/curl.h>
#include <string>
#include <sstream>
#include <stdexcept>
using namespace std;
int main()
{
CURL *curl;
CURLcode res;
struct curl_slist *headerlist=NULL;
headerlist = curl_slist_append( headerlist, "X-Parse-Application-Id: aaaaaaaaaaa");
headerlist = curl_slist_append( headerlist, "X-Parse-REST-API-Key: bbbbbbbbbbbbbbbb");
headerlist = curl_slist_append( headerlist, "Content-Type: application/json");
//headerlist = curl_slist_append(headerlist, "-d '{"direction":"south"}'");
curl = curl_easy_init();
if(curl)
{
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_URL, "https://api.parse.com/1/classes/testing");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"direction\" : \"south\"}");
res = curl_easy_perform(curl);
if(res != CURLE_OK){
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
}
}