using System.Net; namespace XFESystem.Browser; public interface IWebCookieStore { string ReadDocumentCookies(Uri address); void WriteDocumentCookie(Uri address, string value); } /// Bounded session cookies shared by HTTP and document.cookie. No host profile import. public sealed class BrowserCookieStore : IWebCookieStore { private readonly CookieContainer cookies = new(256, 32, 4096); private readonly object gate = new(); public string RequestHeader(Uri address) { lock (gate) return cookies.GetCookieHeader(address); } public void Receive(Uri address, string header) { if (header.Length > 4096) return; lock (gate) { try { cookies.SetCookies(address, header); } catch (CookieException) { } } } public string ReadDocumentCookies(Uri address) { lock (gate) return string.Join("; ", cookies.GetCookies(address).Cast().Where(c => !c.HttpOnly).Select(c => c.Name + "=" + c.Value)); } public void WriteDocumentCookie(Uri address, string value) { if (value.Length > 4096 || value.Any(c => c is '\r' or '\n' or '\0')) return; // Script cannot create HttpOnly cookies or overwrite an existing one. string name = value.Split(';')[0].Split('=')[0].Trim(); if (value.Split(';').Skip(1).Any(p => p.Trim().Equals("httponly", StringComparison.OrdinalIgnoreCase))) return; lock (gate) { if (cookies.GetCookies(address).Cast().Any(c => c.HttpOnly && c.Name == name)) return; try { cookies.SetCookies(address, value); } catch (CookieException) { } } } }