Making POST request and receiving JSON response in C++ - c++

I have an application where I send base64 data of images from my OpenCV C++ code to an AWS URL which will find the age and gender of the faces in the images and send the results back in a JSON format.
I use cURL library to send the data through POST request. This part works fine, I am able to send the data and it the image is getting saved correctly every frame.
For reading the JSON data, I use the jsoncpp library to parse the JSON data.
I want to integrate both the parts in one function. This works as well when I send a single image. I have an issue when I send multiple images in a loop and receive their JSON responses. I keep receiving the first JSON response every time. I have tested this by generating random numbers and sending that as a JSON response each time on the server side and when I receive it in my C++ code, I only get the first JSON response, ie the first number, every time. But when I try receiving JSON data without sending POST data and just send a GET request, I receive the JSON data correctly every time. My code for both the parts integrated is here:
#include <iostream>
#include <string>
#include <memory>
#include <sstream>
#include <curl/curl.h>
#include <jsoncpp/json/json.h>
#include <stdio.h>
#include "opencv2/opencv.hpp"
#include "base64.h"
using namespace std;
using namespace cv;
/*Converts Mat to base64 string*/
string image_to_base64(Mat image)
{
string base64Output;
vector<uchar> vec_frame;
vector<int> vecCompression_params;
vecCompression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
vecCompression_params.push_back(90);
imencode(".jpg", image, vec_frame, vecCompression_params);
uchar *enc_msg = new uchar[vec_frame.size()];
for(int i=0; i < vec_frame.size(); i++)
enc_msg[i] = vec_frame[i];
base64Output = base64_encode(enc_msg, vec_frame.size());
std::replace(base64Output.begin(), base64Output.end(), '+', '-');
std::replace(base64Output.begin(), base64Output.end(), '/', '_');
std::replace(base64Output.begin(), base64Output.end(), '=', '*');
return base64Output;
}
/**Sends the base64 string to AWS**/
struct WriteThis
{
const char *readptr;
long long sizeleft;
};
static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
{
struct WriteThis *pooh = (struct WriteThis *)userp;
if(size*nmemb < 1)
return 0;
if(pooh->sizeleft)
{
*(char *)ptr = pooh->readptr[0]; /* copy one single byte */
pooh->readptr++; /* advance pointer */
pooh->sizeleft--; /* less data left */
return 1; /* we return 1 byte at a time! */
}
return 0; /* no more data left to deliver */
}
string cURL_JSON_data;
size_t writeJSONURLCallback(char* buf, size_t size, size_t nmemb, void* up)//Callback function to store the URL's data
{
for (int c = 0; c<size*nmemb; c++)
{
cURL_JSON_data.push_back(buf[c]);
}
return size*nmemb;
}
string jsonTest;
tuple<string, string> send_base64(string base64_string)
{
CURL *curl;
CURLcode res;
long long int httpCode(0);
unique_ptr<std::string> httpData(new std::string());
string age_info, gender_info;
struct WriteThis pooh;
//cout<<"base64_string.length(): "<<base64_string.length();
char data[base64_string.length()];
strcpy(data, base64_string.c_str());
pooh.readptr = data;
pooh.sizeleft = (long long)strlen(data);
//cout<<"strlen(data): "<<strlen(data)<<endl;
/* In windows, this will init the winsock stuff */
res = curl_global_init(CURL_GLOBAL_DEFAULT);
/* Check for errors */
if(res != CURLE_OK)
{
fprintf(stderr, "curl_global_init() failed: %s\n",
curl_easy_strerror(res));
//return 1;
}
/* get a curl handle */
curl = curl_easy_init();
if(curl)
{
/* First set the URL that is about to receive our POST. */
curl_easy_setopt(curl, CURLOPT_URL, "MYURL");
/* Now specify we want to POST data */
curl_easy_setopt(curl, CURLOPT_POST, 1L);
/* we want to use our own read function */
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
/* pointer to pass to our read function */
curl_easy_setopt(curl, CURLOPT_READDATA, &pooh);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeJSONURLCallback);//writes the conents of url
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); //output cURL's progress
curl_easy_setopt(curl, CURLOPT_WRITEDATA, httpData.get());
/* get verbose debug output please */
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
/*
If you use POST to a HTTP 1.1 server, you can send data without knowing
the size before starting the POST if you use chunked encoding. You
enable this by adding a header like "Transfer-Encoding: chunked" with
CURLOPT_HTTPHEADER. With HTTP 1.0 or without chunked transfer, you must
specify the size in the request.
*/
#ifdef USE_CHUNKED
{
struct curl_slist *chunk = NULL;
chunk = curl_slist_append(chunk, "Transfer-Encoding: chunked");
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
/* use curl_slist_free_all() after the *perform() call to free this
list again */
}
#else
/* Set the expected POST size. If you want to POST large amounts of data,
consider CURLOPT_POSTFIELDSIZE_LARGE */
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (pooh.sizeleft));
#endif
#ifdef DISABLE_EXPECT
/*
Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue"
header. You can disable this header with CURLOPT_HTTPHEADER as usual.
NOTE: if you want chunked transfer too, you need to combine these two
since you can only set one list of headers with CURLOPT_HTTPHEADER. */
/* A less good option would be to enforce HTTP 1.0, but that might also
have other implications. */
{
struct curl_slist *chunk = NULL;
chunk = curl_slist_append(chunk, "Expect:");
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
/* use curl_slist_free_all() after the *perform() call to free this
list again */
}
#endif
/* Perform the request, res will get the return code */
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_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
//cout<<"Testing_1"<<endl;
curl_easy_cleanup(curl);
}
curl_global_cleanup();
Json::Reader jsonReader;
Json::Value jsonData;
if (jsonReader.parse(cURL_JSON_data, jsonData))
{
cout << "Successfully parsed JSON data" << std::endl;
cout << "\nJSON data received:" << std::endl;
jsonTest = jsonData.toStyledString();
cout << jsonData.toStyledString() << std::endl;
age_info = jsonData["Age"].asString();
gender_info = jsonData["Gender"].asString();
}
else
{
cout<<"Could not parse JSON data"<<endl;
}
jsonData.clear();
return make_tuple(age_info, gender_info);
}
int main()
{
Mat frame;
string base64_data,age, gender;
int count = 0;
VideoCapture cap(1);
while(1)
{
cap>>frame;
count++;
resize(frame, frame, Size(frame.cols / 2, frame.rows / 2));
if(count % 10 ==0)//Sending the data every 10 frames
{
base64_data = image_to_base64(frame);
tie(age, gender) = send_base64(base64_data);
cout<<"age: "<<age<<", gender: "<<gender<<endl;
}
imshow("window", frame);
waitKey(30);
}
return 0;
}
And the code I use for receiving JSON with only GET request is here:
#include <iostream>
#include <stdlib.h>
#include <string>
#include <memory>
#include <curl/curl.h>
#include <jsoncpp/json/json.h>
using namespace std;
string cURLdata;
size_t writeURLCallback(char* buf, size_t size, size_t nmemb, void* up)
{
for (int c = 0; c<size*nmemb; c++)
{
cURLdata.push_back(buf[c]);
}
return size*nmemb;
}
int main()
{
int count = 0;
while(1){
CURL* curl; //curl object
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "MYURL");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeURLCallback);//writes the conents of url
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); //output cURL's progress
curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_global_cleanup();
Json::Reader jsonReader;
Json::Value jsonData;
bool parsedSuccess = jsonReader.parse(cURLdata,jsonData,false);
if (parsedSuccess)
{
std::cout << "Successfully parsed JSON data" << std::endl;
std::cout << "\nJSON data received:" << std::endl;
cout << jsonData.toStyledString() << std::endl;
}
else
{
std::cout << "Could not parse HTTP data as JSON" << std::endl;
}
jsonData.clear();
cURLdata.clear();
}
return 0;
}
Can someone help me point out what I'm doing wrong?

