/* * Copyright (c) 2022 Vaughn Nugent * * Library: VNLib * Package: VNLib.Net.Http * File: ConnectionInfo.cs * * ConnectionInfo.cs is part of VNLib.Net.Http which is part of the larger * VNLib collection of libraries and utilities. * * VNLib.Net.Http is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * VNLib.Net.Http is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see https://www.gnu.org/licenses/. */ using System; using System.Net; using System.Linq; using System.Text; using System.Collections.Generic; using System.Security.Authentication; using VNLib.Net.Http.Core; using VNLib.Utils.Extensions; namespace VNLib.Net.Http { /// internal sealed class ConnectionInfo : IConnectionInfo { private HttpContext Context; /// public Uri RequestUri => Context.Request.Location; /// public string Path => RequestUri.LocalPath; /// public string? UserAgent => Context.Request.UserAgent; /// public IHeaderCollection Headers { get; private set; } /// public bool CrossOrigin { get; } /// public bool IsWebSocketRequest { get; } /// public ContentType ContentType => Context.Request.ContentType; /// public HttpMethod Method => Context.Request.Method; /// public HttpVersion ProtocolVersion => Context.Request.HttpVersion; /// public bool IsSecure => Context.Request.EncryptionVersion != SslProtocols.None; /// public SslProtocols SecurityProtocol => Context.Request.EncryptionVersion; /// public Uri? Origin => Context.Request.Origin; /// public Uri? Referer => Context.Request.Referrer; /// public Tuple? Range => Context.Request.Range; /// public IPEndPoint LocalEndpoint => Context.Request.LocalEndPoint; /// public IPEndPoint RemoteEndpoint => Context.Request.RemoteEndPoint; /// public Encoding Encoding => Context.ParentServer.Config.HttpEncoding; /// public IReadOnlyDictionary RequestCookies => Context.Request.Cookies; /// public IEnumerable Accept => Context.Request.Accept; /// public TransportSecurityInfo? TransportSecurity => Context.GetSecurityInfo(); /// public bool Accepts(ContentType type) { //Get the content type string from he specified content type string contentType = HttpHelpers.GetContentTypeString(type); return Accepts(contentType); } /// public bool Accepts(string contentType) { if (AcceptsAny()) { return true; } //If client accepts exact requested encoding if (Accept.Contains(contentType)) { return true; } //Search accept types to determine if the content type is acceptable bool accepted = Accept .Where(ctype => { //Get prinary side of mime type ReadOnlySpan primary = contentType.AsSpan().SliceBeforeParam('/'); ReadOnlySpan ctSubType = ctype.AsSpan().SliceBeforeParam('/'); //See if accepts any subtype, or the primary sub-type matches return ctSubType[0] == '*' || ctSubType.Equals(primary, StringComparison.OrdinalIgnoreCase); }).Any(); return accepted; } /// /// Determines if the connection accepts any content type /// /// true if the connection accepts any content typ, false otherwise private bool AcceptsAny() { //Accept any if no accept header was present, or accept all value */* return Context.Request.Accept.Count == 0 || Accept.Where(static t => t.StartsWith("*/*", StringComparison.OrdinalIgnoreCase)).Any(); } /// public void SetCookie(string name, string value, string? domain, string? path, TimeSpan Expires, CookieSameSite sameSite, bool httpOnly, bool secure) { //Create the new cookie HttpCookie cookie = new(name) { Value = value, Domain = domain, Path = path, MaxAge = Expires, //Set the session lifetime flag if the timeout is max value IsSession = Expires == TimeSpan.MaxValue, //If the connection is cross origin, then we need to modify the secure and samsite values SameSite = CrossOrigin ? CookieSameSite.None : sameSite, Secure = secure | CrossOrigin, HttpOnly = httpOnly }; //Set the cookie Context.Response.AddCookie(cookie); } internal ConnectionInfo(HttpContext ctx) { //Create new header collection Headers = new VnHeaderCollection(ctx); //set co value CrossOrigin = ctx.Request.IsCrossOrigin(); //Set websocket status IsWebSocketRequest = ctx.Request.IsWebSocketRequest(); //Update the context referrence Context = ctx; } #nullable disable internal void Clear() { Context = null; (Headers as VnHeaderCollection).Clear(); Headers = null; } } }