< Summary

Class:Azure.Core.Http.Multipart.NameValueHeaderValue
Assembly:Azure.Storage.Blobs.Batch
File(s):C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Blobs.Batch\src\Shared\NameValueHeaderValue.cs
Covered lines:0
Uncovered lines:141
Coverable lines:141
Total lines:438
Line coverage:0% (0 of 141)
Covered branches:0
Total branches:76
Branch coverage:0% (0 of 76)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.cctor()-0%100%
.ctor()-0%100%
.ctor(...)-0%100%
.ctor(...)-0%100%
get_Name()-0%100%
get_Value()-0%100%
set_Value(...)-0%100%
get_IsReadOnly()-0%100%
Copy()-0%100%
CopyAsReadOnly()-0%0%
GetHashCode()-0%0%
Equals(...)-0%0%
Parse(...)-0%100%
TryParse(...)-0%100%
ParseList(...)-0%100%
ParseStrictList(...)-0%100%
TryParseList(...)-0%100%
TryParseStrictList(...)-0%100%
ToString()-0%0%
ToString(...)-0%0%
ToString(...)-0%0%
GetHashCode(...)-0%0%
GetNameValueLength(...)-0%0%
GetNameValueListLength(...)-0%0%
Find(...)-0%0%
GetValueLength(...)-0%0%
CheckNameValueFormat(...)-0%100%
CheckValueFormat(...)-0%0%
CreateNameValue()-0%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Blobs.Batch\src\Shared\NameValueHeaderValue.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4// Copied from https://github.com/aspnet/AspNetCore/tree/master/src/Http/Headers/src
 5
 6using System;
 7using System.Collections.Generic;
 8using System.Diagnostics.Contracts;
 9using System.Globalization;
 10using System.Text;
 11
 12#pragma warning disable IDE0008 // Use explicit type
 13#pragma warning disable IDE0017 // Simplify object initialization
 14#pragma warning disable IDE0018 // Inline declaration
 15#pragma warning disable IDE0019 // Use pattern matching
 16#pragma warning disable IDE0032 // Use auto property
 17#pragma warning disable IDE0051 // Private is unused
 18#pragma warning disable IDE0054 // Use compound assignment
 19#pragma warning disable IDE0059 // Unnecessary assignment
 20#pragma warning disable IDE1006 // Missing s_ prefix
 21
 22namespace Azure.Core.Http.Multipart
 23{
 24    // According to the RFC, in places where a "parameter" is required, the value is mandatory
 25    // (e.g. Media-Type, Accept). However, we don't introduce a dedicated type for it. So NameValueHeaderValue supports
 26    // name-only values in addition to name/value pairs.
 27    internal class NameValueHeaderValue
 28    {
 029        private static readonly HttpHeaderParser<NameValueHeaderValue> SingleValueParser
 030            = new GenericHeaderParser<NameValueHeaderValue>(false, GetNameValueLength);
 031        internal static readonly HttpHeaderParser<NameValueHeaderValue> MultipleValueParser
 032            = new GenericHeaderParser<NameValueHeaderValue>(true, GetNameValueLength);
 33
 34        private StringSegment _name;
 35        private StringSegment _value;
 36        private bool _isReadOnly;
 37
 038        private NameValueHeaderValue()
 39        {
 40            // Used by the parser to create a new instance of this type.
 041        }
 42
 43        public NameValueHeaderValue(StringSegment name)
 044            : this(name, null)
 45        {
 046        }
 47
 048        public NameValueHeaderValue(StringSegment name, StringSegment value)
 49        {
 050            CheckNameValueFormat(name, value);
 51
 052            _name = name;
 053            _value = value;
 054        }
 55
 56        public StringSegment Name
 57        {
 058            get { return _name; }
 59        }
 60
 61        public StringSegment Value
 62        {
 063            get { return _value; }
 64            set
 65            {
 066                HeaderUtilities.ThrowIfReadOnly(IsReadOnly);
 067                CheckValueFormat(value);
 068                _value = value;
 069            }
 70        }
 71
 072        public bool IsReadOnly { get { return _isReadOnly; } }
 73
 74        /// <summary>
 75        /// Provides a copy of this object without the cost of re-validating the values.
 76        /// </summary>
 77        /// <returns>A copy.</returns>
 78        public NameValueHeaderValue Copy()
 79        {
 080            return new NameValueHeaderValue()
 081            {
 082                _name = _name,
 083                _value = _value
 084            };
 85        }
 86
 87        public NameValueHeaderValue CopyAsReadOnly()
 88        {
 089            if (IsReadOnly)
 90            {
 091                return this;
 92            }
 93
 094            return new NameValueHeaderValue()
 095            {
 096                _name = _name,
 097                _value = _value,
 098                _isReadOnly = true
 099            };
 100        }
 101
 102        public override int GetHashCode()
 103        {
 104            Contract.Assert(_name != null);
 105
 0106            var nameHashCode = StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_name);
 107
 0108            if (!StringSegment.IsNullOrEmpty(_value))
 109            {
 110                // If we have a quoted-string, then just use the hash code. If we have a token, convert to lowercase
 111                // and retrieve the hash code.
 0112                if (_value[0] == '"')
 113                {
 0114                    return nameHashCode ^ _value.GetHashCode();
 115                }
 116
 0117                return nameHashCode ^ StringSegmentComparer.OrdinalIgnoreCase.GetHashCode(_value);
 118            }
 119
 0120            return nameHashCode;
 121        }
 122
 123        public override bool Equals(object obj)
 124        {
 0125            var other = obj as NameValueHeaderValue;
 126
 0127            if (other == null)
 128            {
 0129                return false;
 130            }
 131
 0132            if (!_name.Equals(other._name, StringComparison.OrdinalIgnoreCase))
 133            {
 0134                return false;
 135            }
 136
 137            // RFC2616: 14.20: unquoted tokens should use case-INsensitive comparison; quoted-strings should use
 138            // case-sensitive comparison. The RFC doesn't mention how to compare quoted-strings outside the "Expect"
 139            // header. We treat all quoted-strings the same: case-sensitive comparison.
 140
 0141            if (StringSegment.IsNullOrEmpty(_value))
 142            {
 0143                return StringSegment.IsNullOrEmpty(other._value);
 144            }
 145
 0146            if (_value[0] == '"')
 147            {
 148                // We have a quoted string, so we need to do case-sensitive comparison.
 0149                return (_value.Equals(other._value, StringComparison.Ordinal));
 150            }
 151            else
 152            {
 0153                return (_value.Equals(other._value, StringComparison.OrdinalIgnoreCase));
 154            }
 155        }
 156
 157        /*
 158        public StringSegment GetUnescapedValue()
 159        {
 160            if (!HeaderUtilities.IsQuoted(_value))
 161            {
 162                return _value;
 163            }
 164            return HeaderUtilities.UnescapeAsQuotedString(_value);
 165        }
 166
 167        public void SetAndEscapeValue(StringSegment value)
 168        {
 169            HeaderUtilities.ThrowIfReadOnly(IsReadOnly);
 170            if (StringSegment.IsNullOrEmpty(value) || (GetValueLength(value, 0) == value.Length))
 171            {
 172                _value = value;
 173            }
 174            else
 175            {
 176                Value = HeaderUtilities.EscapeAsQuotedString(value);
 177            }
 178        }
 179        */
 180
 181        public static NameValueHeaderValue Parse(StringSegment input)
 182        {
 0183            var index = 0;
 0184            return SingleValueParser.ParseValue(input, ref index);
 185        }
 186
 187        public static bool TryParse(StringSegment input, out NameValueHeaderValue parsedValue)
 188        {
 0189            var index = 0;
 0190            return SingleValueParser.TryParseValue(input, ref index, out parsedValue);
 191        }
 192
 193        public static IList<NameValueHeaderValue> ParseList(IList<string> input)
 194        {
 0195            return MultipleValueParser.ParseValues(input);
 196        }
 197
 198        public static IList<NameValueHeaderValue> ParseStrictList(IList<string> input)
 199        {
 0200            return MultipleValueParser.ParseStrictValues(input);
 201        }
 202
 203        public static bool TryParseList(IList<string> input, out IList<NameValueHeaderValue> parsedValues)
 204        {
 0205            return MultipleValueParser.TryParseValues(input, out parsedValues);
 206        }
 207
 208        public static bool TryParseStrictList(IList<string> input, out IList<NameValueHeaderValue> parsedValues)
 209        {
 0210            return MultipleValueParser.TryParseStrictValues(input, out parsedValues);
 211        }
 212
 213        public override string ToString()
 214        {
 0215            if (!StringSegment.IsNullOrEmpty(_value))
 216            {
 0217                return _name + "=" + _value;
 218            }
 0219            return _name.ToString();
 220        }
 221
 222        internal static void ToString(
 223            IList<NameValueHeaderValue> values,
 224            char separator,
 225            bool leadingSeparator,
 226            StringBuilder destination)
 227        {
 228            Contract.Assert(destination != null);
 229
 0230            if ((values == null) || (values.Count == 0))
 231            {
 0232                return;
 233            }
 234
 0235            for (var i = 0; i < values.Count; i++)
 236            {
 0237                if (leadingSeparator || (destination.Length > 0))
 238                {
 0239                    destination.Append(separator);
 0240                    destination.Append(' ');
 241                }
 0242                destination.Append(values[i].Name.AsSpan());
 0243                if (!StringSegment.IsNullOrEmpty(values[i].Value))
 244                {
 0245                    destination.Append('=');
 0246                    destination.Append(values[i].Value.AsSpan());
 247                }
 248            }
 0249        }
 250
 251        internal static string ToString(IList<NameValueHeaderValue> values, char separator, bool leadingSeparator)
 252        {
 0253            if ((values == null) || (values.Count == 0))
 254            {
 0255                return null;
 256            }
 257
 0258            var sb = new StringBuilder();
 259
 0260            ToString(values, separator, leadingSeparator, sb);
 261
 0262            return sb.ToString();
 263        }
 264
 265        internal static int GetHashCode(IList<NameValueHeaderValue> values)
 266        {
 0267            if ((values == null) || (values.Count == 0))
 268            {
 0269                return 0;
 270            }
 271
 0272            var result = 0;
 0273            for (var i = 0; i < values.Count; i++)
 274            {
 0275                result = result ^ values[i].GetHashCode();
 276            }
 0277            return result;
 278        }
 279
 280        private static int GetNameValueLength(StringSegment input, int startIndex, out NameValueHeaderValue parsedValue)
 281        {
 282            Contract.Requires(input != null);
 283            Contract.Requires(startIndex >= 0);
 284
 0285            parsedValue = null;
 286
 0287            if (StringSegment.IsNullOrEmpty(input) || (startIndex >= input.Length))
 288            {
 0289                return 0;
 290            }
 291
 292            // Parse the name, i.e. <name> in name/value string "<name>=<value>". Caller must remove
 293            // leading whitespaces.
 0294            var nameLength = HttpRuleParser.GetTokenLength(input, startIndex);
 295
 0296            if (nameLength == 0)
 297            {
 0298                return 0;
 299            }
 300
 0301            var name = input.Subsegment(startIndex, nameLength);
 0302            var current = startIndex + nameLength;
 0303            current = current + HttpRuleParser.GetWhitespaceLength(input, current);
 304
 305            // Parse the separator between name and value
 0306            if ((current == input.Length) || (input[current] != '='))
 307            {
 308                // We only have a name and that's OK. Return.
 0309                parsedValue = new NameValueHeaderValue();
 0310                parsedValue._name = name;
 0311                current = current + HttpRuleParser.GetWhitespaceLength(input, current); // skip whitespaces
 0312                return current - startIndex;
 313            }
 314
 0315            current++; // skip delimiter.
 0316            current = current + HttpRuleParser.GetWhitespaceLength(input, current);
 317
 318            // Parse the value, i.e. <value> in name/value string "<name>=<value>"
 0319            int valueLength = GetValueLength(input, current);
 320
 321            // Value after the '=' may be empty
 322            // Use parameterless ctor to avoid double-parsing of name and value, i.e. skip public ctor validation.
 0323            parsedValue = new NameValueHeaderValue();
 0324            parsedValue._name = name;
 0325            parsedValue._value = input.Subsegment(current, valueLength);
 0326            current = current + valueLength;
 0327            current = current + HttpRuleParser.GetWhitespaceLength(input, current); // skip whitespaces
 0328            return current - startIndex;
 329        }
 330
 331        // Returns the length of a name/value list, separated by 'delimiter'. E.g. "a=b, c=d, e=f" adds 3
 332        // name/value pairs to 'nameValueCollection' if 'delimiter' equals ','.
 333        internal static int GetNameValueListLength(
 334            StringSegment input,
 335            int startIndex,
 336            char delimiter,
 337            IList<NameValueHeaderValue> nameValueCollection)
 338        {
 339            Contract.Requires(nameValueCollection != null);
 340            Contract.Requires(startIndex >= 0);
 341
 0342            if ((StringSegment.IsNullOrEmpty(input)) || (startIndex >= input.Length))
 343            {
 0344                return 0;
 345            }
 346
 0347            var current = startIndex + HttpRuleParser.GetWhitespaceLength(input, startIndex);
 0348            while (true)
 349            {
 0350                NameValueHeaderValue parameter = null;
 0351                var nameValueLength = GetNameValueLength(input, current, out parameter);
 352
 0353                if (nameValueLength == 0)
 354                {
 355                    // There may be a trailing ';'
 0356                    return current - startIndex;
 357                }
 358
 0359                nameValueCollection.Add(parameter);
 0360                current = current + nameValueLength;
 0361                current = current + HttpRuleParser.GetWhitespaceLength(input, current);
 362
 0363                if ((current == input.Length) || (input[current] != delimiter))
 364                {
 365                    // We're done and we have at least one valid name/value pair.
 0366                    return current - startIndex;
 367                }
 368
 369                // input[current] is 'delimiter'. Skip the delimiter and whitespaces and try to parse again.
 0370                current++; // skip delimiter.
 0371                current = current + HttpRuleParser.GetWhitespaceLength(input, current);
 372            }
 373        }
 374
 375        public static NameValueHeaderValue Find(IList<NameValueHeaderValue> values, StringSegment name)
 376        {
 377            Contract.Requires((name != null) && (name.Length > 0));
 378
 0379            if ((values == null) || (values.Count == 0))
 380            {
 0381                return null;
 382            }
 383
 0384            for (var i = 0; i < values.Count; i++)
 385            {
 0386                var value = values[i];
 0387                if (value.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
 388                {
 0389                    return value;
 390                }
 391            }
 0392            return null;
 393        }
 394
 395        internal static int GetValueLength(StringSegment input, int startIndex)
 396        {
 397            Contract.Requires(input != null);
 398
 0399            if (startIndex >= input.Length)
 400            {
 0401                return 0;
 402            }
 403
 0404            var valueLength = HttpRuleParser.GetTokenLength(input, startIndex);
 405
 0406            if (valueLength == 0)
 407            {
 408                // A value can either be a token or a quoted string. Check if it is a quoted string.
 0409                if (HttpRuleParser.GetQuotedStringLength(input, startIndex, out valueLength) != HttpParseResult.Parsed)
 410                {
 411                    // We have an invalid value. Reset the name and return.
 0412                    return 0;
 413                }
 414            }
 0415            return valueLength;
 416        }
 417
 418        private static void CheckNameValueFormat(StringSegment name, StringSegment value)
 419        {
 0420            HeaderUtilities.CheckValidToken(name, nameof(name));
 0421            CheckValueFormat(value);
 0422        }
 423
 424        private static void CheckValueFormat(StringSegment value)
 425        {
 426            // Either value is null/empty or a valid token/quoted string
 0427            if (!(StringSegment.IsNullOrEmpty(value) || (GetValueLength(value, 0) == value.Length)))
 428            {
 0429                throw new FormatException(string.Format(CultureInfo.InvariantCulture, "The header value is invalid: '{0}
 430            }
 0431        }
 432
 433        private static NameValueHeaderValue CreateNameValue()
 434        {
 0435            return new NameValueHeaderValue();
 436        }
 437    }
 438}