Fixes a parsing bug with the AcceptHeaderParser

When we find an invalid character at the end of a media type value we
should advance and skip over it.
This commit is contained in:
Ryan Nowak 2017-01-23 11:07:26 -08:00
parent 1c4a78597a
commit 5885feb7c0
2 changed files with 123 additions and 0 deletions

View File

@ -36,6 +36,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Internal
while (!string.IsNullOrEmpty(value) && charIndex < value.Length)
{
var startCharIndex = charIndex;
MediaTypeSegmentWithQuality output;
if (TryParseValue(value, ref charIndex, out output))
{
@ -45,6 +47,12 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Internal
parsedValues.Add(output);
}
}
if (charIndex <= startCharIndex)
{
Debug.Fail("ParseAcceptHeader should advance charIndex, this is a bug.");
break;
}
}
}
}
@ -110,6 +118,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Internal
// E. g application/json, text/plain <- We must be at ',' otherwise, we've failed parsing.
if (!separatorFound && (currentIndex < value.Length))
{
index = currentIndex;
return false;
}

View File

@ -122,5 +122,119 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Internal
// Assert
Assert.Equal(expected, parsed);
}
// The text "*/*Content-Type" parses as a valid media type value. However it's followed
// by ':' instead of whitespace or a delimiter, which means that it's actually invalid.
[Fact]
public void ParseAcceptHeader_ValidMediaType_FollowedByNondelimiter()
{
// Arrange
var expected = new MediaTypeSegmentWithQuality[0];
var input = "*/*Content-Type:application/json";
// Act
var parsed = AcceptHeaderParser.ParseAcceptHeader(new List<string>() { input });
// Assert
Assert.Equal(expected, parsed);
}
[Fact]
public void ParseAcceptHeader_ValidMediaType_FollowedBySemicolon()
{
// Arrange
var expected = new MediaTypeSegmentWithQuality[0];
var input = "*/*Content-Type;application/json";
// Act
var parsed = AcceptHeaderParser.ParseAcceptHeader(new List<string>() { input });
// Assert
Assert.Equal(expected, parsed);
}
[Fact]
public void ParseAcceptHeader_ValidMediaType_FollowedByComma()
{
// Arrange
var expected = new MediaTypeSegmentWithQuality[]
{
new MediaTypeSegmentWithQuality(new StringSegment("*/*Content-Type"), 1.0),
new MediaTypeSegmentWithQuality(new StringSegment("application/json"), 1.0),
};
var input = "*/*Content-Type,application/json";
// Act
var parsed = AcceptHeaderParser.ParseAcceptHeader(new List<string>() { input });
// Assert
Assert.Equal(expected, parsed);
}
[Fact]
public void ParseAcceptHeader_ValidMediaType_FollowedByWhitespace()
{
// Arrange
var expected = new MediaTypeSegmentWithQuality[]
{
new MediaTypeSegmentWithQuality(new StringSegment("application/json"), 1.0),
};
var input = "*/*Content-Type application/json";
// Act
var parsed = AcceptHeaderParser.ParseAcceptHeader(new List<string>() { input });
// Assert
Assert.Equal(expected, parsed);
}
[Fact]
public void ParseAcceptHeader_InvalidTokenAtStart()
{
// Arrange
var expected = new MediaTypeSegmentWithQuality[0];
var input = ":;:";
// Act
var parsed = AcceptHeaderParser.ParseAcceptHeader(new List<string>() { input });
// Assert
Assert.Equal(expected, parsed);
}
[Fact]
public void ParseAcceptHeader_DelimiterAtStart()
{
// Arrange
var expected = new MediaTypeSegmentWithQuality[0];
var input = ",;:";
// Act
var parsed = AcceptHeaderParser.ParseAcceptHeader(new List<string>() { input });
// Assert
Assert.Equal(expected, parsed);
}
[Fact]
public void ParseAcceptHeader_InvalidTokenAtEnd()
{
// Arrange
var expected = new MediaTypeSegmentWithQuality[0];
var input = "*/*:";
// Act
var parsed = AcceptHeaderParser.ParseAcceptHeader(new List<string>() { input });
// Assert
Assert.Equal(expected, parsed);
}
}
}