File: Logging\HttpHeadersLogValue.cs
Web Access
Project: src\src\libraries\Microsoft.Extensions.Http\src\Microsoft.Extensions.Http.csproj (Microsoft.Extensions.Http)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Http.Headers;
using System.Text;
 
namespace Microsoft.Extensions.Http.Logging
{
    internal sealed class HttpHeadersLogValue : IReadOnlyList<KeyValuePair<string, object>>
    {
        private readonly Kind _kind;
        private readonly Func<string, bool> _shouldRedactHeaderValue;
 
        private string? _formatted;
        private List<KeyValuePair<string, object>>? _values;
 
        public HttpHeadersLogValue(Kind kind, HttpHeaders headers, HttpHeaders? contentHeaders, Func<string, bool> shouldRedactHeaderValue)
        {
            _kind = kind;
            _shouldRedactHeaderValue = shouldRedactHeaderValue;
 
            Headers = headers;
            ContentHeaders = contentHeaders;
        }
 
        public HttpHeaders Headers { get; }
 
        public HttpHeaders? ContentHeaders { get; }
 
        private List<KeyValuePair<string, object>> Values
        {
            get
            {
                if (_values == null)
                {
                    var values = new List<KeyValuePair<string, object>>();
 
                    foreach (KeyValuePair<string, IEnumerable<string>> kvp in Headers)
                    {
                        values.Add(new KeyValuePair<string, object>(kvp.Key, kvp.Value));
                    }
 
                    if (ContentHeaders != null)
                    {
                        foreach (KeyValuePair<string, IEnumerable<string>> kvp in ContentHeaders)
                        {
                            values.Add(new KeyValuePair<string, object>(kvp.Key, kvp.Value));
                        }
                    }
 
                    _values = values;
                }
 
                return _values;
            }
        }
 
        public KeyValuePair<string, object> this[int index]
        {
            get
            {
                if (index < 0 || index >= Count)
                {
                    throw new IndexOutOfRangeException(nameof(index));
                }
 
                return Values[index];
            }
        }
 
        public int Count => Values.Count;
 
        public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
        {
            return Values.GetEnumerator();
        }
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return Values.GetEnumerator();
        }
 
        public override string ToString()
        {
            if (_formatted == null)
            {
                var builder = new StringBuilder();
                builder.AppendLine(_kind == Kind.Request ? "Request Headers:" : "Response Headers:");
 
                for (int i = 0; i < Values.Count; i++)
                {
                    KeyValuePair<string, object> kvp = Values[i];
                    builder.Append(kvp.Key);
                    builder.Append(": ");
 
                    if (_shouldRedactHeaderValue(kvp.Key))
                    {
                        builder.Append('*');
                        builder.AppendLine();
                    }
                    else
                    {
#if NET
                        builder.AppendJoin(", ", (IEnumerable<object>)kvp.Value);
                        builder.AppendLine();
#else
                        foreach (object value in (IEnumerable<object>)kvp.Value)
                        {
                            builder.Append(value);
                            builder.Append(", ");
                        }
 
                        // Remove the extra ', '
                        builder.Remove(builder.Length - 2, 2);
                        builder.AppendLine();
#endif
                    }
                }
 
                _formatted = builder.ToString();
            }
 
            return _formatted;
        }
 
        public enum Kind
        {
            Request,
            Response,
        }
    }
}