我正在使用一个HTTP请求工具(类似于cURL),但服务器的响应有问题。 要么就是我对HTTP 1.1的RFC和分块数据的理解有问题。
我看到的是分块数据应该是这种格式。
4\r\n
Wiki\r\n
5\r\n
pedia\r\n
e\r\n
in\r\n\r\nchunks.\r\n
0\r\n
\r\n
我看到的实际上是下面的格式。
4\r\n
Wiki\r\n
5\r\n
pedia\r\n
e\r\n
in\r\n\r\nchunks.\r\n
0
换句话说,我测试过的几台服务器在0之后就没有再发送数据了... 不是CRLF,更不是CRLFCRLF。
如果没有正确的分块标签格式,我们怎么知道这是分块数据的结束? 超时发生寻找0后面的CRLF,这是不充分的。
是的,它违反了标准。但我们希望兼容所有可能的http服务器和客户端,所以我们必须了解它是如何被违反的。
Chunked经常被用于内容的一种方式。流媒体 通过http1.1协议。标准要求以附加的内容结束 CRLF
. 所以我们可以看到下面的伪代码。
def stream(endpoint)
Socket.open(endpoint) do |socket|
sleep 10
more_data do |data|
print data.length.to_s(16)
print data
print "CRLF"
end
end
print "CRLF"
end
但正确的代码是下面的:
def stream(endpoint)
Socket.open(endpoint) do |socket|
sleep 10
more_data do |data|
print data.length.to_s(16)
print data
print "CRLF"
end
end
ensure
print "CRLF"
end
它的意思是,在输入插座中断后,其他任何一个插座 例外 方法的错误版本将无法打印额外的 "CRLF "到输出插口。
如果没有正确的chunked标签格式,我们怎么知道这是chunked数据的结束?超时的发生是为了寻找0后面的CRLF,这是不充分的。
许多实现忽略了这种违规行为,因为他们不需要知道内容的大小。他们只是试图在套接字被关闭之前接收尽可能多的数据。
使用Content-Length,只要我知道就一定要用;对于文件下载,检查文件大小对资源来说是微不足道的。 对于分块传输,我们不扫描报文体中是否有CRLF对。它首先读取指定数量的字节,然后再读取两个字节,确认它们是CR和LF。如果它们不是,则消息体是错误的,要么是大小指定不当,要么是数据被破坏。
更多信息请阅读 RCF其中说
在响应中使用分块传输编码的服务器必须不对任何头字段使用预告片,除非以下情况至少有一项为真。
a)请求中包含一个TE头字段,表明在响应的传输编码中可以接受 "预告片",如第14.39节所述;或者。
b)服务器是响应的源服务器,拖车字段完全由可选的元数据组成,收件人可以(以源服务器可接受的方式)使用该消息而不接收该元数据。换句话说,源服务器愿意接受拖车字段在通往客户端的路径上被默默丢弃的可能性。
如果头有Transfer-Encoding,并且分块传输是最终编码,那么消息体长度是通过读取和解码分块数据来确定的,直到传输编码表明数据已经完成。
如果头有Transfer-Encoding,并且分块传输不是最终编码,那么消息主体长度由读取连接决定,直到服务器关闭。
如果请求中的头有Transfer-Encoding,并且分块传输不是最终编码,那么消息体长度不能可靠地确定;服务器必须以400(坏请求)状态码响应,然后关闭连接。
如果收到的消息同时包含传输编码和内容长度头字段,则传输编码将覆盖内容长度。 这样的消息可能表示试图执行请求响应分割,应该作为错误处理。 发送者在向下游转发这样的消息之前,必须删除收到的Content-Length字段。