Mig*_*ada 8 sockets networking protocols http
我想写一个 HTTP 实现。
几天来,我一直在寻找关于使用Content-Type: multipart/form-data.
我已经在 stackoverflow 上查看了很多关于它的问题,例如:
HTTP 文件上传是如何工作的?
enctype='multipart/form-data' 是什么意思?
我深入研究了 RFC 2616(和更新版本)、2046 等。但我没有找到明确的答案(显然我没有得到它背后的想法)。
在大多数文章和答案中,我发现了这段请求字符串,这对我来说很容易解释,所有这些都记录在 RFC 中...
POST /upload?upload_progress_id=12344 HTTP/1.1
Host: localhost:3000
Content-Length: 1325
Origin: http://localhost:3000
... other headers ...
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryePkpFF7tjBAqx29L
------WebKitFormBoundaryePkpFF7tjBAqx29L
Content-Disposition: form-data; name="MAX_FILE_SIZE"
100000
------WebKitFormBoundaryePkpFF7tjBAqx29L
Content-Disposition: form-data; name="uploadedfile"; filename="hello.o"
Content-Type: application/x-object
... contents of file goes here ...
------WebKitFormBoundaryePkpFF7tjBAqx29L--
Run Code Online (Sandbox Code Playgroud)
...并且实现一个 HTTP 客户端以在任何语言中以这种方式构造一段字符串会很简单。
问题变成了... contents of file goes here ...,关于“文件内容”的信息很少。我知道它是具有某种类型和编码的二进制数据,但是很难想到字符串数据,我将如何添加一段在字符串中没有字符串表示的二进制数据。
我想看到任何语言的 HTTP 协议的低级实现示例。或许还有关于通过 HTTP 传输二进制数据、客户端如何创建请求以及服务器如何读取/解析它的深入解释。
PD。我知道这个问题我看起来很重复,但大多数答案并不集中在解释二进制数据传输(如媒体)上。
您不应该尝试在正文的这部分处理字符串,您应该发送二进制数据,将其视为从资源读取字节并发送这些字节不变。
所以特别是没有应用编码,没有 utf-8,没有 base64,HTTP 不是像 smtp 那样具有 ascii7 限制的协议,其中应用 base64 编码以确保仅使用 ascii7 字符。
根据定义,此数据没有字符串版本,查看原始 HTTP 传输(例如,使用wireshark)您应该会看到二进制数据、字节等内容。
这就是大多数 HTTP 服务器使用 C 来管理 HTTP 的原因,它们解析每个字节的 HTTP 通信字节(因为协议标头只有 ascii 7,当然不是多字节字符),并且它们还可以很容易地读取/写入正文的任意二进制数据(甚至使用像readfile这样的系统调用让内核管理二进制部分)。
现在,关于例子。
当您使用Content-Length而没有多部分内容时,正文正好是 (content-length) 个字节长,因此解析您发送的数据的客户端将仅读取此字节数并将整个原始数据视为正文内容(这可能有一个 mime 类型和编码信息,但这只是设置在 HTTP 协议之上的层的信息)。
当您使用Transfer-Encoding: chunked 时,原始二进制主体被分成几部分,然后每个部分都以十六进制数字(块的大小)和行尾标记为前缀。最后有一个空标记。
如果我们以维基百科为例:
4\r\n
Wiki\r\n
5\r\n
pedia\r\n
E\r\n
in\r\n
\r\n
chunks.\r\n
0\r\n
\r\n
Run Code Online (Sandbox Code Playgroud)
我们可以用任何字节替换每个 ascii7 字母,甚至是一个没有 ascii7 表示的字节,我将对每个真实的正文字节使用 * 字符:
4\r\n
****\r\n
5\r\n
*****\r\n
E\r\n
**************\r\n
0\r\n
\r\n
Run Code Online (Sandbox Code Playgroud)
所有其他字符都是 HTTP 协议的一部分(这里是块体传输)。我还可以使用\n二进制数据的表示,并且只为正文的每个字节发送空字节,即:
4\r\n
\0\0\0\0\0\r\n
5\r\n
\0\0\0\0\0\0\r\n
E\r\n
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r\n
0\r\n
\r\n
Run Code Online (Sandbox Code Playgroud)
这只是一个表示,我们也可以使用\xNNor\NN表示,实际上这些是字节,8 位(懒得写这个主体的 0/1 表示:-))。
如果示例的文本,而不是:
Wikipedia in\r\n
\r\n
chunks.
Run Code Online (Sandbox Code Playgroud)
它可能是一个更复杂的,带有多字节字符(这里是 utf-8 中的 é):
Wikipédia in\r\n
\r\n
chunks.
Run Code Online (Sandbox Code Playgroud)
此E是实际上11000011:10101001在UTF-8,两个字节:\xc3\xa9在\xNN表示),而不是简单的01100101/ \x65/e字符。HTTP 正文现在是(请参阅第二个块大小是 6 而不是 5):
4\r\n
Wiki\r\n
6\r\n
p\xc3\xa9dia\r\n
E\r\n
in\r\n
\r\n
chunks.\r\n
0\r\n
\r\n
Run Code Online (Sandbox Code Playgroud)
但这仅在源数据有效地采用 utf-8 时才有效,可能是另一种编码。默认情况下,除非您的 Web 服务器中有一些特定的配置设置可用,您可以在其中强制以特定编码转换源文档,这并不是 Web 服务器转换源文档的真正工作,您可以使用所拥有的,并且您可能会添加一个标头来告诉客户端在源文档上定义了什么编码。
最后,我们有传输正文的多部分方式,就像在您的问题中一样,它很像分块版本,除了这里使用了边界和中间标头,但是对于这些边界、标头和行尾控制字符之间的二进制数据,它是相同的规则,里面的一切都只是字节......
| 归档时间: |
|
| 查看次数: |
10917 次 |
| 最近记录: |