Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Curl command line works, C++ curl library does not

I'm trying to do some request via curl library of C++. I can successfully do my request and get the correct response via command line, but I cannot get the correct response via C++ code. My command line command looks like this

curl -X POST -H 'Accept: application/json' -H 'Content-Type: application/json' -H 'Authorization: <some_hash_value>' -k <my_full_url> -data '<my_json_string>'

That works fine. Now I try to do the same request in C++ code. My code looks like this

void performRequest(const std::string& json, const void* userData, CallbackFunction callback)
{
    struct curl_slist* headers = NULL;

    headers = curl_slist_append(headers, "Accept: application/json");
    headers = curl_slist_append(headers, "Content-Type: application/json");
    headers = curl_slist_append(headers, (std::string("Authorization: ") + m_authorization).c_str());

    CURL* curlHandle = curl_easy_init();
    if (!curlHandle)
    {
        std::cerr << "Curl handler initialization failed";
    }

    curl_easy_setopt(curlHandle, CURLOPT_NOSIGNAL, 1);
    curl_easy_setopt(curlHandle, CURLOPT_HTTPHEADER, headers);

    // specify target URL, and note that this URL should include a file name, not only a directory
     curl_easy_setopt(curlHandle, CURLOPT_URL, m_url.c_str());

    // enable uploading
    curl_easy_setopt(curlHandle, CURLOPT_UPLOAD, 1L);

    // set HTTP method to POST
    curl_easy_setopt(curlHandle, CURLOPT_CUSTOMREQUEST, "POST");

    // set json data; I use EXACTLY the same string as in command line
    curl_easy_setopt(curlHandle, CURLOPT_COPYPOSTFIELDS, json.c_str());

    // set data size
    curl_easy_setopt(curlHandle, CURLOPT_POSTFIELDSIZE_LARGE, json.size());

    // set user data for getting it in response
    curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, userData);    // pointer to a custom struct

    // set callback function for getting response
    curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, callback);    // some callback

    // send request
    curl_easy_perform(curlHandle);

    curl_easy_cleanup(curlHandle);
    curl_slist_free_all(headers);
}

However, for some reason I get an error in the response from the server, from which I can assume that my code's request is not equivalent to command line's command. It seems that body is not sent. I cannot see my request Json body when I use CURLOPT_DEBUGFUNCTION for dumping debug info.

What is the problem here? What am I doing wrong? Any ideas?

like image 910
nabroyan Avatar asked Apr 18 '16 13:04

nabroyan


1 Answers

Here is sample code that should work for you.

Notice that I:

  • Removed CURLOPT_UPLOAD as it does not seem as you are actually uploading something but rather just doing a simple POST.

  • Changed CURLOPT_CUSTOMREQUEST to CURLOPT_POST (not that it should matter), but I find it cleaner.

  • Reordered CURLOPT_POSTFIELDSIZE_LARGE and CURLOPT_COPYPOSTFIELDS

  • Removed the CURLOPT_WRITEDATA line for the sake of this sample code.

I have tested the following only by connecting to an instance of nc -l localhost 80

 static size_t callback(char *ptr, size_t size, size_t nmemb, void *userdata)
 {
   string s(ptr);
   cout << s << endl;
   return size * nmemb;
 }


 int main(int argc, char** argv)
 {
   string m_authorization("PWNED");
   string m_url("http://localhost");
   string m_json("{}");

   curl_global_init(CURL_GLOBAL_ALL);

   CURL* curlHandle = curl_easy_init();

   struct curl_slist* headers = nullptr;
   headers = curl_slist_append(headers, "Accept: application/json");
   headers = curl_slist_append(headers, "Content-Type: application/json");
   headers = curl_slist_append(headers, (std::string("Authorization: ") + m_authorization).c_str());

   curl_easy_setopt(curlHandle, CURLOPT_NOSIGNAL, 1);
   curl_easy_setopt(curlHandle, CURLOPT_HTTPHEADER, headers);

   // specify target URL, and note that this URL should include a file name, not only a directory
   curl_easy_setopt(curlHandle, CURLOPT_URL, m_url.c_str());

   // <= You are not uploading anything actually, this is a simple POST with payload
   // enable uploading
   // curl_easy_setopt(curlHandle, CURLOPT_UPLOAD, 1L);

   // set HTTP method to POST
   curl_easy_setopt(curlHandle, CURLOPT_POST, 1L);

   // set data size before copy
   curl_easy_setopt(curlHandle, CURLOPT_POSTFIELDSIZE_LARGE, m_json.size());

   // set json data; I use EXACTLY the same string as in command line
   curl_easy_setopt(curlHandle, CURLOPT_COPYPOSTFIELDS, m_json.c_str());

   // set user data for getting it in response
   // curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, userData);    // pointer to a custom struct

   // set callback function for getting response
   curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, callback);    // some callback

   // send request
   curl_easy_perform(curlHandle);

   curl_slist_free_all(headers);

   curl_easy_cleanup(curlHandle);
   curl_global_cleanup();
   return 0;
 }
like image 84
BlakBat Avatar answered Sep 22 '22 03:09

BlakBat