Kaynağa Gözat

Add XML doc comments for Microsoft.Net.Http.Headers (#28415)

* Enable missing doc comments to appear as warnings when building locally.
* Update nullability bug that I noticed in RangeConditionHeaderValue
Pranav K 5 yıl önce
ebeveyn
işleme
8df66d1c16

+ 3 - 2
Directory.Build.props

@@ -100,10 +100,11 @@
 
   <!-- Warnings and errors -->
   <PropertyGroup>
+    <!-- Ensure API docs are available. -->
+    <NoWarn>$(NoWarn.Replace('1591', ''))</NoWarn>
+
     <!-- For local builds, don't make missing XML docs a fatal build error, but still surface so we have visibility into undocumented APIs. -->
     <WarningsNotAsErrors Condition=" '$(ContinuousIntegrationBuild)' != 'true' ">$(WarningsNotAsErrors);CS1591</WarningsNotAsErrors>
-    <!-- For CI builds, ensure API docs are available. -->
-    <NoWarn Condition=" '$(ContinuousIntegrationBuild)' == 'true' ">$(NoWarn.Replace('1591', ''))</NoWarn>
 
     <!-- xUnit1004 = warns about skipped tests. Make this a non-fatal build warning. -->
     <WarningsNotAsErrors>$(WarningsNotAsErrors);xUnit1004</WarningsNotAsErrors>

+ 169 - 0
src/Http/Headers/src/CacheControlHeaderValue.cs

@@ -11,19 +11,69 @@ using Microsoft.Extensions.Primitives;
 
 namespace Microsoft.Net.Http.Headers
 {
+    /// <summary>
+    /// Represents the <c>Cache-Control</c> HTTP header.
+    /// </summary>
     public class CacheControlHeaderValue
     {
+        /// <summary>
+        /// A constant for the <c>public</c> cache-control directive.
+        /// </summary>
         public static readonly string PublicString = "public";
+
+        /// <summary>
+        /// A constant for the <c>private</c> cache-control directive.
+        /// </summary>
         public static readonly string PrivateString = "private";
+
+        /// <summary>
+        /// A constant for the <c>max-age</c> cache-control directive.
+        /// </summary>
         public static readonly string MaxAgeString = "max-age";
+
+        /// <summary>
+        /// A constant for the <c>s-maxage</c> cache-control directive.
+        /// </summary>
         public static readonly string SharedMaxAgeString = "s-maxage";
+
+        /// <summary>
+        /// A constant for the <c>no-cache</c> cache-control directive.
+        /// </summary>
         public static readonly string NoCacheString = "no-cache";
+
+        /// <summary>
+        /// A constant for the <c>no-store</c> cache-control directive.
+        /// </summary>
         public static readonly string NoStoreString = "no-store";
+
+        /// <summary>
+        /// A constant for the <c>max-stale</c> cache-control directive.
+        /// </summary>
         public static readonly string MaxStaleString = "max-stale";
+
+        /// <summary>
+        /// A constant for the <c>min-fresh</c> cache-control directive.
+        /// </summary>
         public static readonly string MinFreshString = "min-fresh";
+
+        /// <summary>
+        /// A constant for the <c>no-transform</c> cache-control directive.
+        /// </summary>
         public static readonly string NoTransformString = "no-transform";
+
+        /// <summary>
+        /// A constant for the <c>only-if-cached</c> cache-control directive.
+        /// </summary>
         public static readonly string OnlyIfCachedString = "only-if-cached";
+
+        /// <summary>
+        /// A constant for the <c>must-revalidate</c> cache-control directive.
+        /// </summary>
         public static readonly string MustRevalidateString = "must-revalidate";
+
+        /// <summary>
+        /// A constant for the <c>proxy-revalidate</c> cache-control directive.
+        /// </summary>
         public static readonly string ProxyRevalidateString = "proxy-revalidate";
 
         // The Cache-Control header is special: It is a header supporting a list of values, but we represent the list
@@ -53,17 +103,31 @@ namespace Microsoft.Net.Http.Headers
         private bool _proxyRevalidate;
         private IList<NameValueHeaderValue>? _extensions;
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="CacheControlHeaderValue"/>.
+        /// </summary>
         public CacheControlHeaderValue()
         {
             // This type is unique in that there is no single required parameter.
         }
 
+        /// <summary>
+        /// Gets or sets a value for the <c>no-cache</c> directive.
+        /// <para>
+        /// Configuring no-cache indicates that the client must re-validate cached responses with the original server
+        /// before using it.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc7234#section-5.2.1.4</remarks>
         public bool NoCache
         {
             get { return _noCache; }
             set { _noCache = value; }
         }
 
+        /// <summary>
+        /// Gets a collection of field names in the "no-cache" directive in a cache-control header field on an HTTP response.
+        /// </summary>
         public ICollection<StringSegment> NoCacheHeaders
         {
             get
@@ -76,66 +140,140 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <summary>
+        /// Gets or sets a value for the <c>no-store</c> directive.
+        /// <para>
+        /// Configuring no-store indicates that the response may not be stored in any cache.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc7234#section-5.2.1.5</remarks>
         public bool NoStore
         {
             get { return _noStore; }
             set { _noStore = value; }
         }
 
+        /// <summary>
+        /// Gets or sets a value for the <c>max-age</c> directive.
+        /// <para>
+        /// max-age specifies the maximum amount of time the response is considered fresh.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc7234#section-5.2.1.1</remarks>
         public TimeSpan? MaxAge
         {
             get { return _maxAge; }
             set { _maxAge = value; }
         }
 
+        /// <summary>
+        /// Gets or sets a value for the <c>s-maxage</c> directive.
+        /// <para>
+        /// Overrides <see cref="MaxAge">max-age</see>, but only for shared caches (such as proxies).
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc7234#section-5.2.2.9</remarks>
         public TimeSpan? SharedMaxAge
         {
             get { return _sharedMaxAge; }
             set { _sharedMaxAge = value; }
         }
 
+        /// <summary>
+        /// Gets or sets a value that determines if the <c>max-stale</c> is included.
+        /// <para>
+        /// <c>max-stale</c> that the client will accept stale responses. The maximum tolerance for staleness
+        /// is specified by <see cref="MaxStaleLimit"/>.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc7234#section-5.2.1.2</remarks>
         public bool MaxStale
         {
             get { return _maxStale; }
             set { _maxStale = value; }
         }
 
+        /// <summary>
+        /// Gets or sets a value for the <c>max-stale</c> directive.
+        /// <para>
+        /// Indicates the maximum duration an HTTP client is willing to accept a response that has exceeded its expiration time.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc7234#section-5.2.1.2</remarks>
         public TimeSpan? MaxStaleLimit
         {
             get { return _maxStaleLimit; }
             set { _maxStaleLimit = value; }
         }
 
+        /// <summary>
+        /// Gets or sets a value for the <c>min-fresh</c> directive.
+        /// <para>
+        /// Indicates the freshness lifetime that an HTTP client is willing to accept a response.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc7234#section-5.2.1.3</remarks>
         public TimeSpan? MinFresh
         {
             get { return _minFresh; }
             set { _minFresh = value; }
         }
 
+        /// <summary>
+        /// Gets or sets a value for the <c>no-transform</c> request directive.
+        /// <para>
+        /// Forbids intermediate caches or proxies from editing the response payload.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc7234#section-5.2.1.6</remarks>
         public bool NoTransform
         {
             get { return _noTransform; }
             set { _noTransform = value; }
         }
 
+        /// <summary>
+        /// Gets or sets a value for the <c>only-if-cached</c> request directive.
+        /// <para>
+        /// Indicates that the client only wishes to obtain a stored response
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc7234#section-5.2.1.7</remarks>
         public bool OnlyIfCached
         {
             get { return _onlyIfCached; }
             set { _onlyIfCached = value; }
         }
 
+        /// <summary>
+        /// Gets or sets a value that determines if the <c>public</c> response directive is included.
+        /// <para>
+        /// Indicates that the response may be stored by any cache.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc7234#section-5.2.2.5</remarks>
         public bool Public
         {
             get { return _public; }
             set { _public = value; }
         }
 
+        /// <summary>
+        /// Gets or sets a value that determines if the <c>private</c> response directive is included.
+        /// <para>
+        /// Indicates that the response may not be stored by a shared cache.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc7234#section-5.2.2.6</remarks>
         public bool Private
         {
             get { return _private; }
             set { _private = value; }
         }
 
+        /// <summary>
+        /// Gets a collection of field names in the "private" directive in a cache-control header field on an HTTP response.
+        /// </summary>
         public ICollection<StringSegment> PrivateHeaders
         {
             get
@@ -148,18 +286,35 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <summary>
+        /// Gets or sets a value that determines if the <c>must-revalidate</c> response directive is included.
+        /// <para>
+        /// Indicates that caches must revalidate the use of stale caches with the origin server before their use.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc7234#section-5.2.2.1</remarks>
         public bool MustRevalidate
         {
             get { return _mustRevalidate; }
             set { _mustRevalidate = value; }
         }
 
+        /// <summary>
+        /// Gets or sets a value that determines if the <c>proxy-validate</c> response directive is included.
+        /// <para>
+        /// Indicates that shared caches must revalidate the use of stale caches with the origin server before their use.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc7234#section-5.2.2.1</remarks>
         public bool ProxyRevalidate
         {
             get { return _proxyRevalidate; }
             set { _proxyRevalidate = value; }
         }
 
+        /// <summary>
+        /// Gets cache-extension tokens, each with an optional assigned value.
+        /// </summary>
         public IList<NameValueHeaderValue> Extensions
         {
             get
@@ -172,6 +327,7 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <inheritdoc />
         public override string ToString()
         {
             var sb = new StringBuilder();
@@ -241,6 +397,7 @@ namespace Microsoft.Net.Http.Headers
             return sb.ToString();
         }
 
+        /// <inheritdoc />
         public override bool Equals(object? obj)
         {
             var other = obj as CacheControlHeaderValue;
@@ -280,6 +437,7 @@ namespace Microsoft.Net.Http.Headers
             return true;
         }
 
+        /// <inheritdoc />
         public override int GetHashCode()
         {
             // Use a different bit for bool fields: bool.GetHashCode() will return 0 (false) or 1 (true). So we would
@@ -324,6 +482,11 @@ namespace Microsoft.Net.Http.Headers
             return result;
         }
 
+        /// <summary>
+        /// Parses <paramref name="input"/> as a <see cref="CacheControlHeaderValue"/> value.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static CacheControlHeaderValue Parse(StringSegment input)
         {
             var index = 0;
@@ -336,6 +499,12 @@ namespace Microsoft.Net.Http.Headers
             return result;
         }
 
+        /// <summary>
+        /// Attempts to parse the specified <paramref name="input"/> as a <see cref="CacheControlHeaderValue"/>.
+        /// </summary>
+        /// <param name="input">The value to parse.</param>
+        /// <param name="parsedValue">The parsed value.</param>
+        /// <returns><see langword="true"/> if input is a valid <see cref="SetCookieHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParse(StringSegment input, [NotNullWhen(true)] out CacheControlHeaderValue? parsedValue)
         {
             var index = 0;

+ 53 - 2
src/Http/Headers/src/ContentDispositionHeaderValue.cs

@@ -13,7 +13,12 @@ using Microsoft.Extensions.Primitives;
 
 namespace Microsoft.Net.Http.Headers
 {
-    // Note this is for use both in HTTP (https://tools.ietf.org/html/rfc6266) and MIME (https://tools.ietf.org/html/rfc2183)
+    /// <summary>
+    /// Represents the value of a <c>Content-Disposition</c> header.
+    /// </summary>
+    /// <remarks>
+    /// Note this is for use both in HTTP (https://tools.ietf.org/html/rfc6266) and MIME (https://tools.ietf.org/html/rfc2183)
+    /// </remarks>
     public class ContentDispositionHeaderValue
     {
         private const string FileNameString = "filename";
@@ -38,12 +43,19 @@ namespace Microsoft.Net.Http.Headers
             // Used by the parser to create a new instance of this type.
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="ContentDispositionHeaderValue"/>.
+        /// </summary>
+        /// <param name="dispositionType">A <see cref="StringSegment"/> that represents a content disposition type.</param>
         public ContentDispositionHeaderValue(StringSegment dispositionType)
         {
             CheckDispositionTypeFormat(dispositionType, "dispositionType");
             _dispositionType = dispositionType;
         }
 
+        /// <summary>
+        /// Gets or sets a content disposition type.
+        /// </summary>
         public StringSegment DispositionType
         {
             get { return _dispositionType; }
@@ -54,6 +66,9 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <summary>
+        /// Gets a collection of parameters included the <c>Content-Disposition</c> header.
+        /// </summary>
         public IList<NameValueHeaderValue> Parameters
         {
             get
@@ -68,43 +83,65 @@ namespace Microsoft.Net.Http.Headers
 
         // Helpers to access specific parameters in the list
 
+        /// <summary>
+        /// Gets or sets the name of the content body part.
+        /// </summary>
         public StringSegment Name
         {
             get { return GetName(NameString); }
             set { SetName(NameString, value); }
         }
 
-
+        /// <summary>
+        /// Gets or sets a value that suggests how to construct a filename for storing the message payload
+        /// to be used if the entity is detached and stored in a separate file.
+        /// </summary>
         public StringSegment FileName
         {
             get { return GetName(FileNameString); }
             set { SetName(FileNameString, value); }
         }
 
+        /// <summary>
+        /// Gets or sets a value that suggests how to construct filenames for storing message payloads
+        /// to be used if the entities are detached and stored in a separate files.
+        /// </summary>
         public StringSegment FileNameStar
         {
             get { return GetName(FileNameStarString); }
             set { SetName(FileNameStarString, value); }
         }
 
+        /// <summary>
+        /// Gets or sets the <see cref="DateTimeOffset"/> at which the file was created.
+        /// </summary>
         public DateTimeOffset? CreationDate
         {
             get { return GetDate(CreationDateString); }
             set { SetDate(CreationDateString, value); }
         }
 
+        /// <summary>
+        /// Gets or sets the <see cref="DateTimeOffset"/> at which the file was last modified.
+        /// </summary>
         public DateTimeOffset? ModificationDate
         {
             get { return GetDate(ModificationDateString); }
             set { SetDate(ModificationDateString, value); }
         }
 
+        /// <summary>
+        /// Gets or sets the <see cref="DateTimeOffset"/> at which the file was last read.
+        /// </summary>
         public DateTimeOffset? ReadDate
         {
             get { return GetDate(ReadDateString); }
             set { SetDate(ReadDateString, value); }
         }
 
+        /// <summary>
+        /// Gets or sets the approximate size, in bytes, of the file.
+        /// </summary>
         public long? Size
         {
             get
@@ -175,11 +212,13 @@ namespace Microsoft.Net.Http.Headers
             FileName = fileName;
         }
 
+        /// <inheritdoc />
         public override string ToString()
         {
             return _dispositionType + NameValueHeaderValue.ToString(_parameters, ';', true);
         }
 
+        /// <inheritdoc />
         public override bool Equals(object? obj)
         {
             var other = obj as ContentDispositionHeaderValue;
@@ -193,18 +232,30 @@ namespace Microsoft.Net.Http.Headers
                 HeaderUtilities.AreEqualCollections(_parameters, other._parameters);
         }
 
+        /// <inheritdoc />
         public override int GetHashCode()
         {
             // The dispositionType string is case-insensitive.
             return StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_dispositionType) ^ NameValueHeaderValue.GetHashCode(_parameters);
         }
 
+        /// <summary>
+        /// Parses <paramref name="input"/> as a <see cref="ContentDispositionHeaderValue"/> value.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static ContentDispositionHeaderValue Parse(StringSegment input)
         {
             var index = 0;
             return Parser.ParseValue(input, ref index)!;
         }
 
+        /// <summary>
+        /// Attempts to parse the specified <paramref name="input"/> as a <see cref="ContentDispositionHeaderValue"/>.
+        /// </summary>
+        /// <param name="input">The value to parse.</param>
+        /// <param name="parsedValue">The parsed value.</param>
+        /// <returns><see langword="true"/> if input is a valid <see cref="ContentDispositionHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParse(StringSegment input, [NotNullWhen(true)] out ContentDispositionHeaderValue? parsedValue)
         {
             var index = 0;

+ 80 - 38
src/Http/Headers/src/ContentRangeHeaderValue.cs

@@ -10,21 +10,27 @@ using Microsoft.Extensions.Primitives;
 
 namespace Microsoft.Net.Http.Headers
 {
+    /// <summary>
+    /// Represents a <c>Content-Range</c> response HTTP header.
+    /// </summary>
     public class ContentRangeHeaderValue
     {
         private static readonly HttpHeaderParser<ContentRangeHeaderValue> Parser
             = new GenericHeaderParser<ContentRangeHeaderValue>(false, GetContentRangeLength);
 
         private StringSegment _unit;
-        private long? _from;
-        private long? _to;
-        private long? _length;
 
         private ContentRangeHeaderValue()
         {
             // Used by the parser to create a new instance of this type.
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="ContentRangeHeaderValue"/>.
+        /// </summary>
+        /// <param name="from">The start of the range.</param>
+        /// <param name="to">The end of the range.</param>
+        /// <param name="length">The total size of the document in bytes.</param>
         public ContentRangeHeaderValue(long from, long to, long length)
         {
             // Scenario: "Content-Range: bytes 12-34/5678"
@@ -42,12 +48,16 @@ namespace Microsoft.Net.Http.Headers
                 throw new ArgumentOutOfRangeException(nameof(from));
             }
 
-            _from = from;
-            _to = to;
-            _length = length;
+            From = from;
+            To = to;
+            Length = length;
             _unit = HeaderUtilities.BytesUnit;
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="ContentRangeHeaderValue"/>.
+        /// </summary>
+        /// <param name="length">The total size of the document in bytes.</param>
         public ContentRangeHeaderValue(long length)
         {
             // Scenario: "Content-Range: bytes */1234"
@@ -57,10 +67,15 @@ namespace Microsoft.Net.Http.Headers
                 throw new ArgumentOutOfRangeException(nameof(length));
             }
 
-            _length = length;
+            Length = length;
             _unit = HeaderUtilities.BytesUnit;
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="ContentRangeHeaderValue"/>.
+        /// </summary>
+        /// <param name="from">The start of the range.</param>
+        /// <param name="to">The end of the range.</param>
         public ContentRangeHeaderValue(long from, long to)
         {
             // Scenario: "Content-Range: bytes 12-34/*"
@@ -74,11 +89,15 @@ namespace Microsoft.Net.Http.Headers
                 throw new ArgumentOutOfRangeException(nameof(@from));
             }
 
-            _from = from;
-            _to = to;
+            From = from;
+            To = to;
             _unit = HeaderUtilities.BytesUnit;
         }
 
+        /// <summary>
+        /// Gets or sets the unit in which ranges are specified.
+        /// </summary>
+        /// <value>Defaults to <c>bytes</c>.</value>
         public StringSegment Unit
         {
             get { return _unit; }
@@ -89,31 +108,41 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
-        public long? From
-        {
-            get { return _from; }
-        }
-
-        public long? To
-        {
-            get { return _to; }
-        }
-
-        public long? Length
-        {
-            get { return _length; }
-        }
-
+        /// <summary>
+        /// Gets the start of the range.
+        /// </summary>
+        public long? From { get; private set; }
+
+        /// <summary>
+        /// Gets the end of the range.
+        /// </summary>
+        public long? To { get; private set; }
+
+        /// <summary>
+        /// Gets the total size of the document.
+        /// </summary>
+        [NotNullIfNotNull(nameof(Length))]
+        public long? Length { get; private set; }
+
+        /// <summary>
+        /// Gets a value that determines if <see cref="Length"/> has been specified.
+        /// </summary>
+        [MemberNotNullWhen(true, nameof(Length))]
         public bool HasLength // e.g. "Content-Range: bytes 12-34/*"
         {
-            get { return _length != null; }
+            get { return Length != null; }
         }
 
+        /// <summary>
+        /// Gets a value that determines if <see cref="From"/> and <see cref="To"/> have been specified.
+        /// </summary>
+        [MemberNotNullWhen(true, nameof(From), nameof(To))]
         public bool HasRange // e.g. "Content-Range: bytes */1234"
         {
-            get { return _from != null; }
+            get { return From != null && To != null; }
         }
 
+        /// <inheritdoc/>
         public override bool Equals(object? obj)
         {
             var other = obj as ContentRangeHeaderValue;
@@ -123,38 +152,40 @@ namespace Microsoft.Net.Http.Headers
                 return false;
             }
 
-            return ((_from == other._from) && (_to == other._to) && (_length == other._length) &&
-                StringSegment.Equals(_unit, other._unit, StringComparison.OrdinalIgnoreCase));
+            return ((From == other.From) && (To == other.To) && (Length == other.Length) &&
+                StringSegment.Equals(Unit, other.Unit, StringComparison.OrdinalIgnoreCase));
         }
 
+        /// <inheritdoc/>
         public override int GetHashCode()
         {
-            var result = StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_unit);
+            var result = StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(Unit);
 
             if (HasRange)
             {
-                result = result ^ _from.GetHashCode() ^ _to.GetHashCode();
+                result = result ^ From.GetHashCode() ^ To.GetHashCode();
             }
 
             if (HasLength)
             {
-                result = result ^ _length.GetHashCode();
+                result = result ^ Length.GetHashCode();
             }
 
             return result;
         }
 
+        /// <inheritdoc/>
         public override string ToString()
         {
             var sb = new StringBuilder();
-            sb.Append(_unit.AsSpan());
+            sb.Append(Unit.AsSpan());
             sb.Append(' ');
 
             if (HasRange)
             {
-                sb.Append(_from.GetValueOrDefault().ToString(NumberFormatInfo.InvariantInfo));
+                sb.Append(From.GetValueOrDefault().ToString(NumberFormatInfo.InvariantInfo));
                 sb.Append('-');
-                sb.Append(_to.GetValueOrDefault().ToString(NumberFormatInfo.InvariantInfo));
+                sb.Append(To.GetValueOrDefault().ToString(NumberFormatInfo.InvariantInfo));
             }
             else
             {
@@ -164,7 +195,7 @@ namespace Microsoft.Net.Http.Headers
             sb.Append('/');
             if (HasLength)
             {
-                sb.Append(_length.GetValueOrDefault().ToString(NumberFormatInfo.InvariantInfo));
+                sb.Append(Length.GetValueOrDefault().ToString(NumberFormatInfo.InvariantInfo));
             }
             else
             {
@@ -174,12 +205,23 @@ namespace Microsoft.Net.Http.Headers
             return sb.ToString();
         }
 
+        /// <summary>
+        /// Parses <paramref name="input"/> as a <see cref="ContentRangeHeaderValue"/> value.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static ContentRangeHeaderValue Parse(StringSegment input)
         {
             var index = 0;
             return Parser.ParseValue(input, ref index)!;
         }
 
+        /// <summary>
+        /// Attempts to parse the specified <paramref name="input"/> as a <see cref="ContentRangeHeaderValue"/>.
+        /// </summary>
+        /// <param name="input">The value to parse.</param>
+        /// <param name="parsedValue">The parsed value.</param>
+        /// <returns><see langword="true"/> if input is a valid <see cref="ContentRangeHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParse(StringSegment input, [NotNullWhen(true)] out ContentRangeHeaderValue parsedValue)
         {
             var index = 0;
@@ -392,13 +434,13 @@ namespace Microsoft.Net.Http.Headers
 
             if (fromLength > 0)
             {
-                result._from = from;
-                result._to = to;
+                result.From = from;
+                result.To = to;
             }
 
             if (lengthLength > 0)
             {
-                result._length = length;
+                result.Length = length;
             }
 
             parsedValue = result;

+ 54 - 0
src/Http/Headers/src/CookieHeaderValue.cs

@@ -11,6 +11,9 @@ using Microsoft.Extensions.Primitives;
 namespace Microsoft.Net.Http.Headers
 {
     // http://tools.ietf.org/html/rfc6265
+    /// <summary>
+    /// Represents the HTTP request <c>Cookie</c> header.
+    /// </summary>
     public class CookieHeaderValue
     {
         private static readonly CookieHeaderParser SingleValueParser = new CookieHeaderParser(supportsMultipleValues: false);
@@ -24,6 +27,10 @@ namespace Microsoft.Net.Http.Headers
             // Used by the parser to create a new instance of this type.
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="CookieHeaderValue"/>.
+        /// </summary>
+        /// <param name="name">The cookie name.</param>
         public CookieHeaderValue(StringSegment name)
             : this(name, StringSegment.Empty)
         {
@@ -33,6 +40,11 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="CookieHeaderValue"/>.
+        /// </summary>
+        /// <param name="name">The cookie name.</param>
+        /// <param name="value">The cookie value.</param>
         public CookieHeaderValue(StringSegment name, StringSegment value)
         {
             if (name == null)
@@ -49,6 +61,9 @@ namespace Microsoft.Net.Http.Headers
             Value = value;
         }
 
+        /// <summary>
+        /// Gets or sets the cookie name.
+        /// </summary>
         public StringSegment Name
         {
             get { return _name; }
@@ -59,6 +74,9 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <summary>
+        /// Gets or sets the cookie value.
+        /// </summary>
         public StringSegment Value
         {
             get { return _value; }
@@ -69,6 +87,7 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <inheritdoc />
         // name="val ue";
         public override string ToString()
         {
@@ -81,33 +100,66 @@ namespace Microsoft.Net.Http.Headers
             return header.ToString();
         }
 
+        /// <summary>
+        /// Parses <paramref name="input"/> as a <see cref="CookieHeaderValue"/> value.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static CookieHeaderValue Parse(StringSegment input)
         {
             var index = 0;
             return SingleValueParser.ParseValue(input, ref index)!;
         }
 
+        /// <summary>
+        /// Attempts to parse the specified <paramref name="input"/> as a <see cref="CookieHeaderValue"/>.
+        /// </summary>
+        /// <param name="input">The value to parse.</param>
+        /// <param name="parsedValue">The parsed value.</param>
+        /// <returns><see langword="true"/> if input is a valid <see cref="CookieHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParse(StringSegment input, [NotNullWhen(true)] out CookieHeaderValue? parsedValue)
         {
             var index = 0;
             return SingleValueParser.TryParseValue(input, ref index, out parsedValue!);
         }
 
+        /// <summary>
+        /// Parses a sequence of inputs as a sequence of <see cref="CookieHeaderValue"/> values.
+        /// </summary>
+        /// <param name="inputs">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static IList<CookieHeaderValue> ParseList(IList<string>? inputs)
         {
             return MultipleValueParser.ParseValues(inputs);
         }
 
+        /// <summary>
+        /// Parses a sequence of inputs as a sequence of <see cref="CookieHeaderValue"/> values using string parsing rules.
+        /// </summary>
+        /// <param name="inputs">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static IList<CookieHeaderValue> ParseStrictList(IList<string>? inputs)
         {
             return MultipleValueParser.ParseStrictValues(inputs);
         }
 
+        /// <summary>
+        /// Attempts to parse the sequence of values as a sequence of <see cref="CookieHeaderValue"/>.
+        /// </summary>
+        /// <param name="inputs">The values to parse.</param>
+        /// <param name="parsedValues">The parsed values.</param>
+        /// <returns><see langword="true"/> if all inputs are valid <see cref="CookieHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParseList(IList<string>? inputs, [NotNullWhen(true)] out IList<CookieHeaderValue>? parsedValues)
         {
             return MultipleValueParser.TryParseValues(inputs, out parsedValues);
         }
 
+        /// <summary>
+        /// Attempts to parse the sequence of values as a sequence of <see cref="CookieHeaderValue"/> using string parsing rules.
+        /// </summary>
+        /// <param name="inputs">The values to parse.</param>
+        /// <param name="parsedValues">The parsed values.</param>
+        /// <returns><see langword="true"/> if all inputs are valid <see cref="StringWithQualityHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParseStrictList(IList<string>? inputs, [NotNullWhen(true)] out IList<CookieHeaderValue>? parsedValues)
         {
             return MultipleValueParser.TryParseStrictValues(inputs, out parsedValues);
@@ -256,6 +308,7 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <inheritdoc />
         public override bool Equals(object? obj)
         {
             var other = obj as CookieHeaderValue;
@@ -269,6 +322,7 @@ namespace Microsoft.Net.Http.Headers
                 && StringSegment.Equals(_value, other._value, StringComparison.OrdinalIgnoreCase);
         }
 
+        /// <inheritdoc />
         public override int GetHashCode()
         {
             return _name.GetHashCode() ^ _value.GetHashCode();

+ 62 - 34
src/Http/Headers/src/EntityTagHeaderValue.cs

@@ -9,6 +9,9 @@ using Microsoft.Extensions.Primitives;
 
 namespace Microsoft.Net.Http.Headers
 {
+    /// <summary>
+    /// Represents an entity-tag (<c>etag</c>) header value.
+    /// </summary>
     public class EntityTagHeaderValue
     {
         // Note that the ETag header does not allow a * but we're not that strict: We allow both '*' and ETag values in a single value.
@@ -22,8 +25,6 @@ namespace Microsoft.Net.Http.Headers
         private static readonly HttpHeaderParser<EntityTagHeaderValue> MultipleValueParser
             = new GenericHeaderParser<EntityTagHeaderValue>(true, GetEntityTagLength);
 
-        private static EntityTagHeaderValue? AnyType;
-
         private StringSegment _tag;
         private bool _isWeak;
 
@@ -32,11 +33,20 @@ namespace Microsoft.Net.Http.Headers
             // Used by the parser to create a new instance of this type.
         }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="EntityTagHeaderValue"/>.
+        /// </summary>
+        /// <param name="tag">A <see cref="StringSegment"/> that contains an <see cref="EntityTagHeaderValue"/>.</param>
         public EntityTagHeaderValue(StringSegment tag)
-            : this(tag, false)
+            : this(tag, isWeak: false)
         {
         }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="EntityTagHeaderValue"/>.
+        /// </summary>
+        /// <param name="tag">A <see cref="StringSegment"/> that contains an <see cref="EntityTagHeaderValue"/>.</param>
+        /// <param name="isWeak">A value that indicates if this entity-tag header is a weak validator.</param>
         public EntityTagHeaderValue(StringSegment tag, bool isWeak)
         {
             if (StringSegment.IsNullOrEmpty(tag))
@@ -44,13 +54,12 @@ namespace Microsoft.Net.Http.Headers
                 throw new ArgumentException("An empty string is not allowed.", nameof(tag));
             }
 
-            int length = 0;
             if (!isWeak && StringSegment.Equals(tag, "*", StringComparison.Ordinal))
             {
                 // * is valid, but W/* isn't.
                 _tag = tag;
             }
-            else if ((HttpRuleParser.GetQuotedStringLength(tag, 0, out length) != HttpParseResult.Parsed) ||
+            else if ((HttpRuleParser.GetQuotedStringLength(tag, 0, out var length) != HttpParseResult.Parsed) ||
                 (length != tag.Length))
             {
                 // Note that we don't allow 'W/' prefixes for weak ETags in the 'tag' parameter. If the user wants to
@@ -62,30 +71,22 @@ namespace Microsoft.Net.Http.Headers
             _isWeak = isWeak;
         }
 
-        public static EntityTagHeaderValue Any
-        {
-            get
-            {
-                if (AnyType == null)
-                {
-                    AnyType = new EntityTagHeaderValue();
-                    AnyType._tag = "*";
-                    AnyType._isWeak = false;
-                }
-                return AnyType;
-            }
-        }
+        /// <summary>
+        /// Gets the "any" etag.
+        /// </summary>
+        public static EntityTagHeaderValue Any { get; } = new EntityTagHeaderValue("*", isWeak: false);
 
-        public StringSegment Tag
-        {
-            get { return _tag; }
-        }
+        /// <summary>
+        /// Gets the quoted tag.
+        /// </summary>
+        public StringSegment Tag => _tag;
 
-        public bool IsWeak
-        {
-            get { return _isWeak; }
-        }
+        /// <summary>
+        /// Gets a value that determines if the entity-tag header is a weak validator.
+        /// </summary>
+        public bool IsWeak => _isWeak;
 
+        /// <inheritdoc />
         public override string ToString()
         {
             if (_isWeak)
@@ -106,17 +107,11 @@ namespace Microsoft.Net.Http.Headers
         /// </returns>
         public override bool Equals(object? obj)
         {
-            var other = obj as EntityTagHeaderValue;
-
-            if (other == null)
-            {
-                return false;
-            }
-
             // Since the tag is a quoted-string we treat it case-sensitive.
-            return _isWeak == other._isWeak && StringSegment.Equals(_tag, other._tag, StringComparison.Ordinal);
+            return obj is EntityTagHeaderValue other && _isWeak == other._isWeak && StringSegment.Equals(_tag, other._tag, StringComparison.Ordinal);
         }
 
+        /// <inheritdoc />
         public override int GetHashCode()
         {
             // Since the tag is a quoted-string we treat it case-sensitive.
@@ -149,33 +144,66 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <summary>
+        /// Parses <paramref name="input"/> as a <see cref="EntityTagHeaderValue"/> value.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static EntityTagHeaderValue Parse(StringSegment input)
         {
             var index = 0;
             return SingleValueParser.ParseValue(input, ref index)!;
         }
 
+        /// <summary>
+        /// Attempts to parse the specified <paramref name="input"/> as a <see cref="EntityTagHeaderValue"/>.
+        /// </summary>
+        /// <param name="input">The value to parse.</param>
+        /// <param name="parsedValue">The parsed value.</param>
+        /// <returns><see langword="true"/> if input is a valid <see cref="EntityTagHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParse(StringSegment input, [NotNullWhen(true)] out EntityTagHeaderValue parsedValue)
         {
             var index = 0;
             return SingleValueParser.TryParseValue(input, ref index, out parsedValue!);
         }
 
+        /// <summary>
+        /// Parses a sequence of inputs as a sequence of <see cref="EntityTagHeaderValue"/> values.
+        /// </summary>
+        /// <param name="inputs">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static IList<EntityTagHeaderValue> ParseList(IList<string>? inputs)
         {
             return MultipleValueParser.ParseValues(inputs);
         }
 
+        /// <summary>
+        /// Parses a sequence of inputs as a sequence of <see cref="EntityTagHeaderValue"/> values using string parsing rules.
+        /// </summary>
+        /// <param name="inputs">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static IList<EntityTagHeaderValue> ParseStrictList(IList<string>? inputs)
         {
             return MultipleValueParser.ParseStrictValues(inputs);
         }
 
+        /// <summary>
+        /// Attempts to parse the sequence of values as a sequence of <see cref="EntityTagHeaderValue"/>.
+        /// </summary>
+        /// <param name="inputs">The values to parse.</param>
+        /// <param name="parsedValues">The parsed values.</param>
+        /// <returns><see langword="true"/> if all inputs are valid <see cref="EntityTagHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParseList(IList<string>? inputs, [NotNullWhen(true)] out IList<EntityTagHeaderValue>? parsedValues)
         {
             return MultipleValueParser.TryParseValues(inputs, out parsedValues);
         }
 
+        /// <summary>
+        /// Attempts to parse the sequence of values as a sequence of <see cref="EntityTagHeaderValue"/> using string parsing rules.
+        /// </summary>
+        /// <param name="inputs">The values to parse.</param>
+        /// <param name="parsedValues">The parsed values.</param>
+        /// <returns><see langword="true"/> if all inputs are valid <see cref="EntityTagHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParseStrictList(IList<string>? inputs, [NotNullWhen(true)] out IList<EntityTagHeaderValue>? parsedValues)
         {
             return MultipleValueParser.TryParseStrictValues(inputs, out parsedValues);

+ 181 - 0
src/Http/Headers/src/HeaderNames.cs

@@ -3,97 +3,278 @@
 
 namespace Microsoft.Net.Http.Headers
 {
+    /// <summary>
+    /// Defines cnstants for well-known HTTP headers.
+    /// </summary>
     public static class HeaderNames
     {
         // Use readonly statics rather than constants so ReferenceEquals works
+
+        /// <summary>Gets the <c>Accept</c> HTTP header name.</summary>
         public static readonly string Accept = "Accept";
+
+        /// <summary>Gets the <c>Accept-Charset</c> HTTP header name.</summary>
         public static readonly string AcceptCharset = "Accept-Charset";
+
+        /// <summary>Gets the <c>Accept-Encoding</c> HTTP header name.</summary>
         public static readonly string AcceptEncoding = "Accept-Encoding";
+
+        /// <summary>Gets the <c>Accept-Language</c> HTTP header name.</summary>
         public static readonly string AcceptLanguage = "Accept-Language";
+
+        /// <summary>Gets the <c>Accept-Ranges</c> HTTP header name.</summary>
         public static readonly string AcceptRanges = "Accept-Ranges";
+
+        /// <summary>Gets the <c>Access-Control-Allow-Credentials</c> HTTP header name.</summary>
         public static readonly string AccessControlAllowCredentials = "Access-Control-Allow-Credentials";
+
+        /// <summary>Gets the <c>Access-Control-Allow-Headers</c> HTTP header name.</summary>
         public static readonly string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
+
+        /// <summary>Gets the <c>Access-Control-Allow-Methods</c> HTTP header name.</summary>
         public static readonly string AccessControlAllowMethods = "Access-Control-Allow-Methods";
+
+        /// <summary>Gets the <c>Access-Control-Allow-Origin</c> HTTP header name.</summary>
         public static readonly string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
+
+        /// <summary>Gets the <c>Access-Control-Expose-Headers</c> HTTP header name.</summary>
         public static readonly string AccessControlExposeHeaders = "Access-Control-Expose-Headers";
+
+        /// <summary>Gets the <c>Access-Control-Max-Age</c> HTTP header name.</summary>
         public static readonly string AccessControlMaxAge = "Access-Control-Max-Age";
+
+        /// <summary>Gets the <c>Access-Control-Request-Headers</c> HTTP header name.</summary>
         public static readonly string AccessControlRequestHeaders = "Access-Control-Request-Headers";
+
+        /// <summary>Gets the <c>Access-Control-Request-Method</c> HTTP header name.</summary>
         public static readonly string AccessControlRequestMethod = "Access-Control-Request-Method";
+
+        /// <summary>Gets the <c>Age</c> HTTP header name.</summary>
         public static readonly string Age = "Age";
+
+        /// <summary>Gets the <c>Allow</c> HTTP header name.</summary>
         public static readonly string Allow = "Allow";
+
+        /// <summary>Gets the <c>Alt-Svc</c> HTTP header name.</summary>
         public static readonly string AltSvc = "Alt-Svc";
+
+        /// <summary>Gets the <c>:authority</c> HTTP header name.</summary>
         public static readonly string Authority = ":authority";
+
+        /// <summary>Gets the <c>Authorization</c> HTTP header name.</summary>
         public static readonly string Authorization = "Authorization";
+
+        /// <summary>Gets the <c>Cache-Control</c> HTTP header name.</summary>
         public static readonly string CacheControl = "Cache-Control";
+
+        /// <summary>Gets the <c>Connection</c> HTTP header name.</summary>
         public static readonly string Connection = "Connection";
+
+        /// <summary>Gets the <c>Content-Disposition</c> HTTP header name.</summary>
         public static readonly string ContentDisposition = "Content-Disposition";
+
+        /// <summary>Gets the <c>Content-Encoding</c> HTTP header name.</summary>
         public static readonly string ContentEncoding = "Content-Encoding";
+
+        /// <summary>Gets the <c>Content-Language</c> HTTP header name.</summary>
         public static readonly string ContentLanguage = "Content-Language";
+
+        /// <summary>Gets the <c>Content-Length</c> HTTP header name.</summary>
         public static readonly string ContentLength = "Content-Length";
+
+        /// <summary>Gets the <c>Content-Location</c> HTTP header name.</summary>
         public static readonly string ContentLocation = "Content-Location";
+
+        /// <summary>Gets the <c>Content-MD5</c> HTTP header name.</summary>
         public static readonly string ContentMD5 = "Content-MD5";
+
+        /// <summary>Gets the <c>Content-Range</c> HTTP header name.</summary>
         public static readonly string ContentRange = "Content-Range";
+
+        /// <summary>Gets the <c>Content-Security-Policy</c> HTTP header name.</summary>
         public static readonly string ContentSecurityPolicy = "Content-Security-Policy";
+
+        /// <summary>Gets the <c>Content-Security-Policy-Report-Only</c> HTTP header name.</summary>
         public static readonly string ContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only";
+
+        /// <summary>Gets the <c>Content-Type</c> HTTP header name.</summary>
         public static readonly string ContentType = "Content-Type";
+
+        /// <summary>Gets the <c>Correlation-Context</c> HTTP header name.</summary>
         public static readonly string CorrelationContext = "Correlation-Context";
+
+        /// <summary>Gets the <c>Cookie</c> HTTP header name.</summary>
         public static readonly string Cookie = "Cookie";
+
+        /// <summary>Gets the <c>Date</c> HTTP header name.</summary>
         public static readonly string Date = "Date";
+
+        /// <summary>Gets the <c>DNT</c> HTTP header name.</summary>
         public static readonly string DNT = "DNT";
+
+        /// <summary>Gets the <c>ETag</c> HTTP header name.</summary>
         public static readonly string ETag = "ETag";
+
+        /// <summary>Gets the <c>Expires</c> HTTP header name.</summary>
         public static readonly string Expires = "Expires";
+
+        /// <summary>Gets the <c>Expect</c> HTTP header name.</summary>
         public static readonly string Expect = "Expect";
+
+        /// <summary>Gets the <c>From</c> HTTP header name.</summary>
         public static readonly string From = "From";
+
+        /// <summary>Gets the <c>Grpc-Accept-Encoding</c> HTTP header name.</summary>
         public static readonly string GrpcAcceptEncoding = "Grpc-Accept-Encoding";
+
+        /// <summary>Gets the <c>Grpc-Encoding</c> HTTP header name.</summary>
         public static readonly string GrpcEncoding = "Grpc-Encoding";
+
+        /// <summary>Gets the <c>Grpc-Message</c> HTTP header name.</summary>
         public static readonly string GrpcMessage = "Grpc-Message";
+
+        /// <summary>Gets the <c>Grpc-Status</c> HTTP header name.</summary>
         public static readonly string GrpcStatus = "Grpc-Status";
+
+        /// <summary>Gets the <c>Grpc-Timeout</c> HTTP header name.</summary>
         public static readonly string GrpcTimeout = "Grpc-Timeout";
+
+        /// <summary>Gets the <c>Host</c> HTTP header name.</summary>
         public static readonly string Host = "Host";
+
+        /// <summary>Gets the <c>Keep-Alive</c> HTTP header name.</summary>
         public static readonly string KeepAlive = "Keep-Alive";
+
+        /// <summary>Gets the <c>If-Match</c> HTTP header name.</summary>
         public static readonly string IfMatch = "If-Match";
+
+        /// <summary>Gets the <c>If-Modified-Since</c> HTTP header name.</summary>
         public static readonly string IfModifiedSince = "If-Modified-Since";
+
+        /// <summary>Gets the <c>If-None-Match</c> HTTP header name.</summary>
         public static readonly string IfNoneMatch = "If-None-Match";
+
+        /// <summary>Gets the <c>If-Range</c> HTTP header name.</summary>
         public static readonly string IfRange = "If-Range";
+
+        /// <summary>Gets the <c>If-Unmodified-Since</c> HTTP header name.</summary>
         public static readonly string IfUnmodifiedSince = "If-Unmodified-Since";
+
+        /// <summary>Gets the <c>Last-Modified</c> HTTP header name.</summary>
         public static readonly string LastModified = "Last-Modified";
+
+        /// <summary>Gets the <c>Location</c> HTTP header name.</summary>
         public static readonly string Location = "Location";
+
+        /// <summary>Gets the <c>Max-Forwards</c> HTTP header name.</summary>
         public static readonly string MaxForwards = "Max-Forwards";
+
+        /// <summary>Gets the <c>:method</c> HTTP header name.</summary>
         public static readonly string Method = ":method";
+
+        /// <summary>Gets the <c>Origin</c> HTTP header name.</summary>
         public static readonly string Origin = "Origin";
+
+        /// <summary>Gets the <c>:path</c> HTTP header name.</summary>
         public static readonly string Path = ":path";
+
+        /// <summary>Gets the <c>Pragma</c> HTTP header name.</summary>
         public static readonly string Pragma = "Pragma";
+
+        /// <summary>Gets the <c>Proxy-Authenticate</c> HTTP header name.</summary>
         public static readonly string ProxyAuthenticate = "Proxy-Authenticate";
+
+        /// <summary>Gets the <c>Proxy-Authorization</c> HTTP header name.</summary>
         public static readonly string ProxyAuthorization = "Proxy-Authorization";
+
+        /// <summary>Gets the <c>Proxy-Connection</c> HTTP header name.</summary>
         public static readonly string ProxyConnection = "Proxy-Connection";
+
+        /// <summary>Gets the <c>Range</c> HTTP header name.</summary>
         public static readonly string Range = "Range";
+
+        /// <summary>Gets the <c>Referer</c> HTTP header name.</summary>
         public static readonly string Referer = "Referer";
+
+        /// <summary>Gets the <c>Retry-After</c> HTTP header name.</summary>
         public static readonly string RetryAfter = "Retry-After";
+
+        /// <summary>Gets the <c>Request-Id</c> HTTP header name.</summary>
         public static readonly string RequestId = "Request-Id";
+
+        /// <summary>Gets the <c>:scheme</c> HTTP header name.</summary>
         public static readonly string Scheme = ":scheme";
+
+        /// <summary>Gets the <c>Sec-WebSocket-Accept</c> HTTP header name.</summary>
         public static readonly string SecWebSocketAccept = "Sec-WebSocket-Accept";
+
+        /// <summary>Gets the <c>Sec-WebSocket-Key</c> HTTP header name.</summary>
         public static readonly string SecWebSocketKey = "Sec-WebSocket-Key";
+
+        /// <summary>Gets the <c>Sec-WebSocket-Protocol</c> HTTP header name.</summary>
         public static readonly string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
+
+        /// <summary>Gets the <c>Sec-WebSocket-Version</c> HTTP header name.</summary>
         public static readonly string SecWebSocketVersion = "Sec-WebSocket-Version";
+
+        /// <summary>Gets the <c>Server</c> HTTP header name.</summary>
         public static readonly string Server = "Server";
+
+        /// <summary>Gets the <c>Set-Cookie</c> HTTP header name.</summary>
         public static readonly string SetCookie = "Set-Cookie";
+
+        /// <summary>Gets the <c>:status</c> HTTP header name.</summary>
         public static readonly string Status = ":status";
+
+        /// <summary>Gets the <c>Strict-Transport-Security</c> HTTP header name.</summary>
         public static readonly string StrictTransportSecurity = "Strict-Transport-Security";
+
+        /// <summary>Gets the <c>TE</c> HTTP header name.</summary>
         public static readonly string TE = "TE";
+
+        /// <summary>Gets the <c>Trailer</c> HTTP header name.</summary>
         public static readonly string Trailer = "Trailer";
+
+        /// <summary>Gets the <c>Transfer-Encoding</c> HTTP header name.</summary>
         public static readonly string TransferEncoding = "Transfer-Encoding";
+
+        /// <summary>Gets the <c>Translate</c> HTTP header name.</summary>
         public static readonly string Translate = "Translate";
+
+        /// <summary>Gets the <c>traceparent</c> HTTP header name.</summary>
         public static readonly string TraceParent = "traceparent";
+
+        /// <summary>Gets the <c>tracestate</c> HTTP header name.</summary>
         public static readonly string TraceState = "tracestate";
+
+        /// <summary>Gets the <c>Upgrade</c> HTTP header name.</summary>
         public static readonly string Upgrade = "Upgrade";
+
+        /// <summary>Gets the <c>Upgrade-Insecure-Requests</c> HTTP header name.</summary>
         public static readonly string UpgradeInsecureRequests = "Upgrade-Insecure-Requests";
+
+        /// <summary>Gets the <c>User-Agent</c> HTTP header name.</summary>
         public static readonly string UserAgent = "User-Agent";
+
+        /// <summary>Gets the <c>Vary</c> HTTP header name.</summary>
         public static readonly string Vary = "Vary";
+
+        /// <summary>Gets the <c>Via</c> HTTP header name.</summary>
         public static readonly string Via = "Via";
+
+        /// <summary>Gets the <c>Warning</c> HTTP header name.</summary>
         public static readonly string Warning = "Warning";
+
+        /// <summary>Gets the <c>Sec-WebSocket-Protocol</c> HTTP header name.</summary>
         public static readonly string WebSocketSubProtocols = "Sec-WebSocket-Protocol";
+
+        /// <summary>Gets the <c>WWW-Authenticate</c> HTTP header name.</summary>
         public static readonly string WWWAuthenticate = "WWW-Authenticate";
+
+        /// <summary>Gets the <c>X-Frame-Options</c> HTTP header name.</summary>
         public static readonly string XFrameOptions = "X-Frame-Options";
+
+        /// <summary>Gets the <c>X-Requested-With</c> HTTP header name.</summary>
         public static readonly string XRequestedWith = "X-Requested-With";
     }
 }

+ 4 - 1
src/Http/Headers/src/HeaderQuality.cs

@@ -3,6 +3,9 @@
 
 namespace Microsoft.Net.Http.Headers
 {
+    /// <summary>
+    /// Provides HTTP header quality factors.
+    /// </summary>
     public static class HeaderQuality
     {
         /// <summary>
@@ -15,4 +18,4 @@ namespace Microsoft.Net.Http.Headers
         /// </summary>
         public const double NoMatch = 0.0;
     }
-}
+}

+ 33 - 1
src/Http/Headers/src/HeaderUtilities.cs

@@ -11,6 +11,9 @@ using Microsoft.Extensions.Primitives;
 
 namespace Microsoft.Net.Http.Headers
 {
+    /// <summary>
+    /// Provides utilities to parse and modify HTTP header valeus.
+    /// </summary>
     public static class HeaderUtilities
     {
         private static readonly int _int64MaxStringLength = 19;
@@ -577,16 +580,35 @@ namespace Microsoft.Net.Http.Headers
             return new string(charBuffer, position, _int64MaxStringLength - position);
         }
 
+        /// <summary>
+        ///Attempts to parse the specified <paramref name="input"/> as a <see cref="DateTimeOffset"/> value.
+        /// </summary>
+        /// <param name="input">The input value.</param>
+        /// <param name="result">The parsed value.</param>
+        /// <returns>
+        /// <see langword="true" /> if <paramref name="input"/> can be parsed as a date, otherwise <see langword="false" />.
+        /// </returns>
         public static bool TryParseDate(StringSegment input, out DateTimeOffset result)
         {
             return HttpRuleParser.TryStringToDate(input, out result);
         }
 
+        /// <summary>
+        /// Formats the <paramref name="dateTime"/> using the RFC1123 format specifier.
+        /// </summary>
+        /// <param name="dateTime">The date to format.</param>
+        /// <returns>The formatted date.</returns>
         public static string FormatDate(DateTimeOffset dateTime)
         {
-            return FormatDate(dateTime, false);
+            return FormatDate(dateTime, quoted: false);
         }
 
+        /// <summary>
+        /// Formats the <paramref name="dateTime"/> using the RFC1123 format specifier and optionally quotes it.
+        /// </summary>
+        /// <param name="dateTime">The date to format.</param>
+        /// <param name="quoted">Determines if the formatted date should be quoted.</param>
+        /// <returns>The formatted date.</returns>
         public static string FormatDate(DateTimeOffset dateTime, bool quoted)
         {
             if (quoted)
@@ -601,6 +623,11 @@ namespace Microsoft.Net.Http.Headers
             return dateTime.ToString("r", CultureInfo.InvariantCulture);
         }
 
+        /// <summary>
+        /// Removes quotes from the specified <paramref name="input"/> if quoted.
+        /// </summary>
+        /// <param name="input">The input to remove quotes from.</param>
+        /// <returns>The value without quotes.</returns>
         public static StringSegment RemoveQuotes(StringSegment input)
         {
             if (IsQuoted(input))
@@ -610,6 +637,11 @@ namespace Microsoft.Net.Http.Headers
             return input;
         }
 
+        /// <summary>
+        /// Determines if the specified <paramref name="input"/> is quoted.
+        /// </summary>
+        /// <param name="input">The value to inspect.</param>
+        /// <returns><see langword="true"/> if the value is quoted, otherwise <see langword="false"/>.</returns>
         public static bool IsQuoted(StringSegment input)
         {
             return !StringSegment.IsNullOrEmpty(input) && input.Length >= 2 && input[0] == '"' && input[input.Length - 1] == '"';

+ 3 - 1
src/Http/Headers/src/MediaTypeHeaderValue.cs

@@ -462,7 +462,7 @@ namespace Microsoft.Net.Http.Headers
             return MatchesType(mediaType) && MatchesSubtype(mediaType);
         }
 
-
+        /// <inheritdoc />
         public override string ToString()
         {
             var builder = new StringBuilder();
@@ -471,6 +471,7 @@ namespace Microsoft.Net.Http.Headers
             return builder.ToString();
         }
 
+        /// <inheritdoc />
         public override bool Equals(object? obj)
         {
             var other = obj as MediaTypeHeaderValue;
@@ -484,6 +485,7 @@ namespace Microsoft.Net.Http.Headers
                 HeaderUtilities.AreEqualCollections(_parameters, other._parameters);
         }
 
+        /// <inheritdoc />
         public override int GetHashCode()
         {
             // The media-type string is case-insensitive.

+ 3 - 0
src/Http/Headers/src/MediaTypeHeaderValueComparer.cs

@@ -16,6 +16,9 @@ namespace Microsoft.Net.Http.Headers
         {
         }
 
+        /// <summary>
+        /// Gets the <see cref="MediaTypeHeaderValueComparer"/> instance.
+        /// </summary>
         public static MediaTypeHeaderValueComparer QualityComparer { get; } = new MediaTypeHeaderValueComparer();
 
         /// <inheritdoc />

+ 1 - 2
src/Http/Headers/src/Microsoft.Net.Http.Headers.csproj

@@ -1,10 +1,9 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
     <Description>HTTP header parser implementations.</Description>
     <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
     <IsAspNetCoreApp>true</IsAspNetCoreApp>
-    <NoWarn>$(NoWarn);CS1591</NoWarn>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <PackageTags>http</PackageTags>

+ 76 - 0
src/Http/Headers/src/NameValueHeaderValue.cs

@@ -14,6 +14,9 @@ namespace Microsoft.Net.Http.Headers
     // According to the RFC, in places where a "parameter" is required, the value is mandatory
     // (e.g. Media-Type, Accept). However, we don't introduce a dedicated type for it. So NameValueHeaderValue supports
     // name-only values in addition to name/value pairs.
+    /// <summary>
+    /// Represents a name/value pair used in various headers as defined in RFC 2616.
+    /// </summary>
     public class NameValueHeaderValue
     {
         private static readonly HttpHeaderParser<NameValueHeaderValue> SingleValueParser
@@ -30,11 +33,20 @@ namespace Microsoft.Net.Http.Headers
             // Used by the parser to create a new instance of this type.
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="NameValueHeaderValue"/>.
+        /// </summary>
+        /// <param name="name">The header name.</param>
         public NameValueHeaderValue(StringSegment name)
             : this(name, null)
         {
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="NameValueHeaderValue"/>.
+        /// </summary>
+        /// <param name="name">The header name.</param>
+        /// <param name="value">The header value.</param>
         public NameValueHeaderValue(StringSegment name, StringSegment value)
         {
             CheckNameValueFormat(name, value);
@@ -43,11 +55,17 @@ namespace Microsoft.Net.Http.Headers
             _value = value;
         }
 
+        /// <summary>
+        /// Gets the header name.
+        /// </summary>
         public StringSegment Name
         {
             get { return _name; }
         }
 
+        /// <summary>
+        /// Gets or sets the header value.
+        /// </summary>
         public StringSegment Value
         {
             get { return _value; }
@@ -59,6 +77,9 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <summary>
+        /// Gets a value that determines if this header is read only.
+        /// </summary>
         public bool IsReadOnly { get { return _isReadOnly; } }
 
         /// <summary>
@@ -74,6 +95,10 @@ namespace Microsoft.Net.Http.Headers
             };
         }
 
+        /// <summary>
+        /// Provides a copy of this instance while making it immutable.
+        /// </summary>
+        /// <returns>The readonly <see cref="NameValueHeaderValue"/>.</returns>
         public NameValueHeaderValue CopyAsReadOnly()
         {
             if (IsReadOnly)
@@ -89,6 +114,7 @@ namespace Microsoft.Net.Http.Headers
             };
         }
 
+        /// <inheritdoc/>
         public override int GetHashCode()
         {
             Contract.Assert(_name != null);
@@ -110,6 +136,7 @@ namespace Microsoft.Net.Http.Headers
             return nameHashCode;
         }
 
+        /// <inheritdoc/>
         public override bool Equals(object? obj)
         {
             var other = obj as NameValueHeaderValue;
@@ -144,6 +171,11 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <summary>
+        /// If the value is a quoted-string as defined by <see href="https://tools.ietf.org/html/rfc7230#section-3.2.6">the RFC specification</see>,
+        /// removes quotes and unescapes backslashes and quotes.
+        /// </summary>
+        /// <returns>An unescaped version of <see cref="Value"/>.</returns>
         public StringSegment GetUnescapedValue()
         {
             if (!HeaderUtilities.IsQuoted(_value))
@@ -153,6 +185,10 @@ namespace Microsoft.Net.Http.Headers
             return HeaderUtilities.UnescapeAsQuotedString(_value);
         }
 
+        /// <summary>
+        /// Sets <see cref="Value"/> after it has been quoted as defined by <see href="https://tools.ietf.org/html/rfc7230#section-3.2.6">the RFC specification</see>.
+        /// </summary>
+        /// <param name="value"></param>
         public void SetAndEscapeValue(StringSegment value)
         {
             HeaderUtilities.ThrowIfReadOnly(IsReadOnly);
@@ -166,38 +202,72 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <summary>
+        /// Parses <paramref name="input"/> as a <see cref="NameValueHeaderValue"/> value.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static NameValueHeaderValue Parse(StringSegment input)
         {
             var index = 0;
             return SingleValueParser.ParseValue(input, ref index)!;
         }
 
+        /// <summary>
+        /// Attempts to parse the specified <paramref name="input"/> as a <see cref="NameValueHeaderValue"/>.
+        /// </summary>
+        /// <param name="input">The value to parse.</param>
+        /// <param name="parsedValue">The parsed value.</param>
+        /// <returns><see langword="true"/> if input is a valid <see cref="NameValueHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParse(StringSegment input, [NotNullWhen(true)] out NameValueHeaderValue? parsedValue)
         {
             var index = 0;
             return SingleValueParser.TryParseValue(input, ref index, out parsedValue!);
         }
 
+        /// <summary>
+        /// Parses a sequence of inputs as a sequence of <see cref="NameValueHeaderValue"/> values.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static IList<NameValueHeaderValue> ParseList(IList<string>? input)
         {
             return MultipleValueParser.ParseValues(input);
         }
 
+        /// <summary>
+        /// Parses a sequence of inputs as a sequence of <see cref="NameValueHeaderValue"/> values using string parsing rules.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static IList<NameValueHeaderValue> ParseStrictList(IList<string>? input)
         {
             return MultipleValueParser.ParseStrictValues(input);
         }
 
+        /// <summary>
+        /// Attempts to parse the sequence of values as a sequence of <see cref="NameValueHeaderValue"/>.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <param name="parsedValues">The parsed values.</param>
+        /// <returns><see langword="true"/> if all inputs are valid <see cref="NameValueHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParseList(IList<string>? input, [NotNullWhen(true)] out IList<NameValueHeaderValue>? parsedValues)
         {
             return MultipleValueParser.TryParseValues(input, out parsedValues);
         }
 
+        /// <summary>
+        /// Attempts to parse the sequence of values as a sequence of <see cref="NameValueHeaderValue"/> using string parsing rules.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <param name="parsedValues">The parsed values.</param>
+        /// <returns><see langword="true"/> if all inputs are valid <see cref="StringWithQualityHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParseStrictList(IList<string>? input, [NotNullWhen(true)] out IList<NameValueHeaderValue>? parsedValues)
         {
             return MultipleValueParser.TryParseStrictValues(input, out parsedValues);
         }
 
+        /// <inheritdoc />
         public override string ToString()
         {
             if (!StringSegment.IsNullOrEmpty(_value))
@@ -357,6 +427,12 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <summary>
+        /// Finds a <see cref="NameValueHeaderValue"/> with the specified <paramref name="name"/>.
+        /// </summary>
+        /// <param name="values">The collection to search.</param>
+        /// <param name="name">The name to find.</param>
+        /// <returns>The <see cref="NameValueHeaderValue" /> if found, otherwise <see langword="null" />.</returns>
         public static NameValueHeaderValue? Find(IList<NameValueHeaderValue>? values, StringSegment name)
         {
             Contract.Requires(name.Length > 0);

+ 0 - 1
src/Http/Headers/src/PublicAPI.Shipped.txt

@@ -121,7 +121,6 @@ Microsoft.Net.Http.Headers.NameValueHeaderValue.Value.set -> void
 Microsoft.Net.Http.Headers.RangeConditionHeaderValue
 Microsoft.Net.Http.Headers.RangeConditionHeaderValue.EntityTag.get -> Microsoft.Net.Http.Headers.EntityTagHeaderValue?
 Microsoft.Net.Http.Headers.RangeConditionHeaderValue.LastModified.get -> System.DateTimeOffset?
-Microsoft.Net.Http.Headers.RangeConditionHeaderValue.RangeConditionHeaderValue(Microsoft.Net.Http.Headers.EntityTagHeaderValue? entityTag) -> void
 Microsoft.Net.Http.Headers.RangeConditionHeaderValue.RangeConditionHeaderValue(System.DateTimeOffset lastModified) -> void
 Microsoft.Net.Http.Headers.RangeConditionHeaderValue.RangeConditionHeaderValue(string? entityTag) -> void
 Microsoft.Net.Http.Headers.RangeHeaderValue

+ 1 - 0
src/Http/Headers/src/PublicAPI.Unshipped.txt

@@ -1,3 +1,4 @@
 #nullable enable
 Microsoft.Net.Http.Headers.MediaTypeHeaderValue.MatchesMediaType(Microsoft.Extensions.Primitives.StringSegment otherMediaType) -> bool
+Microsoft.Net.Http.Headers.RangeConditionHeaderValue.RangeConditionHeaderValue(Microsoft.Net.Http.Headers.EntityTagHeaderValue! entityTag) -> void
 static readonly Microsoft.Net.Http.Headers.HeaderNames.ProxyConnection -> string!

+ 36 - 1
src/Http/Headers/src/RangeConditionHeaderValue.cs

@@ -8,6 +8,9 @@ using Microsoft.Extensions.Primitives;
 
 namespace Microsoft.Net.Http.Headers
 {
+    /// <summary>
+    /// Represents an <c>If-Range</c> header value which can either be a date/time or an entity-tag value.
+    /// </summary>
     public class RangeConditionHeaderValue
     {
         private static readonly HttpHeaderParser<RangeConditionHeaderValue> Parser
@@ -21,12 +24,20 @@ namespace Microsoft.Net.Http.Headers
             // Used by the parser to create a new instance of this type.
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="RangeConditionHeaderValue"/>.
+        /// </summary>
+        /// <param name="lastModified">A date value used to initialize the new instance.</param>
         public RangeConditionHeaderValue(DateTimeOffset lastModified)
         {
             _lastModified = lastModified;
         }
 
-        public RangeConditionHeaderValue(EntityTagHeaderValue? entityTag)
+        /// <summary>
+        /// Initializes a new instance of <see cref="RangeConditionHeaderValue"/>.
+        /// </summary>
+        /// <param name="entityTag">An entity tag uniquely representing the requested resource.</param>
+        public RangeConditionHeaderValue(EntityTagHeaderValue entityTag)
         {
             if (entityTag == null)
             {
@@ -36,21 +47,32 @@ namespace Microsoft.Net.Http.Headers
             _entityTag = entityTag;
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="RangeConditionHeaderValue"/>.
+        /// </summary>
+        /// <param name="entityTag">An entity tag uniquely representing the requested resource.</param>
         public RangeConditionHeaderValue(string? entityTag)
             : this(new EntityTagHeaderValue(entityTag))
         {
         }
 
+        /// <summary>
+        /// Gets the LastModified date from header.
+        /// </summary>
         public DateTimeOffset? LastModified
         {
             get { return _lastModified; }
         }
 
+        /// <summary>
+        /// Gets the <see cref="EntityTagHeaderValue"/> from header.
+        /// </summary>
         public EntityTagHeaderValue? EntityTag
         {
             get { return _entityTag; }
         }
 
+        /// <inheritdoc />
         public override string ToString()
         {
             if (_entityTag == null)
@@ -60,6 +82,7 @@ namespace Microsoft.Net.Http.Headers
             return _entityTag.ToString();
         }
 
+        /// <inheritdoc />
         public override bool Equals(object? obj)
         {
             var other = obj as RangeConditionHeaderValue;
@@ -77,6 +100,7 @@ namespace Microsoft.Net.Http.Headers
             return _entityTag.Equals(other._entityTag);
         }
 
+        /// <inheritdoc />
         public override int GetHashCode()
         {
             if (_entityTag == null)
@@ -87,12 +111,23 @@ namespace Microsoft.Net.Http.Headers
             return _entityTag.GetHashCode();
         }
 
+        /// <summary>
+        /// Parses <paramref name="input"/> as a <see cref="RangeConditionHeaderValue"/> value.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static RangeConditionHeaderValue Parse(StringSegment input)
         {
             var index = 0;
             return Parser.ParseValue(input, ref index)!;
         }
 
+        /// <summary>
+        /// Attempts to parse the specified <paramref name="input"/> as a <see cref="RangeConditionHeaderValue"/>.
+        /// </summary>
+        /// <param name="input">The value to parse.</param>
+        /// <param name="parsedValue">The parsed value.</param>
+        /// <returns><see langword="true"/> if input is a valid <see cref="RangeConditionHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParse(StringSegment input, [NotNullWhen(true)] out RangeConditionHeaderValue? parsedValue)
         {
             var index = 0;

+ 36 - 0
src/Http/Headers/src/RangeHeaderValue.cs

@@ -10,6 +10,13 @@ using Microsoft.Extensions.Primitives;
 
 namespace Microsoft.Net.Http.Headers
 {
+    /// <summary>
+    /// Represents a <c>Range</c> header value.
+    /// <para>
+    /// The <see cref="RangeHeaderValue"/> class provides support for the Range header as defined in
+    /// <see href="https://tools.ietf.org/html/rfc2616">RFC 2616</see>.
+    /// </para>
+    /// </summary>
     public class RangeHeaderValue
     {
         private static readonly HttpHeaderParser<RangeHeaderValue> Parser
@@ -18,11 +25,19 @@ namespace Microsoft.Net.Http.Headers
         private StringSegment _unit;
         private ICollection<RangeItemHeaderValue>? _ranges;
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="RangeHeaderValue"/>.
+        /// </summary>
         public RangeHeaderValue()
         {
             _unit = HeaderUtilities.BytesUnit;
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="RangeHeaderValue"/>.
+        /// </summary>
+        /// <param name="from">The position at which to start sending data.</param>
+        /// <param name="to">The position at which to stop sending data.</param>
         public RangeHeaderValue(long? from, long? to)
         {
             // convenience ctor: "Range: bytes=from-to"
@@ -30,6 +45,10 @@ namespace Microsoft.Net.Http.Headers
             Ranges.Add(new RangeItemHeaderValue(from, to));
         }
 
+        /// <summary>
+        /// Gets or sets the unit from the header.
+        /// </summary>
+        /// <value>Defaults to <c>bytes</c>.</value>
         public StringSegment Unit
         {
             get { return _unit; }
@@ -40,6 +59,9 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <summary>
+        /// Gets the ranges specified in the header.
+        /// </summary>
         public ICollection<RangeItemHeaderValue> Ranges
         {
             get
@@ -52,6 +74,7 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <inheritdoc />
         public override string ToString()
         {
             var sb = new StringBuilder();
@@ -78,6 +101,7 @@ namespace Microsoft.Net.Http.Headers
             return sb.ToString();
         }
 
+        /// <inheritdoc />
         public override bool Equals(object? obj)
         {
             var other = obj as RangeHeaderValue;
@@ -91,6 +115,7 @@ namespace Microsoft.Net.Http.Headers
                 HeaderUtilities.AreEqualCollections(Ranges, other.Ranges);
         }
 
+        /// <inheritdoc />
         public override int GetHashCode()
         {
             var result = StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_unit);
@@ -103,12 +128,23 @@ namespace Microsoft.Net.Http.Headers
             return result;
         }
 
+        /// <summary>
+        /// Parses <paramref name="input"/> as a <see cref="RangeHeaderValue"/> value.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static RangeHeaderValue Parse(StringSegment input)
         {
             var index = 0;
             return Parser.ParseValue(input, ref index)!;
         }
 
+        /// <summary>
+        /// Attempts to parse the specified <paramref name="input"/> as a <see cref="RangeHeaderValue"/>.
+        /// </summary>
+        /// <param name="input">The value to parse.</param>
+        /// <param name="parsedValue">The parsed value.</param>
+        /// <returns><see langword="true"/> if input is a valid <see cref="RangeHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParse(StringSegment input, [NotNullWhen(true)] out RangeHeaderValue parsedValue)
         {
             var index = 0;

+ 24 - 10
src/Http/Headers/src/RangeItemHeaderValue.cs

@@ -9,11 +9,23 @@ using Microsoft.Extensions.Primitives;
 
 namespace Microsoft.Net.Http.Headers
 {
+    /// <summary>
+    /// Represents a byte range in a Range header value.
+    /// <para>
+    /// The <see cref="RangeItemHeaderValue"/> class provides support for a byte range in a <c>Range</c> as defined
+    /// in <see href="https://tools.ietf.org/html/rfc2616">RFC 2616</see>.
+    /// </para>
+    /// </summary>
     public class RangeItemHeaderValue
     {
         private long? _from;
         private long? _to;
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RangeItemHeaderValue"/> class.
+        /// </summary>
+        /// <param name="from">The position at which to start sending data.</param>
+        /// <param name="to">The position at which to stop sending data.</param>
         public RangeItemHeaderValue(long? from, long? to)
         {
             if (!from.HasValue && !to.HasValue)
@@ -37,16 +49,23 @@ namespace Microsoft.Net.Http.Headers
             _to = to;
         }
 
+        /// <summary>
+        /// Gets the position at which to start sending data.
+        /// </summary>
         public long? From
         {
             get { return _from; }
         }
 
+        /// <summary>
+        /// Gets the position at which to stop sending data.
+        /// </summary>
         public long? To
         {
             get { return _to; }
         }
 
+        /// <inheritdoc />
         public override string ToString()
         {
             if (!_from.HasValue)
@@ -61,16 +80,13 @@ namespace Microsoft.Net.Http.Headers
                 _to.GetValueOrDefault().ToString(NumberFormatInfo.InvariantInfo);
         }
 
+        /// <inheritdoc />
         public override bool Equals(object? obj)
         {
-            if (obj is RangeItemHeaderValue other)
-            {
-                return ((_from == other._from) && (_to == other._to));
-            }
-
-            return false;
+            return obj is RangeItemHeaderValue other && ((_from == other._from) && (_to == other._to));
         }
 
+        /// <inheritdoc />
         public override int GetHashCode()
         {
             if (!_from.HasValue)
@@ -101,8 +117,7 @@ namespace Microsoft.Net.Http.Headers
             }
 
             // Empty segments are allowed, so skip all delimiter-only segments (e.g. ", ,").
-            var separatorFound = false;
-            var current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(input, startIndex, true, out separatorFound);
+            var current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(input, startIndex, true, out var separatorFound);
             // It's OK if we didn't find leading separator characters. Ignore 'separatorFound'.
 
             if (current == input.Length)
@@ -110,10 +125,9 @@ namespace Microsoft.Net.Http.Headers
                 return 0;
             }
 
-            RangeItemHeaderValue? range = null;
             while (true)
             {
-                var rangeLength = GetRangeItemLength(input, current, out range);
+                var rangeLength = GetRangeItemLength(input, current, out var range);
 
                 if (rangeLength == 0)
                 {

+ 117 - 1
src/Http/Headers/src/SetCookieHeaderValue.cs

@@ -12,7 +12,12 @@ using Microsoft.Extensions.Primitives;
 
 namespace Microsoft.Net.Http.Headers
 {
-    // http://tools.ietf.org/html/rfc6265
+    /// <summary>
+    /// Represents the <c>Set-Cookie</c> header.
+    /// <para>
+    /// See http://tools.ietf.org/html/rfc6265 for the Set-Cookie header specification.
+    /// </para>
+    /// </summary>
     public class SetCookieHeaderValue
     {
         private const string ExpiresToken = "expires";
@@ -45,11 +50,20 @@ namespace Microsoft.Net.Http.Headers
             // Used by the parser to create a new instance of this type.
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="SetCookieHeaderValue"/>.
+        /// </summary>
+        /// <param name="name">The cookie name.</param>
         public SetCookieHeaderValue(StringSegment name)
             : this(name, StringSegment.Empty)
         {
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="SetCookieHeaderValue"/>.
+        /// </summary>
+        /// <param name="name">The cookie name.</param>
+        /// <param name="value">The cookie value.</param>
         public SetCookieHeaderValue(StringSegment name, StringSegment value)
         {
             if (name == null)
@@ -66,6 +80,9 @@ namespace Microsoft.Net.Http.Headers
             Value = value;
         }
 
+        /// <summary>
+        /// Gets or sets the cookie name.
+        /// </summary>
         public StringSegment Name
         {
             get { return _name; }
@@ -76,6 +93,9 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <summary>
+        /// Gets or sets the cookie value.
+        /// </summary>
         public StringSegment Value
         {
             get { return _value; }
@@ -86,23 +106,84 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <summary>
+        /// Gets or sets a value for the <c>Expires</c> cookie attribute.
+        /// <para>
+        /// The Expires attribute indicates the maximum lifetime of the cookie,
+        /// represented as the date and time at which the cookie expires.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc6265#section-4.1.2.1</remarks>
         public DateTimeOffset? Expires { get; set; }
 
+        /// <summary>
+        /// Gets or sets a value for the <c>Max-Age</c> cookie attribute.
+        /// <para>
+        /// The Max-Age attribute indicates the maximum lifetime of the cookie,
+        /// represented as the number of seconds until the cookie expires.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc6265#section-4.1.2.2</remarks>
         public TimeSpan? MaxAge { get; set; }
 
+        /// <summary>
+        /// Gets or sets a value for the <c>Domain</c> cookie attribute.
+        /// <para>
+        /// The Domain attribute specifies those hosts to which the cookie will
+        /// be sent.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc6265#section-4.1.2.3</remarks>
         public StringSegment Domain { get; set; }
 
+        /// <summary>
+        /// Gets or sets a value for the <c>Path</c> cookie attribute.
+        /// <para>
+        /// The path attribute specifies those hosts to which the cookie will
+        /// be sent.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc6265#section-4.1.2.4</remarks>
         public StringSegment Path { get; set; }
 
+        /// <summary>
+        /// Gets or sets a value for the <c>Secure</c> cookie attribute.
+        /// <para>
+        /// The Secure attribute limits the scope of the cookie to "secure"
+        /// channels.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc6265#section-4.1.2.5</remarks>
         public bool Secure { get; set; }
 
+        /// <summary>
+        /// Gets or sets a value for the <c>SameSite</c> cookie attribute.
+        /// <para>
+        /// "SameSite" cookies offer a robust defense against CSRF attack when
+        /// deployed in strict mode, and when supported by the client.
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-05#section-8.8</remarks>
         public SameSiteMode SameSite { get; set; } = SameSiteMode.Unspecified;
 
+        /// <summary>
+        /// Gets or sets a value for the <c>HttpOnly</c> cookie attribute.
+        /// <para>
+        /// HttpOnly instructs the user agent to
+        /// omit the cookie when providing access to cookies via "non-HTTP" APIs
+        /// (such as a web browser API that exposes cookies to scripts).
+        /// </para>
+        /// </summary>
+        /// <remarks>See https://tools.ietf.org/html/rfc6265#section-4.1.2.6</remarks>
         public bool HttpOnly { get; set; }
 
+        /// <summary>
+        /// Gets a collection of additional values to append to the cookie.
+        /// </summary>
         public IList<StringSegment> Extensions { get; } = new List<StringSegment>();
 
         // name="value"; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={strict|lax|none}; httponly
+        /// <inheritdoc />
         public override string ToString()
         {
             var length = _name.Length + EqualsToken.Length + _value.Length;
@@ -312,33 +393,66 @@ namespace Microsoft.Net.Http.Headers
             }
         }
 
+        /// <summary>
+        /// Parses <paramref name="input"/> as a <see cref="SetCookieHeaderValue"/> value.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static SetCookieHeaderValue Parse(StringSegment input)
         {
             var index = 0;
             return SingleValueParser.ParseValue(input, ref index)!;
         }
 
+        /// <summary>
+        /// Attempts to parse the specified <paramref name="input"/> as a <see cref="SetCookieHeaderValue"/>.
+        /// </summary>
+        /// <param name="input">The value to parse.</param>
+        /// <param name="parsedValue">The parsed value.</param>
+        /// <returns><see langword="true"/> if input is a valid <see cref="SetCookieHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParse(StringSegment input, [NotNullWhen(true)] out SetCookieHeaderValue? parsedValue)
         {
             var index = 0;
             return SingleValueParser.TryParseValue(input, ref index, out parsedValue!);
         }
 
+        /// <summary>
+        /// Parses a sequence of inputs as a sequence of <see cref="SetCookieHeaderValue"/> values.
+        /// </summary>
+        /// <param name="inputs">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static IList<SetCookieHeaderValue> ParseList(IList<string>? inputs)
         {
             return MultipleValueParser.ParseValues(inputs);
         }
 
+        /// <summary>
+        /// Parses a sequence of inputs as a sequence of <see cref="SetCookieHeaderValue"/> values using string parsing rules.
+        /// </summary>
+        /// <param name="inputs">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static IList<SetCookieHeaderValue> ParseStrictList(IList<string>? inputs)
         {
             return MultipleValueParser.ParseStrictValues(inputs);
         }
 
+        /// <summary>
+        /// Attempts to parse the sequence of values as a sequence of <see cref="SetCookieHeaderValue"/>.
+        /// </summary>
+        /// <param name="inputs">The values to parse.</param>
+        /// <param name="parsedValues">The parsed values.</param>
+        /// <returns><see langword="true"/> if all inputs are valid <see cref="SetCookieHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParseList(IList<string>? inputs, [NotNullWhen(true)] out IList<SetCookieHeaderValue>? parsedValues)
         {
             return MultipleValueParser.TryParseValues(inputs, out parsedValues);
         }
 
+        /// <summary>
+        /// Attempts to parse the sequence of values as a sequence of <see cref="SetCookieHeaderValue"/> using string parsing rules.
+        /// </summary>
+        /// <param name="inputs">The values to parse.</param>
+        /// <param name="parsedValues">The parsed values.</param>
+        /// <returns><see langword="true"/> if all inputs are valid <see cref="StringWithQualityHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParseStrictList(IList<string>? inputs, [NotNullWhen(true)] out IList<SetCookieHeaderValue>? parsedValues)
         {
             return MultipleValueParser.TryParseStrictValues(inputs, out parsedValues);
@@ -571,6 +685,7 @@ namespace Microsoft.Net.Http.Headers
             return result;
         }
 
+        /// <inheritdoc />
         public override bool Equals(object? obj)
         {
             var other = obj as SetCookieHeaderValue;
@@ -592,6 +707,7 @@ namespace Microsoft.Net.Http.Headers
                 && HeaderUtilities.AreEqualCollections(Extensions, other.Extensions, StringSegmentComparer.OrdinalIgnoreCase);
         }
 
+        /// <inheritdoc />
         public override int GetHashCode()
         {
             var hash = StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_name)

+ 56 - 8
src/Http/Headers/src/StringWithQualityHeaderValue.cs

@@ -10,6 +10,9 @@ using Microsoft.Extensions.Primitives;
 
 namespace Microsoft.Net.Http.Headers
 {
+    /// <summary>
+    /// A string header value with an optional quality.
+    /// </summary>
     public class StringWithQualityHeaderValue
     {
         private static readonly HttpHeaderParser<StringWithQualityHeaderValue> SingleValueParser
@@ -25,6 +28,10 @@ namespace Microsoft.Net.Http.Headers
             // Used by the parser to create a new instance of this type.
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="StringWithQualityHeaderValue"/>.
+        /// </summary>
+        /// <param name="value">The <see cref="StringSegment"/> used to initialize the new instance.</param>
         public StringWithQualityHeaderValue(StringSegment value)
         {
             HeaderUtilities.CheckValidToken(value, nameof(value));
@@ -32,6 +39,11 @@ namespace Microsoft.Net.Http.Headers
             _value = value;
         }
 
+        /// <summary>
+        /// Initializes a new instance of <see cref="StringWithQualityHeaderValue"/>.
+        /// </summary>
+        /// <param name="value">The <see cref="StringSegment"/> used to initialize the new instance.</param>
+        /// <param name="quality">The quality factor.</param>
         public StringWithQualityHeaderValue(StringSegment value, double quality)
         {
             HeaderUtilities.CheckValidToken(value, nameof(value));
@@ -45,16 +57,17 @@ namespace Microsoft.Net.Http.Headers
             _quality = quality;
         }
 
-        public StringSegment Value
-        {
-            get { return _value; }
-        }
+        /// <summary>
+        /// Gets the string header value.
+        /// </summary>
+        public StringSegment Value => _value;
 
-        public double? Quality
-        {
-            get { return _quality; }
-        }
+        /// <summary>
+        /// Gets the quality factor.
+        /// </summary>
+        public double? Quality => _quality;
 
+        /// <inheritdoc />
         public override string ToString()
         {
             if (_quality.HasValue)
@@ -65,6 +78,7 @@ namespace Microsoft.Net.Http.Headers
             return _value.ToString();
         }
 
+        /// <inheritdoc />
         public override bool Equals(object? obj)
         {
             var other = obj as StringWithQualityHeaderValue;
@@ -92,6 +106,7 @@ namespace Microsoft.Net.Http.Headers
             return !other._quality.HasValue;
         }
 
+        /// <inheritdoc />
         public override int GetHashCode()
         {
             var result = StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_value);
@@ -104,33 +119,66 @@ namespace Microsoft.Net.Http.Headers
             return result;
         }
 
+        /// <summary>
+        /// Parses the specified <paramref name="input"/> as a <see cref="StringWithQualityHeaderValue"/>.
+        /// </summary>
+        /// <param name="input">The value to parse.</param>
+        /// <returns>The parsed value.</returns>
         public static StringWithQualityHeaderValue Parse(StringSegment input)
         {
             var index = 0;
             return SingleValueParser.ParseValue(input, ref index)!;
         }
 
+        /// <summary>
+        /// Attempts to parse the specified <paramref name="input"/> as a <see cref="StringWithQualityHeaderValue"/>.
+        /// </summary>
+        /// <param name="input">The value to parse.</param>
+        /// <param name="parsedValue">The parsed value.</param>
+        /// <returns><see langword="true"/> if input is a valid <see cref="StringWithQualityHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParse(StringSegment input, [NotNullWhen(true)] out StringWithQualityHeaderValue parsedValue)
         {
             var index = 0;
             return SingleValueParser.TryParseValue(input, ref index, out parsedValue!);
         }
 
+        /// <summary>
+        /// Parses a sequence of inputs as a sequence of <see cref="StringWithQualityHeaderValue"/> values.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static IList<StringWithQualityHeaderValue> ParseList(IList<string>? input)
         {
             return MultipleValueParser.ParseValues(input);
         }
 
+        /// <summary>
+        /// Parses a sequence of inputs as a sequence of <see cref="StringWithQualityHeaderValue"/> values using string parsing rules.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <returns>The parsed values.</returns>
         public static IList<StringWithQualityHeaderValue> ParseStrictList(IList<string>? input)
         {
             return MultipleValueParser.ParseStrictValues(input);
         }
 
+        /// <summary>
+        /// Attempts to parse the sequence of values as a sequence of <see cref="StringWithQualityHeaderValue"/>.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <param name="parsedValues">The parsed values.</param>
+        /// <returns><see langword="true"/> if all inputs are valid <see cref="StringWithQualityHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParseList(IList<string>? input, [NotNullWhen(true)] out IList<StringWithQualityHeaderValue>? parsedValues)
         {
             return MultipleValueParser.TryParseValues(input, out parsedValues);
         }
 
+        /// <summary>
+        /// Attempts to parse the sequence of values as a sequence of <see cref="StringWithQualityHeaderValue"/> using string parsing rules.
+        /// </summary>
+        /// <param name="input">The values to parse.</param>
+        /// <param name="parsedValues">The parsed values.</param>
+        /// <returns><see langword="true"/> if all inputs are valid <see cref="StringWithQualityHeaderValue"/>, otherwise <see langword="false"/>.</returns>
         public static bool TryParseStrictList(IList<string>? input, [NotNullWhen(true)] out IList<StringWithQualityHeaderValue>? parsedValues)
         {
             return MultipleValueParser.TryParseStrictValues(input, out parsedValues);

+ 3 - 0
src/Http/Headers/src/StringWithQualityHeaderValueComparer.cs

@@ -20,6 +20,9 @@ namespace Microsoft.Net.Http.Headers
         {
         }
 
+        /// <summary>
+        /// Gets the default instance of <see cref="StringWithQualityHeaderValueComparer"/>.
+        /// </summary>
         public static StringWithQualityHeaderValueComparer QualityComparer { get; } = new StringWithQualityHeaderValueComparer();
 
         /// <summary>