You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C++解析HTTP多部分表单数据并在二进制缓冲区中查找分隔符

在大型二进制缓冲区中定位HTTP Multipart分隔符的C++实现方法

核心思路

HTTP Multipart的分隔符是ASCII文本格式(普通分隔符为--+boundary,结束分隔符为--+boundary+--,均带\r\n后缀),可直接按字节序列匹配。针对大型缓冲区,优先采用KMP算法实现高效匹配,避免暴力匹配的低效问题。

实现步骤

1. 解析并构造分隔符字节序列

先从HTTP请求头的Content-Type字段提取boundary,再转换为二进制格式的分隔符序列:

#include <vector>
#include <cstddef>
#include <string>
#include <stdexcept>
#include <algorithm>

// 从Content-Type头提取boundary,处理可能的引号包裹
std::string extract_boundary(const std::string& content_type) {
    size_t boundary_pos = content_type.find("boundary=");
    if (boundary_pos == std::string::npos) {
        throw std::invalid_argument("Invalid Content-Type header");
    }
    std::string boundary = content_type.substr(boundary_pos + 9);
    if (!boundary.empty() && boundary.front() == '"') {
        auto end_quote = boundary.find_last_of('"');
        if (end_quote != std::string::npos) {
            boundary = boundary.substr(1, end_quote - 1);
        }
    }
    return boundary;
}

// 构造普通分隔符字节序列:--<boundary>\r\n
std::vector<std::byte> build_regular_delimiter(const std::string& boundary) {
    std::string delimiter_str = "--" + boundary + "\r\n";
    std::vector<std::byte> delimiter;
    delimiter.reserve(delimiter_str.size());
    for (char c : delimiter_str) {
        delimiter.push_back(static_cast<std::byte>(c));
    }
    return delimiter;
}

// 构造结束分隔符字节序列:--<boundary>--\r\n
std::vector<std::byte> build_end_delimiter(const std::string& boundary) {
    std::string delimiter_str = "--" + boundary + "--\r\n";
    std::vector<std::byte> delimiter;
    delimiter.reserve(delimiter_str.size());
    for (char c : delimiter_str) {
        delimiter.push_back(static_cast<std::byte>(c));
    }
    return delimiter;
}

2. 用KMP算法高效查找匹配

KMP算法通过预处理生成部分匹配表(LPS),将匹配时间复杂度优化到O(n+m)(n为缓冲区长度,m为分隔符长度),适合处理大型二进制数据:

// 生成KMP算法的部分匹配表
std::vector<size_t> compute_lps(const std::vector<std::byte>& pattern) {
    size_t n = pattern.size();
    std::vector<size_t> lps(n, 0);
    size_t len = 0; // 最长前缀后缀的长度
    size_t i = 1;
    while (i < n) {
        if (pattern[i] == pattern[len]) {
            len++;
            lps[i] = len;
            i++;
        } else {
            len = len != 0 ? lps[len - 1] : 0;
            if (len == 0) {
                lps[i] = 0;
                i++;
            }
        }
    }
    return lps;
}

// 在二进制缓冲区中查找所有分隔符的起始位置
std::vector<size_t> find_all_delimiters(const std::vector<std::byte>& buffer, const std::vector<std::byte>& delimiter) {
    std::vector<size_t> matches;
    if (delimiter.empty() || buffer.size() < delimiter.size()) {
        return matches;
    }
    std::vector<size_t> lps = compute_lps(delimiter);
    size_t buf_idx = 0;
    size_t pat_idx = 0;
    while (buf_idx < buffer.size()) {
        if (delimiter[pat_idx] == buffer[buf_idx]) {
            buf_idx++;
            pat_idx++;
        }
        if (pat_idx == delimiter.size()) {
            matches.push_back(buf_idx - pat_idx);
            pat_idx = lps[pat_idx - 1];
        } else if (buf_idx < buffer.size() && delimiter[pat_idx] != buffer[buf_idx]) {
            pat_idx = pat_idx != 0 ? lps[pat_idx - 1] : 0;
            if (pat_idx == 0) {
                buf_idx++;
            }
        }
    }
    return matches;
}

3. 分割缓冲区为多个数据块

拿到所有分隔符位置后,将缓冲区分割为对应的part,存入vector<vector<std::byte>>:

std::vector<std::vector<std::byte>> split_multipart_buffer(
    const std::vector<std::byte>& buffer,
    const std::vector<size_t>& regular_matches,
    const size_t end_match_pos
) {
    std::vector<std::vector<std::byte>> parts;
    size_t start = 0;
    size_t delimiter_len = regular_matches.empty() ? 0 : build_regular_delimiter("").size();
    for (size_t match_pos : regular_matches) {
        if (match_pos > start) {
            parts.emplace_back(buffer.begin() + start, buffer.begin() + match_pos);
        }
        start = match_pos + delimiter_len;
    }
    if (end_match_pos > start) {
        parts.emplace_back(buffer.begin() + start, buffer.begin() + end_match_pos);
    }
    return parts;
}

注意事项

  • 分段接收场景:若缓冲区从网络分段接收,需保留上一段末尾长度为分隔符长度-1的字节,与下一段拼接后再查找,避免跨段分隔符被截断。
  • 内容空行处理:每个part的头信息与实际内容间存在\r\n\r\n空行,分割后需跳过该部分才能获取真实文件内容。
  • 规范兼容性:严格遵循HTTP规范,分隔符必须包含\r\n后缀,避免误匹配二进制内容中类似的字节序列。

内容的提问来源于stack exchange,提问作者Troy Hamilton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 04:28:11