简体   繁体   中英

Making libcurl json post request in C/C++

I am writing a Qt application, and I have a button which is supposed to register a user. I'm using the following libraries:

  1. https://github.com/nlohmann/json <- for json serialization/deserialization
  2. libcurl

My goal is to be able to make a post request to the following endpoint: http://localhost:8000/api/register

It is expecting a POST of Content-Type: application/json, of utf-8, with a json body like this:

{
    "username": "test", 
    "password": "test"
}

The post request goes through, but the response is giving errors. I'm trying to pinpoint if this is an issue with my libcurl code, or if it's an error with my python django application.

Here is the verbose output of the libcurl code:

E0125 08:52:00.886679  5816 API.h:43] {"password":"test2","username":"test"}
* STATE: INIT => CONNECT handle 0x2489d6b0bf8; line 1835 (connection #-5000)
* Added connection 0. The cache now contains 1 members
* family0 == v4, family1 == v6
*   Trying 127.0.0.1:8000...
* STATE: CONNECT => CONNECTING handle 0x2489d6b0bf8; line 1896 (connection #0)
* Connected to 127.0.0.1 (127.0.0.1) port 8000 (#0)
* STATE: CONNECTING => PROTOCONNECT handle 0x2489d6b0bf8; line 2030 (connection #0)
* STATE: PROTOCONNECT => DO handle 0x2489d6b0bf8; line 2051 (connection #0)
> POST /api/register HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: Jellybean-Launcher
Content-Type: application/json; charset: utf-8
Accept: application/json
Content-Length: 8

* STATE: DO => DID handle 0x2489d6b0bf8; line 2147 (connection #0)
* STATE: DID => PERFORMING handle 0x2489d6b0bf8; line 2266 (connection #0)
* Mark bundle as not supporting multiuse
* HTTP 1.1 or later with persistent connection
< HTTP/1.1 400 Bad Request
< Date: Tue, 25 Jan 2022 16:52:00 GMT
< Server: WSGIServer/0.2 CPython/3.9.7
< Content-Type: application/json
< Vary: Accept, Cookie
< Allow: POST, OPTIONS
< X-Frame-Options: DENY
< Content-Length: 109
< X-Content-Type-Options: nosniff
< Referrer-Policy: same-origin
<
{"detail":"JSON parse error - 'utf-8' codec can't decode byte 0xdd in position 0: invalid continuation byte"}* STATE: PERFORMING => DONE handle 0x2489d6b0bf8; line 2465 (connection #0)
* multi_done: status: 0 prem: 0 done: 0
* Connection #0 to host 127.0.0.1 left intact
* Expire cleared (transfer 0x2489d6b0bf8)

Here is the libcurl code itself:

void RegisterUser(std::string username, std::string password)
{
    curl_global_init(CURL_GLOBAL_ALL);

    nlohmann::json json_data;
    json_data["username"] = "test";
    json_data["password"] = "test2";
    CURL* curl = curl_easy_init();
    CURLcode res;

    if (curl)
    {
        curl_easy_setopt(curl, CURLOPT_URL, GetRegistrationURL().c_str());
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
        
        struct curl_slist* chunk = NULL;
        chunk = curl_slist_append(chunk, "Content-Type: application/json; charset: utf-8");
        chunk = curl_slist_append(chunk, "Accept: application/json");

        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
        curl_easy_setopt(curl, CURLOPT_POST, 1L);

        /* Set the expected POST size. */
        curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sizeof(json_data.dump().c_str()));
        LOG(ERROR) << json_data.dump().c_str();
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data.dump().c_str());
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "Jellybean-Launcher");


        res = curl_easy_perform(curl);
        if (res == CURLE_OK)
        {
            //res = curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &ct);
        }
        curl_easy_cleanup(curl);
        curl_slist_free_all(chunk);
    }

    curl_global_cleanup();

}

GetRegistrationURL() Returns an std::string which is scoped based on if you're in a development build or not. During development builds, it always passes localhost, and in release builds it passes the live web url.

Does anyone have any idea of what I may be doing wrong here?

The first error is in the line curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, sizeof(json_data.dump().c_str())); . sizeof does not do what you suppose it does.

Yet another error is in the line curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data.dump().c_str()); stores a pointer to an inside of a temporary data json_data.dump() , it causes undefined behavior, possibly sending a garbage. The error 'utf-8' codec can't decode byte 0xdd hints about the Microsoft C runtime marker 0xdddddddd of a deleted memory region.

curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)json_data.dump().size()));

curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, json_data.dump().c_str());

should fix the issue. Setting CURLOPT_POSTFIELDSIZE may be omitted, if the size has not been set prior to CURLOPT_COPYPOSTFIELDS , the data is assumed to be a null-terminated string - it is your case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM