有效的算法/方法来解析(没有任何框架)多部分/表单数据请求,而不将所有内容读取到内存中?

Tak*_*oUp 4 forms algorithm parsing file-upload http

我的问题很简单:我想在大文件上传到达时将其写入磁盘。我有两个大文件正在由同一个人上传multipart/form-data表单上传。如何检测文件结尾,换句话说,如何检测边界------WebKitFormBoundaryuFPBAbBHzPMrZn8g到达字节中间的边界?

\n\n

拥有正在上传的文件的长度可以完全解决这个问题,但是这个信息不是由http请求给出的(只是完整的内容长度,而不是正在上传的单个文件的长度)。

\n\n

那么当我将字节写入磁盘时检测边界的逻辑/策略/算法是什么。当然,我不想写边界,认为它是文件的一部分。我必须检测并停止写入磁盘。请注意,在开始写入磁盘之前,我无法将整个文件加载到内存中。这将使问题变得容易得多。

\n\n

以下是包含两个文件的 multipart/form-data 的格式:

\n\n
\nPOST / HTTP/1.1\n主机:本地主机:8000\n连接:保持活动\n内容长度:362\n缓存控制:max-age=0\n来源:null\n升级不安全请求:1\n用户代理:Mozilla/5.0(Macintosh;Intel Mac OS X 10_10_5)AppleWebKit/537.36(KHTML,如 Gecko)Chrome/53.0.2785.116 Safari/537.36\nContent-Type:multipart/form-data;border=----WebKitFormBoundaryuFPBAbBHzPMrZn8g\n接受:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\n接受-编码: gzip, deflate\n接受-语言:en-US,en;q=0.8,pt;q=0.6\n\n------WebKitFormBoundaryuFPBAbBHzPMrZn8g\n内容处置:表单数据;名称=“文件1”;filename="binary.dat"\n内容类型:application/octet-stream\n\na\xcf\x89b\n-----WebKitFormBoundaryuFPBAbBHzPMrZn8g\n内容处置:表单数据;名称=“文件2”;文件名 =“binary.dat”\n内容类型:application/octet-stream\n\na\xcf\x89b\n-----WebKitFormBoundaryuFPBAbBHzPMrZn8g--\n
\n

小智 5

第一个非常简单的方法可能适合您的需求,并且您可以使用内存库函数来查找和移动数据来实现,如下所示:

假设您的边界是 N + 1 字节(在您的情况下,数据是 40,N 是 39),分配一个比您的签名大的任何大小的缓冲区,然后在缓冲区中第一次接收缓冲区大小并进入处理循环如下所述的数据,直到您没有更多数据可以接收:

1 - 在缓冲区中查找签名。如果找到它,那么您就完成了第一个文件。保存到查找点的字节并关闭第一个文件。然后打开第二个文件,将字节从查找点的末尾移动到缓冲区末尾到缓冲区的开头,接收字节以完成缓冲区并继续循环。

2 - 如果在缓冲区中找不到数据,则将 (buffer + sizeof(buffer) - N - 1) 以内的所有数据写入文件,将最后 N 个字节移动到缓冲区的开头,接收剩余的字节来填充缓冲区并继续循环。

一种不移动数据但要求您检查每个字节的更干净的方法是执行以下操作:

1 - 分配任意大小的缓冲区。

2 - 将匹配计数器设置为零。

3 - 设置包含边界数据字节的boundingData 数组。

4 - 输入执行以下操作的循环

5 - 接收缓冲区中的字节,最多达到缓冲区大小或接收端

6 - 输入另一个循环,检查每个字节的接收数据范围,如下所示:

如果正在检查的字节等于boundingData[matchCounter],则增加计数器并检查它是否达到了boundingData的长度。如果是,则关闭您的文件,打开下一个文件并将 matchCounter 设置为零。

否则,如果 matchCounter 不为零,则 write(boundingData, matchCount) ,然后将检查的字节写入文件。

当您完成缓冲区的操作后,请返回步骤 5,直到不再有数据可接收为止。

  • 我想知道谁是编写这个多部分/表单数据协议的聪明人。这使得解析变得极其困难。人们对有效负载协议、有效负载长度+有效负载有什么看法? (5认同)