diff --git a/src/Microsoft.AspNetCore.Http.Extensions/HttpRequestMultipartExtensions.cs b/src/Microsoft.AspNetCore.Http.Extensions/HttpRequestMultipartExtensions.cs
index 76770428a0..da9188dad3 100644
--- a/src/Microsoft.AspNetCore.Http.Extensions/HttpRequestMultipartExtensions.cs
+++ b/src/Microsoft.AspNetCore.Http.Extensions/HttpRequestMultipartExtensions.cs
@@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Http.Extensions
{
return string.Empty;
}
- return HeaderUtilities.RemoveQuotes(mediaType.Boundary);
+ return HeaderUtilities.RemoveQuotes(mediaType.Boundary).ToString();
}
}
}
diff --git a/src/Microsoft.AspNetCore.Http/Features/FormFeature.cs b/src/Microsoft.AspNetCore.Http/Features/FormFeature.cs
index cd8b491ffd..f091e3b166 100644
--- a/src/Microsoft.AspNetCore.Http/Features/FormFeature.cs
+++ b/src/Microsoft.AspNetCore.Http/Features/FormFeature.cs
@@ -8,6 +8,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.WebUtilities;
+using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Http.Features
@@ -293,14 +294,14 @@ namespace Microsoft.AspNetCore.Http.Features
{
// Content-Disposition: form-data; name="key";
return contentDisposition != null && contentDisposition.DispositionType.Equals("form-data")
- && string.IsNullOrEmpty(contentDisposition.FileName) && string.IsNullOrEmpty(contentDisposition.FileNameStar);
+ && StringSegment.IsNullOrEmpty(contentDisposition.FileName) && StringSegment.IsNullOrEmpty(contentDisposition.FileNameStar);
}
private bool HasFileContentDisposition(ContentDispositionHeaderValue contentDisposition)
{
// Content-Disposition: form-data; name="myfile1"; filename="Misc 002.jpg"
return contentDisposition != null && contentDisposition.DispositionType.Equals("form-data")
- && (!string.IsNullOrEmpty(contentDisposition.FileName) || !string.IsNullOrEmpty(contentDisposition.FileNameStar));
+ && (!StringSegment.IsNullOrEmpty(contentDisposition.FileName) || !StringSegment.IsNullOrEmpty(contentDisposition.FileNameStar));
}
// Content-Type: multipart/form-data; boundary="----WebKitFormBoundarymx2fSWqWSd0OxQqq"
@@ -308,7 +309,7 @@ namespace Microsoft.AspNetCore.Http.Features
private static string GetBoundary(MediaTypeHeaderValue contentType, int lengthLimit)
{
var boundary = HeaderUtilities.RemoveQuotes(contentType.Boundary);
- if (string.IsNullOrWhiteSpace(boundary))
+ if (StringSegment.IsNullOrEmpty(boundary))
{
throw new InvalidDataException("Missing content-type boundary.");
}
@@ -316,7 +317,7 @@ namespace Microsoft.AspNetCore.Http.Features
{
throw new InvalidDataException($"Multipart boundary length limit {lengthLimit} exceeded.");
}
- return boundary;
+ return boundary.ToString();
}
}
}
diff --git a/src/Microsoft.AspNetCore.Http/Internal/RequestCookieCollection.cs b/src/Microsoft.AspNetCore.Http/Internal/RequestCookieCollection.cs
index d02c9fade5..ca85fd1d04 100644
--- a/src/Microsoft.AspNetCore.Http/Internal/RequestCookieCollection.cs
+++ b/src/Microsoft.AspNetCore.Http/Internal/RequestCookieCollection.cs
@@ -75,8 +75,8 @@ namespace Microsoft.AspNetCore.Http.Internal
for (var i = 0; i < cookies.Count; i++)
{
var cookie = cookies[i];
- var name = Uri.UnescapeDataString(cookie.Name);
- var value = Uri.UnescapeDataString(cookie.Value);
+ var name = Uri.UnescapeDataString(cookie.Name.Value);
+ var value = Uri.UnescapeDataString(cookie.Value.Value);
store[name] = value;
}
diff --git a/src/Microsoft.AspNetCore.WebUtilities/FileMultipartSection.cs b/src/Microsoft.AspNetCore.WebUtilities/FileMultipartSection.cs
index b1ba2ff47e..70d7741f64 100644
--- a/src/Microsoft.AspNetCore.WebUtilities/FileMultipartSection.cs
+++ b/src/Microsoft.AspNetCore.WebUtilities/FileMultipartSection.cs
@@ -39,11 +39,11 @@ namespace Microsoft.AspNetCore.WebUtilities
Section = section;
_contentDispositionHeader = header;
- Name = HeaderUtilities.RemoveQuotes(_contentDispositionHeader.Name) ?? string.Empty;
+ Name = HeaderUtilities.RemoveQuotes(_contentDispositionHeader.Name).ToString();
FileName = HeaderUtilities.RemoveQuotes(
- _contentDispositionHeader.FileNameStar ??
- _contentDispositionHeader.FileName ??
- string.Empty);
+ _contentDispositionHeader.FileNameStar.HasValue ?
+ _contentDispositionHeader.FileNameStar :
+ _contentDispositionHeader.FileName).ToString();
}
///
diff --git a/src/Microsoft.AspNetCore.WebUtilities/FormMultipartSection.cs b/src/Microsoft.AspNetCore.WebUtilities/FormMultipartSection.cs
index 652cbdeb12..01af0455b8 100644
--- a/src/Microsoft.AspNetCore.WebUtilities/FormMultipartSection.cs
+++ b/src/Microsoft.AspNetCore.WebUtilities/FormMultipartSection.cs
@@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.WebUtilities
Section = section;
_contentDispositionHeader = header;
- Name = HeaderUtilities.RemoveQuotes(_contentDispositionHeader.Name);
+ Name = HeaderUtilities.RemoveQuotes(_contentDispositionHeader.Name).ToString();
}
///
diff --git a/src/Microsoft.Net.Http.Headers/BaseHeaderParser.cs b/src/Microsoft.Net.Http.Headers/BaseHeaderParser.cs
index 1b4038d21b..f3caaafb70 100644
--- a/src/Microsoft.Net.Http.Headers/BaseHeaderParser.cs
+++ b/src/Microsoft.Net.Http.Headers/BaseHeaderParser.cs
@@ -1,6 +1,8 @@
// 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 Microsoft.Extensions.Primitives;
+
namespace Microsoft.Net.Http.Headers
{
internal abstract class BaseHeaderParser : HttpHeaderParser
@@ -10,9 +12,9 @@ namespace Microsoft.Net.Http.Headers
{
}
- protected abstract int GetParsedValueLength(string value, int startIndex, out T parsedValue);
+ protected abstract int GetParsedValueLength(StringSegment value, int startIndex, out T parsedValue);
- public sealed override bool TryParseValue(string value, ref int index, out T parsedValue)
+ public sealed override bool TryParseValue(StringSegment value, ref int index, out T parsedValue)
{
parsedValue = default(T);
@@ -21,7 +23,7 @@ namespace Microsoft.Net.Http.Headers
// Accept: text/xml; q=1
// Accept:
// Accept: text/plain; q=0.2
- if (string.IsNullOrEmpty(value) || (index == value.Length))
+ if (StringSegment.IsNullOrEmpty(value) || (index == value.Length))
{
return SupportsMultipleValues;
}
diff --git a/src/Microsoft.Net.Http.Headers/CacheControlHeaderValue.cs b/src/Microsoft.Net.Http.Headers/CacheControlHeaderValue.cs
index af31316667..81e18faf47 100644
--- a/src/Microsoft.Net.Http.Headers/CacheControlHeaderValue.cs
+++ b/src/Microsoft.Net.Http.Headers/CacheControlHeaderValue.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Text;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -32,10 +33,10 @@ namespace Microsoft.Net.Http.Headers
private static readonly HttpHeaderParser Parser
= new GenericHeaderParser(true, GetCacheControlLength);
- private static readonly Action CheckIsValidTokenAction = CheckIsValidToken;
+ private static readonly Action CheckIsValidTokenAction = CheckIsValidToken;
private bool _noCache;
- private ICollection _noCacheHeaders;
+ private ICollection _noCacheHeaders;
private bool _noStore;
private TimeSpan? _maxAge;
private TimeSpan? _sharedMaxAge;
@@ -46,7 +47,7 @@ namespace Microsoft.Net.Http.Headers
private bool _onlyIfCached;
private bool _public;
private bool _private;
- private ICollection _privateHeaders;
+ private ICollection _privateHeaders;
private bool _mustRevalidate;
private bool _proxyRevalidate;
private IList _extensions;
@@ -62,13 +63,13 @@ namespace Microsoft.Net.Http.Headers
set { _noCache = value; }
}
- public ICollection NoCacheHeaders
+ public ICollection NoCacheHeaders
{
get
{
if (_noCacheHeaders == null)
{
- _noCacheHeaders = new ObjectCollection(CheckIsValidTokenAction);
+ _noCacheHeaders = new ObjectCollection(CheckIsValidTokenAction);
}
return _noCacheHeaders;
}
@@ -134,13 +135,13 @@ namespace Microsoft.Net.Http.Headers
set { _private = value; }
}
- public ICollection PrivateHeaders
+ public ICollection PrivateHeaders
{
get
{
if (_privateHeaders == null)
{
- _privateHeaders = new ObjectCollection(CheckIsValidTokenAction);
+ _privateHeaders = new ObjectCollection(CheckIsValidTokenAction);
}
return _privateHeaders;
}
@@ -259,13 +260,13 @@ namespace Microsoft.Net.Http.Headers
}
if (!HeaderUtilities.AreEqualCollections(_noCacheHeaders, other._noCacheHeaders,
- StringComparer.OrdinalIgnoreCase))
+ StringSegmentComparer.OrdinalIgnoreCase))
{
return false;
}
if (!HeaderUtilities.AreEqualCollections(_privateHeaders, other._privateHeaders,
- StringComparer.OrdinalIgnoreCase))
+ StringSegmentComparer.OrdinalIgnoreCase))
{
return false;
}
@@ -299,7 +300,7 @@ namespace Microsoft.Net.Http.Headers
{
foreach (var noCacheHeader in _noCacheHeaders)
{
- result = result ^ StringComparer.OrdinalIgnoreCase.GetHashCode(noCacheHeader);
+ result = result ^ StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(noCacheHeader);
}
}
@@ -307,7 +308,7 @@ namespace Microsoft.Net.Http.Headers
{
foreach (var privateHeader in _privateHeaders)
{
- result = result ^ StringComparer.OrdinalIgnoreCase.GetHashCode(privateHeader);
+ result = result ^ StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(privateHeader);
}
}
@@ -322,7 +323,7 @@ namespace Microsoft.Net.Http.Headers
return result;
}
- public static CacheControlHeaderValue Parse(string input)
+ public static CacheControlHeaderValue Parse(StringSegment input)
{
int index = 0;
// Cache-Control is unusual because there are no required values so the parser will succeed for an empty string, but still return null.
@@ -334,7 +335,7 @@ namespace Microsoft.Net.Http.Headers
return result;
}
- public static bool TryParse(string input, out CacheControlHeaderValue parsedValue)
+ public static bool TryParse(StringSegment input, out CacheControlHeaderValue parsedValue)
{
int index = 0;
// Cache-Control is unusual because there are no required values so the parser will succeed for an empty string, but still return null.
@@ -346,13 +347,13 @@ namespace Microsoft.Net.Http.Headers
return false;
}
- private static int GetCacheControlLength(string input, int startIndex, out CacheControlHeaderValue parsedValue)
+ private static int GetCacheControlLength(StringSegment input, int startIndex, out CacheControlHeaderValue parsedValue)
{
Contract.Requires(startIndex >= 0);
parsedValue = null;
- if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
+ if (StringSegment.IsNullOrEmpty(input) || (startIndex >= input.Length))
{
return 0;
}
@@ -403,7 +404,7 @@ namespace Microsoft.Net.Http.Headers
switch (name.Length)
{
case 6:
- if (string.Equals(PublicString, name, StringComparison.OrdinalIgnoreCase))
+ if (StringSegment.Equals(PublicString, name, StringComparison.OrdinalIgnoreCase))
{
success = TrySetTokenOnlyValue(nameValue, ref cc._public);
}
@@ -414,11 +415,11 @@ namespace Microsoft.Net.Http.Headers
break;
case 7:
- if (string.Equals(MaxAgeString, name, StringComparison.OrdinalIgnoreCase))
+ if (StringSegment.Equals(MaxAgeString, name, StringComparison.OrdinalIgnoreCase))
{
success = TrySetTimeSpan(nameValue, ref cc._maxAge);
}
- else if(string.Equals(PrivateString, name, StringComparison.OrdinalIgnoreCase))
+ else if(StringSegment.Equals(PrivateString, name, StringComparison.OrdinalIgnoreCase))
{
success = TrySetOptionalTokenList(nameValue, ref cc._private, ref cc._privateHeaders);
}
@@ -429,15 +430,15 @@ namespace Microsoft.Net.Http.Headers
break;
case 8:
- if (string.Equals(NoCacheString, name, StringComparison.OrdinalIgnoreCase))
+ if (StringSegment.Equals(NoCacheString, name, StringComparison.OrdinalIgnoreCase))
{
success = TrySetOptionalTokenList(nameValue, ref cc._noCache, ref cc._noCacheHeaders);
}
- else if (string.Equals(NoStoreString, name, StringComparison.OrdinalIgnoreCase))
+ else if (StringSegment.Equals(NoStoreString, name, StringComparison.OrdinalIgnoreCase))
{
success = TrySetTokenOnlyValue(nameValue, ref cc._noStore);
}
- else if (string.Equals(SharedMaxAgeString, name, StringComparison.OrdinalIgnoreCase))
+ else if (StringSegment.Equals(SharedMaxAgeString, name, StringComparison.OrdinalIgnoreCase))
{
success = TrySetTimeSpan(nameValue, ref cc._sharedMaxAge);
}
@@ -448,7 +449,7 @@ namespace Microsoft.Net.Http.Headers
break;
case 9:
- if (string.Equals(MaxStaleString, name, StringComparison.OrdinalIgnoreCase))
+ if (StringSegment.Equals(MaxStaleString, name, StringComparison.OrdinalIgnoreCase))
{
success = ((nameValue.Value == null) || TrySetTimeSpan(nameValue, ref cc._maxStaleLimit));
if (success)
@@ -456,7 +457,7 @@ namespace Microsoft.Net.Http.Headers
cc._maxStale = true;
}
}
- else if (string.Equals(MinFreshString, name, StringComparison.OrdinalIgnoreCase))
+ else if (StringSegment.Equals(MinFreshString, name, StringComparison.OrdinalIgnoreCase))
{
success = TrySetTimeSpan(nameValue, ref cc._minFresh);
}
@@ -467,7 +468,7 @@ namespace Microsoft.Net.Http.Headers
break;
case 12:
- if (string.Equals(NoTransformString, name, StringComparison.OrdinalIgnoreCase))
+ if (StringSegment.Equals(NoTransformString, name, StringComparison.OrdinalIgnoreCase))
{
success = TrySetTokenOnlyValue(nameValue, ref cc._noTransform);
}
@@ -478,7 +479,7 @@ namespace Microsoft.Net.Http.Headers
break;
case 14:
- if (string.Equals(OnlyIfCachedString, name, StringComparison.OrdinalIgnoreCase))
+ if (StringSegment.Equals(OnlyIfCachedString, name, StringComparison.OrdinalIgnoreCase))
{
success = TrySetTokenOnlyValue(nameValue, ref cc._onlyIfCached);
}
@@ -489,7 +490,7 @@ namespace Microsoft.Net.Http.Headers
break;
case 15:
- if (string.Equals(MustRevalidateString, name, StringComparison.OrdinalIgnoreCase))
+ if (StringSegment.Equals(MustRevalidateString, name, StringComparison.OrdinalIgnoreCase))
{
success = TrySetTokenOnlyValue(nameValue, ref cc._mustRevalidate);
}
@@ -500,7 +501,7 @@ namespace Microsoft.Net.Http.Headers
break;
case 16:
- if (string.Equals(ProxyRevalidateString, name, StringComparison.OrdinalIgnoreCase))
+ if (StringSegment.Equals(ProxyRevalidateString, name, StringComparison.OrdinalIgnoreCase))
{
success = TrySetTokenOnlyValue(nameValue, ref cc._proxyRevalidate);
}
@@ -538,7 +539,7 @@ namespace Microsoft.Net.Http.Headers
private static bool TrySetOptionalTokenList(
NameValueHeaderValue nameValue,
ref bool boolField,
- ref ICollection destination)
+ ref ICollection destination)
{
Contract.Requires(nameValue != null);
@@ -582,10 +583,10 @@ namespace Microsoft.Net.Http.Headers
if (destination == null)
{
- destination = new ObjectCollection(CheckIsValidTokenAction);
+ destination = new ObjectCollection(CheckIsValidTokenAction);
}
- destination.Add(valueString.Substring(current, tokenLength));
+ destination.Add(valueString.Subsegment(current, tokenLength));
current = current + tokenLength;
}
@@ -637,10 +638,10 @@ namespace Microsoft.Net.Http.Headers
sb.Append(value);
}
- private static void AppendValues(StringBuilder sb, IEnumerable values)
+ private static void AppendValues(StringBuilder sb, IEnumerable values)
{
var first = true;
- foreach (string value in values)
+ foreach (var value in values)
{
if (first)
{
@@ -655,7 +656,7 @@ namespace Microsoft.Net.Http.Headers
}
}
- private static void CheckIsValidToken(string item)
+ private static void CheckIsValidToken(StringSegment item)
{
HeaderUtilities.CheckValidToken(item, nameof(item));
}
diff --git a/src/Microsoft.Net.Http.Headers/ContentDispositionHeaderValue.cs b/src/Microsoft.Net.Http.Headers/ContentDispositionHeaderValue.cs
index fbae25b6d1..ff9faf066b 100644
--- a/src/Microsoft.Net.Http.Headers/ContentDispositionHeaderValue.cs
+++ b/src/Microsoft.Net.Http.Headers/ContentDispositionHeaderValue.cs
@@ -6,7 +6,9 @@ using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
+using System.Linq;
using System.Text;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -20,26 +22,28 @@ namespace Microsoft.Net.Http.Headers
private const string ModificationDateString = "modification-date";
private const string ReadDateString = "read-date";
private const string SizeString = "size";
+ private static readonly char[] QuestionMark = new char[] { '?' };
+ private static readonly char[] SingleQuote = new char[] { '\'' };
private static readonly HttpHeaderParser Parser
= new GenericHeaderParser(false, GetDispositionTypeLength);
// Use list instead of dictionary since we may have multiple parameters with the same name.
private ObjectCollection _parameters;
- private string _dispositionType;
+ private StringSegment _dispositionType;
private ContentDispositionHeaderValue()
{
// Used by the parser to create a new instance of this type.
}
- public ContentDispositionHeaderValue(string dispositionType)
+ public ContentDispositionHeaderValue(StringSegment dispositionType)
{
CheckDispositionTypeFormat(dispositionType, "dispositionType");
_dispositionType = dispositionType;
}
- public string DispositionType
+ public StringSegment DispositionType
{
get { return _dispositionType; }
set
@@ -63,19 +67,19 @@ namespace Microsoft.Net.Http.Headers
// Helpers to access specific parameters in the list
- public string Name
+ public StringSegment Name
{
get { return GetName(NameString); }
set { SetName(NameString, value); }
}
- public string FileName
+ public StringSegment FileName
{
get { return GetName(FileNameString); }
set { SetName(FileNameString, value); }
}
- public string FileNameStar
+ public StringSegment FileNameStar
{
get { return GetName(FileNameStarString); }
set { SetName(FileNameStarString, value); }
@@ -146,9 +150,9 @@ namespace Microsoft.Net.Http.Headers
/// Sets both FileName and FileNameStar using encodings appropriate for HTTP headers.
///
///
- public void SetHttpFileName(string fileName)
+ public void SetHttpFileName(StringSegment fileName)
{
- if (!string.IsNullOrEmpty(fileName))
+ if (!StringSegment.IsNullOrEmpty(fileName))
{
FileName = Sanatize(fileName);
}
@@ -164,7 +168,7 @@ namespace Microsoft.Net.Http.Headers
/// The FileNameStar paraemter is removed.
///
///
- public void SetMimeFileName(string fileName)
+ public void SetMimeFileName(StringSegment fileName)
{
FileNameStar = null;
FileName = fileName;
@@ -184,42 +188,41 @@ namespace Microsoft.Net.Http.Headers
return false;
}
- return (string.Compare(_dispositionType, other._dispositionType, StringComparison.OrdinalIgnoreCase) == 0) &&
+ return _dispositionType.Equals(other._dispositionType, StringComparison.OrdinalIgnoreCase) &&
HeaderUtilities.AreEqualCollections(_parameters, other._parameters);
}
public override int GetHashCode()
{
// The dispositionType string is case-insensitive.
- return StringComparer.OrdinalIgnoreCase.GetHashCode(_dispositionType) ^ NameValueHeaderValue.GetHashCode(_parameters);
+ return StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_dispositionType) ^ NameValueHeaderValue.GetHashCode(_parameters);
}
- public static ContentDispositionHeaderValue Parse(string input)
+ public static ContentDispositionHeaderValue Parse(StringSegment input)
{
var index = 0;
return Parser.ParseValue(input, ref index);
}
- public static bool TryParse(string input, out ContentDispositionHeaderValue parsedValue)
+ public static bool TryParse(StringSegment input, out ContentDispositionHeaderValue parsedValue)
{
var index = 0;
return Parser.TryParseValue(input, ref index, out parsedValue);
}
- private static int GetDispositionTypeLength(string input, int startIndex, out ContentDispositionHeaderValue parsedValue)
+ private static int GetDispositionTypeLength(StringSegment input, int startIndex, out ContentDispositionHeaderValue parsedValue)
{
Contract.Requires(startIndex >= 0);
parsedValue = null;
- if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
+ if (StringSegment.IsNullOrEmpty(input) || (startIndex >= input.Length))
{
return 0;
}
// Caller must remove leading whitespaces. If not, we'll return 0.
- string dispositionType = null;
- var dispositionTypeLength = GetDispositionTypeExpressionLength(input, startIndex, out dispositionType);
+ var dispositionTypeLength = GetDispositionTypeExpressionLength(input, startIndex, out var dispositionType);
if (dispositionTypeLength == 0)
{
@@ -247,7 +250,7 @@ namespace Microsoft.Net.Http.Headers
return current - startIndex;
}
- private static int GetDispositionTypeExpressionLength(string input, int startIndex, out string dispositionType)
+ private static int GetDispositionTypeExpressionLength(StringSegment input, int startIndex, out StringSegment dispositionType)
{
Contract.Requires((input != null) && (input.Length > 0) && (startIndex < input.Length));
@@ -263,20 +266,19 @@ namespace Microsoft.Net.Http.Headers
return 0;
}
- dispositionType = input.Substring(startIndex, typeLength);
+ dispositionType = input.Subsegment(startIndex, typeLength);
return typeLength;
}
- private static void CheckDispositionTypeFormat(string dispositionType, string parameterName)
+ private static void CheckDispositionTypeFormat(StringSegment dispositionType, string parameterName)
{
- if (string.IsNullOrEmpty(dispositionType))
+ if (StringSegment.IsNullOrEmpty(dispositionType))
{
throw new ArgumentException("An empty string is not allowed.", parameterName);
}
// When adding values using strongly typed objects, no leading/trailing LWS (whitespaces) are allowed.
- string tempDispositionType;
- var dispositionTypeLength = GetDispositionTypeExpressionLength(dispositionType, 0, out tempDispositionType);
+ var dispositionTypeLength = GetDispositionTypeExpressionLength(dispositionType, 0, out var tempDispositionType);
if ((dispositionTypeLength == 0) || (tempDispositionType.Length != dispositionType.Length))
{
throw new FormatException(string.Format(CultureInfo.InvariantCulture,
@@ -291,11 +293,11 @@ namespace Microsoft.Net.Http.Headers
var dateParameter = NameValueHeaderValue.Find(_parameters, parameter);
if (dateParameter != null)
{
- string dateString = dateParameter.Value;
+ var dateString = dateParameter.Value;
// Should have quotes, remove them.
if (IsQuoted(dateString))
{
- dateString = dateString.Substring(1, dateString.Length - 2);
+ dateString = dateString.Subsegment(1, dateString.Length - 2);
}
DateTimeOffset date;
if (HttpRuleParser.TryStringToDate(dateString, out date))
@@ -357,17 +359,17 @@ namespace Microsoft.Net.Http.Headers
return result;
}
// May not have been encoded
- return nameParameter.Value;
+ return nameParameter.Value.ToString();
}
return null;
}
// Add/update the given parameter in the list, encoding if necessary.
// Remove if value is null/Empty
- private void SetName(string parameter, string value)
+ private void SetName(StringSegment parameter, StringSegment value)
{
var nameParameter = NameValueHeaderValue.Find(_parameters, parameter);
- if (string.IsNullOrEmpty(value))
+ if (StringSegment.IsNullOrEmpty(value))
{
// Remove parameter
if (nameParameter != null)
@@ -377,7 +379,7 @@ namespace Microsoft.Net.Http.Headers
}
else
{
- var processedValue = string.Empty;
+ var processedValue = StringSegment.Empty;
if (parameter.EndsWith("*", StringComparison.Ordinal))
{
processedValue = Encode5987(value);
@@ -399,14 +401,14 @@ namespace Microsoft.Net.Http.Headers
}
// Returns input for decoding failures, as the content might not be encoded
- private string EncodeAndQuoteMime(string input)
+ private StringSegment EncodeAndQuoteMime(StringSegment input)
{
var result = input;
var needsQuotes = false;
// Remove bounding quotes, they'll get re-added later
if (IsQuoted(result))
{
- result = result.Substring(1, result.Length - 2);
+ result = result.Subsegment(1, result.Length - 2);
needsQuotes = true;
}
@@ -423,8 +425,7 @@ namespace Microsoft.Net.Http.Headers
if (needsQuotes)
{
// '\' and '"' must be escaped in a quoted string
- result = result.Replace(@"\", @"\\");
- result = result.Replace(@"""", @"\""");
+ result = result.ToString().Replace(@"\", @"\\").Replace(@"""", @"\""");
// Re-add quotes "value"
result = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", result);
}
@@ -432,7 +433,7 @@ namespace Microsoft.Net.Http.Headers
}
// Replaces characters not suitable for HTTP headers with '_' rather than MIME encoding them.
- private string Sanatize(string input)
+ private StringSegment Sanatize(StringSegment input)
{
var result = input;
@@ -455,7 +456,7 @@ namespace Microsoft.Net.Http.Headers
}
// Returns true if the value starts and ends with a quote
- private bool IsQuoted(string value)
+ private bool IsQuoted(StringSegment value)
{
Contract.Assert(value != null);
@@ -464,13 +465,13 @@ namespace Microsoft.Net.Http.Headers
}
// tspecials are required to be in a quoted string. Only non-ascii needs to be encoded.
- private bool RequiresEncoding(string input)
+ private bool RequiresEncoding(StringSegment input)
{
Contract.Assert(input != null);
- foreach (char c in input)
+ for (int i = 0; i < input.Length; i++)
{
- if ((int)c > 0x7f)
+ if ((int)input[i] > 0x7f)
{
return true;
}
@@ -479,15 +480,23 @@ namespace Microsoft.Net.Http.Headers
}
// Encode using MIME encoding
- private string EncodeMime(string input)
+ private unsafe string EncodeMime(StringSegment input)
{
- var buffer = Encoding.UTF8.GetBytes(input);
- var encodedName = Convert.ToBase64String(buffer);
- return string.Format(CultureInfo.InvariantCulture, "=?utf-8?B?{0}?=", encodedName);
+ fixed (char* chars = input.Buffer)
+ {
+ var byteCount = Encoding.UTF8.GetByteCount(chars + input.Offset, input.Length);
+ var buffer = new byte[byteCount];
+ fixed (byte* bytes = buffer)
+ {
+ Encoding.UTF8.GetBytes(chars + input.Offset, input.Length, bytes, byteCount);
+ }
+ var encodedName = Convert.ToBase64String(buffer);
+ return "=?utf-8?B?" + encodedName + "?=";
+ }
}
// Attempt to decode MIME encoded strings
- private bool TryDecodeMime(string input, out string output)
+ private bool TryDecodeMime(StringSegment input, out string output)
{
Contract.Assert(input != null);
@@ -498,9 +507,11 @@ namespace Microsoft.Net.Http.Headers
{
return false;
}
- var parts = processedInput.Split('?');
+
+ var parts = processedInput.Split(QuestionMark).ToArray();
// "=, encodingName, encodingType, encodedData, ="
- if (parts.Length != 5 || parts[0] != "\"=" || parts[4] != "=\"" || parts[2].ToLowerInvariant() != "b")
+ if (parts.Length != 5 || parts[0] != "\"=" || parts[4] != "=\""
+ || !parts[2].Equals("b", StringComparison.OrdinalIgnoreCase))
{
// Not encoded.
// This does not support multi-line encoding.
@@ -510,8 +521,8 @@ namespace Microsoft.Net.Http.Headers
try
{
- var encoding = Encoding.GetEncoding(parts[1]);
- var bytes = Convert.FromBase64String(parts[3]);
+ var encoding = Encoding.GetEncoding(parts[1].ToString());
+ var bytes = Convert.FromBase64String(parts[3].ToString());
output = encoding.GetString(bytes, 0, bytes.Length);
return true;
}
@@ -528,11 +539,12 @@ namespace Microsoft.Net.Http.Headers
// Encode a string using RFC 5987 encoding
// encoding'lang'PercentEncodedSpecials
- private string Encode5987(string input)
+ private string Encode5987(StringSegment input)
{
var builder = new StringBuilder("UTF-8\'\'");
- foreach (char c in input)
+ for (int i = 0; i < input.Length; i++)
{
+ var c = input[i];
// attr-char = ALPHA / DIGIT / "!" / "#" / "$" / "&" / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
// ; token except ( "*" / "'" / "%" )
if (c > 0x7F) // Encodes as multiple utf-8 bytes
@@ -569,10 +581,11 @@ namespace Microsoft.Net.Http.Headers
// Attempt to decode using RFC 5987 encoding.
// encoding'language'my%20string
- private bool TryDecode5987(string input, out string output)
+ private bool TryDecode5987(StringSegment input, out string output)
{
output = null;
- var parts = input.Split('\'');
+
+ var parts = input.Split(SingleQuote).ToArray();
if (parts.Length != 3)
{
return false;
@@ -582,7 +595,7 @@ namespace Microsoft.Net.Http.Headers
byte[] unescapedBytes = null;
try
{
- var encoding = Encoding.GetEncoding(parts[0]);
+ var encoding = Encoding.GetEncoding(parts[0].ToString());
var dataString = parts[2];
unescapedBytes = ArrayPool.Shared.Rent(dataString.Length);
@@ -629,7 +642,7 @@ namespace Microsoft.Net.Http.Headers
return true;
}
- private static bool IsHexEncoding(string pattern, int index)
+ private static bool IsHexEncoding(StringSegment pattern, int index)
{
if ((pattern.Length - index) < 3)
{
@@ -661,7 +674,7 @@ namespace Microsoft.Net.Http.Headers
return true;
}
- private static byte HexUnescape(string pattern, ref int index)
+ private static byte HexUnescape(StringSegment pattern, ref int index)
{
if ((index < 0) || (index >= pattern.Length))
{
diff --git a/src/Microsoft.Net.Http.Headers/ContentDispositionHeaderValueIdentityExtensions.cs b/src/Microsoft.Net.Http.Headers/ContentDispositionHeaderValueIdentityExtensions.cs
index 0a275e55b8..9ef74baa0c 100644
--- a/src/Microsoft.Net.Http.Headers/ContentDispositionHeaderValueIdentityExtensions.cs
+++ b/src/Microsoft.Net.Http.Headers/ContentDispositionHeaderValueIdentityExtensions.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -23,7 +24,7 @@ namespace Microsoft.Net.Http.Headers
}
return header.DispositionType.Equals("form-data")
- && (!string.IsNullOrEmpty(header.FileName) || !string.IsNullOrEmpty(header.FileNameStar));
+ && (!StringSegment.IsNullOrEmpty(header.FileName) || !StringSegment.IsNullOrEmpty(header.FileNameStar));
}
///
@@ -39,7 +40,7 @@ namespace Microsoft.Net.Http.Headers
}
return header.DispositionType.Equals("form-data")
- && string.IsNullOrEmpty(header.FileName) && string.IsNullOrEmpty(header.FileNameStar);
+ && StringSegment.IsNullOrEmpty(header.FileName) && StringSegment.IsNullOrEmpty(header.FileNameStar);
}
}
}
diff --git a/src/Microsoft.Net.Http.Headers/ContentRangeHeaderValue.cs b/src/Microsoft.Net.Http.Headers/ContentRangeHeaderValue.cs
index c187491dfc..99583cdf47 100644
--- a/src/Microsoft.Net.Http.Headers/ContentRangeHeaderValue.cs
+++ b/src/Microsoft.Net.Http.Headers/ContentRangeHeaderValue.cs
@@ -5,6 +5,7 @@ using System;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Text;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -13,7 +14,7 @@ namespace Microsoft.Net.Http.Headers
private static readonly HttpHeaderParser Parser
= new GenericHeaderParser(false, GetContentRangeLength);
- private string _unit;
+ private StringSegment _unit;
private long? _from;
private long? _to;
private long? _length;
@@ -77,7 +78,7 @@ namespace Microsoft.Net.Http.Headers
_unit = HeaderUtilities.BytesUnit;
}
- public string Unit
+ public StringSegment Unit
{
get { return _unit; }
set
@@ -122,12 +123,12 @@ namespace Microsoft.Net.Http.Headers
}
return ((_from == other._from) && (_to == other._to) && (_length == other._length) &&
- (string.Compare(_unit, other._unit, StringComparison.OrdinalIgnoreCase) == 0));
+ StringSegment.Equals(_unit, other._unit, StringComparison.OrdinalIgnoreCase));
}
public override int GetHashCode()
{
- var result = StringComparer.OrdinalIgnoreCase.GetHashCode(_unit);
+ var result = StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_unit);
if (HasRange)
{
@@ -144,7 +145,8 @@ namespace Microsoft.Net.Http.Headers
public override string ToString()
{
- var sb = new StringBuilder(_unit);
+ var sb = new StringBuilder();
+ sb.Append(_unit);
sb.Append(' ');
if (HasRange)
@@ -171,25 +173,25 @@ namespace Microsoft.Net.Http.Headers
return sb.ToString();
}
- public static ContentRangeHeaderValue Parse(string input)
+ public static ContentRangeHeaderValue Parse(StringSegment input)
{
var index = 0;
return Parser.ParseValue(input, ref index);
}
- public static bool TryParse(string input, out ContentRangeHeaderValue parsedValue)
+ public static bool TryParse(StringSegment input, out ContentRangeHeaderValue parsedValue)
{
var index = 0;
return Parser.TryParseValue(input, ref index, out parsedValue);
}
- private static int GetContentRangeLength(string input, int startIndex, out ContentRangeHeaderValue parsedValue)
+ private static int GetContentRangeLength(StringSegment input, int startIndex, out ContentRangeHeaderValue parsedValue)
{
Contract.Requires(startIndex >= 0);
parsedValue = null;
- if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
+ if (StringSegment.IsNullOrEmpty(input) || (startIndex >= input.Length))
{
return 0;
}
@@ -202,7 +204,7 @@ namespace Microsoft.Net.Http.Headers
return 0;
}
- var unit = input.Substring(startIndex, unitLength);
+ var unit = input.Subsegment(startIndex, unitLength);
var current = startIndex + unitLength;
var separatorLength = HttpRuleParser.GetWhitespaceLength(input, current);
@@ -259,7 +261,7 @@ namespace Microsoft.Net.Http.Headers
return current - startIndex;
}
- private static bool TryGetLengthLength(string input, ref int current, out int lengthLength)
+ private static bool TryGetLengthLength(StringSegment input, ref int current, out int lengthLength)
{
lengthLength = 0;
@@ -284,7 +286,7 @@ namespace Microsoft.Net.Http.Headers
return true;
}
- private static bool TryGetRangeLength(string input, ref int current, out int fromLength, out int toStartIndex, out int toLength)
+ private static bool TryGetRangeLength(StringSegment input, ref int current, out int fromLength, out int toStartIndex, out int toLength)
{
fromLength = 0;
toStartIndex = 0;
@@ -341,8 +343,8 @@ namespace Microsoft.Net.Http.Headers
}
private static bool TryCreateContentRange(
- string input,
- string unit,
+ StringSegment input,
+ StringSegment unit,
int fromStartIndex,
int fromLength,
int toStartIndex,
@@ -354,13 +356,13 @@ namespace Microsoft.Net.Http.Headers
parsedValue = null;
long from = 0;
- if ((fromLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Substring(fromStartIndex, fromLength), out from))
+ if ((fromLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Subsegment(fromStartIndex, fromLength), out from))
{
return false;
}
long to = 0;
- if ((toLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Substring(toStartIndex, toLength), out to))
+ if ((toLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Subsegment(toStartIndex, toLength), out to))
{
return false;
}
@@ -372,7 +374,7 @@ namespace Microsoft.Net.Http.Headers
}
long length = 0;
- if ((lengthLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Substring(lengthStartIndex, lengthLength),
+ if ((lengthLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Subsegment(lengthStartIndex, lengthLength),
out length))
{
return false;
diff --git a/src/Microsoft.Net.Http.Headers/CookieHeaderParser.cs b/src/Microsoft.Net.Http.Headers/CookieHeaderParser.cs
index 9253e881e5..a94b61d319 100644
--- a/src/Microsoft.Net.Http.Headers/CookieHeaderParser.cs
+++ b/src/Microsoft.Net.Http.Headers/CookieHeaderParser.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics.Contracts;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -12,7 +13,7 @@ namespace Microsoft.Net.Http.Headers
{
}
- public sealed override bool TryParseValue(string value, ref int index, out CookieHeaderValue parsedValue)
+ public sealed override bool TryParseValue(StringSegment value, ref int index, out CookieHeaderValue parsedValue)
{
parsedValue = null;
@@ -21,7 +22,7 @@ namespace Microsoft.Net.Http.Headers
// Accept: text/xml; q=1
// Accept:
// Accept: text/plain; q=0.2
- if (string.IsNullOrEmpty(value) || (index == value.Length))
+ if (StringSegment.IsNullOrEmpty(value) || (index == value.Length))
{
return SupportsMultipleValues;
}
@@ -62,7 +63,7 @@ namespace Microsoft.Net.Http.Headers
return true;
}
- private static int GetNextNonEmptyOrWhitespaceIndex(string input, int startIndex, bool skipEmptyValues, out bool separatorFound)
+ private static int GetNextNonEmptyOrWhitespaceIndex(StringSegment input, int startIndex, bool skipEmptyValues, out bool separatorFound)
{
Contract.Requires(input != null);
Contract.Requires(startIndex <= input.Length); // it's OK if index == value.Length.
diff --git a/src/Microsoft.Net.Http.Headers/CookieHeaderValue.cs b/src/Microsoft.Net.Http.Headers/CookieHeaderValue.cs
index 77adcf5441..3061b7d2fa 100644
--- a/src/Microsoft.Net.Http.Headers/CookieHeaderValue.cs
+++ b/src/Microsoft.Net.Http.Headers/CookieHeaderValue.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Text;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -14,16 +15,16 @@ namespace Microsoft.Net.Http.Headers
private static readonly CookieHeaderParser SingleValueParser = new CookieHeaderParser(supportsMultipleValues: false);
private static readonly CookieHeaderParser MultipleValueParser = new CookieHeaderParser(supportsMultipleValues: true);
- private string _name;
- private string _value;
+ private StringSegment _name;
+ private StringSegment _value;
private CookieHeaderValue()
{
// Used by the parser to create a new instance of this type.
}
- public CookieHeaderValue(string name)
- : this(name, string.Empty)
+ public CookieHeaderValue(StringSegment name)
+ : this(name, StringSegment.Empty)
{
if (name == null)
{
@@ -31,7 +32,7 @@ namespace Microsoft.Net.Http.Headers
}
}
- public CookieHeaderValue(string name, string value)
+ public CookieHeaderValue(StringSegment name, StringSegment value)
{
if (name == null)
{
@@ -47,7 +48,7 @@ namespace Microsoft.Net.Http.Headers
Value = value;
}
- public string Name
+ public StringSegment Name
{
get { return _name; }
set
@@ -57,7 +58,7 @@ namespace Microsoft.Net.Http.Headers
}
}
- public string Value
+ public StringSegment Value
{
get { return _value; }
set
@@ -79,24 +80,13 @@ namespace Microsoft.Net.Http.Headers
return header.ToString();
}
- private static void AppendSegment(StringBuilder builder, string name, string value)
- {
- builder.Append("; ");
- builder.Append(name);
- if (value != null)
- {
- builder.Append("=");
- builder.Append(value);
- }
- }
-
- public static CookieHeaderValue Parse(string input)
+ public static CookieHeaderValue Parse(StringSegment input)
{
var index = 0;
return SingleValueParser.ParseValue(input, ref index);
}
- public static bool TryParse(string input, out CookieHeaderValue parsedValue)
+ public static bool TryParse(StringSegment input, out CookieHeaderValue parsedValue)
{
var index = 0;
return SingleValueParser.TryParseValue(input, ref index, out parsedValue);
@@ -123,13 +113,13 @@ namespace Microsoft.Net.Http.Headers
}
// name=value; name="value"
- internal static bool TryGetCookieLength(string input, ref int offset, out CookieHeaderValue parsedValue)
+ internal static bool TryGetCookieLength(StringSegment input, ref int offset, out CookieHeaderValue parsedValue)
{
Contract.Requires(offset >= 0);
parsedValue = null;
- if (string.IsNullOrEmpty(input) || (offset >= input.Length))
+ if (StringSegment.IsNullOrEmpty(input) || (offset >= input.Length))
{
return false;
}
@@ -146,7 +136,7 @@ namespace Microsoft.Net.Http.Headers
{
return false;
}
- result._name = input.Substring(offset, itemLength);
+ result._name = input.Subsegment(offset, itemLength);
offset += itemLength;
// = (no spaces)
@@ -166,7 +156,7 @@ namespace Microsoft.Net.Http.Headers
// cookie-value = *cookie-octet / ( DQUOTE* cookie-octet DQUOTE )
// cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
// ; US-ASCII characters excluding CTLs, whitespace DQUOTE, comma, semicolon, and backslash
- internal static string GetCookieValue(string input, ref int offset)
+ internal static StringSegment GetCookieValue(StringSegment input, ref int offset)
{
Contract.Requires(input != null);
Contract.Requires(offset >= 0);
@@ -176,7 +166,7 @@ namespace Microsoft.Net.Http.Headers
if (offset >= input.Length)
{
- return string.Empty;
+ return StringSegment.Empty;
}
var inQuotes = false;
@@ -202,7 +192,7 @@ namespace Microsoft.Net.Http.Headers
if (offset == input.Length || input[offset] != '"')
{
// Missing final quote
- return string.Empty;
+ return StringSegment.Empty;
}
offset++;
}
@@ -210,13 +200,13 @@ namespace Microsoft.Net.Http.Headers
int length = offset - startIndex;
if (offset > startIndex)
{
- return input.Substring(startIndex, length);
+ return input.Subsegment(startIndex, length);
}
- return string.Empty;
+ return StringSegment.Empty;
}
- private static bool ReadEqualsSign(string input, ref int offset)
+ private static bool ReadEqualsSign(StringSegment input, ref int offset)
{
// = (no spaces)
if (offset >= input.Length || input[offset] != '=')
@@ -238,7 +228,7 @@ namespace Microsoft.Net.Http.Headers
return !(c == '"' || c == ',' || c == ';' || c == '\\');
}
- internal static void CheckNameFormat(string name, string parameterName)
+ internal static void CheckNameFormat(StringSegment name, string parameterName)
{
if (name == null)
{
@@ -251,7 +241,7 @@ namespace Microsoft.Net.Http.Headers
}
}
- internal static void CheckValueFormat(string value, string parameterName)
+ internal static void CheckValueFormat(StringSegment value, string parameterName)
{
if (value == null)
{
@@ -275,8 +265,8 @@ namespace Microsoft.Net.Http.Headers
return false;
}
- return string.Equals(_name, other._name, StringComparison.OrdinalIgnoreCase)
- && string.Equals(_value, other._value, StringComparison.OrdinalIgnoreCase);
+ return StringSegment.Equals(_name, other._name, StringComparison.OrdinalIgnoreCase)
+ && StringSegment.Equals(_value, other._value, StringComparison.OrdinalIgnoreCase);
}
public override int GetHashCode()
diff --git a/src/Microsoft.Net.Http.Headers/EntityTagHeaderValue.cs b/src/Microsoft.Net.Http.Headers/EntityTagHeaderValue.cs
index 7d09920c77..e46cee3a34 100644
--- a/src/Microsoft.Net.Http.Headers/EntityTagHeaderValue.cs
+++ b/src/Microsoft.Net.Http.Headers/EntityTagHeaderValue.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -22,7 +23,7 @@ namespace Microsoft.Net.Http.Headers
private static EntityTagHeaderValue AnyType;
- private string _tag;
+ private StringSegment _tag;
private bool _isWeak;
private EntityTagHeaderValue()
@@ -30,20 +31,20 @@ namespace Microsoft.Net.Http.Headers
// Used by the parser to create a new instance of this type.
}
- public EntityTagHeaderValue(string tag)
+ public EntityTagHeaderValue(StringSegment tag)
: this(tag, false)
{
}
- public EntityTagHeaderValue(string tag, bool isWeak)
+ public EntityTagHeaderValue(StringSegment tag, bool isWeak)
{
- if (string.IsNullOrEmpty(tag))
+ if (StringSegment.IsNullOrEmpty(tag))
{
throw new ArgumentException("An empty string is not allowed.", nameof(tag));
}
int length = 0;
- if (!isWeak && string.Equals(tag, "*", StringComparison.Ordinal))
+ if (!isWeak && StringSegment.Equals(tag, "*", StringComparison.Ordinal))
{
// * is valid, but W/* isn't.
_tag = tag;
@@ -74,7 +75,7 @@ namespace Microsoft.Net.Http.Headers
}
}
- public string Tag
+ public StringSegment Tag
{
get { return _tag; }
}
@@ -88,9 +89,9 @@ namespace Microsoft.Net.Http.Headers
{
if (_isWeak)
{
- return "W/" + _tag;
+ return "W/" + _tag.ToString();
}
- return _tag;
+ return _tag.ToString();
}
///
@@ -112,7 +113,7 @@ namespace Microsoft.Net.Http.Headers
}
// Since the tag is a quoted-string we treat it case-sensitive.
- return _isWeak == other._isWeak && string.Equals(_tag, other._tag, StringComparison.Ordinal);
+ return _isWeak == other._isWeak && StringSegment.Equals(_tag, other._tag, StringComparison.Ordinal);
}
public override int GetHashCode()
@@ -139,21 +140,21 @@ namespace Microsoft.Net.Http.Headers
if (useStrongComparison)
{
- return !IsWeak && !other.IsWeak && string.Equals(Tag, other.Tag, StringComparison.Ordinal);
+ return !IsWeak && !other.IsWeak && StringSegment.Equals(Tag, other.Tag, StringComparison.Ordinal);
}
else
{
- return string.Equals(Tag, other.Tag, StringComparison.Ordinal);
+ return StringSegment.Equals(Tag, other.Tag, StringComparison.Ordinal);
}
}
- public static EntityTagHeaderValue Parse(string input)
+ public static EntityTagHeaderValue Parse(StringSegment input)
{
var index = 0;
return SingleValueParser.ParseValue(input, ref index);
}
- public static bool TryParse(string input, out EntityTagHeaderValue parsedValue)
+ public static bool TryParse(StringSegment input, out EntityTagHeaderValue parsedValue)
{
var index = 0;
return SingleValueParser.TryParseValue(input, ref index, out parsedValue);
@@ -179,13 +180,13 @@ namespace Microsoft.Net.Http.Headers
return MultipleValueParser.TryParseStrictValues(inputs, out parsedValues);
}
- internal static int GetEntityTagLength(string input, int startIndex, out EntityTagHeaderValue parsedValue)
+ internal static int GetEntityTagLength(StringSegment input, int startIndex, out EntityTagHeaderValue parsedValue)
{
Contract.Requires(startIndex >= 0);
parsedValue = null;
- if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
+ if (StringSegment.IsNullOrEmpty(input) || (startIndex >= input.Length))
{
return 0;
}
@@ -235,7 +236,7 @@ namespace Microsoft.Net.Http.Headers
}
else
{
- parsedValue._tag = input.Substring(tagStartIndex, tagLength);
+ parsedValue._tag = input.Subsegment(tagStartIndex, tagLength);
parsedValue._isWeak = isWeak;
}
diff --git a/src/Microsoft.Net.Http.Headers/GenericHeaderParser.cs b/src/Microsoft.Net.Http.Headers/GenericHeaderParser.cs
index 63f9b8aed0..a2fbf720f9 100644
--- a/src/Microsoft.Net.Http.Headers/GenericHeaderParser.cs
+++ b/src/Microsoft.Net.Http.Headers/GenericHeaderParser.cs
@@ -2,12 +2,13 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
internal sealed class GenericHeaderParser : BaseHeaderParser
{
- internal delegate int GetParsedValueLengthDelegate(string value, int startIndex, out T parsedValue);
+ internal delegate int GetParsedValueLengthDelegate(StringSegment value, int startIndex, out T parsedValue);
private GetParsedValueLengthDelegate _getParsedValueLength;
@@ -22,7 +23,7 @@ namespace Microsoft.Net.Http.Headers
_getParsedValueLength = getParsedValueLength;
}
- protected override int GetParsedValueLength(string value, int startIndex, out T parsedValue)
+ protected override int GetParsedValueLength(StringSegment value, int startIndex, out T parsedValue)
{
return _getParsedValueLength(value, startIndex, out parsedValue);
}
diff --git a/src/Microsoft.Net.Http.Headers/HeaderUtilities.cs b/src/Microsoft.Net.Http.Headers/HeaderUtilities.cs
index 9f49ba742c..abcf102076 100644
--- a/src/Microsoft.Net.Http.Headers/HeaderUtilities.cs
+++ b/src/Microsoft.Net.Http.Headers/HeaderUtilities.cs
@@ -72,9 +72,9 @@ namespace Microsoft.Net.Http.Headers
return null;
}
- internal static void CheckValidToken(string value, string parameterName)
+ internal static void CheckValidToken(StringSegment value, string parameterName)
{
- if (string.IsNullOrEmpty(value))
+ if (StringSegment.IsNullOrEmpty(value))
{
throw new ArgumentException("An empty string is not allowed.", parameterName);
}
@@ -85,21 +85,6 @@ namespace Microsoft.Net.Http.Headers
}
}
- internal static void CheckValidQuotedString(string value, string parameterName)
- {
- if (string.IsNullOrEmpty(value))
- {
- throw new ArgumentException("An empty string is not allowed.", parameterName);
- }
-
- int length;
- if ((HttpRuleParser.GetQuotedStringLength(value, 0, out length) != HttpParseResult.Parsed) ||
- (length != value.Length)) // no trailing spaces allowed
- {
- throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Invalid quoted string '{0}'.", value));
- }
- }
-
internal static bool AreEqualCollections(ICollection x, ICollection y)
{
return AreEqualCollections(x, y, null);
@@ -167,7 +152,7 @@ namespace Microsoft.Net.Http.Headers
}
internal static int GetNextNonEmptyOrWhitespaceIndex(
- string input,
+ StringSegment input,
int startIndex,
bool skipEmptyValues,
out bool separatorFound)
@@ -368,11 +353,6 @@ namespace Microsoft.Net.Http.Headers
return false;
}
- internal static bool TryParseNonNegativeInt32(string value, out int result)
- {
- return TryParseNonNegativeInt32(new StringSegment(value), out result);
- }
-
///
/// Try to convert a string representation of a positive number to its 64-bit signed integer equivalent.
/// A return value indicates whether the conversion succeeded or failed.
@@ -388,12 +368,7 @@ namespace Microsoft.Net.Http.Headers
/// result will be overwritten.
///
/// true if parsing succeeded; otherwise, false.
- public static bool TryParseNonNegativeInt64(string value, out long result)
- {
- return TryParseNonNegativeInt64(new StringSegment(value), out result);
- }
-
- internal static unsafe bool TryParseNonNegativeInt32(StringSegment value, out int result)
+ public static unsafe bool TryParseNonNegativeInt32(StringSegment value, out int result)
{
if (string.IsNullOrEmpty(value.Buffer) || value.Length == 0)
{
@@ -483,7 +458,7 @@ namespace Microsoft.Net.Http.Headers
// Strict and fast RFC7231 5.3.1 Quality value parser (and without memory allocation)
// See https://tools.ietf.org/html/rfc7231#section-5.3.1
// Check is made to verify if the value is between 0 and 1 (and it returns False if the check fails).
- internal static bool TryParseQualityDouble(string input, int startIndex, out double quality, out int length)
+ internal static bool TryParseQualityDouble(StringSegment input, int startIndex, out double quality, out int length)
{
quality = 0;
length = 0;
@@ -602,7 +577,7 @@ namespace Microsoft.Net.Http.Headers
return new string(charBuffer, position, _int64MaxStringLength - position);
}
- public static bool TryParseDate(string input, out DateTimeOffset result)
+ public static bool TryParseDate(StringSegment input, out DateTimeOffset result)
{
return HttpRuleParser.TryStringToDate(input, out result);
}
@@ -617,11 +592,11 @@ namespace Microsoft.Net.Http.Headers
return dateTime.ToRfc1123String(quoted);
}
- public static string RemoveQuotes(string input)
+ public static StringSegment RemoveQuotes(StringSegment input)
{
- if (!string.IsNullOrEmpty(input) && input.Length >= 2 && input[0] == '"' && input[input.Length - 1] == '"')
+ if (!StringSegment.IsNullOrEmpty(input) && input.Length >= 2 && input[0] == '"' && input[input.Length - 1] == '"')
{
- input = input.Substring(1, input.Length - 2);
+ input = input.Subsegment(1, input.Length - 2);
}
return input;
}
diff --git a/src/Microsoft.Net.Http.Headers/HttpHeaderParser.cs b/src/Microsoft.Net.Http.Headers/HttpHeaderParser.cs
index 383a304dcf..027a9de438 100644
--- a/src/Microsoft.Net.Http.Headers/HttpHeaderParser.cs
+++ b/src/Microsoft.Net.Http.Headers/HttpHeaderParser.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -26,9 +27,9 @@ namespace Microsoft.Net.Http.Headers
// pointing to the next non-whitespace character after a delimiter. E.g. if called with a start index of 0
// for string "value , second_value", then after the call completes, 'index' must point to 's', i.e. the first
// non-whitespace after the separator ','.
- public abstract bool TryParseValue(string value, ref int index, out T parsedValue);
+ public abstract bool TryParseValue(StringSegment value, ref int index, out T parsedValue);
- public T ParseValue(string value, ref int index)
+ public T ParseValue(StringSegment value, ref int index)
{
// Index may be value.Length (e.g. both 0). This may be allowed for some headers (e.g. Accept but not
// allowed by others (e.g. Content-Length). The parser has to decide if this is valid or not.
@@ -40,7 +41,7 @@ namespace Microsoft.Net.Http.Headers
if (!TryParseValue(value, ref index, out result))
{
throw new FormatException(string.Format(CultureInfo.InvariantCulture,
- "The header contains invalid values at index {0}: '{1}'", index, value ?? ""));
+ "The header contains invalid values at index {0}: '{1}'", index, value.Value ?? ""));
}
return result;
}
diff --git a/src/Microsoft.Net.Http.Headers/HttpRuleParser.cs b/src/Microsoft.Net.Http.Headers/HttpRuleParser.cs
index 0ce5833600..5a6adf9415 100644
--- a/src/Microsoft.Net.Http.Headers/HttpRuleParser.cs
+++ b/src/Microsoft.Net.Http.Headers/HttpRuleParser.cs
@@ -5,6 +5,7 @@ using System;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Text;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -89,7 +90,7 @@ namespace Microsoft.Net.Http.Headers
}
[Pure]
- internal static int GetTokenLength(string input, int startIndex)
+ internal static int GetTokenLength(StringSegment input, int startIndex)
{
Contract.Requires(input != null);
Contract.Ensures((Contract.Result() >= 0) && (Contract.Result() <= (input.Length - startIndex)));
@@ -112,7 +113,7 @@ namespace Microsoft.Net.Http.Headers
return input.Length - startIndex;
}
- internal static int GetWhitespaceLength(string input, int startIndex)
+ internal static int GetWhitespaceLength(StringSegment input, int startIndex)
{
Contract.Requires(input != null);
Contract.Ensures((Contract.Result() >= 0) && (Contract.Result() <= (input.Length - startIndex)));
@@ -156,7 +157,7 @@ namespace Microsoft.Net.Http.Headers
return input.Length - startIndex;
}
- internal static int GetNumberLength(string input, int startIndex, bool allowDecimal)
+ internal static int GetNumberLength(StringSegment input, int startIndex, bool allowDecimal)
{
Contract.Requires(input != null);
Contract.Requires((startIndex >= 0) && (startIndex < input.Length));
@@ -201,7 +202,7 @@ namespace Microsoft.Net.Http.Headers
return current - startIndex;
}
- internal static HttpParseResult GetQuotedStringLength(string input, int startIndex, out int length)
+ internal static HttpParseResult GetQuotedStringLength(StringSegment input, int startIndex, out int length)
{
var nestedCount = 0;
return GetExpressionLength(input, startIndex, '"', '"', false, ref nestedCount, out length);
@@ -209,7 +210,7 @@ namespace Microsoft.Net.Http.Headers
// quoted-pair = "\" CHAR
// CHAR =
- internal static HttpParseResult GetQuotedPairLength(string input, int startIndex, out int length)
+ internal static HttpParseResult GetQuotedPairLength(StringSegment input, int startIndex, out int length)
{
Contract.Requires(input != null);
Contract.Requires((startIndex >= 0) && (startIndex < input.Length));
@@ -237,8 +238,8 @@ namespace Microsoft.Net.Http.Headers
// Try the various date formats in the order listed above.
// We should accept a wide verity of common formats, but only output RFC 1123 style dates.
- internal static bool TryStringToDate(string input, out DateTimeOffset result) =>
- DateTimeOffset.TryParseExact(input, DateFormats, DateTimeFormatInfo.InvariantInfo,
+ internal static bool TryStringToDate(StringSegment input, out DateTimeOffset result) =>
+ DateTimeOffset.TryParseExact(input.ToString(), DateFormats, DateTimeFormatInfo.InvariantInfo,
DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeUniversal, out result);
// TEXT =
@@ -253,7 +254,7 @@ namespace Microsoft.Net.Http.Headers
// comments, resulting in a stack overflow exception. In addition having more than 1 nested comment (if any)
// is unusual.
private static HttpParseResult GetExpressionLength(
- string input,
+ StringSegment input,
int startIndex,
char openChar,
char closeChar,
diff --git a/src/Microsoft.Net.Http.Headers/MediaTypeHeaderValue.cs b/src/Microsoft.Net.Http.Headers/MediaTypeHeaderValue.cs
index 0ec7666402..bfda2aac81 100644
--- a/src/Microsoft.Net.Http.Headers/MediaTypeHeaderValue.cs
+++ b/src/Microsoft.Net.Http.Headers/MediaTypeHeaderValue.cs
@@ -7,6 +7,7 @@ using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using System.Text;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -22,7 +23,7 @@ namespace Microsoft.Net.Http.Headers
// Use a collection instead of a dictionary since we may have multiple parameters with the same name.
private ObjectCollection _parameters;
- private string _mediaType;
+ private StringSegment _mediaType;
private bool _isReadOnly;
private MediaTypeHeaderValue()
@@ -30,23 +31,23 @@ namespace Microsoft.Net.Http.Headers
// Used by the parser to create a new instance of this type.
}
- public MediaTypeHeaderValue(string mediaType)
+ public MediaTypeHeaderValue(StringSegment mediaType)
{
CheckMediaTypeFormat(mediaType, "mediaType");
_mediaType = mediaType;
}
- public MediaTypeHeaderValue(string mediaType, double quality)
+ public MediaTypeHeaderValue(StringSegment mediaType, double quality)
: this(mediaType)
{
Quality = quality;
}
- public string Charset
+ public StringSegment Charset
{
get
{
- return NameValueHeaderValue.Find(_parameters, CharsetString)?.Value;
+ return NameValueHeaderValue.Find(_parameters, CharsetString)?.Value.Value;
}
set
{
@@ -54,7 +55,7 @@ namespace Microsoft.Net.Http.Headers
// We don't prevent a user from setting whitespace-only charsets. Like we can't prevent a user from
// setting a non-existing charset.
var charsetParameter = NameValueHeaderValue.Find(_parameters, CharsetString);
- if (string.IsNullOrEmpty(value))
+ if (StringSegment.IsNullOrEmpty(value))
{
// Remove charset parameter
if (charsetParameter != null)
@@ -81,11 +82,11 @@ namespace Microsoft.Net.Http.Headers
get
{
var charset = Charset;
- if (!string.IsNullOrWhiteSpace(charset))
+ if (!StringSegment.IsNullOrEmpty(charset))
{
try
{
- return Encoding.GetEncoding(charset);
+ return Encoding.GetEncoding(charset.Value);
}
catch (ArgumentException)
{
@@ -108,17 +109,17 @@ namespace Microsoft.Net.Http.Headers
}
}
- public string Boundary
+ public StringSegment Boundary
{
get
{
- return NameValueHeaderValue.Find(_parameters, BoundaryString)?.Value;
+ return NameValueHeaderValue.Find(_parameters, BoundaryString)?.Value ?? default(StringSegment);
}
set
{
HeaderUtilities.ThrowIfReadOnly(IsReadOnly);
var boundaryParameter = NameValueHeaderValue.Find(_parameters, BoundaryString);
- if (string.IsNullOrEmpty(value))
+ if (StringSegment.IsNullOrEmpty(value))
{
// Remove charset parameter
if (boundaryParameter != null)
@@ -169,7 +170,7 @@ namespace Microsoft.Net.Http.Headers
}
}
- public string MediaType
+ public StringSegment MediaType
{
get { return _mediaType; }
set
@@ -180,19 +181,19 @@ namespace Microsoft.Net.Http.Headers
}
}
- public string Type
+ public StringSegment Type
{
get
{
- return _mediaType.Substring(0, _mediaType.IndexOf('/'));
+ return _mediaType.Subsegment(0, _mediaType.IndexOf('/'));
}
}
- public string SubType
+ public StringSegment SubType
{
get
{
- return _mediaType.Substring(_mediaType.IndexOf('/') + 1);
+ return _mediaType.Subsegment(_mediaType.IndexOf('/') + 1);
}
}
@@ -214,7 +215,7 @@ namespace Microsoft.Net.Http.Headers
{
get
{
- return string.Compare(_mediaType, _mediaType.IndexOf('/') + 1, "*", 0, 1, StringComparison.Ordinal) == 0;
+ return SubType.Equals("*", StringComparison.Ordinal);
}
}
@@ -245,31 +246,15 @@ namespace Microsoft.Net.Http.Headers
return false;
}
- // PERF: Avoid doing anything here that allocates a substring, this is a very hot path
- // for content-negotiation.
- var indexOfSlash = _mediaType.IndexOf('/');
-
// "text/plain" is a subset of "text/plain", "text/*" and "*/*". "*/*" is a subset only of "*/*".
- if (string.Compare(
- strA: _mediaType,
- indexA: 0,
- strB: otherMediaType._mediaType,
- indexB: 0,
- length: indexOfSlash,
- comparisonType: StringComparison.OrdinalIgnoreCase) != 0)
+ if (!Type.Equals(otherMediaType.Type, comparisonType: StringComparison.OrdinalIgnoreCase))
{
if (!otherMediaType.MatchesAllTypes)
{
return false;
}
}
- else if (string.Compare(
- strA: MediaType,
- indexA: indexOfSlash + 1,
- strB: otherMediaType._mediaType,
- indexB: indexOfSlash + 1, // We know the Type is equal, so the index of '/' is the same in both strings.
- length: _mediaType.Length - indexOfSlash,
- comparisonType: StringComparison.OrdinalIgnoreCase) != 0)
+ else if (!SubType.Equals(otherMediaType.SubType, comparisonType: StringComparison.OrdinalIgnoreCase))
{
if (!otherMediaType.MatchesAllSubTypes)
{
@@ -285,7 +270,7 @@ namespace Microsoft.Net.Http.Headers
// parameters locally; they make this one more specific.
foreach (var parameter in otherMediaType._parameters)
{
- if (string.Equals(parameter.Name, "q", StringComparison.OrdinalIgnoreCase))
+ if (parameter.Name.Equals("q", StringComparison.OrdinalIgnoreCase))
{
// "q" and later parameters are not involved in media type matching. Quoting the RFC: The first
// "q" parameter (if any) separates the media-range parameter(s) from the accept-params.
@@ -299,7 +284,7 @@ namespace Microsoft.Net.Http.Headers
return false;
}
- if (!string.Equals(parameter.Value, localParameter.Value, StringComparison.OrdinalIgnoreCase))
+ if (!StringSegment.Equals(parameter.Value, localParameter.Value, StringComparison.OrdinalIgnoreCase))
{
return false;
}
@@ -352,7 +337,10 @@ namespace Microsoft.Net.Http.Headers
public override string ToString()
{
- return _mediaType + NameValueHeaderValue.ToString(_parameters, ';', true);
+ var builder = new StringBuilder();
+ builder.Append(_mediaType);
+ NameValueHeaderValue.ToString(_parameters, separator: ';', leadingSeparator: true, destination: builder);
+ return builder.ToString();
}
public override bool Equals(object obj)
@@ -364,23 +352,23 @@ namespace Microsoft.Net.Http.Headers
return false;
}
- return (string.Compare(_mediaType, other._mediaType, StringComparison.OrdinalIgnoreCase) == 0) &&
+ return _mediaType.Equals(other._mediaType, StringComparison.OrdinalIgnoreCase) &&
HeaderUtilities.AreEqualCollections(_parameters, other._parameters);
}
public override int GetHashCode()
{
// The media-type string is case-insensitive.
- return StringComparer.OrdinalIgnoreCase.GetHashCode(_mediaType) ^ NameValueHeaderValue.GetHashCode(_parameters);
+ return StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_mediaType) ^ NameValueHeaderValue.GetHashCode(_parameters);
}
- public static MediaTypeHeaderValue Parse(string input)
+ public static MediaTypeHeaderValue Parse(StringSegment input)
{
var index = 0;
return SingleValueParser.ParseValue(input, ref index);
}
- public static bool TryParse(string input, out MediaTypeHeaderValue parsedValue)
+ public static bool TryParse(StringSegment input, out MediaTypeHeaderValue parsedValue)
{
var index = 0;
return SingleValueParser.TryParseValue(input, ref index, out parsedValue);
@@ -406,20 +394,19 @@ namespace Microsoft.Net.Http.Headers
return MultipleValueParser.TryParseStrictValues(inputs, out parsedValues);
}
- private static int GetMediaTypeLength(string input, int startIndex, out MediaTypeHeaderValue parsedValue)
+ private static int GetMediaTypeLength(StringSegment input, int startIndex, out MediaTypeHeaderValue parsedValue)
{
Contract.Requires(startIndex >= 0);
parsedValue = null;
- if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
+ if (StringSegment.IsNullOrEmpty(input) || (startIndex >= input.Length))
{
return 0;
}
// Caller must remove leading whitespace. If not, we'll return 0.
- string mediaType = null;
- var mediaTypeLength = MediaTypeHeaderValue.GetMediaTypeExpressionLength(input, startIndex, out mediaType);
+ var mediaTypeLength = MediaTypeHeaderValue.GetMediaTypeExpressionLength(input, startIndex, out var mediaType);
if (mediaTypeLength == 0)
{
@@ -451,7 +438,7 @@ namespace Microsoft.Net.Http.Headers
return current - startIndex;
}
- private static int GetMediaTypeExpressionLength(string input, int startIndex, out string mediaType)
+ private static int GetMediaTypeExpressionLength(StringSegment input, int startIndex, out StringSegment mediaType)
{
Contract.Requires((input != null) && (input.Length > 0) && (startIndex < input.Length));
@@ -490,7 +477,7 @@ namespace Microsoft.Net.Http.Headers
var mediaTypeLength = current + subtypeLength - startIndex;
if (typeLength + subtypeLength + 1 == mediaTypeLength)
{
- mediaType = input.Substring(startIndex, mediaTypeLength);
+ mediaType = input.Subsegment(startIndex, mediaTypeLength);
}
else
{
@@ -500,17 +487,16 @@ namespace Microsoft.Net.Http.Headers
return mediaTypeLength;
}
- private static void CheckMediaTypeFormat(string mediaType, string parameterName)
+ private static void CheckMediaTypeFormat(StringSegment mediaType, string parameterName)
{
- if (string.IsNullOrEmpty(mediaType))
+ if (StringSegment.IsNullOrEmpty(mediaType))
{
throw new ArgumentException("An empty string is not allowed.", parameterName);
}
// When adding values using strongly typed objects, no leading/trailing LWS (whitespace) is allowed.
// Also no LWS between type and subtype is allowed.
- string tempMediaType;
- var mediaTypeLength = GetMediaTypeExpressionLength(mediaType, 0, out tempMediaType);
+ var mediaTypeLength = GetMediaTypeExpressionLength(mediaType, 0, out var tempMediaType);
if ((mediaTypeLength == 0) || (tempMediaType.Length != mediaType.Length))
{
throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Invalid media type '{0}'.", mediaType));
diff --git a/src/Microsoft.Net.Http.Headers/NameValueHeaderValue.cs b/src/Microsoft.Net.Http.Headers/NameValueHeaderValue.cs
index a04b8d7164..76b48e0093 100644
--- a/src/Microsoft.Net.Http.Headers/NameValueHeaderValue.cs
+++ b/src/Microsoft.Net.Http.Headers/NameValueHeaderValue.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Text;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -18,8 +19,8 @@ namespace Microsoft.Net.Http.Headers
internal static readonly HttpHeaderParser MultipleValueParser
= new GenericHeaderParser(true, GetNameValueLength);
- private string _name;
- private string _value;
+ private StringSegment _name;
+ private StringSegment _value;
private bool _isReadOnly;
private NameValueHeaderValue()
@@ -27,12 +28,12 @@ namespace Microsoft.Net.Http.Headers
// Used by the parser to create a new instance of this type.
}
- public NameValueHeaderValue(string name)
+ public NameValueHeaderValue(StringSegment name)
: this(name, null)
{
}
- public NameValueHeaderValue(string name, string value)
+ public NameValueHeaderValue(StringSegment name, StringSegment value)
{
CheckNameValueFormat(name, value);
@@ -40,12 +41,12 @@ namespace Microsoft.Net.Http.Headers
_value = value;
}
- public string Name
+ public StringSegment Name
{
get { return _name; }
}
- public string Value
+ public StringSegment Value
{
get { return _value; }
set
@@ -90,9 +91,9 @@ namespace Microsoft.Net.Http.Headers
{
Contract.Assert(_name != null);
- var nameHashCode = StringComparer.OrdinalIgnoreCase.GetHashCode(_name);
+ var nameHashCode = StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_name);
- if (!string.IsNullOrEmpty(_value))
+ if (!StringSegment.IsNullOrEmpty(_value))
{
// If we have a quoted-string, then just use the hash code. If we have a token, convert to lowercase
// and retrieve the hash code.
@@ -101,7 +102,7 @@ namespace Microsoft.Net.Http.Headers
return nameHashCode ^ _value.GetHashCode();
}
- return nameHashCode ^ StringComparer.OrdinalIgnoreCase.GetHashCode(_value);
+ return nameHashCode ^ StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_value);
}
return nameHashCode;
@@ -116,7 +117,7 @@ namespace Microsoft.Net.Http.Headers
return false;
}
- if (string.Compare(_name, other._name, StringComparison.OrdinalIgnoreCase) != 0)
+ if (!_name.Equals(other._name, StringComparison.OrdinalIgnoreCase))
{
return false;
}
@@ -125,29 +126,29 @@ namespace Microsoft.Net.Http.Headers
// case-sensitive comparison. The RFC doesn't mention how to compare quoted-strings outside the "Expect"
// header. We treat all quoted-strings the same: case-sensitive comparison.
- if (string.IsNullOrEmpty(_value))
+ if (StringSegment.IsNullOrEmpty(_value))
{
- return string.IsNullOrEmpty(other._value);
+ return StringSegment.IsNullOrEmpty(other._value);
}
if (_value[0] == '"')
{
// We have a quoted string, so we need to do case-sensitive comparison.
- return (string.CompareOrdinal(_value, other._value) == 0);
+ return (_value.Equals(other._value, StringComparison.Ordinal));
}
else
{
- return (string.Compare(_value, other._value, StringComparison.OrdinalIgnoreCase) == 0);
+ return (_value.Equals(other._value, StringComparison.OrdinalIgnoreCase));
}
}
- public static NameValueHeaderValue Parse(string input)
+ public static NameValueHeaderValue Parse(StringSegment input)
{
var index = 0;
return SingleValueParser.ParseValue(input, ref index);
}
- public static bool TryParse(string input, out NameValueHeaderValue parsedValue)
+ public static bool TryParse(StringSegment input, out NameValueHeaderValue parsedValue)
{
var index = 0;
return SingleValueParser.TryParseValue(input, ref index, out parsedValue);
@@ -175,11 +176,11 @@ namespace Microsoft.Net.Http.Headers
public override string ToString()
{
- if (!string.IsNullOrEmpty(_value))
+ if (!StringSegment.IsNullOrEmpty(_value))
{
return _name + "=" + _value;
}
- return _name;
+ return _name.ToString();
}
internal static void ToString(
@@ -202,7 +203,12 @@ namespace Microsoft.Net.Http.Headers
destination.Append(separator);
destination.Append(' ');
}
- destination.Append(values[i].ToString());
+ destination.Append(values[i].Name);
+ if (!StringSegment.IsNullOrEmpty(values[i].Value))
+ {
+ destination.Append('=');
+ destination.Append(values[i].Value);
+ }
}
}
@@ -235,14 +241,14 @@ namespace Microsoft.Net.Http.Headers
return result;
}
- private static int GetNameValueLength(string input, int startIndex, out NameValueHeaderValue parsedValue)
+ private static int GetNameValueLength(StringSegment input, int startIndex, out NameValueHeaderValue parsedValue)
{
Contract.Requires(input != null);
Contract.Requires(startIndex >= 0);
parsedValue = null;
- if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
+ if (StringSegment.IsNullOrEmpty(input) || (startIndex >= input.Length))
{
return 0;
}
@@ -256,7 +262,7 @@ namespace Microsoft.Net.Http.Headers
return 0;
}
- var name = input.Substring(startIndex, nameLength);
+ var name = input.Subsegment(startIndex, nameLength);
var current = startIndex + nameLength;
current = current + HttpRuleParser.GetWhitespaceLength(input, current);
@@ -280,7 +286,7 @@ namespace Microsoft.Net.Http.Headers
// Use parameterless ctor to avoid double-parsing of name and value, i.e. skip public ctor validation.
parsedValue = new NameValueHeaderValue();
parsedValue._name = name;
- parsedValue._value = input.Substring(current, valueLength);
+ parsedValue._value = input.Subsegment(current, valueLength);
current = current + valueLength;
current = current + HttpRuleParser.GetWhitespaceLength(input, current); // skip whitespaces
return current - startIndex;
@@ -289,7 +295,7 @@ namespace Microsoft.Net.Http.Headers
// Returns the length of a name/value list, separated by 'delimiter'. E.g. "a=b, c=d, e=f" adds 3
// name/value pairs to 'nameValueCollection' if 'delimiter' equals ','.
internal static int GetNameValueListLength(
- string input,
+ StringSegment input,
int startIndex,
char delimiter,
IList nameValueCollection)
@@ -297,7 +303,7 @@ namespace Microsoft.Net.Http.Headers
Contract.Requires(nameValueCollection != null);
Contract.Requires(startIndex >= 0);
- if ((string.IsNullOrEmpty(input)) || (startIndex >= input.Length))
+ if ((StringSegment.IsNullOrEmpty(input)) || (startIndex >= input.Length))
{
return 0;
}
@@ -330,7 +336,7 @@ namespace Microsoft.Net.Http.Headers
}
}
- public static NameValueHeaderValue Find(IList values, string name)
+ public static NameValueHeaderValue Find(IList values, StringSegment name)
{
Contract.Requires((name != null) && (name.Length > 0));
@@ -342,7 +348,7 @@ namespace Microsoft.Net.Http.Headers
for (var i = 0; i < values.Count; i++)
{
var value = values[i];
- if (string.Compare(value.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
+ if (value.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
{
return value;
}
@@ -350,7 +356,7 @@ namespace Microsoft.Net.Http.Headers
return null;
}
- internal static int GetValueLength(string input, int startIndex)
+ internal static int GetValueLength(StringSegment input, int startIndex)
{
Contract.Requires(input != null);
@@ -373,16 +379,16 @@ namespace Microsoft.Net.Http.Headers
return valueLength;
}
- private static void CheckNameValueFormat(string name, string value)
+ private static void CheckNameValueFormat(StringSegment name, StringSegment value)
{
HeaderUtilities.CheckValidToken(name, nameof(name));
CheckValueFormat(value);
}
- private static void CheckValueFormat(string value)
+ private static void CheckValueFormat(StringSegment value)
{
// Either value is null/empty or a valid token/quoted string
- if (!(string.IsNullOrEmpty(value) || (GetValueLength(value, 0) == value.Length)))
+ if (!(StringSegment.IsNullOrEmpty(value) || (GetValueLength(value, 0) == value.Length)))
{
throw new FormatException(string.Format(System.Globalization.CultureInfo.InvariantCulture, "The header value is invalid: '{0}'", value));
}
diff --git a/src/Microsoft.Net.Http.Headers/ObjectCollection.cs b/src/Microsoft.Net.Http.Headers/ObjectCollection.cs
index f6d91e1508..db5f876b53 100644
--- a/src/Microsoft.Net.Http.Headers/ObjectCollection.cs
+++ b/src/Microsoft.Net.Http.Headers/ObjectCollection.cs
@@ -11,7 +11,7 @@ namespace Microsoft.Net.Http.Headers
// type to throw if 'null' gets added. Collection internally uses List which comes at some cost. In addition
// Collection.Add() calls List.InsertItem() which is an O(n) operation (compared to O(1) for List.Add()).
// This type is only used for very small collections (1-2 items) to keep the impact of using Collection small.
- internal class ObjectCollection : Collection where T : class
+ internal class ObjectCollection : Collection
{
internal static readonly Action DefaultValidator = CheckNotNull;
internal static readonly ObjectCollection EmptyReadOnlyCollection
diff --git a/src/Microsoft.Net.Http.Headers/RangeConditionHeaderValue.cs b/src/Microsoft.Net.Http.Headers/RangeConditionHeaderValue.cs
index 4960e4beab..f1ebee276c 100644
--- a/src/Microsoft.Net.Http.Headers/RangeConditionHeaderValue.cs
+++ b/src/Microsoft.Net.Http.Headers/RangeConditionHeaderValue.cs
@@ -3,6 +3,7 @@
using System;
using System.Diagnostics.Contracts;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -85,26 +86,26 @@ namespace Microsoft.Net.Http.Headers
return _entityTag.GetHashCode();
}
- public static RangeConditionHeaderValue Parse(string input)
+ public static RangeConditionHeaderValue Parse(StringSegment input)
{
var index = 0;
return Parser.ParseValue(input, ref index);
}
- public static bool TryParse(string input, out RangeConditionHeaderValue parsedValue)
+ public static bool TryParse(StringSegment input, out RangeConditionHeaderValue parsedValue)
{
var index = 0;
return Parser.TryParseValue(input, ref index, out parsedValue);
}
- private static int GetRangeConditionLength(string input, int startIndex, out RangeConditionHeaderValue parsedValue)
+ private static int GetRangeConditionLength(StringSegment input, int startIndex, out RangeConditionHeaderValue parsedValue)
{
Contract.Requires(startIndex >= 0);
parsedValue = null;
// Make sure we have at least 2 characters
- if (string.IsNullOrEmpty(input) || (startIndex + 1 >= input.Length))
+ if (StringSegment.IsNullOrEmpty(input) || (startIndex + 1 >= input.Length))
{
return 0;
}
@@ -141,7 +142,7 @@ namespace Microsoft.Net.Http.Headers
}
else
{
- if (!HttpRuleParser.TryStringToDate(input.Substring(current), out date))
+ if (!HttpRuleParser.TryStringToDate(input.Subsegment(current), out date))
{
return 0;
}
diff --git a/src/Microsoft.Net.Http.Headers/RangeHeaderValue.cs b/src/Microsoft.Net.Http.Headers/RangeHeaderValue.cs
index 3657e24c27..934b6b6cc1 100644
--- a/src/Microsoft.Net.Http.Headers/RangeHeaderValue.cs
+++ b/src/Microsoft.Net.Http.Headers/RangeHeaderValue.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Text;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -13,7 +14,7 @@ namespace Microsoft.Net.Http.Headers
private static readonly HttpHeaderParser Parser
= new GenericHeaderParser(false, GetRangeLength);
- private string _unit;
+ private StringSegment _unit;
private ICollection _ranges;
public RangeHeaderValue()
@@ -28,7 +29,7 @@ namespace Microsoft.Net.Http.Headers
Ranges.Add(new RangeItemHeaderValue(from, to));
}
- public string Unit
+ public StringSegment Unit
{
get { return _unit; }
set
@@ -52,7 +53,8 @@ namespace Microsoft.Net.Http.Headers
public override string ToString()
{
- var sb = new StringBuilder(_unit);
+ var sb = new StringBuilder();
+ sb.Append(_unit);
sb.Append('=');
var first = true;
@@ -84,13 +86,13 @@ namespace Microsoft.Net.Http.Headers
return false;
}
- return (string.Compare(_unit, other._unit, StringComparison.OrdinalIgnoreCase) == 0) &&
+ return StringSegment.Equals(_unit, other._unit, StringComparison.OrdinalIgnoreCase) &&
HeaderUtilities.AreEqualCollections(Ranges, other.Ranges);
}
public override int GetHashCode()
{
- var result = StringComparer.OrdinalIgnoreCase.GetHashCode(_unit);
+ var result = StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_unit);
foreach (var range in Ranges)
{
@@ -100,25 +102,25 @@ namespace Microsoft.Net.Http.Headers
return result;
}
- public static RangeHeaderValue Parse(string input)
+ public static RangeHeaderValue Parse(StringSegment input)
{
var index = 0;
return Parser.ParseValue(input, ref index);
}
- public static bool TryParse(string input, out RangeHeaderValue parsedValue)
+ public static bool TryParse(StringSegment input, out RangeHeaderValue parsedValue)
{
var index = 0;
return Parser.TryParseValue(input, ref index, out parsedValue);
}
- private static int GetRangeLength(string input, int startIndex, out RangeHeaderValue parsedValue)
+ private static int GetRangeLength(StringSegment input, int startIndex, out RangeHeaderValue parsedValue)
{
Contract.Requires(startIndex >= 0);
parsedValue = null;
- if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
+ if (StringSegment.IsNullOrEmpty(input) || (startIndex >= input.Length))
{
return 0;
}
@@ -132,7 +134,7 @@ namespace Microsoft.Net.Http.Headers
}
RangeHeaderValue result = new RangeHeaderValue();
- result._unit = input.Substring(startIndex, unitLength);
+ result._unit = input.Subsegment(startIndex, unitLength);
var current = startIndex + unitLength;
current = current + HttpRuleParser.GetWhitespaceLength(input, current);
diff --git a/src/Microsoft.Net.Http.Headers/RangeItemHeaderValue.cs b/src/Microsoft.Net.Http.Headers/RangeItemHeaderValue.cs
index 866d4b8e8b..99fdbfef5c 100644
--- a/src/Microsoft.Net.Http.Headers/RangeItemHeaderValue.cs
+++ b/src/Microsoft.Net.Http.Headers/RangeItemHeaderValue.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -87,7 +88,7 @@ namespace Microsoft.Net.Http.Headers
// Returns the length of a range list. E.g. "1-2, 3-4, 5-6" adds 3 ranges to 'rangeCollection'. Note that empty
// list segments are allowed, e.g. ",1-2, , 3-4,,".
internal static int GetRangeItemListLength(
- string input,
+ StringSegment input,
int startIndex,
ICollection rangeCollection)
{
@@ -96,7 +97,7 @@ namespace Microsoft.Net.Http.Headers
Contract.Ensures((Contract.Result() == 0) || (rangeCollection.Count > 0),
"If we can parse the string, then we expect to have at least one range item.");
- if ((string.IsNullOrEmpty(input)) || (startIndex >= input.Length))
+ if ((StringSegment.IsNullOrEmpty(input)) || (startIndex >= input.Length))
{
return 0;
}
@@ -140,7 +141,7 @@ namespace Microsoft.Net.Http.Headers
}
}
- internal static int GetRangeItemLength(string input, int startIndex, out RangeItemHeaderValue parsedValue)
+ internal static int GetRangeItemLength(StringSegment input, int startIndex, out RangeItemHeaderValue parsedValue)
{
Contract.Requires(startIndex >= 0);
@@ -148,7 +149,7 @@ namespace Microsoft.Net.Http.Headers
parsedValue = null;
- if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
+ if (StringSegment.IsNullOrEmpty(input) || (startIndex >= input.Length))
{
return 0;
}
@@ -202,14 +203,14 @@ namespace Microsoft.Net.Http.Headers
// Try convert first value to int64
long from = 0;
- if ((fromLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Substring(fromStartIndex, fromLength), out from))
+ if ((fromLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Subsegment(fromStartIndex, fromLength), out from))
{
return 0;
}
// Try convert second value to int64
long to = 0;
- if ((toLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Substring(toStartIndex, toLength), out to))
+ if ((toLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Subsegment(toStartIndex, toLength), out to))
{
return 0;
}
diff --git a/src/Microsoft.Net.Http.Headers/SetCookieHeaderValue.cs b/src/Microsoft.Net.Http.Headers/SetCookieHeaderValue.cs
index 10c68bb5b1..f3477648de 100644
--- a/src/Microsoft.Net.Http.Headers/SetCookieHeaderValue.cs
+++ b/src/Microsoft.Net.Http.Headers/SetCookieHeaderValue.cs
@@ -31,20 +31,20 @@ namespace Microsoft.Net.Http.Headers
private static readonly HttpHeaderParser MultipleValueParser
= new GenericHeaderParser(true, GetSetCookieLength);
- private string _name;
- private string _value;
+ private StringSegment _name;
+ private StringSegment _value;
private SetCookieHeaderValue()
{
// Used by the parser to create a new instance of this type.
}
- public SetCookieHeaderValue(string name)
- : this(name, string.Empty)
+ public SetCookieHeaderValue(StringSegment name)
+ : this(name, StringSegment.Empty)
{
}
- public SetCookieHeaderValue(string name, string value)
+ public SetCookieHeaderValue(StringSegment name, StringSegment value)
{
if (name == null)
{
@@ -60,7 +60,7 @@ namespace Microsoft.Net.Http.Headers
Value = value;
}
- public string Name
+ public StringSegment Name
{
get { return _name; }
set
@@ -70,7 +70,7 @@ namespace Microsoft.Net.Http.Headers
}
}
- public string Value
+ public StringSegment Value
{
get { return _value; }
set
@@ -84,10 +84,9 @@ namespace Microsoft.Net.Http.Headers
public TimeSpan? MaxAge { get; set; }
- public string Domain { get; set; }
+ public StringSegment Domain { get; set; }
- // TODO: PathString?
- public string Path { get; set; }
+ public StringSegment Path { get; set; }
public bool Secure { get; set; }
@@ -186,7 +185,7 @@ namespace Microsoft.Net.Http.Headers
return sb.ToString();
}
- private static void AppendSegment(ref InplaceStringBuilder builder, string name, string value)
+ private static void AppendSegment(ref InplaceStringBuilder builder, StringSegment name, StringSegment value)
{
builder.Append(SeparatorToken);
builder.Append(name);
@@ -247,7 +246,7 @@ namespace Microsoft.Net.Http.Headers
}
}
- private static void AppendSegment(StringBuilder builder, string name, string value)
+ private static void AppendSegment(StringBuilder builder, StringSegment name, StringSegment value)
{
builder.Append("; ");
builder.Append(name);
@@ -258,13 +257,13 @@ namespace Microsoft.Net.Http.Headers
}
}
- public static SetCookieHeaderValue Parse(string input)
+ public static SetCookieHeaderValue Parse(StringSegment input)
{
var index = 0;
return SingleValueParser.ParseValue(input, ref index);
}
- public static bool TryParse(string input, out SetCookieHeaderValue parsedValue)
+ public static bool TryParse(StringSegment input, out SetCookieHeaderValue parsedValue)
{
var index = 0;
return SingleValueParser.TryParseValue(input, ref index, out parsedValue);
@@ -291,14 +290,14 @@ namespace Microsoft.Net.Http.Headers
}
// name=value; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={Strict|Lax}; httponly
- private static int GetSetCookieLength(string input, int startIndex, out SetCookieHeaderValue parsedValue)
+ private static int GetSetCookieLength(StringSegment input, int startIndex, out SetCookieHeaderValue parsedValue)
{
Contract.Requires(startIndex >= 0);
var offset = startIndex;
parsedValue = null;
- if (string.IsNullOrEmpty(input) || (offset >= input.Length))
+ if (StringSegment.IsNullOrEmpty(input) || (offset >= input.Length))
{
return 0;
}
@@ -315,7 +314,7 @@ namespace Microsoft.Net.Http.Headers
{
return 0;
}
- result._name = input.Substring(offset, itemLength);
+ result._name = input.Subsegment(offset, itemLength);
offset += itemLength;
// = (no spaces)
@@ -352,11 +351,11 @@ namespace Microsoft.Net.Http.Headers
// Trailing ';' or leading into garbage. Let the next parser fail.
break;
}
- var token = input.Substring(offset, itemLength);
+ var token = input.Subsegment(offset, itemLength);
offset += itemLength;
// expires-av = "Expires=" sane-cookie-date
- if (string.Equals(token, ExpiresToken, StringComparison.OrdinalIgnoreCase))
+ if (StringSegment.Equals(token, ExpiresToken, StringComparison.OrdinalIgnoreCase))
{
// = (no spaces)
if (!ReadEqualsSign(input, ref offset))
@@ -373,7 +372,7 @@ namespace Microsoft.Net.Http.Headers
result.Expires = expirationDate;
}
// max-age-av = "Max-Age=" non-zero-digit *DIGIT
- else if (string.Equals(token, MaxAgeToken, StringComparison.OrdinalIgnoreCase))
+ else if (StringSegment.Equals(token, MaxAgeToken, StringComparison.OrdinalIgnoreCase))
{
// = (no spaces)
if (!ReadEqualsSign(input, ref offset))
@@ -386,7 +385,7 @@ namespace Microsoft.Net.Http.Headers
{
return 0;
}
- var numberString = input.Substring(offset, itemLength);
+ var numberString = input.Subsegment(offset, itemLength);
long maxAge;
if (!HeaderUtilities.TryParseNonNegativeInt64(numberString, out maxAge))
{
@@ -398,7 +397,7 @@ namespace Microsoft.Net.Http.Headers
}
// domain-av = "Domain=" domain-value
// domain-value = ; defined in [RFC1034], Section 3.5, as enhanced by [RFC1123], Section 2.1
- else if (string.Equals(token, DomainToken, StringComparison.OrdinalIgnoreCase))
+ else if (StringSegment.Equals(token, DomainToken, StringComparison.OrdinalIgnoreCase))
{
// = (no spaces)
if (!ReadEqualsSign(input, ref offset))
@@ -410,7 +409,7 @@ namespace Microsoft.Net.Http.Headers
}
// path-av = "Path=" path-value
// path-value =
- else if (string.Equals(token, PathToken, StringComparison.OrdinalIgnoreCase))
+ else if (StringSegment.Equals(token, PathToken, StringComparison.OrdinalIgnoreCase))
{
// = (no spaces)
if (!ReadEqualsSign(input, ref offset))
@@ -421,13 +420,13 @@ namespace Microsoft.Net.Http.Headers
result.Path = ReadToSemicolonOrEnd(input, ref offset);
}
// secure-av = "Secure"
- else if (string.Equals(token, SecureToken, StringComparison.OrdinalIgnoreCase))
+ else if (StringSegment.Equals(token, SecureToken, StringComparison.OrdinalIgnoreCase))
{
result.Secure = true;
}
// samesite-av = "SameSite" / "SameSite=" samesite-value
// samesite-value = "Strict" / "Lax"
- else if (string.Equals(token, SameSiteToken, StringComparison.OrdinalIgnoreCase))
+ else if (StringSegment.Equals(token, SameSiteToken, StringComparison.OrdinalIgnoreCase))
{
if (!ReadEqualsSign(input, ref offset))
{
@@ -437,7 +436,7 @@ namespace Microsoft.Net.Http.Headers
{
var enforcementMode = ReadToSemicolonOrEnd(input, ref offset);
- if (string.Equals(enforcementMode, SameSiteLaxToken, StringComparison.OrdinalIgnoreCase))
+ if (StringSegment.Equals(enforcementMode, SameSiteLaxToken, StringComparison.OrdinalIgnoreCase))
{
result.SameSite = SameSiteMode.Lax;
}
@@ -448,7 +447,7 @@ namespace Microsoft.Net.Http.Headers
}
}
// httponly-av = "HttpOnly"
- else if (string.Equals(token, HttpOnlyToken, StringComparison.OrdinalIgnoreCase))
+ else if (StringSegment.Equals(token, HttpOnlyToken, StringComparison.OrdinalIgnoreCase))
{
result.HttpOnly = true;
}
@@ -463,7 +462,7 @@ namespace Microsoft.Net.Http.Headers
return offset - startIndex;
}
- private static bool ReadEqualsSign(string input, ref int offset)
+ private static bool ReadEqualsSign(StringSegment input, ref int offset)
{
// = (no spaces)
if (offset >= input.Length || input[offset] != '=')
@@ -474,7 +473,7 @@ namespace Microsoft.Net.Http.Headers
return true;
}
- private static string ReadToSemicolonOrEnd(string input, ref int offset)
+ private static StringSegment ReadToSemicolonOrEnd(StringSegment input, ref int offset)
{
var end = input.IndexOf(';', offset);
if (end < 0)
@@ -483,7 +482,7 @@ namespace Microsoft.Net.Http.Headers
end = input.Length;
}
var itemLength = end - offset;
- var result = input.Substring(offset, itemLength);
+ var result = input.Subsegment(offset, itemLength);
offset += itemLength;
return result;
}
@@ -497,12 +496,12 @@ namespace Microsoft.Net.Http.Headers
return false;
}
- return string.Equals(_name, other._name, StringComparison.OrdinalIgnoreCase)
- && string.Equals(_value, other._value, StringComparison.OrdinalIgnoreCase)
+ return StringSegment.Equals(_name, other._name, StringComparison.OrdinalIgnoreCase)
+ && StringSegment.Equals(_value, other._value, StringComparison.OrdinalIgnoreCase)
&& Expires.Equals(other.Expires)
&& MaxAge.Equals(other.MaxAge)
- && string.Equals(Domain, other.Domain, StringComparison.OrdinalIgnoreCase)
- && string.Equals(Path, other.Path, StringComparison.OrdinalIgnoreCase)
+ && StringSegment.Equals(Domain, other.Domain, StringComparison.OrdinalIgnoreCase)
+ && StringSegment.Equals(Path, other.Path, StringComparison.OrdinalIgnoreCase)
&& Secure == other.Secure
&& SameSite == other.SameSite
&& HttpOnly == other.HttpOnly;
@@ -510,12 +509,12 @@ namespace Microsoft.Net.Http.Headers
public override int GetHashCode()
{
- return StringComparer.OrdinalIgnoreCase.GetHashCode(_name)
- ^ StringComparer.OrdinalIgnoreCase.GetHashCode(_value)
+ return StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_name)
+ ^ StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_value)
^ (Expires.HasValue ? Expires.GetHashCode() : 0)
^ (MaxAge.HasValue ? MaxAge.GetHashCode() : 0)
- ^ (Domain != null ? StringComparer.OrdinalIgnoreCase.GetHashCode(Domain) : 0)
- ^ (Path != null ? StringComparer.OrdinalIgnoreCase.GetHashCode(Path) : 0)
+ ^ (Domain != null ? StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(Domain) : 0)
+ ^ (Path != null ? StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(Path) : 0)
^ Secure.GetHashCode()
^ SameSite.GetHashCode()
^ HttpOnly.GetHashCode();
diff --git a/src/Microsoft.Net.Http.Headers/StringWithQualityHeaderValue.cs b/src/Microsoft.Net.Http.Headers/StringWithQualityHeaderValue.cs
index 13ac4fb15c..deba2d2697 100644
--- a/src/Microsoft.Net.Http.Headers/StringWithQualityHeaderValue.cs
+++ b/src/Microsoft.Net.Http.Headers/StringWithQualityHeaderValue.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -15,7 +16,7 @@ namespace Microsoft.Net.Http.Headers
private static readonly HttpHeaderParser MultipleValueParser
= new GenericHeaderParser(true, GetStringWithQualityLength);
- private string _value;
+ private StringSegment _value;
private double? _quality;
private StringWithQualityHeaderValue()
@@ -23,14 +24,14 @@ namespace Microsoft.Net.Http.Headers
// Used by the parser to create a new instance of this type.
}
- public StringWithQualityHeaderValue(string value)
+ public StringWithQualityHeaderValue(StringSegment value)
{
HeaderUtilities.CheckValidToken(value, nameof(value));
_value = value;
}
- public StringWithQualityHeaderValue(string value, double quality)
+ public StringWithQualityHeaderValue(StringSegment value, double quality)
{
HeaderUtilities.CheckValidToken(value, nameof(value));
@@ -43,7 +44,7 @@ namespace Microsoft.Net.Http.Headers
_quality = quality;
}
- public string Value
+ public StringSegment Value
{
get { return _value; }
}
@@ -60,7 +61,7 @@ namespace Microsoft.Net.Http.Headers
return _value + "; q=" + _quality.Value.ToString("0.0##", NumberFormatInfo.InvariantInfo);
}
- return _value;
+ return _value.ToString();
}
public override bool Equals(object obj)
@@ -72,7 +73,7 @@ namespace Microsoft.Net.Http.Headers
return false;
}
- if (string.Compare(_value, other._value, StringComparison.OrdinalIgnoreCase) != 0)
+ if (!StringSegment.Equals(_value, other._value, StringComparison.OrdinalIgnoreCase))
{
return false;
}
@@ -92,7 +93,7 @@ namespace Microsoft.Net.Http.Headers
public override int GetHashCode()
{
- var result = StringComparer.OrdinalIgnoreCase.GetHashCode(_value);
+ var result = StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_value);
if (_quality.HasValue)
{
@@ -102,13 +103,13 @@ namespace Microsoft.Net.Http.Headers
return result;
}
- public static StringWithQualityHeaderValue Parse(string input)
+ public static StringWithQualityHeaderValue Parse(StringSegment input)
{
var index = 0;
return SingleValueParser.ParseValue(input, ref index);
}
- public static bool TryParse(string input, out StringWithQualityHeaderValue parsedValue)
+ public static bool TryParse(StringSegment input, out StringWithQualityHeaderValue parsedValue)
{
var index = 0;
return SingleValueParser.TryParseValue(input, ref index, out parsedValue);
@@ -134,13 +135,13 @@ namespace Microsoft.Net.Http.Headers
return MultipleValueParser.TryParseStrictValues(input, out parsedValues);
}
- private static int GetStringWithQualityLength(string input, int startIndex, out StringWithQualityHeaderValue parsedValue)
+ private static int GetStringWithQualityLength(StringSegment input, int startIndex, out StringWithQualityHeaderValue parsedValue)
{
Contract.Requires(startIndex >= 0);
parsedValue = null;
- if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
+ if (StringSegment.IsNullOrEmpty(input) || (startIndex >= input.Length))
{
return 0;
}
@@ -154,7 +155,7 @@ namespace Microsoft.Net.Http.Headers
}
StringWithQualityHeaderValue result = new StringWithQualityHeaderValue();
- result._value = input.Substring(startIndex, valueLength);
+ result._value = input.Subsegment(startIndex, valueLength);
var current = startIndex + valueLength;
current = current + HttpRuleParser.GetWhitespaceLength(input, current);
@@ -177,7 +178,7 @@ namespace Microsoft.Net.Http.Headers
return current - startIndex;
}
- private static bool TryReadQuality(string input, StringWithQualityHeaderValue result, ref int index)
+ private static bool TryReadQuality(StringSegment input, StringWithQualityHeaderValue result, ref int index)
{
var current = index;
diff --git a/src/Microsoft.Net.Http.Headers/StringWithQualityHeaderValueComparer.cs b/src/Microsoft.Net.Http.Headers/StringWithQualityHeaderValueComparer.cs
index 0d092ec19d..961cc07841 100644
--- a/src/Microsoft.Net.Http.Headers/StringWithQualityHeaderValueComparer.cs
+++ b/src/Microsoft.Net.Http.Headers/StringWithQualityHeaderValueComparer.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Headers
{
@@ -64,13 +65,13 @@ namespace Microsoft.Net.Http.Headers
return 1;
}
- if (!string.Equals(stringWithQuality1.Value, stringWithQuality2.Value, StringComparison.OrdinalIgnoreCase))
+ if (!StringSegment.Equals(stringWithQuality1.Value, stringWithQuality2.Value, StringComparison.OrdinalIgnoreCase))
{
- if (string.Equals(stringWithQuality1.Value, "*", StringComparison.Ordinal))
+ if (StringSegment.Equals(stringWithQuality1.Value, "*", StringComparison.Ordinal))
{
return -1;
}
- else if (string.Equals(stringWithQuality2.Value, "*", StringComparison.Ordinal))
+ else if (StringSegment.Equals(stringWithQuality2.Value, "*", StringComparison.Ordinal))
{
return 1;
}
diff --git a/test/Microsoft.Net.Http.Headers.Tests/ContentDispositionHeaderValueTest.cs b/test/Microsoft.Net.Http.Headers.Tests/ContentDispositionHeaderValueTest.cs
index 89b1ab0f10..17f9623347 100644
--- a/test/Microsoft.Net.Http.Headers.Tests/ContentDispositionHeaderValueTest.cs
+++ b/test/Microsoft.Net.Http.Headers.Tests/ContentDispositionHeaderValueTest.cs
@@ -46,8 +46,8 @@ namespace Microsoft.Net.Http.Headers
var contentDisposition = new ContentDispositionHeaderValue("inline");
Assert.Equal("inline", contentDisposition.DispositionType);
Assert.Equal(0, contentDisposition.Parameters.Count);
- Assert.Null(contentDisposition.Name);
- Assert.Null(contentDisposition.FileName);
+ Assert.Null(contentDisposition.Name.Value);
+ Assert.Null(contentDisposition.FileName.Value);
Assert.Null(contentDisposition.CreationDate);
Assert.Null(contentDisposition.ModificationDate);
Assert.Null(contentDisposition.ReadDate);
@@ -81,7 +81,7 @@ namespace Microsoft.Net.Http.Headers
Assert.Equal("name", contentDisposition.Parameters.First().Name);
contentDisposition.Name = null;
- Assert.Null(contentDisposition.Name);
+ Assert.Null(contentDisposition.Name.Value);
Assert.Equal(0, contentDisposition.Parameters.Count);
contentDisposition.Name = null; // It's OK to set it again to null; no exception.
}
@@ -103,7 +103,7 @@ namespace Microsoft.Net.Http.Headers
Assert.Equal("NAME", contentDisposition.Parameters.First().Name);
contentDisposition.Parameters.Remove(name);
- Assert.Null(contentDisposition.Name);
+ Assert.Null(contentDisposition.Name.Value);
}
[Fact]
@@ -123,7 +123,7 @@ namespace Microsoft.Net.Http.Headers
Assert.Equal("FILENAME", contentDisposition.Parameters.First().Name);
contentDisposition.Parameters.Remove(fileName);
- Assert.Null(contentDisposition.FileName);
+ Assert.Null(contentDisposition.FileName.Value);
}
[Fact]
@@ -138,7 +138,7 @@ namespace Microsoft.Net.Http.Headers
Assert.Equal("\"=?utf-8?B?RmlsZcODTmFtZS5iYXQ=?=\"", contentDisposition.Parameters.First().Value);
contentDisposition.Parameters.Remove(contentDisposition.Parameters.First());
- Assert.Null(contentDisposition.FileName);
+ Assert.Null(contentDisposition.FileName.Value);
}
[Fact]
@@ -160,7 +160,7 @@ namespace Microsoft.Net.Http.Headers
Assert.Equal("FILENAME", contentDisposition.Parameters.First().Name);
contentDisposition.Parameters.Remove(fileName);
- Assert.Null(contentDisposition.FileName);
+ Assert.Null(contentDisposition.FileName.Value);
}
[Fact]
@@ -173,7 +173,7 @@ namespace Microsoft.Net.Http.Headers
contentDisposition.Parameters.Add(fileNameStar);
Assert.Equal(1, contentDisposition.Parameters.Count);
Assert.Equal("FILENAME*", contentDisposition.Parameters.First().Name);
- Assert.Null(contentDisposition.FileNameStar); // Decode failure
+ Assert.Null(contentDisposition.FileNameStar.Value); // Decode failure
contentDisposition.FileNameStar = "new_name";
Assert.Equal("new_name", contentDisposition.FileNameStar);
@@ -182,7 +182,7 @@ namespace Microsoft.Net.Http.Headers
Assert.Equal("UTF-8\'\'new_name", contentDisposition.Parameters.First().Value);
contentDisposition.Parameters.Remove(fileNameStar);
- Assert.Null(contentDisposition.FileNameStar);
+ Assert.Null(contentDisposition.FileNameStar.Value);
}
[Fact]
@@ -197,7 +197,7 @@ namespace Microsoft.Net.Http.Headers
Assert.Equal("UTF-8\'\'File%C3%83Name.bat", contentDisposition.Parameters.First().Value);
contentDisposition.Parameters.Remove(contentDisposition.Parameters.First());
- Assert.Null(contentDisposition.FileNameStar);
+ Assert.Null(contentDisposition.FileNameStar.Value);
}
[Fact]
@@ -211,7 +211,7 @@ namespace Microsoft.Net.Http.Headers
Assert.Equal(1, contentDisposition.Parameters.Count);
Assert.Equal("FILENAME*", contentDisposition.Parameters.First().Name);
Assert.Equal("utf-99'lang'File%CZName.bat", contentDisposition.Parameters.First().Value);
- Assert.Null(contentDisposition.FileNameStar); // Decode failure
+ Assert.Null(contentDisposition.FileNameStar.Value); // Decode failure
contentDisposition.FileNameStar = "new_name";
Assert.Equal("new_name", contentDisposition.FileNameStar);
@@ -219,7 +219,7 @@ namespace Microsoft.Net.Http.Headers
Assert.Equal("FILENAME*", contentDisposition.Parameters.First().Name);
contentDisposition.Parameters.Remove(fileNameStar);
- Assert.Null(contentDisposition.FileNameStar);
+ Assert.Null(contentDisposition.FileNameStar.Value);
}
[Fact]
diff --git a/test/Microsoft.Net.Http.Headers.Tests/MediaTypeHeaderValueTest.cs b/test/Microsoft.Net.Http.Headers.Tests/MediaTypeHeaderValueTest.cs
index 0a72951240..1d5c9e9f65 100644
--- a/test/Microsoft.Net.Http.Headers.Tests/MediaTypeHeaderValueTest.cs
+++ b/test/Microsoft.Net.Http.Headers.Tests/MediaTypeHeaderValueTest.cs
@@ -45,7 +45,7 @@ namespace Microsoft.Net.Http.Headers
var mediaType = new MediaTypeHeaderValue("text/plain");
Assert.Equal("text/plain", mediaType.MediaType);
Assert.Equal(0, mediaType.Parameters.Count);
- Assert.Null(mediaType.Charset);
+ Assert.Null(mediaType.Charset.Value);
}
[Fact]
@@ -70,7 +70,7 @@ namespace Microsoft.Net.Http.Headers
var mediaType0 = new MediaTypeHeaderValue("text/plain");
var mediaType1 = mediaType0.Copy();
Assert.NotSame(mediaType0, mediaType1);
- Assert.Same(mediaType0.MediaType, mediaType1.MediaType);
+ Assert.Same(mediaType0.MediaType.Value, mediaType1.MediaType.Value);
Assert.NotSame(mediaType0.Parameters, mediaType1.Parameters);
Assert.Equal(mediaType0.Parameters.Count, mediaType1.Parameters.Count);
}
@@ -81,7 +81,7 @@ namespace Microsoft.Net.Http.Headers
var mediaType0 = new MediaTypeHeaderValue("text/plain");
var mediaType1 = mediaType0.CopyAsReadOnly();
Assert.NotSame(mediaType0, mediaType1);
- Assert.Same(mediaType0.MediaType, mediaType1.MediaType);
+ Assert.Same(mediaType0.MediaType.Value, mediaType1.MediaType.Value);
Assert.NotSame(mediaType0.Parameters, mediaType1.Parameters);
Assert.Equal(mediaType0.Parameters.Count, mediaType1.Parameters.Count);
@@ -97,14 +97,14 @@ namespace Microsoft.Net.Http.Headers
mediaType0.Parameters.Add(new NameValueHeaderValue("name", "value"));
var mediaType1 = mediaType0.Copy();
Assert.NotSame(mediaType0, mediaType1);
- Assert.Same(mediaType0.MediaType, mediaType1.MediaType);
+ Assert.Same(mediaType0.MediaType.Value, mediaType1.MediaType.Value);
Assert.NotSame(mediaType0.Parameters, mediaType1.Parameters);
Assert.Equal(mediaType0.Parameters.Count, mediaType1.Parameters.Count);
var pair0 = mediaType0.Parameters.First();
var pair1 = mediaType1.Parameters.First();
Assert.NotSame(pair0, pair1);
- Assert.Same(pair0.Name, pair1.Name);
- Assert.Same(pair0.Value, pair1.Value);
+ Assert.Same(pair0.Name.Value, pair1.Name.Value);
+ Assert.Same(pair0.Value.Value, pair1.Value.Value);
}
[Fact]
@@ -116,7 +116,7 @@ namespace Microsoft.Net.Http.Headers
Assert.NotSame(mediaType0, mediaType1);
Assert.False(mediaType0.IsReadOnly);
Assert.True(mediaType1.IsReadOnly);
- Assert.Same(mediaType0.MediaType, mediaType1.MediaType);
+ Assert.Same(mediaType0.MediaType.Value, mediaType1.MediaType.Value);
Assert.NotSame(mediaType0.Parameters, mediaType1.Parameters);
Assert.False(mediaType0.Parameters.IsReadOnly);
@@ -131,8 +131,8 @@ namespace Microsoft.Net.Http.Headers
Assert.NotSame(pair0, pair1);
Assert.False(pair0.IsReadOnly);
Assert.True(pair1.IsReadOnly);
- Assert.Same(pair0.Name, pair1.Name);
- Assert.Same(pair0.Value, pair1.Value);
+ Assert.Same(pair0.Name.Value, pair1.Name.Value);
+ Assert.Same(pair0.Value.Value, pair1.Value.Value);
}
[Fact]
@@ -144,7 +144,7 @@ namespace Microsoft.Net.Http.Headers
var mediaType2 = mediaType1.Copy();
Assert.NotSame(mediaType2, mediaType1);
- Assert.Same(mediaType2.MediaType, mediaType1.MediaType);
+ Assert.Same(mediaType2.MediaType.Value, mediaType1.MediaType.Value);
Assert.True(mediaType1.IsReadOnly);
Assert.False(mediaType2.IsReadOnly);
Assert.NotSame(mediaType2.Parameters, mediaType1.Parameters);
@@ -154,8 +154,8 @@ namespace Microsoft.Net.Http.Headers
Assert.NotSame(pair2, pair1);
Assert.True(pair1.IsReadOnly);
Assert.False(pair2.IsReadOnly);
- Assert.Same(pair2.Name, pair1.Name);
- Assert.Same(pair2.Value, pair1.Value);
+ Assert.Same(pair2.Name.Value, pair1.Name.Value);
+ Assert.Same(pair2.Value.Value, pair1.Value.Value);
}
[Fact]
@@ -178,7 +178,7 @@ namespace Microsoft.Net.Http.Headers
Assert.Equal("charset", mediaType.Parameters.First().Name);
mediaType.Charset = null;
- Assert.Null(mediaType.Charset);
+ Assert.Null(mediaType.Charset.Value);
Assert.Equal(0, mediaType.Parameters.Count);
mediaType.Charset = null; // It's OK to set it again to null; no exception.
}
@@ -200,7 +200,7 @@ namespace Microsoft.Net.Http.Headers
Assert.Equal("CHARSET", mediaType.Parameters.First().Name);
mediaType.Parameters.Remove(charset);
- Assert.Null(mediaType.Charset);
+ Assert.Null(mediaType.Charset.Value);
}
[Fact]
diff --git a/test/Microsoft.Net.Http.Headers.Tests/NameValueHeaderValueTest.cs b/test/Microsoft.Net.Http.Headers.Tests/NameValueHeaderValueTest.cs
index 9a8396f79d..8310fa2864 100644
--- a/test/Microsoft.Net.Http.Headers.Tests/NameValueHeaderValueTest.cs
+++ b/test/Microsoft.Net.Http.Headers.Tests/NameValueHeaderValueTest.cs
@@ -1,4 +1,4 @@
-// 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.
using System;
@@ -65,14 +65,14 @@ namespace Microsoft.Net.Http.Headers
var pair0 = new NameValueHeaderValue("name");
var pair1 = pair0.Copy();
Assert.NotSame(pair0, pair1);
- Assert.Same(pair0.Name, pair1.Name);
- Assert.Null(pair0.Value);
- Assert.Null(pair1.Value);
+ Assert.Same(pair0.Name.Value, pair1.Name.Value);
+ Assert.Null(pair0.Value.Value);
+ Assert.Null(pair1.Value.Value);
// Change one value and verify the other is unchanged.
pair0.Value = "othervalue";
Assert.Equal("othervalue", pair0.Value);
- Assert.Null(pair1.Value);
+ Assert.Null(pair1.Value.Value);
}
[Fact]
@@ -81,16 +81,16 @@ namespace Microsoft.Net.Http.Headers
var pair0 = new NameValueHeaderValue("name");
var pair1 = pair0.CopyAsReadOnly();
Assert.NotSame(pair0, pair1);
- Assert.Same(pair0.Name, pair1.Name);
- Assert.Null(pair0.Value);
- Assert.Null(pair1.Value);
+ Assert.Same(pair0.Name.Value, pair1.Name.Value);
+ Assert.Null(pair0.Value.Value);
+ Assert.Null(pair1.Value.Value);
Assert.False(pair0.IsReadOnly);
Assert.True(pair1.IsReadOnly);
// Change one value and verify the other is unchanged.
pair0.Value = "othervalue";
Assert.Equal("othervalue", pair0.Value);
- Assert.Null(pair1.Value);
+ Assert.Null(pair1.Value.Value);
Assert.Throws(() => { pair1.Value = "othervalue"; });
}
@@ -100,8 +100,8 @@ namespace Microsoft.Net.Http.Headers
var pair0 = new NameValueHeaderValue("name", "value");
var pair1 = pair0.Copy();
Assert.NotSame(pair0, pair1);
- Assert.Same(pair0.Name, pair1.Name);
- Assert.Same(pair0.Value, pair1.Value);
+ Assert.Same(pair0.Name.Value, pair1.Name.Value);
+ Assert.Same(pair0.Value.Value, pair1.Value.Value);
// Change one value and verify the other is unchanged.
pair0.Value = "othervalue";
@@ -115,8 +115,8 @@ namespace Microsoft.Net.Http.Headers
var pair0 = new NameValueHeaderValue("name", "value");
var pair1 = pair0.CopyAsReadOnly();
Assert.NotSame(pair0, pair1);
- Assert.Same(pair0.Name, pair1.Name);
- Assert.Same(pair0.Value, pair1.Value);
+ Assert.Same(pair0.Name.Value, pair1.Name.Value);
+ Assert.Same(pair0.Value.Value, pair1.Value.Value);
Assert.False(pair0.IsReadOnly);
Assert.True(pair1.IsReadOnly);
@@ -134,8 +134,8 @@ namespace Microsoft.Net.Http.Headers
var pair1 = pair0.CopyAsReadOnly();
var pair2 = pair1.Copy();
Assert.NotSame(pair0, pair1);
- Assert.Same(pair0.Name, pair1.Name);
- Assert.Same(pair0.Value, pair1.Value);
+ Assert.Same(pair0.Name.Value, pair1.Name.Value);
+ Assert.Same(pair0.Value.Value, pair1.Value.Value);
// Change one value and verify the other is unchanged.
pair2.Value = "othervalue";