C++客户端与Cloudflare Worker SHA-1校验和不匹配问题排查
我正尝试从嵌入式设备向Cloudflare上传文件。C++应用在上传前生成SHA-1校验和,代码如下:
std::string generate_checksum(const std::string& file_path) { std::string test_file_path = file_path; std::ifstream file(test_file_path, std::ios::binary); if (!file) { throw std::runtime_error("Cannot open file for checksum."); } SHA_CTX sha1; SHA1_Init(&sha1); char buffer[8192]; while (file.read(buffer, sizeof(buffer))) { SHA1_Update(&sha1, buffer, file.gcount()); } unsigned char hash[SHA_DIGEST_LENGTH]; SHA1_Final(hash, &sha1); std::ostringstream result; for (int i = 0; i < SHA_DIGEST_LENGTH; ++i) { result << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]); } return result.str(); }
生成的校验和存入数据库后启动上传,使用标准CURL设置。Cloudflare Worker处理上传时,将上传文件的校验和与数据库值对比,代码如下:
async function validateChecksum(fileContent, expectedChecksum) { const sha1Buffer = await crypto.subtle.digest("SHA-1", fileContent); const sha1Array = Array.from(new Uint8Array(sha1Buffer)); const computedChecksum = sha1Array.map(b => b.toString(16).padStart(2, '0')).join(''); return computedChecksum === expectedChecksum; } // handle upload method ... const url = new URL(request.url); const checksum = url.searchParams.get('checksum'); const uploadStream = await request.body; const originalFileName = request.headers.get('X-Original-File-Name'); const uploadResponse = await env.STREAM_BUCKET.put(`some-folder/${originalFileName}`, uploadStream); if (!uploadResponse) { await updateTransferStatus(site_id, camera_id, "FAILURE", env); return new Response( JSON.stringify({ transfer_status: "FAILURE" }), { status: 500, headers: { 'Content-Type': 'application/json' } } ); } const uploadedFile = await env.STREAM_BUCKET.get(`${site_id}/${camera_id}/${originalFileName}`); const fileContent = await uploadedFile.arrayBuffer(); const isChecksumValid = await validateChecksum(fileContent, checksum);
文件完整性良好,可下载打开,文件名一致,但校验和不匹配,请问我遗漏了哪些要点?
C++端文件读取不完整:原C++代码的
while循环会在读取到文件末尾(剩余字节不足8192)时直接退出,导致最后一段数据未被纳入SHA-1计算。需在循环结束后补充处理剩余字节:while (file.read(buffer, sizeof(buffer))) { SHA1_Update(&sha1, buffer, file.gcount()); } // 处理最后一次未填满buffer的读取内容 if (file.gcount() > 0) { SHA1_Update(&sha1, buffer, file.gcount()); }Cloudflare存储路径不匹配:Worker中上传路径是
some-folder/${originalFileName},但读取路径是${site_id}/${camera_id}/${originalFileName},两者不一致,导致读取的并非刚上传的目标文件,校验自然不匹配。需统一上传和读取的路径。校验和大小写差异:C的
std::hex默认输出小写十六进制字符,JavaScript的toString(16)同样输出小写,但需确认数据库存储、URL传输过程中是否存在大小写转换(比如被转成大写)。可在两边统一转成大写/小写后再对比,比如C添加std::uppercase,或JS中用.toUpperCase()。CURL上传模式问题:嵌入式环境的旧版CURL可能未默认启用二进制传输,需显式设置
CURLOPT_BINARYTRANSFER,避免文本模式下的换行符转换(如CRLF转LF),导致上传文件内容与本地文件不一致。校验和传输编码问题:检查URL参数中的
checksum是否被意外URL编码(如包含%字符时),Worker的searchParams.get会自动解码,若数据库存储的是原始值,可能导致对比失败。可在Worker中打印两个校验和的具体值,直接对比差异。
内容的提问来源于stack exchange,提问作者user21122267

