news 2026/9/10 4:32:44

curl 中 CURLINFO_PROTOCOL 选项详解:查询传输所用 URL 方案的已弃用 libcurl 接口与 CURLINFO_SCHEME 迁移指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
curl 中 CURLINFO_PROTOCOL 选项详解:查询传输所用 URL 方案的已弃用 libcurl 接口与 CURLINFO_SCHEME 迁移指南

curl 中 CURLINFO_PROTOCOL 选项详解:查询传输所用 URL 方案的已弃用 libcurl 接口与 CURLINFO_SCHEME 迁移指南

【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl

CURLINFO_PROTOCOL是 libcurl 通过curl_easy_getinfo()提供的一个查询选项,用于在传输完成后获取本次传输所使用的 URL 方案(scheme),返回一个long类型的CURLPROTO_*位标志。该选项自 7.52.0 引入,自 7.85.0 起被官方标记为弃用,并推荐改用返回字符串的CURLINFO_SCHEME。本文以 CURLINFO_PROTOCOL 官方文档 为核心,结合 curl 仓库源码,完整讲解其用法、全部可返回值、底层赋值链路以及弃用原因和迁移方法。

基本用法

CURLINFO_PROTOCOL的使用方式是通过curl_easy_getinfo()传入一个long *指针,接收最后一次传输所用的方案标志值:

#include <curl/curl.h> CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PROTOCOL, long *p);

注意几点关键约束:

  • 传入参数必须是long *类型指针,与其他CURLINFO_LONG类型选项(如CURLINFO_RESPONSE_CODE)使用同一取值通道;
  • 返回的是“最后一次传输”(the last transfer)所使用的方案,在curl_easy_perform()之后调用才有意义;
  • 该选项适用于所有协议(文档 front matter 中Protocol: All)。

include/curl/curl.h中,该枚举定义为CURLINFO_LONG + 48,且带有弃用属性:

CURLINFO_PROTOCOL CURL_DEPRECATED(7.85.0, "Use CURLINFO_SCHEME") = CURLINFO_LONG + 48,

见 include/curl/curl.h。紧随其后的CURLINFO_SCHEME = CURLINFO_STRING + 49就是官方推荐的替代选项。

返回值:CURLPROTO_* 位标志全集

文档列出的全部可能返回值如下,每个值都是一个独立的 bit(1L << N)。结合 include/curl/curl.h 中的定义,可整理成完整的取值表:

常量位值含义
CURLPROTO_HTTP1L << 0http
CURLPROTO_HTTPS1L << 1https
CURLPROTO_FTP1L << 2ftp
CURLPROTO_FTPS1L << 3ftps
CURLPROTO_SCP1L << 4scp
CURLPROTO_SFTP1L << 5sftp
CURLPROTO_TELNET1L << 6telnet
CURLPROTO_LDAP1L << 7ldap
CURLPROTO_LDAPS1L << 8ldaps
CURLPROTO_DICT1L << 9dict
CURLPROTO_FILE1L << 10file
CURLPROTO_TFTP1L << 11tftp
CURLPROTO_IMAP1L << 12imap
CURLPROTO_IMAPS1L << 13imaps
CURLPROTO_POP31L << 14pop3
CURLPROTO_POP3S1L << 15pop3s
CURLPROTO_SMTP1L << 16smtp
CURLPROTO_SMTPS1L << 17smtps
CURLPROTO_RTSP1L << 18rtsp
CURLPROTO_RTMP1L << 19rtmp
CURLPROTO_RTMPT1L << 20rtmpt
CURLPROTO_RTMPE1L << 21rtmpe
CURLPROTO_RTMPTE1L << 22rtmpete
CURLPROTO_RTMPS1L << 23rtmps
CURLPROTO_RTMPTS1L << 24rtMPTS
CURLPROTO_GOPHER1L << 25gopher
CURLPROTO_SMB1L << 26smb
CURLPROTO_SMBS1L << 27smbs
CURLPROTO_MQTT1L << 28mqtt
CURLPROTO_GOPHERS1L << 29gophers

