如何计算HTTP多部分“Content-length”标头值?

时间:2015-07-14 12:02:07

标签: http-headers multipart content-length http-content-length

我读过对“如何计算多部分HTTP请求内容长度?”这一问题的冲突和有些含糊不清的回复。我特别想知道:

  • 计算“Content-length”标题的精确内容范围是什么?
  • CRLF(“\ r \ n”)八位字节序列是否计为一个或两个八位字节?

有人能提供一个明确的例子来回答这些问题吗?

4 个答案:

答案 0 :(得分:8)

以下实际示例应该有希望回答问题。

使用Google的OAuth 2.0 Playground执行多部分请求

Google的OAuth 2.0 Playground网页是针对Google云端硬盘云执行多部分HTTP请求的绝佳方式。您不必了解有关Google云端硬盘的任何信息 - 我会为您完成所有工作。我们只对HTTP请求和响应感兴趣。但是,如果需要,使用游乐场将允许您尝试使用多部分并回答其他问题。

创建用于上传的测试文件

我创建了一个名为" test-multipart.txt"的本地文本文件,保存在我的文件系统上。该文件大小为34个字节,如下所示:

We're testing multipart uploading!

打开Goog​​le的OAuth 2.0 Playground

我们首先使用网址https://developers.google.com/oauthplayground/在浏览器中打开Goog​​le的OAuth 2.0 Playground:

Google OAuth 2.0 Playground opening screen

填写第1步

选择Drive API v2和" https://www.googleapis.com/auth/drive",然后按"授权API":

Fields filled in for Step 1

填写第2步

点击代币的#34; Exchange授权代码":

Fields filled in for Step 2

填写第3步

这里我们提供所有相关的多部分请求信息:

  • 将HTTP方法设置为" POST"
  • 无需添加任何标题,Google Playground将添加所需内容(例如标题,边界序列,内容长度)
  • 请求URI:" https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart"
  • 输入请求正文:这是Google云端硬盘执行分段上传所需的一些元数据JSON。我使用了以下内容:
{"title": "test-multipart.txt", "parents": [{"id":"0B09i2ZH5SsTHTjNtSS9QYUZqdTA"}], "properties": [{"kind": "drive#property", "key": "cloudwrapper", "value": "true"}]}
  • 在" Request Body"的底部屏幕,选择test-multipart.txt文件进行上传。
  • 按"发送请求"按钮

enter image description here

请求和响应

Google的OAuth 2.0 Playground奇迹般地插入所有必需的标题,计算内容长度,生成边界序列,在需要的地方插入边界字符串,并向我们显示服务器的响应: enter image description here

分析

多部分HTTP请求以200状态代码成功,因此请求和响应是我们可以依赖的好的。谷歌的Playground插入了执行多部分HTTP上传所需的一切。你可以看到" Content-length"设置为352.让我们看一下标题后面的空行后的每一行:

--===============0688100289==\r\n
Content-type: application/json\r\n
\r\n
{"title": "test-multipart.txt", "parents": [{"id":"0B09i2ZH5SsTHTjNtSS9QYUZqdTA"}], "properties": [{"kind": "drive#property", "key": "cloudwrapper", "value": "true"}]}\r\n
--===============0688100289==\r\n
Content-type: text/plain\r\n
\r\n
We're testing multipart uploading!\r\n
--===============0688100289==--

有九(9)行,我手动添加" \ r \ n"在前八(8)行的每一行的末尾(出于可读性的原因)。以下是每行中八位字节(字符)的数量:

  1. 29 +' \ r \ n'
  2. 30 +' \ r \ n'
  3. ' \ r \ n'
  4. 167 +' \ r \ n'
  5. 29 +' \ r \ n'
  6. 24 +' \ r \ n'
  7. ' \ r \ n'
  8. 34 +' \ r \ n' (虽然' \ r \ n'不是文本文件的一部分,Google会将其插入)
  9. 31
  10. 八位字节的总和是344,并且考虑到每个字符串。\ r \ n \ n&n;作为单个一个八位字节序列给我们令人垂涎的内容长度344 + 8 = 352。

    摘要

    总结调查结果:

    1. 多部分请求"内容长度"从标题部分的空白行后面的边界序列的第一个字节计算,并继续,直到并包括最后一个边界序列的最后一个连字符。
    2. ' \ r \ n'无论您使用何种操作系统,序列都应计为一(1)个八位字节,而不是两个。

答案 1 :(得分:8)

如何计算Content-Length不依赖于有效负载的状态代码或媒体类型;它是线上的字节数。因此,撰写多部分响应,计算字节数(以及CRLF计数为2),并将其用于Content-Length

请参阅:http://httpwg.org/specs/rfc7230.html#message.body.length

答案 2 :(得分:2)

如果http消息具有Content-Length标头,则此标头指示HTTP标头之后的确切字节数。如果有什么决定自由地将\r\n计为一个字节,那么一切都将崩溃:保持活动的http连接将停止工作,因为HTTP栈无法看到下一个HTTP消息的起始位置并将尝试解析随机数据,好像它是一条HTTP消息。

答案 3 :(得分:1)

\n\r 是两个字节。

Moshe Rubin 的回答是错误的。该实现在那里被窃听。

我发送了一个 curl 请求来上传文件,并使用 WireShark 专门收集了我的网络发送的确切实际数据。每个人都应该同意的方法比在某个地方给我一个数字的在线申请更有效。

--------------------------de798c65c334bc76\r\n
Content-Disposition: form-data; name="file"; filename="requireoptions.txt"\r\n
Content-Type: text/plain\r\n
\r\n
Pillow
pyusb
wxPython
ezdxf
opencv-python-headless
\r\n--------------------------de798c65c334bc76--\r\n

Curl,每个人都会同意它很可能正确地实现: Content-Length: 250

> len("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d646537393863363563333334626337360d0a436f6e74656e742d446973706f736974696f6e3a20666f726d2d646174613b206e616d653d2266696c65223b2066696c656e616d653d22726571756972656f7074696f6e732e747874220d0a436f6e74656e742d547970653a20746578742f706c61696e0d0a0d0a50696c6c6f770d0a70797573620d0a7778507974686f6e0d0a657a6478660d0a6f70656e63762d707974686f6e2d686561646c6573730d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d646537393863363563333334626337362d2d0d0a")
500

(2x250 = 500,从 WireShark 复制十六进制流。)

我在那里拿到了实际的二进制文件。 '2d' 是 --- 开始边界。

请注意,给服务器错误的计数,将 0d0a 视为 1 而不是 2 个八位字节(这很疯狂,它们是八位字节,不能复合),主动拒绝了该请求。


此外,这回答了问题的第二部分。实际的内容长度就是这里的一切。从第一个边界到最后一个带有结语 --\r\n 的边界,是连线中剩下的所有八位字节。