Chunked Stream отвечает неправильно - PullRequest
0 голосов
/ 09 сентября 2018

Извините за столь расплывчатое название, я действительно не знаю, как озаглавить этот выпуск. В основном, когда я получаю поток, который разделен на части, как сказано в 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;
}

То, что это делает, читает одну строку данных из потока, которая должна быть длиной блока, выполняет некоторые проверки здесь и там, но в конечном итоге преобразует это в целое число Int32 Radix16.

Оттуда он по существу создает байтовый буфер этого int32 как его размер длины.

Затем он просто продолжает читать из потока до тех пор, пока его чтение не станет таким же, как у преобразованного Int32.

Это работает великолепно, однако, по какой-то причине, он некорректно реагирует на последнее чтение.

Он будет считывать точное количество байтов, так как длина фрагмента отлично, и все данные, которые я ожидаю, читаются. НО это ТАКЖЕ читает еще один маленький кусок данных, который УЖЕ был прочитан в самом конце, в результате чего давайте скажем все данные от <!DOCTYPE html> до </html> ASWELL как некоторые данные изнутри где-то вроде <form> e.t.c

Вот пример того, что произошло:

enter image description here

Как видите, выделенный красный текст НЕ должен был возвращаться из чтения! Это должно было закончиться в </html>. Почему длина куска лжет мне и как я могу найти правильный размер для чтения?

1 Ответ

0 голосов
/ 09 сентября 2018

Я не знаком с C #, но если я правильно понимаю ваш код и семантику Read в C # (что похоже на read в C), тогда проблема в том, что вы используете тот же буфер снова и снова без сброса сначала:

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, а первое чтение вернет 6 байтов, а второе прочитает оставшиеся 4 байта. В этом случае ваш буфер будет 012345 после первого чтения и 567845 после второго чтения. Эти 45 в конце буфера остаются от предыдущего чтения, так как вы заменили только первые 4 байта в буфере, но оставили остальные.

Что странно, AF: если я передаю запрос другому прокси TCPStream (127.0.0.1:8888 в качестве прокси-сервера, который является fiddler), он работает отлично ...

Fiddler является прокси-сервером и может изменить способ передачи ответа. Например, он может использовать Content-length вместо кодирования чанков или может использовать меньшие чанки, чтобы вы всегда получали полный чанк при первом чтении.

...