分块流响应不正确

Chunked Stream Responds Incorrectly

对不起,这么模糊的标题,我真的不知道给这个问题起什么标题。 基本上当我得到一个按照 Transfer-Encoding 分块的流时,我会执行以下代码:

private IEnumerable<byte[]> ReceiveMessageBodyChunked() {
    readChunk:
    #region Read a line from the Stream which should be a Block Length (Chunk Body Length)
    string blockLength = _receiverHelper.ReadLine();
    #endregion
    #region If the end of the block is reached, re-read from the stream
    if (blockLength == Http.NewLine) {
        goto readChunk;
    }
    #endregion
    #region Trim it so it should end up with JUST the number
    blockLength = blockLength.Trim(' ', '\r', '\n');
    #endregion
    #region If the end of the message body is reached
    if (blockLength == string.Empty) {
        yield break;
    }
    #endregion
    int blockLengthInt = 0;
    #region Convert the Block Length String to an Int32 base16 (hex)
    try {
        blockLengthInt = Convert.ToInt32(blockLength, 16);
    } catch (Exception ex) {
        if (ex is FormatException || ex is OverflowException) {
            throw new Exception(string.Format(ExceptionValues.HttpException_WrongChunkedBlockLength, blockLength), ex);
        }
        throw;
    }
    #endregion
    // If the end of the message body is reached.
    if (blockLengthInt == 0) {
        yield break;
    }
    byte[] buffer = new byte[blockLengthInt];
    int totalBytesRead = 0;
    while (totalBytesRead != blockLengthInt) {
        int length = blockLengthInt - totalBytesRead;
        int bytesRead = _receiverHelper.HasData ? _receiverHelper.Read(buffer, 0, length) : _request.ClientStream.Read(buffer, 0, length);
        if (bytesRead == 0) {
            WaitData();
            continue;
        }
        totalBytesRead += bytesRead;
        System.Windows.Forms.MessageBox.Show("Chunk Length: " + blockLengthInt + "\nBytes Read/Total:" + bytesRead + "/" + totalBytesRead + "\n\n" + Encoding.ASCII.GetString(buffer));
        yield return buffer;
    }
    goto readChunk;
}

这样做是从流中读取 1 行数据,这应该是块的长度,在这里和那里做一些检查,但最终将其转换为 Int32 Radix16 整数。

从那里它基本上创建了一个 int32 的字节缓冲区作为它的长度大小。

然后它一直从流中读取,直到读取的数量与我们转换的 Int32 相同。

这很好用,但是,无论出于何种原因,它在上次读取时响应不正确。

它将读取准确的字节数作为块长度,并且读取了我期望的所有数据。但它也在再次读取另一小块数据,该数据块已经在最后读取,导致可以说从 <!DOCTYPE html></html> 的所有数据以及来自内部某处的一些数据,例如 <form> e.t.c

这是一个发生的例子:

如您所见,突出显示的红色文本不应该从阅读中返回!它应该在 </html> 结束。 为什么 Chunk 的长度对我撒谎,我怎样才能找到合适的阅读尺寸?

我不熟悉 C# 但如果我正确理解你的代码和 C# 中 Read 的语义(这似乎类似于 C 中的 read )那么问题是您一次又一次地使用同一个缓冲区而没有先重置它:

byte[] buffer = new byte[blockLengthInt];
int totalBytesRead = 0;
while (totalBytesRead != blockLengthInt) {
    int length = blockLengthInt - totalBytesRead;
    int bytesRead = _receiverHelper.HasData ? _receiverHelper.Read(buffer, 0, length) : _request.ClientStream.Read(buffer, 0, length);
    ...
    totalBytesRead += bytesRead;
    ...
    yield return buffer;
}

举例说明这里出了什么问题:假设块大小为 10,您读取的内容是 0123456789,第一次读取将 return 6 个字节,第二次读取剩余 4 个字节。在这种情况下,您的缓冲区将在第一次读取后为 012345,在第二次读取后为 567845。缓冲区末尾的这些 45 保留了上次读取的内容,因为您只替换了缓冲区中的前 4 个字节,但保留了其余字节。

Whats odd AF is that if I hand the request to another TCPStream proxied (127.0.0.1:8888 as a proxy which is fiddler) it works perfectly fine...

Fiddler 是一个代理,可能会更改响应的传输方式。例如,它可能使用 Content-length 而不是分块编码,或者它可能使用较小的块,以便您始终在第一次读取时获得完整的块。