Related

libcurl C++: issue with printing responses when multiplexing

Goal:
To modify the libcurl example for HTTP/2 multiplexing that can be found here to save a payload response as it arrives into some buffer, instead of writing it to a file like the aforementioned example currently does. The payload within the buffer would then be available for things such as printing, searching for strings etc.
Expected output:
Program should print out each received payload response to stdout whenever the callback function detects that one has been delivered.
Actual output:
Sometimes the program works as expected for a small number of transfers (see line of code int num_transfers = 3 in main() further below). If the number of transfers is increased to say 8 or 10, sometimes the program doesn't function properly and the program will still print the output to stdout, but in the default format that libcurl will do if no CURL_WRITEFUNCTION/CURL_WRITEDATA has been included in the code, possibly suggesting nothing is being received by the callback function? Also in this scenario, an incorrect number of responses will be printed.
In the main do...while loop within main(), I set chunk.memory and chunk.size equal to 0 after they had been printed out. Without doing this, every time a new response was received these would continue growing. I'm unsure if this was the correct approach, however.
Current attempt:
Using the libcurl example that can be found here, I have attempted to mimic the functionality of writing the output to a callback function as seen below (instead of writing each response payload to a file).
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
/* somewhat unix-specific */
#include <sys/time.h>
#include <unistd.h>
/* curl stuff */
#include <curl/curl.h>
#include <curl/mprintf.h>
#ifndef CURLPIPE_MULTIPLEX
#define CURLPIPE_MULTIPLEX 0
#endif
struct CURLMsg *msg;
struct transfer {
CURL *easy;
unsigned int num;
FILE *out;
};
struct MemoryStruct {
char *memory;
size_t size;
};
struct MemoryStruct chunk;
#define NUM_HANDLES 1000
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
char *ptr = (char*)realloc(mem->memory, mem->size + realsize + 1);
if(!ptr) {
/* out of memory! */
std::cout << "not enough memory (realloc returned NULL)" << std::endl;
return 0;
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
static void setup(struct transfer *t, int num)
{
CURL *hnd;
hnd = t->easy = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, (void *)&chunk);
/* set the same URL */
curl_easy_setopt(hnd, CURLOPT_URL, "https://someurl.xyz");
/* HTTP/2 please */
curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
/* we use a self-signed test server, skip verification during debugging */
curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L);
#if (CURLPIPE_MULTIPLEX > 0)
/* wait for pipe connection to confirm */
curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L);
#endif
}
int main() {
struct transfer trans[NUM_HANDLES];
CURLM *multi_handle;
int i;
int still_running = 0; /* keep number of running handles */
int num_transfers = 3;
chunk.memory = (char*)malloc(1);
chunk.size = 0;
/* init a multi stack */
multi_handle = curl_multi_init();
for(i = 0; i < num_transfers; i++) {
setup(&trans[i], i);
/* add the individual transfer */
curl_multi_add_handle(multi_handle, trans[i].easy);
}
curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
// Main loop
do {
CURLMcode mc = curl_multi_perform(multi_handle, &still_running);
if(still_running) {
/* wait for activity, timeout or "nothing" */
mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL);
}
if(mc) {
break;
}
// Get response
do {
int queued;
msg = curl_multi_info_read(multi_handle, &queued);
if ((msg) && (msg->msg == CURLMSG_DONE) && (msg->data.result == CURLE_OK)) {
// Print the response payload
std::cout << "size: " << chunk.size << std::endl;
std::cout << chunk.memory << std::endl;
chunk.memory = 0;
chunk.size = 0;
}
} while (msg);
} while (still_running);
for(i = 0; i < num_transfers; i++) {
curl_multi_remove_handle(multi_handle, trans[i].easy);
curl_easy_cleanup(trans[i].easy);
}
free(chunk.memory);
curl_multi_cleanup(multi_handle);
return 0;
}
Summary question:
Q1. How can I modify the above program to correctly save a received payload response into a struct or a buffer asynchronously so that it can be available for functionality such as printing to stdout or searching for strings?
First, you should associate the transfer struct with a way of accessing the output:
struct transfer {
CURL *easy;
unsigned int num;
std::string contents;
};
and associate the CURLOPT_WRITEDATA with the pointer:
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, (void *)t);
Then, WriteMemoryCallback becomes:
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
transfer *t = (transfer *)userp;
size_t realsize = size * nmemb;
t->contents.append((const char *)contents, realsize);
return realsize;
}
Afterwards you can find the contents in the trans[i].contents variables.

