Boardy
Boardy

Reputation: 36227

C++ libcurl not posting data

I am working on a C++ library which is making use of the curl library to perform an HTTP POST request to a webservice.

I have a function which is responsible for performing curl and processing the response, and this function calls another function to set curl up as it can be used from multiple places with the same setup.

Its successfully connects to the web service and I can see the response returned however, no post data is sent to the web service.

Below the code that I have to perform the HTTP request.

The first function is the function that does the curl perform, it calls a function to init the curl library and then return the pointer to it for use.

string response;
struct curl_slist *list = NULL;
const char * jsonString = ddEvent.getDDEventAsJSONString().c_str();
CURL *curl = this->initCurl(ddEvent, &response, list, &jsonString);
if (curl == NULL)
{
    return false;
}

list = curl_slist_append(list, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
CURLcode res = curl_easy_perform(curl);

The function that initialises curl is as follows:

CURL * MyClass::initCurl(DDEvent ddEvent, string *response, struct curl_slist *list, const char **jsonString)
{
    CURL *curl = NULL;

    curl = curl_easy_init();
    if (curl == NULL)
    {
        cout << "Failed to initialise curl" << endl;
        return NULL;
    }
    stringstream url_stream;
    url_stream << "http://192.168.1.123";
    string url= dd_url_stream.str();

    cout << "Using URL: " << url<< endl;

    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, response);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &MyClass::curlResponseWriteCallback);
    curl_easy_setopt(curl, CURLOPT_HEADER, 1);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
    curl_easy_setopt(curl, CURLOPT_POST, 1);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, *jsonString);

    return curl;
}

Also, the post data is a JSON string, its not a key/value posted form data.

Below is the output from the the verbose mode of curl

Using JSON string {"title":"HTTP Event Teesg","text":"Test warning event","alert_type":"success","tags":["simple_string_tag"]}
Using URL: http://192.168.1.123
* About to connect() to 192.168.1.123 port 80 (#0)
*   Trying 192.168.1.123...
* Connected to 192.168.1.123 (192.168.1.123) port 80 (#0)
> POST / HTTP/1.1
Host: 192.168.1.123
Accept: */*
Content-Type: application/json
Content-Length: 0

< HTTP/1.1 200 OK
< Date: Sun, 04 Feb 2018 20:11:12 GMT
< Server: Apache/2.4.6 (CentOS) PHP/5.6.32
< X-Powered-By: PHP/5.6.32
< X-XSS-Protection: 1; mode=block
< Content-Length: 52
< Content-Type: text/html; charset=UTF-8
<

Upvotes: 0

Views: 1537

Answers (2)

th yoo
th yoo

Reputation: 1

It seems that ddEvent.getDDEventAsJSONString() returns a temporary std::string object. Save it in a local variable and then pass it as reference.

std::string jsonString = ddEvent.getDDEventAsJSONString();
this->initCurl(ddEvent, &response, list, jsonString);

CURL * MyClass::initCurl(DDEvent ddEvent, string *response, struct curl_slist *list, const std::string& jsonString)

You have to keep the string alive until you call curl_easy_perform() since CURLOPT_POSTFIELDS doesn't copy the string into libcurl.

Strings passed to libcurl as 'char *' arguments, are copied by the library; thus the string storage associated to the pointer argument may be overwritten after curl_easy_setopt returns. The only exception to this rule is really CURLOPT_POSTFIELDS, but the alternative that copies the string CURLOPT_COPYPOSTFIELDS has some usage characteristics you need to read up on.

There is no problem in your code where you call curl_easy_perform in the life scope of jsonString. However, if you intend to call the function afterward, instead of CURLOPT_POSTFIELDS use CURLOPT_COPYPOSTFIELDS which copy and memorize the data to post.

Upvotes: 0

Daniel Stenberg
Daniel Stenberg

Reputation: 58164

The Content-Length: 0 in the outgoing request suggests that the data you pass to CURLOPT_POSTFIELDS has zero length.

Note that CURLOPT_POSTFIELDS doesn't copy the data, it just points to your memory so you might want to make sure the data is still around for the entire time libcurl needs it. Since you haven't shown us the entire program we can't really tell you exactly how this happens for you.

Finally: why not just pass a 'char *' to initCurl instead of 'char **' that you need to dereference within the method?. It looks odd to me.

Upvotes: 1

Related Questions