7

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?

13
  • Do you have wireshark diagnostics available? Commented Apr 20, 2016 at 17:16
  • I'm afraid - no, I don't have. Commented Apr 20, 2016 at 17:22
  • 4
    You should remove curl_easy_setopt(curlHandle, CURLOPT_POSTFIELDSIZE_LARGE, json.size());. If the size has not been set prior to CURLOPT_COPYPOSTFIELDS, the data is assumed to be a zero terminated string; else the stored size informs the library about the byte count to copy. In any case, the size must not be changed after CURLOPT_COPYPOSTFIELDS, unless another CURLOPT_POSTFIELDS or CURLOPT_COPYPOSTFIELDS option is issued. See: curl.haxx.se/libcurl/c/CURLOPT_COPYPOSTFIELDS.html Commented Apr 20, 2016 at 17:23
  • Since you get a response from the server that could be very useful. Look at wireshark.org Commented Apr 20, 2016 at 17:23
  • 1
    What if you get rid of both CURLOPT_CUSTOMREQUEST and CURLOPT_UPLOAD as these are not needed for this request? Does it work? Commented Apr 20, 2016 at 20:51

3 Answers 3

1

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;
 }
Sign up to request clarification or add additional context in comments.

Comments

1

In windows, you must init the winsock stuff with below function

curl_global_init(CURL_GLOBAL_ALL);

Comments

1

The problem was solved tanks to Rocki's and drew010's comments.

  1. I have removed CURLOPT_CUSTOMREQUEST, CURLOPT_UPLOAD and CURLOPT_NOSIGNAL setting statements as there is no need of them.
  2. I have also removed the line for setting CURLOPT_POSTFIELDSIZE_LARGE, although it works fine if it is set before setting CURLOPT_COPYPOSTFIELDS. If the size has not been set prior to CURLOPT_COPYPOSTFIELDS, the data is assumed to be a zero terminated string; else the stored size informs the library about the byte count to copy. In any case, the size must not be changed after CURLOPT_COPYPOSTFIELDS, unless another CURLOPT_POSTFIELDS or CURLOPT_COPYPOSTFIELDS option is issued. (See: curl.haxx.se/libcurl/c/CURLOPT_COPYPOSTFIELDS.html)

1 Comment

Could the answer be rephrased someway to emphazise on what was wrong rather than "I did a bunch of stuff and then it works"?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.