将数据数组格式化为multipart/form-data

3

我有一个代码,在其中接收一个数组中的加密数据。 我正在努力使用curl mime api创建multipart / form-data。 有人可以帮助/指导我如何创建multipart / form-data吗?谢谢。 我对curl很陌生,以前从未用过curl。我收到错误消息“无法打开/读取来自文件/应用程序的本地数据”。

#include <string>
#include <vector>
#include <iostream>
#include <curl/curl.h>
#include <curl/easy.h>

#define SYSLOG_INFO std::clog

struct Post {
    std::string url, chunk;
    static constexpr auto HeaderSize = 10;
    size_t static callBackFunk(char* buffer, size_t size, size_t nitmes,
                               void* userdata)
    { /*ignore?*/
        SYSLOG_INFO << __PRETTY_FUNCTION__ << "\n";
        return 0;
    }

    std::string libcurl(const std::vector<uint8_t>& cmdData)
    {
        CURL*              curl{nullptr};
        CURLcode           res;
        curl_mime*         form    = NULL;
        curl_mimepart*     field   = NULL;
        struct curl_slist* headers = NULL;
        static const char  buf[]   = "Expect:";

        std::string data = std::string(cmdData.begin(), cmdData.end());

        curl = curl_easy_init();
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());

        form  = curl_mime_init(curl);
        field = curl_mime_addpart(form);
        curl_mime_name(field, "upfile");
        curl_mime_filedata(field, data.c_str());

        field = curl_mime_addpart(form);
        curl_mime_name(field, "filename");
        curl_mime_filedata(field, data.c_str());

        std::string header =
            std::string(cmdData.begin(), cmdData.begin() + HeaderSize);
        SYSLOG_INFO << "header = " << header << std::endl;
        std::string headerAuth = "SCPv2: " + header;

        headers = curl_slist_append(headers, headerAuth.c_str());
        headers = curl_slist_append(headers, buf);

        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

        curl_easy_setopt(curl, CURLOPT_HEADERDATA, (std::string*)&chunk);
        curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, callBackFunk);

        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);

        res = curl_easy_perform(curl);
        if (res != CURLE_OK) {
            std::cout << stderr << " curl_easy_perform() failed "
                      << curl_easy_strerror(res) << std::endl;
        }

        curl_easy_cleanup(curl);
        curl_mime_free(form);
        curl_slist_free_all(headers);

        return chunk;
    }
};

int main() {
    Post post {"http://www.example.com", "hello world"};

    post.libcurl({1,2,3,4});
}

命令
curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "cache-control:", CURLFORM_COPYCONTENTS, "no-cache", CURLFORM_END);

   curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "content-type:", CURLFORM_COPYCONTENTS, "multipart/form-data", CURLFORM_END);

   curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "file", CURLFORM_BUFFER, "data", CURLFORM_BUFFERPTR, cmdData.data(), CURLFORM_BUFFERLENGTH, cmdData.size(), CURLFORM_END);

请提供最小可复现示例(MCVE)。目前不清楚cmdData中包含什么,或者payload是什么等等... - pptaszni
1
抱歉,我更新了代码。 - Shanmukha Raju
不行,这个例子甚至无法编译。 - pptaszni
@pptaszni已经为您使其自包含。 - sehe
1个回答

0
使用curl_mime_filedata()函数,curl将尝试从名为data.c_str()的文件路径加载内容,如果找不到该文件,则curl会显示上面的错误消息。如果要上传数据内容,应改用curl_mime_data():

filename指向以空字符结尾的文件路径名。指针可以为NULL以分离先前部分的内容设置。此调用后,可以安全地重复使用文件名存储。

...

文件的内容在文件传输期间以流式方式读取,以允许传输大文件而不使用太多内存。因此,在整个请求期间必须保持文件完整。

上传名为“example.dat”的文件并将其内容设置为数据字符串的代码应为(从curl示例here修改):
  CURL *curl;
  CURLM *multi_handle;

  int still_running = 0;
  curl_mime *form = NULL;
  curl_mimepart *field = NULL;
  struct curl_slist *headerlist = NULL;

  std::string data = {"1234"};

  //... add your headers definition ....

  curl = curl_easy_init();
  multi_handle = curl_multi_init();

  if(curl && multi_handle) {

    /* Create the form */
    form = curl_mime_init(curl);

    /* Fill in the file upload field */
    field = curl_mime_addpart(form);
    curl_mime_name(field, "upfile");
    curl_mime_filedata(field, data.c_str(), data.size() );

    /* Fill in the filename field */
    field = curl_mime_addpart(form);
    curl_mime_name(field, "filename");
    curl_mime_data(field, "example.dat", CURL_ZERO_TERMINATED);

    //... set your headers here ...

    /* what URL that receives this POST */
    curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/");
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
    curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
    curl_multi_add_handle(multi_handle, curl);
    do {
      CURLMcode mc = curl_multi_perform(multi_handle, &still_running);
      if(still_running)
        /* wait for activity, timeout or "nothing" */
        mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL);
      if(mc)
        break;
    } while(still_running);
    curl_multi_cleanup(multi_handle);
    /* always cleanup */
    curl_easy_cleanup(curl);
    /* then cleanup the form */
    curl_mime_free(form);
    /* free slist */
    curl_slist_free_all(headerlist);
  }

如果程序出现错误,这意味着服务器端不接受“upfile”或“filename”变量。您应该检查服务器端部分以获取更多信息。
上面显示的代码与以下curl命令相同:
curl -F 'upfile=1234' -F 'filename=example.dat' http://www.example.com

它不起作用,我从服务器得到了400错误请求。 - Shanmukha Raju
我已经在上面的问题中添加了formadd函数。现在我得到了500个内部服务器错误。请求头是正确的,但我仍然不明白为什么会显示错误。 - Shanmukha Raju

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接