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);
// Start the client in the main thread
_client = new WSClient(clientUri);
_client.SSL.Certificates.Add(new X509Certificate(certificatePath, certificatePassword));
_client = new WSClient(clientUri, new X509Certificate(certificatePath, certificatePassword));
_client.OnConnect += (sender, e) => Console.WriteLine($"Connected to server");
_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}");

View File

@ -1,11 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace EonaCat.Network
namespace EonaCat.Network
{
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>
<PackageReleaseNotes></PackageReleaseNotes>
<Description>EonaCat Networking library with Quic, TCP, UDP, WebSockets and a Webserver</Description>
<Version>1.1.3</Version>
<AssemblyVersion>1.1.3</AssemblyVersion>
<FileVersion>1.1.3</FileVersion>
<Version>1.1.4</Version>
<AssemblyVersion>1.1.4</AssemblyVersion>
<FileVersion>1.1.4</FileVersion>
<PackageIcon>icon.png</PackageIcon>
</PropertyGroup>

View File

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

View File

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

View File

@ -1,5 +1,4 @@
using EonaCat.Quic.Streams;
using System;
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.
// 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.
// 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 System;
using System.Collections.Generic;
namespace EonaCat.Quic.Infrastructure.Frames

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,4 @@
using EonaCat.Quic.Helpers;
using System;
using System.Collections.Generic;
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.
// 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.Infrastructure.Frames;
using EonaCat.Quic.Infrastructure.Packets;
using System;
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.
// 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 System;
using System.Collections.Generic;
namespace EonaCat.Quic.Infrastructure.Packets

View File

@ -2,7 +2,6 @@
using EonaCat.Quic.Infrastructure.Exceptions;
using EonaCat.Quic.Infrastructure.Frames;
using EonaCat.Quic.Infrastructure.Settings;
using System;
using System.Collections.Generic;
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
{

View File

@ -5,6 +5,51 @@ namespace EonaCat.Network
{
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,
Away = 1001,
@ -25,10 +70,16 @@ namespace EonaCat.Network
TooBig = 1009,
MandatoryExtension = 1010,
MissingExtension = 1010,
ServerError = 1011,
ServiceRestart = 1012,
TryAgainLater = 1013,
BadGateway = 1014,
TlsHandshakeFailure = 1015
}
}

View File

@ -41,6 +41,7 @@ namespace EonaCat.Network
: base(scheme, parameters)
{
}
/// <summary>
/// Gets the domain for Digest authentication.
/// </summary>
@ -104,49 +105,32 @@ namespace EonaCat.Network
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()
{
var output = new StringBuilder(DIGEST_SIZE);
var realm = Parameters["realm"];
var nonce = Parameters["nonce"];
var domain = Parameters["domain"];
if (domain != null)
if (realm != null)
{
output.AppendFormat($"Digest realm=\"{Parameters["realm"]}\", domain=\"{domain}\", nonce=\"{Parameters["nonce"]}\"");
}
else
{
output.AppendFormat($"Digest realm=\"{Parameters["realm"]}\", nonce=\"{Parameters["nonce"]}\"");
}
output.AppendFormat("Digest realm=\"{0}\", nonce=\"{1}\"", realm, nonce);
var opaque = Parameters["opaque"];
if (opaque != null)
{
output.AppendFormat($", opaque=\"{opaque}\"");
}
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}\"");
AppendIfNotNull(output, "domain", Parameters["domain"]);
AppendIfNotNull(output, "opaque", Parameters["opaque"]);
AppendIfNotNull(output, "stale", Parameters["stale"]);
AppendIfNotNull(output, "algorithm", Parameters["algorithm"]);
AppendIfNotNull(output, "qop", Parameters["qop"]);
}
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)
{
}
/// <summary>
/// Gets the cnonce value for Digest authentication.
/// </summary>
@ -108,6 +109,7 @@ namespace EonaCat.Network
internal uint NonceCount => _nonceCount < uint.MaxValue
? _nonceCount
: 0;
/// <summary>
/// Converts the authentication response to an identity.
/// </summary>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,7 +5,6 @@ using EonaCat.Logger.SplunkServer;
using EonaCat.Logger.Syslog;
using System;
using System.Collections.Generic;
using System.Numerics;
namespace EonaCat.Network
{
@ -26,10 +25,11 @@ namespace EonaCat.Network
internal class Logger
{
private static readonly LogManager _logManager;
static Logger()
{
_logManager = new LogManager(new LoggerSettings { RemoveMessagePrefix = true });
_logManager.OnException += _logManager_OnException;
_logManager = new LogManager(new LoggerSettings());
_logManager.OnException += LogManager_OnException;
}
internal static bool DisableConsole { get; set; }
@ -37,6 +37,7 @@ namespace EonaCat.Network
internal static bool IsLoggingEnabled { get; set; }
internal static string LoggingDirectory { get; private set; }
private static bool HasBeenSetup { get; set; }
internal static void AddGrayLogServer(string hostname, int 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)
{
if (!IsLoggingEnabled)
{
return;
}
if (DisableConsole)
{
writeToConsole = false;
}
if (!HasBeenSetup)
{
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)
{
if (!IsLoggingEnabled)
{
return;
}
if (DisableConsole)
{
writeToConsole = false;
}
if (!HasBeenSetup)
{
Setup();
@ -169,7 +190,7 @@ namespace EonaCat.Network
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);
if (e.Exception != null)
@ -177,11 +198,12 @@ namespace EonaCat.Network
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)
{
if (!HasBeenSetup)
if (!IsLoggingEnabled)
{
Setup();
return;
}
if (DisableConsole)
@ -189,6 +211,11 @@ namespace EonaCat.Network
writeToConsole = false;
}
if (!HasBeenSetup)
{
Setup();
}
if (grayLogSettings != null)
{
_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 LocalCertificateSelectionCallback ClientCertificateSelectionCallback
{
get

View File

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

View File

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

View File

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

View File

@ -9,7 +9,7 @@ namespace EonaCat.Network
{
internal CloseEventArgs()
{
PayloadData = PayloadData.Empty;
Payload = Payload.Empty;
}
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)
{
PayloadData = new PayloadData(code, reason);
Payload = new Payload(code, reason);
}
internal CloseEventArgs(CloseStatusCode code, string reason)
@ -37,9 +37,24 @@ namespace EonaCat.Network
{
}
public ushort Code => PayloadData.Code;
public string Reason => PayloadData.Reason ?? string.Empty;
/// <summary>
/// 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; }
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 string _data;
private bool _dataSet;
internal MessageEventArgs(WSFrame frame)
{
Opcode = frame.Opcode;
_rawData = frame.PayloadData.ApplicationData;
_rawData = frame.Payload.ApplicationData;
}
internal MessageEventArgs(OperationCode opcode, byte[] rawData)
{
if ((ulong)rawData.LongLength > PayloadData.MaxLength)
if ((ulong)rawData.LongLength > Payload.MaxLength)
{
throw new WSException(CloseStatusCode.TooBig);
}
@ -39,6 +40,7 @@ namespace EonaCat.Network
public bool IsBinary => Opcode == OperationCode.Binary;
public bool IsPing => Opcode == OperationCode.Ping;
public bool IsText => Opcode == OperationCode.Text;
public byte[] RawData
{
get
@ -49,6 +51,7 @@ namespace EonaCat.Network
}
internal OperationCode Opcode { get; }
private void setData()
{
if (_dataSet)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -12,25 +12,26 @@ namespace EonaCat.Network
{
public class WSSessionManager
{
private readonly object _forSweep;
private const int _cleanupIntervalInMiliSeconds = 60000;
private readonly object _cleanLocker;
private readonly Dictionary<string, IWSSession> _sessions;
private readonly object _sync;
private readonly object _locker;
private volatile bool _clean;
private volatile ServerState _state;
private volatile bool _sweeping;
private System.Timers.Timer _sweepTimer;
private TimeSpan _waitTime;
private TimeSpan _responseWaitingTime;
internal WSSessionManager()
{
_clean = true;
_forSweep = new object();
_cleanLocker = new object();
_sessions = new Dictionary<string, IWSSession>();
_state = ServerState.Started;
_sync = ((ICollection)_sessions).SyncRoot;
_waitTime = TimeSpan.FromSeconds(1);
_locker = ((ICollection)_sessions).SyncRoot;
_responseWaitingTime = TimeSpan.FromSeconds(1);
setSweepTimer(60000);
setCleanupTimer(_cleanupIntervalInMiliSeconds);
}
public IEnumerable<string> ActiveIDs
@ -51,7 +52,7 @@ namespace EonaCat.Network
{
get
{
lock (_sync)
lock (_locker)
{
return _sessions.Count;
}
@ -67,7 +68,7 @@ namespace EonaCat.Network
return Enumerable.Empty<string>();
}
lock (_sync)
lock (_locker)
{
if (_state != ServerState.Start)
{
@ -108,7 +109,7 @@ namespace EonaCat.Network
return;
}
lock (_sync)
lock (_locker)
{
if (!canSet(out message))
{
@ -130,7 +131,7 @@ namespace EonaCat.Network
return Enumerable.Empty<IWSSession>();
}
lock (_sync)
lock (_locker)
{
if (_state != ServerState.Start)
{
@ -142,11 +143,11 @@ namespace EonaCat.Network
}
}
public TimeSpan WaitTime
internal TimeSpan ResponseWaitingTime
{
get
{
return _waitTime;
return _responseWaitingTime;
}
set
@ -162,7 +163,7 @@ namespace EonaCat.Network
return;
}
lock (_sync)
lock (_locker)
{
if (!canSet(out message))
{
@ -170,12 +171,13 @@ namespace EonaCat.Network
return;
}
_waitTime = value;
_responseWaitingTime = value;
}
}
}
internal ServerState State => _state;
public IWSSession this[string id]
{
get
@ -195,6 +197,7 @@ namespace EonaCat.Network
return session;
}
}
public void Broadcast(byte[] data)
{
if (_state != ServerState.Start)
@ -538,7 +541,7 @@ namespace EonaCat.Network
return;
}
lock (_forSweep)
lock (_cleanLocker)
{
if (_sweeping)
{
@ -556,7 +559,7 @@ namespace EonaCat.Network
break;
}
lock (_sync)
lock (_locker)
{
if (_state != ServerState.Start)
{
@ -602,7 +605,7 @@ namespace EonaCat.Network
internal string Add(IWSSession session)
{
lock (_sync)
lock (_locker)
{
if (_state != ServerState.Start)
{
@ -624,7 +627,7 @@ namespace EonaCat.Network
{
if (_state != ServerState.Start)
{
Logger.Error("The service is shutting down.");
Logger.Error("The endpoint is shutting down.");
break;
}
@ -640,7 +643,7 @@ namespace EonaCat.Network
{
if (_state != ServerState.Start)
{
Logger.Error("The service is shutting down.");
Logger.Error("The endpoint is shutting down.");
break;
}
@ -658,7 +661,7 @@ namespace EonaCat.Network
{
if (_state != ServerState.Start)
{
Logger.Error("The service is shutting down.");
Logger.Error("The endpoint is shutting down.");
break;
}
@ -671,7 +674,7 @@ namespace EonaCat.Network
internal bool Remove(string id)
{
lock (_sync)
lock (_locker)
{
return _sessions.Remove(id);
}
@ -679,7 +682,7 @@ namespace EonaCat.Network
internal void Start()
{
lock (_sync)
lock (_locker)
{
_sweepTimer.Enabled = _clean;
_state = ServerState.Start;
@ -690,11 +693,11 @@ namespace EonaCat.Network
{
if (code == (ushort)CloseStatusCode.NoStatus)
{ // == no status
stop(PayloadData.Empty, true);
stop(Payload.Empty, true);
return;
}
stop(new PayloadData(code, reason), !code.IsReserved());
stop(new Payload(code, reason), !code.IsReserved());
}
private static string createID()
@ -712,17 +715,14 @@ namespace EonaCat.Network
{
if (_state != ServerState.Start)
{
Logger.Error("The service is shutting down.");
Logger.Error("The endpoint is shutting down.");
break;
}
session.Context.WebSocket.Send(opcode, data, cache);
}
if (completed != null)
{
completed();
}
completed?.Invoke();
}
catch (Exception ex)
{
@ -745,17 +745,14 @@ namespace EonaCat.Network
{
if (_state != ServerState.Start)
{
Logger.Error("The service is shutting down.");
Logger.Error("The endpoint is shutting down.");
break;
}
session.Context.WebSocket.Send(opcode, stream, cache);
}
if (completed != null)
{
completed();
}
completed?.Invoke();
}
catch (Exception ex)
{
@ -789,21 +786,21 @@ namespace EonaCat.Network
private Dictionary<string, bool> broadping(byte[] frameAsBytes)
{
var ret = new Dictionary<string, bool>();
var result = new Dictionary<string, bool>();
foreach (var session in Sessions)
{
if (_state != ServerState.Start)
{
Logger.Error("The service is shutting down.");
Logger.Error("The endpoint is shutting down.");
break;
}
var res = session.Context.WebSocket.Ping(frameAsBytes, _waitTime);
ret.Add(session.ID, res);
var pingResult = session.Context.WebSocket.Ping(frameAsBytes, _responseWaitingTime);
result.Add(session.ID, pingResult);
}
return ret;
return result;
}
private bool canSet(out string message)
@ -812,38 +809,39 @@ namespace EonaCat.Network
if (_state == ServerState.Start)
{
message = "The service has already started.";
message = "The endpoint has already started.";
return false;
}
if (_state == ServerState.ShuttingDown)
{
message = "The service is shutting down.";
message = "The endpoint is shutting down.";
return false;
}
return true;
}
private void setSweepTimer(double interval)
private void setCleanupTimer(double interval)
{
_sweepTimer = new System.Timers.Timer(interval);
_sweepTimer.Elapsed += (sender, e) => Sweep();
}
private void stop(PayloadData payloadData, bool send)
private void stop(Payload payload, bool send)
{
var bytes = send
? WSFrame.CreateCloseFrame(payloadData, false).ToArray()
? WSFrame.CreateCloseFrame(payload, false).ToArray()
: null;
lock (_sync)
lock (_locker)
{
_state = ServerState.ShuttingDown;
_sweepTimer.Enabled = false;
foreach (var session in _sessions.Values.ToList())
{
session.Context.WebSocket.Close(payloadData, bytes);
session.Context.WebSocket.Close(payload, bytes);
}
_state = ServerState.Stop;
@ -859,7 +857,7 @@ namespace EonaCat.Network
return false;
}
lock (_sync)
lock (_locker)
{
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;
private const int BUFFER_SIZE = 1024;
static WSFrame()
{
EmptyPingBytes = CreatePingFrame(false).ToArray();
}
internal WSFrame(OperationCode opcode, PayloadData payloadData, bool mask)
: this(FinalFrame.Final, opcode, payloadData, false, mask)
internal WSFrame(OperationCode opcode, Payload payload, bool mask)
: this(FinalFrame.Final, opcode, payload, false, 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(
FinalFrame fin, OperationCode opcode, PayloadData payloadData, bool compressed, bool mask)
FinalFrame fin, OperationCode opcode, Payload payload, bool compressed, bool mask)
{
Fin = fin;
Rsv1 = opcode.IsData() && compressed ? Rsv.On : Rsv.Off;
Rsv2 = Rsv.Off;
Rsv3 = Rsv.Off;
Rsv1 = opcode.IsData() && compressed ? ReservedBits.On : ReservedBits.Off;
Rsv2 = ReservedBits.Off;
Rsv3 = ReservedBits.Off;
Opcode = opcode;
PayloadData = new PayloadData(payloadData);
Payload = new Payload(payload);
var len = PayloadData.Length;
var len = Payload.Length;
if (len < 126)
{
PayloadLength = (byte)len;
@ -58,8 +59,8 @@ namespace EonaCat.Network
if (mask)
{
Mask = Mask.On;
MaskingKey = createMaskingKey();
PayloadData.Mask(MaskingKey);
MaskingKey = CreateMaskingKey();
Payload.Mask(MaskingKey);
}
else
{
@ -71,11 +72,12 @@ namespace EonaCat.Network
private WSFrame()
{
}
public byte[] ExtendedPayloadLength { get; private set; }
public FinalFrame Fin { get; private set; }
public bool IsBinary => Opcode == OperationCode.Binary;
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 IsControl => Opcode >= OperationCode.Close;
public bool IsData => Opcode == OperationCode.Text || Opcode == OperationCode.Binary;
@ -85,15 +87,15 @@ namespace EonaCat.Network
public bool IsPing => Opcode == OperationCode.Ping;
public bool IsPong => Opcode == OperationCode.Pong;
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 byte[] MaskingKey { 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 Rsv Rsv1 { get; private set; }
public Rsv Rsv2 { get; private set; }
public Rsv Rsv3 { get; private set; }
public ReservedBits Rsv1 { get; private set; }
public ReservedBits Rsv2 { get; private set; }
public ReservedBits Rsv3 { get; private set; }
internal int ExtendedPayloadLengthCount => PayloadLength < 126 ? 0 : (PayloadLength == 126 ? 2 : 8);
internal ulong FullPayloadLength => PayloadLength < 126
@ -101,6 +103,7 @@ namespace EonaCat.Network
: PayloadLength == 126
? ExtendedPayloadLength.ToUInt16(ByteOrder.Big)
: ExtendedPayloadLength.ToUInt64(ByteOrder.Big);
public IEnumerator<byte> GetEnumerator()
{
foreach (var b in ToArray())
@ -116,12 +119,12 @@ namespace EonaCat.Network
public void Print(bool dumped)
{
Console.WriteLine(dumped ? dump(this) : print(this));
Console.WriteLine(dumped ? Dump(this) : Print(this));
}
public string PrintToString(bool dumped)
{
return dumped ? dump(this) : print(this);
return dumped ? Dump(this) : Print(this);
}
public byte[] ToArray()
@ -149,7 +152,7 @@ namespace EonaCat.Network
if (PayloadLength > 0)
{
var bytes = PayloadData.ToArray();
var bytes = Payload.ToArray();
if (PayloadLength < 127)
{
buff.Write(bytes, 0, bytes.Length);
@ -171,34 +174,34 @@ namespace EonaCat.Network
}
internal static WSFrame CreateCloseFrame(
PayloadData payloadData, bool mask
Payload payload, bool mask
)
{
return new WSFrame(
FinalFrame.Final, OperationCode.Close, payloadData, false, mask
FinalFrame.Final, OperationCode.Close, payload, false, mask
);
}
internal static WSFrame CreatePingFrame(bool mask)
{
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)
{
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(
PayloadData payloadData, bool mask
Payload payload, bool mask
)
{
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);
readExtendedPayloadLength(stream, frame);
readMaskingKey(stream, frame);
readPayloadData(stream, frame);
readPayload(stream, frame);
if (unmask)
{
@ -235,7 +238,7 @@ namespace EonaCat.Network
stream,
frame1,
frame2 =>
readPayloadDataAsync(
readPayloadAsync(
stream,
frame2,
frame3 =>
@ -265,11 +268,11 @@ namespace EonaCat.Network
}
Mask = Mask.Off;
PayloadData.Mask(MaskingKey);
Payload.Mask(MaskingKey);
MaskingKey = WSClient.EmptyBytes;
}
private static byte[] createMaskingKey()
private static byte[] CreateMaskingKey()
{
var key = new byte[4];
WSClient.RandomNumber.GetBytes(key);
@ -277,40 +280,40 @@ namespace EonaCat.Network
return key;
}
private static string dump(WSFrame frame)
private static string Dump(WSFrame frame)
{
var len = frame.Length;
var cnt = (long)(len / 4);
var rem = (int)(len % 4);
var amount = (long)(len / 4);
var remainder = (int)(len % 4);
int cntDigit;
string cntFmt;
if (cnt < 10000)
int digitAmount;
string frameCount;
if (amount < 10000)
{
cntDigit = 4;
cntFmt = "{0,4}";
digitAmount = 4;
frameCount = "{0,4}";
}
else if (cnt < 0x010000)
else if (amount < 0x010000)
{
cntDigit = 4;
cntFmt = "{0,4:X}";
digitAmount = 4;
frameCount = "{0,4:X}";
}
else if (cnt < 0x0100000000)
else if (amount < 0x0100000000)
{
cntDigit = 8;
cntFmt = "{0,8:X}";
digitAmount = 8;
frameCount = "{0,8:X}";
}
else
{
cntDigit = 16;
cntFmt = "{0,16:X}";
digitAmount = 16;
frameCount = "{0,16:X}";
}
var spFmt = string.Format("{{0,{0}}}", cntDigit);
var headerFmt = string.Format(@"
var spFmt = string.Format("{{0,{0}}}", digitAmount);
var headerFormat = string.Format(@"
{0} 01234567 89ABCDEF 01234567 89ABCDEF
{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 output = new StringBuilder(64);
@ -322,13 +325,13 @@ namespace EonaCat.Network
};
var printLine = linePrinter();
output.AppendFormat(headerFmt, string.Empty);
output.AppendFormat(headerFormat, string.Empty);
var bytes = frame.ToArray();
for (long i = 0; i <= cnt; i++)
for (long i = 0; i <= amount; i++)
{
var j = i * 4;
if (i < cnt)
if (i < amount)
{
printLine(
Convert.ToString(bytes[j], 2).PadLeft(8, '0'),
@ -339,12 +342,12 @@ namespace EonaCat.Network
continue;
}
if (rem > 0)
if (remainder > 0)
{
printLine(
Convert.ToString(bytes[j], 2).PadLeft(8, '0'),
rem >= 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 >= 2 ? Convert.ToString(bytes[j + 1], 2).PadLeft(8, '0') : string.Empty,
remainder == 3 ? Convert.ToString(bytes[j + 2], 2).PadLeft(8, '0') : string.Empty,
string.Empty);
}
}
@ -353,7 +356,7 @@ namespace EonaCat.Network
return output.ToString();
}
private static string print(WSFrame frame)
private static string Print(WSFrame frame)
{
// Payload Length
var payloadLen = frame.PayloadLength;
@ -370,10 +373,10 @@ namespace EonaCat.Network
: payloadLen > 125
? "---"
: frame.IsText && !(frame.IsFragment || frame.IsMasked || frame.IsCompressed)
? frame.PayloadData.ApplicationData.UTF8Decode()
: frame.PayloadData.ToString();
? frame.Payload.ApplicationData.UTF8Decode()
: frame.Payload.ToString();
var fmt = @"
var format = @"
FIN: {0}
RSV1: {1}
RSV2: {2}
@ -386,7 +389,7 @@ Extended Payload Length: {7}
Payload Data: {9}";
return string.Format(
fmt,
format,
frame.Fin,
frame.Rsv1,
frame.Rsv2,
@ -399,7 +402,7 @@ Extended Payload Length: {7}
payload);
}
private static WSFrame processHeader(byte[] header)
private static WSFrame ProcessHeader(byte[] header)
{
if (header.Length != 2)
{
@ -410,13 +413,13 @@ Extended Payload Length: {7}
var fin = (header[0] & 0x80) == 0x80 ? FinalFrame.Final : FinalFrame.More;
// RSV1
var rsv1 = (header[0] & 0x40) == 0x40 ? Rsv.On : Rsv.Off;
var rsv1 = (header[0] & 0x40) == 0x40 ? ReservedBits.On : ReservedBits.Off;
// RSV2
var rsv2 = (header[0] & 0x20) == 0x20 ? Rsv.On : Rsv.Off;
var rsv2 = (header[0] & 0x20) == 0x20 ? ReservedBits.On : ReservedBits.Off;
// RSV3
var rsv3 = (header[0] & 0x10) == 0x10 ? Rsv.On : Rsv.Off;
var rsv3 = (header[0] & 0x10) == 0x10 ? ReservedBits.On : ReservedBits.Off;
// Opcode
var opcode = (byte)(header[0] & 0x0f);
@ -429,7 +432,7 @@ Extended Payload Length: {7}
var err = !opcode.IsSupported()
? "An unsupported opcode."
: !opcode.IsData() && rsv1 == Rsv.On
: !opcode.IsData() && rsv1 == ReservedBits.On
? "A non data frame is compressed."
: opcode.IsControl() && fin == FinalFrame.More
? "A control frame is fragmented."
@ -507,13 +510,13 @@ Extended Payload Length: {7}
private static WSFrame readHeader(Stream stream)
{
return processHeader(stream.ReadBytes(2));
return ProcessHeader(stream.ReadBytes(2));
}
private static void readHeaderAsync(
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)
@ -566,16 +569,16 @@ Extended Payload Length: {7}
error);
}
private static WSFrame readPayloadData(Stream stream, WSFrame frame)
private static WSFrame readPayload(Stream stream, WSFrame frame)
{
var len = frame.FullPayloadLength;
if (len == 0)
{
frame.PayloadData = PayloadData.Empty;
frame.Payload = Payload.Empty;
return frame;
}
if (len > PayloadData.MaxLength)
if (len > Payload.MaxLength)
{
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.");
}
frame.PayloadData = new PayloadData(bytes, llen);
frame.Payload = new Payload(bytes, llen);
return frame;
}
private static void readPayloadDataAsync(
private static void readPayloadAsync(
Stream stream,
WSFrame frame,
Action<WSFrame> completed,
@ -604,13 +607,13 @@ Extended Payload Length: {7}
var len = frame.FullPayloadLength;
if (len == 0)
{
frame.PayloadData = PayloadData.Empty;
frame.Payload = Payload.Empty;
completed(frame);
return;
}
if (len > PayloadData.MaxLength)
if (len > Payload.MaxLength)
{
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.");
}
frame.PayloadData = new PayloadData(bytes, llen);
frame.Payload = new Payload(bytes, llen);
completed(frame);
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -184,14 +184,14 @@ namespace EonaCat.Network
_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;
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))
{
@ -235,11 +235,11 @@ namespace EonaCat.Network
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;
await ctx.Response.Send().ConfigureAwait(false);
context.Response.ContentLength = 0;
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;
Port = ctx.Request.Source.Port;
Method = ctx.Request.Method;
Url = ctx.Request.Url.Full;
Query = ctx.Request.Query.Elements;
RequestHeaders = ctx.Request.Headers;
RequestContentLength = ctx.Request.ContentLength;
StatusCode = ctx.Response.StatusCode;
ResponseContentLength = ctx.Response.ContentLength;
Ip = context.Request.Source.IpAddress;
Port = context.Request.Source.Port;
Method = context.Request.Method;
Url = context.Request.Url.Full;
Query = context.Request.Query.Elements;
RequestHeaders = context.Request.Headers;
RequestContentLength = context.Request.ContentLength;
StatusCode = context.Response.StatusCode;
ResponseContentLength = context.Response.ContentLength;
}
Exception = e;

View File

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

View File

@ -66,17 +66,17 @@ namespace EonaCat.Network
/// </summary>
public double TotalMs { get; private set; } = 0;
internal ResponseEventArgs(HttpContext ctx, double totalMs)
internal ResponseEventArgs(HttpContext context, double totalMs)
{
Ip = ctx.Request.Source.IpAddress;
Port = ctx.Request.Source.Port;
Method = ctx.Request.Method;
Url = ctx.Request.Url.Full;
Query = ctx.Request.Query.Elements;
RequestHeaders = ctx.Request.Headers;
RequestContentLength = ctx.Request.ContentLength;
StatusCode = ctx.Response.StatusCode;
ResponseContentLength = ctx.Response.ContentLength;
Ip = context.Request.Source.IpAddress;
Port = context.Request.Source.Port;
Method = context.Request.Method;
Url = context.Request.Url.Full;
Query = context.Request.Query.Elements;
RequestHeaders = context.Request.Headers;
RequestContentLength = context.Request.ContentLength;
StatusCode = context.Response.StatusCode;
ResponseContentLength = context.Response.ContentLength;
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)
@ -62,9 +62,9 @@ namespace EonaCat.Network
throw new ArgumentNullException(nameof(events));
}
_Context = ctx;
Request = new HttpRequest(ctx);
Response = new HttpResponse(Request, ctx, settings, events);
_Context = context;
Request = new HttpRequest(context);
Response = new HttpResponse(Request, context, settings, events);
}
}
}

View File

@ -182,41 +182,41 @@ namespace EonaCat.Network
/// HTTP request.
/// Instantiate the object using an HttpListenerContext.
/// </summary>
/// <param name="ctx">HttpListenerContext.</param>
public HttpRequest(System.Net.HttpListenerContext ctx)
/// <param name="context">HttpListenerContext.</param>
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;
Keepalive = ctx.Request.KeepAlive;
ContentLength = ctx.Request.ContentLength64;
Useragent = ctx.Request.UserAgent;
ContentType = ctx.Request.ContentType;
ListenerContext = context;
Keepalive = context.Request.KeepAlive;
ContentLength = context.Request.ContentLength64;
Useragent = context.Request.UserAgent;
ContentType = context.Request.ContentType;
_Uri = new Uri(ctx.Request.Url.ToString().Trim());
_Uri = new Uri(context.Request.Url.ToString().Trim());
ThreadId = Thread.CurrentThread.ManagedThreadId;
TimestampUtc = DateTime.Now.ToUniversalTime();
ProtocolVersion = "HTTP/" + ctx.Request.ProtocolVersion.ToString();
Source = new SourceDetails(ctx.Request.RemoteEndPoint.Address.ToString(), ctx.Request.RemoteEndPoint.Port);
Destination = new DestinationDetails(ctx.Request.LocalEndPoint.Address.ToString(), ctx.Request.LocalEndPoint.Port, _Uri.Host);
Method = (HttpMethod)Enum.Parse(typeof(HttpMethod), ctx.Request.HttpMethod, true);
Url = new UrlDetails(ctx.Request.Url.ToString().Trim(), ctx.Request.RawUrl.ToString().Trim());
ProtocolVersion = "HTTP/" + context.Request.ProtocolVersion.ToString();
Source = new SourceDetails(context.Request.RemoteEndPoint.Address.ToString(), context.Request.RemoteEndPoint.Port);
Destination = new DestinationDetails(context.Request.LocalEndPoint.Address.ToString(), context.Request.LocalEndPoint.Port, _Uri.Host);
Method = (HttpMethod)Enum.Parse(typeof(HttpMethod), context.Request.HttpMethod, true);
Url = new UrlDetails(context.Request.Url.ToString().Trim(), context.Request.RawUrl.ToString().Trim());
Query = new QueryDetails(Url.Full);
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 val = ctx.Request.Headers.Get(i);
string key = context.Request.Headers.GetKey(i);
string val = context.Request.Headers.Get(i);
Headers = AddToDict(key, val, Headers);
}
@ -258,7 +258,7 @@ namespace EonaCat.Network
}
}
Data = ctx.Request.InputStream;
Data = context.Request.InputStream;
}
/// <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)
@ -162,8 +162,8 @@ namespace EonaCat.Network
throw new ArgumentNullException(nameof(events));
}
_Request = req;
_Context = ctx;
_Request = httpRequest;
_Context = context;
_Response = _Context.Response;
_Settings = settings;
_Events = events;