This commit is contained in:
Jeroen 2023-11-18 12:19:53 +01:00
parent 08a2be3221
commit 2dca7a7f4f
73 changed files with 851 additions and 799 deletions

View File

@ -66,8 +66,7 @@ internal class Program
StartServer(serverUri, certificatePath, certificatePassword, requiredPassword); StartServer(serverUri, certificatePath, certificatePassword, requiredPassword);
// Start the client in the main thread // Start the client in the main thread
_client = new WSClient(clientUri); _client = new WSClient(clientUri, new X509Certificate(certificatePath, certificatePassword));
_client.SSL.Certificates.Add(new X509Certificate(certificatePath, certificatePassword));
_client.OnConnect += (sender, e) => Console.WriteLine($"Connected to server"); _client.OnConnect += (sender, e) => Console.WriteLine($"Connected to server");
_client.OnMessageReceived += (sender, e) => Console.WriteLine($"Received message from server: {e.Data}"); _client.OnMessageReceived += (sender, e) => Console.WriteLine($"Received message from server: {e.Data}");
_client.OnDisconnect += (sender, e) => Console.WriteLine($"Disconnected from server: {e.Code} : {e.Reason}"); _client.OnDisconnect += (sender, e) => Console.WriteLine($"Disconnected from server: {e.Code} : {e.Reason}");

View File

@ -1,11 +1,7 @@
using System; namespace EonaCat.Network
using System.Collections.Generic;
using System.Text;
namespace EonaCat.Network
{ {
internal class Constants internal class Constants
{ {
public static string Version { get; set; } = "1.1.2"; public static string Version { get; set; } = "1.1.4";
} }
} }

View File

@ -16,9 +16,9 @@
<PackageTags>EonaCat, Network, .NET Standard, EonaCatHelpers, Jeroen, Saey, Protocol, Quic, UDP, TCP, Web, Server</PackageTags> <PackageTags>EonaCat, Network, .NET Standard, EonaCatHelpers, Jeroen, Saey, Protocol, Quic, UDP, TCP, Web, Server</PackageTags>
<PackageReleaseNotes></PackageReleaseNotes> <PackageReleaseNotes></PackageReleaseNotes>
<Description>EonaCat Networking library with Quic, TCP, UDP, WebSockets and a Webserver</Description> <Description>EonaCat Networking library with Quic, TCP, UDP, WebSockets and a Webserver</Description>
<Version>1.1.3</Version> <Version>1.1.4</Version>
<AssemblyVersion>1.1.3</AssemblyVersion> <AssemblyVersion>1.1.4</AssemblyVersion>
<FileVersion>1.1.3</FileVersion> <FileVersion>1.1.4</FileVersion>
<PackageIcon>icon.png</PackageIcon> <PackageIcon>icon.png</PackageIcon>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,6 @@
using EonaCat.Quic.Infrastructure; using EonaCat.Quic.Infrastructure;
using EonaCat.Quic.Infrastructure.Settings; using EonaCat.Quic.Infrastructure.Settings;
using EonaCat.Quic.InternalInfrastructure; using EonaCat.Quic.InternalInfrastructure;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace EonaCat.Quic.Connections namespace EonaCat.Quic.Connections

View File

@ -9,7 +9,6 @@ using EonaCat.Quic.Infrastructure.Packets;
using EonaCat.Quic.Infrastructure.Settings; using EonaCat.Quic.Infrastructure.Settings;
using EonaCat.Quic.InternalInfrastructure; using EonaCat.Quic.InternalInfrastructure;
using EonaCat.Quic.Streams; using EonaCat.Quic.Streams;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace EonaCat.Quic.Connections namespace EonaCat.Quic.Connections

View File

@ -1,5 +1,4 @@
using EonaCat.Quic.Streams; using EonaCat.Quic.Streams;
using System;
namespace EonaCat.Quic.Context namespace EonaCat.Quic.Context
{ {

View File

@ -1,6 +1,4 @@
using System; namespace EonaCat.Quic.Helpers
namespace EonaCat.Quic.Helpers
{ {
// This file is part of the EonaCat project(s) which is released under the Apache License. // This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details. // See the LICENSE file or go to https://EonaCat.com/License for full license details.

View File

@ -1,6 +1,4 @@
using System; namespace EonaCat.Quic.Infrastructure
namespace EonaCat.Quic.Infrastructure
{ {
// This file is part of the EonaCat project(s) which is released under the Apache License. // This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details. // See the LICENSE file or go to https://EonaCat.com/License for full license details.

View File

@ -1,5 +1,4 @@
using EonaCat.Quic.Helpers; using EonaCat.Quic.Helpers;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace EonaCat.Quic.Infrastructure.Frames namespace EonaCat.Quic.Infrastructure.Frames

View File

@ -1,5 +1,4 @@
using EonaCat.Quic.Helpers; using EonaCat.Quic.Helpers;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace EonaCat.Quic.Infrastructure.Frames namespace EonaCat.Quic.Infrastructure.Frames

View File

@ -1,5 +1,4 @@
using EonaCat.Quic.Helpers; using EonaCat.Quic.Helpers;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace EonaCat.Quic.Infrastructure.Frames namespace EonaCat.Quic.Infrastructure.Frames

View File

@ -1,5 +1,4 @@
using EonaCat.Quic.Helpers; using EonaCat.Quic.Helpers;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace EonaCat.Quic.Infrastructure.Frames namespace EonaCat.Quic.Infrastructure.Frames

View File

@ -1,5 +1,4 @@
using EonaCat.Quic.Helpers; using EonaCat.Quic.Helpers;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace EonaCat.Quic.Infrastructure.Frames namespace EonaCat.Quic.Infrastructure.Frames

View File

@ -1,5 +1,4 @@
using EonaCat.Quic.Helpers; using EonaCat.Quic.Helpers;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace EonaCat.Quic.Infrastructure.Frames namespace EonaCat.Quic.Infrastructure.Frames

View File

@ -1,6 +1,4 @@
using System; namespace EonaCat.Quic.Infrastructure
namespace EonaCat.Quic.Infrastructure
{ {
// This file is part of the EonaCat project(s) which is released under the Apache License. // This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details. // See the LICENSE file or go to https://EonaCat.com/License for full license details.

View File

@ -1,7 +1,6 @@
using EonaCat.Quic.Helpers; using EonaCat.Quic.Helpers;
using EonaCat.Quic.Infrastructure.Frames; using EonaCat.Quic.Infrastructure.Frames;
using EonaCat.Quic.Infrastructure.Packets; using EonaCat.Quic.Infrastructure.Packets;
using System;
namespace EonaCat.Quic.Infrastructure.PacketProcessing namespace EonaCat.Quic.Infrastructure.PacketProcessing
{ {

View File

@ -1,6 +1,4 @@
using System; namespace EonaCat.Quic.Infrastructure
namespace EonaCat.Quic.Infrastructure
{ {
// This file is part of the EonaCat project(s) which is released under the Apache License. // This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details. // See the LICENSE file or go to https://EonaCat.com/License for full license details.

View File

@ -1,5 +1,4 @@
using EonaCat.Quic.Helpers; using EonaCat.Quic.Helpers;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace EonaCat.Quic.Infrastructure.Packets namespace EonaCat.Quic.Infrastructure.Packets

View File

@ -2,7 +2,6 @@
using EonaCat.Quic.Infrastructure.Exceptions; using EonaCat.Quic.Infrastructure.Exceptions;
using EonaCat.Quic.Infrastructure.Frames; using EonaCat.Quic.Infrastructure.Frames;
using EonaCat.Quic.Infrastructure.Settings; using EonaCat.Quic.Infrastructure.Settings;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace EonaCat.Quic.Infrastructure.Packets namespace EonaCat.Quic.Infrastructure.Packets

View File

@ -1,5 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
namespace EonaCat.Quic.Infrastructure.Settings namespace EonaCat.Quic.Infrastructure.Settings
{ {

View File

@ -5,6 +5,51 @@ namespace EonaCat.Network
{ {
public enum CloseStatusCode : ushort public enum CloseStatusCode : ushort
{ {
//1000: Normal Closure
//Indicates a normal closure, meaning that the purpose for which the connection was established has been fulfilled.
//1001: Going Away
//The endpoint is going away, such as a server going down or a browser tab is closing.
//1002: Protocol Error
//Indicates that the endpoint is terminating the connection due to a protocol error.
//1003: Unsupported Data
//Indicates that the endpoint is terminating the connection because it received data that it cannot process.
//1005: No Status Received
//Reserved. It indicates that no status code was received.
//1006: Abnormal Closure
//Reserved. It is a reserved value and should not be set as a status code in a Close control frame by an endpoint.
//1007: Invalid frame payload data
//Indicates that an endpoint is terminating the connection because it has received data within a message that was not consistent with the type of the message.
//1008: Policy Violation
//Indicates that an endpoint is terminating the connection because it has received a message that violates its policy.
//1009: Message Too Big
//Indicates that an endpoint is terminating the connection because it has received a message that is too big for it to process.
//1010: Missing Extension
//Indicates that an endpoint is terminating the connection because it has received a message that requires negotiation of an extension, and the client did not offer that extension.
//1011: Internal Error
//Indicates that a server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request.
//1012: Service Restart
//Reserved. It indicates that the service is restarting.
//1013: Try Again Later
//Reserved. It indicates that the server is temporarily unable to process the request.
//1014: Bad Gateway
//Reserved. It indicates that an intermediate server failed to fulfill a request.
//1015: TLS Handshake Failure
//Reserved. It indicates that the connection was closed due to a failure to perform a TLS handshake.
Normal = 1000, Normal = 1000,
Away = 1001, Away = 1001,
@ -25,10 +70,16 @@ namespace EonaCat.Network
TooBig = 1009, TooBig = 1009,
MandatoryExtension = 1010, MissingExtension = 1010,
ServerError = 1011, ServerError = 1011,
ServiceRestart = 1012,
TryAgainLater = 1013,
BadGateway = 1014,
TlsHandshakeFailure = 1015 TlsHandshakeFailure = 1015
} }
} }

View File

@ -41,6 +41,7 @@ namespace EonaCat.Network
: base(scheme, parameters) : base(scheme, parameters)
{ {
} }
/// <summary> /// <summary>
/// Gets the domain for Digest authentication. /// Gets the domain for Digest authentication.
/// </summary> /// </summary>
@ -104,49 +105,32 @@ namespace EonaCat.Network
return string.Format($"Basic realm=\"{{0}}\"", Parameters["realm"]); return string.Format($"Basic realm=\"{{0}}\"", Parameters["realm"]);
} }
/// <summary>
/// Gets the Digest authentication string representation of the authentication challenge.
/// </summary>
/// <returns>A string representing the Digest authentication challenge.</returns>
internal override string ToDigestString() internal override string ToDigestString()
{ {
var output = new StringBuilder(DIGEST_SIZE); var output = new StringBuilder(DIGEST_SIZE);
var realm = Parameters["realm"];
var nonce = Parameters["nonce"];
var domain = Parameters["domain"]; if (realm != null)
if (domain != null)
{ {
output.AppendFormat($"Digest realm=\"{Parameters["realm"]}\", domain=\"{domain}\", nonce=\"{Parameters["nonce"]}\""); output.AppendFormat("Digest realm=\"{0}\", nonce=\"{1}\"", realm, nonce);
}
else
{
output.AppendFormat($"Digest realm=\"{Parameters["realm"]}\", nonce=\"{Parameters["nonce"]}\"");
}
var opaque = Parameters["opaque"]; AppendIfNotNull(output, "domain", Parameters["domain"]);
if (opaque != null) AppendIfNotNull(output, "opaque", Parameters["opaque"]);
{ AppendIfNotNull(output, "stale", Parameters["stale"]);
output.AppendFormat($", opaque=\"{opaque}\""); AppendIfNotNull(output, "algorithm", Parameters["algorithm"]);
} AppendIfNotNull(output, "qop", Parameters["qop"]);
var stale = Parameters["stale"];
if (stale != null)
{
output.AppendFormat($", stale={stale}");
}
var algorithm = Parameters["algorithm"];
if (algorithm != null)
{
output.AppendFormat($", algorithm={algorithm}");
}
var qop = Parameters["qop"];
if (qop != null)
{
output.AppendFormat($", qop=\"{qop}\"");
} }
return output.ToString(); return output.ToString();
} }
private static void AppendIfNotNull(StringBuilder output, string key, string value)
{
if (value != null)
{
output.AppendFormat(", {0}=\"{1}\"", key, value);
}
}
} }
} }

View File

@ -72,6 +72,7 @@ namespace EonaCat.Network
: base(scheme, parameters) : base(scheme, parameters)
{ {
} }
/// <summary> /// <summary>
/// Gets the cnonce value for Digest authentication. /// Gets the cnonce value for Digest authentication.
/// </summary> /// </summary>
@ -108,6 +109,7 @@ namespace EonaCat.Network
internal uint NonceCount => _nonceCount < uint.MaxValue internal uint NonceCount => _nonceCount < uint.MaxValue
? _nonceCount ? _nonceCount
: 0; : 0;
/// <summary> /// <summary>
/// Converts the authentication response to an identity. /// Converts the authentication response to an identity.
/// </summary> /// </summary>

View File

@ -63,6 +63,7 @@ namespace EonaCat.Network
/// Gets the web headers associated with the chunk stream. /// Gets the web headers associated with the chunk stream.
/// </summary> /// </summary>
internal WebHeaderCollection Headers { get; } internal WebHeaderCollection Headers { get; }
/// <summary> /// <summary>
/// Reads a specified amount of data from the chunk stream. /// Reads a specified amount of data from the chunk stream.
/// </summary> /// </summary>
@ -159,6 +160,7 @@ namespace EonaCat.Network
return nread; return nread;
} }
private InputChunkState SeekCrLf(byte[] buffer, ref int offset, int length) private InputChunkState SeekCrLf(byte[] buffer, ref int offset, int length)
{ {
if (!_gotChunck) if (!_gotChunck)
@ -316,6 +318,7 @@ namespace EonaCat.Network
return InputChunkState.End; return InputChunkState.End;
} }
private void Write(byte[] buffer, ref int offset, int length) private void Write(byte[] buffer, ref int offset, int length)
{ {
if (_state == InputChunkState.End) if (_state == InputChunkState.End)

View File

@ -19,6 +19,7 @@ namespace EonaCat.Network
[ComVisible(true)] [ComVisible(true)]
public class WebHeaderCollection : NameValueCollection, ISerializable public class WebHeaderCollection : NameValueCollection, ISerializable
{ {
private const int BUFFER_SIZE = 65535;
private static readonly Dictionary<string, HttpHeaderInfo> _headers; private static readonly Dictionary<string, HttpHeaderInfo> _headers;
private readonly bool _internallyUsed; private readonly bool _internallyUsed;
private HttpHeaderType _state; private HttpHeaderType _state;
@ -136,10 +137,12 @@ namespace EonaCat.Network
throw new ArgumentException(ex.Message, nameof(serializationInfo), ex); throw new ArgumentException(ex.Message, nameof(serializationInfo), ex);
} }
} }
public override string[] AllKeys => base.AllKeys; public override string[] AllKeys => base.AllKeys;
public override int Count => base.Count; public override int Count => base.Count;
public override KeysCollection Keys => base.Keys; public override KeysCollection Keys => base.Keys;
internal HttpHeaderType State => _state; internal HttpHeaderType State => _state;
public string this[HttpRequestHeader header] public string this[HttpRequestHeader header]
{ {
get get
@ -165,6 +168,7 @@ namespace EonaCat.Network
Add(header, value); Add(header, value);
} }
} }
public static bool IsRestricted(string headerName) public static bool IsRestricted(string headerName)
{ {
return isRestricted(CheckName(headerName), false); return isRestricted(CheckName(headerName), false);
@ -462,7 +466,7 @@ namespace EonaCat.Network
} }
value = value.Trim(); value = value.Trim();
if (value.Length > 65535) if (value.Length > BUFFER_SIZE)
{ {
throw new ArgumentOutOfRangeException(nameof(value), "Greater than 65,535 characters."); throw new ArgumentOutOfRangeException(nameof(value), "Greater than 65,535 characters.");
} }
@ -517,6 +521,7 @@ namespace EonaCat.Network
{ {
base.Add(name, CheckValue(value)); base.Add(name, CheckValue(value));
} }
private void CheckRestricted(string name) private void CheckRestricted(string name)
{ {
if (!_internallyUsed && isRestricted(name, true)) if (!_internallyUsed && isRestricted(name, true))
@ -544,6 +549,7 @@ namespace EonaCat.Network
"This collection has already been used to store the response headers."); "This collection has already been used to store the response headers.");
} }
} }
private void DoWithCheckingState( private void DoWithCheckingState(
Action<string, string> action, string name, string value, bool setState) Action<string, string> action, string name, string value, bool setState)
{ {
@ -578,6 +584,7 @@ namespace EonaCat.Network
CheckRestricted(name); CheckRestricted(name);
action(name, CheckValue(value)); action(name, CheckValue(value));
} }
private void removeWithoutCheckingName(string name, string unuse) private void removeWithoutCheckingName(string name, string unuse)
{ {
CheckRestricted(name); CheckRestricted(name);

View File

@ -84,6 +84,7 @@ namespace EonaCat.Network
/// Gets the stream of the underlying TCP connection. /// Gets the stream of the underlying TCP connection.
/// </summary> /// </summary>
internal Stream Stream => _context.Connection.Stream; internal Stream Stream => _context.Connection.Stream;
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {

View File

@ -29,6 +29,7 @@ namespace EonaCat.Network
private NameValueCollection _queryString; private NameValueCollection _queryString;
private WebRequest _request; private WebRequest _request;
private IPrincipal _user; private IPrincipal _user;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="TcpListenerWSContext"/> class. /// Initializes a new instance of the <see cref="TcpListenerWSContext"/> class.
/// </summary> /// </summary>
@ -130,6 +131,7 @@ namespace EonaCat.Network
/// Gets the stream of the underlying TCP connection. /// Gets the stream of the underlying TCP connection.
/// </summary> /// </summary>
internal Stream Stream { get; } internal Stream Stream { get; }
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {

View File

@ -332,6 +332,7 @@ namespace EonaCat.Network
} }
internal int[] Ports => _ports; internal int[] Ports => _ports;
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object comparand) public override bool Equals(object comparand)
{ {
@ -414,7 +415,7 @@ namespace EonaCat.Network
internal string ToResponseString() internal string ToResponseString()
{ {
return _name.Length > 0 return _name.Length > 0
? (_version == 0 ? toResponseStringVersion0() : toResponseStringVersion1()) ? (_version == 0 ? ToResponseStringVersion0() : ToResponseStringVersion1())
: string.Empty; : string.Empty;
} }
@ -493,7 +494,7 @@ namespace EonaCat.Network
return true; return true;
} }
private string toResponseStringVersion0() private string ToResponseStringVersion0()
{ {
var output = new StringBuilder(64); var output = new StringBuilder(64);
output.AppendFormat("{0}={1}", _name, _value); output.AppendFormat("{0}={1}", _name, _value);
@ -530,7 +531,7 @@ namespace EonaCat.Network
return output.ToString(); return output.ToString();
} }
private string toResponseStringVersion1() private string ToResponseStringVersion1()
{ {
var output = new StringBuilder(64); var output = new StringBuilder(64);
output.AppendFormat("{0}={1}; Version={2}", _name, _value, _version); output.AppendFormat("{0}={1}; Version={2}", _name, _value, _version);

View File

@ -16,7 +16,7 @@ namespace EonaCat.Network
public class CookieCollection : ICollection, IEnumerable public class CookieCollection : ICollection, IEnumerable
{ {
private readonly List<Cookie> _list; private readonly List<Cookie> _list;
private object _sync; private object _locker;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CookieCollection"/> class. /// Initializes a new instance of the <see cref="CookieCollection"/> class.
@ -26,7 +26,6 @@ namespace EonaCat.Network
_list = new List<Cookie>(); _list = new List<Cookie>();
} }
/// <summary> /// <summary>
/// Gets the number of cookies in the collection. /// Gets the number of cookies in the collection.
/// </summary> /// </summary>
@ -45,7 +44,7 @@ namespace EonaCat.Network
/// <summary> /// <summary>
/// Gets an object that can be used to synchronize access to the collection. /// Gets an object that can be used to synchronize access to the collection.
/// </summary> /// </summary>
public object SyncRoot => _sync ??= ((ICollection)_list).SyncRoot; public object SyncRoot => _locker ??= ((ICollection)_list).SyncRoot;
internal IList<Cookie> List => _list; internal IList<Cookie> List => _list;
@ -62,6 +61,7 @@ namespace EonaCat.Network
return list; return list;
} }
} }
/// <summary> /// <summary>
/// Gets or sets the cookie at the specified index. /// Gets or sets the cookie at the specified index.
/// </summary> /// </summary>
@ -105,6 +105,7 @@ namespace EonaCat.Network
return null; return null;
} }
} }
/// <summary> /// <summary>
/// Adds the specified cookie to the collection, updating it if it already exists. /// Adds the specified cookie to the collection, updating it if it already exists.
/// </summary> /// </summary>

