curl/libcurl 的 CURLOPT_POSTFIELDSIZE 详解:精确指定 POST 数据长度,让二进制数据安全上传 curl/libcurl 的 CURLOPT_POSTFIELDSIZE 详解精确指定 POST 数据长度让二进制数据安全上传【免费下载链接】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_POSTFIELDSIZE是 libcurl 中用于声明 POST 请求体数据长度的选项其核心价值在于当调用方通过CURLOPT_POSTFIELDS传入静态内存数据时可以显式告知 libcurl 数据的字节长度从而避免 libcurl 使用strlen()自动测量那会在数据首次出现\0字节处截断使包含\0的二进制数据也能被完整、安全地 POST 到服务器。本文以 curl 仓库中的 CURLOPT_POSTFIELDSIZE 官方文档 为骨架结合 lib/setopt.c、lib/http.c、lib/mqtt.c、lib/rtsp.c 等源码实现完整讲解该选项的用法、默认值、边界约束及其与CURLOPT_POSTFIELDSIZE_LARGE、CURLOPT_COPYPOSTFIELDS等选项的配合关系。读完本文你将掌握如何用正确姿势发送二进制 POST 数据、如何区分大小两个变体的适用场景以及它们背后的源码行为。选项概览与适用协议CURLOPT_POSTFIELDSIZE的作用是告诉 libcurl 由CURLOPT_POSTFIELDS或CURLOPT_COPYPOSTFIELDS指向的 POST 数据的字节大小。按官方文档该选项适用于以下协议HTTP最典型的使用场景对应application/x-www-form-urlencoded风格的简单 POST 请求体MQTTMQTT 协议借用了部分 HTTP 选项lib/mqtt.c中的mqtt_publish()会直接读取data-set.postfields与data-set.postfieldsize来构造 PUBLISH 报文RTSPRTSP 的 SET_PARAMETER 等请求同样借用了该选项见 lib/rtsp.c。选项从 curl 7.2 版本开始提供见文档Added-in: 7.2字段在 lib/easyoptions.c 的选项表中被登记为CURLOT_LONG类型即它接收一个long类型的值。函数原型与调用方式该选项通过通用的curl_easy_setopt接口设置函数原型如下#include curl/curl.h CURLcode curl_easy_setopt(CURL *handle, CURLOPT_POSTFIELDSIZE, long size);设置成功时返回CURLE_OK (0)非零值表示出错具体错误码可参考 libcurl-errors(3)。官方文档给出的完整示例#include string.h /* for strlen */ int main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; static const char *data data to send; curl_easy_setopt(curl, CURLOPT_URL, https://example.com); /* size of the POST data */ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(data)); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); result curl_easy_perform(curl); curl_easy_cleanup(curl); } }需要注意示例中显式将strlen()的结果强转为long后传入这正是该选项的设计初衷——由调用方负责测量长度libcurl 不再重复执行strlen()。核心语义为什么需要显式指定大小规避 strlen() 的截断问题官方文档对DESCRIPTION的说明非常明确如果你想把静态数据 POST 给服务器却不想让 libcurl 执行strlen()去测量数据大小就必须使用本选项。一旦使用该选项就可以发送完全二进制的数据否则二进制数据中夹杂\0字节时POST 几乎必然失败——因为strlen()以\0为终止符会在第一个空字节处提前停止导致请求体被截断。size 为 -1 时的回退行为如果将该大小设置为-1libcurl 会退回到strlen()测量或者依赖CURLOPT_READFUNCTION若使用了读取回调来发出数据结束的信号。也就是说-1相当于我不确定/我不想算请你自行判断。超过 2GB 时使用大尺寸变体如果 POST 的数据超过 2GB超出long在 32 位平台的可表达范围必须改用CURLOPT_POSTFIELDSIZE_LARGE它接收curl_off_t类型在 lib/easyoptions.c 中登记为CURLOT_OFF_T可以表达更大的尺寸。默认值与源码级验证文档DEFAULT字段明确指出该选项的默认值为-1即默认情况下 libcurl 走strlen()测量路径。在 lib/http.c 的HTTPREQ_POST分支中可以清楚看到该默认值的影响case HTTPREQ_POST: /* this is the simple POST, using x-www-form-urlencoded style */ /* the size of the post body */ if(!postsize) { result Curl_creader_set_null(data); } else if(data-set.postfields) { size_t plen curlx_sotouz_range(postsize, 0, SIZE_MAX); if(plen SIZE_MAX) return CURLE_OUT_OF_MEMORY; else if(plen) result Curl_creader_set_buf(data,>case CURLOPT_POSTFIELDSIZE: if(arg -1) return CURLE_BAD_FUNCTION_ARGUMENT; if(s-postfieldsize arg s-str_copypostfields) { curlx_safefree(s-str_copypostfields); s-postfields NULL; } s-postfieldsize arg; break;这里有两层含义参数校验传入小于-1的值会被拒绝返回CURLE_BAD_FUNCTION_ARGUMENT。失效旧数据如果新声明的大小比之前已设置的postfieldsize更大且此前用过CURLOPT_COPYPOSTFIELDSlibcurl 会主动释放旧副本并将postfields置为NULL——因为旧的复制数据已无法覆盖新声明的更大长度继续使用会导致越界读。这也意味着设置大小的顺序与数据来源必须协调一致否则可能出现数据指针被清空的情况。CURLOPT_POSTFIELDSIZE_LARGElib/setopt.c 中处理具备完全相同的校验与失效逻辑只是接受curl_off_t类型的offtcase CURLOPT_POSTFIELDSIZE_LARGE: if(offt -1) return CURLE_BAD_FUNCTION_ARGUMENT; if(s-postfieldsize offt s-str_copypostfields) { /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */ curlx_safefree(s-str_copypostfields); s-postfields NULL; } s-postfieldsize offt; break;最终两者都写入同一个字段s-postfieldsize因此它们本质上是同一语义的小尺寸/大尺寸两个入口。在 MQTT 与 RTSP 协议中的实际使用MQTTPUBLISH 报文的负载来源MQTT 协议借用了 HTTP 的 POST 选项lib/setopt.c 中注释 MQTT borrows some of the HTTP options。在 lib/mqtt.c 的mqtt_publish()中char *payload >if(data-set.postfields) { size_t plen (data-set.postfieldsize 0) ? (size_t)data-set.postfieldsize : strlen(data-set.postfields); result Curl_creader_set_buf(data, contenteditable="false">【免费下载链接】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),仅供参考