头文件中还额外定义了CURLPROTO_ALL ((unsigned long)0xffffffff),表示“旧式”的“全部启用”掩码。需要说明:

  • 头文件明确注释这些CURLPROTO_定义“是供已弃用的CURLOPT_*PROTOCOLS选项使用的,请勿使用”(见 include/curl/curl.h)。CURLINFO_PROTOCOL只是复用了这套位定义作为“查询结果枚举”;
  • 文档所列的 RTMP 系列(RTMP/RTMPE/RTMPS/RTMPT/RTMPTE/RTMPTS)在头文件中仍保留位定义,但 RTMP 支持在较新的 curl 中已被移除,这些值实际上不会再被返回——这也是位枚举难以反映现状的一个例子;
  • 头文件注释特别指出long可能是 32 位或 64 位,但“永远不应依赖 32 位以外的任何假设”,因此这套位空间事实上只覆盖 30 个已知方案,无法表达后来新增的 scheme。

底层实现:conn_protocol 从哪来

从源码结构看,CURLINFO_PROTOCOL的取值链路非常短:

  1. 存储struct Curl_easy中的data->info结构保存conn_protocoluint32_t类型,见 lib/urldata.h)。curl_easy_getinfo处理前会在 lib/getinfo.c 将其清零(info->conn_protocol = 0;)。

  2. 赋值:真正写入发生在建连阶段。lib/url.c有两处赋值点:

    • file://这类无需网络连接的协议在 lib/url.c:

      data->info.conn_scheme = needle->scheme->name; /* conn_protocol can only provide "old" protocols */>data->info.conn_scheme =>case CURLINFO_PROTOCOL: *param_longp = (long)data->info.conn_protocol; break;
    • 掩码:赋值时与CURLPROTO_MASK0x3fffffff,定义于 lib/protocol.h)按位与,确保结果只落在 30 位已定义的枚举空间内。

对比之下,替代选项CURLINFO_SCHEME的读取实现是返回字符串指针data->info.conn_scheme(见 lib/getinfo.c 中case CURLINFO_SCHEME:分支),两者写入时机完全相同、来源相同(scheme->name),差异只在表达形式:一个是受限的位枚举,一个是任意 scheme 名称字符串。

弃用原因与 CURLINFO_SCHEME 迁移

文档明确声明:

This option is deprecated. We strongly recommend using CURLINFO_SCHEME(3) instead, because this option cannot return all possible schemes. The scheme might also sometimes be referred to as the protocol.

弃用时间点为7.85.0(DEPRECATED 章节),与curl.h中的CURL_DEPRECATED(7.85.0, "Use CURLINFO_SCHEME")一致。弃用的根本原因在于能力边界:

  • 位标志空间被固定为 30 个历史方案,任何新增 scheme(例如 curl 目前支持的wswss等 WebSocket 方案,以及未来新增的 scheme)都没有对应位,CURLINFO_PROTOCOL对它们无能为力;
  • CURLINFO_SCHEME返回char *(内部常量字符串,指向 scheme 名称,如"https"),可以表达任意方案,且与CURLINFO_PROTOCOL使用同一个内部字段conn_scheme,行为语义一致。

CURLINFO_SCHEME同样自 7.52.0 引入(见 CURLINFO_SCHEME 文档),因此迁移无需担心版本门槛——只要你的 libcurl >= 7.52.0,两个选项都可用;升级到 7.85.0 之后的版本时,继续编译使用CURLINFO_PROTOCOL的代码可能会触发编译器弃用告警(取决于CURL_DEPRECATED的宏实现)。

迁移前后代码对照

文档原始示例(使用已弃用选项):

int main(void) { CURL *curl = curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); result = curl_easy_perform(curl); if(result == CURLE_OK) { long scheme; curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &scheme); } curl_easy_cleanup(curl); } }

等价的推荐写法:

int main(void) { CURL *curl = curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); result = curl_easy_perform(curl); if(result == CURLE_OK) { char *scheme = NULL; curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme); /* scheme 为内部常量字符串(如 "https"),无需释放; 仅当本次传输未能建立连接时可能为 NULL,使用前建议判空 */ } curl_easy_cleanup(curl); } }

迁移检查清单:

  1. long scheme改为char *scheme = NULL
  2. CURLINFO_PROTOCOL改为CURLINFO_SCHEME
  3. 下游逻辑从“按位比较CURLPROTO_*”改为“字符串比较(如strcmp(scheme, "https") == 0)”,并处理scheme == NULL的边界情况。