View File

@ -49,6 +49,7 @@ namespace EonaCat.Network
: base(serializationInfo, streamingContext) : base(serializationInfo, streamingContext)
{ {
} }
/// <summary> /// <summary>
/// Populates a <see cref="SerializationInfo"/> with the data needed to serialize the exception. /// Populates a <see cref="SerializationInfo"/> with the data needed to serialize the exception.
/// </summary> /// </summary>

View File

@ -26,6 +26,7 @@ namespace EonaCat.Network
private List<HttpListenerPrefix> _all; // host == '+' private List<HttpListenerPrefix> _all; // host == '+'
private Dictionary<HttpListenerPrefix, HttpListener> _prefixes; private Dictionary<HttpListenerPrefix, HttpListener> _prefixes;
private List<HttpListenerPrefix> _unhandled; // host == '*' private List<HttpListenerPrefix> _unhandled; // host == '*'
static EndPointListener() static EndPointListener()
{ {
_defaultCertFolderPath = _defaultCertFolderPath =

View File

@ -618,6 +618,7 @@ namespace EonaCat.Network
_position = 0; _position = 0;
_requestBuffer = new MemoryStream(); _requestBuffer = new MemoryStream();
} }
private void UnregisterContext() private void UnregisterContext()
{ {
if (!_contextRegistered) if (!_contextRegistered)

View File

@ -48,6 +48,7 @@ namespace EonaCat.Network
/// Gets a value indicating whether the header is multi-value in a response. /// Gets a value indicating whether the header is multi-value in a response.
/// </summary> /// </summary>
internal bool IsMultiValueInResponse => (Type & HttpHeaderType.MultiValueInResponse) == HttpHeaderType.MultiValueInResponse; internal bool IsMultiValueInResponse => (Type & HttpHeaderType.MultiValueInResponse) == HttpHeaderType.MultiValueInResponse;
/// <summary> /// <summary>
/// Gets a value indicating whether the header is multi-value. /// Gets a value indicating whether the header is multi-value.
/// </summary> /// </summary>

View File

@ -32,6 +32,7 @@ namespace EonaCat.Network
private string _realm; private string _realm;
private SSLConfigServer _sslConfig; private SSLConfigServer _sslConfig;
private Func<IIdentity, NetworkCredential> _userCredFinder; private Func<IIdentity, NetworkCredential> _userCredFinder;
static HttpListener() static HttpListener()
{ {
_defaultRealm = "SECRET AREA"; _defaultRealm = "SECRET AREA";
@ -60,6 +61,7 @@ namespace EonaCat.Network
} }
public static bool IsSupported => true; public static bool IsSupported => true;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the server accepts every /// Gets or sets a value indicating whether the server accepts every
/// handshake request without checking the request URI. /// handshake request without checking the request URI.
@ -147,6 +149,7 @@ namespace EonaCat.Network
} }
public bool IsListening => _listening; public bool IsListening => _listening;
public HttpListenerPrefixCollection Prefixes public HttpListenerPrefixCollection Prefixes
{ {
get get
@ -217,6 +220,7 @@ namespace EonaCat.Network
internal bool IsDisposed { get; private set; } internal bool IsDisposed { get; private set; }
internal bool ReuseAddress { get; set; } internal bool ReuseAddress { get; set; }
/// <summary> /// <summary>
/// Aborts the listener and releases all resources associated with it. /// Aborts the listener and releases all resources associated with it.
/// </summary> /// </summary>
@ -400,14 +404,14 @@ namespace EonaCat.Network
throw new HttpListenerException(995); throw new HttpListenerException(995);
} }
var ctx = GetContextFromQueue(); var context = GetContextFromQueue();
if (ctx == null) if (context == null)
{ {
_waitQueue.Add(asyncResult); _waitQueue.Add(asyncResult);
} }
else else
{ {
asyncResult.Complete(ctx, true); asyncResult.Complete(context, true);
} }
return asyncResult; return asyncResult;
@ -630,10 +634,10 @@ namespace EonaCat.Network
return null; return null;
} }
var ctx = contextQueue[0]; var context = contextQueue[0];
contextQueue.RemoveAt(0); contextQueue.RemoveAt(0);
return ctx; return context;
} }
} }
} }

View File

