Merge branch 'rel/1.1.0-preview1' into dev
This commit is contained in:
commit
d5b0ebd10c
|
|
@ -292,6 +292,12 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
public static MediaTypeSegmentWithQuality CreateMediaTypeSegmentWithQuality(string mediaType, int start)
|
public static MediaTypeSegmentWithQuality CreateMediaTypeSegmentWithQuality(string mediaType, int start)
|
||||||
{
|
{
|
||||||
var parsedMediaType = new MediaType(mediaType, start, length: null);
|
var parsedMediaType = new MediaType(mediaType, start, length: null);
|
||||||
|
if (parsedMediaType.Type.Equals(default(StringSegment)) ||
|
||||||
|
parsedMediaType.SubType.Equals(default(StringSegment)))
|
||||||
|
{
|
||||||
|
return default(MediaTypeSegmentWithQuality);
|
||||||
|
}
|
||||||
|
|
||||||
var parser = parsedMediaType._parameterParser;
|
var parser = parsedMediaType._parameterParser;
|
||||||
|
|
||||||
double quality = 1.0d;
|
double quality = 1.0d;
|
||||||
|
|
@ -306,7 +312,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We check if the parsed media type has value at this stage when we have iterated
|
// We check if the parsed media type has a value at this stage when we have iterated
|
||||||
// over all the parameters and we know if the parsing was sucessful.
|
// over all the parameters and we know if the parsing was sucessful.
|
||||||
if (!parser.ParsingFailed)
|
if (!parser.ParsingFailed)
|
||||||
{
|
{
|
||||||
|
|
@ -395,6 +401,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
{
|
{
|
||||||
if (_mediaTypeBuffer == null)
|
if (_mediaTypeBuffer == null)
|
||||||
{
|
{
|
||||||
|
ParsingFailed = true;
|
||||||
result = default(MediaTypeParameter);
|
result = default(MediaTypeParameter);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Internal
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(parsedValues));
|
throw new ArgumentNullException(nameof(parsedValues));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < acceptHeaders.Count; i++)
|
for (var i = 0; i < acceptHeaders.Count; i++)
|
||||||
{
|
{
|
||||||
var charIndex = 0;
|
var charIndex = 0;
|
||||||
|
|
@ -46,13 +45,6 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Internal
|
||||||
parsedValues.Add(output);
|
parsedValues.Add(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
var invalidValuesError = Resources.FormatAcceptHeaderParser_ParseAcceptHeader_InvalidValues(
|
|
||||||
value.Substring(charIndex));
|
|
||||||
|
|
||||||
throw new FormatException(invalidValuesError);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -80,11 +72,34 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Internal
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaTypeSegmentWithQuality result;
|
// We deliberately want to ignore media types that we are not capable of parsing.
|
||||||
var length = GetMediaTypeWithQualityLength(value, currentIndex, out result);
|
// This is due to the fact that some browsers will send invalid media types like
|
||||||
|
// ; q=0.9 or */;q=0.2, etc.
|
||||||
|
// In this scenario, our recovery action consists of advancing the pointer to the
|
||||||
|
// next separator and moving on.
|
||||||
|
// In case we don't find the next separator, we simply advance the cursor to the
|
||||||
|
// end of the string to signal that we are done parsing.
|
||||||
|
var result = default(MediaTypeSegmentWithQuality);
|
||||||
|
var length = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
length = GetMediaTypeWithQualityLength(value, currentIndex, out result);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
{
|
{
|
||||||
|
// The parsing failed.
|
||||||
|
currentIndex = value.IndexOf(',', currentIndex);
|
||||||
|
if (currentIndex == -1)
|
||||||
|
{
|
||||||
|
index = value.Length;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
index = currentIndex;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -48,14 +50,69 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ParseAcceptHeader_ParsesSimpleHeaderWithMultipleValues_InvalidFormat()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var header = "application/json, application/xml,;q=0.8";
|
||||||
|
var expectedMediaTypes = new List<MediaTypeSegmentWithQuality>
|
||||||
|
{
|
||||||
|
new MediaTypeSegmentWithQuality(new StringSegment("application/json"),1.0),
|
||||||
|
new MediaTypeSegmentWithQuality(new StringSegment("application/xml"),1.0),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var mediaTypes = AcceptHeaderParser.ParseAcceptHeader(new List<string> { header });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedMediaTypes, mediaTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TheoryData<string[], string[]> ParseAcceptHeaderWithInvalidMediaTypesData =>
|
||||||
|
new TheoryData<string[], string[]>
|
||||||
|
{
|
||||||
|
{ new [] { ";q=0.9" }, new string[] { } },
|
||||||
|
{ new [] { "/" }, new string[] { } },
|
||||||
|
{ new [] { "*/" }, new string[] { } },
|
||||||
|
{ new [] { "/*" }, new string[] { } },
|
||||||
|
{ new [] { "/;q=0.9" }, new string[] { } },
|
||||||
|
{ new [] { "*/;q=0.9" }, new string[] { } },
|
||||||
|
{ new [] { "/*;q=0.9" }, new string[] { } },
|
||||||
|
{ new [] { "/;q=0.9,text/html" }, new string[] { "text/html" } },
|
||||||
|
{ new [] { "*/;q=0.9,text/html" }, new string[] { "text/html" } },
|
||||||
|
{ new [] { "/*;q=0.9,text/html" }, new string[] { "text/html" } },
|
||||||
|
{ new [] { "img/png,/;q=0.9,text/html" }, new string[] { "img/png", "text/html" } },
|
||||||
|
{ new [] { "img/png,*/;q=0.9,text/html" }, new string[] { "img/png", "text/html" } },
|
||||||
|
{ new [] { "img/png,/*;q=0.9,text/html" }, new string[] { "img/png", "text/html" } },
|
||||||
|
{ new [] { "img/png, /;q=0.9" }, new string[] { "img/png", } },
|
||||||
|
{ new [] { "img/png, */;q=0.9" }, new string[] { "img/png", } },
|
||||||
|
{ new [] { "img/png;q=1.0, /*;q=0.9" }, new string[] { "img/png;q=1.0", } },
|
||||||
|
};
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(ParseAcceptHeaderWithInvalidMediaTypesData))]
|
||||||
|
public void ParseAcceptHeader_GracefullyRecoversFromInvalidMediaTypeValues_AndReturnsValidMediaTypes(
|
||||||
|
string[] acceptHeader,
|
||||||
|
string[] expected)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedMediaTypes = expected.Select(e => new MediaTypeSegmentWithQuality(new StringSegment(e), 1.0)).ToList();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var parsed = AcceptHeaderParser.ParseAcceptHeader(acceptHeader);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedMediaTypes, parsed);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ParseAcceptHeader_ParsesMultipleHeaderValues()
|
public void ParseAcceptHeader_ParsesMultipleHeaderValues()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = new List<MediaTypeSegmentWithQuality>
|
var expected = new List<MediaTypeSegmentWithQuality>
|
||||||
{
|
{
|
||||||
new MediaTypeSegmentWithQuality(new StringSegment("application/json"),1.0),
|
new MediaTypeSegmentWithQuality(new StringSegment("application/json"), 1.0),
|
||||||
new MediaTypeSegmentWithQuality(new StringSegment("application/xml;q=0.8"),0.8)
|
new MediaTypeSegmentWithQuality(new StringSegment("application/xml;q=0.8"), 0.8)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,26 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
Assert.Equal(expectedContentType, response.Content.Headers.ContentType);
|
Assert.Equal(expectedContentType, response.Content.Headers.ContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("/;q=0.9")]
|
||||||
|
[InlineData("/;q=0.9, invalid;q=0.5;application/json;q=0.1")]
|
||||||
|
[InlineData("/invalid;q=0.9, application/json;q=0.1,invalid;q=0.5")]
|
||||||
|
[InlineData("text/html, application/json, image/jpeg, *; q=.2, */*; q=.2")]
|
||||||
|
public async Task ContentNegotiationWithPartiallyValidAcceptHeader_SkipsInvalidEntries(string acceptHeader)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedContentType = MediaTypeHeaderValue.Parse("application/json;charset=utf-8");
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/ContentNegotiation/UserInfo_ProducesWithTypeOnly");
|
||||||
|
request.Headers.TryAddWithoutValidation("Accept", acceptHeader);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await Client.SendAsync(request);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.Equal(expectedContentType, response.Content.Headers.ContentType);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ProducesAttributeWithTypeOnly_RunsRegularContentNegotiation()
|
public async Task ProducesAttributeWithTypeOnly_RunsRegularContentNegotiation()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue