| File: BaseHeaderParser.cs | Web Access |
| Project: src\aspnetcore\src\Http\Headers\src\Microsoft.Net.Http.Headers.csproj (Microsoft.Net.Http.Headers) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Primitives; namespace Microsoft.Net.Http.Headers; internal abstract class BaseHeaderParser<T> : HttpHeaderParser<T> { protected BaseHeaderParser(bool supportsMultipleValues) : base(supportsMultipleValues) { } // Returns the number of characters consumed at 'startIndex'. // - returns > 0 and sets 'parsedValue' to a non-null value when a value was successfully parsed. // - returns > 0 and sets 'parsedValue' to null when input was consumed but no value could be // produced (e.g. an unterminated quoted-string was scanned to end-of-input). This lets the // outer recovery loop in HttpHeaderParser.TryParseValues skip past the malformed span in O(1) // instead of advancing one character at a time. // - returns 0 when nothing was recognized at 'startIndex'. protected abstract int GetParsedValueLength(StringSegment value, int startIndex, out T? parsedValue); public sealed override bool TryParseValue(StringSegment value, int startIndex, out int parsedLength, out T? parsedValue) { parsedLength = 0; parsedValue = default; // If multiple values are supported (i.e. list of values), then accept an empty string: The header may // be added multiple times to the request/response message. E.g. // Accept: text/xml; q=1 // Accept: // Accept: text/plain; q=0.2 if (StringSegment.IsNullOrEmpty(value) || (startIndex == value.Length)) { return SupportsMultipleValues; } var current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(value, startIndex, SupportsMultipleValues, out var separatorFound); if (separatorFound && !SupportsMultipleValues) { return false; // leading separators not allowed if we don't support multiple values. } if (current == value.Length) { if (SupportsMultipleValues) { parsedLength = current - startIndex; } return SupportsMultipleValues; } var length = GetParsedValueLength(value, current, out var result); if (length == 0) { return false; } current = current + length; // The per-element parser consumed input but couldn't produce a value. Report the consumed // span so the caller can resume parsing after the malformed input rather than re-scanning it. if (result == null) { parsedLength = current - startIndex; return false; } current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(value, current, SupportsMultipleValues, out separatorFound); // If we support multiple values and we've not reached the end of the string, then we must have a separator. if ((separatorFound && !SupportsMultipleValues) || (!separatorFound && (current < value.Length))) { parsedLength = current - startIndex; return false; } parsedLength = current - startIndex; parsedValue = result; return true; } }