File: Internal\RequestMessageSnapshot.cs
Web Access
Project: src\src\Libraries\Microsoft.Extensions.Http.Resilience\Microsoft.Extensions.Http.Resilience.csproj (Microsoft.Extensions.Http.Resilience)
// 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.Generic;
using System.Net.Http;
using Microsoft.Extensions.ObjectPool;
using Microsoft.Shared.Diagnostics;
using Microsoft.Shared.Pools;
 
namespace Microsoft.Extensions.Http.Resilience.Internal;
 
internal sealed class RequestMessageSnapshot : IResettable, IDisposable
{
    private static readonly ObjectPool<RequestMessageSnapshot> _snapshots = PoolFactory.CreateResettingPool<RequestMessageSnapshot>();
 
    private readonly List<KeyValuePair<string, IEnumerable<string>>> _headers = [];
    private readonly List<KeyValuePair<string, object?>> _properties = [];
 
    private HttpMethod? _method;
    private Uri? _requestUri;
    private Version? _version;
    private HttpContent? _content;
 
    public static RequestMessageSnapshot Create(HttpRequestMessage request)
    {
        var snapshot = _snapshots.Get();
        snapshot.Initialize(request);
        return snapshot;
    }
 
    public HttpRequestMessage CreateRequestMessage()
    {
        var clone = new HttpRequestMessage(_method!, _requestUri)
        {
            Content = _content,
            Version = _version!
        };
 
#if NET5_0_OR_GREATER
        foreach (var prop in _properties)
        {
            _ = clone.Options.TryAdd(prop.Key, prop.Value);
        }
#else
        foreach (var prop in _properties)
        {
            clone.Properties.Add(prop);
        }
#endif
        foreach (KeyValuePair<string, IEnumerable<string>> header in _headers)
        {
            _ = clone.Headers.TryAddWithoutValidation(header.Key, header.Value);
        }
 
        return clone;
    }
 
    bool IResettable.TryReset()
    {
        _properties.Clear();
        _headers.Clear();
 
        _method = null;
        _version = null;
        _requestUri = null;
        _content = null;
 
        return true;
    }
 
    void IDisposable.Dispose() => _snapshots.Return(this);
 
    private void Initialize(HttpRequestMessage request)
    {
        if (request.Content is StreamContent)
        {
            Throw.InvalidOperationException($"{nameof(StreamContent)} content cannot by cloned.");
        }
 
        _method = request.Method;
        _version = request.Version;
        _requestUri = request.RequestUri;
        _content = request.Content;
 
        // headers
        _headers.AddRange(request.Headers);
 
        // props
#if NET5_0_OR_GREATER
        _properties.AddRange(request.Options);
#else
        _properties.AddRange(request.Properties);
#endif
    }
}