@ -12,7 +12,7 @@ namespace EonaCat.Network
internal class HttpListenerAsyncResult : IAsyncResult internal class HttpListenerAsyncResult : IAsyncResult
{ {
private readonly AsyncCallback _callback; private readonly AsyncCallback _callback;
private readonly object _sync; private readonly object _locker;
private bool _completed; private bool _completed;
private HttpListenerContext _context; private HttpListenerContext _context;
private Exception _exception; private Exception _exception;
@ -27,7 +27,7 @@ namespace EonaCat.Network
{ {
_callback = callback; _callback = callback;
AsyncState = state; AsyncState = state;
_sync = new object(); _locker = new object();
} }
/// <summary> /// <summary>
@ -42,7 +42,7 @@ namespace EonaCat.Network
{ {
get get
{ {
lock (_sync) lock (_locker)
{ {
return _waitHandle ??= new ManualResetEvent(_completed); return _waitHandle ??= new ManualResetEvent(_completed);
} }
@ -61,7 +61,7 @@ namespace EonaCat.Network
{ {
get get
{ {
lock (_sync) lock (_locker)
{ {
return _completed; return _completed;
} }
@ -77,6 +77,7 @@ namespace EonaCat.Network
/// Gets or sets a value indicating whether the asynchronous operation is in progress. /// Gets or sets a value indicating whether the asynchronous operation is in progress.
/// </summary> /// </summary>
internal bool InGet { get; set; } internal bool InGet { get; set; }
/// <summary> /// <summary>
/// Completes the asynchronous operation with the specified exception. /// Completes the asynchronous operation with the specified exception.
/// </summary> /// </summary>
@ -129,7 +130,7 @@ namespace EonaCat.Network
// Private method to complete the asynchronous operation // Private method to complete the asynchronous operation
private static void complete(HttpListenerAsyncResult asyncResult) private static void complete(HttpListenerAsyncResult asyncResult)
{ {
lock (asyncResult._sync) lock (asyncResult._locker)
{ {
asyncResult._completed = true; asyncResult._completed = true;

View File

@ -64,6 +64,7 @@ namespace EonaCat.Network
/// Gets or sets the <see cref="HttpListener"/> associated with the context. /// Gets or sets the <see cref="HttpListener"/> associated with the context.
/// </summary> /// </summary>
internal HttpListener Listener { get; set; } internal HttpListener Listener { get; set; }
/// <summary> /// <summary>
/// Accepts a WebSocket connection with the specified protocol. /// Accepts a WebSocket connection with the specified protocol.
/// </summary> /// </summary>

View File

@ -47,6 +47,7 @@ namespace EonaCat.Network
: base(serializationInfo, streamingContext) : base(serializationInfo, streamingContext)
{ {
} }
/// <summary> /// <summary>
/// Gets the Win32 error code associated with this exception. /// Gets the Win32 error code associated with this exception.
/// </summary> /// </summary>

View File

@ -294,7 +294,6 @@ namespace EonaCat.Network
} }
} }
internal bool CloseConnection { get; set; } internal bool CloseConnection { get; set; }
internal bool HeadersSent { get; set; } internal bool HeadersSent { get; set; }

View File

@ -9,7 +9,7 @@ namespace EonaCat.Network
internal class HttpStreamAsyncResult : IAsyncResult internal class HttpStreamAsyncResult : IAsyncResult
{ {
private readonly AsyncCallback _callback; private readonly AsyncCallback _callback;
private readonly object _sync; private readonly object _locker;
private bool _isCompleted; private bool _isCompleted;
private ManualResetEvent _waitHandle; private ManualResetEvent _waitHandle;
@ -17,15 +17,16 @@ namespace EonaCat.Network
{ {
_callback = callback; _callback = callback;
AsyncState = state; AsyncState = state;
_sync = new object(); _locker = new object();
} }
public object AsyncState { get; } public object AsyncState { get; }
public WaitHandle AsyncWaitHandle public WaitHandle AsyncWaitHandle
{ {
get get
{ {
lock (_sync) lock (_locker)
{ {
return _waitHandle ??= new ManualResetEvent(_isCompleted); return _waitHandle ??= new ManualResetEvent(_isCompleted);
} }
@ -33,11 +34,12 @@ namespace EonaCat.Network
} }
public bool CompletedSynchronously => SyncRead == Count; public bool CompletedSynchronously => SyncRead == Count;
public bool IsCompleted public bool IsCompleted
{ {
get get
{ {
lock (_sync) lock (_locker)
{ {
return _isCompleted; return _isCompleted;
} }
@ -55,9 +57,10 @@ namespace EonaCat.Network
internal int Offset { get; set; } internal int Offset { get; set; }
internal int SyncRead { get; set; } internal int SyncRead { get; set; }
internal void Complete() internal void Complete()
{ {
lock (_sync) lock (_locker)
{ {
if (_isCompleted) if (_isCompleted)
{ {

View File

@ -15,8 +15,9 @@ namespace EonaCat.Network
internal sealed class HttpUtility internal sealed class HttpUtility
{ {
private static readonly char[] _hexChars = "0123456789abcdef".ToCharArray(); private static readonly char[] _hexChars = "0123456789abcdef".ToCharArray();
private static readonly object _sync = new object(); private static readonly object _locker = new object();
private static Dictionary<string, char> _entities; private static Dictionary<string, char> _entities;
public static string HtmlAttributeEncode(string s) public static string HtmlAttributeEncode(string s)
{ {
if (s == null || s.Length == 0 || !s.Contains('&', '"', '<', '>')) if (s == null || s.Length == 0 || !s.Contains('&', '"', '<', '>'))
@ -1212,7 +1213,7 @@ namespace EonaCat.Network
private static Dictionary<string, char> getEntities() private static Dictionary<string, char> getEntities()
{ {
lock (_sync) lock (_locker)
{ {
if (_entities == null) if (_entities == null)
{ {
@ -1234,6 +1235,7 @@ namespace EonaCat.Network
? c - 'A' + 10 ? c - 'A' + 10
: -1; : -1;
} }
private static bool notEncoded(char c) private static bool notEncoded(char c)
{ {
return c == '!' || return c == '!' ||

View File

@ -5,7 +5,6 @@ using EonaCat.Logger.SplunkServer;
using EonaCat.Logger.Syslog; using EonaCat.Logger.Syslog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Numerics;
namespace EonaCat.Network namespace EonaCat.Network
{ {
@ -26,10 +25,11 @@ namespace EonaCat.Network
internal class Logger internal class Logger
{ {
private static readonly LogManager _logManager; private static readonly LogManager _logManager;
static Logger() static Logger()
{ {
_logManager = new LogManager(new LoggerSettings { RemoveMessagePrefix = true }); _logManager = new LogManager(new LoggerSettings());
_logManager.OnException += _logManager_OnException; _logManager.OnException += LogManager_OnException;
} }
internal static bool DisableConsole { get; set; } internal static bool DisableConsole { get; set; }
@ -37,6 +37,7 @@ namespace EonaCat.Network
internal static bool IsLoggingEnabled { get; set; } internal static bool IsLoggingEnabled { get; set; }
internal static string LoggingDirectory { get; private set; } internal static string LoggingDirectory { get; private set; }
private static bool HasBeenSetup { get; set; } private static bool HasBeenSetup { get; set; }
internal static void AddGrayLogServer(string hostname, int port) internal static void AddGrayLogServer(string hostname, int port)
{ {
_logManager.Settings.GrayLogServers.Add(new GrayLogServer(hostname, port)); _logManager.Settings.GrayLogServers.Add(new GrayLogServer(hostname, port));
@ -69,6 +70,16 @@ namespace EonaCat.Network
internal static void Error(Exception exception, string message = null, bool isCriticalException = false, bool? writeToConsole = null, bool? sendToSysLogServers = null, bool? sendToSplunkServers = null, string? customSplunkSourceType = null, bool? sendToGrayLogServers = null, GrayLogSettings grayLogSettings = null) internal static void Error(Exception exception, string message = null, bool isCriticalException = false, bool? writeToConsole = null, bool? sendToSysLogServers = null, bool? sendToSplunkServers = null, string? customSplunkSourceType = null, bool? sendToGrayLogServers = null, GrayLogSettings grayLogSettings = null)
{ {
if (!IsLoggingEnabled)
{
return;
}
if (DisableConsole)
{
writeToConsole = false;
}
if (!HasBeenSetup) if (!HasBeenSetup)
{ {
Setup(); Setup();
@ -86,6 +97,16 @@ namespace EonaCat.Network
internal static void Error(string message = null, bool? writeToConsole = null, bool? sendToSysLogServers = null, bool? sendToSplunkServers = null, string? customSplunkSourceType = null, bool? sendToGrayLogServers = null, string grayLogFacility = null, string grayLogSource = null, string grayLogVersion = "1.1", bool isCriticalException = false) internal static void Error(string message = null, bool? writeToConsole = null, bool? sendToSysLogServers = null, bool? sendToSplunkServers = null, string? customSplunkSourceType = null, bool? sendToGrayLogServers = null, string grayLogFacility = null, string grayLogSource = null, string grayLogVersion = "1.1", bool isCriticalException = false)
{ {
if (!IsLoggingEnabled)
{
return;
}
if (DisableConsole)
{
writeToConsole = false;
}
if (!HasBeenSetup) if (!HasBeenSetup)
{ {
Setup(); Setup();
@ -169,7 +190,7 @@ namespace EonaCat.Network
Write(message, ELogType.WARNING, writeToConsole, sendToSysLogServers, sendToSplunkServers, customSplunkSourceType, sendToGrayLogServers, grayLogSettings); Write(message, ELogType.WARNING, writeToConsole, sendToSysLogServers, sendToSplunkServers, customSplunkSourceType, sendToGrayLogServers, grayLogSettings);
} }
private static void _logManager_OnException(object? sender, ErrorMessage e) private static void LogManager_OnException(object? sender, ErrorMessage e)
{ {
Console.WriteLine(e.Message); Console.WriteLine(e.Message);
if (e.Exception != null) if (e.Exception != null)
@ -177,11 +198,12 @@ namespace EonaCat.Network
Console.WriteLine(e.Exception); Console.WriteLine(e.Exception);
} }
} }
private static void Write(string message, ELogType logType, bool? writeToConsole = null, bool? sendToSysLogServers = null, bool? sendToSplunkServers = null, string? customSplunkSourceType = null, bool? sendToGrayLogServers = null, GrayLogSettings grayLogSettings = null) private static void Write(string message, ELogType logType, bool? writeToConsole = null, bool? sendToSysLogServers = null, bool? sendToSplunkServers = null, string? customSplunkSourceType = null, bool? sendToGrayLogServers = null, GrayLogSettings grayLogSettings = null)
{ {
if (!HasBeenSetup) if (!IsLoggingEnabled)
{ {
Setup(); return;
} }
if (DisableConsole) if (DisableConsole)
@ -189,6 +211,11 @@ namespace EonaCat.Network
writeToConsole = false; writeToConsole = false;
} }
if (!HasBeenSetup)
{
Setup();
}
if (grayLogSettings != null) if (grayLogSettings != null)
{ {
_logManager.Write(message, logType, writeToConsole, sendToSysLogServers, sendToSplunkServers, customSplunkSourceType, sendToGrayLogServers, grayLogSettings.Facility, grayLogSettings.Source, grayLogSettings.Version); _logManager.Write(message, logType, writeToConsole, sendToSysLogServers, sendToSplunkServers, customSplunkSourceType, sendToGrayLogServers, grayLogSettings.Facility, grayLogSettings.Source, grayLogSettings.Version);

View File

@ -55,6 +55,7 @@ namespace EonaCat.Network
} }
public bool CheckForCertificateRevocation { get; set; } public bool CheckForCertificateRevocation { get; set; }
public LocalCertificateSelectionCallback ClientCertificateSelectionCallback public LocalCertificateSelectionCallback ClientCertificateSelectionCallback
{ {
get get

View File

@ -57,6 +57,7 @@ namespace EonaCat.Network
public bool IsClientCertificateRequired { get; set; } public bool IsClientCertificateRequired { get; set; }
public SslProtocols SslProtocols { get; set; } public SslProtocols SslProtocols { get; set; }
private static bool ValidateClientCertificate( private static bool ValidateClientCertificate(
object sender, object sender,
X509Certificate certificate, X509Certificate certificate,

View File

@ -14,6 +14,7 @@ namespace EonaCat.Network
private int _count; private int _count;
private bool _disposed; private bool _disposed;
private int _offset; private int _offset;
internal RequestStream(Stream stream, byte[] buffer, int offset, int count) internal RequestStream(Stream stream, byte[] buffer, int offset, int count)
: this(stream, buffer, offset, count, -1) : this(stream, buffer, offset, count, -1)
{ {

View File

@ -18,6 +18,7 @@ namespace EonaCat.Network
private bool _sendChunked; private bool _sendChunked;
private Stream _stream; private Stream _stream;
private Action<byte[], int, int> _writeBody; private Action<byte[], int, int> _writeBody;
internal ResponseStream( internal ResponseStream(
Stream stream, HttpListenerResponse response, bool ignoreWriteExceptions) Stream stream, HttpListenerResponse response, bool ignoreWriteExceptions)
{ {
@ -251,6 +252,7 @@ namespace EonaCat.Network
return true; return true;
} }
private void writeChunked(byte[] buffer, int offset, int count) private void writeChunked(byte[] buffer, int offset, int count)
{ {
var size = getChunkSizeBytes(count, false); var size = getChunkSizeBytes(count, false);

View File

@ -9,7 +9,7 @@ namespace EonaCat.Network
{ {
internal CloseEventArgs() internal CloseEventArgs()
{ {
PayloadData = PayloadData.Empty; Payload = Payload.Empty;
} }
internal CloseEventArgs(ushort code) internal CloseEventArgs(ushort code)
@ -22,14 +22,14 @@ namespace EonaCat.Network
{ {
} }
internal CloseEventArgs(PayloadData payloadData) internal CloseEventArgs(Payload payload)
{ {
PayloadData = payloadData; Payload = payload;
} }
internal CloseEventArgs(ushort code, string reason) internal CloseEventArgs(ushort code, string reason)
{ {
PayloadData = new PayloadData(code, reason); Payload = new Payload(code, reason);
} }
internal CloseEventArgs(CloseStatusCode code, string reason) internal CloseEventArgs(CloseStatusCode code, string reason)
@ -37,9 +37,24 @@ namespace EonaCat.Network
{ {
} }
public ushort Code => PayloadData.Code; /// <summary>
public string Reason => PayloadData.Reason ?? string.Empty; /// Code
/// </summary>
public ushort Code => Payload.Code;
/// <summary>
/// Reason
/// </summary>
public string Reason => Payload.Reason ?? string.Empty;
/// <summary>
/// Determnines if both the client and server requests where handled
/// </summary>
public bool WasClean { get; internal set; } public bool WasClean { get; internal set; }
internal PayloadData PayloadData { get; }
/// <summary>
/// Payload
/// </summary>
internal Payload Payload { get; }
} }
} }

View File

@ -10,15 +10,16 @@ namespace EonaCat.Network
private readonly byte[] _rawData; private readonly byte[] _rawData;
private string _data; private string _data;
private bool _dataSet; private bool _dataSet;
internal MessageEventArgs(WSFrame frame) internal MessageEventArgs(WSFrame frame)
{ {
Opcode = frame.Opcode; Opcode = frame.Opcode;
_rawData = frame.PayloadData.ApplicationData; _rawData = frame.Payload.ApplicationData;
} }
internal MessageEventArgs(OperationCode opcode, byte[] rawData) internal MessageEventArgs(OperationCode opcode, byte[] rawData)
{ {
if ((ulong)rawData.LongLength > PayloadData.MaxLength) if ((ulong)rawData.LongLength > Payload.MaxLength)
{ {
throw new WSException(CloseStatusCode.TooBig); throw new WSException(CloseStatusCode.TooBig);
} }
@ -39,6 +40,7 @@ namespace EonaCat.Network
public bool IsBinary => Opcode == OperationCode.Binary; public bool IsBinary => Opcode == OperationCode.Binary;
public bool IsPing => Opcode == OperationCode.Ping; public bool IsPing => Opcode == OperationCode.Ping;
public bool IsText => Opcode == OperationCode.Text; public bool IsText => Opcode == OperationCode.Text;
public byte[] RawData public byte[] RawData
{ {
get get
@ -49,6 +51,7 @@ namespace EonaCat.Network
} }
internal OperationCode Opcode { get; } internal OperationCode Opcode { get; }
private void setData() private void setData()
{ {
if (_dataSet) if (_dataSet)

View File

@ -17,6 +17,7 @@ namespace EonaCat.Network
private const int BUFFER_SIZE = 1024; private const int BUFFER_SIZE = 1024;
private static readonly byte[] _last = new byte[] { 0x00 }; private static readonly byte[] _last = new byte[] { 0x00 };
private static readonly int _retry = 5; private static readonly int _retry = 5;
public static bool Contains(this string value, params char[] chars) public static bool Contains(this string value, params char[] chars)
{ {
return chars == null || chars.Length == 0 return chars == null || chars.Length == 0
@ -55,20 +56,14 @@ namespace EonaCat.Network
public static void Emit(this EventHandler eventHandler, object sender, EventArgs e) public static void Emit(this EventHandler eventHandler, object sender, EventArgs e)
{ {
if (eventHandler != null) eventHandler?.Invoke(sender, e);
{
eventHandler(sender, e);
}
} }
public static void Emit<TEventArgs>( public static void Emit<TEventArgs>(
this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs e) this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs e)
where TEventArgs : EventArgs where TEventArgs : EventArgs
{ {
if (eventHandler != null) eventHandler?.Invoke(sender, e);
{
eventHandler(sender, e);
}
} }
public static CookieCollection GetCookies(this NameValueCollection headers, bool response) public static CookieCollection GetCookies(this NameValueCollection headers, bool response)
@ -174,10 +169,13 @@ namespace EonaCat.Network
{ {
case 10: case 10:
return true; return true;
case 172: case 172:
return bytes[1] < 32 && bytes[1] >= 16; return bytes[1] < 32 && bytes[1] >= 16;
case 192: case 192:
return bytes[1] == 168; return bytes[1] == 168;
default: default:
return false; return false;
} }
@ -741,10 +739,7 @@ namespace EonaCat.Network
var nread = source.EndRead(ar); var nread = source.EndRead(ar);
if (nread <= 0) if (nread <= 0)
{ {
if (completed != null) completed?.Invoke();
{
completed();
}
return; return;
} }
@ -754,10 +749,7 @@ namespace EonaCat.Network
} }
catch (Exception ex) catch (Exception ex)
{ {
if (error != null) error?.Invoke(ex);
{
error(ex);
}
} }
}; };
@ -767,10 +759,7 @@ namespace EonaCat.Network
} }
catch (Exception ex) catch (Exception ex)
{ {
if (error != null) error?.Invoke(ex);
{
error(ex);
}
} }
} }
@ -839,7 +828,7 @@ namespace EonaCat.Network
? "A policy violation has occurred." ? "A policy violation has occurred."
: code == CloseStatusCode.TooBig : code == CloseStatusCode.TooBig
? "A too big message has been received." ? "A too big message has been received."
: code == CloseStatusCode.MandatoryExtension : code == CloseStatusCode.MissingExtension
? "WebSocket client didn't receive expected extension(s)." ? "WebSocket client didn't receive expected extension(s)."
: code == CloseStatusCode.ServerError : code == CloseStatusCode.ServerError
? "WebSocket server got an internal error." ? "WebSocket server got an internal error."
@ -1101,10 +1090,7 @@ namespace EonaCat.Network
if (nread == length) if (nread == length)
{ {
if (completed != null) completed?.Invoke(buff.SubArray(0, offset + nread));
{
completed(buff.SubArray(0, offset + nread));
}
return; return;
} }
@ -1118,10 +1104,7 @@ namespace EonaCat.Network
} }
catch (Exception ex) catch (Exception ex)
{ {
if (error != null) error?.Invoke(ex);
{
error(ex);
}
} }
}; };
@ -1131,10 +1114,7 @@ namespace EonaCat.Network
} }
catch (Exception ex) catch (Exception ex)
{ {
if (error != null) error?.Invoke(ex);
{
error(ex);
}
} }
} }
@ -1199,10 +1179,7 @@ namespace EonaCat.Network
catch (Exception ex) catch (Exception ex)
{ {
dest.Dispose(); dest.Dispose();
if (error != null) error?.Invoke(ex);
{
error(ex);
}
} }
}, },
null null
@ -1216,10 +1193,7 @@ namespace EonaCat.Network
catch (Exception ex) catch (Exception ex)
{ {
dest.Dispose(); dest.Dispose();
if (error != null) error?.Invoke(ex);
{
error(ex);
}
} }
} }
@ -1558,20 +1532,14 @@ namespace EonaCat.Network
bufferLength, bufferLength,
() => () =>
{ {
if (completed != null) completed?.Invoke();
{
completed();
}
input.Dispose(); input.Dispose();
}, },
ex => ex =>
{ {
input.Dispose(); input.Dispose();
if (error != null) error?.Invoke(ex);
{
error(ex);
}
}); });
} }

View File

@ -7,7 +7,7 @@ using System.Collections.Generic;
namespace EonaCat.Network namespace EonaCat.Network
{ {
internal class PayloadData : IEnumerable<byte> internal class Payload : IEnumerable<byte>
{ {
private ushort _code; private ushort _code;
private bool _codeSet; private bool _codeSet;
@ -16,17 +16,17 @@ namespace EonaCat.Network
private string _reason; private string _reason;
private bool _reasonSet; private bool _reasonSet;
public static readonly PayloadData Empty; public static readonly Payload Empty;
public static readonly ulong MaxLength; public static readonly ulong MaxLength;
static PayloadData() static Payload()
{ {
Empty = new PayloadData(); Empty = new Payload();
MaxLength = long.MaxValue; MaxLength = long.MaxValue;
} }
internal PayloadData() internal Payload()
{ {
_code = (ushort)CloseStatusCode.NoStatus; _code = (ushort)CloseStatusCode.NoStatus;
_reason = string.Empty; _reason = string.Empty;
@ -37,7 +37,7 @@ namespace EonaCat.Network
_reasonSet = true; _reasonSet = true;
} }
internal PayloadData(PayloadData original) internal Payload(Payload original)
{ {
_code = original._code; _code = original._code;
_codeSet = original._codeSet; _codeSet = original._codeSet;
@ -48,22 +48,20 @@ namespace EonaCat.Network
_data = new byte[_length]; _data = new byte[_length];
original._data.CopyTo(_data, 0); original._data.CopyTo(_data, 0);
} }
internal PayloadData(byte[] data) internal Payload(byte[] data)
: this(data, data.LongLength) : this(data, data.LongLength)
{ {
} }
internal PayloadData(byte[] data, long length) internal Payload(byte[] data, long length)
{ {
_data = data; _data = data;
_length = length; _length = length;
} }
internal PayloadData(ushort code, string reason) internal Payload(ushort code, string reason)
{ {
_code = code; _code = code;
_reason = reason ?? string.Empty; _reason = reason ?? string.Empty;

View File

@ -3,7 +3,7 @@
namespace EonaCat.Network namespace EonaCat.Network
{ {
internal enum Rsv : byte internal enum ReservedBits : byte
{ {
Off = 0x0, Off = 0x0,

View File

@ -44,7 +44,7 @@ namespace EonaCat.Network
throw new ArgumentException("It contains '..'.", nameof(path)); throw new ArgumentException("It contains '..'.", nameof(path));
} }
tryReadFile(createFilePath(path), out byte[] contents); tryReadFile(CreateFilePath(path), out byte[] contents);
return contents; return contents;
} }
@ -66,7 +66,7 @@ namespace EonaCat.Network
throw new ArgumentException("It contains '..'.", nameof(path)); throw new ArgumentException("It contains '..'.", nameof(path));
} }
return tryReadFile(createFilePath(path), out contents); return tryReadFile(CreateFilePath(path), out contents);
} }
private static bool tryReadFile(string path, out byte[] contents) private static bool tryReadFile(string path, out byte[] contents)
@ -90,7 +90,7 @@ namespace EonaCat.Network
return true; return true;
} }
private string createFilePath(string childPath) private string CreateFilePath(string childPath)
{ {
childPath = childPath.TrimStart('/', '\\'); childPath = childPath.TrimStart('/', '\\');
return new StringBuilder(_docRootPath, 32) return new StringBuilder(_docRootPath, 32)

View File

@ -4,7 +4,6 @@
using System; using System;
using System.IO; using System.IO;
using System.Security.Principal; using System.Security.Principal;
using System.Text;
using System.Threading; using System.Threading;
namespace EonaCat.Network namespace EonaCat.Network
@ -17,7 +16,8 @@ namespace EonaCat.Network
private HttpListener _listener; private HttpListener _listener;
private Thread _receiveThread; private Thread _receiveThread;
private volatile ServerState _state; private volatile ServerState _state;
private object _sync; private object _locker;
public HttpServer() public HttpServer()
{ {
init("*", System.Net.IPAddress.Any, 80, false); init("*", System.Net.IPAddress.Any, 80, false);
@ -158,7 +158,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (!canSet(out message)) if (!canSet(out message))
{ {
@ -234,7 +234,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (!canSet(out message)) if (!canSet(out message))
{ {
@ -256,15 +256,17 @@ namespace EonaCat.Network
{ {
get get
{ {
return WebSocketServices.AutoCleanSessions; return WSEndpoints.AutoCleanSessions;
} }
set set
{ {
WebSocketServices.AutoCleanSessions = value; WSEndpoints.AutoCleanSessions = value;
} }
} }
public int Port { get; private set; } public int Port { get; private set; }
public string Realm public string Realm
{ {
get get
@ -280,7 +282,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (!canSet(out message)) if (!canSet(out message))
{ {
@ -308,7 +310,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (!canSet(out message)) if (!canSet(out message))
{ {
@ -350,7 +352,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (!canSet(out message)) if (!canSet(out message))
{ {
@ -363,24 +365,25 @@ namespace EonaCat.Network
} }
} }
public TimeSpan WaitTime public TimeSpan ResponseWaitingTime
{ {
get get
{ {
return WebSocketServices.WaitTime; return WSEndpoints.ResponseWaitingTime;
} }
set set
{ {
WebSocketServices.WaitTime = value; WSEndpoints.ResponseWaitingTime = value;
} }
} }
public WSEndpointManager WebSocketServices { get; private set; } public WSEndpointManager WSEndpoints { get; private set; }
public void AddWebSocketService<TEndpoint>(string path) public void AddWebSocketService<TEndpoint>(string path)
where TEndpoint : WSEndpoint, new() where TEndpoint : WSEndpoint, new()
{ {
WebSocketServices.AddService<TEndpoint>(path, null); WSEndpoints.AddEndpoint<TEndpoint>(path, null);
} }
public void AddWebSocketService<TEndpoint>( public void AddWebSocketService<TEndpoint>(
@ -388,12 +391,12 @@ namespace EonaCat.Network
) )
where TEndpoint : WSEndpoint, new() where TEndpoint : WSEndpoint, new()
{ {
WebSocketServices.AddService(path, initializer); WSEndpoints.AddEndpoint(path, initializer);
} }
public bool RemoveWebSocketService(string path) public bool RemoveWebSocketService(string path)
{ {
return WebSocketServices.RemoveService(path); return WSEndpoints.RemoveEndpoint(path);
} }
public void Start() public void Start()
@ -422,9 +425,9 @@ namespace EonaCat.Network
throw new ArgumentOutOfRangeException(nameof(code), message); throw new ArgumentOutOfRangeException(nameof(code), message);
} }
if (code == (ushort)CloseStatusCode.MandatoryExtension) if (code == (ushort)CloseStatusCode.MissingExtension)
{ {
var message = $"{(ushort)CloseStatusCode.MandatoryExtension} cannot be used."; var message = $"{(ushort)CloseStatusCode.MissingExtension} cannot be used.";
throw new ArgumentException(message, nameof(code)); throw new ArgumentException(message, nameof(code));
} }
@ -454,7 +457,7 @@ namespace EonaCat.Network
public void Stop(CloseStatusCode code, string reason) public void Stop(CloseStatusCode code, string reason)
{ {
if (code == CloseStatusCode.MandatoryExtension) if (code == CloseStatusCode.MissingExtension)
{ {
var message = "MandatoryExtension cannot be used."; var message = "MandatoryExtension cannot be used.";
throw new ArgumentException(message, nameof(code)); throw new ArgumentException(message, nameof(code));
@ -548,7 +551,7 @@ namespace EonaCat.Network
private void abort() private void abort()
{ {
lock (_sync) lock (_locker)
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
@ -562,7 +565,7 @@ namespace EonaCat.Network
{ {
try try
{ {
WebSocketServices.Stop((ushort)CloseStatusCode.Abnormal, string.Empty); WSEndpoints.Stop((ushort)CloseStatusCode.Abnormal, string.Empty);
} }
finally finally
{ {
@ -620,6 +623,7 @@ namespace EonaCat.Network
return true; return true;
} }
private void init( private void init(
string hostname, System.Net.IPAddress address, int port, bool secure string hostname, System.Net.IPAddress address, int port, bool secure
) )
@ -631,8 +635,8 @@ namespace EonaCat.Network
_docRootPath = "./Public"; _docRootPath = "./Public";
_listener = createListener(_hostname, Port, IsSecure); _listener = createListener(_hostname, Port, IsSecure);
WebSocketServices = new WSEndpointManager(); WSEndpoints = new WSEndpointManager();
_sync = new object(); _locker = new object();
} }
private void processRequest(HttpListenerContext context) private void processRequest(HttpListenerContext context)
@ -674,7 +678,7 @@ namespace EonaCat.Network
{ {
var path = context.RequestUri.AbsolutePath; var path = context.RequestUri.AbsolutePath;
if (!WebSocketServices.InternalTryGetServiceHost(path, out WSEndpointHost host)) if (!WSEndpoints.InternalTryGetEndpointHost(path, out WSEndpointHost host))
{ {
context.Close(HttpStatusCode.NotImplemented); context.Close(HttpStatusCode.NotImplemented);
return; return;
@ -687,29 +691,29 @@ namespace EonaCat.Network
{ {
while (true) while (true)
{ {
HttpListenerContext ctx = null; HttpListenerContext context = null;
try try
{ {
ctx = _listener.GetContext(); context = _listener.GetContext();
ThreadPool.QueueUserWorkItem( ThreadPool.QueueUserWorkItem(
state => state =>
{ {
try try
{ {
if (ctx.Request.IsUpgradeTo("websocket")) if (context.Request.IsUpgradeTo("websocket"))
{ {
processRequest(ctx.AcceptWebSocket(null)); processRequest(context.AcceptWebSocket(null));
return; return;
} }
processRequest(ctx); processRequest(context);
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Error(ex.Message); Logger.Error(ex.Message);
Logger.Debug(ex.ToString()); Logger.Debug(ex.ToString());
ctx.Connection.Close(true); context.Connection.Close(true);
} }
} }
); );
@ -729,7 +733,7 @@ namespace EonaCat.Network
Logger.Error(ex.Message); Logger.Error(ex.Message);
Logger.Debug(ex.ToString()); Logger.Debug(ex.ToString());
ctx?.Connection.Close(true); context?.Connection.Close(true);
break; break;
} }
@ -755,7 +759,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (_state == ServerState.Start) if (_state == ServerState.Start)
{ {
@ -769,7 +773,7 @@ namespace EonaCat.Network
return; return;
} }
WebSocketServices.Start(); WSEndpoints.Start();
try try
{ {
@ -777,7 +781,7 @@ namespace EonaCat.Network
} }
catch catch
{ {
WebSocketServices.Stop((ushort)CloseStatusCode.ServerError, string.Empty); WSEndpoints.Stop((ushort)CloseStatusCode.ServerError, string.Empty);
throw; throw;
} }
@ -822,7 +826,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (_state == ServerState.ShuttingDown) if (_state == ServerState.ShuttingDown)
{ {
@ -844,7 +848,7 @@ namespace EonaCat.Network
var threw = false; var threw = false;
try try
{ {
WebSocketServices.Stop(code, reason); WSEndpoints.Stop(code, reason);
} }
catch catch
{ {

View File

@ -19,6 +19,7 @@ namespace EonaCat.Network
public WSContext Context { get; private set; } public WSContext Context { get; private set; }
public Func<CookieCollection, CookieCollection, bool> CookiesValidator { get; set; } public Func<CookieCollection, CookieCollection, bool> CookiesValidator { get; set; }
public bool EmitOnPing public bool EmitOnPing
{ {
get get
@ -41,6 +42,7 @@ namespace EonaCat.Network
public string ID { get; private set; } public string ID { get; private set; }
public bool IgnoreExtensions { get; set; } public bool IgnoreExtensions { get; set; }
public Func<string, bool> OriginValidator { get; set; } public Func<string, bool> OriginValidator { get; set; }
public string Protocol public string Protocol
{ {
get get
@ -67,6 +69,7 @@ namespace EonaCat.Network
public DateTime StartTime { get; private set; } public DateTime StartTime { get; private set; }
public WSState State => _websocket != null ? _websocket.ReadyState : WSState.Connecting; public WSState State => _websocket != null ? _websocket.ReadyState : WSState.Connecting;
protected WSSessionManager Sessions { get; private set; } protected WSSessionManager Sessions { get; private set; }
internal void Start(WSContext context, WSSessionManager sessions) internal void Start(WSContext context, WSSessionManager sessions)
{ {
if (_websocket != null) if (_websocket != null)
@ -86,10 +89,10 @@ namespace EonaCat.Network
_websocket.IgnoreExtensions = IgnoreExtensions; _websocket.IgnoreExtensions = IgnoreExtensions;
_websocket.Protocol = _protocol; _websocket.Protocol = _protocol;
var waitTime = sessions.WaitTime; var responseWaitingTime = sessions.ResponseWaitingTime;
if (waitTime != _websocket.WaitTime) if (responseWaitingTime != _websocket.ResponseWaitingTime)
{ {
_websocket.WaitTime = waitTime; _websocket.ResponseWaitingTime = responseWaitingTime;
} }
_websocket.OnConnect += onOpen; _websocket.OnConnect += onOpen;

View File

@ -14,7 +14,8 @@ namespace EonaCat.Network
} }
public abstract Type EndpointType { get; } public abstract Type EndpointType { get; }
public bool KeepClean
public bool AutoCleanSessions
{ {
get get
{ {
@ -29,20 +30,22 @@ namespace EonaCat.Network
public string Path { get; } public string Path { get; }
public WSSessionManager Sessions { get; } public WSSessionManager Sessions { get; }
public TimeSpan WaitTime
public TimeSpan ResponseWaitingTime
{ {
get get
{ {
return Sessions.WaitTime; return Sessions.ResponseWaitingTime;
} }
set set
{ {
Sessions.WaitTime = value; Sessions.ResponseWaitingTime = value;
} }
} }
internal ServerState State => Sessions.State; internal ServerState State => Sessions.State;
internal void Start() internal void Start()
{ {
Sessions.Start(); Sessions.Start();

View File

@ -5,25 +5,24 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading;
namespace EonaCat.Network namespace EonaCat.Network
{ {
public class WSEndpointManager public class WSEndpointManager
{ {
private readonly Dictionary<string, WSEndpointHost> _hosts; private readonly Dictionary<string, WSEndpointHost> _hosts;
private readonly object _sync; private readonly object _locker;
private volatile bool _clean; private volatile bool _clean;
private volatile ServerState _state; private volatile ServerState _state;
private TimeSpan _waitTime; private TimeSpan _responseWaitingTime;
internal WSEndpointManager() internal WSEndpointManager()
{ {
_clean = true; _clean = true;
_hosts = new Dictionary<string, WSEndpointHost>(); _hosts = new Dictionary<string, WSEndpointHost>();
_state = ServerState.Started; _state = ServerState.Started;
_sync = ((ICollection)_hosts).SyncRoot; _locker = ((ICollection)_hosts).SyncRoot;
_waitTime = TimeSpan.FromSeconds(1); _responseWaitingTime = TimeSpan.FromSeconds(1);
} }
public bool AutoCleanSessions public bool AutoCleanSessions
@ -41,7 +40,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (!canSet(out message)) if (!canSet(out message))
{ {
@ -51,7 +50,7 @@ namespace EonaCat.Network
foreach (var host in _hosts.Values) foreach (var host in _hosts.Values)
{ {
host.KeepClean = value; host.AutoCleanSessions = value;
} }
_clean = value; _clean = value;
@ -63,7 +62,7 @@ namespace EonaCat.Network
{ {
get get
{ {
lock (_sync) lock (_locker)
{ {
return _hosts.Count; return _hosts.Count;
} }
@ -74,7 +73,7 @@ namespace EonaCat.Network
{ {
get get
{ {
lock (_sync) lock (_locker)
{ {
return _hosts.Values.ToList(); return _hosts.Values.ToList();
} }
@ -85,18 +84,18 @@ namespace EonaCat.Network
{ {
get get
{ {
lock (_sync) lock (_locker)
{ {
return _hosts.Keys.ToList(); return _hosts.Keys.ToList();
} }
} }
} }
public TimeSpan WaitTime public TimeSpan ResponseWaitingTime
{ {
get get
{ {
return _waitTime; return _responseWaitingTime;
} }
set set
@ -112,7 +111,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (!canSet(out message)) if (!canSet(out message))
{ {
@ -122,10 +121,10 @@ namespace EonaCat.Network
foreach (var host in _hosts.Values) foreach (var host in _hosts.Values)
{ {
host.WaitTime = value; host.ResponseWaitingTime = value;
} }
_waitTime = value; _responseWaitingTime = value;
} }
} }
} }
@ -155,12 +154,13 @@ namespace EonaCat.Network
throw new ArgumentException(message, nameof(path)); throw new ArgumentException(message, nameof(path));
} }
InternalTryGetServiceHost(path, out WSEndpointHost host); InternalTryGetEndpointHost(path, out WSEndpointHost host);
return host; return host;
} }
} }
public void AddService<TEndpoint>(
public void AddEndpoint<TEndpoint>(
string path, Action<TEndpoint> initializer string path, Action<TEndpoint> initializer
) )
where TEndpoint : WSEndpoint, new() where TEndpoint : WSEndpoint, new()
@ -188,7 +188,7 @@ namespace EonaCat.Network
path = HttpUtility.UrlDecode(path).TrimSlashFromEnd(); path = HttpUtility.UrlDecode(path).TrimSlashFromEnd();
lock (_sync) lock (_locker)
{ {
if (_hosts.TryGetValue(path, out WSEndpointHost host)) if (_hosts.TryGetValue(path, out WSEndpointHost host))
{ {
@ -201,12 +201,12 @@ namespace EonaCat.Network
if (!_clean) if (!_clean)
{ {
host.KeepClean = false; host.AutoCleanSessions = false;
} }
if (_waitTime != host.WaitTime) if (_responseWaitingTime != host.ResponseWaitingTime)
{ {
host.WaitTime = _waitTime; host.ResponseWaitingTime = _responseWaitingTime;
} }
if (_state == ServerState.Start) if (_state == ServerState.Start)
@ -222,7 +222,7 @@ namespace EonaCat.Network
{ {
List<WSEndpointHost> hosts = null; List<WSEndpointHost> hosts = null;
lock (_sync) lock (_locker)
{ {
hosts = _hosts.Values.ToList(); hosts = _hosts.Values.ToList();
_hosts.Clear(); _hosts.Clear();
@ -237,7 +237,7 @@ namespace EonaCat.Network
} }
} }
public bool RemoveService(string path) public bool RemoveEndpoint(string path)
{ {
if (path == null) if (path == null)
{ {
@ -263,7 +263,7 @@ namespace EonaCat.Network
path = HttpUtility.UrlDecode(path).TrimSlashFromEnd(); path = HttpUtility.UrlDecode(path).TrimSlashFromEnd();
WSEndpointHost host; WSEndpointHost host;
lock (_sync) lock (_locker)
{ {
if (!_hosts.TryGetValue(path, out host)) if (!_hosts.TryGetValue(path, out host))
{ {
@ -281,7 +281,7 @@ namespace EonaCat.Network
return true; return true;
} }
public bool TryGetServiceHost(string path, out WSEndpointHost host) public bool TryGetEndpointHost(string path, out WSEndpointHost host)
{ {
if (path == null) if (path == null)
{ {
@ -304,7 +304,7 @@ namespace EonaCat.Network
throw new ArgumentException(message, nameof(path)); throw new ArgumentException(message, nameof(path));
} }
return InternalTryGetServiceHost(path, out host); return InternalTryGetEndpointHost(path, out host);
} }
internal void Add<TEndpoint>(string path, Func<TEndpoint> creator) internal void Add<TEndpoint>(string path, Func<TEndpoint> creator)
@ -312,7 +312,7 @@ namespace EonaCat.Network
{ {
path = HttpUtility.UrlDecode(path).TrimSlashFromEnd(); path = HttpUtility.UrlDecode(path).TrimSlashFromEnd();
lock (_sync) lock (_locker)
{ {
if (_hosts.TryGetValue(path, out WSEndpointHost host)) if (_hosts.TryGetValue(path, out WSEndpointHost host))
{ {
@ -325,12 +325,12 @@ namespace EonaCat.Network
if (!_clean) if (!_clean)
{ {
host.KeepClean = false; host.AutoCleanSessions = false;
} }
if (_waitTime != host.WaitTime) if (_responseWaitingTime != host.ResponseWaitingTime)
{ {
host.WaitTime = _waitTime; host.ResponseWaitingTime = _responseWaitingTime;
} }
if (_state == ServerState.Start) if (_state == ServerState.Start)
@ -342,13 +342,13 @@ namespace EonaCat.Network
} }
} }
internal bool InternalTryGetServiceHost( internal bool InternalTryGetEndpointHost(
string path, out WSEndpointHost host string path, out WSEndpointHost host
) )
{ {
path = HttpUtility.UrlDecode(path).TrimSlashFromEnd(); path = HttpUtility.UrlDecode(path).TrimSlashFromEnd();
lock (_sync) lock (_locker)
{ {
return _hosts.TryGetValue(path, out host); return _hosts.TryGetValue(path, out host);
} }
@ -356,7 +356,7 @@ namespace EonaCat.Network
internal void Start() internal void Start()
{ {
lock (_sync) lock (_locker)
{ {
foreach (var host in _hosts.Values) foreach (var host in _hosts.Values)
{ {
@ -369,7 +369,7 @@ namespace EonaCat.Network
internal void Stop(ushort code, string reason) internal void Stop(ushort code, string reason)
{ {
lock (_sync) lock (_locker)
{ {
_state = ServerState.ShuttingDown; _state = ServerState.ShuttingDown;
@ -399,10 +399,7 @@ namespace EonaCat.Network
host.Sessions.Broadcast(opcode, data, cache); host.Sessions.Broadcast(opcode, data, cache);
} }
if (completed != null) completed?.Invoke();
{
completed();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -431,10 +428,7 @@ namespace EonaCat.Network
host.Sessions.Broadcast(opcode, stream, cache); host.Sessions.Broadcast(opcode, stream, cache);
} }
if (completed != null) completed?.Invoke();
{
completed();
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -10,7 +10,7 @@ namespace EonaCat.Network
{ {
public class WSServer public class WSServer
{ {
private static readonly string _defaultRealm; private static readonly string _defaultRealm = "EonaCat Network - Area51";
private bool _allowForwardedRequest; private bool _allowForwardedRequest;
private AuthenticationSchemes _authSchemes; private AuthenticationSchemes _authSchemes;
private bool _dnsStyle; private bool _dnsStyle;
@ -23,12 +23,8 @@ namespace EonaCat.Network
private SSLConfigServer _sslConfig; private SSLConfigServer _sslConfig;
private SSLConfigServer _sslConfigInUse; private SSLConfigServer _sslConfigInUse;
private volatile ServerState _state; private volatile ServerState _state;
private object _sync; private object _locker;
private Func<IIdentity, NetworkCredential> _userCredentialsFinder; private Func<IIdentity, NetworkCredential> _userCredentialsFinder;
static WSServer()
{
_defaultRealm = "SECRET AREA";
}
public WSServer() public WSServer()
{ {
@ -115,6 +111,7 @@ namespace EonaCat.Network
} }
public System.Net.IPAddress Address { get; private set; } public System.Net.IPAddress Address { get; private set; }
public bool AllowForwardedRequest public bool AllowForwardedRequest
{ {
get get
@ -130,7 +127,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (!CanSet(out message)) if (!CanSet(out message))
{ {
@ -158,7 +155,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (!CanSet(out message)) if (!CanSet(out message))
{ {
@ -188,6 +185,7 @@ namespace EonaCat.Network
} }
public WSEndpointManager Endpoints { get; private set; } public WSEndpointManager Endpoints { get; private set; }
public Func<IIdentity, NetworkCredential> FindCredentials public Func<IIdentity, NetworkCredential> FindCredentials
{ {
get get
@ -203,7 +201,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (!CanSet(out message)) if (!CanSet(out message))
{ {
@ -237,7 +235,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (!CanSet(out message)) if (!CanSet(out message))
{ {
@ -265,7 +263,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (!CanSet(out message)) if (!CanSet(out message))
{ {
@ -291,31 +289,33 @@ namespace EonaCat.Network
return GetSSLConfig(); return GetSSLConfig();
} }
} }
public TimeSpan WaitTime
public TimeSpan ResponseWaitingTime
{ {
get get
{ {
return Endpoints.WaitTime; return Endpoints.ResponseWaitingTime;
} }
set set
{ {
Endpoints.WaitTime = value; Endpoints.ResponseWaitingTime = value;
} }
} }
public void AddEndpoint<TEndpoint>(string path) where TEndpoint : WSEndpoint, new() public void AddEndpoint<TEndpoint>(string path) where TEndpoint : WSEndpoint, new()
{ {
Endpoints.AddService<TEndpoint>(path, null); Endpoints.AddEndpoint<TEndpoint>(path, null);
} }
public void AddEndpoint<TEndpoint>(string path, Action<TEndpoint> initializer) where TEndpoint : WSEndpoint, new() public void AddEndpoint<TEndpoint>(string path, Action<TEndpoint> initializer) where TEndpoint : WSEndpoint, new()
{ {
Endpoints.AddService(path, initializer); Endpoints.AddEndpoint(path, initializer);
} }
public bool RemoveEndpoint(string path) public bool RemoveEndpoint(string path)
{ {
return Endpoints.RemoveService(path); return Endpoints.RemoveEndpoint(path);
} }
public void Start() public void Start()
@ -348,9 +348,9 @@ namespace EonaCat.Network
throw new ArgumentOutOfRangeException(nameof(code), message); throw new ArgumentOutOfRangeException(nameof(code), message);
} }
if (code == (ushort)CloseStatusCode.MandatoryExtension) if (code == (ushort)CloseStatusCode.MissingExtension)
{ {
var message = $"{(ushort)CloseStatusCode.MandatoryExtension} cannot be used."; var message = $"{(ushort)CloseStatusCode.MissingExtension} cannot be used.";
throw new ArgumentException(message, nameof(code)); throw new ArgumentException(message, nameof(code));
} }
@ -380,7 +380,7 @@ namespace EonaCat.Network
public void Stop(CloseStatusCode code, string reason) public void Stop(CloseStatusCode code, string reason)
{ {
if (code == CloseStatusCode.MandatoryExtension) if (code == CloseStatusCode.MissingExtension)
{ {
var message = "MandatoryExtension cannot be used."; var message = "MandatoryExtension cannot be used.";
throw new ArgumentException(message, nameof(code)); throw new ArgumentException(message, nameof(code));
@ -446,7 +446,7 @@ namespace EonaCat.Network
private void abort() private void abort()
{ {
lock (_sync) lock (_locker)
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
@ -499,6 +499,7 @@ namespace EonaCat.Network
|| Uri.CheckHostName(name) != UriHostNameType.Dns || Uri.CheckHostName(name) != UriHostNameType.Dns
|| name == _hostname; || name == _hostname;
} }
private string GetRealm() private string GetRealm()
{ {
var realm = _realm; var realm = _realm;
@ -525,7 +526,7 @@ namespace EonaCat.Network
_dnsStyle = Uri.CheckHostName(hostname) == UriHostNameType.Dns; _dnsStyle = Uri.CheckHostName(hostname) == UriHostNameType.Dns;
_listener = new TcpListener(address, port); _listener = new TcpListener(address, port);
Endpoints = new WSEndpointManager(); Endpoints = new WSEndpointManager();
_sync = new object(); _locker = new object();
} }
private void processRequest(TcpListenerWSContext context) private void processRequest(TcpListenerWSContext context)
@ -552,7 +553,7 @@ namespace EonaCat.Network
} }
} }
if (!Endpoints.InternalTryGetServiceHost(uri.AbsolutePath, out WSEndpointHost host)) if (!Endpoints.InternalTryGetEndpointHost(uri.AbsolutePath, out WSEndpointHost host))
{ {
context.Close(HttpStatusCode.NotImplemented); context.Close(HttpStatusCode.NotImplemented);
return; return;
@ -574,15 +575,15 @@ namespace EonaCat.Network
{ {
try try
{ {
var ctx = new TcpListenerWSContext( var context = new TcpListenerWSContext(
cl, null, IsSecure, _sslConfigInUse); cl, null, IsSecure, _sslConfigInUse);
if (!ctx.Authenticate(_authSchemes, _realmInUse, _userCredentialsFinder)) if (!context.Authenticate(_authSchemes, _realmInUse, _userCredentialsFinder))
{ {
return; return;
} }
processRequest(ctx); processRequest(context);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -641,7 +642,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (_state == ServerState.Start) if (_state == ServerState.Start)
{ {
@ -717,7 +718,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (_state == ServerState.ShuttingDown) if (_state == ServerState.ShuttingDown)
{ {

View File

@ -12,25 +12,26 @@ namespace EonaCat.Network
{ {
public class WSSessionManager public class WSSessionManager
{ {
private readonly object _forSweep; private const int _cleanupIntervalInMiliSeconds = 60000;
private readonly object _cleanLocker;
private readonly Dictionary<string, IWSSession> _sessions; private readonly Dictionary<string, IWSSession> _sessions;
private readonly object _sync; private readonly object _locker;
private volatile bool _clean; private volatile bool _clean;
private volatile ServerState _state; private volatile ServerState _state;
private volatile bool _sweeping; private volatile bool _sweeping;
private System.Timers.Timer _sweepTimer; private System.Timers.Timer _sweepTimer;
private TimeSpan _waitTime; private TimeSpan _responseWaitingTime;
internal WSSessionManager() internal WSSessionManager()
{ {
_clean = true; _clean = true;
_forSweep = new object(); _cleanLocker = new object();
_sessions = new Dictionary<string, IWSSession>(); _sessions = new Dictionary<string, IWSSession>();
_state = ServerState.Started; _state = ServerState.Started;
_sync = ((ICollection)_sessions).SyncRoot; _locker = ((ICollection)_sessions).SyncRoot;
_waitTime = TimeSpan.FromSeconds(1); _responseWaitingTime = TimeSpan.FromSeconds(1);
setSweepTimer(60000); setCleanupTimer(_cleanupIntervalInMiliSeconds);
} }
public IEnumerable<string> ActiveIDs public IEnumerable<string> ActiveIDs
@ -51,7 +52,7 @@ namespace EonaCat.Network
{ {
get get
{ {
lock (_sync) lock (_locker)
{ {
return _sessions.Count; return _sessions.Count;
} }
@ -67,7 +68,7 @@ namespace EonaCat.Network
return Enumerable.Empty<string>(); return Enumerable.Empty<string>();
} }
lock (_sync) lock (_locker)
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
@ -108,7 +109,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (!canSet(out message)) if (!canSet(out message))
{ {
@ -130,7 +131,7 @@ namespace EonaCat.Network
return Enumerable.Empty<IWSSession>(); return Enumerable.Empty<IWSSession>();
} }
lock (_sync) lock (_locker)
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
@ -142,11 +143,11 @@ namespace EonaCat.Network
} }
} }
public TimeSpan WaitTime internal TimeSpan ResponseWaitingTime
{ {
get get
{ {
return _waitTime; return _responseWaitingTime;
} }
set set
@ -162,7 +163,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_sync) lock (_locker)
{ {
if (!canSet(out message)) if (!canSet(out message))
{ {
@ -170,12 +171,13 @@ namespace EonaCat.Network
return; return;
} }
_waitTime = value; _responseWaitingTime = value;
} }
} }
} }
internal ServerState State => _state; internal ServerState State => _state;
public IWSSession this[string id] public IWSSession this[string id]
{ {
get get
@ -195,6 +197,7 @@ namespace EonaCat.Network
return session; return session;
} }
} }
public void Broadcast(byte[] data) public void Broadcast(byte[] data)
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
@ -538,7 +541,7 @@ namespace EonaCat.Network
return; return;
} }
lock (_forSweep) lock (_cleanLocker)
{ {
if (_sweeping) if (_sweeping)
{ {
@ -556,7 +559,7 @@ namespace EonaCat.Network
break; break;
} }
lock (_sync) lock (_locker)
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
@ -602,7 +605,7 @@ namespace EonaCat.Network
internal string Add(IWSSession session) internal string Add(IWSSession session)
{ {
lock (_sync) lock (_locker)
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
@ -624,7 +627,7 @@ namespace EonaCat.Network
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
Logger.Error("The service is shutting down."); Logger.Error("The endpoint is shutting down.");
break; break;
} }
@ -640,7 +643,7 @@ namespace EonaCat.Network
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
Logger.Error("The service is shutting down."); Logger.Error("The endpoint is shutting down.");
break; break;
} }
@ -658,7 +661,7 @@ namespace EonaCat.Network
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
Logger.Error("The service is shutting down."); Logger.Error("The endpoint is shutting down.");
break; break;
} }
@ -671,7 +674,7 @@ namespace EonaCat.Network
internal bool Remove(string id) internal bool Remove(string id)
{ {
lock (_sync) lock (_locker)
{ {
return _sessions.Remove(id); return _sessions.Remove(id);
} }
@ -679,7 +682,7 @@ namespace EonaCat.Network
internal void Start() internal void Start()
{ {
lock (_sync) lock (_locker)
{ {
_sweepTimer.Enabled = _clean; _sweepTimer.Enabled = _clean;
_state = ServerState.Start; _state = ServerState.Start;
@ -690,11 +693,11 @@ namespace EonaCat.Network
{ {
if (code == (ushort)CloseStatusCode.NoStatus) if (code == (ushort)CloseStatusCode.NoStatus)
{ // == no status { // == no status
stop(PayloadData.Empty, true); stop(Payload.Empty, true);
return; return;
} }
stop(new PayloadData(code, reason), !code.IsReserved()); stop(new Payload(code, reason), !code.IsReserved());
} }
private static string createID() private static string createID()
@ -712,17 +715,14 @@ namespace EonaCat.Network
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
Logger.Error("The service is shutting down."); Logger.Error("The endpoint is shutting down.");
break; break;
} }
session.Context.WebSocket.Send(opcode, data, cache); session.Context.WebSocket.Send(opcode, data, cache);
} }
if (completed != null) completed?.Invoke();
{
completed();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -745,17 +745,14 @@ namespace EonaCat.Network
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
Logger.Error("The service is shutting down."); Logger.Error("The endpoint is shutting down.");
break; break;
} }
session.Context.WebSocket.Send(opcode, stream, cache); session.Context.WebSocket.Send(opcode, stream, cache);
} }
if (completed != null) completed?.Invoke();
{
completed();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -789,21 +786,21 @@ namespace EonaCat.Network
private Dictionary<string, bool> broadping(byte[] frameAsBytes) private Dictionary<string, bool> broadping(byte[] frameAsBytes)
{ {
var ret = new Dictionary<string, bool>(); var result = new Dictionary<string, bool>();
foreach (var session in Sessions) foreach (var session in Sessions)
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {
Logger.Error("The service is shutting down."); Logger.Error("The endpoint is shutting down.");
break; break;
} }
var res = session.Context.WebSocket.Ping(frameAsBytes, _waitTime); var pingResult = session.Context.WebSocket.Ping(frameAsBytes, _responseWaitingTime);
ret.Add(session.ID, res); result.Add(session.ID, pingResult);
} }
return ret; return result;
} }
private bool canSet(out string message) private bool canSet(out string message)
@ -812,38 +809,39 @@ namespace EonaCat.Network
if (_state == ServerState.Start) if (_state == ServerState.Start)
{ {
message = "The service has already started."; message = "The endpoint has already started.";
return false; return false;
} }
if (_state == ServerState.ShuttingDown) if (_state == ServerState.ShuttingDown)
{ {
message = "The service is shutting down."; message = "The endpoint is shutting down.";
return false; return false;
} }
return true; return true;
} }
private void setSweepTimer(double interval)
private void setCleanupTimer(double interval)
{ {
_sweepTimer = new System.Timers.Timer(interval); _sweepTimer = new System.Timers.Timer(interval);
_sweepTimer.Elapsed += (sender, e) => Sweep(); _sweepTimer.Elapsed += (sender, e) => Sweep();
} }
private void stop(PayloadData payloadData, bool send) private void stop(Payload payload, bool send)
{ {
var bytes = send var bytes = send
? WSFrame.CreateCloseFrame(payloadData, false).ToArray() ? WSFrame.CreateCloseFrame(payload, false).ToArray()
: null; : null;
lock (_sync) lock (_locker)
{ {
_state = ServerState.ShuttingDown; _state = ServerState.ShuttingDown;
_sweepTimer.Enabled = false; _sweepTimer.Enabled = false;
foreach (var session in _sessions.Values.ToList()) foreach (var session in _sessions.Values.ToList())
{ {
session.Context.WebSocket.Close(payloadData, bytes); session.Context.WebSocket.Close(payload, bytes);
} }
_state = ServerState.Stop; _state = ServerState.Stop;
@ -859,7 +857,7 @@ namespace EonaCat.Network
return false; return false;
} }
lock (_sync) lock (_locker)
{ {
if (_state != ServerState.Start) if (_state != ServerState.Start)
{ {

File diff suppressed because it is too large Load Diff

View File

@ -13,32 +13,33 @@ namespace EonaCat.Network
{ {
internal static readonly byte[] EmptyPingBytes; internal static readonly byte[] EmptyPingBytes;
private const int BUFFER_SIZE = 1024; private const int BUFFER_SIZE = 1024;
static WSFrame() static WSFrame()
{ {
EmptyPingBytes = CreatePingFrame(false).ToArray(); EmptyPingBytes = CreatePingFrame(false).ToArray();
} }
internal WSFrame(OperationCode opcode, PayloadData payloadData, bool mask) internal WSFrame(OperationCode opcode, Payload payload, bool mask)
: this(FinalFrame.Final, opcode, payloadData, false, mask) : this(FinalFrame.Final, opcode, payload, false, mask)
{ {
} }
internal WSFrame(FinalFrame finalFrame, OperationCode opcode, byte[] data, bool compressed, bool mask) internal WSFrame(FinalFrame finalFrame, OperationCode opcode, byte[] data, bool compressed, bool mask)
: this(finalFrame, opcode, new PayloadData(data), compressed, mask) : this(finalFrame, opcode, new Payload(data), compressed, mask)
{ {
} }
internal WSFrame( internal WSFrame(
FinalFrame fin, OperationCode opcode, PayloadData payloadData, bool compressed, bool mask) FinalFrame fin, OperationCode opcode, Payload payload, bool compressed, bool mask)
{ {
Fin = fin; Fin = fin;
Rsv1 = opcode.IsData() && compressed ? Rsv.On : Rsv.Off; Rsv1 = opcode.IsData() && compressed ? ReservedBits.On : ReservedBits.Off;
Rsv2 = Rsv.Off; Rsv2 = ReservedBits.Off;
Rsv3 = Rsv.Off; Rsv3 = ReservedBits.Off;
Opcode = opcode; Opcode = opcode;
PayloadData = new PayloadData(payloadData); Payload = new Payload(payload);
var len = PayloadData.Length; var len = Payload.Length;
if (len < 126) if (len < 126)
{ {
PayloadLength = (byte)len; PayloadLength = (byte)len;
@ -58,8 +59,8 @@ namespace EonaCat.Network
if (mask) if (mask)
{ {
Mask = Mask.On; Mask = Mask.On;
MaskingKey = createMaskingKey(); MaskingKey = CreateMaskingKey();
PayloadData.Mask(MaskingKey); Payload.Mask(MaskingKey);
} }
else else
{ {
@ -71,11 +72,12 @@ namespace EonaCat.Network
private WSFrame() private WSFrame()
{ {
} }
public byte[] ExtendedPayloadLength { get; private set; } public byte[] ExtendedPayloadLength { get; private set; }
public FinalFrame Fin { get; private set; } public FinalFrame Fin { get; private set; }
public bool IsBinary => Opcode == OperationCode.Binary; public bool IsBinary => Opcode == OperationCode.Binary;
public bool IsClose => Opcode == OperationCode.Close; public bool IsClose => Opcode == OperationCode.Close;
public bool IsCompressed => Rsv1 == Rsv.On; public bool IsCompressed => Rsv1 == ReservedBits.On;
public bool IsContinuation => Opcode == OperationCode.Continue; public bool IsContinuation => Opcode == OperationCode.Continue;
public bool IsControl => Opcode >= OperationCode.Close; public bool IsControl => Opcode >= OperationCode.Close;
public bool IsData => Opcode == OperationCode.Text || Opcode == OperationCode.Binary; public bool IsData => Opcode == OperationCode.Text || Opcode == OperationCode.Binary;
@ -85,15 +87,15 @@ namespace EonaCat.Network
public bool IsPing => Opcode == OperationCode.Ping; public bool IsPing => Opcode == OperationCode.Ping;
public bool IsPong => Opcode == OperationCode.Pong; public bool IsPong => Opcode == OperationCode.Pong;
public bool IsText => Opcode == OperationCode.Text; public bool IsText => Opcode == OperationCode.Text;
public ulong Length => 2 + (ulong)(ExtendedPayloadLength.Length + MaskingKey.Length) + PayloadData.Length; public ulong Length => 2 + (ulong)(ExtendedPayloadLength.Length + MaskingKey.Length) + Payload.Length;
public Mask Mask { get; private set; } public Mask Mask { get; private set; }
public byte[] MaskingKey { get; private set; } public byte[] MaskingKey { get; private set; }
public OperationCode Opcode { get; private set; } public OperationCode Opcode { get; private set; }
public PayloadData PayloadData { get; private set; } public Payload Payload { get; private set; }
public byte PayloadLength { get; private set; } public byte PayloadLength { get; private set; }
public Rsv Rsv1 { get; private set; } public ReservedBits Rsv1 { get; private set; }
public Rsv Rsv2 { get; private set; } public ReservedBits Rsv2 { get; private set; }
public Rsv Rsv3 { get; private set; } public ReservedBits Rsv3 { get; private set; }
internal int ExtendedPayloadLengthCount => PayloadLength < 126 ? 0 : (PayloadLength == 126 ? 2 : 8); internal int ExtendedPayloadLengthCount => PayloadLength < 126 ? 0 : (PayloadLength == 126 ? 2 : 8);
internal ulong FullPayloadLength => PayloadLength < 126 internal ulong FullPayloadLength => PayloadLength < 126
@ -101,6 +103,7 @@ namespace EonaCat.Network
: PayloadLength == 126 : PayloadLength == 126
? ExtendedPayloadLength.ToUInt16(ByteOrder.Big) ? ExtendedPayloadLength.ToUInt16(ByteOrder.Big)
: ExtendedPayloadLength.ToUInt64(ByteOrder.Big); : ExtendedPayloadLength.ToUInt64(ByteOrder.Big);
public IEnumerator<byte> GetEnumerator() public IEnumerator<byte> GetEnumerator()
{ {
foreach (var b in ToArray()) foreach (var b in ToArray())
@ -116,12 +119,12 @@ namespace EonaCat.Network
public void Print(bool dumped) public void Print(bool dumped)
{ {
Console.WriteLine(dumped ? dump(this) : print(this)); Console.WriteLine(dumped ? Dump(this) : Print(this));
} }
public string PrintToString(bool dumped) public string PrintToString(bool dumped)
{ {
return dumped ? dump(this) : print(this); return dumped ? Dump(this) : Print(this);
} }
public byte[] ToArray() public byte[] ToArray()
@ -149,7 +152,7 @@ namespace EonaCat.Network
if (PayloadLength > 0) if (PayloadLength > 0)
{ {
var bytes = PayloadData.ToArray(); var bytes = Payload.ToArray();
if (PayloadLength < 127) if (PayloadLength < 127)
{ {
buff.Write(bytes, 0, bytes.Length); buff.Write(bytes, 0, bytes.Length);
@ -171,34 +174,34 @@ namespace EonaCat.Network
} }
internal static WSFrame CreateCloseFrame( internal static WSFrame CreateCloseFrame(
PayloadData payloadData, bool mask Payload payload, bool mask
) )
{ {
return new WSFrame( return new WSFrame(
FinalFrame.Final, OperationCode.Close, payloadData, false, mask FinalFrame.Final, OperationCode.Close, payload, false, mask
); );
} }
internal static WSFrame CreatePingFrame(bool mask) internal static WSFrame CreatePingFrame(bool mask)
{ {
return new WSFrame( return new WSFrame(
FinalFrame.Final, OperationCode.Ping, PayloadData.Empty, false, mask FinalFrame.Final, OperationCode.Ping, Payload.Empty, false, mask
); );
} }
internal static WSFrame CreatePingFrame(byte[] data, bool mask) internal static WSFrame CreatePingFrame(byte[] data, bool mask)
{ {
return new WSFrame( return new WSFrame(
FinalFrame.Final, OperationCode.Ping, new PayloadData(data), false, mask FinalFrame.Final, OperationCode.Ping, new Payload(data), false, mask
); );
} }
internal static WSFrame CreatePongFrame( internal static WSFrame CreatePongFrame(
PayloadData payloadData, bool mask Payload payload, bool mask
) )
{ {
return new WSFrame( return new WSFrame(
FinalFrame.Final, OperationCode.Pong, payloadData, false, mask FinalFrame.Final, OperationCode.Pong, payload, false, mask
); );
} }
@ -207,7 +210,7 @@ namespace EonaCat.Network
var frame = readHeader(stream); var frame = readHeader(stream);
readExtendedPayloadLength(stream, frame); readExtendedPayloadLength(stream, frame);
readMaskingKey(stream, frame); readMaskingKey(stream, frame);
readPayloadData(stream, frame); readPayload(stream, frame);
if (unmask) if (unmask)
{ {
@ -235,7 +238,7 @@ namespace EonaCat.Network
stream, stream,
frame1, frame1,
frame2 => frame2 =>
readPayloadDataAsync( readPayloadAsync(
stream, stream,
frame2, frame2,
frame3 => frame3 =>
@ -265,11 +268,11 @@ namespace EonaCat.Network
} }
Mask = Mask.Off; Mask = Mask.Off;
PayloadData.Mask(MaskingKey); Payload.Mask(MaskingKey);
MaskingKey = WSClient.EmptyBytes; MaskingKey = WSClient.EmptyBytes;
} }
private static byte[] createMaskingKey() private static byte[] CreateMaskingKey()
{ {
var key = new byte[4]; var key = new byte[4];
WSClient.RandomNumber.GetBytes(key); WSClient.RandomNumber.GetBytes(key);
@ -277,40 +280,40 @@ namespace EonaCat.Network
return key; return key;
} }
private static string dump(WSFrame frame) private static string Dump(WSFrame frame)
{ {
var len = frame.Length; var len = frame.Length;
var cnt = (long)(len / 4); var amount = (long)(len / 4);
var rem = (int)(len % 4); var remainder = (int)(len % 4);
int cntDigit; int digitAmount;
string cntFmt; string frameCount;
if (cnt < 10000) if (amount < 10000)
{ {
cntDigit = 4; digitAmount = 4;
cntFmt = "{0,4}"; frameCount = "{0,4}";
} }
else if (cnt < 0x010000) else if (amount < 0x010000)
{ {
cntDigit = 4; digitAmount = 4;
cntFmt = "{0,4:X}"; frameCount = "{0,4:X}";
} }
else if (cnt < 0x0100000000) else if (amount < 0x0100000000)
{ {
cntDigit = 8; digitAmount = 8;
cntFmt = "{0,8:X}"; frameCount = "{0,8:X}";
} }
else else
{ {
cntDigit = 16; digitAmount = 16;
cntFmt = "{0,16:X}"; frameCount = "{0,16:X}";
} }
var spFmt = string.Format("{{0,{0}}}", cntDigit); var spFmt = string.Format("{{0,{0}}}", digitAmount);
var headerFmt = string.Format(@" var headerFormat = string.Format(@"
{0} 01234567 89ABCDEF 01234567 89ABCDEF {0} 01234567 89ABCDEF 01234567 89ABCDEF
{0}+--------+--------+--------+--------+\n", spFmt); {0}+--------+--------+--------+--------+\n", spFmt);
var lineFmt = string.Format("{0}|{{1,8}} {{2,8}} {{3,8}} {{4,8}}|\n", cntFmt); var lineFmt = string.Format("{0}|{{1,8}} {{2,8}} {{3,8}} {{4,8}}|\n", frameCount);
var footerFmt = string.Format("{0}+--------+--------+--------+--------+", spFmt); var footerFmt = string.Format("{0}+--------+--------+--------+--------+", spFmt);
var output = new StringBuilder(64); var output = new StringBuilder(64);
@ -322,13 +325,13 @@ namespace EonaCat.Network
}; };
var printLine = linePrinter(); var printLine = linePrinter();
output.AppendFormat(headerFmt, string.Empty); output.AppendFormat(headerFormat, string.Empty);
var bytes = frame.ToArray(); var bytes = frame.ToArray();
for (long i = 0; i <= cnt; i++) for (long i = 0; i <= amount; i++)
{ {
var j = i * 4; var j = i * 4;
if (i < cnt) if (i < amount)
{ {
printLine( printLine(
Convert.ToString(bytes[j], 2).PadLeft(8, '0'), Convert.ToString(bytes[j], 2).PadLeft(8, '0'),
@ -339,12 +342,12 @@ namespace EonaCat.Network
continue; continue;
} }
if (rem > 0) if (remainder > 0)
{ {
printLine( printLine(
Convert.ToString(bytes[j], 2).PadLeft(8, '0'), Convert.ToString(bytes[j], 2).PadLeft(8, '0'),
rem >= 2 ? Convert.ToString(bytes[j + 1], 2).PadLeft(8, '0') : string.Empty, remainder >= 2 ? Convert.ToString(bytes[j + 1], 2).PadLeft(8, '0') : string.Empty,
rem == 3 ? Convert.ToString(bytes[j + 2], 2).PadLeft(8, '0') : string.Empty, remainder == 3 ? Convert.ToString(bytes[j + 2], 2).PadLeft(8, '0') : string.Empty,
string.Empty); string.Empty);
} }
} }
@ -353,7 +356,7 @@ namespace EonaCat.Network
return output.ToString(); return output.ToString();
} }
private static string print(WSFrame frame) private static string Print(WSFrame frame)
{ {
// Payload Length // Payload Length
var payloadLen = frame.PayloadLength; var payloadLen = frame.PayloadLength;
@ -370,10 +373,10 @@ namespace EonaCat.Network
: payloadLen > 125 : payloadLen > 125
? "---" ? "---"
: frame.IsText && !(frame.IsFragment || frame.IsMasked || frame.IsCompressed) : frame.IsText && !(frame.IsFragment || frame.IsMasked || frame.IsCompressed)
? frame.PayloadData.ApplicationData.UTF8Decode() ? frame.Payload.ApplicationData.UTF8Decode()
: frame.PayloadData.ToString(); : frame.Payload.ToString();
var fmt = @" var format = @"
FIN: {0} FIN: {0}
RSV1: {1} RSV1: {1}
RSV2: {2} RSV2: {2}
@ -386,7 +389,7 @@ Extended Payload Length: {7}
Payload Data: {9}"; Payload Data: {9}";
return string.Format( return string.Format(
fmt, format,
frame.Fin, frame.Fin,
frame.Rsv1, frame.Rsv1,
frame.Rsv2, frame.Rsv2,
@ -399,7 +402,7 @@ Extended Payload Length: {7}
payload); payload);
} }
private static WSFrame processHeader(byte[] header) private static WSFrame ProcessHeader(byte[] header)
{ {
if (header.Length != 2) if (header.Length != 2)
{ {
@ -410,13 +413,13 @@ Extended Payload Length: {7}
var fin = (header[0] & 0x80) == 0x80 ? FinalFrame.Final : FinalFrame.More; var fin = (header[0] & 0x80) == 0x80 ? FinalFrame.Final : FinalFrame.More;
// RSV1 // RSV1
var rsv1 = (header[0] & 0x40) == 0x40 ? Rsv.On : Rsv.Off; var rsv1 = (header[0] & 0x40) == 0x40 ? ReservedBits.On : ReservedBits.Off;
// RSV2 // RSV2
var rsv2 = (header[0] & 0x20) == 0x20 ? Rsv.On : Rsv.Off; var rsv2 = (header[0] & 0x20) == 0x20 ? ReservedBits.On : ReservedBits.Off;
// RSV3 // RSV3
var rsv3 = (header[0] & 0x10) == 0x10 ? Rsv.On : Rsv.Off; var rsv3 = (header[0] & 0x10) == 0x10 ? ReservedBits.On : ReservedBits.Off;
// Opcode // Opcode
var opcode = (byte)(header[0] & 0x0f); var opcode = (byte)(header[0] & 0x0f);
@ -429,7 +432,7 @@ Extended Payload Length: {7}
var err = !opcode.IsSupported() var err = !opcode.IsSupported()
? "An unsupported opcode." ? "An unsupported opcode."
: !opcode.IsData() && rsv1 == Rsv.On : !opcode.IsData() && rsv1 == ReservedBits.On
? "A non data frame is compressed." ? "A non data frame is compressed."
: opcode.IsControl() && fin == FinalFrame.More : opcode.IsControl() && fin == FinalFrame.More
? "A control frame is fragmented." ? "A control frame is fragmented."
@ -507,13 +510,13 @@ Extended Payload Length: {7}
private static WSFrame readHeader(Stream stream) private static WSFrame readHeader(Stream stream)
{ {
return processHeader(stream.ReadBytes(2)); return ProcessHeader(stream.ReadBytes(2));
} }
private static void readHeaderAsync( private static void readHeaderAsync(
Stream stream, Action<WSFrame> completed, Action<Exception> error) Stream stream, Action<WSFrame> completed, Action<Exception> error)
{ {
stream.ReadBytesAsync(2, bytes => completed(processHeader(bytes)), error); stream.ReadBytesAsync(2, bytes => completed(ProcessHeader(bytes)), error);
} }
private static WSFrame readMaskingKey(Stream stream, WSFrame frame) private static WSFrame readMaskingKey(Stream stream, WSFrame frame)
@ -566,16 +569,16 @@ Extended Payload Length: {7}
error); error);
} }
private static WSFrame readPayloadData(Stream stream, WSFrame frame) private static WSFrame readPayload(Stream stream, WSFrame frame)
{ {
var len = frame.FullPayloadLength; var len = frame.FullPayloadLength;
if (len == 0) if (len == 0)
{ {
frame.PayloadData = PayloadData.Empty; frame.Payload = Payload.Empty;
return frame; return frame;
} }
if (len > PayloadData.MaxLength) if (len > Payload.MaxLength)
{ {
throw new WSException(CloseStatusCode.TooBig, "A frame has a long payload length."); throw new WSException(CloseStatusCode.TooBig, "A frame has a long payload length.");
} }
@ -591,11 +594,11 @@ Extended Payload Length: {7}
"The payload data of a frame cannot be read from the stream."); "The payload data of a frame cannot be read from the stream.");
} }
frame.PayloadData = new PayloadData(bytes, llen); frame.Payload = new Payload(bytes, llen);
return frame; return frame;
} }
private static void readPayloadDataAsync( private static void readPayloadAsync(
Stream stream, Stream stream,
WSFrame frame, WSFrame frame,
Action<WSFrame> completed, Action<WSFrame> completed,
@ -604,13 +607,13 @@ Extended Payload Length: {7}
var len = frame.FullPayloadLength; var len = frame.FullPayloadLength;
if (len == 0) if (len == 0)
{ {
frame.PayloadData = PayloadData.Empty; frame.Payload = Payload.Empty;
completed(frame); completed(frame);
return; return;
} }
if (len > PayloadData.MaxLength) if (len > Payload.MaxLength)
{ {
throw new WSException(CloseStatusCode.TooBig, "A frame has a long payload length."); throw new WSException(CloseStatusCode.TooBig, "A frame has a long payload length.");
} }
@ -624,7 +627,7 @@ Extended Payload Length: {7}
"The payload data of a frame cannot be read from the stream."); "The payload data of a frame cannot be read from the stream.");
} }
frame.PayloadData = new PayloadData(bytes, llen); frame.Payload = new Payload(bytes, llen);
completed(frame); completed(frame);
}; };

View File

@ -15,6 +15,7 @@ namespace EonaCat.Network
internal byte[] EntityBodyData; internal byte[] EntityBodyData;
protected const string CrLf = "\r\n"; protected const string CrLf = "\r\n";
private const int _headersMaxLength = 8192; private const int _headersMaxLength = 8192;
protected WebBase(Version version, NameValueCollection headers) protected WebBase(Version version, NameValueCollection headers)
{ {
ProtocolVersion = version; ProtocolVersion = version;

View File

@ -4,7 +4,6 @@
using System; using System;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.IO; using System.IO;
using System.Reflection;
using System.Text; using System.Text;
namespace EonaCat.Network namespace EonaCat.Network
@ -26,6 +25,7 @@ namespace EonaCat.Network
HttpMethod = method; HttpMethod = method;
RequestUri = uri; RequestUri = uri;
} }
public AuthenticationResponse AuthenticationResponse public AuthenticationResponse AuthenticationResponse
{ {
get get

View File

@ -4,7 +4,6 @@
using System; using System;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.IO; using System.IO;
using System.Reflection;
using System.Text; using System.Text;
namespace EonaCat.Network namespace EonaCat.Network
@ -28,6 +27,7 @@ namespace EonaCat.Network
StatusCode = code; StatusCode = code;
Reason = reason; Reason = reason;
} }
public CookieCollection Cookies => Headers.GetCookies(true); public CookieCollection Cookies => Headers.GetCookies(true);
public bool HasConnectionClose => Headers.Contains("Connection", "close"); public bool HasConnectionClose => Headers.Contains("Connection", "close");

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;

View File

@ -40,32 +40,32 @@ namespace EonaCat.Network
_Routes = routes; _Routes = routes;
} }
internal async Task Process(HttpContext ctx, CancellationToken token) internal async Task Process(HttpContext context, CancellationToken token)
{ {
if (ctx == null) if (context == null)
{ {
throw new ArgumentNullException(nameof(ctx)); throw new ArgumentNullException(nameof(context));
} }
if (ctx.Request == null) if (context.Request == null)
{ {
throw new ArgumentNullException(nameof(ctx.Request)); throw new ArgumentNullException(nameof(context.Request));
} }
if (ctx.Response == null) if (context.Response == null)
{ {
throw new ArgumentNullException(nameof(ctx.Response)); throw new ArgumentNullException(nameof(context.Response));
} }
if (ctx.Request.Method != HttpMethod.GET if (context.Request.Method != HttpMethod.GET
&& ctx.Request.Method != HttpMethod.HEAD) && context.Request.Method != HttpMethod.HEAD)
{ {
Set500Response(ctx); Set500Response(context);
await ctx.Response.Send(token).ConfigureAwait(false); await context.Response.Send(token).ConfigureAwait(false);
return; return;
} }
string filePath = ctx.Request.Url.RawWithoutQuery; string filePath = context.Request.Url.RawWithoutQuery;
if (!string.IsNullOrEmpty(filePath)) if (!string.IsNullOrEmpty(filePath))
{ {
while (filePath.StartsWith("/")) while (filePath.StartsWith("/"))
@ -88,35 +88,35 @@ namespace EonaCat.Network
if (!File.Exists(filePath)) if (!File.Exists(filePath))
{ {
Set404Response(ctx); Set404Response(context);
await ctx.Response.Send(token).ConfigureAwait(false); await context.Response.Send(token).ConfigureAwait(false);
return; return;
} }
FileInfo fi = new FileInfo(filePath); FileInfo fi = new FileInfo(filePath);
long contentLength = fi.Length; long contentLength = fi.Length;
if (ctx.Request.Method == HttpMethod.GET) if (context.Request.Method == HttpMethod.GET)
{ {
FileStream fs = new FileStream(filePath, ContentFileMode, ContentFileAccess, ContentFileShare); FileStream fs = new FileStream(filePath, ContentFileMode, ContentFileAccess, ContentFileShare);
ctx.Response.StatusCode = 200; context.Response.StatusCode = 200;
ctx.Response.ContentLength = contentLength; context.Response.ContentLength = contentLength;
ctx.Response.ContentType = GetContentType(filePath); context.Response.ContentType = GetContentType(filePath);
await ctx.Response.Send(contentLength, fs, token).ConfigureAwait(false); await context.Response.Send(contentLength, fs, token).ConfigureAwait(false);
return; return;
} }
else if (ctx.Request.Method == HttpMethod.HEAD) else if (context.Request.Method == HttpMethod.HEAD)
{ {
ctx.Response.StatusCode = 200; context.Response.StatusCode = 200;
ctx.Response.ContentLength = contentLength; context.Response.ContentLength = contentLength;
ctx.Response.ContentType = GetContentType(filePath); context.Response.ContentType = GetContentType(filePath);
await ctx.Response.Send(contentLength, token).ConfigureAwait(false); await context.Response.Send(contentLength, token).ConfigureAwait(false);
return; return;
} }
else else
{ {
Set500Response(ctx); Set500Response(context);
await ctx.Response.Send(token).ConfigureAwait(false); await context.Response.Send(token).ConfigureAwait(false);
return; return;
} }
} }
@ -137,16 +137,16 @@ namespace EonaCat.Network
return "application/octet-stream"; return "application/octet-stream";
} }
private void Set404Response(HttpContext ctx) private void Set404Response(HttpContext context)
{ {
ctx.Response.StatusCode = 404; context.Response.StatusCode = 404;
ctx.Response.ContentLength = 0; context.Response.ContentLength = 0;
} }
private void Set500Response(HttpContext ctx) private void Set500Response(HttpContext context)
{ {
ctx.Response.StatusCode = 500; context.Response.StatusCode = 500;
ctx.Response.ContentLength = 0; context.Response.ContentLength = 0;
} }
} }
} }

View File

@ -129,7 +129,6 @@ namespace EonaCat.Network
throw new ArgumentNullException(nameof(rawUrl)); throw new ArgumentNullException(nameof(rawUrl));
} }
if (Matcher.Match( if (Matcher.Match(
BuildConsolidatedRegex(method, rawUrl), BuildConsolidatedRegex(method, rawUrl),
out object val)) out object val))

View File

@ -374,9 +374,9 @@ namespace EonaCat.Network
continue; continue;
} }
System.Net.HttpListenerContext listenerCtx = await _HttpListener.GetContextAsync().ConfigureAwait(false); System.Net.HttpListenerContext listenercontext = await _HttpListener.GetContextAsync().ConfigureAwait(false);
Interlocked.Increment(ref _RequestCount); Interlocked.Increment(ref _RequestCount);
HttpContext ctx = null; HttpContext context = null;
Task unawaited = Task.Run(async () => Task unawaited = Task.Run(async () =>
{ {
@ -385,49 +385,49 @@ namespace EonaCat.Network
try try
{ {
Events.HandleConnectionReceived(this, new ConnectionEventArgs( Events.HandleConnectionReceived(this, new ConnectionEventArgs(
listenerCtx.Request.RemoteEndPoint.Address.ToString(), listenercontext.Request.RemoteEndPoint.Address.ToString(),
listenerCtx.Request.RemoteEndPoint.Port)); listenercontext.Request.RemoteEndPoint.Port));
ctx = new HttpContext(listenerCtx, _Settings, Events); context = new HttpContext(listenercontext, _Settings, Events);
Events.HandleRequestReceived(this, new RequestEventArgs(ctx)); Events.HandleRequestReceived(this, new RequestEventArgs(context));
if (_Settings.Debug.Requests) if (_Settings.Debug.Requests)
{ {
Events.Logger?.Invoke( Events.Logger?.Invoke(
_Header + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + _Header + context.Request.Source.IpAddress + ":" + context.Request.Source.Port + " " +
ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); context.Request.Method.ToString() + " " + context.Request.Url.RawWithoutQuery);
} }
Statistics.IncrementRequestCounter(ctx.Request.Method); Statistics.IncrementRequestCounter(context.Request.Method);
Statistics.IncrementReceivedPayloadBytes(ctx.Request.ContentLength); Statistics.IncrementReceivedPayloadBytes(context.Request.ContentLength);
if (!_Settings.AccessControl.Permit(ctx.Request.Source.IpAddress)) if (!_Settings.AccessControl.Permit(context.Request.Source.IpAddress))
{ {
Events.HandleRequestDenied(this, new RequestEventArgs(ctx)); Events.HandleRequestDenied(this, new RequestEventArgs(context));
if (_Settings.Debug.AccessControl) if (_Settings.Debug.AccessControl)
{ {
Events.Logger?.Invoke(_Header + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " denied due to access control"); Events.Logger?.Invoke(_Header + context.Request.Source.IpAddress + ":" + context.Request.Source.Port + " denied due to access control");
} }
listenerCtx.Response.StatusCode = 403; listenercontext.Response.StatusCode = 403;
listenerCtx.Response.Close(); listenercontext.Response.Close();
return; return;
} }
if (ctx.Request.Method == HttpMethod.OPTIONS) if (context.Request.Method == HttpMethod.OPTIONS)
{ {
if (_Routes.Preflight != null) if (_Routes.Preflight != null)
{ {
if (_Settings.Debug.Routing) if (_Settings.Debug.Routing)
{ {
Events.Logger?.Invoke( Events.Logger?.Invoke(
_Header + "preflight route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + _Header + "preflight route for " + context.Request.Source.IpAddress + ":" + context.Request.Source.Port + " " +
ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); context.Request.Method.ToString() + " " + context.Request.Url.RawWithoutQuery);
} }
await _Routes.Preflight(ctx).ConfigureAwait(false); await _Routes.Preflight(context).ConfigureAwait(false);
return; return;
} }
} }
@ -435,85 +435,85 @@ namespace EonaCat.Network
bool terminate = false; bool terminate = false;
if (_Routes.PreRouting != null) if (_Routes.PreRouting != null)
{ {
terminate = await _Routes.PreRouting(ctx).ConfigureAwait(false); terminate = await _Routes.PreRouting(context).ConfigureAwait(false);
if (terminate) if (terminate)
{ {
if (_Settings.Debug.Routing) if (_Settings.Debug.Routing)
{ {
Events.Logger?.Invoke( Events.Logger?.Invoke(
_Header + "prerouting terminated connection for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + _Header + "prerouting terminated connection for " + context.Request.Source.IpAddress + ":" + context.Request.Source.Port + " " +
ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); context.Request.Method.ToString() + " " + context.Request.Url.RawWithoutQuery);
} }
return; return;
} }
} }
if (ctx.Request.Method == HttpMethod.GET || ctx.Request.Method == HttpMethod.HEAD) if (context.Request.Method == HttpMethod.GET || context.Request.Method == HttpMethod.HEAD)
{ {
if (_Routes.Content.Match(ctx.Request.Url.RawWithoutQuery, out ContentRoute cr)) if (_Routes.Content.Match(context.Request.Url.RawWithoutQuery, out ContentRoute cr))
{ {
if (_Settings.Debug.Routing) if (_Settings.Debug.Routing)
{ {
Events.Logger?.Invoke( Events.Logger?.Invoke(
_Header + "content route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + _Header + "content route for " + context.Request.Source.IpAddress + ":" + context.Request.Source.Port + " " +
ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); context.Request.Method.ToString() + " " + context.Request.Url.RawWithoutQuery);
} }
ctx.RouteType = RouteTypeEnum.Content; context.RouteType = RouteTypeEnum.Content;
ctx.Route = cr; context.Route = cr;
await _Routes.ContentHandler.Process(ctx, token).ConfigureAwait(false); await _Routes.ContentHandler.Process(context, token).ConfigureAwait(false);
return; return;
} }
} }
Func<HttpContext, Task> handler = _Routes.Static.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out StaticRoute sr); Func<HttpContext, Task> handler = _Routes.Static.Match(context.Request.Method, context.Request.Url.RawWithoutQuery, out StaticRoute sr);
if (handler != null) if (handler != null)
{ {
if (_Settings.Debug.Routing) if (_Settings.Debug.Routing)
{ {
Events.Logger?.Invoke( Events.Logger?.Invoke(
_Header + "static route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + _Header + "static route for " + context.Request.Source.IpAddress + ":" + context.Request.Source.Port + " " +
ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); context.Request.Method.ToString() + " " + context.Request.Url.RawWithoutQuery);
} }
ctx.RouteType = RouteTypeEnum.Static; context.RouteType = RouteTypeEnum.Static;
ctx.Route = sr; context.Route = sr;
await handler(ctx).ConfigureAwait(false); await handler(context).ConfigureAwait(false);
return; return;
} }
handler = _Routes.Parameter.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out Dictionary<string, string> parameters, out ParameterRoute pr); handler = _Routes.Parameter.Match(context.Request.Method, context.Request.Url.RawWithoutQuery, out Dictionary<string, string> parameters, out ParameterRoute pr);
if (handler != null) if (handler != null)
{ {
ctx.Request.Url.Parameters = new Dictionary<string, string>(parameters); context.Request.Url.Parameters = new Dictionary<string, string>(parameters);
if (_Settings.Debug.Routing) if (_Settings.Debug.Routing)
{ {
Events.Logger?.Invoke( Events.Logger?.Invoke(
_Header + "parameter route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + _Header + "parameter route for " + context.Request.Source.IpAddress + ":" + context.Request.Source.Port + " " +
ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); context.Request.Method.ToString() + " " + context.Request.Url.RawWithoutQuery);
} }
ctx.RouteType = RouteTypeEnum.Parameter; context.RouteType = RouteTypeEnum.Parameter;
ctx.Route = pr; context.Route = pr;
await handler(ctx).ConfigureAwait(false); await handler(context).ConfigureAwait(false);
return; return;
} }
handler = _Routes.Dynamic.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out DynamicRoute dr); handler = _Routes.Dynamic.Match(context.Request.Method, context.Request.Url.RawWithoutQuery, out DynamicRoute dr);
if (handler != null) if (handler != null)
{ {
if (_Settings.Debug.Routing) if (_Settings.Debug.Routing)
{ {
Events.Logger?.Invoke( Events.Logger?.Invoke(
_Header + "dynamic route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + _Header + "dynamic route for " + context.Request.Source.IpAddress + ":" + context.Request.Source.Port + " " +
ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); context.Request.Method.ToString() + " " + context.Request.Url.RawWithoutQuery);
} }
ctx.RouteType = RouteTypeEnum.Dynamic; context.RouteType = RouteTypeEnum.Dynamic;
ctx.Route = dr; context.Route = dr;
await handler(ctx).ConfigureAwait(false); await handler(context).ConfigureAwait(false);
return; return;
} }
@ -522,12 +522,12 @@ namespace EonaCat.Network
if (_Settings.Debug.Routing) if (_Settings.Debug.Routing)
{ {
Events.Logger?.Invoke( Events.Logger?.Invoke(
_Header + "default route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + _Header + "default route for " + context.Request.Source.IpAddress + ":" + context.Request.Source.Port + " " +
ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); context.Request.Method.ToString() + " " + context.Request.Url.RawWithoutQuery);
} }
ctx.RouteType = RouteTypeEnum.Default; context.RouteType = RouteTypeEnum.Default;
await _Routes.Default(ctx).ConfigureAwait(false); await _Routes.Default(context).ConfigureAwait(false);
return; return;
} }
else else
@ -535,31 +535,31 @@ namespace EonaCat.Network
if (_Settings.Debug.Routing) if (_Settings.Debug.Routing)
{ {
Events.Logger?.Invoke( Events.Logger?.Invoke(
_Header + "default route not found for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " + _Header + "default route not found for " + context.Request.Source.IpAddress + ":" + context.Request.Source.Port + " " +
ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery); context.Request.Method.ToString() + " " + context.Request.Url.RawWithoutQuery);
} }
ctx.Response.StatusCode = 404; context.Response.StatusCode = 404;
ctx.Response.ContentType = Pages.Default404Page.ContentType; context.Response.ContentType = Pages.Default404Page.ContentType;
await ctx.Response.Send(Pages.Default404Page.Content).ConfigureAwait(false); await context.Response.Send(Pages.Default404Page.Content).ConfigureAwait(false);
return; return;
} }
} }
catch (Exception eInner) catch (Exception eInner)
{ {
ctx.Response.StatusCode = 500; context.Response.StatusCode = 500;
ctx.Response.ContentType = Pages.Default500Page.ContentType; context.Response.ContentType = Pages.Default500Page.ContentType;
await ctx.Response.Send(Pages.Default500Page.Content).ConfigureAwait(false); await context.Response.Send(Pages.Default500Page.Content).ConfigureAwait(false);
Events.HandleExceptionEncountered(this, new ExceptionEventArgs(ctx, eInner)); Events.HandleExceptionEncountered(this, new ExceptionEventArgs(context, eInner));
} }
finally finally
{ {
Interlocked.Decrement(ref _RequestCount); Interlocked.Decrement(ref _RequestCount);
if (ctx != null && ctx.Response != null && ctx.Response.ResponseSent) if (context != null && context.Response != null && context.Response.ResponseSent)
{ {
Events.HandleResponseSent(this, new ResponseEventArgs(ctx, TotalMsFrom(startTime))); Events.HandleResponseSent(this, new ResponseEventArgs(context, TotalMsFrom(startTime)));
Statistics.IncrementSentPayloadBytes(ctx.Response.ContentLength); Statistics.IncrementSentPayloadBytes(context.Response.ContentLength);
} }
} }
}, token); }, token);

View File

@ -184,14 +184,14 @@ namespace EonaCat.Network
_ContentHandler = new ContentRouteHandler(_Content); _ContentHandler = new ContentRouteHandler(_Content);
} }
private async Task PreflightInternal(HttpContext ctx) private async Task PreflightInternal(HttpContext context)
{ {
ctx.Response.StatusCode = 200; context.Response.StatusCode = 200;
string[] requestedHeaders = null; string[] requestedHeaders = null;
if (ctx.Request.Headers != null) if (context.Request.Headers != null)
{ {
foreach (KeyValuePair<string, string> curr in ctx.Request.Headers) foreach (KeyValuePair<string, string> curr in context.Request.Headers)
{ {
if (string.IsNullOrEmpty(curr.Key)) if (string.IsNullOrEmpty(curr.Key))
{ {
@ -235,11 +235,11 @@ namespace EonaCat.Network
foreach (KeyValuePair<string, string> header in _Settings.Headers) foreach (KeyValuePair<string, string> header in _Settings.Headers)
{ {
ctx.Response.Headers.Add(header.Key, header.Value); context.Response.Headers.Add(header.Key, header.Value);
} }
ctx.Response.ContentLength = 0; context.Response.ContentLength = 0;
await ctx.Response.Send().ConfigureAwait(false); await context.Response.Send().ConfigureAwait(false);
} }
} }
} }

View File

@ -82,19 +82,19 @@ namespace EonaCat.Network
} }
} }
internal ExceptionEventArgs(HttpContext ctx, Exception e) internal ExceptionEventArgs(HttpContext context, Exception e)
{ {
if (ctx != null) if (context != null)
{ {
Ip = ctx.Request.Source.IpAddress; Ip = context.Request.Source.IpAddress;
Port = ctx.Request.Source.Port; Port = context.Request.Source.Port;
Method = ctx.Request.Method; Method = context.Request.Method;
Url = ctx.Request.Url.Full; Url = context.Request.Url.Full;
Query = ctx.Request.Query.Elements; Query = context.Request.Query.Elements;
RequestHeaders = ctx.Request.Headers; RequestHeaders = context.Request.Headers;
RequestContentLength = ctx.Request.ContentLength; RequestContentLength = context.Request.ContentLength;
StatusCode = ctx.Response.StatusCode; StatusCode = context.Response.StatusCode;
ResponseContentLength = ctx.Response.ContentLength; ResponseContentLength = context.Response.ContentLength;
} }
Exception = e; Exception = e;

View File

@ -46,15 +46,15 @@ namespace EonaCat.Network
/// </summary> /// </summary>
public long ContentLength { get; private set; } = 0; public long ContentLength { get; private set; } = 0;
internal RequestEventArgs(HttpContext ctx) internal RequestEventArgs(HttpContext context)
{ {
Ip = ctx.Request.Source.IpAddress; Ip = context.Request.Source.IpAddress;
Port = ctx.Request.Source.Port; Port = context.Request.Source.Port;
Method = ctx.Request.Method; Method = context.Request.Method;
Url = ctx.Request.Url.Full; Url = context.Request.Url.Full;
Query = ctx.Request.Query.Elements; Query = context.Request.Query.Elements;
Headers = ctx.Request.Headers; Headers = context.Request.Headers;
ContentLength = ctx.Request.ContentLength; ContentLength = context.Request.ContentLength;
} }
} }
} }

View File

@ -66,17 +66,17 @@ namespace EonaCat.Network
/// </summary> /// </summary>
public double TotalMs { get; private set; } = 0; public double TotalMs { get; private set; } = 0;
internal ResponseEventArgs(HttpContext ctx, double totalMs) internal ResponseEventArgs(HttpContext context, double totalMs)
{ {
Ip = ctx.Request.Source.IpAddress; Ip = context.Request.Source.IpAddress;
Port = ctx.Request.Source.Port; Port = context.Request.Source.Port;
Method = ctx.Request.Method; Method = context.Request.Method;
Url = ctx.Request.Url.Full; Url = context.Request.Url.Full;
Query = ctx.Request.Query.Elements; Query = context.Request.Query.Elements;
RequestHeaders = ctx.Request.Headers; RequestHeaders = context.Request.Headers;
RequestContentLength = ctx.Request.ContentLength; RequestContentLength = context.Request.ContentLength;
StatusCode = ctx.Response.StatusCode; StatusCode = context.Response.StatusCode;
ResponseContentLength = ctx.Response.ContentLength; ResponseContentLength = context.Response.ContentLength;
TotalMs = totalMs; TotalMs = totalMs;
} }
} }

View File

@ -50,11 +50,11 @@ namespace EonaCat.Network
{ {
} }
internal HttpContext(System.Net.HttpListenerContext ctx, EonaCatWebserverSettings settings, EonaCatWebserverEvents events) internal HttpContext(System.Net.HttpListenerContext context, EonaCatWebserverSettings settings, EonaCatWebserverEvents events)
{ {
if (ctx == null) if (context == null)
{ {
throw new ArgumentNullException(nameof(ctx)); throw new ArgumentNullException(nameof(context));
} }
if (events == null) if (events == null)
@ -62,9 +62,9 @@ namespace EonaCat.Network
throw new ArgumentNullException(nameof(events)); throw new ArgumentNullException(nameof(events));
} }
_Context = ctx; _Context = context;
Request = new HttpRequest(ctx); Request = new HttpRequest(context);
Response = new HttpResponse(Request, ctx, settings, events); Response = new HttpResponse(Request, context, settings, events);
} }
} }
} }

View File

@ -182,41 +182,41 @@ namespace EonaCat.Network
/// HTTP request. /// HTTP request.
/// Instantiate the object using an HttpListenerContext. /// Instantiate the object using an HttpListenerContext.
/// </summary> /// </summary>
/// <param name="ctx">HttpListenerContext.</param> /// <param name="context">HttpListenerContext.</param>
public HttpRequest(System.Net.HttpListenerContext ctx) public HttpRequest(System.Net.HttpListenerContext context)
{ {
if (ctx == null) if (context == null)
{ {
throw new ArgumentNullException(nameof(ctx)); throw new ArgumentNullException(nameof(context));
} }
if (ctx.Request == null) if (context.Request == null)
{ {
throw new ArgumentNullException(nameof(ctx.Request)); throw new ArgumentNullException(nameof(context.Request));
} }
ListenerContext = ctx; ListenerContext = context;
Keepalive = ctx.Request.KeepAlive; Keepalive = context.Request.KeepAlive;
ContentLength = ctx.Request.ContentLength64; ContentLength = context.Request.ContentLength64;
Useragent = ctx.Request.UserAgent; Useragent = context.Request.UserAgent;
ContentType = ctx.Request.ContentType; ContentType = context.Request.ContentType;
_Uri = new Uri(ctx.Request.Url.ToString().Trim()); _Uri = new Uri(context.Request.Url.ToString().Trim());
ThreadId = Thread.CurrentThread.ManagedThreadId; ThreadId = Thread.CurrentThread.ManagedThreadId;
TimestampUtc = DateTime.Now.ToUniversalTime(); TimestampUtc = DateTime.Now.ToUniversalTime();
ProtocolVersion = "HTTP/" + ctx.Request.ProtocolVersion.ToString(); ProtocolVersion = "HTTP/" + context.Request.ProtocolVersion.ToString();
Source = new SourceDetails(ctx.Request.RemoteEndPoint.Address.ToString(), ctx.Request.RemoteEndPoint.Port); Source = new SourceDetails(context.Request.RemoteEndPoint.Address.ToString(), context.Request.RemoteEndPoint.Port);
Destination = new DestinationDetails(ctx.Request.LocalEndPoint.Address.ToString(), ctx.Request.LocalEndPoint.Port, _Uri.Host); Destination = new DestinationDetails(context.Request.LocalEndPoint.Address.ToString(), context.Request.LocalEndPoint.Port, _Uri.Host);
Method = (HttpMethod)Enum.Parse(typeof(HttpMethod), ctx.Request.HttpMethod, true); Method = (HttpMethod)Enum.Parse(typeof(HttpMethod), context.Request.HttpMethod, true);
Url = new UrlDetails(ctx.Request.Url.ToString().Trim(), ctx.Request.RawUrl.ToString().Trim()); Url = new UrlDetails(context.Request.Url.ToString().Trim(), context.Request.RawUrl.ToString().Trim());
Query = new QueryDetails(Url.Full); Query = new QueryDetails(Url.Full);
Headers = new Dictionary<string, string>(); Headers = new Dictionary<string, string>();
for (int i = 0; i < ctx.Request.Headers.Count; i++) for (int i = 0; i < context.Request.Headers.Count; i++)
{ {
string key = ctx.Request.Headers.GetKey(i); string key = context.Request.Headers.GetKey(i);
string val = ctx.Request.Headers.Get(i); string val = context.Request.Headers.Get(i);
Headers = AddToDict(key, val, Headers); Headers = AddToDict(key, val, Headers);
} }
@ -258,7 +258,7 @@ namespace EonaCat.Network
} }
} }
Data = ctx.Request.InputStream; Data = context.Request.InputStream;
} }
/// <summary> /// <summary>

View File

@ -140,16 +140,16 @@ namespace EonaCat.Network
{ {
} }
internal HttpResponse(HttpRequest req, System.Net.HttpListenerContext ctx, EonaCatWebserverSettings settings, EonaCatWebserverEvents events) internal HttpResponse(HttpRequest httpRequest, System.Net.HttpListenerContext context, EonaCatWebserverSettings settings, EonaCatWebserverEvents events)
{ {
if (req == null) if (httpRequest == null)
{ {
throw new ArgumentNullException(nameof(req)); throw new ArgumentNullException(nameof(httpRequest));
} }
if (ctx == null) if (context == null)
{ {
throw new ArgumentNullException(nameof(ctx)); throw new ArgumentNullException(nameof(context));
} }
if (settings == null) if (settings == null)
@ -162,8 +162,8 @@ namespace EonaCat.Network
throw new ArgumentNullException(nameof(events)); throw new ArgumentNullException(nameof(events));
} }
_Request = req; _Request = httpRequest;
_Context = ctx; _Context = context;
_Response = _Context.Response; _Response = _Context.Response;
_Settings = settings; _Settings = settings;
_Events = events; _Events = events;