< Summary

Information
Class: System.Net.Http.Headers.MediaTypeHeaderValue
Assembly: System.Net.Http
File(s): D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\Headers\MediaTypeHeaderValue.cs
Line coverage
48%
Covered lines: 69
Uncovered lines: 74
Coverable lines: 143
Total lines: 294
Line coverage: 48.2%
Branch coverage
53%
Covered branches: 29
Total branches: 54
Branch coverage: 53.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor()100%11100%
.ctor(...)100%110%
.ctor(...)100%110%
.ctor(...)0%220%
ToString()83.33%66100%
Equals(...)0%440%
GetHashCode()100%110%
Parse(...)100%110%
TryParse(...)0%220%
GetMediaTypeLength(...)83.33%121293.33%
GetMediaTypeExpressionLength(...)85.71%1414100%
CheckMediaTypeFormat(...)0%440%
System.ICloneable.Clone()100%110%

File(s)

D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\Headers\MediaTypeHeaderValue.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Collections.Generic;
 5using System.Diagnostics;
 6using System.Diagnostics.CodeAnalysis;
 7using System.Runtime.CompilerServices;
 8using System.Text;
 9
 10namespace System.Net.Http.Headers
 11{
 12    /// <summary>Represents a media type used in a Content-Type header as defined in the RFC 2616.</summary>
 13    /// <remarks>
 14    /// The <see cref="MediaTypeHeaderValue"/> class provides support for the media type used in a Content-Type header
 15    /// as defined in RFC 2616 by the IETF. An example of a media-type would be "text/plain; charset=iso-8859-5".
 16    /// </remarks>
 17    public class MediaTypeHeaderValue : ICloneable
 18    {
 19        /// <summary>The name of the charset header value.</summary>
 20        private const string CharSetName = "charset";
 21
 22        /// <summary>The lazily-initialized parameters of the header value.</summary>
 23        private UnvalidatedObjectCollection<NameValueHeaderValue>? _parameters;
 24        /// <summary>The media type.</summary>
 25        private string? _mediaType;
 26
 27        /// <summary>Gets or sets the character set.</summary>
 28        /// <value>The character set.</value>
 29        public string? CharSet
 30        {
 031            get => NameValueHeaderValue.Find(_parameters, CharSetName)?.Value;
 32            set
 033            {
 34                // We don't prevent a user from setting whitespace-only charsets. Like we can't prevent a user from
 35                // setting a non-existing charset.
 036                NameValueHeaderValue? charSetParameter = NameValueHeaderValue.Find(_parameters, CharSetName);
 037                if (string.IsNullOrEmpty(value))
 038                {
 39                    // Remove charset parameter
 040                    if (charSetParameter != null)
 041                    {
 042                        _parameters!.Remove(charSetParameter);
 043                    }
 044                }
 45                else
 046                {
 047                    if (charSetParameter != null)
 048                    {
 049                        charSetParameter.Value = value;
 050                    }
 51                    else
 052                    {
 053                        Parameters.Add(new NameValueHeaderValue(CharSetName, value));
 054                    }
 055                }
 056            }
 57        }
 58
 59        /// <summary>Gets the media-type header value parameters.</summary>
 60        /// <value>The media-type header value parameters.</value>
 87261        public ICollection<NameValueHeaderValue> Parameters => _parameters ??= new UnvalidatedObjectCollection<NameValue
 62
 63        /// <summary>Gets or sets the media-type header value.</summary>
 64        /// <value>The media-type header value.</value>
 65        [DisallowNull]
 66        public string? MediaType
 67        {
 068            get { return _mediaType; }
 69            set
 070            {
 071                CheckMediaTypeFormat(value);
 072                _mediaType = value;
 073            }
 74        }
 75
 76        /// <summary>Used by the parser to create a new instance of this type.</summary>
 390777        internal MediaTypeHeaderValue()
 390778        {
 390779        }
 80
 81        /// <summary>Initializes a new instance of the <see cref="MediaTypeHeaderValue"/> class.</summary>
 82        /// <param name="source">A <see cref="MediaTypeHeaderValue"/> object used to initialize the new instance.</param
 083        protected MediaTypeHeaderValue(MediaTypeHeaderValue source)
 084        {
 085            Debug.Assert(source != null);
 86
 087            _mediaType = source._mediaType;
 088            _parameters = source._parameters.Clone();
 089        }
 90
 91        /// <summary>Initializes a new instance of the <see cref="MediaTypeHeaderValue"/> class.</summary>
 92        /// <param name="mediaType">The source represented as a string to initialize the new instance.</param>
 93        public MediaTypeHeaderValue(string mediaType)
 094            : this(mediaType, charSet: null)
 095        {
 096        }
 97
 98        /// <summary>Initializes a new instance of the <see cref="MediaTypeHeaderValue"/> class.</summary>
 99        /// <param name="mediaType">The source represented as a string to initialize the new instance.</param>
 100        /// <param name="charSet">The value to use for the character set.</param>
 0101        public MediaTypeHeaderValue(string mediaType, string? charSet)
 0102        {
 0103            CheckMediaTypeFormat(mediaType);
 0104            _mediaType = mediaType;
 105
 0106            if (!string.IsNullOrEmpty(charSet))
 0107            {
 0108                CharSet = charSet;
 0109            }
 0110        }
 111
 112        /// <summary>Returns a string that represents the current <see cref="MediaTypeHeaderValue"/> object.</summary>
 113        /// <returns>A string that represents the current object.</returns>
 114        public override string ToString()
 6014115        {
 6014116            if (_parameters is null || _parameters.Count == 0)
 4790117            {
 4790118                return _mediaType ?? string.Empty;
 119            }
 120
 1224121            var sb = StringBuilderCache.Acquire();
 1224122            sb.Append(_mediaType);
 1224123            NameValueHeaderValue.ToString(_parameters, ';', true, sb);
 1224124            return StringBuilderCache.GetStringAndRelease(sb);
 6014125        }
 126
 127        /// <summary>Determines whether the specified <see cref="object"/> is equal to the current <see cref="MediaTypeH
 128        /// <param name="obj">The object to compare with the current object.</param>
 129        /// <returns><see langword="true"/> if the specified <see cref="object"/> is equal to the current object; otherw
 130        public override bool Equals([NotNullWhen(true)] object? obj) =>
 0131            obj is MediaTypeHeaderValue other &&
 0132            string.Equals(_mediaType, other._mediaType, StringComparison.OrdinalIgnoreCase) &&
 0133            HeaderUtilities.AreEqualCollections(_parameters, other._parameters);
 134
 135        /// <summary>Serves as a hash function for an <see cref="MediaTypeHeaderValue"/> object.</summary>
 136        /// <returns>A hash code for the current object.</returns>
 137        /// <remarks>
 138        /// A hash code is a numeric value that is used to identify an object during equality testing. It can also serve
 139        /// The GetHashCode method is suitable for use in hashing algorithms and data structures such as a hash table.
 140        /// </remarks>
 141        public override int GetHashCode()
 0142        {
 143            // The media-type string is case-insensitive.
 0144            return StringComparer.OrdinalIgnoreCase.GetHashCode(_mediaType!) ^ NameValueHeaderValue.GetHashCode(_paramet
 0145        }
 146
 147        /// <summary>Converts a string to an <see cref="MediaTypeHeaderValue"/> instance.</summary>
 148        /// <param name="input">A string that represents media type header value information.</param>
 149        /// <returns>A <see cref="MediaTypeHeaderValue"/> instance.</returns>
 150        /// <exception cref="ArgumentNullException"><paramref name="input"/> is a <see langword="null"/> reference.</exc
 151        /// <exception cref="FormatException"><parmref name="input"/> is not valid media type header value information.<
 152        public static MediaTypeHeaderValue Parse(string input)
 0153        {
 0154            int index = 0;
 0155            return (MediaTypeHeaderValue)MediaTypeHeaderParser.SingleValueParser.ParseValue(input, null, ref index);
 0156        }
 157
 158        /// <summary>Determines whether a string is valid <see cref="MediaTypeHeaderValue"/> information.</summary>
 159        /// <param name="input">The string to validate.</param>
 160        /// <param name="parsedValue">The <see cref="MediaTypeHeaderValue"/> version of the string.</param>
 161        /// <returns><see langword="true"/> if input is valid <see cref="MediaTypeHeaderValue"/> information; otherwise,
 162        public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out MediaTypeHeaderValue? par
 0163        {
 0164            int index = 0;
 0165            parsedValue = null;
 166
 0167            if (MediaTypeHeaderParser.SingleValueParser.TryParseValue(input, null, ref index, out object? output))
 0168            {
 0169                parsedValue = (MediaTypeHeaderValue)output!;
 0170                return true;
 171            }
 0172            return false;
 0173        }
 174
 175        internal static int GetMediaTypeLength(string? input, int startIndex,
 176            Func<MediaTypeHeaderValue> mediaTypeCreator, out MediaTypeHeaderValue? parsedValue)
 3969177        {
 3969178            Debug.Assert(mediaTypeCreator != null);
 3969179            Debug.Assert(startIndex >= 0);
 180
 3969181            parsedValue = null;
 182
 3969183            if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
 0184            {
 0185                return 0;
 186            }
 187
 188            // Caller must remove leading whitespace. If not, we'll return 0.
 3969189            int mediaTypeLength = MediaTypeHeaderValue.GetMediaTypeExpressionLength(input, startIndex, out string? media
 190
 3969191            if (mediaTypeLength == 0)
 62192            {
 62193                return 0;
 194            }
 195
 3907196            int current = startIndex + mediaTypeLength;
 3907197            current += HttpRuleParser.GetWhitespaceLength(input, current);
 198            MediaTypeHeaderValue mediaTypeHeader;
 199
 200            // If we're not done and we have a parameter delimiter, then we have a list of parameters.
 3907201            if ((current < input.Length) && (input[current] == ';'))
 872202            {
 872203                mediaTypeHeader = mediaTypeCreator();
 872204                mediaTypeHeader._mediaType = mediaType;
 205
 872206                current++; // skip delimiter.
 872207                int parameterLength = NameValueHeaderValue.GetNameValueListLength(input, current, ';',
 872208                    (UnvalidatedObjectCollection<NameValueHeaderValue>)mediaTypeHeader.Parameters);
 209
 872210                if (parameterLength == 0)
 32211                {
 32212                    return 0;
 213                }
 214
 840215                parsedValue = mediaTypeHeader;
 840216                return current + parameterLength - startIndex;
 217            }
 218
 219            // We have a media type without parameters.
 3035220            mediaTypeHeader = mediaTypeCreator();
 3035221            mediaTypeHeader._mediaType = mediaType;
 3035222            parsedValue = mediaTypeHeader;
 3035223            return current - startIndex;
 3969224        }
 225
 226        private static int GetMediaTypeExpressionLength(string input, int startIndex, out string? mediaType)
 3969227        {
 3969228            Debug.Assert((input != null) && (input.Length > 0) && (startIndex < input.Length));
 229
 230            // This method just parses the "type/subtype" string, it does not parse parameters.
 3969231            mediaType = null;
 232
 233            // Parse the type, i.e. <type> in media type string "<type>/<subtype>; param1=value1; param2=value2"
 3969234            int typeLength = HttpRuleParser.GetTokenLength(input, startIndex);
 235
 3969236            if (typeLength == 0)
 6237            {
 6238                return 0;
 239            }
 240
 3963241            int current = startIndex + typeLength;
 3963242            current += HttpRuleParser.GetWhitespaceLength(input, current);
 243
 244            // Parse the separator between type and subtype
 3963245            if ((current >= input.Length) || (input[current] != '/'))
 52246            {
 52247                return 0;
 248            }
 3911249            current++; // skip delimiter.
 3911250            current += HttpRuleParser.GetWhitespaceLength(input, current);
 251
 252            // Parse the subtype, i.e. <subtype> in media type string "<type>/<subtype>; param1=value1; param2=value2"
 3911253            int subtypeLength = HttpRuleParser.GetTokenLength(input, current);
 254
 3911255            if (subtypeLength == 0)
 4256            {
 4257                return 0;
 258            }
 259
 260            // If there is no whitespace between <type> and <subtype> in <type>/<subtype> get the media type using
 261            // one Substring call. Otherwise get substrings for <type> and <subtype> and combine them.
 3907262            int mediaTypeLength = current + subtypeLength - startIndex;
 3907263            if (typeLength + subtypeLength + 1 == mediaTypeLength)
 3872264            {
 3872265                mediaType = input.Substring(startIndex, mediaTypeLength);
 3872266            }
 267            else
 35268            {
 35269                mediaType = string.Concat(input.AsSpan(startIndex, typeLength), "/", input.AsSpan(current, subtypeLength
 35270            }
 271
 3907272            return mediaTypeLength;
 3969273        }
 274
 275        private static void CheckMediaTypeFormat(string mediaType, [CallerArgumentExpression(nameof(mediaType))] string?
 0276        {
 0277            ArgumentException.ThrowIfNullOrEmpty(mediaType, parameterName);
 278
 279            // When adding values using strongly typed objects, no leading/trailing LWS (whitespace) are allowed.
 280            // Also no LWS between type and subtype are allowed.
 0281            int mediaTypeLength = GetMediaTypeExpressionLength(mediaType, 0, out string? tempMediaType);
 0282            if ((mediaTypeLength == 0) || (tempMediaType!.Length != mediaType.Length))
 0283            {
 0284                throw new FormatException(SR.Format(System.Globalization.CultureInfo.InvariantCulture, SR.net_http_heade
 285            }
 0286        }
 287
 288        // Implement ICloneable explicitly to allow derived types to "override" the implementation.
 289        object ICloneable.Clone()
 0290        {
 0291            return new MediaTypeHeaderValue(this);
 0292        }
 293    }
 294}