未验证 提交 56539095 编写于 作者: F feiyun0112 提交者: GitHub

Do not reorder HTTP header values (#65249)

* Do not reorder HTTP header values

* fix complie error

* make the changes @ danmoseley recommended

* make the changes @MihaZupan recommended

* make the changes @MihaZupan recommended

* make the changes @MihaZupan recommended

* make the changes @MihaZupan recommended

* make the changes @MihaZupan recommended

* check array length

* fix unit test

* Update src/libraries/System.Net.Http/tests/UnitTests/Headers/HttpHeadersTest.cs
Co-authored-by: NMiha Zupan <mihazupan.zupan1@gmail.com>

* Update src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs
Co-authored-by: NMiha Zupan <mihazupan.zupan1@gmail.com>

* Update src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs
Co-authored-by: NMiha Zupan <mihazupan.zupan1@gmail.com>

* Update src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs
Co-authored-by: NMiha Zupan <mihazupan.zupan1@gmail.com>

* make the changes @MihaZupan recommended

* Update src/libraries/System.Net.Http/src/System/Net/Http/Headers/CacheControlHeaderParser.cs
Co-authored-by: NMiha Zupan <mihazupan.zupan1@gmail.com>

* chang unit test

* GetParsedValueLength

* fix build error

* Update src/libraries/System.Net.Http/src/System/Net/Http/Headers/CacheControlHeaderParser.cs
Co-authored-by: NMiha Zupan <mihazupan.zupan1@gmail.com>

* Update src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs
Co-authored-by: NMiha Zupan <mihazupan.zupan1@gmail.com>

* unit test

* make changes @geoffkizer recommended

* CloneAndAddValue for InvalidValues

* Update src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs
Co-authored-by: NMiha Zupan <mihazupan.zupan1@gmail.com>

* Update src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs
Co-authored-by: NMiha Zupan <mihazupan.zupan1@gmail.com>

* Final nits
Co-authored-by: NMiha Zupan <mihazupan.zupan1@gmail.com>
上级 bd43f552
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Diagnostics;
namespace System.Net.Http.Headers
......@@ -22,8 +23,29 @@ private CacheControlHeaderParser()
protected override int GetParsedValueLength(string value, int startIndex, object? storeValue,
out object? parsedValue)
{
CacheControlHeaderValue? temp = storeValue as CacheControlHeaderValue;
Debug.Assert(storeValue == null || temp != null, "'storeValue' is not of type CacheControlHeaderValue");
CacheControlHeaderValue? temp = null;
bool isInvalidValue = true;
if (storeValue is List<object> list)
{
foreach (object item in list)
{
if (item is not HttpHeaders.InvalidValue)
{
isInvalidValue = false;
temp = item as CacheControlHeaderValue;
break;
}
}
}
else
{
if (storeValue is not HttpHeaders.InvalidValue)
{
isInvalidValue = false;
temp = storeValue as CacheControlHeaderValue;
}
}
Debug.Assert(isInvalidValue || storeValue == null || temp != null, "'storeValue' is not of type CacheControlHeaderValue");
int resultLength = CacheControlHeaderValue.GetCacheControlLength(value, startIndex, temp, out temp);
......
......@@ -287,7 +287,7 @@ internal static void CheckValidQuotedString(string value, string parameterName)
{
Debug.Assert(store != null);
object? storedValue = store.GetParsedValues(descriptor);
object? storedValue = store.GetSingleParsedValue(descriptor);
if (storedValue != null)
{
return (DateTimeOffset)storedValue;
......@@ -304,7 +304,7 @@ internal static void CheckValidQuotedString(string value, string parameterName)
{
Debug.Assert(store != null);
object? storedValue = store.GetParsedValues(descriptor);
object? storedValue = store.GetSingleParsedValue(descriptor);
if (storedValue != null)
{
return (TimeSpan)storedValue;
......
......@@ -19,7 +19,7 @@ public sealed class HttpContentHeaders : HttpHeaders
public ContentDispositionHeaderValue? ContentDisposition
{
get { return (ContentDispositionHeaderValue?)GetParsedValues(KnownHeaders.ContentDisposition.Descriptor); }
get { return (ContentDispositionHeaderValue?)GetSingleParsedValue(KnownHeaders.ContentDisposition.Descriptor); }
set { SetOrRemoveParsedValue(KnownHeaders.ContentDisposition.Descriptor, value); }
}
......@@ -36,7 +36,7 @@ public sealed class HttpContentHeaders : HttpHeaders
get
{
// 'Content-Length' can only hold one value. So either we get 'null' back or a boxed long value.
object? storedValue = GetParsedValues(KnownHeaders.ContentLength.Descriptor);
object? storedValue = GetSingleParsedValue(KnownHeaders.ContentLength.Descriptor);
// Only try to calculate the length if the user didn't set the value explicitly using the setter.
if (!_contentLengthSet && (storedValue == null))
......@@ -72,25 +72,25 @@ public sealed class HttpContentHeaders : HttpHeaders
public Uri? ContentLocation
{
get { return (Uri?)GetParsedValues(KnownHeaders.ContentLocation.Descriptor); }
get { return (Uri?)GetSingleParsedValue(KnownHeaders.ContentLocation.Descriptor); }
set { SetOrRemoveParsedValue(KnownHeaders.ContentLocation.Descriptor, value); }
}
public byte[]? ContentMD5
{
get { return (byte[]?)GetParsedValues(KnownHeaders.ContentMD5.Descriptor); }
get { return (byte[]?)GetSingleParsedValue(KnownHeaders.ContentMD5.Descriptor); }
set { SetOrRemoveParsedValue(KnownHeaders.ContentMD5.Descriptor, value); }
}
public ContentRangeHeaderValue? ContentRange
{
get { return (ContentRangeHeaderValue?)GetParsedValues(KnownHeaders.ContentRange.Descriptor); }
get { return (ContentRangeHeaderValue?)GetSingleParsedValue(KnownHeaders.ContentRange.Descriptor); }
set { SetOrRemoveParsedValue(KnownHeaders.ContentRange.Descriptor, value); }
}
public MediaTypeHeaderValue? ContentType
{
get { return (MediaTypeHeaderValue?)GetParsedValues(KnownHeaders.ContentType.Descriptor); }
get { return (MediaTypeHeaderValue?)GetSingleParsedValue(KnownHeaders.ContentType.Descriptor); }
set { SetOrRemoveParsedValue(KnownHeaders.ContentType.Descriptor, value); }
}
......
......@@ -22,7 +22,7 @@ internal sealed class HttpGeneralHeaders
public CacheControlHeaderValue? CacheControl
{
get { return (CacheControlHeaderValue?)_parent.GetParsedValues(KnownHeaders.CacheControl.Descriptor); }
get { return (CacheControlHeaderValue?)_parent.GetSingleParsedValue(KnownHeaders.CacheControl.Descriptor); }
set { _parent.SetOrRemoveParsedValue(KnownHeaders.CacheControl.Descriptor, value); }
}
......
......@@ -86,7 +86,7 @@ public void CopyTo(T[] array!!, int arrayIndex)
throw new ArgumentOutOfRangeException(nameof(arrayIndex));
}
object? storeValue = _store.GetParsedValues(_descriptor);
object? storeValue = _store.GetParsedAndInvalidValues(_descriptor);
if (storeValue == null)
{
......@@ -97,18 +97,30 @@ public void CopyTo(T[] array!!, int arrayIndex)
if (storeValues == null)
{
// We only have 1 value: If it is the "special value" just return, otherwise add the value to the
// array and return.
Debug.Assert(storeValue is T);
if (arrayIndex == array.Length)
if (storeValue is not HttpHeaders.InvalidValue)
{
throw new ArgumentException(SR.net_http_copyto_array_too_small);
Debug.Assert(storeValue is T);
if (arrayIndex == array.Length)
{
throw new ArgumentException(SR.net_http_copyto_array_too_small);
}
array[arrayIndex] = (T)storeValue;
}
array[arrayIndex] = (T)storeValue;
}
else
{
storeValues.CopyTo(array, arrayIndex);
foreach (object item in storeValues)
{
if (item is not HttpHeaders.InvalidValue)
{
Debug.Assert(item is T);
if (arrayIndex == array.Length)
{
throw new ArgumentException(SR.net_http_copyto_array_too_small);
}
array[arrayIndex++] = (T)item;
}
}
}
}
......@@ -122,8 +134,8 @@ public bool Remove(T item)
public IEnumerator<T> GetEnumerator()
{
object? storeValue = _store.GetParsedValues(_descriptor);
return storeValue is null ?
object? storeValue = _store.GetParsedAndInvalidValues(_descriptor);
return storeValue is null || storeValue is HttpHeaders.InvalidValue ?
((IEnumerable<T>)Array.Empty<T>()).GetEnumerator() : // use singleton empty array enumerator
Iterate(storeValue);
......@@ -134,6 +146,10 @@ static IEnumerator<T> Iterate(object storeValue)
// We have multiple values. Iterate through the values and return them.
foreach (object item in storeValues)
{
if (item is HttpHeaders.InvalidValue)
{
continue;
}
Debug.Assert(item is T);
yield return (T)item;
}
......@@ -178,7 +194,7 @@ private int GetCount()
{
// This is an O(n) operation.
object? storeValue = _store.GetParsedValues(_descriptor);
object? storeValue = _store.GetParsedAndInvalidValues(_descriptor);
if (storeValue == null)
{
......@@ -189,11 +205,23 @@ private int GetCount()
if (storeValues == null)
{
return 1;
if (storeValue is not HttpHeaders.InvalidValue)
{
return 1;
}
return 0;
}
else
{
return storeValues.Count;
int count = 0;
foreach (object item in storeValues)
{
if (item is not HttpHeaders.InvalidValue)
{
count++;
}
}
return count;
}
}
}
......
......@@ -47,7 +47,7 @@ private T GetSpecializedCollection<T>(int slot, Func<HttpRequestHeaders, T> crea
public AuthenticationHeaderValue? Authorization
{
get { return (AuthenticationHeaderValue?)GetParsedValues(KnownHeaders.Authorization.Descriptor); }
get { return (AuthenticationHeaderValue?)GetSingleParsedValue(KnownHeaders.Authorization.Descriptor); }
set { SetOrRemoveParsedValue(KnownHeaders.Authorization.Descriptor, value); }
}
......@@ -87,7 +87,7 @@ private T GetSpecializedCollection<T>(int slot, Func<HttpRequestHeaders, T> crea
public string? From
{
get { return (string?)GetParsedValues(KnownHeaders.From.Descriptor); }
get { return (string?)GetSingleParsedValue(KnownHeaders.From.Descriptor); }
set
{
// Null and empty string are equivalent. In this case it means, remove the From header value (if any).
......@@ -104,7 +104,7 @@ private T GetSpecializedCollection<T>(int slot, Func<HttpRequestHeaders, T> crea
public string? Host
{
get { return (string?)GetParsedValues(KnownHeaders.Host.Descriptor); }
get { return (string?)GetSingleParsedValue(KnownHeaders.Host.Descriptor); }
set
{
// Null and empty string are equivalent. In this case it means, remove the Host header value (if any).
......@@ -135,7 +135,7 @@ private T GetSpecializedCollection<T>(int slot, Func<HttpRequestHeaders, T> crea
public RangeConditionHeaderValue? IfRange
{
get { return (RangeConditionHeaderValue?)GetParsedValues(KnownHeaders.IfRange.Descriptor); }
get { return (RangeConditionHeaderValue?)GetSingleParsedValue(KnownHeaders.IfRange.Descriptor); }
set { SetOrRemoveParsedValue(KnownHeaders.IfRange.Descriptor, value); }
}
......@@ -149,7 +149,7 @@ private T GetSpecializedCollection<T>(int slot, Func<HttpRequestHeaders, T> crea
{
get
{
object? storedValue = GetParsedValues(KnownHeaders.MaxForwards.Descriptor);
object? storedValue = GetSingleParsedValue(KnownHeaders.MaxForwards.Descriptor);
if (storedValue != null)
{
return (int)storedValue;
......@@ -162,19 +162,19 @@ private T GetSpecializedCollection<T>(int slot, Func<HttpRequestHeaders, T> crea
public AuthenticationHeaderValue? ProxyAuthorization
{
get { return (AuthenticationHeaderValue?)GetParsedValues(KnownHeaders.ProxyAuthorization.Descriptor); }
get { return (AuthenticationHeaderValue?)GetSingleParsedValue(KnownHeaders.ProxyAuthorization.Descriptor); }
set { SetOrRemoveParsedValue(KnownHeaders.ProxyAuthorization.Descriptor, value); }
}
public RangeHeaderValue? Range
{
get { return (RangeHeaderValue?)GetParsedValues(KnownHeaders.Range.Descriptor); }
get { return (RangeHeaderValue?)GetSingleParsedValue(KnownHeaders.Range.Descriptor); }
set { SetOrRemoveParsedValue(KnownHeaders.Range.Descriptor, value); }
}
public Uri? Referrer
{
get { return (Uri?)GetParsedValues(KnownHeaders.Referer.Descriptor); }
get { return (Uri?)GetSingleParsedValue(KnownHeaders.Referer.Descriptor); }
set { SetOrRemoveParsedValue(KnownHeaders.Referer.Descriptor, value); }
}
......
......@@ -45,13 +45,13 @@ private T GetSpecializedCollection<T>(int slot, Func<HttpResponseHeaders, T> cre
public EntityTagHeaderValue? ETag
{
get { return (EntityTagHeaderValue?)GetParsedValues(KnownHeaders.ETag.Descriptor); }
get { return (EntityTagHeaderValue?)GetSingleParsedValue(KnownHeaders.ETag.Descriptor); }
set { SetOrRemoveParsedValue(KnownHeaders.ETag.Descriptor, value); }
}
public Uri? Location
{
get { return (Uri?)GetParsedValues(KnownHeaders.Location.Descriptor); }
get { return (Uri?)GetSingleParsedValue(KnownHeaders.Location.Descriptor); }
set { SetOrRemoveParsedValue(KnownHeaders.Location.Descriptor, value); }
}
......@@ -60,7 +60,7 @@ private T GetSpecializedCollection<T>(int slot, Func<HttpResponseHeaders, T> cre
public RetryConditionHeaderValue? RetryAfter
{
get { return (RetryConditionHeaderValue?)GetParsedValues(KnownHeaders.RetryAfter.Descriptor); }
get { return (RetryConditionHeaderValue?)GetSingleParsedValue(KnownHeaders.RetryAfter.Descriptor); }
set { SetOrRemoveParsedValue(KnownHeaders.RetryAfter.Descriptor, value); }
}
......
......@@ -34,7 +34,7 @@ public void ContentLength_ReadValue_TryComputeLengthInvoked()
// The delegate is invoked to return the length.
Assert.Equal(15, _headers.ContentLength);
Assert.Equal((long)15, _headers.GetParsedValues(KnownHeaders.ContentLength.Descriptor));
Assert.Equal((long)15, _headers.GetSingleParsedValue(KnownHeaders.ContentLength.Descriptor));
// After getting the calculated content length, set it to null.
_headers.ContentLength = null;
......@@ -43,7 +43,7 @@ public void ContentLength_ReadValue_TryComputeLengthInvoked()
_headers.ContentLength = 27;
Assert.Equal((long)27, _headers.ContentLength);
Assert.Equal((long)27, _headers.GetParsedValues(KnownHeaders.ContentLength.Descriptor));
Assert.Equal((long)27, _headers.GetSingleParsedValue(KnownHeaders.ContentLength.Descriptor));
}
[Fact]
......@@ -53,7 +53,7 @@ public void ContentLength_SetCustomValue_TryComputeLengthNotInvoked()
_headers.ContentLength = 27;
Assert.Equal((long)27, _headers.ContentLength);
Assert.Equal((long)27, _headers.GetParsedValues(KnownHeaders.ContentLength.Descriptor));
Assert.Equal((long)27, _headers.GetSingleParsedValue(KnownHeaders.ContentLength.Descriptor));
// After explicitly setting the content length, set it to null.
_headers.ContentLength = null;
......@@ -177,13 +177,13 @@ public void ContentLocation_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
public void ContentLocation_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
_headers.TryAddWithoutValidation("Content-Location", " http://example.com http://other");
Assert.Null(_headers.GetParsedValues(KnownHeaders.ContentLocation.Descriptor));
Assert.Null(_headers.GetSingleParsedValue(KnownHeaders.ContentLocation.Descriptor));
Assert.Equal(1, _headers.GetValues("Content-Location").Count());
Assert.Equal(" http://example.com http://other", _headers.GetValues("Content-Location").First());
_headers.Clear();
_headers.TryAddWithoutValidation("Content-Location", "http://host /other");
Assert.Null(_headers.GetParsedValues(KnownHeaders.ContentLocation.Descriptor));
Assert.Null(_headers.GetSingleParsedValue(KnownHeaders.ContentLocation.Descriptor));
Assert.Equal(1, _headers.GetValues("Content-Location").Count());
Assert.Equal("http://host /other", _headers.GetValues("Content-Location").First());
}
......@@ -315,13 +315,13 @@ public void ContentMD5_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
public void ContentMD5_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
_headers.TryAddWithoutValidation("Content-MD5", "AQ--");
Assert.Null(_headers.GetParsedValues(KnownHeaders.ContentMD5.Descriptor));
Assert.Null(_headers.GetSingleParsedValue(KnownHeaders.ContentMD5.Descriptor));
Assert.Equal(1, _headers.GetValues("Content-MD5").Count());
Assert.Equal("AQ--", _headers.GetValues("Content-MD5").First());
_headers.Clear();
_headers.TryAddWithoutValidation("Content-MD5", "AQ==, CD");
Assert.Null(_headers.GetParsedValues(KnownHeaders.ContentMD5.Descriptor));
Assert.Null(_headers.GetSingleParsedValue(KnownHeaders.ContentMD5.Descriptor));
Assert.Equal(1, _headers.GetValues("Content-MD5").Count());
Assert.Equal("AQ==, CD", _headers.GetValues("Content-MD5").First());
}
......@@ -401,13 +401,13 @@ public void Expires_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
public void Expires_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
_headers.TryAddWithoutValidation("Expires", " Sun, 06 Nov 1994 08:49:37 GMT ,");
Assert.Null(_headers.GetParsedValues(KnownHeaders.Expires.Descriptor));
Assert.Null(_headers.GetSingleParsedValue(KnownHeaders.Expires.Descriptor));
Assert.Equal(1, _headers.GetValues("Expires").Count());
Assert.Equal(" Sun, 06 Nov 1994 08:49:37 GMT ,", _headers.GetValues("Expires").First());
_headers.Clear();
_headers.TryAddWithoutValidation("Expires", " Sun, 06 Nov ");
Assert.Null(_headers.GetParsedValues(KnownHeaders.Expires.Descriptor));
Assert.Null(_headers.GetSingleParsedValue(KnownHeaders.Expires.Descriptor));
Assert.Equal(1, _headers.GetValues("Expires").Count());
Assert.Equal(" Sun, 06 Nov ", _headers.GetValues("Expires").First());
}
......@@ -441,13 +441,13 @@ public void LastModified_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
public void LastModified_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
_headers.TryAddWithoutValidation("Last-Modified", " Sun, 06 Nov 1994 08:49:37 GMT ,");
Assert.Null(_headers.GetParsedValues(KnownHeaders.LastModified.Descriptor));
Assert.Null(_headers.GetSingleParsedValue(KnownHeaders.LastModified.Descriptor));
Assert.Equal(1, _headers.GetValues("Last-Modified").Count());
Assert.Equal(" Sun, 06 Nov 1994 08:49:37 GMT ,", _headers.GetValues("Last-Modified").First());
_headers.Clear();
_headers.TryAddWithoutValidation("Last-Modified", " Sun, 06 Nov ");
Assert.Null(_headers.GetParsedValues(KnownHeaders.LastModified.Descriptor));
Assert.Null(_headers.GetSingleParsedValue(KnownHeaders.LastModified.Descriptor));
Assert.Equal(1, _headers.GetValues("Last-Modified").Count());
Assert.Equal(" Sun, 06 Nov ", _headers.GetValues("Last-Modified").First());
}
......
......@@ -262,7 +262,7 @@ public void CopyTo_CallWithStartIndexPlusElementCountGreaterArrayLength_Throw()
Uri[] array = new Uri[2];
// startIndex + Count = 1 + 2 > array.Length
AssertExtensions.Throws<ArgumentException>("destinationArray", "", () => { collection.CopyTo(array, 1); });
AssertExtensions.Throws<ArgumentException>(() => { collection.CopyTo(array, 1); });
}
[Fact]
......@@ -346,18 +346,18 @@ public void CopyTo_ArrayTooSmall_Throw()
headers.Add(knownStringHeader, "special");
headers.Add(knownStringHeader, "special");
array = new string[1];
AssertExtensions.Throws<ArgumentException>("destinationArray", "", () => { collection.CopyTo(array, 0); });
AssertExtensions.Throws<ArgumentException>(() => { collection.CopyTo(array, 0); });
headers.Add(knownStringHeader, "value1");
array = new string[0];
AssertExtensions.Throws<ArgumentException>("destinationArray", "", () => { collection.CopyTo(array, 0); });
AssertExtensions.Throws<ArgumentException>(() => { collection.CopyTo(array, 0); });
headers.Add(knownStringHeader, "value2");
array = new string[1];
AssertExtensions.Throws<ArgumentException>("destinationArray", "", () => { collection.CopyTo(array, 0); });
AssertExtensions.Throws<ArgumentException>(() => { collection.CopyTo(array, 0); });
array = new string[2];
AssertExtensions.Throws<ArgumentException>("destinationArray", "", () => { collection.CopyTo(array, 1); });
AssertExtensions.Throws<ArgumentException>(() => { collection.CopyTo(array, 1); });
}
[Fact]
......
......@@ -35,6 +35,22 @@ static HttpHeadersTest()
private const string parsedPrefix = "parsed";
private const string invalidHeaderValue = "invalid";
[Fact]
public void TryAddWithoutValidation_ValidAndInvalidValues_InsertionOrderIsPreserved()
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://microsoft.com");
request.Headers.TryAddWithoutValidation("Accept", "text/bar");
request.Headers.TryAddWithoutValidation("Accept", "invalid");
request.Headers.TryAddWithoutValidation("Accept", "text/baz");
// Force parsing
_ = request.Headers.Accept.Count;
Assert.Equal(1, request.Headers.NonValidated.Count);
HeaderStringValues accept = request.Headers.NonValidated["Accept"];
Assert.Equal(new[] { "text/bar", "invalid", "text/baz" }, accept);
}
[Theory]
[InlineData(null)]
[InlineData("")]
......@@ -190,21 +206,11 @@ public void TryAddWithoutValidation_AddValidAndInvalidValueString_BothValuesPars
Assert.Equal(1, headers.Count());
Assert.Equal(2, headers.First().Value.Count());
// If you compare this test with the previous one: Note that we reversed the order of adding the invalid
// string and the valid string. However, when enumerating header values the order is still the same as in
// the previous test.
// We don't keep track of the order if we have both invalid & valid values. This would add complexity
// and additional memory to store the information. Given how rare this scenario is we consider this
// by design. Note that this scenario is only an issue if:
// - The header value has an invalid format (very rare for standard headers) AND
// - There are multiple header values (some valid, some invalid) AND
// - The order of the headers matters (e.g. Transfer-Encoding)
Assert.Equal(parsedPrefix, headers.First().Value.ElementAt(0));
Assert.Equal(invalidHeaderValue, headers.First().Value.ElementAt(1));
Assert.Equal(invalidHeaderValue, headers.First().Value.ElementAt(0));
Assert.Equal(parsedPrefix, headers.First().Value.ElementAt(1));
Assert.Equal(2, headers.Parser.TryParseValueCallCount);
string expected = headers.Descriptor.Name + ": " + parsedPrefix + ", " + invalidHeaderValue + Environment.NewLine;
string expected = headers.Descriptor.Name + ": " + invalidHeaderValue + ", " + parsedPrefix + Environment.NewLine;
Assert.Equal(expected, headers.ToString());
}
......@@ -616,8 +622,8 @@ public void Add_SingleFirstTryAddWithoutValidationForInvalidValueThenAdd_TwoPars
Assert.Equal(1, headers.Count());
Assert.Equal(2, headers.First().Value.Count());
Assert.Equal(parsedPrefix + "1", headers.First().Value.ElementAt(0));
Assert.Equal(invalidHeaderValue, headers.First().Value.ElementAt(1));
Assert.Equal(invalidHeaderValue, headers.First().Value.ElementAt(0));
Assert.Equal(parsedPrefix + "1", headers.First().Value.ElementAt(1));
// Value is already parsed. There shouldn't be additional calls to the parser.
Assert.Equal(2, headers.Parser.TryParseValueCallCount);
......@@ -1265,34 +1271,34 @@ public void GetValues_HeadersWithEmptyValues_ReturnsEmptyArray()
}
[Fact]
public void GetParsedValues_GetValuesFromUninitializedHeaderStore_ReturnsNull()
public void GetSingleParsedValue_GetValuesFromUninitializedHeaderStore_ReturnsNull()
{
MockHeaders headers = new MockHeaders();
// Get header values from uninitialized store (store collection is null).
object storeValue = headers.GetParsedValues(customHeader);
object storeValue = headers.GetSingleParsedValue(customHeader);
Assert.Null(storeValue);
}
[Fact]
public void GetParsedValues_GetValuesForNonExistingHeader_ReturnsNull()
public void GetSingleParsedValue_GetValuesForNonExistingHeader_ReturnsNull()
{
MockHeaders headers = new MockHeaders();
headers.Add("custom1", "customValue1");
// Get header values for non-existing header (but other headers exist in the store).
object storeValue = headers.GetParsedValues(customHeader);
object storeValue = headers.GetSingleParsedValue(customHeader);
Assert.Null(storeValue);
}
[Fact]
public void GetParsedValues_GetSingleValueForExistingHeader_ReturnsAddedValue()
public void GetSingleParsedValue_GetSingleValueForExistingHeader_ReturnsAddedValue()
{
MockHeaders headers = new MockHeaders();
headers.Add(customHeader.Name, "customValue1");
// Get header values for non-existing header (but other headers exist in the store).
object storeValue = headers.GetParsedValues(customHeader);
object storeValue = headers.GetSingleParsedValue(customHeader);
Assert.NotNull(storeValue);
// If we only have one value, then GetValues() should return just the value and not wrap it in a List<T>.
......@@ -1300,17 +1306,17 @@ public void GetParsedValues_GetSingleValueForExistingHeader_ReturnsAddedValue()
}
[Fact]
public void GetParsedValues_HeaderWithEmptyValues_ReturnsEmpty()
public void GetSingleParsedValue_HeaderWithEmptyValues_ReturnsEmpty()
{
MockHeaders headers = new MockHeaders();
headers.Add(headers.Descriptor, string.Empty);
object storeValue = headers.GetParsedValues(headers.Descriptor);
object storeValue = headers.GetSingleParsedValue(headers.Descriptor);
Assert.Null(storeValue);
}
[Fact]
public void GetParsedValues_GetMultipleValuesForExistingHeader_ReturnsListOfValues()
public void GetSingleParsedValue_GetMultipleValuesForExistingHeader_ReturnsListOfValues()
{
MockHeaders headers = new MockHeaders();
headers.TryAddWithoutValidation("custom", rawPrefix + "0"); // this must not influence the result.
......@@ -1320,7 +1326,7 @@ public void GetParsedValues_GetMultipleValuesForExistingHeader_ReturnsListOfValu
// Only 1 value should get parsed (call to Add() with known header value).
Assert.Equal(1, headers.Parser.TryParseValueCallCount);
object storeValue = headers.GetParsedValues(headers.Descriptor);
object storeValue = headers.GetParsedAndInvalidValues(headers.Descriptor);
Assert.NotNull(storeValue);
// GetValues<T>() should trigger parsing of values added with TryAddWithoutValidation()
......@@ -1336,7 +1342,7 @@ public void GetParsedValues_GetMultipleValuesForExistingHeader_ReturnsListOfValu
}
[Fact]
public void GetParsedValues_GetValuesForExistingHeaderWithInvalidValues_ReturnsOnlyParsedValues()
public void GetSingleParsedValue_GetValuesForExistingHeaderWithInvalidValues_ReturnsOnlyParsedValues()
{
MockHeaders headers = new MockHeaders();
headers.Add(headers.Descriptor, rawPrefix);
......@@ -1349,7 +1355,7 @@ public void GetParsedValues_GetValuesForExistingHeaderWithInvalidValues_ReturnsO
// Only 1 value should get parsed (call to Add() with known header value).
Assert.Equal(1, headers.Parser.TryParseValueCallCount);
object storeValue = headers.GetParsedValues(headers.Descriptor);
object storeValue = headers.GetSingleParsedValue(headers.Descriptor);
Assert.NotNull(storeValue);
// GetValues<T>() should trigger parsing of values added with TryAddWithoutValidation()
......@@ -1360,7 +1366,7 @@ public void GetParsedValues_GetValuesForExistingHeaderWithInvalidValues_ReturnsO
}
[Fact]
public void GetParsedValues_GetValuesForExistingHeaderWithOnlyInvalidValues_ReturnsEmptyEnumerator()
public void GetSingleParsedValue_GetValuesForExistingHeaderWithOnlyInvalidValues_ReturnsEmptyEnumerator()
{
MockHeaders headers = new MockHeaders();
......@@ -1371,7 +1377,7 @@ public void GetParsedValues_GetValuesForExistingHeaderWithOnlyInvalidValues_Retu
Assert.Equal(0, headers.Parser.TryParseValueCallCount);
object storeValue = headers.GetParsedValues(headers.Descriptor);
object storeValue = headers.GetSingleParsedValue(headers.Descriptor);
Assert.Null(storeValue);
// GetValues<T>() should trigger parsing of values added with TryAddWithoutValidation()
......@@ -1379,20 +1385,20 @@ public void GetParsedValues_GetValuesForExistingHeaderWithOnlyInvalidValues_Retu
}
[Fact]
public void GetParsedValues_AddInvalidValueToHeader_HeaderGetsRemovedAndNullReturned()
public void GetSingleParsedValue_AddInvalidValueToHeader_HeaderGetsRemovedAndNullReturned()
{
MockHeaders headers = new MockHeaders();
headers.TryAddWithoutValidation(headers.Descriptor, invalidHeaderValue + "\r\ninvalid");
Assert.Equal(0, headers.Parser.TryParseValueCallCount);
object storeValue = headers.GetParsedValues(headers.Descriptor);
object storeValue = headers.GetSingleParsedValue(headers.Descriptor);
Assert.Null(storeValue);
Assert.False(headers.Contains(headers.Descriptor));
}
[Fact]
public void GetParsedValues_GetParsedValuesForKnownHeaderWithNewlineChars_ReturnsNull()
public void GetSingleParsedValue_GetSingleParsedValueForKnownHeaderWithNewlineChars_ReturnsNull()
{
MockHeaders headers = new MockHeaders();
......@@ -1400,7 +1406,7 @@ public void GetParsedValues_GetParsedValuesForKnownHeaderWithNewlineChars_Return
headers.TryAddWithoutValidation(headers.Descriptor, invalidHeaderValue + "\r\ninvalid");
Assert.Equal(0, headers.Parser.TryParseValueCallCount);
Assert.Null(headers.GetParsedValues(headers.Descriptor));
Assert.Null(headers.GetSingleParsedValue(headers.Descriptor));
Assert.Equal(0, headers.Count());
Assert.Equal(1, headers.Parser.TryParseValueCallCount);
}
......@@ -2065,9 +2071,8 @@ public void AddHeaders_SourceAndDestinationStoreHaveMultipleHeaders_OnlyHeadersN
// invalid value.
Assert.Equal(3, destination.GetValues(known2Header).Count());
Assert.Equal(parsedPrefix + "5", destination.GetValues(known2Header).ElementAt(0));
Assert.Equal(parsedPrefix + "7", destination.GetValues(known2Header).ElementAt(1));
Assert.Equal(invalidHeaderValue, destination.GetValues(known2Header).ElementAt(2));
Assert.Equal(invalidHeaderValue, destination.GetValues(known2Header).ElementAt(1));
Assert.Equal(parsedPrefix + "7", destination.GetValues(known2Header).ElementAt(2));
// Header 'known3' should not be copied, since it doesn't contain any values.
Assert.False(destination.Contains(known3Header), "'known3' header value count.");
......
......@@ -162,7 +162,7 @@ public void AcceptCharset_AddMultipleValuesAndGetValueString_AllValuesAddedUsing
foreach (var header in headers.NonValidated)
{
Assert.Equal("Accept-Charset", header.Key);
Assert.Equal("utf-8, iso-8859-5; q=0.5, invalid value", header.Value.ToString());
Assert.Equal("invalid value, utf-8, iso-8859-5; q=0.5", header.Value.ToString());
}
}
......@@ -633,26 +633,26 @@ public void UserAgent_TryGetValuesAndGetValues_Malformed()
public void UserAgent_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
headers.TryAddWithoutValidation("User-Agent", "custom\u4F1A");
Assert.Null(headers.GetParsedValues(KnownHeaders.UserAgent.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.UserAgent.Descriptor));
Assert.Equal(1, headers.GetValues("User-Agent").Count());
Assert.Equal("custom\u4F1A", headers.GetValues("User-Agent").First());
headers.Clear();
// Note that "User-Agent" uses whitespace as separators, so the following is an invalid value
headers.TryAddWithoutValidation("User-Agent", "custom1, custom2");
Assert.Null(headers.GetParsedValues(KnownHeaders.UserAgent.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.UserAgent.Descriptor));
Assert.Equal(1, headers.GetValues("User-Agent").Count());
Assert.Equal("custom1, custom2", headers.GetValues("User-Agent").First());
headers.Clear();
headers.TryAddWithoutValidation("User-Agent", "custom1, ");
Assert.Null(headers.GetParsedValues(KnownHeaders.UserAgent.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.UserAgent.Descriptor));
Assert.Equal(1, headers.GetValues("User-Agent").Count());
Assert.Equal("custom1, ", headers.GetValues("User-Agent").First());
headers.Clear();
headers.TryAddWithoutValidation("User-Agent", ",custom1");
Assert.Null(headers.GetParsedValues(KnownHeaders.UserAgent.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.UserAgent.Descriptor));
Assert.Equal(1, headers.GetValues("User-Agent").Count());
Assert.Equal(",custom1", headers.GetValues("User-Agent").First());
}
......@@ -667,7 +667,7 @@ public void UserAgent_AddMultipleValuesAndGetValueString_AllValuesAddedUsingTheC
foreach (var header in headers.NonValidated)
{
Assert.Equal("User-Agent", header.Key);
Assert.Equal("custom2/1.1 (comment) custom\u4F1A", header.Value.ToString());
Assert.Equal("custom\u4F1A custom2/1.1 (comment)", header.Value.ToString());
}
}
......@@ -704,13 +704,13 @@ public void IfRange_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
public void IfRange_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
headers.TryAddWithoutValidation("If-Range", "\"tag\"\u4F1A");
Assert.Null(headers.GetParsedValues(KnownHeaders.IfRange.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.IfRange.Descriptor));
Assert.Equal(1, headers.GetValues("If-Range").Count());
Assert.Equal("\"tag\"\u4F1A", headers.GetValues("If-Range").First());
headers.Clear();
headers.TryAddWithoutValidation("If-Range", " \"tag\", ");
Assert.Null(headers.GetParsedValues(KnownHeaders.IfRange.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.IfRange.Descriptor));
Assert.Equal(1, headers.GetValues("If-Range").Count());
Assert.Equal(" \"tag\", ", headers.GetValues("If-Range").First());
}
......@@ -759,13 +759,13 @@ public void From_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
// values are not validated, so invalid values are accepted
headers.TryAddWithoutValidation("From", " info@example.com ,");
Assert.Equal("info@example.com ,", headers.GetParsedValues(KnownHeaders.From.Descriptor));
Assert.Equal("info@example.com ,", headers.GetSingleParsedValue(KnownHeaders.From.Descriptor));
Assert.Equal(1, headers.GetValues("From").Count());
Assert.Equal("info@example.com ,", headers.GetValues("From").First());
headers.Clear();
headers.TryAddWithoutValidation("From", "info@");
Assert.Equal("info@", headers.GetParsedValues(KnownHeaders.From.Descriptor));
Assert.Equal("info@", headers.GetSingleParsedValue(KnownHeaders.From.Descriptor));
Assert.Equal(1, headers.GetValues("From").Count());
Assert.Equal("info@", headers.GetValues("From").First());
}
......@@ -807,13 +807,13 @@ public void IfModifiedSince_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
public void IfModifiedSince_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
headers.TryAddWithoutValidation("If-Modified-Since", " Sun, 06 Nov 1994 08:49:37 GMT ,");
Assert.Null(headers.GetParsedValues(KnownHeaders.IfModifiedSince.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.IfModifiedSince.Descriptor));
Assert.Equal(1, headers.GetValues("If-Modified-Since").Count());
Assert.Equal(" Sun, 06 Nov 1994 08:49:37 GMT ,", headers.GetValues("If-Modified-Since").First());
headers.Clear();
headers.TryAddWithoutValidation("If-Modified-Since", " Sun, 06 Nov ");
Assert.Null(headers.GetParsedValues(KnownHeaders.IfModifiedSince.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.IfModifiedSince.Descriptor));
Assert.Equal(1, headers.GetValues("If-Modified-Since").Count());
Assert.Equal(" Sun, 06 Nov ", headers.GetValues("If-Modified-Since").First());
}
......@@ -848,13 +848,13 @@ public void IfUnmodifiedSince_UseAddMethod_AddedValueCanBeRetrievedUsingProperty
public void IfUnmodifiedSince_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
headers.TryAddWithoutValidation("If-Unmodified-Since", " Sun, 06 Nov 1994 08:49:37 GMT ,");
Assert.Null(headers.GetParsedValues(KnownHeaders.IfUnmodifiedSince.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.IfUnmodifiedSince.Descriptor));
Assert.Equal(1, headers.GetValues("If-Unmodified-Since").Count());
Assert.Equal(" Sun, 06 Nov 1994 08:49:37 GMT ,", headers.GetValues("If-Unmodified-Since").First());
headers.Clear();
headers.TryAddWithoutValidation("If-Unmodified-Since", " Sun, 06 Nov ");
Assert.Null(headers.GetParsedValues(KnownHeaders.IfUnmodifiedSince.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.IfUnmodifiedSince.Descriptor));
Assert.Equal(1, headers.GetValues("If-Unmodified-Since").Count());
Assert.Equal(" Sun, 06 Nov ", headers.GetValues("If-Unmodified-Since").First());
}
......@@ -889,13 +889,13 @@ public void Referrer_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
public void Referrer_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
headers.TryAddWithoutValidation("Referer", " http://example.com http://other");
Assert.Null(headers.GetParsedValues(KnownHeaders.Referer.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.Referer.Descriptor));
Assert.Equal(1, headers.GetValues("Referer").Count());
Assert.Equal(" http://example.com http://other", headers.GetValues("Referer").First());
headers.Clear();
headers.TryAddWithoutValidation("Referer", "http://host /other");
Assert.Null(headers.GetParsedValues(KnownHeaders.Referer.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.Referer.Descriptor));
Assert.Equal(1, headers.GetValues("Referer").Count());
Assert.Equal("http://host /other", headers.GetValues("Referer").First());
}
......@@ -933,13 +933,13 @@ public void MaxForwards_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
public void MaxForwards_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
headers.TryAddWithoutValidation("Max-Forwards", "15,");
Assert.Null(headers.GetParsedValues(KnownHeaders.MaxForwards.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.MaxForwards.Descriptor));
Assert.Equal(1, headers.GetValues("Max-Forwards").Count());
Assert.Equal("15,", headers.GetValues("Max-Forwards").First());
headers.Clear();
headers.TryAddWithoutValidation("Max-Forwards", "1.0");
Assert.Null(headers.GetParsedValues(KnownHeaders.MaxForwards.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.MaxForwards.Descriptor));
Assert.Equal(1, headers.GetValues("Max-Forwards").Count());
Assert.Equal("1.0", headers.GetValues("Max-Forwards").First());
}
......@@ -1209,13 +1209,13 @@ public void TransferEncoding_UseAddMethod_AddedValueCanBeRetrievedUsingProperty(
public void TransferEncoding_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
headers.TryAddWithoutValidation("Transfer-Encoding", "custom\u4F1A");
Assert.Null(headers.GetParsedValues(KnownHeaders.TransferEncoding.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.TransferEncoding.Descriptor));
Assert.Equal(1, headers.GetValues("Transfer-Encoding").Count());
Assert.Equal("custom\u4F1A", headers.GetValues("Transfer-Encoding").First());
headers.Clear();
headers.TryAddWithoutValidation("Transfer-Encoding", "custom1 custom2");
Assert.Null(headers.GetParsedValues(KnownHeaders.TransferEncoding.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.TransferEncoding.Descriptor));
Assert.Equal(1, headers.GetValues("Transfer-Encoding").Count());
Assert.Equal("custom1 custom2", headers.GetValues("Transfer-Encoding").First());
......@@ -1263,13 +1263,13 @@ public void Upgrade_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
public void Upgrade_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
headers.TryAddWithoutValidation("Upgrade", "custom\u4F1A");
Assert.Null(headers.GetParsedValues(KnownHeaders.Upgrade.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.Upgrade.Descriptor));
Assert.Equal(1, headers.GetValues("Upgrade").Count());
Assert.Equal("custom\u4F1A", headers.GetValues("Upgrade").First());
headers.Clear();
headers.TryAddWithoutValidation("Upgrade", "custom1 custom2");
Assert.Null(headers.GetParsedValues(KnownHeaders.Upgrade.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.Upgrade.Descriptor));
Assert.Equal(1, headers.GetValues("Upgrade").Count());
Assert.Equal("custom1 custom2", headers.GetValues("Upgrade").First());
}
......@@ -1308,13 +1308,13 @@ public void Date_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
public void Date_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
headers.TryAddWithoutValidation("Date", " Sun, 06 Nov 1994 08:49:37 GMT ,");
Assert.Null(headers.GetParsedValues(KnownHeaders.Date.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.Date.Descriptor));
Assert.Equal(1, headers.GetValues("Date").Count());
Assert.Equal(" Sun, 06 Nov 1994 08:49:37 GMT ,", headers.GetValues("Date").First());
headers.Clear();
headers.TryAddWithoutValidation("Date", " Sun, 06 Nov ");
Assert.Null(headers.GetParsedValues(KnownHeaders.Date.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.Date.Descriptor));
Assert.Equal(1, headers.GetValues("Date").Count());
Assert.Equal(" Sun, 06 Nov ", headers.GetValues("Date").First());
}
......@@ -1455,6 +1455,18 @@ public void CacheControl_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
Assert.Equal(value, headers.CacheControl);
}
[Fact]
public void CacheControl_ValidAndInvalidValues_ReturnValidValue()
{
headers.TryAddWithoutValidation("Cache-Control", "<invalid>");
headers.TryAddWithoutValidation("Cache-Control", "no-cache=\"token1\", must-revalidate, max-age=3");
headers.TryAddWithoutValidation("Cache-Control", "public, s-maxage=15");
Assert.True(headers.CacheControl.NoCache);
Assert.True(headers.NonValidated["Cache-Control"].Count == 2);
Assert.Equal("<invalid>", headers.NonValidated["Cache-Control"].ElementAt(0));
Assert.Equal("public, must-revalidate, no-cache=\"token1\", max-age=3, s-maxage=15", headers.NonValidated["Cache-Control"].ElementAt(1));
}
[Fact]
public void Trailer_ReadAndWriteProperty_ValueMatchesPriorSetValue()
{
......
......@@ -94,7 +94,7 @@ public void Location_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
public void Location_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
headers.TryAddWithoutValidation("Location", " http://example.com http://other");
Assert.Null(headers.GetParsedValues(KnownHeaders.Location.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.Location.Descriptor));
Assert.Equal(1, headers.GetValues("Location").Count());
Assert.Equal(" http://example.com http://other", headers.GetValues("Location").First());
}
......@@ -348,26 +348,26 @@ public void Server_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
public void Server_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
headers.TryAddWithoutValidation("Server", "custom\u4F1A");
Assert.Null(headers.GetParsedValues(KnownHeaders.Server.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.Server.Descriptor));
Assert.Equal(1, headers.GetValues("Server").Count());
Assert.Equal("custom\u4F1A", headers.GetValues("Server").First());
headers.Clear();
// Note that "Server" uses whitespace as separators, so the following is an invalid value
headers.TryAddWithoutValidation("Server", "custom1, custom2");
Assert.Null(headers.GetParsedValues(KnownHeaders.Server.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.Server.Descriptor));
Assert.Equal(1, headers.GetValues("Server").Count());
Assert.Equal("custom1, custom2", headers.GetValues("Server").First());
headers.Clear();
headers.TryAddWithoutValidation("Server", "custom1, ");
Assert.Null(headers.GetParsedValues(KnownHeaders.Server.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.Server.Descriptor));
Assert.Equal(1, headers.GetValues("Server").Count());
Assert.Equal("custom1, ", headers.GetValues("Server").First());
headers.Clear();
headers.TryAddWithoutValidation("Server", ",custom1");
Assert.Null(headers.GetParsedValues(KnownHeaders.Server.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.Server.Descriptor));
Assert.Equal(1, headers.GetValues("Server").Count());
Assert.Equal(",custom1", headers.GetValues("Server").First());
}
......@@ -491,13 +491,13 @@ public void Age_UseAddMethod_AddedValueCanBeRetrievedUsingProperty()
public void Age_UseAddMethodWithInvalidValue_InvalidValueRecognized()
{
headers.TryAddWithoutValidation("Age", "10,");
Assert.Null(headers.GetParsedValues(KnownHeaders.Age.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.Age.Descriptor));
Assert.Equal(1, headers.GetValues("Age").Count());
Assert.Equal("10,", headers.GetValues("Age").First());
headers.Clear();
headers.TryAddWithoutValidation("Age", "1.1");
Assert.Null(headers.GetParsedValues(KnownHeaders.Age.Descriptor));
Assert.Null(headers.GetSingleParsedValue(KnownHeaders.Age.Descriptor));
Assert.Equal(1, headers.GetValues("Age").Count());
Assert.Equal("1.1", headers.GetValues("Age").First());
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册