c++httppostlibcurlonvif

Add URI Request to LibCurl Post command


I am using ubuntu 22.04 and libcurl 7.81.0 to create and send onvif post command. I originally got everything working in python, but am unable to use python in the final project. Therefore I'd like to replicate the command in libcurl. My issue is not with sending commands and receiving responses.

I need more clarity on how to set the request URI in the header. When I send a post command via python using zeep, the post header is as follows in the image from wireshark: Python Post Request

However, when I try to send a post message inside libcurl, I get the following: libcurl Post Request

Is there a curlopt option that I'm missing to set that URI field? I really need curl to replicate exactly what was sent in python.

My curl options are set with:

curl = curl_easy_init();
std::string url = serverIP + ":" + std::to_string(serverPort);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, settings.responseTimeout_ms);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &cameraResponse);

My callback is just:

size_t writeCallback(char* contents, size_t size, size_t nmemb, std::string* userp)
{
    userp->append(contents, size * nmemb);
    return size * nmemb;
}

I then create and set my header field (omitting the actual string contents from this post)

struct curl_slist* header = nullptr;
header = curl_slist_append(header, host.c_str());
header = curl_slist_append(header, agent.c_str());
header = curl_slist_append(header, acceptEncoding.c_str());
header = curl_slist_append(header, accept.c_str());
header = curl_slist_append(header, connection.c_str());
header = curl_slist_append(header, soapAction.c_str());
header = curl_slist_append(header, contentType.c_str());
header = curl_slist_append(header, contentLength.c_str());

with content just being the encoded data in a soap format that I want to send. As far as I'm aware, no problem here as well.

Then I set the last curl options and calling easy perform

curl_easy_setopt(curl, CURLOPT_POSTFIELDS, content.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
CURLcode curlResult = curl_easy_perform(curl);

I find that the responses using libcurl from my camera are about 2X slower than when using python. I'm assuming it has to do with the differences in the format of the message. I'd like to start with fixing the URI request as mentioned above. Would appreciate feedback on that topic.


Solution

  • Is there a curlopt option that I'm missing to set that URI field?

    You are already using it - CURLOPT_URL. You just need to specify the complete HTTP URL, not just the server's IP and port by itself:

    Pass in a pointer to the URL to work with. The parameter should be a char * to a null-terminated string which must be URL-encoded in the following format:

    scheme://host:port/path

    Try this:

    std::string url = "http://" + serverIP + ":" + std::to_string(serverPort) + "/onvif/DeviceIO";
    // or "https://" if needed ...
    

    If serverPort is the standard 80 for an HTTP url, or 443 for an HTTPS url, you can just omit it completely:

    std::string url = "http://" + serverIP + "/onvif/DeviceIO";
    // or "https://" if needed ...
    

    On a side note: when using CURLOPT_HTTPHEADER, you do not need to send a Host header yourself, let libcurl handle that for you, based on thee URL you specify. Also, some of the other headers you are sending manually can be handled with other libcurl options instead, such as CURLOPT_ACCEPT_ENCODING, CURLOPT_USERAGENT, CURLOPT_POSTFIELDSIZE, etc.