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?
3 Answers
Answers 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 simplePOST
.Changed
CURLOPT_CUSTOMREQUEST
toCURLOPT_POST
(not that it should matter), but I find it cleaner.Reordered
CURLOPT_POSTFIELDSIZE_LARGE
andCURLOPT_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; }
Answers 2
In windows, you must init the winsock stuff with below function
curl_global_init(CURL_GLOBAL_ALL);
Answers 3
The problem was solved tanks to Rocki's and drew010's comments.
- I have removed
CURLOPT_CUSTOMREQUEST
,CURLOPT_UPLOAD
andCURLOPT_NOSIGNAL
setting statements as there is no need of them. - I have also removed the line for setting
CURLOPT_POSTFIELDSIZE_LARGE
, although it works fine if it is set before settingCURLOPT_COPYPOSTFIELDS
. If the size has not been set prior toCURLOPT_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 afterCURLOPT_COPYPOSTFIELDS
, unless anotherCURLOPT_POSTFIELDS
orCURLOPT_COPYPOSTFIELDS
option is issued. (See: curl.haxx.se/libcurl/c/CURLOPT_COPYPOSTFIELDS.html)
0 comments:
Post a Comment