Return post values with libcurl as std::string

How do you extract the value in id field in the form and declare it as a std::string
When this function is called it makes a post request to the link provided and outputs the result to command line on the client side
int push_(void)
{
CURL* curl;
CURLcode res;
/* In windows, this will init the winsock stuff */
curl_global_init(CURL_GLOBAL_ALL);
/* get a curl handle */
curl = curl_easy_init();
if (curl) {
/* First set the URL that is about to receive our POST. This URL can
just as well be a https:// URL if that is what should receive the
data. */
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/api/0000/push");
/* Now specify the POST data */
// the form on the server side has a single field
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "id=");
/* Perform the request, res will get the return code */
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);
}
curl_global_cleanup();
return 0;
}
id provided as input
fffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Server response
fffffffffffffffffffffffffffffffffffffffffffffffffffffffff<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to target URL: /login.
I got this far to extracting the id value but I don't know how to split the id from the html tags
You have to add a callback function CurlWrite_CallbackFunc_StdString to get the data out of the post request
#include <iostream>
#include <string>
#include <curl/curl.h>
size_t CurlWrite_CallbackFunc_StdString(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)
{
//handle memory problem
return 0;
}
return newLength;
}
std::string h3ll0() {
CURL* curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
std::string s;
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "localhost/api/0000/hello");
// Add post data to get the command line from the server post request
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "id=");
// A calback function that copies the data from the post request output
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString);
// Write the copied data to the variable s to return it
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
/* Perform the request, res will get the return code */
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);
}
//std::cout << s << std::endl;
//std::cout << "Program finished!" << std::endl;
return s;
}
int main() {
std::string result = h3ll0();
std::cout << result << std::endl;
}

