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?
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;
}
在Windows中,你必须用下面的函数初始化winsock的东西
curl_global_init(CURL_GLOBAL_ALL);
The problem was solved tanks to Rocki's and drew010's comments.
CURLOPT_CUSTOMREQUEST
, CURLOPT_UPLOAD
and CURLOPT_NOSIGNAL
setting statements as there is no need of them. 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)