File: Internal\ParsingHelpers.cs
Web Access
Project: src\src\Http\Http.Abstractions\src\Microsoft.AspNetCore.Http.Abstractions.csproj (Microsoft.AspNetCore.Http.Abstractions)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Linq;
using Microsoft.Extensions.Primitives;
 
namespace Microsoft.AspNetCore.Http;
 
internal static class ParsingHelpers
{
    public static StringValues GetHeader(IHeaderDictionary headers, string key)
    {
        StringValues value;
        return headers.TryGetValue(key, out value) ? value : StringValues.Empty;
    }
 
    public static string[] GetHeaderSplit(IHeaderDictionary headers, string key)
    {
        var values = GetHeaderUnmodified(headers, key);
 
        ValueListBuilder<string> strings = new([null!, null!, null!, null!]);
 
        foreach (var segment in new HeaderSegmentCollection(values))
        {
            if (!StringSegment.IsNullOrEmpty(segment.Data))
            {
                var value = DeQuote(segment.Data.Value);
                if (!string.IsNullOrEmpty(value))
                {
                    strings.Add(value);
                }
            }
        }
 
        string[] result = strings.AsSpan().ToArray();
        strings.Dispose();
 
        return result;
    }
 
    public static StringValues GetHeaderUnmodified(IHeaderDictionary headers, string key)
    {
        ArgumentNullException.ThrowIfNull(headers);
 
        StringValues values;
        return headers.TryGetValue(key, out values) ? values : StringValues.Empty;
    }
 
    public static void SetHeaderJoined(IHeaderDictionary headers, string key, StringValues value)
    {
        ArgumentNullException.ThrowIfNull(headers);
        ArgumentException.ThrowIfNullOrEmpty(key);
 
        if (StringValues.IsNullOrEmpty(value))
        {
            headers.Remove(key);
        }
        else
        {
            headers[key] = string.Join(",", value.Select(QuoteIfNeeded));
        }
    }
 
    // Quote items that contain commas and are not already quoted.
    private static string? QuoteIfNeeded(string? value)
    {
        if (!string.IsNullOrEmpty(value) &&
            value.Contains(',') &&
            (value[0] != '"' || value[value.Length - 1] != '"'))
        {
            return $"\"{value}\"";
        }
        return value;
    }
 
    private static string? DeQuote(string? value)
    {
        if (!string.IsNullOrEmpty(value) &&
            (value.Length > 1 && value[0] == '"' && value[value.Length - 1] == '"'))
        {
            value = value.Substring(1, value.Length - 2);
        }
 
        return value;
    }
 
    public static void SetHeaderUnmodified(IHeaderDictionary headers, string key, StringValues? values)
    {
        ArgumentNullException.ThrowIfNull(headers);
        ArgumentException.ThrowIfNullOrEmpty(key);
 
        if (!values.HasValue || StringValues.IsNullOrEmpty(values.GetValueOrDefault()))
        {
            headers.Remove(key);
        }
        else
        {
            headers[key] = values.GetValueOrDefault();
        }
    }
 
    public static void AppendHeaderJoined(IHeaderDictionary headers, string key, params string[] values)
    {
        ArgumentNullException.ThrowIfNull(headers);
        ArgumentNullException.ThrowIfNull(key);
 
        if (values == null || values.Length == 0)
        {
            return;
        }
 
        string? existing = GetHeader(headers, key);
        if (existing == null)
        {
            SetHeaderJoined(headers, key, values);
        }
        else
        {
            headers[key] = existing + "," + string.Join(",", values.Select(QuoteIfNeeded));
        }
    }
 
    public static void AppendHeaderUnmodified(IHeaderDictionary headers, string key, StringValues values)
    {
        ArgumentNullException.ThrowIfNull(headers);
        ArgumentNullException.ThrowIfNull(key);
 
        if (values.Count == 0)
        {
            return;
        }
 
        var existing = GetHeaderUnmodified(headers, key);
        SetHeaderUnmodified(headers, key, StringValues.Concat(existing, values));
    }
}