aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Hashing.Portable/src/IdentityUtility/JsonWebToken.cs17
-rw-r--r--lib/Hashing.Portable/src/IdentityUtility/JwtExtensions.cs37
-rw-r--r--lib/Plugins.Essentials/src/HttpEntity.cs2
-rw-r--r--lib/Plugins.Essentials/src/Sessions/SessionHandle.cs39
-rw-r--r--lib/Plugins.Runtime/src/AsmFileWatcher.cs13
-rw-r--r--lib/Plugins.Runtime/src/RuntimePluginLoader.cs3
-rw-r--r--lib/Utils/src/VnEncoding.cs91
7 files changed, 125 insertions, 77 deletions
diff --git a/lib/Hashing.Portable/src/IdentityUtility/JsonWebToken.cs b/lib/Hashing.Portable/src/IdentityUtility/JsonWebToken.cs
index 6ee597e..ef313ca 100644
--- a/lib/Hashing.Portable/src/IdentityUtility/JsonWebToken.cs
+++ b/lib/Hashing.Portable/src/IdentityUtility/JsonWebToken.cs
@@ -24,7 +24,6 @@
using System;
using System.Text;
-using System.Buffers;
using System.Buffers.Text;
using VNLib.Utils;
@@ -250,19 +249,21 @@ namespace VNLib.Hashing.IdentityUtility
{
//Calculate the proper base64 buffer size
int base64BufSize = Base64.GetMaxEncodedToUtf8Length(value.Length);
- //Alloc buffer
+
+ //Alloc buffer from out heap
using UnsafeMemoryHandle<byte> binBuffer = Heap.UnsafeAlloc<byte>(base64BufSize);
+
+ //Urlencode without base64 padding characters
+ ERRNO written = VnEncoding.Base64UrlEncode(value, binBuffer.Span, false);
+
//Slice off the begiing of the buffer for the base64 encoding
- if(Base64.EncodeToUtf8(value, binBuffer.Span, out _, out int written) != OperationStatus.Done)
+ if(!written)
{
throw new InternalBufferTooSmallException("Failed to encode the specified value to base64");
}
- //Base64 encoded
- Span<byte> base64Data = binBuffer.Span[..written].Trim(PADDING_BYTES);
- //Convert to rfc4648 urlsafe version
- VnEncoding.Base64ToUrlSafeInPlace(base64Data);
+
//Write the endoded buffer to the stream
- DataStream.Write(base64Data);
+ DataStream.Write(binBuffer.Span[..(int)written]);
}
#endregion
diff --git a/lib/Hashing.Portable/src/IdentityUtility/JwtExtensions.cs b/lib/Hashing.Portable/src/IdentityUtility/JwtExtensions.cs
index 38c40bf..34211e5 100644
--- a/lib/Hashing.Portable/src/IdentityUtility/JwtExtensions.cs
+++ b/lib/Hashing.Portable/src/IdentityUtility/JwtExtensions.cs
@@ -23,7 +23,6 @@
*/
using System;
-using System.Buffers;
using System.Text.Json;
using System.Buffers.Text;
using System.Security.Cryptography;
@@ -348,21 +347,17 @@ namespace VNLib.Hashing.IdentityUtility
{
throw new InternalBufferTooSmallException("Failed to compute the hash of the JWT data");
}
-
- //Do an in-place base64 conversion of the signature to base64
- if (Base64.EncodeToUtf8InPlace(signatureBuffer, bytesWritten, out int base64BytesWritten) != OperationStatus.Done)
+
+ //Do an in-place base64 conversion of the signature to base64url
+ ERRNO encoded = VnEncoding.Base64UrlEncodeInPlace(signatureBuffer, bytesWritten, false);
+
+ if (!encoded)
{
throw new InternalBufferTooSmallException("Failed to convert the signature buffer to its base64 because the buffer was too small");
- }
-
- //Trim padding
- Span<byte> base64 = signatureBuffer[..base64BytesWritten].Trim(JsonWebToken.PADDING_BYTES);
-
- //Urlencode
- VnEncoding.Base64ToUrlSafeInPlace(base64);
+ }
//Verify the signatures and return results
- return CryptographicOperations.FixedTimeEquals(jwt.SignatureData, base64);
+ return CryptographicOperations.FixedTimeEquals(jwt.SignatureData, signatureBuffer[..(int)encoded]);
}
/// <summary>
@@ -444,20 +439,16 @@ namespace VNLib.Hashing.IdentityUtility
throw new InternalBufferTooSmallException("Failed to compute the hash of the JWT data");
}
- //Do an in-place base64 conversion of the signature to base64
- if (Base64.EncodeToUtf8InPlace(signatureBuffer, count, out int base64BytesWritten) != OperationStatus.Done)
+ //Do an in-place base64 conversion of the signature to base64url
+ ERRNO encoded = VnEncoding.Base64UrlEncodeInPlace(signatureBuffer, (int)alg, false);
+
+ if (!encoded)
{
throw new InternalBufferTooSmallException("Failed to convert the signature buffer to its base64 because the buffer was too small");
- }
-
- //Trim padding
- Span<byte> base64 = signatureBuffer[..base64BytesWritten].Trim(JsonWebToken.PADDING_BYTES);
-
- //Urlencode
- VnEncoding.Base64ToUrlSafeInPlace(base64);
-
+ }
+
//Verify the signatures and return results
- return CryptographicOperations.FixedTimeEquals(jwt.SignatureData, base64);
+ return CryptographicOperations.FixedTimeEquals(jwt.SignatureData, signatureBuffer[..(int)encoded]);
}
/// <summary>
diff --git a/lib/Plugins.Essentials/src/HttpEntity.cs b/lib/Plugins.Essentials/src/HttpEntity.cs
index f2f9387..ad89d14 100644
--- a/lib/Plugins.Essentials/src/HttpEntity.cs
+++ b/lib/Plugins.Essentials/src/HttpEntity.cs
@@ -58,7 +58,7 @@ namespace VNLib.Plugins.Essentials
/// </summary>
private readonly IHttpEvent Entity;
- public HttpEntity(IHttpEvent entity, EventProcessor root, in SessionHandle session, in CancellationToken cancellation)
+ public HttpEntity(IHttpEvent entity, IWebProcessor root, in SessionHandle session, CancellationToken cancellation)
{
Entity = entity;
RequestedRoot = root;
diff --git a/lib/Plugins.Essentials/src/Sessions/SessionHandle.cs b/lib/Plugins.Essentials/src/Sessions/SessionHandle.cs
index 8dbb077..68f5764 100644
--- a/lib/Plugins.Essentials/src/Sessions/SessionHandle.cs
+++ b/lib/Plugins.Essentials/src/Sessions/SessionHandle.cs
@@ -22,9 +22,7 @@
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
-using System;
using System.Threading.Tasks;
-using System.Diagnostics.CodeAnalysis;
using VNLib.Net.Http;
@@ -44,7 +42,7 @@ namespace VNLib.Plugins.Essentials.Sessions
/// A handle that holds exclusive access to a <see cref="ISession"/>
/// session object
/// </summary>
- public readonly struct SessionHandle : IEquatable<SessionHandle>
+ public readonly record struct SessionHandle
{
/// <summary>
/// An empty <see cref="SessionHandle"/> instance. (A handle without a session object)
@@ -93,40 +91,5 @@ namespace VNLib.Plugins.Essentials.Sessions
/// </summary>
/// <param name="event">The current connection event object</param>
public readonly ValueTask ReleaseAsync(IHttpEvent @event) => ReleaseCb?.Invoke(SessionData!, @event) ?? ValueTask.CompletedTask;
-
- /// <summary>
- /// Determines if another <see cref="SessionHandle"/> is equal to the current handle.
- /// Handles are equal if neither handle is set or if their SessionData object is equal.
- /// </summary>
- /// <param name="other">The other handle to</param>
- /// <returns>true if neither handle is set or if their SessionData object is equal, false otherwise</returns>
- public readonly bool Equals(SessionHandle other)
- {
- //If neither handle is set, then they are equal, otherwise they are equal if the session objects themselves are equal
- return (!IsSet && !other.IsSet) || (SessionData?.Equals(other.SessionData) ?? false);
- }
- ///<inheritdoc/>
- public readonly override bool Equals([NotNullWhen(true)] object? obj) => (obj is SessionHandle other) && Equals(other);
- ///<inheritdoc/>
- public readonly override int GetHashCode()
- {
- return IsSet ? SessionData!.GetHashCode() : base.GetHashCode();
- }
-
- /// <summary>
- /// Checks if two <see cref="SessionHandle"/> instances are equal
- /// </summary>
- /// <param name="left"></param>
- /// <param name="right"></param>
- /// <returns></returns>
- public static bool operator ==(SessionHandle left, SessionHandle right) => left.Equals(right);
-
- /// <summary>
- /// Checks if two <see cref="SessionHandle"/> instances are not equal
- /// </summary>
- /// <param name="left"></param>
- /// <param name="right"></param>
- /// <returns></returns>
- public static bool operator !=(SessionHandle left, SessionHandle right) => !(left == right);
}
}
diff --git a/lib/Plugins.Runtime/src/AsmFileWatcher.cs b/lib/Plugins.Runtime/src/AsmFileWatcher.cs
index 0aee21b..f2a0ca7 100644
--- a/lib/Plugins.Runtime/src/AsmFileWatcher.cs
+++ b/lib/Plugins.Runtime/src/AsmFileWatcher.cs
@@ -52,12 +52,13 @@ namespace VNLib.Plugins.Runtime
{
Filter = "*.dll",
EnableRaisingEvents = false,
- IncludeSubdirectories = false,
- NotifyFilter = NotifyFilters.LastWrite
+ IncludeSubdirectories = true,
+ NotifyFilter = NotifyFilters.LastWrite,
};
//Configure listener
_watcher.Changed += OnFileChanged;
+ _watcher.Created += OnFileChanged;
_watcher.EnableRaisingEvents = true;
@@ -73,16 +74,20 @@ namespace VNLib.Plugins.Runtime
return;
}
+ //Set pause flag
+ _pause = true;
+
//Restart the timer to trigger reload event on elapsed
_delayTimer.Restart(_loaderSource.Config.ReloadDelay);
}
private void OnTimeout(object? state)
{
- //Fire event
- Handler.OnPluginUnloaded(_loaderSource);
_delayTimer.Stop();
+ //Fire event, let exception crash app
+ Handler.OnPluginUnloaded(_loaderSource);
+
//Clear pause flag
_pause = false;
}
diff --git a/lib/Plugins.Runtime/src/RuntimePluginLoader.cs b/lib/Plugins.Runtime/src/RuntimePluginLoader.cs
index e581a86..e7b9404 100644
--- a/lib/Plugins.Runtime/src/RuntimePluginLoader.cs
+++ b/lib/Plugins.Runtime/src/RuntimePluginLoader.cs
@@ -40,8 +40,7 @@ namespace VNLib.Plugins.Runtime
public sealed class RuntimePluginLoader : VnDisposeable, IPluginReloadEventHandler
{
private static readonly IPluginAssemblyWatcher Watcher = new AssemblyWatcher();
-
- //private readonly IPluginAssemblyWatcher Watcher;
+
private readonly IPluginAssemblyLoader Loader;
private readonly JsonDocument HostConfig;
private readonly ILogProvider? Log;
diff --git a/lib/Utils/src/VnEncoding.cs b/lib/Utils/src/VnEncoding.cs
index 4a95405..35d52a7 100644
--- a/lib/Utils/src/VnEncoding.cs
+++ b/lib/Utils/src/VnEncoding.cs
@@ -452,7 +452,7 @@ namespace VNLib.Utils
//Calculate the base32 entropy to alloc an appropriate buffer (minium buffer of 2 chars)
int entropy = Base32CalcMaxBufferSize(binBuffer.Length);
//Alloc buffer for enough size (2*long bytes) is not an issue
- using (UnsafeMemoryHandle<char> charBuffer = Memory.MemoryUtil.UnsafeAlloc<char>(entropy))
+ using (UnsafeMemoryHandle<char> charBuffer = MemoryUtil.UnsafeAlloc<char>(entropy))
{
//Encode
ERRNO encoded = TryToBase32Chars(binBuffer, charBuffer.Span);
@@ -890,6 +890,95 @@ namespace VNLib.Utils
return Base64UrlDecode(decodeHandle.Span[..count], output);
}
+
+ /// <summary>
+ /// Base64url encodes the binary buffer to its utf8 binary representation
+ /// </summary>
+ /// <param name="buffer">The intput binary buffer to base64url encode</param>
+ /// <param name="dataLength">The data within the buffer to encode, must be smaller than the entire buffer</param>
+ /// <param name="includePadding">A value that indicates if base64 padding should be url encoded(true), or removed(false).</param>
+ /// <returns>The number characters written to the buffer, or <see cref="ERRNO.E_FAIL"/> if a error occured.</returns>
+ public static ERRNO Base64UrlEncodeInPlace(Span<byte> buffer, int dataLength, bool includePadding)
+ {
+ //Convert to base64
+ if (Base64.EncodeToUtf8InPlace(buffer, dataLength, out int bytesWritten) != OperationStatus.Done)
+ {
+ return ERRNO.E_FAIL;
+ }
+
+ if (includePadding)
+ {
+ //Url encode in place
+ Base64ToUrlSafeInPlace(buffer[..bytesWritten]);
+ return bytesWritten;
+ }
+ else
+ {
+ //Remove padding bytes
+ Span<byte> nonPadded = buffer[..bytesWritten].TrimEnd((byte)0x3d);
+
+ Base64ToUrlSafeInPlace(nonPadded);
+ return nonPadded.Length;
+ }
+
+ }
+
+ /// <summary>
+ /// Encodes the binary input buffer to its base64url safe utf8 encoding, and writes the output
+ /// to the supplied buffer. Be sure to call <see cref="Base64.GetMaxEncodedToUtf8Length(int)"/>
+ /// to allocate the correct size buffer for encoding
+ /// </summary>
+ /// <param name="input">The intput binary buffer to base64url encode</param>
+ /// <param name="output">The output buffer to write the base64url safe encodded date to</param>
+ /// <param name="includePadding">A value that indicates if base64 padding should be url encoded(true), or removed(false).</param>
+ /// <returns>The number characters written to the buffer, or <see cref="ERRNO.E_FAIL"/> if a error occured.</returns>
+ public static ERRNO Base64UrlEncode(ReadOnlySpan<byte> input, Span<byte> output, bool includePadding)
+ {
+ //Write the input buffer to the output buffer
+ input.CopyTo(output);
+
+ //encode in place
+ return Base64UrlEncodeInPlace(output, input.Length, includePadding);
+ }
+
+ /// <summary>
+ /// Encodes the binary intput buffer to its base64url safe encoding, then converts the internal buffer
+ /// to its character encoding using the supplied <paramref name="encoding"/>, and writes the characters
+ /// to the output buffer. Defaults to UTF8 character encoding. Base64url is a subset of ASCII,UTF7,UTF8,UTF16 etc
+ /// so most encodings should be safe.
+ /// </summary>
+ /// <param name="input">The input binary intput buffer</param>
+ /// <param name="output">The character output buffer</param>
+ /// <param name="includePadding">A value that indicates if base64 padding should be url encoded(true), or removed(false).</param>
+ /// <param name="encoding">The encoding used to convert the binary buffer to its character representation.</param>
+ /// <returns>The number of characters written to the buffer, or <see cref="ERRNO.E_FAIL"/> if a error occured</returns>
+ public static ERRNO Base64UrlEncode(ReadOnlySpan<byte> input, Span<char> output, bool includePadding, Encoding? encoding = null)
+ {
+ encoding ??= Encoding.UTF8;
+
+ //We need to alloc an intermediate buffer, get the base64 max size
+ int maxSize = Base64.GetMaxEncodedToUtf8Length(input.Length);
+
+ //Alloc buffer
+ using UnsafeMemoryHandle<byte> buffer = MemoryUtil.UnsafeAlloc(maxSize);
+
+ //Encode to url safe binary
+ ERRNO count = Base64UrlEncode(input, buffer.Span, includePadding);
+
+ if (count <= 0)
+ {
+ return count;
+ }
+
+ //Get char count to return to caller
+ int charCount = encoding.GetCharCount(buffer.Span[..(int)count]);
+
+ //Encode to characters
+ encoding.GetChars(buffer.AsSpan(0, count), output);
+
+ return charCount;
+ }
+
#endregion
}
} \ No newline at end of file