diff --git a/src/WebExpress.WebCore.Test/Html/UnitTestRandomId.cs b/src/WebExpress.WebCore.Test/Html/UnitTestRandomId.cs index 7b9554b..6152894 100644 --- a/src/WebExpress.WebCore.Test/Html/UnitTestRandomId.cs +++ b/src/WebExpress.WebCore.Test/Html/UnitTestRandomId.cs @@ -59,7 +59,7 @@ public void HexCharacters() var id = RandomId.Create(); // validation - var hex = id.Substring(4); + var hex = id.Substring("id_".Length); Assert.Matches("^[0-9A-F]+$", hex); } diff --git a/src/WebExpress.WebCore.Test/Manager/UnitTestStatusPageManager.cs b/src/WebExpress.WebCore.Test/Manager/UnitTestStatusPageManager.cs index b6cbce4..6b13db3 100644 --- a/src/WebExpress.WebCore.Test/Manager/UnitTestStatusPageManager.cs +++ b/src/WebExpress.WebCore.Test/Manager/UnitTestStatusPageManager.cs @@ -165,8 +165,8 @@ public void CreateAndCheckCode(Type applicationType, int statusCode, int? expect /// Test the CreateStatusResponse function of the status page. /// [Theory] - [InlineData(typeof(TestApplicationA), 400, "content", "content", 78)] - [InlineData(typeof(TestApplicationA), 500, "content", "content", 78)] + [InlineData(typeof(TestApplicationA), 400, "content", "content", 72)] + [InlineData(typeof(TestApplicationA), 500, "content", "content", 72)] public void CreateAndCheckMessage(Type applicationType, int statusCode, string content, string expected, int length) { // arrange diff --git a/src/WebExpress.WebCore/WebAttribute/SegmentRegexAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SegmentRegexAttribute.cs index 9544cd4..207fb83 100644 --- a/src/WebExpress.WebCore/WebAttribute/SegmentRegexAttribute.cs +++ b/src/WebExpress.WebCore/WebAttribute/SegmentRegexAttribute.cs @@ -20,19 +20,19 @@ public class SegmentRegexAttribute : Attribute, IEndpointAttribute, private string Expression { get; set; } /// - /// Returns or sets the display string. + /// Returns or sets the tag. /// - private string Display { get; set; } + private string Tag { get; set; } /// /// Initializes a new instance of the class. /// /// The regular expression. - /// The display string. - public SegmentRegexAttribute(string expression, string display = null) + /// The tag. + public SegmentRegexAttribute(string expression, string tag = null) { Expression = expression; - Display = display; + Tag = tag; } /// @@ -41,7 +41,7 @@ public SegmentRegexAttribute(string expression, string display = null) /// The path segment. public IUriPathSegment ToPathSegment() { - return new UriPathSegmentVariableRegex(Expression, Display); + return new UriPathSegmentVariableRegex(Expression, Tag); } } } diff --git a/src/WebExpress.WebCore/WebAttribute/SegmentStringAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SegmentStringAttribute.cs index ad98978..b52850f 100644 --- a/src/WebExpress.WebCore/WebAttribute/SegmentStringAttribute.cs +++ b/src/WebExpress.WebCore/WebAttribute/SegmentStringAttribute.cs @@ -15,17 +15,17 @@ public class SegmentStringAttribute : Attribute, IEndpointAttribute, where TParameter : IParameterStatic, new() { /// - /// Returns or sets the display string. + /// Returns or sets the tag. /// - private string Display { get; set; } + private string Tag { get; set; } /// /// Initializes a new instance of the class. /// - /// The display string. - public SegmentStringAttribute(string display = null) + /// The tag. + public SegmentStringAttribute(string tag = null) { - Display = display; + Tag = tag; } /// @@ -34,7 +34,7 @@ public SegmentStringAttribute(string display = null) /// The path segment. public IUriPathSegment ToPathSegment() { - return new UriPathSegmentVariableString(Display); + return new UriPathSegmentVariableString(Tag); } } } diff --git a/src/WebExpress.WebCore/WebAttribute/SegmentUIntAttribute.cs b/src/WebExpress.WebCore/WebAttribute/SegmentUIntAttribute.cs index fe2fb27..1d1d8ba 100644 --- a/src/WebExpress.WebCore/WebAttribute/SegmentUIntAttribute.cs +++ b/src/WebExpress.WebCore/WebAttribute/SegmentUIntAttribute.cs @@ -18,17 +18,17 @@ public class SegmentUIntAttribute : Attribute, IEndpointAttribute, I where TParameter : IParameterStatic, new() { /// - /// Returns or sets the display string. + /// Returns or sets the tag. /// - private string Display { get; set; } + private string Tag { get; set; } /// /// Initializes a new instance of the class. /// - /// The display string. - public SegmentUIntAttribute(string display = null) + /// The tag. + public SegmentUIntAttribute(string tag = null) { - Display = display; + Tag = tag; } /// @@ -37,7 +37,7 @@ public SegmentUIntAttribute(string display = null) /// The path segment. public IUriPathSegment ToPathSegment() { - return new UriPathSegmentVariableUInt(Display); + return new UriPathSegmentVariableUInt(Tag); } } } diff --git a/src/WebExpress.WebCore/WebMessage/RequestHeaderFields.cs b/src/WebExpress.WebCore/WebMessage/RequestHeaderFields.cs index 26bb453..d5a0cad 100644 --- a/src/WebExpress.WebCore/WebMessage/RequestHeaderFields.cs +++ b/src/WebExpress.WebCore/WebMessage/RequestHeaderFields.cs @@ -124,11 +124,14 @@ internal RequestHeaderFields(IFeatureCollection contextFeatures) SecWebSocketVersion = requestFeature.Headers.SecWebSocketVersion; Cookies = requestFeature.Headers.Cookie + .SelectMany(c => c.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)) .Select(c => { - var split = c.Split('='); - return new Cookie(split[0], split[1]); - }); + var eqIndex = c.IndexOf('='); + if (eqIndex < 0) { return null; } + return new Cookie(c[..eqIndex].Trim(), c[(eqIndex + 1)..].Trim()); + }) + .Where(c => c != null); Authorization = RequestAuthorization.Parse(requestFeature.Headers.Authorization); } diff --git a/src/WebExpress.WebCore/WebMessage/ResponseHeaderFields.cs b/src/WebExpress.WebCore/WebMessage/ResponseHeaderFields.cs index 642d06d..b1de805 100644 --- a/src/WebExpress.WebCore/WebMessage/ResponseHeaderFields.cs +++ b/src/WebExpress.WebCore/WebMessage/ResponseHeaderFields.cs @@ -142,6 +142,11 @@ public override string ToString() sb.AppendLine("Connection: Upgrade"); } + if (!string.IsNullOrWhiteSpace(SecWebSocketAccept)) + { + sb.AppendLine("Sec-WebSocket-Accept: " + SecWebSocketAccept); + } + foreach (var c in CustomHeader) { sb.AppendLine(c.Key + ": " + c.Value); diff --git a/src/WebExpress.WebCore/WebSocket/ISockt.cs b/src/WebExpress.WebCore/WebSocket/ISocket.cs similarity index 74% rename from src/WebExpress.WebCore/WebSocket/ISockt.cs rename to src/WebExpress.WebCore/WebSocket/ISocket.cs index 532c651..3d208a2 100644 --- a/src/WebExpress.WebCore/WebSocket/ISockt.cs +++ b/src/WebExpress.WebCore/WebSocket/ISocket.cs @@ -11,8 +11,6 @@ public interface ISocket : IEndpoint, IDisposable { /// /// Invoked after the websocket handshake has been accepted. - /// Implementers may use the optional cancellation token to abort long-running startup tasks. - /// the optional connectMessage provides initial metadata from the client (may be null). /// /// The socket connection. /// An asynchronous task. diff --git a/src/WebExpress.WebCore/WebSocket/ISocketContext.cs b/src/WebExpress.WebCore/WebSocket/ISocketContext.cs index 2616e19..7042eb0 100644 --- a/src/WebExpress.WebCore/WebSocket/ISocketContext.cs +++ b/src/WebExpress.WebCore/WebSocket/ISocketContext.cs @@ -25,7 +25,7 @@ public interface ISocketContext : IEndpointContext /// Returns the maximum allowed message size in bytes, or null when the endpoint imposes no limit. /// servers and hosts may use this to protect against excessively large frames. /// - ulong MaxMessageSize { get; } + ulong? MaxMessageSize { get; } /// /// Indicates whether this websocket endpoint requires an authenticated client. diff --git a/src/WebExpress.WebCore/WebSocket/Model/SocketItem.cs b/src/WebExpress.WebCore/WebSocket/Model/SocketItem.cs index 9e0d95c..85f5142 100644 --- a/src/WebExpress.WebCore/WebSocket/Model/SocketItem.cs +++ b/src/WebExpress.WebCore/WebSocket/Model/SocketItem.cs @@ -50,7 +50,7 @@ internal class SocketItem : IDisposable /// Returns the maximum allowed message size in bytes, or null when the endpoint imposes no limit. /// servers and hosts may use this to protect against excessively large frames. /// - public ulong MaxMessageSize { get; set; } + public ulong? MaxMessageSize { get; set; } /// /// Returns the conditions that must be met for the resource to be active. diff --git a/src/WebExpress.WebCore/WebSocket/SocketContext.cs b/src/WebExpress.WebCore/WebSocket/SocketContext.cs index 5ea54f0..5fa2031 100644 --- a/src/WebExpress.WebCore/WebSocket/SocketContext.cs +++ b/src/WebExpress.WebCore/WebSocket/SocketContext.cs @@ -50,7 +50,7 @@ public class SocketContext : ISocketContext /// /// Maximum allowed message size in bytes, or null when no limit is imposed. /// - public ulong MaxMessageSize { get; set; } + public ulong? MaxMessageSize { get; set; } /// /// Indicates whether this websocket endpoint requires an authenticated client. diff --git a/src/WebExpress.WebCore/WebSocket/SocketManager.cs b/src/WebExpress.WebCore/WebSocket/SocketManager.cs index 9232cc2..72f663d 100644 --- a/src/WebExpress.WebCore/WebSocket/SocketManager.cs +++ b/src/WebExpress.WebCore/WebSocket/SocketManager.cs @@ -308,7 +308,7 @@ private void Register(IPluginContext pluginContext, IEnumerable !x.AttributeType.GetInterfaces().Contains(typeof(IEndpointAttribute))); @@ -376,7 +376,7 @@ var attribute in socketType // MAX MESSAGE SIZE if (attributeType == typeof(MaxMessageSizeAttribute)) { - maxMessageSize = (attribute as MaxMessageSizeAttribute)?.MaxMessageSize ?? 0; + maxMessageSize = (attribute as MaxMessageSizeAttribute)?.MaxMessageSize; continue; } } diff --git a/src/WebExpress.WebCore/WebTask/TaskManager.cs b/src/WebExpress.WebCore/WebTask/TaskManager.cs index 0859cd7..5543401 100644 --- a/src/WebExpress.WebCore/WebTask/TaskManager.cs +++ b/src/WebExpress.WebCore/WebTask/TaskManager.cs @@ -78,7 +78,7 @@ public ITask CreateTask(string id, params object[] args) { var key = id?.ToLower(); - if (_dictionary.TryGetValue(id, out var value)) + if (_dictionary.TryGetValue(key, out var value)) { return value; } @@ -118,7 +118,7 @@ public ITask CreateTask(string id, EventHandler handler, p { var key = id?.ToLower(); - if (_dictionary.TryGetValue(id, out var value)) + if (_dictionary.TryGetValue(key, out var value)) { return value; } @@ -141,7 +141,12 @@ public ITask CreateTask(string id, EventHandler handler, p /// The task. public void RemoveTask(ITask task) { - var key = task?.Id.ToLower(); + if (task?.Id is null) + { + return; + } + + var key = task.Id.ToLower(); if (_dictionary.TryGetValue(key, out var storedTask) && storedTask is Task t) { diff --git a/src/WebExpress.WebCore/WebUri/IUriPathSegment.cs b/src/WebExpress.WebCore/WebUri/IUriPathSegment.cs index a876c35..4877693 100644 --- a/src/WebExpress.WebCore/WebUri/IUriPathSegment.cs +++ b/src/WebExpress.WebCore/WebUri/IUriPathSegment.cs @@ -8,7 +8,7 @@ public interface IUriPathSegment /// /// Returns or sets the id. /// - internal string Id { get; } + string Id { get; } /// /// Returns the value. @@ -32,12 +32,12 @@ public interface IUriPathSegment /// This property can be used to determine if the item should be displayed in user /// interfaces or lists. /// - bool IsHidden { get; internal set; } + bool IsHidden { get; set; } /// /// Returns the URI to which the user is redirected. /// - IUri Uri { get; internal set; } + IUri Uri { get; set; } /// /// Checks whether the node matches the path element. diff --git a/src/WebExpress.WebCore/WebUri/UriQuery.cs b/src/WebExpress.WebCore/WebUri/UriQuery.cs index ebf5b07..21e3bb2 100644 --- a/src/WebExpress.WebCore/WebUri/UriQuery.cs +++ b/src/WebExpress.WebCore/WebUri/UriQuery.cs @@ -41,12 +41,12 @@ public override string ToString() /// /// Represents a key-value pair used as a query parameter in a URI. /// - /// + /// /// The type that implements the IParameterStatic interface and defines the structure /// of the query parameter. /// - public class UriQuery : IUriQuery - where TParamerer : IParameterStatic + public class UriQuery : IUriQuery + where TParameter : IParameterStatic { /// /// Returns the key. @@ -64,7 +64,7 @@ public class UriQuery : IUriQuery /// The value. public UriQuery(string value = null) { - Key = TParamerer.Key; + Key = TParameter.Key; Value = value; }