libcurl 存在内存溢出问题

libcurl 7.69.0 ~ 8.3.0版本,不受漏洞影响的版本:libcurl < 7.69.0 和 >= 8.4.0    (问题记录)

mac 中总会有内存增加得非快, 替换后解决问题

官方描述 curl 8.4.0 | daniel.haxx.se

<think> 我们使用libcurl来提取HTTP响应中的Location标头(重定向URL)。主要步骤如下: 1. 使用curl_easy_init()初始化一个CURL句柄。 2. 设置URL和回调函数(CURLOPT_WRITEFUNCTION)以捕获响应体(如果需要的话),但我们更关注头部。 3. 设置一个回调函数来捕获头部(CURLOPT_HEADERFUNCTION),并在其中查找"Location"标头。 4. 或者,我们可以设置CURLOPT_FOLLOWLOCATION为0来禁止自动重定向,这样我们就能在响应头部中看到Location。 5. 使用curl_easy_perform()执行请求。 6. 在头部回调函数中,检查每个头部行是否以"Location: "开头,然后提取其值。 具体实现: 我们将编写一个用于处理头部的回调函数,当接收到头部数据时,该函数会被调用。我们在这个函数中检查是否有Location头。 注意:Location头在重定向响应(如301, 302等)中出现。 示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <curl/curl.h> // 用于存储Location的全局变量(简单示例,实际应用中可改为结构体等) static char location[1024] = {0}; // 头部回调函数 static size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata) { // 每个头部行都会调用此函数,buffer是头部行的数据,大小为size*nitems size_t numbytes = size * nitems; // 检查是否是Location头 if (strncmp(buffer, "Location: ", 10) == 0) { // 找到Location头,提取后面的URL const char *location_value = buffer + 10; // 跳过"Location: " // 去掉可能有的换行符(可能是\r\n或\n) char *pos; if ((pos = strchr(location_value, '\r')) != NULL) { *pos = '\0'; } if ((pos = strchr(location_value, '\n')) != NULL) { *pos = '\0'; } // 复制到全局变量location中,注意避免溢出 strncpy(location, location_value, sizeof(location)-1); location[sizeof(location)-1] = '\0'; } return numbytes; // 必须返回实际处理的字节数 } int main(void) { CURL *curl; CURLcode res; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { // 设置要访问的URL curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); // 禁止自动重定向,这样我们才能看到Location头 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0L); // 设置头部回调函数 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback); // 可以设置一个userdata指针,这里我们不需要,设为NULL curl_easy_setopt(curl, CURLOPT_HEADERDATA, NULL); // 执行请求 res = curl_easy_perform(curl); // 检查错误 if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } else { // 如果成功,我们打印Location if (location[0] != '\0') { printf("Location: %s\n", location); } else { printf("No Location header found.\n"); } } // 清理 curl_easy_cleanup(curl); } curl_global_cleanup(); return 0; } ``` 注意事项: 1. 上述代码使用了一个全局变量来存储Location,在实际应用中,可以通过设置userdata(CURLOPT_HEADERDATA)来传递一个结构体,避免全局变量。 2. 我们禁止了自动重定向(CURLOPT_FOLLOWLOCATION设为0),这样libcurl就不会自动跟随重定向,而是返回原始响应,包括Location头。 3. 在头部回调函数中,我们处理了换行符,因为头部行以\r\n或\n结束,我们将其截断以便获得纯URL字符串。 4. 如果存在多个Location头(通常不会),这里只保存最后一个。根据HTTP标准,Location头在重定向响应中应该只有一个。 编译命令(假设使用gcc): ```bash gcc -o location location.c -lcurl ``` §§相关问题§§ 1. 如何让libcurl自动跟随重定向? 2. 除了Location头,如何提取其他HTTP响应头? 3. 在libcurl中如何处理HTTPS请求? 4. 如果重定向链中有多个跳转,如何获取每一个跳转的Location? 5. 如何设置libcurl的超时时间? </think> # 使用 libcurl 提取 Location 标头 在 libcurl 中提取 HTTP Location 标头(重定向 URL)有以下几种方法: ## 方法一:使用 HEADERFUNCTION 回调(推荐) 这是最灵活的方式,可以精确控制标头处理: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <curl/curl.h> // 全局变量存储Location static char redirect_url[2048] = ""; // 标头回调函数 static size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata) { size_t real_size = size * nitems; const char *prefix = "Location: "; size_t prefix_len = strlen(prefix); // 检查是否为Location标头 if (strncasecmp(buffer, prefix, prefix_len) == 0) { // 提取Location值 char *location_start = buffer + prefix_len; char *end = strpbrk(location_start, "\r\n"); if (end) *end = '\0'; // 截断到行尾 // 复制到全局变量 strncpy(redirect_url, location_start, sizeof(redirect_url) - 1); redirect_url[sizeof(redirect_url) - 1] = '\0'; } return real_size; } int main(void) { CURL *curl; CURLcode res; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { // 设置URL curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); // 禁止自动重定向 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0L); // 设置标头回调函数 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback); curl_easy_setopt(curl, CURLOPT_HEADERDATA, NULL); // 执行请求 res = curl_easy_perform(curl); // 检查错误 if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } else { // 输出提取的Location if (redirect_url[0] != '\0') { printf("Found Location: %s\n", redirect_url); } else { printf("No Location header found\n"); } } // 清理 curl_easy_cleanup(curl); } curl_global_cleanup(); return 0; } ``` ## 方法二:使用 CURLINFO_REDIRECT_URL(仅限最终重定向) 此方法只能获取最终重定向的URL: ```c // 在curl_easy_perform之后添加: char *final_url = NULL; curl_easy_getinfo(curl, CURLINFO_REDIRECT_URL, &final_url); if (final_url) { printf("Final redirect URL: %s\n", final_url); } ``` ## 方法三:使用 CURLOPT_FOLLOWLOCATION 和 CURLOPT_MAXREDIRS 自动跟随重定向并获取所有重定向链: ```c // 设置重定向选项 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // 启用重定向 curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10L); // 最大重定向次数 // 在执行请求后获取重定向历史 struct curl_slist *redirects = NULL; curl_easy_getinfo(curl, CURLINFO_REDIRECT_LIST, &redirects); // 遍历所有重定向URL printf("Redirect chain:\n"); struct curl_slist *item = redirects; while (item) { printf(" - %s\n", item->data); item = item->next; } // 注意:不要释放此列表,libcurl会管理它的内存 ``` ## 关键点说明 1. **禁止自动重定向**: ```c curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0L); ``` 这是提取中间Location标头而非最终URL的关键设置 2. **标头处理注意事项**: - Location 标头可能包含空格和特殊字符 - 标头行以 `\r\n` 结束 - HTTP/2 标头使用小写形式,所以使用 `strncasecmp` 进行不区分大小写的比较 3. **错误处理**: ```c if (res != CURLE_OK) { fprintf(stderr, "Error: %s\n", curl_easy_strerror(res)); } ``` 4. **编译命令**: ```bash gcc -o location_extractor location_extractor.c -lcurl ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值