| | | 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 | | |
| | | 4 | | using System.Collections; |
| | | 5 | | using System.Diagnostics; |
| | | 6 | | using System.Diagnostics.CodeAnalysis; |
| | | 7 | | using System.Text; |
| | | 8 | | |
| | | 9 | | namespace System.Net.Http.Headers |
| | | 10 | | { |
| | | 11 | | internal abstract class HttpHeaderParser |
| | | 12 | | { |
| | | 13 | | public const string DefaultSeparator = ", "; |
| | 1 | 14 | | public static readonly byte[] DefaultSeparatorBytes = ", "u8.ToArray(); |
| | | 15 | | |
| | 2938495 | 16 | | public bool SupportsMultipleValues { get; } |
| | | 17 | | |
| | 0 | 18 | | public string Separator { get; } |
| | | 19 | | |
| | 0 | 20 | | public byte[] SeparatorBytes { get; } |
| | | 21 | | |
| | | 22 | | // If ValueType implements Equals() as required, there is no need to provide a comparer. A comparer is needed |
| | | 23 | | // e.g. if we want to compare strings using case-insensitive comparison. |
| | 0 | 24 | | public virtual IEqualityComparer? Comparer => null; |
| | | 25 | | |
| | 42 | 26 | | protected HttpHeaderParser(bool supportsMultipleValues) |
| | 42 | 27 | | { |
| | 42 | 28 | | SupportsMultipleValues = supportsMultipleValues; |
| | 42 | 29 | | Separator = DefaultSeparator; |
| | 42 | 30 | | SeparatorBytes = DefaultSeparatorBytes; |
| | 42 | 31 | | } |
| | | 32 | | |
| | 3 | 33 | | protected HttpHeaderParser(bool supportsMultipleValues, string separator) : this(supportsMultipleValues) |
| | 3 | 34 | | { |
| | 3 | 35 | | Debug.Assert(!string.IsNullOrEmpty(separator)); |
| | 3 | 36 | | Debug.Assert(Ascii.IsValid(separator)); |
| | | 37 | | |
| | 3 | 38 | | if (supportsMultipleValues) |
| | 2 | 39 | | { |
| | 2 | 40 | | Separator = separator; |
| | 2 | 41 | | SeparatorBytes = Encoding.ASCII.GetBytes(separator); |
| | 2 | 42 | | } |
| | 3 | 43 | | } |
| | | 44 | | |
| | | 45 | | // If a parser supports multiple values, a call to ParseValue/TryParseValue should return a value for 'index' |
| | | 46 | | // pointing to the next non-whitespace character after a delimiter. E.g. if called with a start index of 0 |
| | | 47 | | // for string "value , second_value", then after the call completes, 'index' must point to 's', i.e. the first |
| | | 48 | | // non-whitespace after the separator ','. |
| | | 49 | | public abstract bool TryParseValue(string? value, object? storeValue, ref int index, [NotNullWhen(true)] out obj |
| | | 50 | | |
| | | 51 | | public object ParseValue(string? value, object? storeValue, ref int index) |
| | 516138 | 52 | | { |
| | | 53 | | // Index may be value.Length (e.g. both 0). This may be allowed for some headers (e.g. Accept but not |
| | | 54 | | // allowed by others (e.g. Content-Length). The parser has to decide if this is valid or not. |
| | 516138 | 55 | | Debug.Assert((value == null) || ((index >= 0) && (index <= value.Length))); |
| | | 56 | | |
| | | 57 | | // If a parser returns 'null', it means there was no value, but that's valid (e.g. "Accept: "). The caller |
| | | 58 | | // can ignore the value. |
| | 516138 | 59 | | if (!TryParseValue(value, storeValue, ref index, out object? result)) |
| | 7540 | 60 | | { |
| | 7540 | 61 | | throw new FormatException(SR.Format(System.Globalization.CultureInfo.InvariantCulture, SR.net_http_heade |
| | 7540 | 62 | | value == null ? "<null>" : value.Substring(index))); |
| | | 63 | | } |
| | 508598 | 64 | | return result; |
| | 508598 | 65 | | } |
| | | 66 | | |
| | | 67 | | // If ValueType is a custom header value type (e.g. NameValueHeaderValue) it already implements ToString() corre |
| | | 68 | | // However for existing types like int, byte[], DateTimeOffset we can't override ToString(). Therefore the |
| | | 69 | | // parser provides a ToString() virtual method that can be overridden by derived types to correctly serialize |
| | | 70 | | // values (e.g. byte[] to Base64 encoded string). |
| | | 71 | | public virtual string? ToString(object value) |
| | 1216422 | 72 | | { |
| | 1216422 | 73 | | Debug.Assert(value != null); |
| | | 74 | | |
| | 1216422 | 75 | | return value.ToString(); |
| | 1216422 | 76 | | } |
| | | 77 | | } |
| | | 78 | | } |