Correctly check for limits in the split buffer case (#12117)
- We were looking all total consumed bytes instead of bytes consumed since the last time we parsed a form value. This resulted in thinking that the key or value was too long if it couldn't be parsed after having parsed a bunch of data in the same read. - Added tests
This commit is contained in:
parent
dfe159023a
commit
72f91b8507
|
|
@ -218,6 +218,7 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
{
|
||||
var sequenceReader = new SequenceReader<byte>(buffer);
|
||||
var consumed = sequenceReader.Position;
|
||||
var consumedBytes = default(long);
|
||||
var equalsDelimiter = GetEqualsForEncoding();
|
||||
var andDelimiter = GetAndForEncoding();
|
||||
|
||||
|
|
@ -227,7 +228,7 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
if (!sequenceReader.TryReadTo(out ReadOnlySequence<byte> key, equalsDelimiter, advancePastDelimiter: false) ||
|
||||
!sequenceReader.IsNext(equalsDelimiter, true))
|
||||
{
|
||||
if (sequenceReader.Consumed > KeyLengthLimit)
|
||||
if ((sequenceReader.Consumed - consumedBytes) > KeyLengthLimit)
|
||||
{
|
||||
ThrowKeyTooLargeException();
|
||||
}
|
||||
|
|
@ -245,7 +246,7 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
{
|
||||
if (!isFinalBlock)
|
||||
{
|
||||
if (sequenceReader.Consumed - key.Length > ValueLengthLimit)
|
||||
if ((sequenceReader.Consumed - consumedBytes - key.Length) > ValueLengthLimit)
|
||||
{
|
||||
ThrowValueTooLargeException();
|
||||
}
|
||||
|
|
@ -268,6 +269,7 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
|
||||
AppendAndVerify(ref accumulator, decodedKey, decodedValue);
|
||||
|
||||
consumedBytes = sequenceReader.Consumed;
|
||||
consumed = sequenceReader.Position;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
|
@ -152,15 +153,6 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
Assert.Equal(expectedValue, form[key]);
|
||||
}
|
||||
|
||||
public static TheoryData<Encoding> Encodings =>
|
||||
new TheoryData<Encoding>
|
||||
{
|
||||
{ Encoding.UTF8 },
|
||||
{ Encoding.UTF32 },
|
||||
{ Encoding.ASCII },
|
||||
{ Encoding.Unicode }
|
||||
};
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(Encodings))]
|
||||
public void TryParseFormValues_SingleSegmentWorks(Encoding encoding)
|
||||
|
|
@ -386,6 +378,67 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(IncompleteFormKeys))]
|
||||
public void ParseFormWithIncompleteKeyWhenIsFinalBlockSucceeds(ReadOnlySequence<byte> readOnlySequence)
|
||||
{
|
||||
KeyValueAccumulator accumulator = default;
|
||||
|
||||
var formReader = new FormPipeReader(null)
|
||||
{
|
||||
KeyLengthLimit = 3
|
||||
};
|
||||
|
||||
formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: false);
|
||||
|
||||
IDictionary<string, StringValues> values = accumulator.GetResults();
|
||||
Assert.Single(values);
|
||||
Assert.Contains("fo", values);
|
||||
Assert.Equal("bar", values["fo"]);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(IncompleteFormValues))]
|
||||
public void ParseFormWithIncompleteValueWhenIsFinalBlockSucceeds(ReadOnlySequence<byte> readOnlySequence)
|
||||
{
|
||||
KeyValueAccumulator accumulator = default;
|
||||
|
||||
var formReader = new FormPipeReader(null)
|
||||
{
|
||||
ValueLengthLimit = 3
|
||||
};
|
||||
|
||||
formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: false);
|
||||
|
||||
IDictionary<string, StringValues> values = accumulator.GetResults();
|
||||
Assert.Single(values);
|
||||
Assert.Contains("fo", values);
|
||||
Assert.Equal("bar", values["fo"]);
|
||||
}
|
||||
|
||||
public static TheoryData<ReadOnlySequence<byte>> IncompleteFormKeys =>
|
||||
new TheoryData<ReadOnlySequence<byte>>
|
||||
{
|
||||
{ ReadOnlySequenceFactory.CreateSegments(Encoding.UTF8.GetBytes("fo=bar&b"), Encoding.UTF8.GetBytes("a")) },
|
||||
{ new ReadOnlySequence<byte>(Encoding.UTF8.GetBytes("fo=bar&ba")) }
|
||||
};
|
||||
|
||||
public static TheoryData<ReadOnlySequence<byte>> IncompleteFormValues =>
|
||||
new TheoryData<ReadOnlySequence<byte>>
|
||||
{
|
||||
{ ReadOnlySequenceFactory.CreateSegments(Encoding.UTF8.GetBytes("fo=bar&b"), Encoding.UTF8.GetBytes("=")) },
|
||||
{ new ReadOnlySequence<byte>(Encoding.UTF8.GetBytes("fo=bar&b=")) }
|
||||
};
|
||||
|
||||
public static TheoryData<Encoding> Encodings =>
|
||||
new TheoryData<Encoding>
|
||||
{
|
||||
{ Encoding.UTF8 },
|
||||
{ Encoding.UTF32 },
|
||||
{ Encoding.ASCII },
|
||||
{ Encoding.Unicode }
|
||||
};
|
||||
|
||||
internal virtual Task<Dictionary<string, StringValues>> ReadFormAsync(FormPipeReader reader)
|
||||
{
|
||||
return reader.ReadFormAsync();
|
||||
|
|
|
|||
Loading…
Reference in New Issue