aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Net.Http/src/Core/HttpServerBase.cs23
-rw-r--r--lib/Net.Http/src/Core/HttpServerProcessing.cs28
-rw-r--r--lib/Net.Http/src/Core/Request/HttpInputStream.cs24
-rw-r--r--lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs16
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs9
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/IVirtualHostHooks.cs16
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs4
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs2
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/IPluginInitializer.cs3
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs6
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/PluginLoadEventListener.cs80
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs48
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs36
-rw-r--r--lib/Plugins.Essentials/src/Accounts/AccountData.cs22
-rw-r--r--lib/Plugins.Essentials/src/Accounts/AccountUtils.cs42
-rw-r--r--lib/Plugins.Essentials/src/Accounts/AuthorzationCheckLevel.cs2
-rw-r--r--lib/Plugins.Essentials/src/Accounts/ClientSecurityToken.cs2
-rw-r--r--lib/Plugins.Essentials/src/Accounts/FailedLoginLockout.cs2
-rw-r--r--lib/Plugins.Essentials/src/Accounts/IAccountSecurityProvider.cs2
-rw-r--r--lib/Plugins.Essentials/src/Accounts/IClientAuthorization.cs2
-rw-r--r--lib/Plugins.Essentials/src/Accounts/IClientSecInfo.cs2
-rw-r--r--lib/Plugins.Essentials/src/Accounts/IPasswordHashingProvider.cs4
-rw-r--r--lib/Plugins.Essentials/src/Accounts/LoginMessage.cs5
-rw-r--r--lib/Plugins.Essentials/src/Accounts/PasswordChallengeResult.cs3
-rw-r--r--lib/Plugins.Essentials/src/Content/IPageRouter.cs4
-rw-r--r--lib/Plugins.Essentials/src/Endpoints/ProtectionSettings.cs1
-rw-r--r--lib/Plugins.Essentials/src/Endpoints/ResourceEndpointBase.cs51
-rw-r--r--lib/Plugins.Essentials/src/EventProcessor.cs161
-rw-r--r--lib/Plugins.Essentials/src/Extensions/CollectionsExtensions.cs4
-rw-r--r--lib/Plugins.Essentials/src/Extensions/ConnectionInfoExtensions.cs2
-rw-r--r--lib/Plugins.Essentials/src/Extensions/EssentialHttpEventExtensions.cs2
-rw-r--r--lib/Plugins.Essentials/src/Extensions/HttpCookie.cs2
-rw-r--r--lib/Plugins.Essentials/src/Extensions/IJsonSerializerBuffer.cs6
-rw-r--r--lib/Plugins.Essentials/src/Extensions/InternalSerializerExtensions.cs4
-rw-r--r--lib/Plugins.Essentials/src/Extensions/InvalidJsonRequestException.cs4
-rw-r--r--lib/Plugins.Essentials/src/Extensions/JsonResponse.cs15
-rw-r--r--lib/Plugins.Essentials/src/Extensions/SimpleMemoryResponse.cs8
-rw-r--r--lib/Plugins.Essentials/src/Extensions/UserExtensions.cs6
-rw-r--r--lib/Plugins.Essentials/src/FileProcessArgs.cs3
-rw-r--r--lib/Plugins.Essentials/src/HttpEntity.cs42
-rw-r--r--lib/Plugins.Essentials/src/IEpProcessingOptions.cs2
-rw-r--r--lib/Plugins.Essentials/src/IVirtualEndpointTable.cs5
-rw-r--r--lib/Plugins.Essentials/src/IWebProcessorInfo.cs3
-rw-r--r--lib/Plugins.Essentials/src/Middleware/IHttpMiddlewareChain.cs2
-rw-r--r--lib/Plugins.Essentials/src/Middleware/SemiConistentMiddlewareChain.cs2
-rw-r--r--lib/Plugins.Essentials/src/Oauth/O2EndpointBase.cs52
-rw-r--r--lib/Plugins.Essentials/src/SemiConsistentVeTable.cs2
-rw-r--r--lib/Plugins.Essentials/src/Sessions/ISession.cs28
-rw-r--r--lib/Plugins.Essentials/src/Sessions/ISessionExtensions.cs2
-rw-r--r--lib/Plugins.Essentials/src/Sessions/SessionBase.cs2
-rw-r--r--lib/Plugins.Essentials/src/Sessions/SessionHandle.cs2
-rw-r--r--lib/Plugins.Essentials/src/Sessions/SessionInfo.cs2
-rw-r--r--lib/Plugins.Essentials/src/Sessions/SessionType.cs42
-rw-r--r--lib/Plugins.Essentials/src/Users/IUser.cs2
-rw-r--r--lib/Plugins.Essentials/src/Users/IUserManager.cs9
-rw-r--r--lib/Plugins.Essentials/src/Users/UserCreationFailedException.cs5
-rw-r--r--lib/Plugins.Essentials/src/Users/UserDeleteException.cs7
-rw-r--r--lib/Plugins.Essentials/src/Users/UserExistsException.cs13
-rw-r--r--lib/Plugins.Essentials/src/Users/UserUpdateException.cs7
-rw-r--r--lib/Plugins.Essentials/src/VNLib.Plugins.Essentials.csproj3
-rw-r--r--lib/Plugins.Essentials/src/WebSocketSession.cs39
-rw-r--r--lib/Utils/src/Memory/MemoryUtil.cs2
62 files changed, 486 insertions, 445 deletions
diff --git a/lib/Net.Http/src/Core/HttpServerBase.cs b/lib/Net.Http/src/Core/HttpServerBase.cs
index 790d0ff..f9e0418 100644
--- a/lib/Net.Http/src/Core/HttpServerBase.cs
+++ b/lib/Net.Http/src/Core/HttpServerBase.cs
@@ -79,6 +79,7 @@ namespace VNLib.Net.Http
private readonly ITransportProvider Transport;
private readonly IReadOnlyDictionary<string, IWebRoot> ServerRoots;
private readonly IWebRoot? _wildcardRoot;
+ private readonly HttpConfig _config;
#region caches
/// <summary>
@@ -98,7 +99,7 @@ namespace VNLib.Net.Http
/// <summary>
/// The <see cref="HttpConfig"/> for the current server
/// </summary>
- public HttpConfig Config { get; }
+ public ref readonly HttpConfig Config => ref _config;
/// <summary>
/// Gets a value indicating whether the server is listening for connections
@@ -129,11 +130,11 @@ namespace VNLib.Net.Http
//Validate the configuration
ValidateConfig(in config);
- Config = config;
+ _config = config;
//Configure roots and their directories
ServerRoots = sites.ToDictionary(static r => r.Hostname, static tv => tv, StringComparer.OrdinalIgnoreCase);
//Compile and store the timeout keepalive header
- KeepAliveTimeoutHeaderValue = $"timeout={(int)Config.ConnectionKeepAlive.TotalSeconds}";
+ KeepAliveTimeoutHeaderValue = $"timeout={(int)_config.ConnectionKeepAlive.TotalSeconds}";
//Create a new context store
ContextStore = ObjectRental.CreateReusable(() => new HttpContext(this));
//Setup config copy with the internal http pool
@@ -303,7 +304,7 @@ namespace VNLib.Net.Http
//Set running flag
Running = true;
- Config.ServerLog.Information("HTTP server {hc} listening for connections", GetHashCode());
+ _config.ServerLog.Information("HTTP server {hc} listening for connections", GetHashCode());
//Listen for connections until canceled
while (true)
@@ -323,15 +324,15 @@ namespace VNLib.Net.Http
}
catch(AuthenticationException ae) when(ae.HResult == INVALID_FRAME_HRESULT)
{
- Config.ServerLog.Debug("A TLS connection attempt was made but an invalid TLS frame was received");
+ _config.ServerLog.Debug("A TLS connection attempt was made but an invalid TLS frame was received");
}
catch (AuthenticationException ae)
{
- Config.ServerLog.Error(ae);
+ _config.ServerLog.Error(ae);
}
catch (Exception ex)
{
- Config.ServerLog.Error(ex);
+ _config.ServerLog.Error(ex);
}
}
@@ -340,7 +341,7 @@ namespace VNLib.Net.Http
//Clear running flag
Running = false;
- Config.ServerLog.Information("HTTP server {hc} exiting", GetHashCode());
+ _config.ServerLog.Information("HTTP server {hc} exiting", GetHashCode());
}
@@ -365,13 +366,13 @@ namespace VNLib.Net.Http
case SocketError.ConnectionAborted:
break;
case SocketError.ConnectionReset:
- Config.ServerLog.Debug("Connecion reset by client");
+ _config.ServerLog.Debug("Connecion reset by client");
break;
case SocketError.TimedOut:
- Config.ServerLog.Debug("Socket operation timed out");
+ _config.ServerLog.Debug("Socket operation timed out");
break;
default:
- Config.ServerLog.Information(se);
+ _config.ServerLog.Information(se);
break;
}
}
diff --git a/lib/Net.Http/src/Core/HttpServerProcessing.cs b/lib/Net.Http/src/Core/HttpServerProcessing.cs
index 6c5fd43..7d01e23 100644
--- a/lib/Net.Http/src/Core/HttpServerProcessing.cs
+++ b/lib/Net.Http/src/Core/HttpServerProcessing.cs
@@ -56,7 +56,7 @@ namespace VNLib.Net.Http
try
{
//Set write timeout
- transportContext.ConnectionStream.WriteTimeout = Config.SendTimeout;
+ transportContext.ConnectionStream.WriteTimeout = _config.SendTimeout;
//Init stream
context.InitializeContext(transportContext);
@@ -65,7 +65,7 @@ namespace VNLib.Net.Http
do
{
//Set rx timeout low for initial reading
- transportContext.ConnectionStream.ReadTimeout = Config.ActiveConnectionRecvTimeout;
+ transportContext.ConnectionStream.ReadTimeout = _config.ActiveConnectionRecvTimeout;
//Process the request
bool keepAlive = await ProcessHttpEventAsync(context);
@@ -77,7 +77,7 @@ namespace VNLib.Net.Http
}
//Reset inactive keeaplive timeout, when expired the following read will throw a cancealltion exception
- transportContext.ConnectionStream.ReadTimeout = (int)Config.ConnectionKeepAlive.TotalMilliseconds;
+ transportContext.ConnectionStream.ReadTimeout = (int)_config.ConnectionKeepAlive.TotalMilliseconds;
//"Peek" or wait for more data to begin another request (may throw timeout exception when timmed out)
await transportContext.ConnectionStream.ReadAsync(Memory<byte>.Empty, StopToken!.Token);
@@ -114,15 +114,15 @@ namespace VNLib.Net.Http
//Catch wrapped OC exceptions
catch (IOException ioe) when (ioe.InnerException is OperationCanceledException oce)
{
- Config.ServerLog.Debug("Failed to receive transport data within a timeout period {m} connection closed", oce.Message);
+ _config.ServerLog.Debug("Failed to receive transport data within a timeout period {m} connection closed", oce.Message);
}
catch (OperationCanceledException oce)
{
- Config.ServerLog.Debug("Failed to receive transport data within a timeout period {m} connection closed", oce.Message);
+ _config.ServerLog.Debug("Failed to receive transport data within a timeout period {m} connection closed", oce.Message);
}
catch(Exception ex)
{
- Config.ServerLog.Error(ex);
+ _config.ServerLog.Error(ex);
}
//Dec open connection count
@@ -142,7 +142,7 @@ namespace VNLib.Net.Http
}
catch(Exception ex)
{
- Config.ServerLog.Error(ex);
+ _config.ServerLog.Error(ex);
}
}
@@ -188,11 +188,11 @@ namespace VNLib.Net.Http
//Response
context.Response.Compile(ref writer);
- server.Config.RequestDebugLog!.Verbose("\r\n{dbg}", writer.ToString());
+ server._config.RequestDebugLog!.Verbose("\r\n{dbg}", writer.ToString());
}
//Write debug response log
- if(Config.RequestDebugLog != null)
+ if(_config.RequestDebugLog != null)
{
WriteConnectionDebugLog(this, context);
}
@@ -248,7 +248,7 @@ namespace VNLib.Net.Http
IHttpHeaderParseBuffer parseBuffer = ctx.Buffers.RequestHeaderParseBuffer;
//Init parser
- TransportReader reader = new (ctx.GetTransport(), parseBuffer, Config.HttpEncoding, HeaderLineTermination);
+ TransportReader reader = new (ctx.GetTransport(), parseBuffer, _config.HttpEncoding, HeaderLineTermination);
try
{
@@ -323,7 +323,7 @@ namespace VNLib.Net.Http
}
//Check open connection count (not super accurate, or might not be atomic)
- if (OpenConnectionCount > Config.MaxOpenConnections)
+ if (OpenConnectionCount > _config.MaxOpenConnections)
{
//Close the connection and return 503
context.Response.Headers[HttpResponseHeader.Connection] = "closed";
@@ -332,7 +332,7 @@ namespace VNLib.Net.Http
}
//Store keepalive value from request, and check if keepalives are enabled by the configuration
- bool keepalive = context.Request.KeepAlive & Config.ConnectionKeepAlive > TimeSpan.Zero;
+ bool keepalive = context.Request.KeepAlive & _config.ConnectionKeepAlive > TimeSpan.Zero;
//Set connection header (only for http1.1)
@@ -400,7 +400,7 @@ namespace VNLib.Net.Http
catch (TerminateConnectionException tce)
{
//Log the event as a debug so user can see it was handled
- Config.ServerLog.Debug(tce, "User-code requested a connection termination");
+ _config.ServerLog.Debug(tce, "User-code requested a connection termination");
//See if the exception requested an error code response
if (tce.Code > 0)
@@ -424,7 +424,7 @@ namespace VNLib.Net.Http
}
catch (Exception ex)
{
- Config.ServerLog.Warn(ex, "Unhandled exception during application code execution.");
+ _config.ServerLog.Warn(ex, "Unhandled exception during application code execution.");
}
finally
{
diff --git a/lib/Net.Http/src/Core/Request/HttpInputStream.cs b/lib/Net.Http/src/Core/Request/HttpInputStream.cs
index fbb1d41..3f6b2a5 100644
--- a/lib/Net.Http/src/Core/Request/HttpInputStream.cs
+++ b/lib/Net.Http/src/Core/Request/HttpInputStream.cs
@@ -74,28 +74,12 @@ namespace VNLib.Net.Http.Core
/// and initial data buffer
/// </summary>
/// <param name="contentLength">The number of bytes to allow being read from the transport or initial buffer</param>
- /// <param name="initial">Entity body data captured on initial read</param>
- internal void Prepare(long contentLength, in InitDataBuffer initial)
+ internal ref InitDataBuffer? Prepare(long contentLength)
{
- ContentLength = contentLength;
- _initalData = initial;
-
- //Cache transport
- InputStream = ContextInfo.GetTransport();
- }
-
- /// <summary>
- /// Prepares the input stream for reading from the transport with the specified content length
- /// amount of data
- /// </summary>
- /// <param name="contentLength">The number of bytes to allow being read from the transport</param>
- internal void Prepare(long contentLength)
- {
- ContentLength = contentLength;
- _initalData = null;
-
- //Cache transport
+ ContentLength = contentLength;
+ //Cache transport stream
InputStream = ContextInfo.GetTransport();
+ return ref _initalData;
}
public override void Close() => throw new NotSupportedException("The HTTP input stream should never be closed!");
diff --git a/lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs b/lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs
index de65e12..5e7f019 100644
--- a/lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs
+++ b/lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs
@@ -555,21 +555,15 @@ namespace VNLib.Net.Http.Core
* with null
*/
+ ref InitDataBuffer? initData = ref Request.InputStream.Prepare(parseState.ContentLength);
+
if (available > 0)
{
- //Creates the new initial data buffer
- InitDataBuffer initData = InitDataBuffer.AllocBuffer(InputDataBufferPool, available);
+ //Alloc the buffer and asign it
+ initData = InitDataBuffer.AllocBuffer(InputDataBufferPool, available);
//Read remaining data into the buffer's data segment
- _ = reader.ReadRemaining(initData.DataSegment);
-
- //Setup the input stream and capture the initial data from the reader, and wrap the transport stream to read data directly
- Request.InputStream.Prepare(parseState.ContentLength, initData);
- }
- else
- {
- //Empty input stream
- Request.InputStream.Prepare(parseState.ContentLength);
+ _ = reader.ReadRemaining(initData.Value.DataSegment);
}
Request.HasEntityBody = true;
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs
index c4d602b..91184bd 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs
@@ -150,6 +150,11 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
servers.AddLast(server);
}
+ return new(servers, sd, GetPluginStack(sd));
+ }
+
+ private PluginStackInitializer GetPluginStack(ServiceDomain domain)
+ {
//Always init manual array
manualPlugins ??= Array.Empty<IManualPlugin>();
@@ -160,9 +165,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
plugins ??= new EmptyPluginStack();
#pragma warning restore CA2000 // Dispose objects before losing scope
- IPluginInitializer init = new PluginStackInitializer(plugins, manualPlugins);
-
- return new(servers, sd, init);
+ return new (domain.GetListener(), plugins, manualPlugins);
}
/*
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/IVirtualHostHooks.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/IVirtualHostHooks.cs
index 6691d6b..acfc6e2 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/Construction/IVirtualHostHooks.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/IVirtualHostHooks.cs
@@ -23,7 +23,6 @@
*/
using System.Net;
-using System.Threading.Tasks;
using VNLib.Net.Http;
@@ -52,7 +51,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
/// When an error occurs and is handled by the library, this event is invoked
/// </para>
/// <para>
- /// NOTE: This function must be thread-safe!
+ /// NOTE: This function must be thread-safe! And should not throw exceptions
/// </para>
/// </summary>
/// <param name="errorCode">The error code that was created during processing</param>
@@ -64,14 +63,19 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
/// For pre-processing a request entity before all endpoint lookups are performed
/// </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>
- ValueTask<FileProcessArgs> PreProcessEntityAsync(HttpEntity entity);
+ /// <param name="args">The results to return to the file processor, or <see cref="FileProcessArgs.Continue"/> if processing should continue</param>
+ /// <returns></returns>
+ void PreProcessEntityAsync(HttpEntity entity, out FileProcessArgs args);
/// <summary>
- /// Allows for post processing of a selected <see cref="FileProcessArgs"/> for the given entity
+ /// Allows for post processing of a selected <see cref="FileProcessArgs"/> for the given entity.
+ /// <para>
+ /// This method may mutate the <paramref name="chosenRoutine"/> argument referrence to change the
+ /// the routine that will be used to process the file.
+ /// </para>
/// </summary>
/// <param name="entity">The http entity to process</param>
/// <param name="chosenRoutine">The selected file processing routine for the given request</param>
- void PostProcessFile(HttpEntity entity, in FileProcessArgs chosenRoutine);
+ void PostProcessFile(HttpEntity entity, ref FileProcessArgs chosenRoutine);
}
}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs
index d518218..54b7ff2 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs
@@ -316,10 +316,10 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
public override bool ErrorHandler(HttpStatusCode errorCode, IHttpEvent entity) => Hooks.ErrorHandler(errorCode, entity);
///<inheritdoc/>
- public override void PostProcessFile(HttpEntity entity, in FileProcessArgs chosenRoutine) => Hooks.PostProcessFile(entity, chosenRoutine);
+ public override void PreProcessEntity(HttpEntity entity, out FileProcessArgs preProcArgs) => Hooks.PreProcessEntityAsync(entity, out preProcArgs);
///<inheritdoc/>
- public override ValueTask<FileProcessArgs> PreProcessEntityAsync(HttpEntity entity) => Hooks.PreProcessEntityAsync(entity);
+ public override void PostProcessEntity(HttpEntity entity, ref FileProcessArgs chosenRoutine) => Hooks.PostProcessFile(entity, ref chosenRoutine);
///<inheritdoc/>
public override string TranslateResourcePath(string requestPath) => Hooks.TranslateResourcePath(requestPath);
diff --git a/lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs b/lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs
index 7cd5ac4..16bc1a0 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs
@@ -65,7 +65,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
{
_servers = servers;
_serviceDomain = serviceDomain;
- _plugins = new(serviceDomain, plugins);
+ _plugins = new(plugins);
WaitForAllTask = Task.CompletedTask;
}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/IPluginInitializer.cs b/lib/Plugins.Essentials.ServiceStack/src/IPluginInitializer.cs
index ac91f45..a9aa103 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/IPluginInitializer.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/IPluginInitializer.cs
@@ -24,14 +24,11 @@
using VNLib.Utils.Logging;
-using VNLib.Plugins.Runtime;
namespace VNLib.Plugins.Essentials.ServiceStack
{
internal interface IPluginInitializer
{
- void PrepareStack(IPluginEventListener listener);
-
IManagedPlugin[] InitializePluginStack(ILogProvider eventLogger);
void UnloadPlugins();
diff --git a/lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs b/lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs
index 010039d..d93df6d 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs
@@ -25,8 +25,8 @@
using System.Linq;
using System.Collections.Generic;
-using VNLib.Plugins.Runtime;
using VNLib.Utils.Logging;
+using VNLib.Plugins.Runtime;
namespace VNLib.Plugins.Essentials.ServiceStack
{
@@ -47,7 +47,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// </summary>
/// <param name="controller"></param>
/// <returns></returns>
- internal static IEnumerable<LivePlugin> GetOnlyWebPlugins(this PluginController controller) => controller.Plugins.Where(p => p.Plugin is IWebPlugin);
+ internal static IEnumerable<LivePlugin> GetOnlyWebPlugins(this PluginController controller) => controller.Plugins.Where(static p => p.Plugin is IWebPlugin);
/// <summary>
/// Loads all plugins that implement <see cref="IWebPlugin"/> interface into the
@@ -56,5 +56,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// <param name="stack"></param>
/// <param name="logProvider">A log provider for writing loading logs to</param>
public static void LoadPlugins(this HttpServiceStack stack, ILogProvider logProvider) => (stack.PluginManager as PluginManager)!.LoadPlugins(logProvider);
+
+ internal static PluginLoadEventListener GetListener(this ServiceDomain domain) => new(domain);
}
}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/PluginLoadEventListener.cs b/lib/Plugins.Essentials.ServiceStack/src/PluginLoadEventListener.cs
new file mode 100644
index 0000000..0eaa3a8
--- /dev/null
+++ b/lib/Plugins.Essentials.ServiceStack/src/PluginLoadEventListener.cs
@@ -0,0 +1,80 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials.ServiceStack
+* File: PluginLoadEventListener.cs
+*
+* PluginLoadEventListener.cs is part of VNLib.Plugins.Essentials.ServiceStack which
+* is part of the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Essentials.ServiceStack 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 2 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Essentials.ServiceStack 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.Linq;
+
+using VNLib.Utils.Extensions;
+using VNLib.Plugins.Runtime;
+
+namespace VNLib.Plugins.Essentials.ServiceStack
+{
+ internal sealed record class PluginLoadEventListener(ServiceDomain Domain) : IPluginEventListener
+ {
+ ///<inheritdoc/>
+ void IPluginEventListener.OnPluginLoaded(PluginController controller, object? state) => OnPluginLoaded((state as IManagedPlugin)!);
+
+ ///<inheritdoc/>
+ void IPluginEventListener.OnPluginUnloaded(PluginController controller, object? state) => OnPluginUnloaded((state as IManagedPlugin)!);
+
+ /// <summary>
+ /// Called when a plugin has been successfully loaded and
+ /// should be put into service
+ /// </summary>
+ /// <param name="plugin">The plugin that was loaded</param>
+ public void OnPluginLoaded(IManagedPlugin plugin)
+ {
+ //Run onload method before invoking other handlers
+ plugin.OnPluginLoaded();
+
+ //Get event listeners at event time because deps may be modified by the domain
+ ServiceGroup[] deps = Domain.ServiceGroups.Select(static d => d).ToArray();
+
+ //run onload method
+ deps.TryForeach(d => d.OnPluginLoaded(plugin));
+ }
+
+ /// <summary>
+ /// Called when a plugin is about to be unloaded and should
+ /// be removed from service.
+ /// </summary>
+ /// <param name="plugin">The plugin instance to unload</param>
+ public void OnPluginUnloaded(IManagedPlugin plugin)
+ {
+ try
+ {
+ //Get event listeners at event time because deps may be modified by the domain
+ ServiceGroup[] deps = Domain.ServiceGroups.Select(static d => d).ToArray();
+
+ //Run unloaded method
+ deps.TryForeach(d => d.OnPluginUnloaded(plugin));
+ }
+ finally
+ {
+ //always unload the plugin wrapper
+ plugin.OnPluginUnloaded();
+ }
+ }
+ }
+}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs b/lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs
index 2f57367..ba3b91a 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs
@@ -24,13 +24,10 @@
using System;
-using System.Linq;
using System.Collections.Generic;
using VNLib.Utils;
using VNLib.Utils.Logging;
-using VNLib.Utils.Extensions;
-using VNLib.Plugins.Runtime;
namespace VNLib.Plugins.Essentials.ServiceStack
{
@@ -39,9 +36,8 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// A sealed type that manages the plugin interaction layer. Manages the lifetime of plugin
/// instances, exposes controls, and relays stateful plugin events.
/// </summary>
- internal sealed class PluginManager : VnDisposeable, IHttpPluginManager, IPluginEventListener
- {
- private readonly ServiceDomain _dependents;
+ internal sealed class PluginManager : VnDisposeable, IHttpPluginManager
+ {
private readonly IPluginInitializer _stack;
/// <summary>
@@ -51,9 +47,8 @@ namespace VNLib.Plugins.Essentials.ServiceStack
private IManagedPlugin[] _loadedPlugins;
- public PluginManager(ServiceDomain dependents, IPluginInitializer stack)
+ public PluginManager(IPluginInitializer stack)
{
- _dependents = dependents;
_stack = stack;
_loadedPlugins = Array.Empty<IManagedPlugin>();
}
@@ -62,11 +57,13 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// Configures the manager to capture and manage plugins within a plugin stack
/// </summary>
/// <param name="debugLog"></param>
+ /// <exception cref="InvalidOperationException"></exception>
+ /// <exception cref="AggregateException"></exception>
public void LoadPlugins(ILogProvider debugLog)
{
_ = _stack ?? throw new InvalidOperationException("Plugin stack has not been set.");
- _stack.PrepareStack(this);
+ Check();
//Initialize the plugin stack and store the loaded plugins
_loadedPlugins = _stack.InitializePluginStack(debugLog);
@@ -124,38 +121,5 @@ namespace VNLib.Plugins.Essentials.ServiceStack
//Dispose the plugin stack
_stack.Dispose();
}
-
- void IPluginEventListener.OnPluginLoaded(PluginController controller, object? state)
- {
- IManagedPlugin mp = (state as IManagedPlugin)!;
-
- //Run onload method before invoking other handlers
- mp.OnPluginLoaded();
-
- //Get event listeners at event time because deps may be modified by the domain
- ServiceGroup[] deps = _dependents.ServiceGroups.Select(static d => d).ToArray();
-
- //run onload method
- deps.TryForeach(d => d.OnPluginLoaded(mp));
- }
-
- void IPluginEventListener.OnPluginUnloaded(PluginController controller, object? state)
- {
- IManagedPlugin plugin = (state as IManagedPlugin)!;
-
- try
- {
- //Get event listeners at event time because deps may be modified by the domain
- ServiceGroup[] deps = _dependents.ServiceGroups.Select(static d => d).ToArray();
-
- //Run unloaded method
- deps.TryForeach(d => d.OnPluginUnloaded(plugin));
- }
- finally
- {
- //always unload the plugin wrapper
- plugin.OnPluginUnloaded();
- }
- }
}
}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs b/lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs
index 6ccd862..8a4e801 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs
@@ -40,13 +40,12 @@ using VNLib.Plugins.Attributes;
namespace VNLib.Plugins.Essentials.ServiceStack
{
- internal sealed record class PluginStackInitializer(IPluginStack Stack, IManualPlugin[] ManualPlugins) : IPluginInitializer
+ internal sealed record class PluginStackInitializer(PluginLoadEventListener Listener, IPluginStack Stack, IManualPlugin[] ManualPlugins) : IPluginInitializer
{
private readonly LinkedList<IManagedPlugin> _managedPlugins = new();
private readonly LinkedList<ManualPluginWrapper> _manualPlugins = new();
-
- ///<inheritdoc/>
- public void PrepareStack(IPluginEventListener listener)
+
+ private void PrepareStack()
{
/*
* Since we own the plugin stack, it is safe to build it here.
@@ -62,7 +61,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
Array.ForEach(wrapper, p => _managedPlugins.AddLast(p));
//Register for all plugins and pass the plugin instance as the state object
- Array.ForEach(wrapper, p => p.Plugin.Controller.Register(listener, p));
+ Array.ForEach(wrapper, p => p.Plugin.Controller.Register(Listener, p));
//Add manual plugins to list of managed plugins
Array.ForEach(ManualPlugins, p => _manualPlugins.AddLast(new ManualPluginWrapper(p)));
@@ -71,6 +70,9 @@ namespace VNLib.Plugins.Essentials.ServiceStack
///<inheritdoc/>
public IManagedPlugin[] InitializePluginStack(ILogProvider debugLog)
{
+ //Prepare the plugin stack before initializing
+ PrepareStack();
+
//single thread initialziation
LinkedList<IManagedPlugin> _loadedPlugins = new();
@@ -96,6 +98,9 @@ namespace VNLib.Plugins.Essentials.ServiceStack
public void UnloadPlugins()
{
Stack.UnloadAll();
+
+ //Unload manual plugins in listener
+ _managedPlugins.TryForeach(mp => Listener.OnPluginUnloaded(mp));
_manualPlugins.TryForeach(static mp => mp.Unload());
}
@@ -104,9 +109,13 @@ namespace VNLib.Plugins.Essentials.ServiceStack
{
Stack.ReloadAll();
- //Reload manual plugins
+ //Unload manual plugins in listener, then call the unload method
+ _managedPlugins.TryForeach(mp => Listener.OnPluginUnloaded(mp));
_manualPlugins.TryForeach(static mp => mp.Unload());
+
+ //Load, then invoke on-loaded events
_manualPlugins.TryForeach(static mp => mp.Load());
+ _managedPlugins.TryForeach(mp => Listener.OnPluginLoaded(mp));
}
///<inheritdoc/>
@@ -155,7 +164,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
return false;
}
- private static void LoadPlugin(IManagedPlugin plugin, ILogProvider debugLog)
+ private void LoadPlugin(IManagedPlugin plugin, ILogProvider debugLog)
{
Stopwatch sw = new();
try
@@ -170,6 +179,8 @@ namespace VNLib.Plugins.Essentials.ServiceStack
else if (plugin is ManualPluginWrapper mpw)
{
mpw.Load();
+ //Call the on-load event in listener explicitly
+ Listener.OnPluginLoaded(plugin);
}
else
{
@@ -313,13 +324,12 @@ namespace VNLib.Plugins.Essentials.ServiceStack
return false;
}
+
+ void IManagedPlugin.OnPluginLoaded()
+ { }
-
- /*
- * SHOULD NEVER BE CALLED
- */
- void IManagedPlugin.OnPluginLoaded() => throw new NotImplementedException();
- void IManagedPlugin.OnPluginUnloaded() => throw new NotImplementedException();
+ void IManagedPlugin.OnPluginUnloaded()
+ { }
///<inheritdoc/>
public override string ToString() => Plugin.Name;
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>
diff --git a/lib/Utils/src/Memory/MemoryUtil.cs b/lib/Utils/src/Memory/MemoryUtil.cs
index dc69e76..6af2392 100644
--- a/lib/Utils/src/Memory/MemoryUtil.cs
+++ b/lib/Utils/src/Memory/MemoryUtil.cs
@@ -660,7 +660,7 @@ namespace VNLib.Utils.Memory
{
if (offset + count > (ulong)block.LongLength)
{
- throw new ArgumentOutOfRangeException("The offset or count is outside of the range of the block of memory");
+ throw new ArgumentOutOfRangeException(nameof(offset), "The offset or count is outside of the range of the block of memory");
}
}