diff options
author | vnugent <public@vaughnnugent.com> | 2023-10-18 00:55:12 -0400 |
---|---|---|
committer | vnugent <public@vaughnnugent.com> | 2023-10-18 00:55:12 -0400 |
commit | 44a05ac3854d6cd0fa65d8ffc0f6efe7abfc87ad (patch) | |
tree | 31a1c2af8f264ca1c53128f91e22827cf0f5a1a0 /lib/Plugins.Essentials/src | |
parent | 62f9e126912fa9a620a361fb5b88d33506e096fb (diff) |
Essentials, plugins, and http core experimental updates
Diffstat (limited to 'lib/Plugins.Essentials/src')
48 files changed, 318 insertions, 316 deletions
diff --git a/lib/Plugins.Essentials/src/Accounts/AccountData.cs b/lib/Plugins.Essentials/src/Accounts/AccountData.cs index d4a4d12..f5db245 100644 --- a/lib/Plugins.Essentials/src/Accounts/AccountData.cs +++ b/lib/Plugins.Essentials/src/Accounts/AccountData.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -29,24 +29,24 @@ namespace VNLib.Plugins.Essentials.Accounts public class AccountData { [JsonPropertyName("email")] - public string EmailAddress { get; set; } + public string? EmailAddress { get; set; } [JsonPropertyName("phone")] - public string PhoneNumber { get; set; } + public string? PhoneNumber { get; set; } [JsonPropertyName("first")] - public string First { get; set; } + public string? First { get; set; } [JsonPropertyName("last")] - public string Last { get; set; } + public string? Last { get; set; } [JsonPropertyName("company")] - public string Company { get; set; } + public string? Company { get; set; } [JsonPropertyName("street")] - public string Street { get; set; } + public string? Street { get; set; } [JsonPropertyName("city")] - public string City { get; set; } + public string? City { get; set; } [JsonPropertyName("state")] - public string State { get; set; } + public string? State { get; set; } [JsonPropertyName("zip")] - public string Zip { get; set; } + public string? Zip { get; set; } [JsonPropertyName("created")] - public string Created { get; set; } + public string? Created { get; set; } } }
\ No newline at end of file diff --git a/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs b/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs index 54deb8c..259f52a 100644 --- a/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs +++ b/lib/Plugins.Essentials/src/Accounts/AccountUtils.cs @@ -23,7 +23,6 @@ */ using System; -using System.Buffers; using System.Threading; using System.Threading.Tasks; using System.Security.Cryptography; @@ -37,8 +36,6 @@ using VNLib.Utils.Extensions; using VNLib.Plugins.Essentials.Users; using VNLib.Plugins.Essentials.Sessions; -#nullable enable - namespace VNLib.Plugins.Essentials.Accounts { @@ -51,7 +48,7 @@ namespace VNLib.Plugins.Essentials.Accounts { /// <summary> - /// The size in bytes of the random passwords generated when invoking the <see cref="SetRandomPasswordAsync(PasswordHashing, IUserManager, IUser, int)"/> + /// The size in bytes of the random passwords generated when invoking the <see cref="SetRandomPasswordAsync(IPasswordHashingProvider, IUserManager, IUser, int)"/> /// </summary> public const int RANDOM_PASS_SIZE = 240; @@ -188,8 +185,10 @@ namespace VNLib.Plugins.Essentials.Accounts /// <returns>A <see cref="PrivateString"/> that contains the new password hash</returns> public static PrivateString GetRandomPassword(this IPasswordHashingProvider hashing, int size = RANDOM_PASS_SIZE) { + _ = hashing ?? throw new ArgumentNullException(nameof(hashing)); + //Get random bytes - byte[] randBuffer = ArrayPool<byte>.Shared.Rent(size); + using UnsafeMemoryHandle<byte> randBuffer = MemoryUtil.UnsafeAlloc(size); try { Span<byte> span = randBuffer.AsSpan(0, size); @@ -203,8 +202,7 @@ namespace VNLib.Plugins.Essentials.Accounts finally { //Zero the block and return to pool - MemoryUtil.InitializeBlock(randBuffer.AsSpan()); - ArrayPool<byte>.Shared.Return(randBuffer); + MemoryUtil.InitializeBlock(randBuffer.Span); } } @@ -221,6 +219,7 @@ namespace VNLib.Plugins.Essentials.Accounts /// <exception cref="ArgumentNullException"></exception> public static async Task<bool> VerifyPasswordAsync(this IUserManager manager, string userId, PrivateString rawPassword, IPasswordHashingProvider hashing, CancellationToken cancellation) { + _ = manager ?? throw new ArgumentNullException(nameof(manager)); _ = userId ?? throw new ArgumentNullException(nameof(userId)); _ = rawPassword ?? throw new ArgumentNullException(nameof(rawPassword)); _ = hashing ?? throw new ArgumentNullException(nameof(hashing)); @@ -228,7 +227,17 @@ namespace VNLib.Plugins.Essentials.Accounts //Get the user, may be null if the user does not exist using IUser? user = await manager.GetUserAndPassFromIDAsync(userId, cancellation); - return user != null && hashing.Verify(user.PassHash.ToReadOnlySpan(), rawPassword.ToReadOnlySpan()); + if(user == null) + { + return false; + } + + if(user.PassHash == null) + { + return false; + } + + return hashing.Verify(user.PassHash.ToReadOnlySpan(), rawPassword.ToReadOnlySpan()); } /// <summary> @@ -242,7 +251,11 @@ namespace VNLib.Plugins.Essentials.Accounts [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool VerifyPassword(this IUser user, PrivateString rawPassword, IPasswordHashingProvider hashing) { - return user.PassHash != null && hashing.Verify(user.PassHash, rawPassword); + _ = user ?? throw new ArgumentNullException(nameof(user)); + _ = rawPassword ?? throw new ArgumentNullException(nameof(rawPassword)); + _ = hashing ?? throw new ArgumentNullException(nameof(hashing)); + + return user.PassHash != null && hashing.Verify(user.PassHash.ToReadOnlySpan(), rawPassword.ToReadOnlySpan()); } /// <summary> @@ -256,8 +269,12 @@ namespace VNLib.Plugins.Essentials.Accounts [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool Verify(this IPasswordHashingProvider provider, PrivateString passHash, PrivateString password) { + _ = provider ?? throw new ArgumentNullException(nameof(provider)); + _ = password ?? throw new ArgumentNullException(nameof(password)); + _ = passHash ?? throw new ArgumentNullException(nameof(passHash)); + //Casting PrivateStrings to spans will reference the base string directly - return provider.Verify((ReadOnlySpan<char>)passHash, (ReadOnlySpan<char>)password); + return provider.Verify(passHash.ToReadOnlySpan(), password.ToReadOnlySpan()); } /// <summary> @@ -270,7 +287,10 @@ namespace VNLib.Plugins.Essentials.Accounts [MethodImpl(MethodImplOptions.AggressiveInlining)] public static PrivateString Hash(this IPasswordHashingProvider provider, PrivateString password) { - return provider.Hash((ReadOnlySpan<char>)password); + _ = provider ?? throw new ArgumentNullException(nameof(provider)); + _ = password ?? throw new ArgumentNullException(nameof(password)); + + return provider.Hash(password.ToReadOnlySpan()); } #endregion diff --git a/lib/Plugins.Essentials/src/Accounts/AuthorzationCheckLevel.cs b/lib/Plugins.Essentials/src/Accounts/AuthorzationCheckLevel.cs index aa09bf4..be6df08 100644 --- a/lib/Plugins.Essentials/src/Accounts/AuthorzationCheckLevel.cs +++ b/lib/Plugins.Essentials/src/Accounts/AuthorzationCheckLevel.cs @@ -23,8 +23,6 @@ */ -#nullable enable - namespace VNLib.Plugins.Essentials.Accounts { /// <summary> diff --git a/lib/Plugins.Essentials/src/Accounts/ClientSecurityToken.cs b/lib/Plugins.Essentials/src/Accounts/ClientSecurityToken.cs index 0d4aa58..0d81344 100644 --- a/lib/Plugins.Essentials/src/Accounts/ClientSecurityToken.cs +++ b/lib/Plugins.Essentials/src/Accounts/ClientSecurityToken.cs @@ -23,8 +23,6 @@ */ -#nullable enable - namespace VNLib.Plugins.Essentials.Accounts { /// <summary> diff --git a/lib/Plugins.Essentials/src/Accounts/FailedLoginLockout.cs b/lib/Plugins.Essentials/src/Accounts/FailedLoginLockout.cs index a67eee2..1ab476d 100644 --- a/lib/Plugins.Essentials/src/Accounts/FailedLoginLockout.cs +++ b/lib/Plugins.Essentials/src/Accounts/FailedLoginLockout.cs @@ -26,8 +26,6 @@ using System; using VNLib.Plugins.Essentials.Users; -#nullable enable - namespace VNLib.Plugins.Essentials.Accounts { /// <summary> diff --git a/lib/Plugins.Essentials/src/Accounts/IAccountSecurityProvider.cs b/lib/Plugins.Essentials/src/Accounts/IAccountSecurityProvider.cs index c30796b..4a2d479 100644 --- a/lib/Plugins.Essentials/src/Accounts/IAccountSecurityProvider.cs +++ b/lib/Plugins.Essentials/src/Accounts/IAccountSecurityProvider.cs @@ -27,8 +27,6 @@ using System; using VNLib.Utils; using VNLib.Plugins.Essentials.Users; -#nullable enable - namespace VNLib.Plugins.Essentials.Accounts { /// <summary> diff --git a/lib/Plugins.Essentials/src/Accounts/IClientAuthorization.cs b/lib/Plugins.Essentials/src/Accounts/IClientAuthorization.cs index 02bc96e..73f97c0 100644 --- a/lib/Plugins.Essentials/src/Accounts/IClientAuthorization.cs +++ b/lib/Plugins.Essentials/src/Accounts/IClientAuthorization.cs @@ -23,8 +23,6 @@ */ -#nullable enable - namespace VNLib.Plugins.Essentials.Accounts { /// <summary> diff --git a/lib/Plugins.Essentials/src/Accounts/IClientSecInfo.cs b/lib/Plugins.Essentials/src/Accounts/IClientSecInfo.cs index 6990191..0071311 100644 --- a/lib/Plugins.Essentials/src/Accounts/IClientSecInfo.cs +++ b/lib/Plugins.Essentials/src/Accounts/IClientSecInfo.cs @@ -23,8 +23,6 @@ */ -#nullable enable - namespace VNLib.Plugins.Essentials.Accounts { /// <summary> diff --git a/lib/Plugins.Essentials/src/Accounts/IPasswordHashingProvider.cs b/lib/Plugins.Essentials/src/Accounts/IPasswordHashingProvider.cs index fc45727..788f69d 100644 --- a/lib/Plugins.Essentials/src/Accounts/IPasswordHashingProvider.cs +++ b/lib/Plugins.Essentials/src/Accounts/IPasswordHashingProvider.cs @@ -53,7 +53,7 @@ namespace VNLib.Plugins.Essentials.Accounts bool Verify(ReadOnlySpan<byte> passHash, ReadOnlySpan<byte> password); /// <summary> - /// Hashes the specified character encoded password to it's secured hashed form. + /// Calculates the cryptographic hash of the specified binary encoded password. /// </summary> /// <param name="password">The character encoded password to encrypt</param> /// <returns>A <see cref="PrivateString"/> containing the new password hash.</returns> @@ -61,7 +61,7 @@ namespace VNLib.Plugins.Essentials.Accounts PrivateString Hash(ReadOnlySpan<char> password); /// <summary> - /// Hashes the specified binary encoded password to it's secured hashed form. + /// Calculates the cryptographic hash of the specified binary encoded password. /// </summary> /// <param name="password">The binary encoded password to encrypt</param> /// <returns>A <see cref="PrivateString"/> containing the new password hash.</returns> diff --git a/lib/Plugins.Essentials/src/Accounts/LoginMessage.cs b/lib/Plugins.Essentials/src/Accounts/LoginMessage.cs index 96bf261..df7a206 100644 --- a/lib/Plugins.Essentials/src/Accounts/LoginMessage.cs +++ b/lib/Plugins.Essentials/src/Accounts/LoginMessage.cs @@ -24,6 +24,7 @@ using System; using System.Text.Json.Serialization; + using VNLib.Utils.Memory; namespace VNLib.Plugins.Essentials.Accounts @@ -48,7 +49,7 @@ namespace VNLib.Plugins.Essentials.Accounts /// may represent a user's password /// </summary> [JsonPropertyName("password")] - public string Password + public string? Password { get => base[0]; set => base[0] = value; @@ -70,7 +71,7 @@ namespace VNLib.Plugins.Essentials.Accounts /// The clients specified local-language /// </summary> [JsonPropertyName("locallanguage")] - public string LocalLanguage { get; set; } + public string? LocalLanguage { get; set; } /// <summary> /// The clients shared public key used for encryption, this property is not protected /// </summary> diff --git a/lib/Plugins.Essentials/src/Accounts/PasswordChallengeResult.cs b/lib/Plugins.Essentials/src/Accounts/PasswordChallengeResult.cs index 3ad05ab..ee48cb0 100644 --- a/lib/Plugins.Essentials/src/Accounts/PasswordChallengeResult.cs +++ b/lib/Plugins.Essentials/src/Accounts/PasswordChallengeResult.cs @@ -22,9 +22,6 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ -using System; - -#nullable enable namespace VNLib.Plugins.Essentials.Accounts { diff --git a/lib/Plugins.Essentials/src/Content/IPageRouter.cs b/lib/Plugins.Essentials/src/Content/IPageRouter.cs index e6952f4..af99b5a 100644 --- a/lib/Plugins.Essentials/src/Content/IPageRouter.cs +++ b/lib/Plugins.Essentials/src/Content/IPageRouter.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -24,8 +24,6 @@ using System.Threading.Tasks; -//Import account system for privilage masks - namespace VNLib.Plugins.Essentials.Content { /// <summary> diff --git a/lib/Plugins.Essentials/src/Endpoints/ProtectionSettings.cs b/lib/Plugins.Essentials/src/Endpoints/ProtectionSettings.cs index 7e1e394..4d09165 100644 --- a/lib/Plugins.Essentials/src/Endpoints/ProtectionSettings.cs +++ b/lib/Plugins.Essentials/src/Endpoints/ProtectionSettings.cs @@ -22,7 +22,6 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ -using System; namespace VNLib.Plugins.Essentials.Endpoints { diff --git a/lib/Plugins.Essentials/src/Endpoints/ResourceEndpointBase.cs b/lib/Plugins.Essentials/src/Endpoints/ResourceEndpointBase.cs index 92643d9..2177838 100644 --- a/lib/Plugins.Essentials/src/Endpoints/ResourceEndpointBase.cs +++ b/lib/Plugins.Essentials/src/Endpoints/ResourceEndpointBase.cs @@ -200,24 +200,28 @@ namespace VNLib.Plugins.Essentials.Endpoints /// <param name="entity">The entity to be processed</param> /// <returns>The result of the operation to return to the file processor</returns> protected virtual ValueTask<VfReturnType> PostAsync(HttpEntity entity) => ValueTask.FromResult(Post(entity)); + /// <summary> /// This method gets invoked when an incoming GET request to the endpoint has been requested. /// </summary> /// <param name="entity">The entity to be processed</param> /// <returns>The result of the operation to return to the file processor</returns> protected virtual ValueTask<VfReturnType> GetAsync(HttpEntity entity) => ValueTask.FromResult(Get(entity)); + /// <summary> /// This method gets invoked when an incoming DELETE request to the endpoint has been requested. /// </summary> /// <param name="entity">The entity to be processed</param> /// <returns>The result of the operation to return to the file processor</returns> protected virtual ValueTask<VfReturnType> DeleteAsync(HttpEntity entity) => ValueTask.FromResult(Delete(entity)); + /// <summary> /// This method gets invoked when an incoming PUT request to the endpoint has been requested. /// </summary> /// <param name="entity">The entity to be processed</param> /// <returns>The result of the operation to return to the file processor</returns> protected virtual ValueTask<VfReturnType> PutAsync(HttpEntity entity) => ValueTask.FromResult(Put(entity)); + /// <summary> /// This method gets invoked when an incoming PATCH request to the endpoint has been requested. /// </summary> @@ -225,6 +229,11 @@ namespace VNLib.Plugins.Essentials.Endpoints /// <returns>The result of the operation to return to the file processor</returns> protected virtual ValueTask<VfReturnType> PatchAsync(HttpEntity entity) => ValueTask.FromResult(Patch(entity)); + /// <summary> + /// This method gets invoked when an incoming OPTIONS request to the endpoint has been requested. + /// </summary> + /// <param name="entity">The entity to be processed</param> + /// <returns>The result of the operation to return to the file processor</returns> protected virtual ValueTask<VfReturnType> OptionsAsync(HttpEntity entity) => ValueTask.FromResult(Options(entity)); /// <summary> @@ -247,63 +256,43 @@ namespace VNLib.Plugins.Essentials.Endpoints /// </summary> /// <param name="entity">The entity to be processed</param> /// <returns>The result of the operation to return to the file processor</returns> - protected virtual VfReturnType Post(HttpEntity entity) - { - //Return method not allowed - entity.CloseResponse(HttpStatusCode.MethodNotAllowed); - return VfReturnType.VirtualSkip; - } + protected virtual VfReturnType Post(HttpEntity entity) => VirtualClose(entity, HttpStatusCode.MethodNotAllowed); + /// <summary> /// This method gets invoked when an incoming GET request to the endpoint has been requested. /// </summary> /// <param name="entity">The entity to be processed</param> /// <returns>The result of the operation to return to the file processor</returns> - protected virtual VfReturnType Get(HttpEntity entity) - { - return VfReturnType.ProcessAsFile; - } + protected virtual VfReturnType Get(HttpEntity entity) => VfReturnType.ProcessAsFile; + /// <summary> /// This method gets invoked when an incoming DELETE request to the endpoint has been requested. /// </summary> /// <param name="entity">The entity to be processed</param> /// <returns>The result of the operation to return to the file processor</returns> - protected virtual VfReturnType Delete(HttpEntity entity) - { - entity.CloseResponse(HttpStatusCode.MethodNotAllowed); - return VfReturnType.VirtualSkip; - } + protected virtual VfReturnType Delete(HttpEntity entity) => VirtualClose(entity, HttpStatusCode.MethodNotAllowed); + /// <summary> /// This method gets invoked when an incoming PUT request to the endpoint has been requested. /// </summary> /// <param name="entity">The entity to be processed</param> /// <returns>The result of the operation to return to the file processor</returns> - protected virtual VfReturnType Put(HttpEntity entity) - { - entity.CloseResponse(HttpStatusCode.MethodNotAllowed); - return VfReturnType.VirtualSkip; - } + protected virtual VfReturnType Put(HttpEntity entity) => VirtualClose(entity, HttpStatusCode.MethodNotAllowed); + /// <summary> /// This method gets invoked when an incoming PATCH request to the endpoint has been requested. /// </summary> /// <param name="entity">The entity to be processed</param> /// <returns>The result of the operation to return to the file processor</returns> - protected virtual VfReturnType Patch(HttpEntity entity) - { - entity.CloseResponse(HttpStatusCode.MethodNotAllowed); - return VfReturnType.VirtualSkip; - } + protected virtual VfReturnType Patch(HttpEntity entity) => VirtualClose(entity, HttpStatusCode.MethodNotAllowed); + /// <summary> /// Invoked when a request is received for a method other than GET, POST, DELETE, or PUT; /// </summary> /// <param name="entity">The entity that </param> /// <param name="method">The request method</param> /// <returns>The results of the processing</returns> - protected virtual VfReturnType AlternateMethod(HttpEntity entity, HttpMethod method) - { - //Return method not allowed - entity.CloseResponse(HttpStatusCode.MethodNotAllowed); - return VfReturnType.VirtualSkip; - } + protected virtual VfReturnType AlternateMethod(HttpEntity entity, HttpMethod method) => VirtualClose(entity, HttpStatusCode.MethodNotAllowed); protected virtual VfReturnType Options(HttpEntity entity) => VfReturnType.Forbidden; diff --git a/lib/Plugins.Essentials/src/EventProcessor.cs b/lib/Plugins.Essentials/src/EventProcessor.cs index a9cd98a..f565707 100644 --- a/lib/Plugins.Essentials/src/EventProcessor.cs +++ b/lib/Plugins.Essentials/src/EventProcessor.cs @@ -41,7 +41,7 @@ using VNLib.Plugins.Essentials.Extensions; using VNLib.Plugins.Essentials.Middleware; using VNLib.Plugins.Essentials.Endpoints; -#nullable enable +#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task namespace VNLib.Plugins.Essentials { @@ -105,18 +105,24 @@ namespace VNLib.Plugins.Essentials public abstract bool ErrorHandler(HttpStatusCode errorCode, IHttpEvent entity); /// <summary> - /// For pre-processing a request entity before all endpoint lookups are performed + /// For pre-processing a request entity before all processing happens, but after + /// a session is attached to the entity. /// </summary> /// <param name="entity">The http entity to process</param> - /// <returns>The results to return to the file processor, or null of the entity requires further processing</returns> - public abstract ValueTask<FileProcessArgs> PreProcessEntityAsync(HttpEntity entity); + /// <param name="result">The results to return to the file processor, or <see cref="FileProcessArgs.Continue"/> to continue further processing</param> + public abstract void PreProcessEntity(HttpEntity entity, out FileProcessArgs result); /// <summary> /// Allows for post processing of a selected <see cref="FileProcessArgs"/> for the given entity + /// <para> + /// Post processing may mutate the <paramref name="chosenRoutine"/> to change the + /// result of the operation. Consider events with the <see cref="FileProcessArgs.VirtualSkip"/> + /// have already been responded to. + /// </para> /// </summary> /// <param name="entity">The http entity to process</param> /// <param name="chosenRoutine">The selected file processing routine for the given request</param> - public abstract void PostProcessFile(HttpEntity entity, in FileProcessArgs chosenRoutine); + public abstract void PostProcessEntity(HttpEntity entity, ref FileProcessArgs chosenRoutine); ///<inheritdoc/> public abstract IAccountSecurityProvider AccountSecurity { get; } @@ -163,129 +169,126 @@ namespace VNLib.Plugins.Essentials /// </summary> /// <param name="router"><see cref="IPageRouter"/> to route incomming connections</param> public void SetPageRouter(IPageRouter? router) => _ = Interlocked.Exchange(ref Router, router); - - ///<inheritdoc/> public virtual async ValueTask ClientConnectedAsync(IHttpEvent httpEvent) { - //load ref to session provider + //read local ref to session provider and page router ISessionProvider? _sessions = Sessions; + IPageRouter? router = Router; + + //event cancellation token + HttpEntity entity = new(httpEvent, this); + LinkedListNode<IHttpMiddleware>? mwNode; + //Set ambient processor context _currentProcessor.Value = this; - //Start cancellation token - CancellationTokenSource timeout = new(Options.ExecutionTimeout); - - FileProcessArgs args; - try { - //Session handle, default to the shared empty session - SessionHandle sessionHandle = SessionHandle.Empty; - //If sessions are set, get a session for the current connection if (_sessions != null) { //Get the session - sessionHandle = await _sessions.GetSessionAsync(httpEvent, timeout.Token); + entity.EventSessionHandle = await _sessions.GetSessionAsync(httpEvent, entity.EventCancellation); + //If the processor had an error recovering the session, return the result to the processor - if (sessionHandle.EntityStatus != FileProcessArgs.Continue) + if (entity.EventSessionHandle.EntityStatus != FileProcessArgs.Continue) { - ProcessFile(httpEvent, sessionHandle.EntityStatus); + ProcessFile(httpEvent, entity.EventSessionHandle.EntityStatus); return; } + + //Attach the new session to the entity + entity.AttachSession(); } + try { - //Setup entity - HttpEntity entity = new(httpEvent, this, in sessionHandle, timeout.Token); - //Pre-process entity - args = await PreProcessEntityAsync(entity); + PreProcessEntity(entity, out entity.EventArgs); //If preprocess returned a value, exit - if (args != FileProcessArgs.Continue) + if (entity.EventArgs != FileProcessArgs.Continue) { - ProcessFile(httpEvent, in args); - return; + goto RespondAndExit; } //Handle middleware before file processing - LinkedListNode<IHttpMiddleware>? mwNode = MiddlewareChain.GetCurrentHead(); + mwNode = MiddlewareChain.GetCurrentHead(); - //Loop though nodes + //Loop through nodes while(mwNode != null) { //Process - args = await mwNode.ValueRef.ProcessAsync(entity); + entity.EventArgs = await mwNode.ValueRef.ProcessAsync(entity); - switch (args.Routine) + switch (entity.EventArgs.Routine) { //move next if continue is returned case FpRoutine.Continue: - mwNode = mwNode.Next; break; //Middleware completed the connection, time to exit default: - goto MwExit; + goto RespondAndExit; } - } + + mwNode = mwNode.Next; + } if (!EndpointTable.IsEmpty) { //See if the virtual file is servicable - if (!EndpointTable.TryGetEndpoint(entity.Server.Path, out IVirtualEndpoint<HttpEntity>? vf)) - { - args = FileProcessArgs.Continue; - } - else + if (EndpointTable.TryGetEndpoint(entity.Server.Path, out IVirtualEndpoint<HttpEntity>? vf)) { //Invoke the page handler process method VfReturnType rt = await vf.Process(entity); //Process a virtual file - args = GetArgsFromReturn(entity, rt); - } + GetArgsFromVirtualReturn(entity, rt, out entity.EventArgs); - //If the entity was processed, exit - if (args != FileProcessArgs.Continue) - { - ProcessFile(httpEvent, in args); - return; + //If the entity was processed, exit + if (entity.EventArgs != FileProcessArgs.Continue) + { + goto RespondAndExit; + } } } //If no virtual processor handled the ws request, deny it if (entity.Server.IsWebSocketRequest) { - ProcessFile(httpEvent, in FileProcessArgs.Deny); - return; + entity.EventArgs = FileProcessArgs.Deny; + } + else + { + //Finally route the connection as a file + entity.EventArgs = await RouteFileAsync(router, entity); } - //Finally process as file - args = await RouteFileAsync(entity); - - MwExit: + RespondAndExit: - //Finally process the file - ProcessFile(httpEvent, in args); + //Call post processor method + PostProcessEntity(entity, ref entity.EventArgs); } - finally + finally { //Capture all session release exceptions try { //Release the session - await sessionHandle.ReleaseAsync(httpEvent); + await entity.EventSessionHandle.ReleaseAsync(httpEvent); } catch (Exception ex) { Log.Error(ex, "Exception raised while releasing the assocated session"); } } + + //Finally process the file + ProcessFile(httpEvent, in entity.EventArgs); } catch (ContentTypeUnacceptableException) { @@ -309,7 +312,6 @@ namespace VNLib.Plugins.Essentials { Log.Warn(se, "An exception was raised while attempting to get or save a session"); CloseWithError(HttpStatusCode.ServiceUnavailable, httpEvent); - return; } catch (OperationCanceledException oce) { @@ -328,7 +330,7 @@ namespace VNLib.Plugins.Essentials } finally { - timeout.Dispose(); + entity.Dispose(); _currentProcessor.Value = null; } } @@ -485,17 +487,19 @@ namespace VNLib.Plugins.Essentials /// </summary> /// <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) + /// <param name="args">The process args to end processing for the virtual endpoint</param> + protected virtual void GetArgsFromVirtualReturn(HttpEntity entity, VfReturnType returnType, out FileProcessArgs args) { if (returnType == VfReturnType.VirtualSkip) { //Virtual file was handled by the handler - return FileProcessArgs.VirtualSkip; + args = FileProcessArgs.VirtualSkip; + return; } else if (returnType == VfReturnType.ProcessAsFile) { - return FileProcessArgs.Continue; + args = FileProcessArgs.Continue; + return; } //If not a get request, process it directly @@ -504,11 +508,14 @@ namespace VNLib.Plugins.Essentials switch (returnType) { case VfReturnType.Forbidden: - return FileProcessArgs.Deny; + args = FileProcessArgs.Deny; + return; case VfReturnType.NotFound: - return FileProcessArgs.NotFound; + args = FileProcessArgs.NotFound; + return; case VfReturnType.Error: - return FileProcessArgs.Error; + args = FileProcessArgs.Error; + return; default: break; } @@ -531,31 +538,31 @@ namespace VNLib.Plugins.Essentials break; } - return FileProcessArgs.VirtualSkip; + args = FileProcessArgs.VirtualSkip; } /// <summary> /// Determines the best <see cref="FileProcessArgs"/> processing response for the given connection. /// Alternativley may respond to the entity directly. /// </summary> + /// <param name="router">A reference to the current <see cref="IPageRouter"/> instance if cofigured</param> /// <param name="entity">The http entity to process</param> /// <returns>The results to return to the file processor, this method must return an argument</returns> - protected virtual async ValueTask<FileProcessArgs> RouteFileAsync(HttpEntity entity) + protected virtual async ValueTask<FileProcessArgs> RouteFileAsync(IPageRouter? router, HttpEntity entity) { - //Read local copy of the router - IPageRouter? router = Router; - - //Make sure router is set - if (router == null) + if(router != null) + { + //Get a file routine + FileProcessArgs routine = await router.RouteAsync(entity); + //Call post processor method + PostProcessEntity(entity, ref routine); + //Return the routine + return routine; + } + else { return FileProcessArgs.Continue; } - //Get a file routine - FileProcessArgs routine = await router.RouteAsync(entity); - //Call post processor method - PostProcessFile(entity, in routine); - //Return the routine - return routine; } /// <summary> diff --git a/lib/Plugins.Essentials/src/Extensions/CollectionsExtensions.cs b/lib/Plugins.Essentials/src/Extensions/CollectionsExtensions.cs index 9500d5e..bc82827 100644 --- a/lib/Plugins.Essentials/src/Extensions/CollectionsExtensions.cs +++ b/lib/Plugins.Essentials/src/Extensions/CollectionsExtensions.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -26,8 +26,6 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -#nullable enable - namespace VNLib.Plugins.Essentials.Extensions { /// <summary> diff --git a/lib/Plugins.Essentials/src/Extensions/ConnectionInfoExtensions.cs b/lib/Plugins.Essentials/src/Extensions/ConnectionInfoExtensions.cs index 393c838..0039efa 100644 --- a/lib/Plugins.Essentials/src/Extensions/ConnectionInfoExtensions.cs +++ b/lib/Plugins.Essentials/src/Extensions/ConnectionInfoExtensions.cs @@ -31,8 +31,6 @@ using System.Runtime.CompilerServices; using VNLib.Net.Http; using VNLib.Utils.Extensions; -#nullable enable - namespace VNLib.Plugins.Essentials.Extensions { diff --git a/lib/Plugins.Essentials/src/Extensions/EssentialHttpEventExtensions.cs b/lib/Plugins.Essentials/src/Extensions/EssentialHttpEventExtensions.cs index cb64cd1..976eed5 100644 --- a/lib/Plugins.Essentials/src/Extensions/EssentialHttpEventExtensions.cs +++ b/lib/Plugins.Essentials/src/Extensions/EssentialHttpEventExtensions.cs @@ -38,8 +38,6 @@ using VNLib.Utils; using VNLib.Utils.Memory.Caching; using static VNLib.Plugins.Essentials.Statics; -#nullable enable - namespace VNLib.Plugins.Essentials.Extensions { diff --git a/lib/Plugins.Essentials/src/Extensions/HttpCookie.cs b/lib/Plugins.Essentials/src/Extensions/HttpCookie.cs index 332e3d6..6158a69 100644 --- a/lib/Plugins.Essentials/src/Extensions/HttpCookie.cs +++ b/lib/Plugins.Essentials/src/Extensions/HttpCookie.cs @@ -26,8 +26,6 @@ using System; using VNLib.Net.Http; -#nullable enable - namespace VNLib.Plugins.Essentials.Extensions { /// <summary> diff --git a/lib/Plugins.Essentials/src/Extensions/IJsonSerializerBuffer.cs b/lib/Plugins.Essentials/src/Extensions/IJsonSerializerBuffer.cs index 34811f4..5e02c54 100644 --- a/lib/Plugins.Essentials/src/Extensions/IJsonSerializerBuffer.cs +++ b/lib/Plugins.Essentials/src/Extensions/IJsonSerializerBuffer.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -24,14 +24,12 @@ using System.IO; -#nullable enable - namespace VNLib.Plugins.Essentials.Extensions { /// <summary> /// Interface for a buffer that can be used to serialize objects to JSON /// </summary> - interface IJsonSerializerBuffer + internal interface IJsonSerializerBuffer { /// <summary> /// Gets a stream used for writing serialzation data to diff --git a/lib/Plugins.Essentials/src/Extensions/InternalSerializerExtensions.cs b/lib/Plugins.Essentials/src/Extensions/InternalSerializerExtensions.cs index 3d441a1..817b673 100644 --- a/lib/Plugins.Essentials/src/Extensions/InternalSerializerExtensions.cs +++ b/lib/Plugins.Essentials/src/Extensions/InternalSerializerExtensions.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -26,8 +26,6 @@ using System; using System.IO; using System.Text.Json; -#nullable enable - namespace VNLib.Plugins.Essentials.Extensions { diff --git a/lib/Plugins.Essentials/src/Extensions/InvalidJsonRequestException.cs b/lib/Plugins.Essentials/src/Extensions/InvalidJsonRequestException.cs index b2352b2..bd7bfe3 100644 --- a/lib/Plugins.Essentials/src/Extensions/InvalidJsonRequestException.cs +++ b/lib/Plugins.Essentials/src/Extensions/InvalidJsonRequestException.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -24,8 +24,6 @@ using System.Text.Json; -#nullable enable - namespace VNLib.Plugins.Essentials.Extensions { /// <summary> diff --git a/lib/Plugins.Essentials/src/Extensions/JsonResponse.cs b/lib/Plugins.Essentials/src/Extensions/JsonResponse.cs index d087c06..549d746 100644 --- a/lib/Plugins.Essentials/src/Extensions/JsonResponse.cs +++ b/lib/Plugins.Essentials/src/Extensions/JsonResponse.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -23,17 +23,15 @@ */ using System; -using System.Buffers; using System.IO; +using System.Buffers; using VNLib.Net.Http; -using VNLib.Utils.Extensions; using VNLib.Utils.IO; using VNLib.Utils.Memory; +using VNLib.Utils.Extensions; using VNLib.Utils.Memory.Caching; -#nullable enable - namespace VNLib.Plugins.Essentials.Extensions { internal sealed class JsonResponse : IJsonSerializerBuffer, IMemoryResponseReader @@ -99,6 +97,7 @@ namespace VNLib.Plugins.Essentials.Extensions _written += written; Remaining -= written; } + ///<inheritdoc/> void IMemoryResponseReader.Close() { @@ -110,10 +109,6 @@ namespace VNLib.Plugins.Essentials.Extensions } ///<inheritdoc/> - ReadOnlyMemory<byte> IMemoryResponseReader.GetMemory() - { - //Get memory from the memory owner and offet the slice, - return _memoryOwner.Memory.Slice(_written, Remaining); - } + ReadOnlyMemory<byte> IMemoryResponseReader.GetMemory() => _memoryOwner.Memory.Slice(_written, Remaining); } }
\ No newline at end of file diff --git a/lib/Plugins.Essentials/src/Extensions/SimpleMemoryResponse.cs b/lib/Plugins.Essentials/src/Extensions/SimpleMemoryResponse.cs index a0f2b17..29ae7b1 100644 --- a/lib/Plugins.Essentials/src/Extensions/SimpleMemoryResponse.cs +++ b/lib/Plugins.Essentials/src/Extensions/SimpleMemoryResponse.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -24,10 +24,9 @@ using System; using System.Text; -using VNLib.Net.Http; using System.Buffers; -#nullable enable +using VNLib.Net.Http; namespace VNLib.Plugins.Essentials.Extensions { @@ -70,12 +69,14 @@ namespace VNLib.Plugins.Essentials.Extensions ///<inheritdoc/> public int Remaining { get; private set; } + ///<inheritdoc/> void IMemoryResponseReader.Advance(int written) { Remaining -= written; _written += written; } + ///<inheritdoc/> void IMemoryResponseReader.Close() { @@ -83,6 +84,7 @@ namespace VNLib.Plugins.Essentials.Extensions ArrayPool<byte>.Shared.Return(_buffer!); _buffer = null; } + ///<inheritdoc/> ReadOnlyMemory<byte> IMemoryResponseReader.GetMemory() => _buffer!.AsMemory(_written, Remaining); } diff --git a/lib/Plugins.Essentials/src/Extensions/UserExtensions.cs b/lib/Plugins.Essentials/src/Extensions/UserExtensions.cs index 9223b1d..77e6e3e 100644 --- a/lib/Plugins.Essentials/src/Extensions/UserExtensions.cs +++ b/lib/Plugins.Essentials/src/Extensions/UserExtensions.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -28,8 +28,6 @@ using System.Text.Json; using VNLib.Plugins.Essentials.Users; using VNLib.Plugins.Essentials.Accounts; -#nullable enable - namespace VNLib.Plugins.Essentials.Extensions { /// <summary> @@ -62,6 +60,7 @@ namespace VNLib.Plugins.Essentials.Extensions profile.EmailAddress = null; ud.SetObject(PROFILE_ENTRY, profile); } + /// <summary> /// Stores the serialized string user's profile to their entry. /// <br/> @@ -70,6 +69,7 @@ namespace VNLib.Plugins.Essentials.Extensions /// <param name="ud"></param> /// <param name="jsonProfile">The JSON serialized "raw" profile data</param> public static void SetProfile(this IUser ud, string jsonProfile) => ud[PROFILE_ENTRY] = jsonProfile; + /// <summary> /// Recovers the user's stored profile /// </summary> diff --git a/lib/Plugins.Essentials/src/FileProcessArgs.cs b/lib/Plugins.Essentials/src/FileProcessArgs.cs index 5ed4667..0f90160 100644 --- a/lib/Plugins.Essentials/src/FileProcessArgs.cs +++ b/lib/Plugins.Essentials/src/FileProcessArgs.cs @@ -22,11 +22,8 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ -using System; using System.Net; -#nullable enable - namespace VNLib.Plugins.Essentials { /// <summary> diff --git a/lib/Plugins.Essentials/src/HttpEntity.cs b/lib/Plugins.Essentials/src/HttpEntity.cs index ad89d14..6487ca3 100644 --- a/lib/Plugins.Essentials/src/HttpEntity.cs +++ b/lib/Plugins.Essentials/src/HttpEntity.cs @@ -33,8 +33,6 @@ using VNLib.Net.Http; using VNLib.Plugins.Essentials.Sessions; using VNLib.Plugins.Essentials.Extensions; -#nullable enable - /* * HttpEntity was converted to an object as during profiling * it was almost always heap allcated due to async opertaions @@ -53,16 +51,20 @@ namespace VNLib.Plugins.Essentials /// </summary> public sealed class HttpEntity : IHttpEvent { + /// <summary> /// The connection event entity /// </summary> private readonly IHttpEvent Entity; - public HttpEntity(IHttpEvent entity, IWebProcessor root, in SessionHandle session, CancellationToken cancellation) + private readonly CancellationTokenSource EventCts; + + public HttpEntity(IHttpEvent entity, IWebProcessor root) { Entity = entity; RequestedRoot = root; - EventCancellation = cancellation; + //Init event cts + EventCts = new(root.Options.ExecutionTimeout); //See if the connection is coming from an downstream server IsBehindDownStreamServer = root.Options.DownStreamServers.Contains(entity.Server.RemoteEndpoint.Address); @@ -72,8 +74,6 @@ namespace VNLib.Plugins.Essentials * otherwise use the remote ep ip address */ TrustedRemoteIp = entity.Server.GetTrustedIp(IsBehindDownStreamServer); - //Initialize the session - Session = session.IsSet ? new(session.SessionData, entity.Server, TrustedRemoteIp) : new(); //Local connection IsLocalConnection = entity.Server.LocalEndpoint.Address.IsLocalSubnet(TrustedRemoteIp); //Cache value @@ -83,14 +83,38 @@ namespace VNLib.Plugins.Essentials RequestedTimeUtc = DateTimeOffset.UtcNow; } + private SessionInfo _session; + internal FileProcessArgs EventArgs; + internal SessionHandle EventSessionHandle; + + /// <summary> + /// Internal call to attach a new session to the entity from the + /// internal session handle + /// </summary> + internal void AttachSession() + { + if (EventSessionHandle.IsSet) + { + _session = new(EventSessionHandle.SessionData!, Entity.Server, TrustedRemoteIp); + } + } + + /// <summary> + /// Internal call to cleanup any internal resources + /// </summary> + internal void Dispose() + { + EventCts.Dispose(); + } + /// <summary> /// A token that has a scheduled timeout to signal the cancellation of the entity event /// </summary> - public readonly CancellationToken EventCancellation; + public CancellationToken EventCancellation => EventCts.Token; /// <summary> - /// The session assocaited with the event + /// The session associated with the event /// </summary> - public readonly SessionInfo Session; + public ref readonly SessionInfo Session => ref _session; /// <summary> /// A value that indicates if the connecion came from a trusted downstream server /// </summary> diff --git a/lib/Plugins.Essentials/src/IEpProcessingOptions.cs b/lib/Plugins.Essentials/src/IEpProcessingOptions.cs index b9efdeb..d7f3da7 100644 --- a/lib/Plugins.Essentials/src/IEpProcessingOptions.cs +++ b/lib/Plugins.Essentials/src/IEpProcessingOptions.cs @@ -27,8 +27,6 @@ using System.IO; using System.Net; using System.Collections.Generic; -#nullable enable - namespace VNLib.Plugins.Essentials { /// <summary> diff --git a/lib/Plugins.Essentials/src/IVirtualEndpointTable.cs b/lib/Plugins.Essentials/src/IVirtualEndpointTable.cs index c260b45..d5aff2a 100644 --- a/lib/Plugins.Essentials/src/IVirtualEndpointTable.cs +++ b/lib/Plugins.Essentials/src/IVirtualEndpointTable.cs @@ -23,11 +23,10 @@ */ using System; +using System.Diagnostics.CodeAnalysis; using VNLib.Plugins.Essentials.Endpoints; -#nullable enable - namespace VNLib.Plugins.Essentials { /// <summary> @@ -70,6 +69,6 @@ namespace VNLib.Plugins.Essentials /// <param name="path">The connection path to recover the endpoint from</param> /// <param name="endpoint"></param> /// <returns></returns> - bool TryGetEndpoint(string path, out IVirtualEndpoint<HttpEntity>? endpoint); + bool TryGetEndpoint(string path, [NotNullWhen(true)] out IVirtualEndpoint<HttpEntity>? endpoint); } }
\ No newline at end of file diff --git a/lib/Plugins.Essentials/src/IWebProcessorInfo.cs b/lib/Plugins.Essentials/src/IWebProcessorInfo.cs index 93a9211..ae920ea 100644 --- a/lib/Plugins.Essentials/src/IWebProcessorInfo.cs +++ b/lib/Plugins.Essentials/src/IWebProcessorInfo.cs @@ -22,9 +22,6 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ - -#nullable enable - using VNLib.Net.Http; using VNLib.Plugins.Essentials.Accounts; diff --git a/lib/Plugins.Essentials/src/Middleware/IHttpMiddlewareChain.cs b/lib/Plugins.Essentials/src/Middleware/IHttpMiddlewareChain.cs index 54da6c1..ace0c86 100644 --- a/lib/Plugins.Essentials/src/Middleware/IHttpMiddlewareChain.cs +++ b/lib/Plugins.Essentials/src/Middleware/IHttpMiddlewareChain.cs @@ -24,8 +24,6 @@ using System.Collections.Generic; -#nullable enable - namespace VNLib.Plugins.Essentials.Middleware { /// <summary> diff --git a/lib/Plugins.Essentials/src/Middleware/SemiConistentMiddlewareChain.cs b/lib/Plugins.Essentials/src/Middleware/SemiConistentMiddlewareChain.cs index 197ba12..1e1db22 100644 --- a/lib/Plugins.Essentials/src/Middleware/SemiConistentMiddlewareChain.cs +++ b/lib/Plugins.Essentials/src/Middleware/SemiConistentMiddlewareChain.cs @@ -24,8 +24,6 @@ using System.Collections.Generic; -#nullable enable - namespace VNLib.Plugins.Essentials.Middleware { /// <summary> diff --git a/lib/Plugins.Essentials/src/Oauth/O2EndpointBase.cs b/lib/Plugins.Essentials/src/Oauth/O2EndpointBase.cs index a1a4d35..60004c7 100644 --- a/lib/Plugins.Essentials/src/Oauth/O2EndpointBase.cs +++ b/lib/Plugins.Essentials/src/Oauth/O2EndpointBase.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -31,8 +31,8 @@ using System.Threading.Tasks; using VNLib.Utils; using VNLib.Utils.Logging; using VNLib.Net.Http; -using VNLib.Plugins.Essentials.Extensions; using VNLib.Plugins.Essentials.Endpoints; +using VNLib.Plugins.Essentials.Extensions; namespace VNLib.Plugins.Essentials.Oauth { @@ -54,21 +54,25 @@ namespace VNLib.Plugins.Essentials.Oauth { VfReturnType rt; ERRNO preProc = PreProccess(entity); + //Entity was responded to by the pre-processor if (preProc < 0) { return VfReturnType.VirtualSkip; } + if (preProc == ERRNO.E_FAIL) { rt = VfReturnType.Forbidden; goto Exit; } + //If websockets are quested allow them to be processed in a logged-in/secure context if (entity.Server.IsWebSocketRequest) { return await WebsocketRequestedAsync(entity); } + //Capture return type rt = entity.Server.Method switch { @@ -81,29 +85,18 @@ namespace VNLib.Plugins.Essentials.Oauth HttpMethod.OPTIONS => await OptionsAsync(entity), _ => await AlternateMethodAsync(entity, entity.Server.Method), }; + Exit: //Write a standard Ouath2 error messag - switch (rt) + return rt switch { - case VfReturnType.VirtualSkip: - return VfReturnType.VirtualSkip; - case VfReturnType.ProcessAsFile: - return VfReturnType.ProcessAsFile; - case VfReturnType.NotFound: - entity.CloseResponseError(HttpStatusCode.NotFound, ErrorType.InvalidRequest, "The requested resource could not be found"); - return VfReturnType.VirtualSkip; - case VfReturnType.BadRequest: - entity.CloseResponseError(HttpStatusCode.BadRequest, ErrorType.InvalidRequest, "Your request was not properlty formatted and could not be proccessed"); - return VfReturnType.VirtualSkip; - case VfReturnType.Error: - entity.CloseResponseError(HttpStatusCode.InternalServerError, ErrorType.ServerError, "There was a server error processing your request"); - return VfReturnType.VirtualSkip; - - case VfReturnType.Forbidden: - default: - entity.CloseResponseError(HttpStatusCode.Forbidden, ErrorType.InvalidClient, "You do not have access to this resource"); - return VfReturnType.VirtualSkip; - } + VfReturnType.VirtualSkip => VfReturnType.VirtualSkip, + VfReturnType.ProcessAsFile => VfReturnType.ProcessAsFile, + VfReturnType.NotFound => O2VirtualClose(entity, HttpStatusCode.NotFound, ErrorType.InvalidRequest, "The requested resource could not be found"), + VfReturnType.BadRequest => O2VirtualClose(entity, HttpStatusCode.BadRequest, ErrorType.InvalidRequest, "Your request was not properlty formatted and could not be proccessed"), + VfReturnType.Error => O2VirtualClose(entity, HttpStatusCode.InternalServerError, ErrorType.ServerError, "There was a server error processing your request"), + _ => O2VirtualClose(entity, HttpStatusCode.Forbidden, ErrorType.InvalidClient, "You do not have access to this resource"), + }; } catch (TerminateConnectionException) { @@ -118,22 +111,19 @@ namespace VNLib.Plugins.Essentials.Oauth catch (ContentTypeUnacceptableException) { //Respond with an 406 error message - entity.CloseResponseError(HttpStatusCode.NotAcceptable, ErrorType.InvalidRequest, "The response type is not acceptable for this endpoint"); - return VfReturnType.VirtualSkip; + return O2VirtualClose(entity, HttpStatusCode.NotAcceptable, ErrorType.InvalidRequest, "The response type is not acceptable for this endpoint"); } catch (InvalidJsonRequestException) { //Respond with an error message - entity.CloseResponseError(HttpStatusCode.BadRequest, ErrorType.InvalidRequest, "The request body was not a proper JSON schema"); - return VfReturnType.VirtualSkip; + return O2VirtualClose(entity, HttpStatusCode.BadRequest, ErrorType.InvalidRequest, "The request body was not a proper JSON schema"); } catch (Exception ex) { //Log an uncaught excetpion and return an error code (log may not be initialized) Log?.Error(ex); //Respond with an error message - entity.CloseResponseError(HttpStatusCode.InternalServerError, ErrorType.ServerError, "There was a server error processing your request"); - return VfReturnType.VirtualSkip; + return O2VirtualClose(entity, HttpStatusCode.InternalServerError, ErrorType.ServerError, "There was a server error processing your request"); } } @@ -158,5 +148,11 @@ namespace VNLib.Plugins.Essentials.Oauth } return base.PreProccess(entity); } + + public static VfReturnType O2VirtualClose(HttpEntity entity, HttpStatusCode statusCode, ErrorType type, string message) + { + entity.CloseResponseError(statusCode, type, message); + return VfReturnType.VirtualSkip; + } } } diff --git a/lib/Plugins.Essentials/src/SemiConsistentVeTable.cs b/lib/Plugins.Essentials/src/SemiConsistentVeTable.cs index 483dc35..4849107 100644 --- a/lib/Plugins.Essentials/src/SemiConsistentVeTable.cs +++ b/lib/Plugins.Essentials/src/SemiConsistentVeTable.cs @@ -31,8 +31,6 @@ using System.Collections.Generic; using VNLib.Net.Http; using VNLib.Plugins.Essentials.Endpoints; -#nullable enable - namespace VNLib.Plugins.Essentials { internal class SemiConsistentVeTable : IVirtualEndpointTable diff --git a/lib/Plugins.Essentials/src/Sessions/ISession.cs b/lib/Plugins.Essentials/src/Sessions/ISession.cs index d2e0ee1..d990d8e 100644 --- a/lib/Plugins.Essentials/src/Sessions/ISession.cs +++ b/lib/Plugins.Essentials/src/Sessions/ISession.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -27,22 +27,10 @@ using System.Net; using VNLib.Utils; +#nullable disable + namespace VNLib.Plugins.Essentials.Sessions { - /// <summary> - /// Flags to specify <see cref="ISession"/> session types - /// </summary> - public enum SessionType - { - /// <summary> - /// The session is a "basic" or web based session - /// </summary> - Web, - /// <summary> - /// The session is an OAuth2 session type - /// </summary> - OAuth2 - } /// <summary> /// Represents a connection oriented session data @@ -70,6 +58,11 @@ namespace VNLib.Plugins.Essentials.Sessions string SessionID { get; } /// <summary> + /// A value that indicates this session was newly created + /// </summary> + bool IsNew { get; } + + /// <summary> /// User ID associated with session /// </summary> string UserID { get; set; } @@ -95,11 +88,6 @@ namespace VNLib.Plugins.Essentials.Sessions void RegenID(); /// <summary> - /// A value that indicates this session was newly created - /// </summary> - bool IsNew { get; } - - /// <summary> /// This is a special function that requests the session to be detached from the current http connection /// but allow it to remain available. /// </summary> diff --git a/lib/Plugins.Essentials/src/Sessions/ISessionExtensions.cs b/lib/Plugins.Essentials/src/Sessions/ISessionExtensions.cs index 44063f9..81d6ad3 100644 --- a/lib/Plugins.Essentials/src/Sessions/ISessionExtensions.cs +++ b/lib/Plugins.Essentials/src/Sessions/ISessionExtensions.cs @@ -30,6 +30,8 @@ using VNLib.Net.Http; using VNLib.Utils; using VNLib.Utils.Extensions; +#nullable disable + namespace VNLib.Plugins.Essentials.Sessions { public static class ISessionExtensions diff --git a/lib/Plugins.Essentials/src/Sessions/SessionBase.cs b/lib/Plugins.Essentials/src/Sessions/SessionBase.cs index 038fd2c..bf20b9d 100644 --- a/lib/Plugins.Essentials/src/Sessions/SessionBase.cs +++ b/lib/Plugins.Essentials/src/Sessions/SessionBase.cs @@ -28,6 +28,8 @@ using System.Runtime.CompilerServices; using VNLib.Utils; +#nullable disable + namespace VNLib.Plugins.Essentials.Sessions { /// <summary> diff --git a/lib/Plugins.Essentials/src/Sessions/SessionHandle.cs b/lib/Plugins.Essentials/src/Sessions/SessionHandle.cs index 68f5764..823012e 100644 --- a/lib/Plugins.Essentials/src/Sessions/SessionHandle.cs +++ b/lib/Plugins.Essentials/src/Sessions/SessionHandle.cs @@ -26,8 +26,6 @@ using System.Threading.Tasks; using VNLib.Net.Http; -#nullable enable - namespace VNLib.Plugins.Essentials.Sessions { /// <summary> diff --git a/lib/Plugins.Essentials/src/Sessions/SessionInfo.cs b/lib/Plugins.Essentials/src/Sessions/SessionInfo.cs index d6d5456..6c1141a 100644 --- a/lib/Plugins.Essentials/src/Sessions/SessionInfo.cs +++ b/lib/Plugins.Essentials/src/Sessions/SessionInfo.cs @@ -44,8 +44,6 @@ using static VNLib.Plugins.Essentials.Statics; #pragma warning disable CA1051 // Do not declare visible instance fields -#nullable enable - namespace VNLib.Plugins.Essentials.Sessions { /// <summary> diff --git a/lib/Plugins.Essentials/src/Sessions/SessionType.cs b/lib/Plugins.Essentials/src/Sessions/SessionType.cs new file mode 100644 index 0000000..9dc991c --- /dev/null +++ b/lib/Plugins.Essentials/src/Sessions/SessionType.cs @@ -0,0 +1,42 @@ +/* +* Copyright (c) 2023 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Plugins.Essentials +* File: SessionType.cs +* +* SessionType.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/. +*/ + + +namespace VNLib.Plugins.Essentials.Sessions +{ + /// <summary> + /// Flags to specify <see cref="ISession"/> session types + /// </summary> + public enum SessionType + { + /// <summary> + /// The session is a "basic" or web based session + /// </summary> + Web, + /// <summary> + /// The session is an OAuth2 session type + /// </summary> + OAuth2 + } +}
\ No newline at end of file diff --git a/lib/Plugins.Essentials/src/Users/IUser.cs b/lib/Plugins.Essentials/src/Users/IUser.cs index 635f5e4..a36ba70 100644 --- a/lib/Plugins.Essentials/src/Users/IUser.cs +++ b/lib/Plugins.Essentials/src/Users/IUser.cs @@ -29,8 +29,6 @@ using VNLib.Utils; using VNLib.Utils.Async; using VNLib.Utils.Memory; -#nullable enable - namespace VNLib.Plugins.Essentials.Users { /// <summary> diff --git a/lib/Plugins.Essentials/src/Users/IUserManager.cs b/lib/Plugins.Essentials/src/Users/IUserManager.cs index 42d482e..b731033 100644 --- a/lib/Plugins.Essentials/src/Users/IUserManager.cs +++ b/lib/Plugins.Essentials/src/Users/IUserManager.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -29,8 +29,6 @@ using System.Threading.Tasks; using VNLib.Utils; using VNLib.Utils.Memory; -#nullable enable - namespace VNLib.Plugins.Essentials.Users { /// <summary> @@ -46,6 +44,7 @@ namespace VNLib.Plugins.Essentials.Users /// <returns>The user's <see cref="IUser"/> object, null if the user was not found</returns> /// <exception cref="ArgumentNullException"></exception> Task<IUser?> GetUserFromIDAsync(string userId, CancellationToken cancellationToken = default); + /// <summary> /// Attempts to get a user object without their password from the database asynchronously /// </summary> @@ -54,6 +53,7 @@ namespace VNLib.Plugins.Essentials.Users /// <returns>The user's <see cref="IUser"/> object, null if the user was not found</returns> /// <exception cref="ArgumentNullException"></exception> Task<IUser?> GetUserFromEmailAsync(string emailAddress, CancellationToken cancellationToken = default); + /// <summary> /// Attempts to get a user object with their password from the database on the current thread /// </summary> @@ -62,6 +62,7 @@ namespace VNLib.Plugins.Essentials.Users /// <returns>The user's <see cref="IUser"/> object, null if the user was not found</returns> /// <exception cref="ArgumentNullException"></exception> Task<IUser?> GetUserAndPassFromIDAsync(string userid, CancellationToken cancellation = default); + /// <summary> /// Attempts to get a user object with their password from the database asynchronously /// </summary> @@ -70,6 +71,7 @@ namespace VNLib.Plugins.Essentials.Users /// <returns>The user's <see cref="IUser"/> object, null if the user was not found</returns> /// <exception cref="ArgumentNullException"></exception> Task<IUser?> GetUserAndPassFromEmailAsync(string emailAddress, CancellationToken cancellationToken = default); + /// <summary> /// Creates a new user in the current user's table and if successful returns the new user object (without password) /// </summary> @@ -83,6 +85,7 @@ namespace VNLib.Plugins.Essentials.Users /// <exception cref="ArgumentNullException"></exception> /// <exception cref="UserCreationFailedException"></exception> Task<IUser> CreateUserAsync(string userid, string emailAddress, ulong privileges, PrivateString passHash, CancellationToken cancellation = default); + /// <summary> /// Updates a password associated with the specified user. If the update fails, the transaction /// is rolled back. diff --git a/lib/Plugins.Essentials/src/Users/UserCreationFailedException.cs b/lib/Plugins.Essentials/src/Users/UserCreationFailedException.cs index 9f509ac..0c901f2 100644 --- a/lib/Plugins.Essentials/src/Users/UserCreationFailedException.cs +++ b/lib/Plugins.Essentials/src/Users/UserCreationFailedException.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -24,9 +24,8 @@ using System; using System.Runtime.Serialization; -using VNLib.Utils.Resources; -#nullable enable +using VNLib.Utils.Resources; namespace VNLib.Plugins.Essentials.Users { diff --git a/lib/Plugins.Essentials/src/Users/UserDeleteException.cs b/lib/Plugins.Essentials/src/Users/UserDeleteException.cs index cd26543..6e1fe59 100644 --- a/lib/Plugins.Essentials/src/Users/UserDeleteException.cs +++ b/lib/Plugins.Essentials/src/Users/UserDeleteException.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -23,6 +23,7 @@ */ using System; + using VNLib.Utils.Resources; namespace VNLib.Plugins.Essentials.Users @@ -36,9 +37,9 @@ namespace VNLib.Plugins.Essentials.Users public UserDeleteException(string message, Exception cause) : base(message, cause) { } public UserDeleteException() - {} + { } public UserDeleteException(string message) : base(message) - {} + { } } }
\ No newline at end of file diff --git a/lib/Plugins.Essentials/src/Users/UserExistsException.cs b/lib/Plugins.Essentials/src/Users/UserExistsException.cs index 5c63547..e9b9586 100644 --- a/lib/Plugins.Essentials/src/Users/UserExistsException.cs +++ b/lib/Plugins.Essentials/src/Users/UserExistsException.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -35,15 +35,18 @@ namespace VNLib.Plugins.Essentials.Users { ///<inheritdoc/> public UserExistsException() - {} + { } + ///<inheritdoc/> public UserExistsException(string message) : base(message) - {} + { } + ///<inheritdoc/> public UserExistsException(string message, Exception innerException) : base(message, innerException) - {} + { } + ///<inheritdoc/> protected UserExistsException(SerializationInfo info, StreamingContext context) : base(info, context) - {} + { } } }
\ No newline at end of file diff --git a/lib/Plugins.Essentials/src/Users/UserUpdateException.cs b/lib/Plugins.Essentials/src/Users/UserUpdateException.cs index 391bb05..46c986c 100644 --- a/lib/Plugins.Essentials/src/Users/UserUpdateException.cs +++ b/lib/Plugins.Essentials/src/Users/UserUpdateException.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials @@ -23,6 +23,7 @@ */ using System; + using VNLib.Utils.Resources; namespace VNLib.Plugins.Essentials.Users @@ -35,9 +36,9 @@ namespace VNLib.Plugins.Essentials.Users public UserUpdateException(string message, Exception cause) : base(message, cause) { } public UserUpdateException() - {} + { } public UserUpdateException(string message) : base(message) - {} + { } } }
\ No newline at end of file diff --git a/lib/Plugins.Essentials/src/VNLib.Plugins.Essentials.csproj b/lib/Plugins.Essentials/src/VNLib.Plugins.Essentials.csproj index 47fd60d..65fff58 100644 --- a/lib/Plugins.Essentials/src/VNLib.Plugins.Essentials.csproj +++ b/lib/Plugins.Essentials/src/VNLib.Plugins.Essentials.csproj @@ -8,6 +8,7 @@ <EnableNETAnalyzers>True</EnableNETAnalyzers> <GenerateDocumentationFile>True</GenerateDocumentationFile> <RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild> + <Nullable>enable</Nullable> </PropertyGroup> <PropertyGroup> @@ -17,8 +18,8 @@ <Product>VNLib Essentials Plugin Library</Product> <Copyright>Copyright © 2023 Vaughn Nugent</Copyright> <Description>Provides essential web, sessions, users abstractions for building extensable web applications with satefull sessions, user based intraction with login and account security extensions.</Description> - <PackageProjectUrl>https://www.vaughnnugent.com/resources/software/modules/VNLib.Core</PackageProjectUrl> <PackageTags>VNLib, Plugins, VNLib.Plugins.Essentials, Essentials, Essential Plugins, HTTP Essentials, OAuth2</PackageTags> + <PackageProjectUrl>https://www.vaughnnugent.com/resources/software/modules/VNLib.Core</PackageProjectUrl> <RepositoryUrl>https://github.com/VnUgE/VNLib.Core/tree/main/lib/Plugins.Essentials</RepositoryUrl> <PackageReadmeFile>README.md</PackageReadmeFile> <PackageLicenseFile>LICENSE</PackageLicenseFile> diff --git a/lib/Plugins.Essentials/src/WebSocketSession.cs b/lib/Plugins.Essentials/src/WebSocketSession.cs index c43a876..e39f352 100644 --- a/lib/Plugins.Essentials/src/WebSocketSession.cs +++ b/lib/Plugins.Essentials/src/WebSocketSession.cs @@ -30,8 +30,6 @@ using System.Threading.Tasks; using VNLib.Net.Http; -#nullable enable - namespace VNLib.Plugins.Essentials { /// <summary> @@ -134,24 +132,16 @@ namespace VNLib.Plugins.Essentials /// <param name="buffer">The buffer to store read data</param> /// <returns>A task that resolves a <see cref="WebSocketReceiveResult"/> which contains the status of the operation</returns> /// <exception cref="OperationCanceledException"></exception> - public Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byte> buffer) - { - //Begin receive operation only with the internal token - return WsHandle!.ReceiveAsync(buffer, CancellationToken.None); - } - + public Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byte> buffer) => WsHandle!.ReceiveAsync(buffer, CancellationToken.None); + /// <summary> /// Asynchronously receives data from the Websocket and copies the data to the specified buffer /// </summary> /// <param name="buffer">The buffer to store read data</param> /// <returns></returns> /// <exception cref="OperationCanceledException"></exception> - public ValueTask<ValueWebSocketReceiveResult> ReceiveAsync(Memory<byte> buffer) - { - //Begin receive operation only with the internal token - return WsHandle!.ReceiveAsync(buffer, CancellationToken.None); - } - + public ValueTask<ValueWebSocketReceiveResult> ReceiveAsync(Memory<byte> buffer) => WsHandle!.ReceiveAsync(buffer, CancellationToken.None); + /// <summary> /// Asynchronously sends the specified buffer to the client of the specified type /// </summary> @@ -160,12 +150,8 @@ namespace VNLib.Plugins.Essentials /// <param name="endOfMessage">A value that indicates this message is the final message of the transaction</param> /// <returns></returns> /// <exception cref="OperationCanceledException"></exception> - public Task SendAsync(ArraySegment<byte> buffer, WebSocketMessageType type, bool endOfMessage) - { - //Create a send request with - return WsHandle!.SendAsync(buffer, type, endOfMessage, CancellationToken.None); - } - + public Task SendAsync(ArraySegment<byte> buffer, WebSocketMessageType type, bool endOfMessage) => WsHandle!.SendAsync(buffer, type, endOfMessage, CancellationToken.None); + /// <summary> /// Asynchronously sends the specified buffer to the client of the specified type @@ -189,11 +175,7 @@ namespace VNLib.Plugins.Essentials /// <param name="flags">Websocket message flags</param> /// <returns></returns> /// <exception cref="OperationCanceledException"></exception> - public ValueTask SendAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType type, WebSocketMessageFlags flags) - { - //Create a send request with - return WsHandle!.SendAsync(buffer, type, flags, CancellationToken.None); - } + public ValueTask SendAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType type, WebSocketMessageFlags flags) => WsHandle!.SendAsync(buffer, type, flags, CancellationToken.None); /// <summary> @@ -202,11 +184,8 @@ namespace VNLib.Plugins.Essentials /// <param name="status">Set the close status</param> /// <param name="reason">Set the close reason</param> /// <exception cref="ObjectDisposedException"></exception> - public Task CloseSocketAsync(WebSocketCloseStatus status, string reason) - { - return WsHandle!.CloseAsync(status, reason, CancellationToken.None); - } - + public Task CloseSocketAsync(WebSocketCloseStatus status, string reason) => WsHandle!.CloseAsync(status, reason, CancellationToken.None); + /// <summary> /// /// </summary> |