
libcurl CURLOPT_URL 完全指南URL 设置、协议猜测、编码与安全边界【免费下载链接】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本篇指南围绕 libcurl 的CURLOPT_URL选项展开说明如何在curl_easy_setopt中为一次传输指定目标 URL深入讲解 URL 解析时机、scheme 缺失时的协议猜测规则、ASCII/IDN 编码要求、默认值语义以及接收不可信外部 URL 时的安全风险与加固手段。读完你可以正确、安全地在自己的 C 程序中设置并执行任意受支持的 URL 传输并理解curl命令行工具底层是如何把用户输入的 URL 交给 libcurl 的。CURLOPT_URL 是什么CURLOPT_URL用于为一次传输指定目标 URL。它是 libcurl 中最基础、最常用的选项之一自 libcurl 7.1 起加入见本仓库 docs/libcurl/opts/CURLOPT_URL.md 头部元信息适用于所有协议。#include curl/curl.h CURLcode curl_easy_setopt(CURL *handle, CURLOPT_URL, char *URL);参数是一个指向 null 结尾字符串的char *该字符串必须以 URL 编码形式给出scheme://host:port/path更完整的格式规范可参考 RFC 3986。scheme即协议名如http、ftp、imaphost为服务器主机名port为可选的端口号path为资源路径URL 中还可以包含用户名、密码、查询串query、片段fragment等组成部分libcurl 会按 RFC 3986 的定义解析。一个最简可运行的示例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); curl_easy_cleanup(curl); } }解析时机设置时不解析执行时才生效libcurl不会在curl_easy_setopt(curl, CURLOPT_URL, ...)调用时校验语法或使用该 URL。即使传入一个非常离谱的值curl_easy_setopt仍然可能返回CURLE_OK。真正的解析发生在传输启动阶段即调用curl_easy_perform(3)或curl_multi_perform(3)时。从源码可以印证这一点。在 lib/setopt.c 中CURLOPT_URL的处理只是把字符串复制到内部存储并绑定到data-state.urlcase CURLOPT_URL: result Curl_setstropt(data, STRING_SET_URL, ptr); Curl_bufref_set(data-state.url, CURL_EASY_STR(data, STRING_SET_URL), 0, NULL); break;URL 的实际解析发生在 lib/url.c 的url_set_data_origin_and_creds函数中传输启动时libcurl 创建一个CURLUURL API 句柄用curl_url_set解析用户设置的 URL并把CURLU_GUESS_SCHEME、CURLU_NON_SUPPORT_SCHEME等标志传入解析后再用curl_url_get取回规范化normalized后的 URL 版本覆盖回内部存储。也就是说传给CURLOPT_URL的原始字符串和实际发起传输的 URL 可能不同——后者是经过解析、规范化、补全默认信息后的真实 URL。也正因如此curl_easy_setopt的返回值并不能反映 URL 是否合法。文档明确给出结论给一个坏 URLcurl_easy_setopt仍可能返回CURLE_OK0错误要到curl_easy_perform或类似函数执行时才暴露。缺失 scheme 时的协议猜测如果给定的 URL 缺少 scheme 名例如没有http://、ftp://这样的前缀libcurl 会根据主机名猜测协议若最外层子域名匹配DICT、FTP、IMAP、LDAP、POP3、SMTP之一则使用对应协议否则默认使用HTTP。也就是说ftp.example.com/file.txt会被当作 FTP URL而example.com/file.txt会被当作 HTTP URL。这一逻辑在 URL API 的guess_scheme函数中有精确实现见 lib/urlapi.cstatic CURLUcode guess_scheme(CURLU *u, struct dynbuf *host) { const char *hostname curlx_dyn_ptr(host); const char *schemep NULL; /* legacy curl-style guess based on hostname */ if(checkprefix(ftp., hostname)) schemep ftp; else if(checkprefix(dict., hostname)) schemep dict; else if(checkprefix(ldap., hostname)) schemep ldap; else if(checkprefix(imap., hostname)) schemep imap; else if(checkprefix(smtp., hostname)) schemep smtp; else if(checkprefix(pop3., hostname)) schemep pop3; else schemep http; u-scheme curlx_strdup(schemep); ... u-guessed_scheme TRUE; return CURLUE_OK; }注意这里猜测依据是主机名最外层的子域前缀ftp.、dict.等猜测成功后会在句柄上标记guessed_scheme TRUE以便后续curl_url_get可以据此决定是否在输出中补全 scheme。另外lib/urlapi.c 的Curl_is_absolute_url是判断 URL 是否绝对自带 scheme的底层函数它按 RFC 3986 3.1 节的 scheme 文法scheme ALPHA *( ALPHA / DIGIT / / - / . )扫描前导字符只有字母开头 冒号非猜测模式下或字母开头 ://猜测模式下才认定为绝对 URL。关闭猜测CURLOPT_DEFAULT_PROTOCOL协议猜测可以通过设置默认协议来关闭。CURLOPT_DEFAULT_PROTOCOL见 docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.md指定当 URL 缺少 scheme 时一律使用的协议。对应实现位于 lib/url.c在解析 URL 之前如果设置了默认协议且当前 URL 不是绝对 URL!Curl_is_absolute_url(...)则直接拼接出默认协议://原始字符串形式的完整 URLif(CURL_EASY_STR(data, STRING_DEFAULT_PROTOCOL) !Curl_is_absolute_url(Curl_bufref_ptr(data-state.url), NULL, 0, TRUE)) { char *url curl_maprintf(%s://%s, CURL_EASY_STR(data, STRING_DEFAULT_PROTOCOL), Curl_bufref_ptr(data-state.url)); ... Curl_bufref_set(data-state.url, url, 0, curl_free); }例如设置了CURLOPT_DEFAULT_PROTOCOL, https后传入example.com会被强制当作https://example.com不再按主机名前缀猜测。libcurl 内部对 DoHDNS over HTTPS请求就是这么做的见 lib/vdns/doh.cERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, https);。不支持协议的报错路径如果协议——无论是 URL 里显式写明的 scheme还是 libcurl 根据主机名推断出来的——是当前 libcurl 构建不支持的那么在调用curl_easy_perform(3)或curl_multi_perform(3)时会返回CURLE_UNSUPPORTED_PROTOCOL。底层链路如下URL API 解析时若遇到不认识的 scheme会返回CURLUE_UNSUPPORTED_SCHEMElib/url.c 的Curl_uc_to_curlcode把它映射为CURLE_UNSUPPORTED_PROTOCOL连接建立阶段lib/url.c 的url_set_conn_scheme还会根据该协议是否在构建中被启用scheme-run是否被CURLOPT_PROTOCOLS_STR允许allowed_protocols是否允许在重定向中使用redir_protocols逐项校验任一不满足都会 failf 提示Protocol ... is disabled并返回CURLE_UNSUPPORTED_PROTOCOL。要查看当前 libcurl 构建到底支持哪些协议使用curl_version_info(3)。命令行工具下可以用curl --version查看编译进的功能与协议列表。限制可用协议CURLOPT_PROTOCOLS_STRCURLOPT_PROTOCOLS_STR见 docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.md可以在独立于编译期支持范围的前提下限制本次传输允许使用的协议。如果你接受的 URL 来自外部来源希望把可访问性收窄到白名单这个选项非常有用——比如只允许http和https其余协议一律拒绝。与 CURLOPT_CURLU 的关系如果设置了CURLOPT_CURLU提供一个预先构造好的 URL API 句柄那么CURLOPT_URL的字符串会被忽略。二者必须设置其一传输才能启动如果都不设置无法发起任何传输。CURLOPT_CURLU的完整语义见 docs/libcurl/opts/CURLOPT_CURLU.md。从 lib/url.c 可以看到传输启动时若data-set.uh存在且不是重定向跟随场景libcurl 会直接复制该句柄curl_url_dup作为解析结果完全跳过对CURLOPT_URL字符串的curl_url_set解析。字符串生命周期与重复设置无需长期保存字符串设置完该选项后应用不需要继续保留这个字符串libcurl 会拷贝一份内部保存。重复设置取最后一次多次设置CURLOPT_URL时最后一次设置的值覆盖之前的。置 NULL 可停用把它设为NULL可以停用该选项但请注意libcurl 执行传输必须有一个 URL停用后自然无法发起传输。解析器一致CURLOPT_URL的字符串所使用的解析器与curl_url_set(3)用的是同一个即前面提到的 URL API /CURLU句柄因此两者对 URL 的接受程度、规范化规则完全一致。相关 API 详见 docs/libcurl/opts/curl_url_set.md 与 docs/libcurl/opts/curl_url_get.md。编码要求ASCII 与 IDNCURLOPT_URL指向的字符串总体上要求是ASCII 兼容编码的字符序列。带 IDN 支持的构建服务器名host部分可以使用国际化域名——按当前 locale 的编码传入在 WinIDN 或使用 libidn2 的 Windows Unicode 构建下则使用 UTF-8。libcurl 会把国际化主机名转成 punycode 后再交给解析器。不带 IDN 支持的构建服务器名会原样严格按传入的字节交给名称解析函数resolver。也就是说此时非 ASCII 主机名可能解析失败或解析出意料之外的结果。因此在编写跨平台、跨构建配置的代码时建议对非 ASCII 的主机名先自行做 IDN 转 ASCIIpunycode处理或确保目标构建启用了 IDN 支持。本仓库中 IDN 相关的实现集中在 lib/idn.c 及其头文件 lib/idn.h。默认值NULLCURLOPT_URL的默认值是NULL。如果未设置该选项无法执行任何传输——这也解释了上文二者必须设置其一的约束。安全注意事项接受外部 URL 的风险应用有时为了方便会让用户自由指定 URL然后把用户字符串直接喂给CURLOPT_URL。从不受信任的外部来源获取 URL 会带来一系列安全风险本地资源访问SSRF如果你的应用以服务器进程方式运行或运行在服务器环境中一条不加过滤的 URL 很容易诱导你的应用去访问本地资源而不是远端。例如http://127.0.0.1/...、http://localhost/...、http://[::1]/...都可能指向本机服务。在接收用户提供的 URL 时防住 localhost 访问本身就很难。任意端口访问端口号是 URL 格式的常规组成部分恶意构造的 URL 可以访问你计划之外的端口。本地主机 自定义端口的组合可能让外部用户对你本地的服务玩花样例如探测内网端口、访问未授权的本地管理端口。非预期协议接收外部 URL 还意味着对方可能使用http://之外的其他协议。应当用CURLOPT_PROTOCOLS_STR(3)把可接受的协议限制住。重定向链用户提供的 URL 可以指向会继续重定向的站点重定向甚至可能换到其他协议。请认真考虑你的CURLOPT_FOLLOWLOCATION见 docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.md与CURLOPT_REDIR_PROTOCOLS_STR见 docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS_STR.md设置——比如是否允许重定向以及重定向时允许哪些协议通常应只放行http/https。推荐的最小加固清单使用CURLOPT_PROTOCOLS_STR只允许必要的协议如http,https对 URL 做 host 解析与白/黑名单校验尤其拒绝 localhost、环回地址127.0.0.0/8、::1、链路本地地址及内网网段用CURLOPT_REDIR_PROTOCOLS_STR限制重定向后的协议防止协议降级/升级被利用谨慎对待CURLOPT_FOLLOWLOCATION必要时限制重定向次数CURLOPT_MAXREDIRS见 docs/libcurl/opts/CURLOPT_MAXREDIRS.md考虑与CURLOPT_DISALLOW_USERNAME_IN_URL见 docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.md配合拒绝 URL 中携带用户名防止http://user:passhost这类注入形式。返回值curl_easy_setopt(3)返回一个CURLcode表示成功或失败CURLE_OK0表示一切正常非零值表示出错具体错误码含义见libcurl-errors(3)文档见 docs/libcurl/libcurl-errors.md。再次强调curl_easy_setopt(3)不会解析传入的字符串所以即使 URL 是坏的也检测不到错误要到curl_easy_perform(3)或类似函数被调用时才会暴露。命令行工具如何设置 URL作为对照curl命令行工具在把用户参数转成 libcurl 调用时最终也是落到CURLOPT_URL上。本仓库 src/config2setopts.c 中有MY_SETOPT_STR(curl, CURLOPT_URL, per-url);即工具解析完命令行参数后把规范化后的 URL 字符串经CURLOPT_URL交给 libcurl。命令行的 URL 解析细节通配符、--url选项等可参考 docs/cmdline-opts/url.md。这意味着你在命令行里观察到的curl行为如缺 scheme 时按主机名猜协议、--proto限制协议、--max-redirs限制重定向等底层都与本文描述的CURLOPT_URL及其关联选项一一对应。关键关联选项速查选项作用文档CURLOPT_DEFAULT_PROTOCOLURL 缺 scheme 时强制使用的默认协议docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.mdCURLOPT_CURLU用预先构造的 URL 句柄替代 URL 字符串docs/libcurl/opts/CURLOPT_CURLU.mdCURLOPT_PROTOCOLS_STR限制本次传输允许的协议白名单docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.mdCURLOPT_REDIR_PROTOCOLS_STR限制重定向时允许的协议docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS_STR.mdCURLOPT_FOLLOWLOCATION是否跟随 HTTP 重定向docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.mdCURLOPT_MAXREDIRS最大重定向次数docs/libcurl/opts/CURLOPT_MAXREDIRS.mdCURLOPT_PATH_AS_IS是否按原样使用路径不做点段规范化docs/libcurl/opts/CURLOPT_PATH_AS_IS.mdCURLOPT_FORBID_REUSE/CURLOPT_FRESH_CONNECT连接复用控制影响 URL 变更后的连接行为docs/libcurl/opts/CURLOPT_FORBID_REUSE.md / docs/libcurl/opts/CURLOPT_FRESH_CONNECT.mdCURLINFO_REDIRECT_URL读取实际重定向后的最终 URLdocs/libcurl/opts/CURLINFO_REDIRECT_URL.md以上选项的完整列表同时记录在CURLOPT_URL文档的 See-also 元信息中见 docs/libcurl/opts/CURLOPT_URL.md。在实践中建议把设置 URL与设置协议白名单 重定向策略视为一个整体来设计尤其当 URL 来源不可控时。【免费下载链接】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),仅供参考