Http 为什么有些服务器在最后一个数据块长度为零后不使用CRLF?

Http 为什么有些服务器在最后一个数据块长度为零后不使用CRLF?,http,chunked-encoding,chunked,Http,Chunked Encoding,Chunked,我使用的是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 def stream(endpoint) Socket

我使用的是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
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
换句话说,我测试过的少数服务器在0之后不会发送更多数据。。不是CRLF,更不用说CRLFCRLF了


如果没有正确的分块标记格式,我们怎么知道这是分块数据的结尾?查找0之后的CRLF时会发生超时,这是不够的。

使用内容长度,只要我知道就一定要使用;对于文件下载,检查文件大小对于资源来说是无关紧要的。对于分块传输,我们不扫描消息正文中的CRLF对。它首先读取指定数量的字节,然后再读取两个字节以确认它们是CR和LF。如果不是,则消息正文的格式不正确,或者指定的大小不正确,或者数据已损坏

欲了解更多信息,请阅读

在响应中使用分块传输编码的服务器不得使用 任何标题字段的尾部,除非至少满足以下条件之一: 正确:

a) 该请求包含一个TE头字段,该字段指示“Trailes”为 响应的传输编码可接受,如中所述 第14.39节;或者

b) 服务器是响应的原始服务器,拖车字段 完全由可选元数据组成,收件人可以使用 消息(以原始服务器可接受的方式)没有 接收此元数据。换句话说,源服务器愿意 接受拖车字段可能处于静默状态的可能性 沿到客户端的路径丢弃

确定消息正文长度的方法: 如果报头具有传输编码,并且分块传输是最终编码,则通过读取和解码分块数据来确定消息正文长度,直到传输编码指示数据已完成

如果标头具有传输编码,且分块传输不是最终编码,则通过读取连接直到服务器关闭连接来确定消息正文长度

如果消息头在请求中有传输编码,且分块传输不是最终编码,则无法可靠地确定消息体长度;服务器必须响应400(错误请求)状态代码,然后关闭连接


如果接收到的消息同时包含传输编码和内容长度标题字段,则传输编码将覆盖内容长度。这样的消息可能表示有人试图执行请求-响应拆分,应该作为错误处理。发送方必须先删除接收的内容长度字段,然后才能将此类邮件转发到下游。

是的,这违反了标准。但我们希望与所有可能的http服务器和客户端兼容,因此我们必须了解如何违反它

分块通常通过http 1.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
但正确的代码如下所示:

4\r\n
Wiki\r\n
5\r\n
pedia\r\n
e\r\n
 in\r\n\r\nchunks.\r\n
0
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”

我们怎么知道这是数据块的结束 分块标记的正确格式?超时发生在寻找 CRLFs在0之后,这是不够的


许多实现忽略了这种冲突,因为它们不需要知道内容的大小。他们只是试图在套接字关闭之前接收尽可能多的数据。

这很奇怪。什么样的服务器响应这种错误?服务器头中有什么?如果在0之后至少有一个CRLF,您可以说些什么,在这里您仍然可以收到一些数字,因此这显然是一个错误。或者你的解析代码中有错误?你有tcpdump或线鲨捕获器吗?没有,我没有这些东西。这是一个套接字应用程序,我已经编写和使用了很多年。但是,我遇到了分块数据的问题。除了结尾的0(即,后面没有CRLF)之外,其他任何东西似乎都可以正常工作。在读取分块长度时,我一次读取一个字节,寻找CRLF,这样我就知道结束了。然后我将该值从十六进制转换为十进制,并从套接字读取该值。当我读取最后一个0并再读取一个字节时,它会在套接字上执行select()超时,等待它准备就绪。如果您确定传入的数据,则服务器出现故障,请参阅“确定”,我进行了一些测试。。在每次读取一个字节以检索分块长度时,我从请求中删除了select(),并且一切正常。有趣…是的,所以您在基于套接字的代码中发现了一个可怕的问题,祝您好运:-)我不认为这是对这个问题的回答。当然,内容长度不是计算分块传输结束时间的方法。@regilero那么您如何确定文档的长度?根据定义分块传输意味着您对文档的大小没有任何线索--您等待最后一个分块--,如果您有内容长度,这只是一个帮助,一些服务器将拒绝使用这两种方法的请求,因为这两种方法都可能用于http走私攻击(通过在协议中使用不同大小的2个指示器,这与http隧道中的消息大小非常敏感),并且尾部信息仅是大小为六位数字和CRLF之间的数据,使用或不使用预告片并不能说明在块大小行的末尾必须有CRLF。如上所述,内容长度不是一个选项。这是H