File: CookiePolicyMiddleware.cs
Web Access
Project: src\src\Security\CookiePolicy\src\Microsoft.AspNetCore.CookiePolicy.csproj (Microsoft.AspNetCore.CookiePolicy)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
 
namespace Microsoft.AspNetCore.CookiePolicy;
 
/// <summary>
/// Initializes a new instance of <see cref="CookiePolicyMiddleware"/>.
/// </summary>
/// <remarks>
/// When using <see cref="CookieOptions"/> to configure cookies, note that a
/// <see cref="CookieOptions"/> instance is intended to govern the behavior of an individual cookie.
/// Reusing the same <see cref="CookieOptions"/> instance across multiple cookies can lead to unintended
/// consequences, such as modifications affecting multiple cookies. We recommend instantiating a new
/// <see cref="CookieOptions"/> object for each cookie to ensure that the configuration is applied
/// independently.
/// </remarks>
public class CookiePolicyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;
 
    /// <summary>
    /// Initializes a new instance of <see cref="CookiePolicyMiddleware"/>.
    /// </summary>
    /// <param name="next">A reference to the next item in the application pipeline.</param>
    /// <param name="options">Accessor to <see cref="CookiePolicyOptions"/>.</param>
    /// <param name="factory">The <see cref="ILoggerFactory"/>.</param>
    public CookiePolicyMiddleware(RequestDelegate next, IOptions<CookiePolicyOptions> options, ILoggerFactory factory)
    {
        Options = options.Value;
        _next = next ?? throw new ArgumentNullException(nameof(next));
        _logger = factory.CreateLogger<CookiePolicyMiddleware>();
    }
 
    /// <summary>
    /// Initializes a new instance of <see cref="CookiePolicyMiddleware"/>.
    /// </summary>
    /// <param name="next">A reference to the next item in the application pipeline.</param>
    /// <param name="options">Accessor to <see cref="CookiePolicyOptions"/>.</param>
    public CookiePolicyMiddleware(RequestDelegate next, IOptions<CookiePolicyOptions> options)
    {
        Options = options.Value;
        _next = next;
        _logger = NullLogger.Instance;
    }
 
    /// <summary>
    /// Gets or sets the <see cref="CookiePolicyOptions"/>.
    /// </summary>
    public CookiePolicyOptions Options { get; set; }
 
    /// <summary>
    /// Invokes the middleware.
    /// </summary>
    /// <param name="context">The <see cref="HttpContext" />.</param>
    public Task Invoke(HttpContext context)
    {
        var feature = context.Features.Get<IResponseCookiesFeature>() ?? new ResponseCookiesFeature(context.Features);
        var wrapper = new ResponseCookiesWrapper(context, Options, feature, _logger);
        context.Features.Set<IResponseCookiesFeature>(new CookiesWrapperFeature(wrapper));
        context.Features.Set<ITrackingConsentFeature>(wrapper);
 
        return _next(context);
    }
 
    private sealed class CookiesWrapperFeature : IResponseCookiesFeature
    {
        public CookiesWrapperFeature(ResponseCookiesWrapper wrapper)
        {
            Cookies = wrapper;
        }
 
        public IResponseCookies Cookies { get; }
    }
}