How to use Curl in C++ to get http response string after sending http string to server

In a C ++ program I need to send an http message using Curl to another machine where is running a REST server written in C ++, and then collect the response from that server.
I am new to using Curl and have been looking at documentation and various examples on the web.
The source code of my program is the one attached below.
Sending the message to the server works, but I do not get the response the server sends me (not a timeout problem).
I would appreciate help with this, as I am not sure the code I use to get the response from the server is correct.
#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <sstream>
#include <curl/curl.h>
size_t getAnswerFunction(void* ptr, size_t size, size_t nmemb, std::string* data) {
data->append((char*)ptr, size * nmemb);
return size * nmemb;
}
void sendDataAndGetAnswer(std::string data)
{
CURL *curl;
CURLcode res;
struct curl_slist *httpHeaders=NULL;
curl = curl_easy_init();
if (curl)
{
curl_global_init(CURL_GLOBAL_ALL);
curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.0.100:15000");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
httpHeaders = curl_slist_append(httpHeaders, "MyProgram-Header");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, httpHeaders);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "MyAgent/1.0");
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 1000);
// .........................................
// MyProgram sends data.
// This works right.
// .........................................
res = curl_easy_perform(curl);
if (res != CURLE_OK)
std::cout << "curl_easy_perform() failed to send message: " << curl_easy_strerror(res) << std::endl;
// .........................................
// MyProgram get answer.
// This does not work.
// .........................................
std::string response_string;
curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.0.100:15000");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, getAnswerFunction);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_string);
// getAnswerFunction waits at most 5000 ms.
// Afterwards, the flow of the program should continue even if there is no response.
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 5000);
res = curl_easy_perform(curl);
if (res == CURLE_OK)
std::cout << response_string;
else
std::cout << "curl_easy_perform() failed to get answer: " << curl_easy_strerror(res) << std::endl;
curl_easy_cleanup(curl);
curl_slist_free_all(httpHeaders);
}
}
int main(void)
{
while (1)
{
int valueVar = 0;
// Execute various statements and perform calculations.
// ...
// Calculate value here.
// ...
std::string msgToSend("CONTITION-IS-TRUE");
if (valueVar = 5)
sendDataAndGetAnswer(msgToSend);
sleep(10);
}
return 0;
}