如果确实需要保留旧式位标志(例如与既有CURLOPT_PROTOCOLS时代的判断逻辑对接),旧写法仍然可以编译运行,弃用是“推荐替换”而非“立即移除”,但新代码不应再引入该用法。

返回值与错误码

按文档 RETURN VALUE 章节:curl_easy_getinfo()返回CURLcode表示成功或错误。CURLE_OK(0)表示一切正常,非零表示发生错误(错误码含义参见 libcurl-errors 文档)。与CURLINFO_PROTOCOL相关的典型错误:

  • CURLE_BAD_FUNCTION_ARGUMENT:未先执行curl_easy_perform()或参数指针类型不匹配(例如误用curl_easy_setopt通道);
  • 从 lib/getinfo.c 的默认分支可见,未知选项类型会返回CURLE_UNKNOWN_OPTION,因此选项必须走CURLINFO_LONG通道,不能与其他类型选项混用指针类型。

注意:调用curl_easy_getinfo本身成功(返回CURLE_OK)不代表值一定有效——如果传输尚未进行或未建立连接,conn_protocol保持初始化的 0,读到 0 时应理解为“无对应老方案”,而非某个真实协议。

测试用例佐证

仓库自带的回归测试对两个选项成对覆盖,可直接作为行为参照:

  • tests/libtest/lib1535.c:专门测试CURLINFO_PROTOCOL。其流程为:curl_easy_init()→ 未执行传输时查询(验证返回 0/CURLE_OK)→ 用curl_easy_dupehandle()复制句柄后查询(验证 dupe 句柄行为)→curl_easy_setopt设置 URL 并执行curl_easy_perform()后再次查询(验证得到正确协议位),最终统一curl_easy_cleanup()收尾;
  • tests/libtest/lib1536.c:对CURLINFO_SCHEME做了完全对称的测试(注释即为“Test CURLINFO_SCHEME”),两者测试骨架一一对应,说明官方在实现层面把两个选项视为同一信息的两种表达方式。

阅读这两个文件可以快速确认:无论新旧选项,查询时机(perform 前后)、dupehandle 场景的语义都一致。

适用版本与小结

事项版本依据
CURLINFO_PROTOCOL引入7.52.0文档 front matterAdded-in: 7.52.0
CURLINFO_PROTOCOL弃用7.85.0文档 DEPRECATED 章节 + include/curl/curl.h
CURLINFO_SCHEME引入7.52.0CURLINFO_SCHEME 文档

小结:

  • CURLINFO_PROTOCOL通过curl_easy_getinfo(handle, CURLINFO_PROTOCOL, &long)返回最后一次传输所用方案的CURLPROTO_*位标志,内部取自data->info.conn_protocol,在lib/url.c建连时以scheme->protocol & CURLPROTO_MASK写入;
  • 它自 7.85.0 起弃用,原因是 30 位枚举空间无法覆盖所有 scheme,源码注释“can only provide 'old' protocols”是其直接证据;
  • 新代码与后续迁移应统一使用CURLINFO_SCHEME获取 scheme 字符串,两者共享同一内部数据源,语义等价、表达更完整;
  • 配套查询接口总览可参考 curl_easy_getinfo 文档 与 CURLINFO_RESPONSE_CODE 文档(文档 See-also 中列出的相邻选项)。

【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 4:32:12

Redis 6.2.6在Linux服务器上的源码编译与Docker部署指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/10 4:31:49

基于STM32智能停车场车位管理系统:从传感器选型到调试实战

简介&#xff1a;基于STM32单片机的智能停车场车位管理系统毕设源码&#xff0c;主要面向计算机、通信、人工智能、自动化等相关专业的学生、老师或从业者&#xff0c;适用于课程设计、大作业和毕业设计参考。源码以C语言编写&#xff0c;涵盖标准外设库、系统初始化、中断处理…

作者头像 李华
网站建设 2026/9/10 4:31:12

树莓派Pico低功耗实战:从35mA到2mA的空闲模式优化指南

入坑树莓派 Pico 之后&#xff0c;我第一个正经项目是给阳台上的自动灌溉系统做控制器。硬件很简单&#xff1a;一块 Pico、一个继电器、一个土壤湿度传感器&#xff0c;还有一节 18650 电池通过 LDO 供电。第一版代码参考主流教程框架写完&#xff0c;功能全部能跑&#xff0c…

作者头像 李华