【问题标题】:C++ Libcurl can't clear headersC++ Libcurl 无法清除标题
【发布时间】:2017-03-24 00:04:49
【问题描述】:

我有以下循环执行的 curl 函数:

curl = curl_easy_init();
if (curl) {
    CurlResponse = "";
    host = "http://exaple.com";
    LibcurlHeaders = curl_slist_append(LibcurlHeaders, "Expect:");
    curl_easy_setopt(curl, CURLOPT_URL, (host).c_str());
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER , 1);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST , 1);
    curl_easy_setopt(curl, CURLOPT_CAINFO, SSLPath.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, LibcurlHeaders);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, CurlVerbose);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, CurlPostData.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, LibcurlResponse);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &CurlResponse);
    res = curl_easy_perform(curl);
    curl_slist_free_all(LibcurlHeaders);        <----------
    if (res != CURLE_OK) {
        LibcurlError(curl_easy_strerror(res), host);
        }
    curl_easy_cleanup(curl);
    }
curl_global_cleanup();

删除线后一切正常:

curl_slist_free_all(LibcurlHeaders);

但是,在Libcurl Docs 中,它显示可以像我一样使用它。至少我是这么理解的……

那么我做错了什么和/或错过了什么?

感谢您的回答

* 编辑 *

所以,基本上:

LibcurlHeaders = null:

Curl call with headers
// cant clear headers
Curl call with 2 headers
// can't clear headers
Curl call with 3 headers
// can't clear headers

我想要的是 curl 调用中使用的标头在 curl 调用完成后被清除,所以我得到: LibcurlHeaders = null:

Curl call with headers
Headers cleared
Curl call with headers
Headers cleared
Curl call with headers
Headers cleared

【问题讨论】:

  • 我认为您显示的代码没有任何问题。致电curl_slist_free_all() 时遇到的实际问题是什么?它只能释放与列表关联的内存,但它不能将您的 LibcurlHeaders 变量设置为 NULL,如果这是您所期望的。在调用curl_slist_append() 之前确保LibcurlHeaders 最初为NULL,以便它分配一个新列表,然后在使用完成后使用curl_slist_free_all() 释放列表。
  • 我在脚本开始时将 LibcurlHeaders 设置为 null。好吧,当我添加启用 curl_slist_free_all 选项时,我的应用程序崩溃了...我希望该功能能够清除标头,因为过了一段时间我收到了来自服务器的 400 错误请求作为响应,因为发送的标头正在增长并且变得很大之后一会儿...因为我不知道如何重置 LibCurl 的 LibcurlHeaders (slist)
  • 嗯,您不认为这是应该包含在您的问题中的相关信息吗?始终提供具体的详细信息,并提供minimal reproducible example 来展示实际存在的问题。
  • 另外,由于您标记了问题C++,您可能会考虑使用libcurl 的C++ Bindings 之一,而不是直接使用C API。让 Binding 为您处理内存管理。
  • "一段时间后,我收到了来自服务器的 400 错误请求作为响应因为发送的标头正在增长并在一段时间后变得很大 " - 这意味着LibcurlHeaders 在调用curl_slist_append() 之前not NULL,因此您将越来越多的标头附加到单个列表中,以便在每个请求中重用。更有理由显示minimal reproducible example 来验证这一点。

标签: c++ http-headers libcurl request-headers


【解决方案1】:

您在 cmets 中说您在循环中调用 curl。你的例子没有表明这一点。但是假设您显示的代码在实际上处于循环中的较大代码内部,您只需要确保您的 LibcurlHeaders 变量是 NULL 在每个新的 HTTP 请求第一次调用 curl_slist_append() 之前,例如:

curl = curl_easy_init();
if (curl) {
    CurlResponse = "";
    host = "http://exaple.com";

    LibcurlHeaders = NULL; // <-- HERE
    LibcurlHeaders = curl_slist_append(LibcurlHeaders, "Expect:");

    /* alternatively, and ultimately safer and more accurate:
    LibcurlHeaders = curl_slist_append(NULL, "Expect:");
    */

    curl_easy_setopt(curl, CURLOPT_URL, host.c_str());
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
    curl_easy_setopt(curl, CURLOPT_CAINFO, SSLPath.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, LibcurlHeaders);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, CurlVerbose);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, CurlPostData.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, LibcurlResponse);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &CurlResponse);

    res = curl_easy_perform(curl);

    curl_slist_free_all(LibcurlHeaders);
    LibcurlHeaders = NULL; // <-- FOR GOOD MEASURE!

    if (res != CURLE_OK) {
        LibcurlError(curl_easy_strerror(res), host);
        }

    curl_easy_cleanup(curl);
    }

【讨论】:

  • 谢谢,您的示例使我能够修复 400 Bad request 问题。我使用了LibcurlHeaders = curl_slist_append(NULL, "Expect:");这一行,因此在LibCurl的开头和结尾都不必使用curl_slist_free_all(LibcurlHeaders);或将LibcurlHeaders重置为NULL!很好的解决方案,非常感谢。我想为我糟糕的文档道歉,但我真的用我一开始的代码给了我最好的机会。谢谢!
  • @TVAvanHesteren 你仍然需要使用curl_slist_free_all() 否则你会泄漏内存。重要的是您将 NULL 指针传递给 curl_slist_append(),以便它分配一个新列表而不是附加到现有列表。完成使用后,您仍然需要释放列表。您似乎不太了解指针和内存分配的一般工作原理
  • 感谢您的来信。确实,这对我来说很模糊。我会在我的代码中调整它
  • 我已经添加了curl_slist_free_all(LibcurlHeaders);,但是当添加到使用标头的 curl 请求时,脚本会立即崩溃。我已经使用了您的代码,但它仍然会因LibcurlHeaders = curl_slist_append(NULL, "Expect:"); 选项而崩溃。这怎么可能......我真的很困惑
【解决方案2】:

哇,

我设法解决了这个问题。这似乎是 Libcurl 的一个错误,可以很容易地修复。

问题是我在全局范围内声明了struct curl_slist *LibcurlHeaders=NULL;

当我在每个 curl_easy_init(); 调用之前声明 struct curl_slist *LibcurlHeaders=NULL; 并删除全局声明时,curl_slist_free_all(LibcurlHeaders); 工作并且不再使我的程序崩溃!

短:

问题在于struct curl_slist *LibcurlHeaders=NULL; 的全局声明必须在每个curl_easy_init(); 函数之前声明。

【讨论】:

  • 为什么在我的代码中?我可以在全球范围内声明它吗?因为我通过我的函数使用了很多变量,效果很好。
  • 当然你可以全局声明它,但是你需要把它当作一个全局的。这超出了 libcurl 的范围。它只是获取并使用您传递给它的指针。
  • 好的,感谢您的澄清。我想我明白你的意思了,谢谢
  • 简单地声明一个变量 global 而不是 local 不会导致错误。发生了其他事情。
猜你喜欢
  • 1970-01-01
  • 2018-06-28
  • 1970-01-01
  • 2017-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-05
相关资源
最近更新 更多