File: System\Net\Http\WinHttpCookieContainerAdapter.cs
Web Access
Project: src\src\runtime\src\libraries\System.Net.Http.WinHttpHandler\src\System.Net.Http.WinHttpHandler.csproj (System.Net.Http.WinHttpHandler)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;

using SafeWinHttpHandle = Interop.WinHttp.SafeWinHttpHandle;

namespace System.Net.Http
{
    internal static class WinHttpCookieContainerAdapter
    {
        private const string CookieHeaderNameWithColon = "Cookie" + ":";

        public static void AddResponseCookiesToContainer(WinHttpRequestState state)
        {
            HttpRequestMessage? request = state.RequestMessage;
            SafeWinHttpHandle? requestHandle = state.RequestHandle;
            Debug.Assert(state.Handler != null);
            CookieContainer? cookieContainer = state.Handler.CookieContainer;

            Debug.Assert(state.Handler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer);
            Debug.Assert(request != null);
            Debug.Assert(requestHandle != null);
            Debug.Assert(cookieContainer != null);
            Debug.Assert(request.RequestUri != null);

            // Get 'Set-Cookie' headers from response.
            char[]? buffer = null;
            uint index = 0;
            string? cookieHeader;
            while (WinHttpResponseParser.GetResponseHeader(
                requestHandle, Interop.WinHttp.WINHTTP_QUERY_SET_COOKIE, ref buffer, ref index, out cookieHeader))
            {
                try
                {
                    cookieContainer.SetCookies(request.RequestUri, cookieHeader);
                    if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(cookieContainer, $"Added cookie: {cookieHeader}");
                }
                catch (CookieException)
                {
                    // We ignore malformed cookies in the response.
                    if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(cookieContainer, $"Ignoring invalid cookie: {cookieHeader}");
                }
            }
        }

        public static void ResetCookieRequestHeaders(WinHttpRequestState state, Uri redirectUri)
        {
            SafeWinHttpHandle? requestHandle = state.RequestHandle;

            Debug.Assert(state.Handler != null);
            Debug.Assert(state.Handler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer);
            Debug.Assert(state.Handler.CookieContainer != null);
            Debug.Assert(requestHandle != null);

            // Clear cookies.
            if (!Interop.WinHttp.WinHttpAddRequestHeaders(
                requestHandle,
                CookieHeaderNameWithColon,
                (uint)CookieHeaderNameWithColon.Length,
                Interop.WinHttp.WINHTTP_ADDREQ_FLAG_REPLACE))
            {
                int lastError = Marshal.GetLastWin32Error();
                if (lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)
                {
                    throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpAddRequestHeaders));
                }
            }

            // Re-add cookies. The GetCookieHeader() method will return the correct set of
            // cookies based on the redirectUri.
            string? cookieHeader = GetCookieHeader(redirectUri, state.Handler.CookieContainer);
            if (!string.IsNullOrEmpty(cookieHeader))
            {
                if (!Interop.WinHttp.WinHttpAddRequestHeaders(
                    requestHandle,
                    cookieHeader,
                    (uint)cookieHeader.Length,
                    Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))
                {
                    throw WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpAddRequestHeaders));
                }
            }
        }

        public static string? GetCookieHeader(Uri uri, CookieContainer cookies)
        {
            string? cookieHeader = null;

            Debug.Assert(cookies != null);

            string cookieValues = cookies.GetCookieHeader(uri);
            if (!string.IsNullOrEmpty(cookieValues))
            {
                cookieHeader = CookieHeaderNameWithColon + " " + cookieValues;
            }

            return cookieHeader;
        }
    }
}