diff options
Diffstat (limited to 'lib/Plugins.Essentials')
7 files changed, 118 insertions, 139 deletions
diff --git a/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs b/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs index 33da10e..137fa4a 100644 --- a/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs +++ b/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs @@ -320,7 +320,7 @@ namespace VNLib.Plugins.Essentials.Accounts //Get the "local" account flag from the user object bool localAccount = user.IsLocalAccount(); - //Set local account flag + //Set local account flag on the session entity.Session.HasLocalAccount(localAccount); //Return the client encrypted data diff --git a/lib/Plugins.Essentials/src/EventProcessor.cs b/lib/Plugins.Essentials/src/EventProcessor.cs index a207e35..bd4383f 100644 --- a/lib/Plugins.Essentials/src/EventProcessor.cs +++ b/lib/Plugins.Essentials/src/EventProcessor.cs @@ -35,10 +35,10 @@ using VNLib.Net.Http; using VNLib.Utils.IO; using VNLib.Utils.Logging; using VNLib.Utils.Resources; +using VNLib.Plugins.Essentials.Accounts; using VNLib.Plugins.Essentials.Content; using VNLib.Plugins.Essentials.Sessions; using VNLib.Plugins.Essentials.Extensions; -using VNLib.Plugins.Essentials.Accounts; #nullable enable @@ -163,12 +163,10 @@ namespace VNLib.Plugins.Essentials * Wrapper class for converting IHttpEvent endpoints to * httpEntityEndpoints */ - private sealed class EvEndpointWrapper : IVirtualEndpoint<HttpEntity> + private sealed record class EvEndpointWrapper(IVirtualEndpoint<IHttpEvent> Wrapped) : IVirtualEndpoint<HttpEntity> { - private readonly IVirtualEndpoint<IHttpEvent> _wrapped; - public EvEndpointWrapper(IVirtualEndpoint<IHttpEvent> wrapping) => _wrapped = wrapping; - string IEndpoint.Path => _wrapped.Path; - ValueTask<VfReturnType> IVirtualEndpoint<HttpEntity>.Process(HttpEntity entity) => _wrapped.Process(entity); + string IEndpoint.Path => Wrapped.Path; + ValueTask<VfReturnType> IVirtualEndpoint<HttpEntity>.Process(HttpEntity entity) => Wrapped.Process(entity); } @@ -318,6 +316,8 @@ namespace VNLib.Plugins.Essentials //Start cancellation token CancellationTokenSource timeout = new(Options.ExecutionTimeout); + FileProcessArgs args; + try { //Session handle, default to the shared empty session @@ -341,24 +341,35 @@ namespace VNLib.Plugins.Essentials HttpEntity entity = new(httpEvent, this, in sessionHandle, timeout.Token); //Pre-process entity - FileProcessArgs preProc = await PreProcessEntityAsync(entity); + args = await PreProcessEntityAsync(entity); //If preprocess returned a value, exit - if (preProc != FileProcessArgs.Continue) + if (args != FileProcessArgs.Continue) { - ProcessFile(httpEvent, in preProc); + ProcessFile(httpEvent, in args); return; } if (VirtualEndpoints.Count > 0) { - //Process a virtual file - FileProcessArgs virtualArgs = await ProcessVirtualAsync(entity); + //See if the virtual file is servicable + if (!VirtualEndpoints.TryGetValue(entity.Server.Path, out IVirtualEndpoint<HttpEntity>? vf)) + { + args = FileProcessArgs.Continue; + } + else + { + //Invoke the page handler process method + VfReturnType rt = await vf.Process(entity); + + //Process a virtual file + args = GetArgsFromReturn(entity, rt); + } //If the entity was processed, exit - if (virtualArgs != FileProcessArgs.Continue) + if (args != FileProcessArgs.Continue) { - ProcessFile(httpEvent, in virtualArgs); + ProcessFile(httpEvent, in args); return; } } @@ -371,7 +382,7 @@ namespace VNLib.Plugins.Essentials } //Finally process as file - FileProcessArgs args = await RouteFileAsync(entity); + args = await RouteFileAsync(entity); //Finally process the file ProcessFile(httpEvent, in args); @@ -582,38 +593,29 @@ namespace VNLib.Plugins.Essentials } } - /// <summary> - /// If virtual endpoints are enabled, checks for the existance of an - /// endpoint and attmepts to process that endpoint. + /// Gets the <see cref="FileProcessArgs"/> that will finalize the response from the + /// given <see cref="VfReturnType"/> /// </summary> - /// <param name="entity">The http entity to proccess</param> - /// <returns>The results to return to the file processor, or null of the entity requires further processing</returns> - protected virtual async ValueTask<FileProcessArgs> ProcessVirtualAsync(HttpEntity entity) + /// <param name="entity">The entity to be processed</param> + /// <param name="returnType">The virtual file processor return type</param> + /// <returns>The process args to end processing for the virtual endpoint</returns> + protected virtual FileProcessArgs GetArgsFromReturn(HttpEntity entity, VfReturnType returnType) { - //See if the virtual file is servicable - if (!VirtualEndpoints.TryGetValue(entity.Server.Path, out IVirtualEndpoint<HttpEntity>? vf)) - { - return FileProcessArgs.Continue; - } - - //Invoke the page handler process method - VfReturnType rt = await vf.Process(entity); - - if (rt == VfReturnType.VirtualSkip) + if (returnType == VfReturnType.VirtualSkip) { //Virtual file was handled by the handler return FileProcessArgs.VirtualSkip; } - else if(rt == VfReturnType.ProcessAsFile) + else if (returnType == VfReturnType.ProcessAsFile) { return FileProcessArgs.Continue; } - + //If not a get request, process it directly if (entity.Server.Method == HttpMethod.GET) { - switch (rt) + switch (returnType) { case VfReturnType.Forbidden: return FileProcessArgs.Deny; @@ -625,8 +627,8 @@ namespace VNLib.Plugins.Essentials break; } } - - switch (rt) + + switch (returnType) { case VfReturnType.Forbidden: entity.CloseResponse(HttpStatusCode.Forbidden); @@ -642,7 +644,7 @@ namespace VNLib.Plugins.Essentials entity.CloseResponse(HttpStatusCode.NotFound); break; } - + return FileProcessArgs.VirtualSkip; } @@ -654,9 +656,9 @@ namespace VNLib.Plugins.Essentials /// <returns>The results to return to the file processor, this method must return an argument</returns> protected virtual async ValueTask<FileProcessArgs> RouteFileAsync(HttpEntity entity) { - //Read local copy of the router - + //Read local copy of the router IPageRouter? router = Router; + //Make sure router is set if (router == null) { @@ -668,8 +670,7 @@ namespace VNLib.Plugins.Essentials PostProcessFile(entity, in routine); //Return the routine return routine; - } - + } /// <summary> /// Finds the file specified by the request and the server root the user has requested. diff --git a/lib/Plugins.Essentials/src/Extensions/ConnectionInfoExtensions.cs b/lib/Plugins.Essentials/src/Extensions/ConnectionInfoExtensions.cs index a91f196..8cabffd 100644 --- a/lib/Plugins.Essentials/src/Extensions/ConnectionInfoExtensions.cs +++ b/lib/Plugins.Essentials/src/Extensions/ConnectionInfoExtensions.cs @@ -24,10 +24,12 @@ using System; using System.Net; +using System.Linq; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using VNLib.Net.Http; +using VNLib.Utils.Extensions; #nullable enable @@ -52,6 +54,69 @@ namespace VNLib.Plugins.Essentials.Extensions /// Cache-Control header value for disabling cache /// </summary> public static readonly string NO_CACHE_RESPONSE_HEADER_VALUE = HttpHelpers.GetCacheString(CacheType.NoCache | CacheType.NoStore | CacheType.Revalidate); + + + /// <summary> + /// Determines if the client accepts the response content type + /// </summary> + /// <param name="server"></param> + /// <param name="type">The desired content type</param> + /// <returns>True if the client accepts the content type, false otherwise</returns> + public static bool Accepts(this IConnectionInfo server, ContentType type) + { + //Get the content type string from he specified content type + string contentType = HttpHelpers.GetContentTypeString(type); + return Accepts(server, contentType); + } + + /// <summary> + /// Determines if the client accepts the response content type + /// </summary> + /// <param name="server"></param> + /// <param name="contentType">The desired content type</param> + /// <returns>True if the client accepts the content type, false otherwise</returns> + public static bool Accepts(this IConnectionInfo server, string contentType) + { + if (AcceptsAny(server)) + { + return true; + } + + //If client accepts exact requested encoding + if (server.Accept.Contains(contentType, StringComparer.OrdinalIgnoreCase)) + { + return true; + } + + //Search for the content-sub-type + + //Get prinary side of mime type + ReadOnlySpan<char> primary = contentType.AsSpan().SliceBeforeParam('/'); + + foreach(string accept in server.Accept) + { + //The the accept subtype + ReadOnlySpan<char> ctSubType = accept.AsSpan().SliceBeforeParam('/'); + + //See if accepts any subtype, or the primary sub-type matches + if (ctSubType[0] == '*' || ctSubType.Equals(primary, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return false; + } + + /// <summary> + /// Determines if the connection accepts any content type + /// </summary> + /// <returns>true if the connection accepts any content typ, false otherwise</returns> + private static bool AcceptsAny(this IConnectionInfo server) + { + //Accept any if no accept header was present, or accept all value */* + return server.Accept.Count == 0 || server.Accept.Where(static t => t.StartsWith("*/*", StringComparison.OrdinalIgnoreCase)).Any(); + } /// <summary> /// Gets the <see cref="HttpRequestHeader.IfModifiedSince"/> header value and converts its value to a datetime value diff --git a/lib/Plugins.Essentials/src/Oauth/IOAuth2Provider.cs b/lib/Plugins.Essentials/src/Oauth/IOAuth2Provider.cs deleted file mode 100644 index 30944b8..0000000 --- a/lib/Plugins.Essentials/src/Oauth/IOAuth2Provider.cs +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Plugins.Essentials -* File: IOAuth2Provider.cs -* -* IOAuth2Provider.cs is part of VNLib.Plugins.Essentials which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Plugins.Essentials 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.Plugins.Essentials 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.Threading.Tasks; - -using VNLib.Plugins.Essentials.Sessions; - -namespace VNLib.Plugins.Essentials.Oauth -{ - /// <summary> - /// An interface that Oauth2 serice providers must implement - /// to provide sessions to an <see cref="EventProcessor"/> - /// processor endpoint processor - /// </summary> - public interface IOAuth2Provider : ISessionProvider - { - /// <summary> - /// Gets a value indicating how long a session may be valid for - /// </summary> - public TimeSpan MaxTokenLifetime { get; } - } -}
\ No newline at end of file diff --git a/lib/Plugins.Essentials/src/Oauth/OauthHttpExtensions.cs b/lib/Plugins.Essentials/src/Oauth/OauthHttpExtensions.cs index 11ab61a..3bce1f6 100644 --- a/lib/Plugins.Essentials/src/Oauth/OauthHttpExtensions.cs +++ b/lib/Plugins.Essentials/src/Oauth/OauthHttpExtensions.cs @@ -134,15 +134,15 @@ namespace VNLib.Plugins.Essentials.Oauth //Set the error result in the header ev.Server.Headers[HttpResponseHeader.WwwAuthenticate] = error switch { - ErrorType.InvalidRequest => $"Bearer error=\"invalid_request\"", - ErrorType.UnauthorizedClient => $"Bearer error=\"unauthorized_client\"", - ErrorType.UnsupportedResponseType => $"Bearer error=\"unsupported_response_type\"", - ErrorType.InvalidScope => $"Bearer error=\"invalid_scope\"", - ErrorType.ServerError => $"Bearer error=\"server_error\"", - ErrorType.TemporarilyUnabavailable => $"Bearer error=\"temporarily_unavailable\"", - ErrorType.InvalidClient => $"Bearer error=\"invalid_client\"", - ErrorType.InvalidToken => $"Bearer error=\"invalid_token\"", - _ => $"Bearer error=\"error\"", + ErrorType.InvalidRequest => "Bearer error=\"invalid_request\"", + ErrorType.UnauthorizedClient => "Bearer error=\"unauthorized_client\"", + ErrorType.UnsupportedResponseType => "Bearer error=\"unsupported_response_type\"", + ErrorType.InvalidScope => "Bearer error=\"invalid_scope\"", + ErrorType.ServerError => "Bearer error=\"server_error\"", + ErrorType.TemporarilyUnabavailable => "Bearer error=\"temporarily_unavailable\"", + ErrorType.InvalidClient => "Bearer error=\"invalid_client\"", + ErrorType.InvalidToken => "Bearer error=\"invalid_token\"", + _ => "Bearer error=\"error\"", }; //Close the response with the status code ev.CloseResponse(code); diff --git a/lib/Plugins.Essentials/src/Oauth/OauthSessionCacheExhaustedException.cs b/lib/Plugins.Essentials/src/Oauth/OauthSessionCacheExhaustedException.cs deleted file mode 100644 index da91444..0000000 --- a/lib/Plugins.Essentials/src/Oauth/OauthSessionCacheExhaustedException.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Plugins.Essentials -* File: OauthSessionCacheExhaustedException.cs -* -* OauthSessionCacheExhaustedException.cs is part of VNLib.Plugins.Essentials which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Plugins.Essentials 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.Plugins.Essentials 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; - - -namespace VNLib.Plugins.Essentials.Oauth -{ - /// <summary> - /// Raised when the session cache space has been exhausted and cannot - /// load the new session into cache. - /// </summary> - public class OauthSessionCacheExhaustedException : Exception - { - public OauthSessionCacheExhaustedException(string message) : base(message) - {} - public OauthSessionCacheExhaustedException(string message, Exception innerException) : base(message, innerException) - {} - public OauthSessionCacheExhaustedException() - {} - } -}
\ No newline at end of file diff --git a/lib/Plugins.Essentials/src/Sessions/SessionBase.cs b/lib/Plugins.Essentials/src/Sessions/SessionBase.cs index 46e6ec8..100818b 100644 --- a/lib/Plugins.Essentials/src/Sessions/SessionBase.cs +++ b/lib/Plugins.Essentials/src/Sessions/SessionBase.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -31,7 +31,7 @@ using VNLib.Utils; namespace VNLib.Plugins.Essentials.Sessions { /// <summary> - /// Provides a base class for the <see cref="ISession"/> interface for exclusive use within a multithreaded + /// Provides a base class for the <see cref="ISession"/> interface that handles basic housekeeping /// context /// </summary> public abstract class SessionBase : ISession |