Libcurl Image Upload Post from memory

I am writing a program that pulls an image from a restful server that is delivered in JSON, parsed, processed and sent back to the server. I am having issues on sending the image back. Currently I have it stored in a string and am trying to use CURLFORM_BUFFER to send it back. I have confirmed that the image is in the string by writing it to file. No problems there. My current code is below. I am currently experiencing a seg fault 11 on the post. My code is below.
#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
#include <stdlib.h>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "dist/jsoncpp.cpp"
#include "dist/json/json.h"
using namespace std;
static size_t write_data(void *contents, size_t size, size_t nmemb,
void *userp)
{
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
void uploadImage(std::string readBuffer){
CURL *curl;
CURLcode res;
struct curl_httppost *formpost=NULL;
struct curl_httppost *lastptr=NULL;
struct curl_slist *headerlist=NULL;
static const char buf[] = "Expect:";
curl_global_init(CURL_GLOBAL_ALL);
printf("Image length: %d\n\n", readBuffer.length());
CURLFORMcode code = curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "processedImage",
CURLFORM_BUFFER, "image.jpg",
CURLFORM_BUFFERPTR, readBuffer,
//CURLFORM_BUFFERLENGTH, readBuffer.length(),
CURLFORM_END);
if(code != 0){
printf("Something went wrong in formadd.\n");
}
curl = curl_easy_init();
/* initialize custom header list (stating that Expect: 100-continue is not
wanted */
headerlist = curl_slist_append(headerlist, buf);
if(curl) {
/* what URL that receives this POST */
curl_easy_setopt(curl, CURLOPT_URL, "uploadProcessedImageURL");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
//curl_easy_setopt(curl, CURLOPT_POSTFIELDS, formpost);
/* Perform the request, res will get the return code */
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);
/* then cleanup the formpost chain */
curl_formfree(formpost);
/* free slist */
curl_slist_free_all (headerlist);
}
}
int main(void)
{
CURL *curl;
CURLcode res;
const cv::_InputArray data;
std::string readBuffer;
char *url = "requestImageFileURL";
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
readBuffer.clear();
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
//printf("%s\n\n", readBuffer.c_str());
printf("Image retrieved.\n");
Json::Value values;
Json::Reader reader;
reader.parse(readBuffer, values);
Json::Value imageArray = values.get("userUploadedImage","default
value");
Json::Value idNumber = values.get("id","default value");
Json::FastWriter fastWriter;
std::string output = fastWriter.write(imageArray);
//cout << output << endl;
std::vector<char> vectordata(output.begin(), output.end());
//for (auto i = vectordata.begin(); i != vectordata.end(); ++i)
//std::cout << *i;
cv::Mat data_mat(vectordata,true);
cv::Mat image(cv::imdecode(data_mat, 1));
std::cout<<"Height: " << image.rows <<" Width: "<<image.cols<<endl;
//cv::namedWindow( "Display Image", CV_WINDOW_AUTOSIZE );
//cv::imshow( "Display Image",image);
//cv::waitKey(0);
uploadImage(readBuffer);
return 0;
}

libcurl not uploading the entier file

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...