From 7d6aac7ef2e6d56d91fae21470099a6428faa368 Mon Sep 17 00:00:00 2001 From: Miha Zupan Date: Sun, 26 May 2024 00:19:29 +0200 Subject: [PATCH] Fix WhiteSpace validation in HttpHeaders --- .../src/Resources/Strings.resx | 3 - .../Headers/ContentDispositionHeaderValue.cs | 21 +--- .../Net/Http/Headers/EntityTagHeaderValue.cs | 99 +++++++------------ .../Net/Http/Headers/HeaderUtilities.cs | 14 ++- .../System/Net/Http/Headers/HttpHeaders.cs | 2 +- .../Net/Http/Headers/MediaTypeHeaderValue.cs | 3 +- .../System/Net/Http/Headers/ViaHeaderValue.cs | 82 ++++++--------- .../Net/Http/Headers/WarningHeaderValue.cs | 34 ++++--- .../UnitTests/Headers/HttpHeadersTest.cs | 61 +++++------- .../UnitTests/Headers/ViaHeaderValueTest.cs | 2 + .../Headers/WarningHeaderValueTest.cs | 1 + 11 files changed, 125 insertions(+), 197 deletions(-) diff --git a/src/libraries/System.Net.Http/src/Resources/Strings.resx b/src/libraries/System.Net.Http/src/Resources/Strings.resx index ca69a570c984f..7612c7679f308 100644 --- a/src/libraries/System.Net.Http/src/Resources/Strings.resx +++ b/src/libraries/System.Net.Http/src/Resources/Strings.resx @@ -147,9 +147,6 @@ The specified value is not a valid 'Host' header string. - - The specified value is not a valid quoted string. - Invalid range. At least one of the two parameters must not be null. diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentDispositionHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentDispositionHeaderValue.cs index 05f731954469e..5a179198bc023 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentDispositionHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentDispositionHeaderValue.cs @@ -5,7 +5,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.Runtime.CompilerServices; using System.Text; namespace System.Net.Http.Headers @@ -35,7 +34,7 @@ public string DispositionType get { return _dispositionType; } set { - CheckDispositionTypeFormat(value); + HeaderUtilities.CheckValidToken(value); _dispositionType = value; } } @@ -125,7 +124,7 @@ public long? Size #region Constructors - internal ContentDispositionHeaderValue() + private ContentDispositionHeaderValue() { // Used by the parser to create a new instance of this type. } @@ -140,7 +139,8 @@ protected ContentDispositionHeaderValue(ContentDispositionHeaderValue source) public ContentDispositionHeaderValue(string dispositionType) { - CheckDispositionTypeFormat(dispositionType); + HeaderUtilities.CheckValidToken(dispositionType); + _dispositionType = dispositionType; } @@ -271,19 +271,6 @@ private static int GetDispositionTypeExpressionLength(string input, int startInd return typeLength; } - private static void CheckDispositionTypeFormat(string dispositionType, [CallerArgumentExpression(nameof(dispositionType))] string? parameterName = null) - { - ArgumentException.ThrowIfNullOrWhiteSpace(dispositionType, parameterName); - - // When adding values using strongly typed objects, no leading/trailing LWS (whitespace) are allowed. - int dispositionTypeLength = GetDispositionTypeExpressionLength(dispositionType, 0, out string? tempDispositionType); - if ((dispositionTypeLength == 0) || (tempDispositionType!.Length != dispositionType.Length)) - { - throw new FormatException(SR.Format(System.Globalization.CultureInfo.InvariantCulture, - SR.net_http_headers_invalid_value, dispositionType)); - } - } - #endregion Parsing #region Helpers diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/EntityTagHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/EntityTagHeaderValue.cs index d6177a2555a56..41fea8bb0f2c2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/EntityTagHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/EntityTagHeaderValue.cs @@ -8,24 +8,25 @@ namespace System.Net.Http.Headers { public class EntityTagHeaderValue : ICloneable { - private readonly string _tag; - private readonly bool _isWeak; + public string Tag { get; private init; } - public string Tag - { - get { return _tag; } - } - - public bool IsWeak - { - get { return _isWeak; } - } + public bool IsWeak { get; private init; } - public static EntityTagHeaderValue Any { get; } = new EntityTagHeaderValue(); + public static EntityTagHeaderValue Any { get; } = new EntityTagHeaderValue("*", isWeak: false, false); - private EntityTagHeaderValue() + private EntityTagHeaderValue(string tag, bool isWeak, bool _) { - _tag = "*"; +#if DEBUG + // This constructor should only be used with already validated values. + // "*" is a special case that can only be created via the static Any property. + if (tag != "*") + { + new EntityTagHeaderValue(tag, isWeak); + } +#endif + + Tag = tag; + IsWeak = isWeak; } public EntityTagHeaderValue(string tag) @@ -35,56 +36,31 @@ public EntityTagHeaderValue(string tag) public EntityTagHeaderValue(string tag, bool isWeak) { - ArgumentException.ThrowIfNullOrWhiteSpace(tag); + HeaderUtilities.CheckValidQuotedString(tag); - int length; - if ((HttpRuleParser.GetQuotedStringLength(tag, 0, out length) != HttpParseResult.Parsed) || - (length != tag.Length)) - { - // Note that we don't allow 'W/' prefixes for weak ETags in the 'tag' parameter. If the user wants to - // add a weak ETag, they can set 'isWeak' to true. - throw new FormatException(SR.net_http_headers_invalid_etag_name); - } - - _tag = tag; - _isWeak = isWeak; + Tag = tag; + IsWeak = isWeak; } private EntityTagHeaderValue(EntityTagHeaderValue source) { Debug.Assert(source != null); - _tag = source._tag; - _isWeak = source._isWeak; + Tag = source.Tag; + IsWeak = source.IsWeak; } - public override string ToString() - { - if (_isWeak) - { - return "W/" + _tag; - } - return _tag; - } - - public override bool Equals([NotNullWhen(true)] object? obj) - { - EntityTagHeaderValue? other = obj as EntityTagHeaderValue; - - if (other == null) - { - return false; - } + public override string ToString() => + IsWeak ? $"W/{Tag}" : Tag; + public override bool Equals([NotNullWhen(true)] object? obj) => + obj is EntityTagHeaderValue other && + IsWeak == other.IsWeak && // Since the tag is a quoted-string we treat it case-sensitive. - return ((_isWeak == other._isWeak) && string.Equals(_tag, other._tag, StringComparison.Ordinal)); - } + string.Equals(Tag, other.Tag, StringComparison.Ordinal); - public override int GetHashCode() - { - // Since the tag is a quoted-string we treat it case-sensitive. - return _tag.GetHashCode() ^ _isWeak.GetHashCode(); - } + public override int GetHashCode() => + HashCode.Combine(Tag, IsWeak); public static EntityTagHeaderValue Parse(string input) { @@ -144,24 +120,15 @@ internal static int GetEntityTagLength(string? input, int startIndex, out Entity current += HttpRuleParser.GetWhitespaceLength(input, current); } - int tagStartIndex = current; - int tagLength; - if (current == input.Length || HttpRuleParser.GetQuotedStringLength(input, current, out tagLength) != HttpParseResult.Parsed) + if (current == input.Length || HttpRuleParser.GetQuotedStringLength(input, current, out int tagLength) != HttpParseResult.Parsed) { return 0; } - if (tagLength == input.Length) - { - // Most of the time we'll have strong ETags without leading/trailing whitespace. - Debug.Assert(startIndex == 0); - Debug.Assert(!isWeak); - parsedValue = new EntityTagHeaderValue(input); - } - else - { - parsedValue = new EntityTagHeaderValue(input.Substring(tagStartIndex, tagLength), isWeak); - } + // Most of the time we'll have strong ETags without leading/trailing whitespace. + Debug.Assert(tagLength != input.Length || (startIndex == 0 && !isWeak)); + + parsedValue = new EntityTagHeaderValue(input.Substring(current, tagLength), isWeak, false); current += tagLength; } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderUtilities.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderUtilities.cs index 1a40f471418c4..cf5ef46a98516 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderUtilities.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderUtilities.cs @@ -142,9 +142,9 @@ private static void AddHexEscaped(byte c, ref ValueStringBuilder destination) internal static void CheckValidToken(string value, [CallerArgumentExpression(nameof(value))] string? parameterName = null) { - ArgumentException.ThrowIfNullOrWhiteSpace(value, parameterName); + ArgumentException.ThrowIfNullOrEmpty(value, parameterName); - if (HttpRuleParser.GetTokenLength(value, 0) != value.Length) + if (!HttpRuleParser.IsToken(value)) { throw new FormatException(SR.Format(CultureInfo.InvariantCulture, SR.net_http_headers_invalid_value, value)); } @@ -152,10 +152,9 @@ internal static void CheckValidToken(string value, [CallerArgumentExpression(nam internal static void CheckValidComment(string value, [CallerArgumentExpression(nameof(value))] string? parameterName = null) { - ArgumentException.ThrowIfNullOrWhiteSpace(value, parameterName); + ArgumentException.ThrowIfNullOrEmpty(value, parameterName); - int length; - if ((HttpRuleParser.GetCommentLength(value, 0, out length) != HttpParseResult.Parsed) || + if ((HttpRuleParser.GetCommentLength(value, 0, out int length) != HttpParseResult.Parsed) || (length != value.Length)) // no trailing spaces allowed { throw new FormatException(SR.Format(CultureInfo.InvariantCulture, SR.net_http_headers_invalid_value, value)); @@ -164,10 +163,9 @@ internal static void CheckValidComment(string value, [CallerArgumentExpression(n internal static void CheckValidQuotedString(string value, [CallerArgumentExpression(nameof(value))] string? parameterName = null) { - ArgumentException.ThrowIfNullOrWhiteSpace(value, parameterName); + ArgumentException.ThrowIfNullOrEmpty(value, parameterName); - int length; - if ((HttpRuleParser.GetQuotedStringLength(value, 0, out length) != HttpParseResult.Parsed) || + if ((HttpRuleParser.GetQuotedStringLength(value, 0, out int length) != HttpParseResult.Parsed) || (length != value.Length)) // no trailing spaces allowed { throw new FormatException(SR.Format(CultureInfo.InvariantCulture, SR.net_http_headers_invalid_value, value)); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs index 56015f488aaae..d004cc9a374d4 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs @@ -1026,7 +1026,7 @@ private static void ParseAndAddValue(HeaderDescriptor descriptor, HeaderStoreIte private HeaderDescriptor GetHeaderDescriptor(string name) { - ArgumentException.ThrowIfNullOrWhiteSpace(name); + ArgumentException.ThrowIfNullOrEmpty(name); if (!HeaderDescriptor.TryGet(name, out HeaderDescriptor descriptor)) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeHeaderValue.cs index 130c8bdd19892..1b5324adc5f6c 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeHeaderValue.cs @@ -6,7 +6,6 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Text; -using static System.HexConverter; namespace System.Net.Http.Headers { @@ -275,7 +274,7 @@ private static int GetMediaTypeExpressionLength(string input, int startIndex, ou private static void CheckMediaTypeFormat(string mediaType, [CallerArgumentExpression(nameof(mediaType))] string? parameterName = null) { - ArgumentException.ThrowIfNullOrWhiteSpace(mediaType, parameterName); + ArgumentException.ThrowIfNullOrEmpty(mediaType, parameterName); // When adding values using strongly typed objects, no leading/trailing LWS (whitespace) are allowed. // Also no LWS between type and subtype are allowed. diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ViaHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ViaHeaderValue.cs index fc9a64e7bc734..ec8da0c2da61b 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ViaHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ViaHeaderValue.cs @@ -3,7 +3,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.IO; using System.Text; namespace System.Net.Http.Headers @@ -15,24 +14,25 @@ public class ViaHeaderValue : ICloneable private readonly string _receivedBy; private readonly string? _comment; - public string? ProtocolName - { - get { return _protocolName; } - } + public string? ProtocolName => _protocolName; - public string ProtocolVersion - { - get { return _protocolVersion; } - } + public string ProtocolVersion => _protocolVersion; - public string ReceivedBy - { - get { return _receivedBy; } - } + public string ReceivedBy => _receivedBy; + + public string? Comment => _comment; - public string? Comment + private ViaHeaderValue(string protocolVersion, string receivedBy, string? protocolName, string? comment, bool _) { - get { return _comment; } +#if DEBUG + // This constructor should only be used with already validated values. + new ViaHeaderValue(protocolVersion, receivedBy, protocolName, comment); +#endif + + _protocolVersion = protocolVersion; + _receivedBy = receivedBy; + _protocolName = protocolName; + _comment = comment; } public ViaHeaderValue(string protocolVersion, string receivedBy) @@ -99,40 +99,21 @@ public override string ToString() return sb.ToString(); } - public override bool Equals([NotNullWhen(true)] object? obj) - { - ViaHeaderValue? other = obj as ViaHeaderValue; - - if (other == null) - { - return false; - } - + public override bool Equals([NotNullWhen(true)] object? obj) => + obj is ViaHeaderValue other && // Note that for token and host case-insensitive comparison is used. Comments are compared using case- // sensitive comparison. - return string.Equals(_protocolVersion, other._protocolVersion, StringComparison.OrdinalIgnoreCase) && - string.Equals(_receivedBy, other._receivedBy, StringComparison.OrdinalIgnoreCase) && - string.Equals(_protocolName, other._protocolName, StringComparison.OrdinalIgnoreCase) && - string.Equals(_comment, other._comment, StringComparison.Ordinal); - } - - public override int GetHashCode() - { - int result = StringComparer.OrdinalIgnoreCase.GetHashCode(_protocolVersion) ^ - StringComparer.OrdinalIgnoreCase.GetHashCode(_receivedBy); - - if (!string.IsNullOrEmpty(_protocolName)) - { - result ^= StringComparer.OrdinalIgnoreCase.GetHashCode(_protocolName); - } - - if (!string.IsNullOrEmpty(_comment)) - { - result ^= _comment.GetHashCode(); - } - - return result; - } + string.Equals(_protocolVersion, other._protocolVersion, StringComparison.OrdinalIgnoreCase) && + string.Equals(_receivedBy, other._receivedBy, StringComparison.OrdinalIgnoreCase) && + string.Equals(_protocolName, other._protocolName, StringComparison.OrdinalIgnoreCase) && + string.Equals(_comment, other._comment, StringComparison.Ordinal); + + public override int GetHashCode() => + HashCode.Combine( + StringComparer.OrdinalIgnoreCase.GetHashCode(_protocolVersion), + StringComparer.OrdinalIgnoreCase.GetHashCode(_receivedBy), + _protocolName is null ? 0 : StringComparer.OrdinalIgnoreCase.GetHashCode(_protocolName), + _comment); public static ViaHeaderValue Parse(string input) { @@ -191,8 +172,7 @@ internal static int GetViaLength(string? input, int startIndex, out object? pars if ((current < input.Length) && (input[current] == '(')) { // We have a in '[/] []' - int commentLength; - if (HttpRuleParser.GetCommentLength(input, current, out commentLength) != HttpParseResult.Parsed) + if (HttpRuleParser.GetCommentLength(input, current, out int commentLength) != HttpParseResult.Parsed) { return 0; // We found a '(' character but it wasn't a valid comment. Abort. } @@ -203,7 +183,7 @@ internal static int GetViaLength(string? input, int startIndex, out object? pars current += HttpRuleParser.GetWhitespaceLength(input, current); } - parsedValue = new ViaHeaderValue(protocolVersion, receivedBy!, protocolName, comment); + parsedValue = new ViaHeaderValue(protocolVersion, receivedBy, protocolName, comment, false); return current - startIndex; } @@ -275,7 +255,7 @@ object ICloneable.Clone() private static void CheckReceivedBy(string receivedBy) { - ArgumentException.ThrowIfNullOrWhiteSpace(receivedBy); + ArgumentException.ThrowIfNullOrEmpty(receivedBy); // 'receivedBy' can either be a host or a token. Since a token is a valid host, we only verify if the value // is a valid host.; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/WarningHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/WarningHeaderValue.cs index 9501eac5f5f5d..6d2f1efb2289e 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/WarningHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/WarningHeaderValue.cs @@ -24,6 +24,20 @@ public class WarningHeaderValue : ICloneable public DateTimeOffset? Date => _dateHasValue ? _date : null; + private WarningHeaderValue(int code, string agent, string text, DateTimeOffset? date) + { +#if DEBUG + // This constructor should only be used with already validated values. + new WarningHeaderValue(code, agent, text); +#endif + + _code = code; + _agent = agent; + _text = text; + _date = date.GetValueOrDefault(); + _dateHasValue = date.HasValue; + } + public WarningHeaderValue(int code, string agent, string text) { CheckCode(code); @@ -130,10 +144,9 @@ internal static int GetWarningLength(string? input, int startIndex, out object? } // Read in ' [""]' - int code; int current = startIndex; - if (!TryReadCode(input, ref current, out code)) + if (!TryReadCode(input, ref current, out int code)) { return 0; } @@ -145,9 +158,8 @@ internal static int GetWarningLength(string? input, int startIndex, out object? } // Read in ' [""]' - int textLength; int textStartIndex = current; - if (HttpRuleParser.GetQuotedStringLength(input, current, out textLength) != HttpParseResult.Parsed) + if (HttpRuleParser.GetQuotedStringLength(input, current, out int textLength) != HttpParseResult.Parsed) { return 0; } @@ -157,15 +169,12 @@ internal static int GetWarningLength(string? input, int startIndex, out object? current += textLength; // Read in ' [""]' - DateTimeOffset? date; - if (!TryReadDate(input, ref current, out date)) + if (!TryReadDate(input, ref current, out DateTimeOffset? date)) { return 0; } - parsedValue = date is null ? - new WarningHeaderValue(code, agent, text) : - new WarningHeaderValue(code, agent, text, date.Value); + parsedValue = new WarningHeaderValue(code, agent, text, date); return current - startIndex; } @@ -254,8 +263,7 @@ private static bool TryReadDate(string input, ref int current, out DateTimeOffse } current += quote; - DateTimeOffset temp; - if (!HttpDateParser.TryParse(input.AsSpan(dateStartIndex, current - dateStartIndex), out temp)) + if (!HttpDateParser.TryParse(input.AsSpan(dateStartIndex, current - dateStartIndex), out DateTimeOffset temp)) { return false; } @@ -282,9 +290,9 @@ private static void CheckCode(int code) private static void CheckAgent(string agent) { - ArgumentException.ThrowIfNullOrWhiteSpace(agent); + ArgumentException.ThrowIfNullOrEmpty(agent); - // 'receivedBy' can either be a host or a token. Since a token is a valid host, we only verify if the value + // 'Agent' can either be a host or a token. Since a token is a valid host, we only verify if the value // is a valid host. if (HttpRuleParser.GetHostLength(agent, 0, true) != agent.Length) { diff --git a/src/libraries/System.Net.Http/tests/UnitTests/Headers/HttpHeadersTest.cs b/src/libraries/System.Net.Http/tests/UnitTests/Headers/HttpHeadersTest.cs index 9def1da0e76bf..dc6239cced592 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/Headers/HttpHeadersTest.cs +++ b/src/libraries/System.Net.Http/tests/UnitTests/Headers/HttpHeadersTest.cs @@ -441,23 +441,20 @@ public void TryAddWithoutValidation_MultipleAddNullValueCollection_Throws() Assert.Throws(() => { headers.TryAddWithoutValidation(headers.Descriptor, values); }); } - [Theory] - [InlineData(null)] - public void Add_SingleUseNullHeaderName_Throw(string headerName) + [Fact] + public void Add_SingleUseNullHeaderName_Throw() { MockHeaders headers = new MockHeaders(); - AssertExtensions.Throws("name", () => { headers.Add(headerName, "value"); }); + AssertExtensions.Throws("name", () => { headers.Add(null, "value"); }); } - [Theory] - [InlineData("")] - [InlineData(" \t\r\n ")] - public void Add_SingleUseWhiteSpaceHeaderName_Throw(string headerName) + [Fact] + public void Add_SingleUseWhiteSpaceHeaderName_Throw() { MockHeaders headers = new MockHeaders(); - AssertExtensions.Throws("name", () => { headers.Add(headerName, "value"); }); + AssertExtensions.Throws("name", () => { headers.Add("", "value"); }); } [Theory] @@ -1071,23 +1068,20 @@ public void Clear_AddMultipleHeadersAndThenClear_NoHeadersInCollection() Assert.Equal(2, headers.Parser.TryParseValueCallCount); } - [Theory] - [InlineData(null)] - public void Remove_UseNullHeaderName_Throw(string headerName) + [Fact] + public void Remove_UseNullHeaderName_Throw() { MockHeaders headers = new MockHeaders(); - AssertExtensions.Throws("name", () => { headers.Remove(headerName); }); + AssertExtensions.Throws("name", () => { headers.Remove(null); }); } - [Theory] - [InlineData("")] - [InlineData(" \t\r\n ")] - public void Remove_UseWhiteSpaceHeaderName_Throw(string headerName) + [Fact] + public void Remove_UseEmptyHeaderName_Throw() { MockHeaders headers = new MockHeaders(); - AssertExtensions.Throws("name", () => { headers.Remove(headerName); }); + AssertExtensions.Throws("name", () => { headers.Remove(""); }); } [Theory] @@ -1227,23 +1221,20 @@ public void TryGetValues_GetValuesForExistingHeader_ReturnsTrueAndListOfValues() Assert.Equal(parsedPrefix + "2", values.ElementAt(1)); } - [Theory] - [InlineData(null)] - public void GetValues_UseNullHeaderName_Throw(string headerName) + [Fact] + public void GetValues_UseNullHeaderName_Throw() { MockHeaders headers = new MockHeaders(); - AssertExtensions.Throws("name", () => { headers.GetValues(headerName); }); + AssertExtensions.Throws("name", () => { headers.GetValues(null); }); } - [Theory] - [InlineData("")] - [InlineData(" \t\r\n ")] - public void GetValues_UseWhiteSpaceHeaderName_Throw(string headerName) + [Fact] + public void GetValues_UseEmptyHeaderName_Throw() { MockHeaders headers = new MockHeaders(); - AssertExtensions.Throws("name", () => { headers.GetValues(headerName); }); + AssertExtensions.Throws("name", () => { headers.GetValues(""); }); } [Theory] @@ -1601,23 +1592,20 @@ public void NonValidated_ValidInvalidAndRaw_AllReturned() } } - [Theory] - [InlineData(null)] - public void Contains_UseNullHeaderName_Throw(string headerName) + [Fact] + public void Contains_UseNullHeaderName_Throw() { MockHeaders headers = new MockHeaders(); - AssertExtensions.Throws("name", () => { headers.Contains(headerName); }); + AssertExtensions.Throws("name", () => { headers.Contains(null); }); } - [Theory] - [InlineData("")] - [InlineData(" \t\r\n ")] - public void Contains_UseEmptyHeaderName_Throw(string headerName) + [Fact] + public void Contains_UseEmptyHeaderName_Throw() { MockHeaders headers = new MockHeaders(); - AssertExtensions.Throws("name", () => { headers.Contains(headerName); }); + AssertExtensions.Throws("name", () => { headers.Contains(""); }); } [Theory] @@ -2578,6 +2566,7 @@ public static IEnumerable GetInvalidHeaderNames() yield return new object[] { "invalid=header" }; yield return new object[] { "invalid{header" }; yield return new object[] { "invalid}header" }; + yield return new object[] { " \t\r\n " }; } public static IEnumerable HeaderValuesWithNewLines() diff --git a/src/libraries/System.Net.Http/tests/UnitTests/Headers/ViaHeaderValueTest.cs b/src/libraries/System.Net.Http/tests/UnitTests/Headers/ViaHeaderValueTest.cs index a803faa912a61..3119f8a95f505 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/Headers/ViaHeaderValueTest.cs +++ b/src/libraries/System.Net.Http/tests/UnitTests/Headers/ViaHeaderValueTest.cs @@ -200,6 +200,8 @@ public void GetViaLength_DifferentValidScenarios_AllReturnNonZero() CheckGetViaLength(null, 0, 0, null); CheckGetViaLength(string.Empty, 0, 0, null); CheckGetViaLength(" ", 0, 0, null); + + CheckGetViaLength("a\t\u2000", 0, 3, new ViaHeaderValue("a", "\u2000")); } [Fact] diff --git a/src/libraries/System.Net.Http/tests/UnitTests/Headers/WarningHeaderValueTest.cs b/src/libraries/System.Net.Http/tests/UnitTests/Headers/WarningHeaderValueTest.cs index 65de44e7ec0c1..7e05b1cbc6459 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/Headers/WarningHeaderValueTest.cs +++ b/src/libraries/System.Net.Http/tests/UnitTests/Headers/WarningHeaderValueTest.cs @@ -213,6 +213,7 @@ public void Parse_SetOfValidValueStrings_ParsedCorrectly() new WarningHeaderValue(1, "h", "\"t\"", new DateTimeOffset(2010, 7, 20, 1, 2, 3, TimeSpan.Zero))); CheckValidParse("1 \u4F1A \"t\" ", new WarningHeaderValue(1, "\u4F1A", "\"t\"")); + CheckValidParse("1 \u2000 \"\"", new WarningHeaderValue(1, "\u2000", "\"\"")); } [Fact]