libcurl CURLOPT_CRLF 选项详解:Unix 换行符到 CRLF 的转换机制与源码实现
libcurl CURLOPT_CRLF 选项详解Unix 换行符到 CRLF 的转换机制与源码实现【免费下载链接】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导读CURLOPT_CRLF是 libcurl 提供的一个用于在上传/下载传输过程中把 Unix 换行符LF转换为 CRLF 换行符\r\n的 legacy 选项。它在 FTP、SMTP 等传统协议与大型机如 MVS/OS/390场景中仍有实际价值。本文以 docs/libcurl/opts/CURLOPT_CRLF.md 为主线结合仓库中 lib/setopt.c、lib/sendf.c、lib/ftp.c、lib/imap.c 等源码完整讲解该选项的用法、底层转换 reader 的实现原理、协议差异与注意事项。读完后你将能正确判断何时启用 CRLF 转换、理解其对上传字节数和文件大小校验的影响并能追踪该选项从curl_easy_setopt到实际字节流的完整调用链。NAME 与原型一个开关型 long 参数该选项的功能定义为 CRLF conversion其 API 原型如下对应文档 SYNOPSIS 节#include curl/curl.h CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CRLF, long conv);从参数签名可以看出它接受一个long类型的开关值传入1开启转换传入0关闭转换。选项在 curl 7.1 版本中加入文档 frontmatter 中的Added-in: 7.1属于最早一批 libcurl 选项之一。在当前的 libcurl 内部该选项被登记在 lib/easyoptions.c 的选项表中{ CRLF, CURLOPT_CRLF, CURLOT_LONG, 0 },CURLOT_LONG表示其参数类型为长整型与文档中 Pass a long 的描述一致。命令行工具curl也提供了对应的--crlf选项见 docs/cmdline-opts/crlf.md其 Help 文案为 Convert LF to CRLF in upload可用于 FTP、SMTP 协议的上传场景。DESCRIPTION转换行为与 legacy 定位文档对行为的描述非常简洁Pass a long. If the value is set to 1 (one), libcurl converts Unix newlines to CRLF newlines on transfers. Disable this option again by setting the value to 0 (zero).This is a legacy option of questionable use.要点提炼开启条件conv值为1时libcurl 在传输过程中把 Unix 换行符\n0x0A转换为 CRLF\r\n0x0D 0x0A。关闭方式将值设为0默认值即0即可禁用。官方态度文档明确标注这是 a legacy option of questionable use一个存疑的遗留选项。这意味着新代码应谨慎使用仅在确有协议兼容或大型机场景需求时启用。值得注意的细节转换方向是单向的 LF → CRLF它不会把 CRLF 转换回 LF也不负责内容的其他换行风格处理。如果数据中已经存在\r\n对转换器会识别并跳过避免产生\r\r\n的双 CR 错误见下文源码分析。源码实现setopt 到转换 Reader 的完整链路1. 参数接收setopt.c 中的 Kludgy optionCURLOPT_CRLF的实际处理位于 lib/setopt.ccase CURLOPT_CRLF: /* * Kludgy option to enable CRLF conversions. Subject for removal. */ s-crlf enabled; break;源码注释直言这是 Kludgy option笨拙的选项且 Subject for removal随时可能被移除与文档中 legacy option of questionable use 的定位互相印证。这里接收到的值被存入 easy handle 的设置结构体data-set.crlf其类型定义在 lib/urldata.hBIT(crlf); /* convert crlf on ftp upload(?) */BIT()宏将该字段声明为位域布尔值且注释用疑问句 on ftp upload(?) 表明其生效范围在历史上与 FTP 上传强相关——实际上该选项对所有上传路径均可能生效见下文。2. 转换执行sendf.c 中的 cr-lineconv Reader真正的字节级转换并不散落在各协议实现中而是由一个名为cr-lineconvstruct cr_lc的客户端读取器client reader统一完成实现在 lib/sendf.c。状态上下文lib/sendf.cstruct cr_lc_ctx { struct Curl_creader super; struct bufq buf; BIT(read_eos); /* we read an EOS from the next reader */ BIT(eos); /* we have returned an EOS */ BIT(prev_cr); /* the last byte was a CR */ };内部使用一个 16KB 软上限缓冲区Curl_bufq_init2(ctx-buf, (16 * 1024), 1, BUFQ_OPT_SOFT_LIMIT)暂存待转换数据并用prev_cr记录上一个字节是否为\r以便跨数据块正确判断\r\n边界。核心转换逻辑lib/sendf.c/* at least one \n might need conversion to \r\n, place into ctx-buf */ for(i start 0; i nread; i) { /* if this byte is not an LF character, or if the preceding character is a CR (meaning this already is a CRLF pair), go to next */ if((buf[i] ! \n) || ctx-prev_cr) { ctx-prev_cr (buf[i] \r); continue; } ctx-prev_cr FALSE; /* on a soft limit bufq, we do not need to check length */ result Curl_bufq_cwrite(ctx-buf, buf start, i - start, n); if(!result) result Curl_bufq_cwrite(ctx-buf, STRCONST(\r\n), n); if(result) return result; start i 1; }这段循环揭示了转换的关键规则逐字节扫描输入遇到\n且前一个字节不是\r时在\n前插入一个\r输出\r\n如果\n前一个字节已经是\r即输入本身就是标准 CRLF则直接跳过保持原样避免产生\r\r\n若一批数据末尾的\r可能与下一批数据的\n配对则由prev_cr状态跨批次记忆。另外还做了快速路径优化lib/sendf.c当memchr(buf, \n, nread)找不到任何\n时整批数据原样透传不进入逐字节转换循环保证无 LF 内容的性能不受影响。Reader 的挂载时机lib/sendf.cclen r-crt-total_length(data, r); /* if we do not have 0 length init, and CRLF conversion is wanted, * add the reader for it */ if(clen #ifdef CURL_PREFER_LF_LINEENDS (data-set.crlf ||>else if(data-state.upload) { if((ftp-transfer PPTRANSFER_BODY) (data-state.infilesize ! -1) /* upload with known size */ ((!data-set.crlf !data-state.prefer_ascii /* no conversion */ (data-state.infilesize !>/* Check we know the size of the upload. This takes all readers * into account. Especially crlf conversions which make the size * unpredictable, e.g. -1. */>curl --crlf -T file ftp://example.com/--crlf与--use-ascii即 libcurl 的CURLOPT_TRANSFERTEXT/ASCII 模式是两条不同的路径前者无条件做 LF→CRLF 转换后者设置 ASCII 传输模式在部分平台二者会同时触发 cr-lineconv reader见上文CURL_PREFER_LF_LINEENDS分支因此组合使用时需注意转换不会重复进行——reader 对已存在的\r\n会跳过不会产生\r\r\n。典型使用示例以下完整示例来自文档的 EXAMPLE 节展示了最小可用代码int main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, ftp://example.com/); curl_easy_setopt(curl, CURLOPT_CRLF, 1L); result curl_easy_perform(curl); curl_easy_cleanup(curl); } }实际应用中更常见的组合是配合上传一起使用CURL *curl curl_easy_init(); if(curl) { FILE *fp fopen(local_unix_text.txt, rb); curl_easy_setopt(curl, CURLOPT_URL, ftp://example.com/upload.txt); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); curl_easy_setopt(curl, CURLOPT_READDATA, fp); curl_easy_setopt(curl, CURLOPT_CRLF, 1L); /* LF - CRLF */ curl_easy_perform(curl); curl_easy_cleanup(curl); fclose(fp); }实战建议只对纯文本内容开启二进制内容中可能出现的0x0A会被误转换破坏数据完整性与CURLOPT_UPLOAD配合做 FTP/SMTP 文本上传时使用HTTP 上传一般无需该选项HTTP 协议层由 Content-Length 精确控制不要与 IMAPAPPEND一起使用会返回CURLE_UPLOAD_FAILED对既有代码而言若项目没有大型机或古老 FTP 服务器兼容需求应保持默认值 0 并考虑用 ASCII 模式等替代手段。RETURN VALUE返回值语义curl_easy_setopt调用该选项后返回CURLcodeCURLE_OK (0)设置成功非零值发生错误具体错误码参见 docs/libcurl/libcurl-errors.md。由于该选项只是把一个 long 值写入内部结构体s-crlf enabled见 lib/setopt.c正常情况下总是返回CURLE_OK参数类型不匹配等调用错误会在 setopt 的公共入口统一拦截。DEFAULT 与 AVAILABILITY默认值0关闭。所有新建的 easy handle 默认不执行任何换行转换。可用性自 curl7.1起加入所有协议均接受该选项文档 frontmatter 中Protocol: All但如前所述其转换效果主要体现在上传路径FTP、SMTP并对 IMAP 等需要预知大小的协议产生实际限制。命令行--crlf自 curl 5.7 起提供。兼容性选项在 setopt 阶段只做状态记录真正的转换行为由cr-lineconvreader 在传输阶段执行lib/sendf.c因此开启/关闭的代价极小不会影响连接建立与协议协商。相关选项该选项的 See-also 链接指向两个转换回调历史遗留与字符集转换相关与行尾转换是不同机制CURLOPT_CONV_FROM_NETWORK_FUNCTION从网络编码转换为本地编码的回调CURLOPT_CONV_TO_NETWORK_FUNCTION从本地编码转换为网络编码的回调。命令行侧的对应选项为--crlfdocs/cmdline-opts/crlf.md与--use-ascii。若想进一步了解 easy 选项的通用设置/获取机制可查阅 docs/libcurl/curl_easy_setopt.md 与 docs/libcurl/curl_easy_getinfo.md。小结项目结论选项名CURLOPT_CRLFlong 型开关默认值0关闭加入版本curl 7.1--crlf命令行选项自 5.7核心行为上传时把 LF 逐字节转换为 CRLF已存在的\r\n保持原样源码位置参数存储 lib/setopt.c、结构体 lib/urldata.h、转换 reader lib/sendf.c主要限制转换后大小不可预测FTP 放宽校验、IMAPAPPEND直接拒绝适用场景大型机MVS/OS/390文本上传、旧式 FTP/SMTP 文本服务器兼容CURLOPT_CRLF是一个功能简单但副作用隐蔽的 legacy 选项打开开关只是一行代码但转换会悄然改变上传字节数与大小校验语义。理解 lib/sendf.c 中cr-lineconvreader 的遇\n前无\r才插入\r规则以及 lib/ftp.c、lib/imap.c 中的两处大小校验分支是安全使用该选项的关键。在绝大多数现代场景下保持默认的 0 值即可。【免费下载链接】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),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →