Skip to content

Commit

Permalink
Structured Message Decode: Validate Content Length (Azure#42370)
Browse files Browse the repository at this point in the history
* validate stream length

* tests
  • Loading branch information
jaschrep-msft committed Aug 12, 2024
1 parent c14d574 commit 26d8a12
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,12 @@ public override long Position
}

public StructuredMessageDecodingStream(
Stream innerStream)
Stream innerStream,
long? expectedStreamLength = default)
{
Argument.AssertNotNull(innerStream, nameof(innerStream));

_innerStreamLength = expectedStreamLength ?? -1;
_innerBufferedStream = new BufferedStream(innerStream);

// Assumes stream will be structured message 1.0. Will validate this when consuming stream.
Expand Down Expand Up @@ -366,9 +369,19 @@ private int ProcessStreamHeader(ReadOnlySpan<byte> span)
{
StructuredMessage.V1_0.ReadStreamHeader(
span.Slice(0, _streamHeaderLength),
out _innerStreamLength,
out long streamLength,
out _flags,
out _totalSegments);

if (_innerStreamLength > 0 && streamLength != _innerStreamLength)
{
throw Errors.InvalidStructuredMessage("Unexpected message size.");
}
else
{
_innerStreamLength = streamLength;
}

if (_flags.HasFlag(StructuredMessage.Flags.StorageCrc64))
{
_segmentFooterLength = _flags.HasFlag(StructuredMessage.Flags.StorageCrc64) ? StructuredMessage.Crc64Length : 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,46 @@ public void BadStreamWrongSegmentNum()
Assert.That(async () => await CopyStream(decodingStream, Stream.Null), Throws.InnerException.TypeOf<InvalidDataException>());
}

[Test]
[Combinatorial]
public async Task BadStreamWrongContentLength(
[Values(-1, 1)] int difference,
[Values(true, false)] bool lengthProvided)
{
byte[] originalData = new byte[1024];
new Random().NextBytes(originalData);
byte[] encodedData = StructuredMessageHelper.MakeEncodedData(originalData, 256, Flags.StorageCrc64);

BinaryPrimitives.WriteInt64LittleEndian(
new Span<byte>(encodedData, V1_0.StreamHeaderMessageLengthOffset, 8),
encodedData.Length + difference);

Stream decodingStream = new StructuredMessageDecodingStream(
new MemoryStream(encodedData),
lengthProvided ? (long?)encodedData.Length : default);

// manual try/catch with tiny buffer to validate the proccess failed mid-stream rather than the end
const int copyBufferSize = 4;
bool caught = false;
try
{
await CopyStream(decodingStream, Stream.Null, copyBufferSize);
}
catch (CopyStreamException ex)
{
caught = true;
if (lengthProvided)
{
Assert.That(ex.TotalCopied, Is.EqualTo(0));
}
else
{
Assert.That(ex.TotalCopied, Is.EqualTo(originalData.Length));
}
}
Assert.That(caught);
}

[Test]
public void BadStreamMissingExpectedStreamFooter()
{
Expand Down

0 comments on commit 26d8a12

Please sign in to comment.