Updated
This commit is contained in:
parent
cbfb1a9407
commit
bcc9a6d44c
|
@ -8,7 +8,7 @@ using System.Security.Cryptography.X509Certificates;
|
|||
|
||||
internal class Program
|
||||
{
|
||||
private static WebSocket _client;
|
||||
private static WSClient _client;
|
||||
private static WSServer _server;
|
||||
|
||||
private static async Task Main(string[] args)
|
||||
|
@ -66,8 +66,8 @@ internal class Program
|
|||
StartServer(serverUri, certificatePath, certificatePassword, requiredPassword);
|
||||
|
||||
// Start the client in the main thread
|
||||
_client = new WebSocket(clientUri);
|
||||
_client.SslConfiguration.Certificates.Add(new X509Certificate(certificatePath, certificatePassword));
|
||||
_client = new WSClient(clientUri);
|
||||
_client.SSL.Certificates.Add(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}");
|
||||
|
|
|
@ -7,13 +7,13 @@ namespace EonaCat.BlockChain
|
|||
{
|
||||
public class P2PClient
|
||||
{
|
||||
private readonly IDictionary<string, WebSocket> wsDict = new Dictionary<string, WebSocket>();
|
||||
private readonly IDictionary<string, WSClient> wsDict = new Dictionary<string, WSClient>();
|
||||
|
||||
public void Connect(string url)
|
||||
{
|
||||
if (!wsDict.ContainsKey(url))
|
||||
{
|
||||
WebSocket webSocket = new WebSocket(url);
|
||||
WSClient webSocket = new WSClient(url);
|
||||
webSocket.OnMessageReceived += (sender, e) =>
|
||||
{
|
||||
if (e.Data == "Hi Client")
|
||||
|
|
|
@ -211,24 +211,6 @@ namespace EonaCat.Quic.Connections
|
|||
TerminateConnection();
|
||||
}
|
||||
|
||||
private void OnStreamDataBlockedFrame(Frame frame)
|
||||
{
|
||||
StreamDataBlockedFrame sdbf = (StreamDataBlockedFrame)frame;
|
||||
StreamId streamId = sdbf.StreamId;
|
||||
|
||||
if (_streams.ContainsKey(streamId.Id) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QuicStream stream = _streams[streamId.Id];
|
||||
|
||||
stream.ProcessStreamDataBlocked(sdbf);
|
||||
|
||||
// Remove the stream from the connection
|
||||
_streams.Remove(streamId.Id);
|
||||
}
|
||||
|
||||
internal QuicConnection(ConnectionData connection)
|
||||
{
|
||||
_currentTransferRate = 0;
|
||||
|
|
|
@ -146,10 +146,7 @@ namespace EonaCat.Quic.Infrastructure
|
|||
break;
|
||||
}
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
result.Decode(_array);
|
||||
}
|
||||
result?.Decode(_array);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -60,8 +60,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
|
|||
|
||||
public override byte[] Encode()
|
||||
{
|
||||
List<byte> result = new List<byte>();
|
||||
result.Add(ActualType);
|
||||
List<byte> result = new List<byte>
|
||||
{
|
||||
ActualType
|
||||
};
|
||||
result.AddRange(ErrorCode.ToByteArray());
|
||||
if (ActualType == 0x1c)
|
||||
{
|
||||
|
|
|
@ -28,8 +28,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
|
|||
|
||||
public override byte[] Encode()
|
||||
{
|
||||
List<byte> result = new List<byte>();
|
||||
result.Add(Type);
|
||||
List<byte> result = new List<byte>
|
||||
{
|
||||
Type
|
||||
};
|
||||
result.AddRange(MaximumData.ToByteArray());
|
||||
|
||||
return result.ToArray();
|
||||
|
|
|
@ -20,9 +20,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
|
|||
|
||||
public override byte[] Encode()
|
||||
{
|
||||
List<byte> result = new List<byte>();
|
||||
|
||||
result.Add(Type);
|
||||
List<byte> result = new List<byte>
|
||||
{
|
||||
Type
|
||||
};
|
||||
result.AddRange(MaximumData.ToByteArray());
|
||||
|
||||
return result.ToArray();
|
||||
|
|
|
@ -34,9 +34,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
|
|||
|
||||
public override byte[] Encode()
|
||||
{
|
||||
List<byte> result = new List<byte>();
|
||||
|
||||
result.Add(Type);
|
||||
List<byte> result = new List<byte>
|
||||
{
|
||||
Type
|
||||
};
|
||||
result.AddRange(StreamId.ToByteArray());
|
||||
result.AddRange(MaximumStreamData.ToByteArray());
|
||||
|
||||
|
|
|
@ -28,9 +28,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
|
|||
|
||||
public override byte[] Encode()
|
||||
{
|
||||
List<byte> result = new List<byte>();
|
||||
|
||||
result.Add(Type);
|
||||
List<byte> result = new List<byte>
|
||||
{
|
||||
Type
|
||||
};
|
||||
result.AddRange(MaximumStreams.ToByteArray());
|
||||
|
||||
return result.ToArray();
|
||||
|
|
|
@ -17,8 +17,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
|
|||
|
||||
public override byte[] Encode()
|
||||
{
|
||||
List<byte> data = new List<byte>();
|
||||
data.Add(Type);
|
||||
List<byte> data = new List<byte>
|
||||
{
|
||||
Type
|
||||
};
|
||||
|
||||
return data.ToArray();
|
||||
}
|
||||
|
|
|
@ -17,8 +17,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
|
|||
|
||||
public override byte[] Encode()
|
||||
{
|
||||
List<byte> data = new List<byte>();
|
||||
data.Add(Type);
|
||||
List<byte> data = new List<byte>
|
||||
{
|
||||
Type
|
||||
};
|
||||
|
||||
return data.ToArray();
|
||||
}
|
||||
|
|
|
@ -23,9 +23,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
|
|||
|
||||
public override byte[] Encode()
|
||||
{
|
||||
List<byte> result = new List<byte>();
|
||||
|
||||
result.Add(Type);
|
||||
List<byte> result = new List<byte>
|
||||
{
|
||||
Type
|
||||
};
|
||||
result.AddRange(StreamId.ToByteArray());
|
||||
result.AddRange(ApplicationProtocolErrorCode.ToByteArray());
|
||||
result.AddRange(FinalSize.ToByteArray());
|
||||
|
|
|
@ -32,9 +32,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
|
|||
|
||||
public override byte[] Encode()
|
||||
{
|
||||
List<byte> result = new List<byte>();
|
||||
|
||||
result.Add(Type);
|
||||
List<byte> result = new List<byte>
|
||||
{
|
||||
Type
|
||||
};
|
||||
result.AddRange(StreamId.ToByteArray());
|
||||
result.AddRange(MaximumStreamData.ToByteArray());
|
||||
|
||||
|
|
|
@ -79,8 +79,10 @@ namespace EonaCat.Quic.Infrastructure.Frames
|
|||
byte LEN_BIT = (byte)(ActualType & 0x02);
|
||||
byte FIN_BIT = (byte)(ActualType & 0x01);
|
||||
|
||||
List<byte> result = new List<byte>();
|
||||
result.Add(ActualType);
|
||||
List<byte> result = new List<byte>
|
||||
{
|
||||
ActualType
|
||||
};
|
||||
byte[] streamId = StreamId;
|
||||
result.AddRange(streamId);
|
||||
|
||||
|
|
|
@ -72,8 +72,10 @@ namespace EonaCat.Quic.Infrastructure.Packets
|
|||
{
|
||||
byte[] frames = EncodeFrames();
|
||||
|
||||
List<byte> result = new List<byte>();
|
||||
result.Add((byte)(Type | (PacketNumber.Size - 1)));
|
||||
List<byte> result = new List<byte>
|
||||
{
|
||||
(byte)(Type | (PacketNumber.Size - 1))
|
||||
};
|
||||
result.AddRange(ByteHelpers.GetBytes(Version));
|
||||
|
||||
result.Add(DestinationConnectionId.Size);
|
||||
|
|
|
@ -59,9 +59,10 @@ namespace EonaCat.Quic.Infrastructure.Packets
|
|||
{
|
||||
byte[] frames = EncodeFrames();
|
||||
|
||||
List<byte> result = new List<byte>();
|
||||
|
||||
result.Add(EncodeTypeField());
|
||||
List<byte> result = new List<byte>
|
||||
{
|
||||
EncodeTypeField()
|
||||
};
|
||||
result.AddRange(ByteHelpers.GetBytes(Version));
|
||||
|
||||
result.Add(DestinationConnectionId.Size);
|
||||
|
|
|
@ -38,8 +38,10 @@ namespace EonaCat.Quic.Infrastructure.Packets
|
|||
{
|
||||
byte[] frames = EncodeFrames();
|
||||
|
||||
List<byte> result = new List<byte>();
|
||||
result.Add((byte)(Type | (PacketNumber.Size - 1)));
|
||||
List<byte> result = new List<byte>
|
||||
{
|
||||
(byte)(Type | (PacketNumber.Size - 1))
|
||||
};
|
||||
result.AddRange(DestinationConnectionId.ToByteArray());
|
||||
|
||||
byte[] pnBytes = PacketNumber;
|
||||
|
|
|
@ -107,7 +107,6 @@ namespace EonaCat.Quic
|
|||
private QuicConnection ProcessInitialPacket(Packet packet, IPEndPoint endPoint)
|
||||
{
|
||||
QuicConnection result = null;
|
||||
ulong availableConnectionId;
|
||||
byte[] data;
|
||||
// Unsupported version. Version negotiation packet is sent only on initial connection. All other packets are dropped. (5.2.2 / 16th draft)
|
||||
if (packet.Version != QuicVersion.CurrentVersion || !QuicVersion.SupportedVersions.Contains(packet.Version))
|
||||
|
@ -127,7 +126,7 @@ namespace EonaCat.Quic
|
|||
{
|
||||
ip.AttachFrame(new ConnectionCloseFrame(ErrorCode.PROTOCOL_VIOLATION, 0x00, ErrorConstants.PMTUNotReached));
|
||||
}
|
||||
else if (ConnectionPool.AddConnection(new ConnectionData(new PacketWireTransfer(_client, endPoint), cast.SourceConnectionId, 0), out availableConnectionId) == true)
|
||||
else if (ConnectionPool.AddConnection(new ConnectionData(new PacketWireTransfer(_client, endPoint), cast.SourceConnectionId, 0), out ulong availableConnectionId) == true)
|
||||
{
|
||||
// Tell the peer the available connection id
|
||||
ip.SourceConnectionId = (byte)availableConnectionId;
|
||||
|
|
|
@ -291,9 +291,11 @@ namespace EonaCat.Network
|
|||
user = user.Substring(i + 1);
|
||||
}
|
||||
|
||||
var res = new NameValueCollection();
|
||||
res["username"] = user;
|
||||
res["password"] = pass;
|
||||
var res = new NameValueCollection
|
||||
{
|
||||
["username"] = user,
|
||||
["password"] = pass
|
||||
};
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -281,8 +281,7 @@ namespace EonaCat.Network
|
|||
|
||||
private static string Convert(string key)
|
||||
{
|
||||
HttpHeaderInfo info;
|
||||
return _headers.TryGetValue(key, out info) ? info.Name : string.Empty;
|
||||
return _headers.TryGetValue(key, out HttpHeaderInfo info) ? info.Name : string.Empty;
|
||||
}
|
||||
|
||||
private void DoWithCheckingState(
|
||||
|
|
|
@ -16,21 +16,21 @@ namespace EonaCat.Network
|
|||
/// This class provides access to various properties and methods for interacting with the WebSocket connection
|
||||
/// within the context of an HTTP request handled by an <see cref="HttpListener"/>.
|
||||
/// </remarks>
|
||||
/// <seealso cref="WebSocketContext"/>
|
||||
public class HttpListenerWebSocketContext : WebSocketContext
|
||||
/// <seealso cref="WSContext"/>
|
||||
public class HttpListenerWSContext : WSContext
|
||||
{
|
||||
private readonly HttpListenerContext _context;
|
||||
private readonly WebSocket _websocket;
|
||||
private readonly WSClient _websocket;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpListenerWebSocketContext"/> class.
|
||||
/// Initializes a new instance of the <see cref="HttpListenerWSContext"/> class.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="HttpListenerContext"/> associated with the WebSocket connection.</param>
|
||||
/// <param name="protocol">The WebSocket protocol negotiated during the connection.</param>
|
||||
internal HttpListenerWebSocketContext(HttpListenerContext context, string protocol)
|
||||
internal HttpListenerWSContext(HttpListenerContext context, string protocol)
|
||||
{
|
||||
_context = context;
|
||||
_websocket = new WebSocket(this, protocol);
|
||||
_websocket = new WSClient(this, protocol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -83,7 +83,7 @@ namespace EonaCat.Network
|
|||
|
||||
public override System.Net.IPEndPoint UserEndPoint => _context.Connection.RemoteEndPoint;
|
||||
|
||||
public override WebSocket WebSocket => _websocket;
|
||||
public override WSClient WebSocket => _websocket;
|
||||
|
||||
/// <summary>
|
||||
/// Closes the WebSocket connection.
|
|
@ -19,7 +19,7 @@ namespace EonaCat.Network
|
|||
/// This internal class provides access to various properties and methods for interacting with the WebSocket connection
|
||||
/// within the context of a TCP listener.
|
||||
/// </remarks>
|
||||
internal class TcpListenerWebSocketContext : WebSocketContext
|
||||
internal class TcpListenerWSContext : WSContext
|
||||
{
|
||||
private CookieCollection _cookies;
|
||||
private NameValueCollection _queryString;
|
||||
|
@ -28,21 +28,21 @@ namespace EonaCat.Network
|
|||
private readonly TcpClient _tcpClient;
|
||||
private readonly Uri _uri;
|
||||
private IPrincipal _user;
|
||||
private readonly WebSocket _websocket;
|
||||
private readonly WSClient _websocket;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TcpListenerWebSocketContext"/> class.
|
||||
/// Initializes a new instance of the <see cref="TcpListenerWSContext"/> class.
|
||||
/// </summary>
|
||||
/// <param name="tcpClient">The <see cref="TcpClient"/> associated with the WebSocket connection.</param>
|
||||
/// <param name="protocol">The WebSocket protocol negotiated during the connection.</param>
|
||||
/// <param name="secure">A boolean indicating whether the connection is secure.</param>
|
||||
/// <param name="sslConfig">The SSL configuration for secure connections.</param>
|
||||
/// <param name="logger">The logger for logging.</param>
|
||||
internal TcpListenerWebSocketContext(
|
||||
internal TcpListenerWSContext(
|
||||
TcpClient tcpClient,
|
||||
string protocol,
|
||||
bool secure,
|
||||
SSLConfigurationServer sslConfig
|
||||
SSLConfigServer sslConfig
|
||||
)
|
||||
{
|
||||
_tcpClient = tcpClient;
|
||||
|
@ -74,7 +74,7 @@ namespace EonaCat.Network
|
|||
_request.RequestUri, _request.Headers["Host"], _request.IsWebSocketRequest, secure
|
||||
);
|
||||
|
||||
_websocket = new WebSocket(this, protocol);
|
||||
_websocket = new WSClient(this, protocol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -100,7 +100,7 @@ namespace EonaCat.Network
|
|||
|
||||
public override NameValueCollection QueryString => _queryString ??=
|
||||
HttpUtility.InternalParseQueryString(
|
||||
_uri != null ? _uri.Query : null, Encoding.UTF8
|
||||
_uri?.Query, Encoding.UTF8
|
||||
)
|
||||
;
|
||||
|
||||
|
@ -131,7 +131,7 @@ namespace EonaCat.Network
|
|||
|
||||
public override System.Net.IPEndPoint UserEndPoint => (System.Net.IPEndPoint)_tcpClient.Client.RemoteEndPoint;
|
||||
|
||||
public override WebSocket WebSocket => _websocket;
|
||||
public override WSClient WebSocket => _websocket;
|
||||
|
||||
/// <summary>
|
||||
/// Authenticates the WebSocket connection based on the specified authentication scheme.
|
|
@ -15,12 +15,12 @@ namespace EonaCat.Network
|
|||
/// This abstract class defines properties and methods for accessing information related to a WebSocket connection,
|
||||
/// such as headers, cookies, authentication status, and more.
|
||||
/// </remarks>
|
||||
public abstract class WebSocketContext
|
||||
public abstract class WSContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WebSocketContext"/> class.
|
||||
/// Initializes a new instance of the <see cref="WSContext"/> class.
|
||||
/// </summary>
|
||||
protected WebSocketContext()
|
||||
protected WSContext()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -107,6 +107,6 @@ namespace EonaCat.Network
|
|||
/// <summary>
|
||||
/// Gets the WebSocket instance associated with the context.
|
||||
/// </summary>
|
||||
public abstract WebSocket WebSocket { get; }
|
||||
public abstract WSClient WebSocket { get; }
|
||||
}
|
||||
}
|
|
@ -226,10 +226,9 @@ namespace EonaCat.Network
|
|||
|
||||
set
|
||||
{
|
||||
string msg;
|
||||
if (!canSetName(value, out msg))
|
||||
if (!canSetName(value, out string message))
|
||||
{
|
||||
throw new CookieException(msg);
|
||||
throw new CookieException(message);
|
||||
}
|
||||
|
||||
_name = value;
|
||||
|
@ -272,8 +271,7 @@ namespace EonaCat.Network
|
|||
"The value specified for the Port attribute isn't enclosed in double quotes.");
|
||||
}
|
||||
|
||||
string err;
|
||||
if (!tryCreatePorts(value, out _ports, out err))
|
||||
if (!tryCreatePorts(value, out _ports, out string err))
|
||||
{
|
||||
throw new CookieException(
|
||||
string.Format(
|
||||
|
@ -308,10 +306,9 @@ namespace EonaCat.Network
|
|||
|
||||
set
|
||||
{
|
||||
string msg;
|
||||
if (!canSetValue(value, out msg))
|
||||
if (!canSetValue(value, out string message))
|
||||
{
|
||||
throw new CookieException(msg);
|
||||
throw new CookieException(message);
|
||||
}
|
||||
|
||||
_value = value.Length > 0 ? value : "\"\"";
|
||||
|
|
|
@ -236,13 +236,12 @@ namespace EonaCat.Network
|
|||
buff.AppendFormat(", {0}", pairs[++i].Trim());
|
||||
}
|
||||
|
||||
DateTime expires;
|
||||
if (!DateTime.TryParseExact(
|
||||
buff.ToString(),
|
||||
new[] { "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'", "r" },
|
||||
CultureInfo.CreateSpecificCulture("en-US"),
|
||||
DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal,
|
||||
out expires))
|
||||
out DateTime expires))
|
||||
{
|
||||
expires = DateTime.Now;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace EonaCat.Network
|
|||
IPEndPoint endpoint,
|
||||
bool secure,
|
||||
string certificateFolderPath,
|
||||
SSLConfigurationServer sslConfig,
|
||||
SSLConfigServer sslConfig,
|
||||
bool reuseAddress
|
||||
)
|
||||
{
|
||||
|
@ -52,8 +52,8 @@ namespace EonaCat.Network
|
|||
}
|
||||
|
||||
IsSecure = true;
|
||||
SslConfiguration = new SSLConfigurationServer(sslConfig);
|
||||
SslConfiguration.Certificate = cert;
|
||||
SSL = new SSLConfigServer(sslConfig);
|
||||
SSL.Certificate = cert;
|
||||
}
|
||||
|
||||
_endpoint = endpoint;
|
||||
|
@ -91,7 +91,7 @@ namespace EonaCat.Network
|
|||
/// <summary>
|
||||
/// Gets the SSL configuration for the secure endpoint.
|
||||
/// </summary>
|
||||
public SSLConfigurationServer SslConfiguration { get; }
|
||||
public SSLConfigServer SSL { get; }
|
||||
|
||||
private static void addSpecial(List<HttpListenerPrefix> prefixes, HttpListenerPrefix prefix)
|
||||
{
|
||||
|
@ -183,7 +183,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
// TODO: Should log the error code when this class has a logging.
|
||||
// Do nothing
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
|
@ -196,10 +196,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
catch
|
||||
{
|
||||
if (sock != null)
|
||||
{
|
||||
sock.Close();
|
||||
}
|
||||
sock?.Close();
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -436,8 +433,10 @@ namespace EonaCat.Network
|
|||
return;
|
||||
}
|
||||
|
||||
prefs2 = new Dictionary<HttpListenerPrefix, HttpListener>(prefs);
|
||||
prefs2[prefix] = listener;
|
||||
prefs2 = new Dictionary<HttpListenerPrefix, HttpListener>(prefs)
|
||||
{
|
||||
[prefix] = listener
|
||||
};
|
||||
}
|
||||
while (Interlocked.CompareExchange(ref _prefixes, prefs2, prefs) != prefs);
|
||||
}
|
||||
|
|
|
@ -40,8 +40,7 @@ namespace EonaCat.Network
|
|||
throw new HttpListenerException(87, "Includes an invalid host.");
|
||||
}
|
||||
|
||||
int port;
|
||||
if (!int.TryParse(pref.Port, out port))
|
||||
if (!int.TryParse(pref.Port, out int port))
|
||||
{
|
||||
throw new HttpListenerException(87, "Includes an invalid port.");
|
||||
}
|
||||
|
@ -64,8 +63,7 @@ namespace EonaCat.Network
|
|||
|
||||
var endpoint = new IPEndPoint(addr, port);
|
||||
|
||||
EndPointListener lsnr;
|
||||
if (_endpoints.TryGetValue(endpoint, out lsnr))
|
||||
if (_endpoints.TryGetValue(endpoint, out EndPointListener lsnr))
|
||||
{
|
||||
if (lsnr.IsSecure ^ pref.IsSecure)
|
||||
{
|
||||
|
@ -104,8 +102,7 @@ namespace EonaCat.Network
|
|||
return;
|
||||
}
|
||||
|
||||
int port;
|
||||
if (!int.TryParse(pref.Port, out port))
|
||||
if (!int.TryParse(pref.Port, out int port))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -128,8 +125,7 @@ namespace EonaCat.Network
|
|||
|
||||
var endpoint = new IPEndPoint(addr, port);
|
||||
|
||||
EndPointListener lsnr;
|
||||
if (!_endpoints.TryGetValue(endpoint, out lsnr))
|
||||
if (!_endpoints.TryGetValue(endpoint, out EndPointListener lsnr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -151,8 +147,7 @@ namespace EonaCat.Network
|
|||
{
|
||||
lock (((ICollection)_endpoints).SyncRoot)
|
||||
{
|
||||
EndPointListener lsnr;
|
||||
if (!_endpoints.TryGetValue(endpoint, out lsnr))
|
||||
if (!_endpoints.TryGetValue(endpoint, out EndPointListener lsnr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ namespace EonaCat.Network
|
|||
{
|
||||
private byte[] _buffer;
|
||||
private const int _bufferLength = 8192;
|
||||
private const int TIMEOUT_CONTINUE = 15000;
|
||||
private const int TIMEOUT_INITIAL = 90000;
|
||||
private HttpListenerContext _context;
|
||||
private bool _contextRegistered;
|
||||
private StringBuilder _currentLine;
|
||||
|
@ -31,7 +33,7 @@ namespace EonaCat.Network
|
|||
private int _position;
|
||||
private MemoryStream _requestBuffer;
|
||||
private Socket _socket;
|
||||
private readonly object _sync;
|
||||
private readonly object _lock;
|
||||
private int _timeout;
|
||||
private readonly Dictionary<int, bool> _timeoutCanceled;
|
||||
private Timer _timer;
|
||||
|
@ -47,11 +49,11 @@ namespace EonaCat.Network
|
|||
_listener = listener;
|
||||
IsSecure = listener.IsSecure;
|
||||
|
||||
var netStream = new NetworkStream(socket, false);
|
||||
var networkStream = new NetworkStream(socket, false);
|
||||
if (IsSecure)
|
||||
{
|
||||
var conf = listener.SslConfiguration;
|
||||
var sslStream = new SslStream(netStream, false, conf.ClientCertificateValidationCallback);
|
||||
var conf = listener.SSL;
|
||||
var sslStream = new SslStream(networkStream, false, conf.ClientCertificateValidationCallback);
|
||||
sslStream.AuthenticateAsServer(
|
||||
conf.Certificate,
|
||||
conf.IsClientCertificateRequired,
|
||||
|
@ -63,15 +65,15 @@ namespace EonaCat.Network
|
|||
}
|
||||
else
|
||||
{
|
||||
Stream = netStream;
|
||||
Stream = networkStream;
|
||||
}
|
||||
|
||||
_sync = new object();
|
||||
_timeout = 90000; // 90k ms for first request, 15k ms from then on.
|
||||
_lock = new object();
|
||||
_timeout = TIMEOUT_INITIAL;
|
||||
_timeoutCanceled = new Dictionary<int, bool>();
|
||||
_timer = new Timer(onTimeout, this, Timeout.Infinite, Timeout.Infinite);
|
||||
_timer = new Timer(OnTimeout, this, Timeout.Infinite, Timeout.Infinite);
|
||||
|
||||
init();
|
||||
Setup();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -106,24 +108,24 @@ namespace EonaCat.Network
|
|||
|
||||
private void close()
|
||||
{
|
||||
lock (_sync)
|
||||
lock (_lock)
|
||||
{
|
||||
if (_socket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
disposeTimer();
|
||||
disposeRequestBuffer();
|
||||
disposeStream();
|
||||
closeSocket();
|
||||
DisposeTimer();
|
||||
DisposeRequestBuffer();
|
||||
DisposeStream();
|
||||
CloseSocket();
|
||||
}
|
||||
|
||||
unregisterContext();
|
||||
removeConnection();
|
||||
UnregisterContext();
|
||||
RemoveConnection();
|
||||
}
|
||||
|
||||
private void closeSocket()
|
||||
private void CloseSocket()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -137,7 +139,7 @@ namespace EonaCat.Network
|
|||
_socket = null;
|
||||
}
|
||||
|
||||
private void disposeRequestBuffer()
|
||||
private void DisposeRequestBuffer()
|
||||
{
|
||||
if (_requestBuffer == null)
|
||||
{
|
||||
|
@ -148,7 +150,7 @@ namespace EonaCat.Network
|
|||
_requestBuffer = null;
|
||||
}
|
||||
|
||||
private void disposeStream()
|
||||
private void DisposeStream()
|
||||
{
|
||||
if (Stream == null)
|
||||
{
|
||||
|
@ -162,7 +164,7 @@ namespace EonaCat.Network
|
|||
Stream = null;
|
||||
}
|
||||
|
||||
private void disposeTimer()
|
||||
private void DisposeTimer()
|
||||
{
|
||||
if (_timer == null)
|
||||
{
|
||||
|
@ -181,7 +183,7 @@ namespace EonaCat.Network
|
|||
_timer = null;
|
||||
}
|
||||
|
||||
private void init()
|
||||
private void Setup()
|
||||
{
|
||||
_context = new HttpListenerContext(this);
|
||||
_inputState = InputState.RequestLine;
|
||||
|
@ -192,17 +194,17 @@ namespace EonaCat.Network
|
|||
_requestBuffer = new MemoryStream();
|
||||
}
|
||||
|
||||
private static void onRead(IAsyncResult asyncResult)
|
||||
private static void OnRead(IAsyncResult asyncResult)
|
||||
{
|
||||
var conn = (HttpConnection)asyncResult.AsyncState;
|
||||
if (conn._socket == null)
|
||||
var httpConnection = (HttpConnection)asyncResult.AsyncState;
|
||||
if (httpConnection._socket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (conn._sync)
|
||||
lock (httpConnection._lock)
|
||||
{
|
||||
if (conn._socket == null)
|
||||
if (httpConnection._socket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -211,111 +213,110 @@ namespace EonaCat.Network
|
|||
var len = 0;
|
||||
try
|
||||
{
|
||||
var current = conn.Reuses;
|
||||
if (!conn._timeoutCanceled[current])
|
||||
var current = httpConnection.Reuses;
|
||||
if (!httpConnection._timeoutCanceled[current])
|
||||
{
|
||||
conn._timer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
conn._timeoutCanceled[current] = true;
|
||||
httpConnection._timer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
httpConnection._timeoutCanceled[current] = true;
|
||||
}
|
||||
|
||||
nread = conn.Stream.EndRead(asyncResult);
|
||||
conn._requestBuffer.Write(conn._buffer, 0, nread);
|
||||
len = (int)conn._requestBuffer.Length;
|
||||
nread = httpConnection.Stream.EndRead(asyncResult);
|
||||
httpConnection._requestBuffer.Write(httpConnection._buffer, 0, nread);
|
||||
len = (int)httpConnection._requestBuffer.Length;
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (conn._requestBuffer != null && conn._requestBuffer.Length > 0)
|
||||
if (httpConnection._requestBuffer != null && httpConnection._requestBuffer.Length > 0)
|
||||
{
|
||||
conn.SendError(ex.Message, 400);
|
||||
httpConnection.SendError(exception.Message, 400);
|
||||
return;
|
||||
}
|
||||
|
||||
conn.close();
|
||||
httpConnection.close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (nread <= 0)
|
||||
{
|
||||
conn.close();
|
||||
httpConnection.close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn.processInput(conn._requestBuffer.GetBuffer(), len))
|
||||
if (httpConnection.ProcessInput(httpConnection._requestBuffer.GetBuffer(), len))
|
||||
{
|
||||
if (!conn._context.HasError)
|
||||
if (!httpConnection._context.HasError)
|
||||
{
|
||||
conn._context.Request.FinishInitialization();
|
||||
httpConnection._context.Request.FinishInitialization();
|
||||
}
|
||||
|
||||
if (conn._context.HasError)
|
||||
if (httpConnection._context.HasError)
|
||||
{
|
||||
conn.SendError();
|
||||
httpConnection.SendError();
|
||||
return;
|
||||
}
|
||||
|
||||
HttpListener lsnr;
|
||||
if (!conn._listener.TrySearchHttpListener(conn._context.Request.Url, out lsnr))
|
||||
if (!httpConnection._listener.TrySearchHttpListener(httpConnection._context.Request.Url, out HttpListener httpListener))
|
||||
{
|
||||
conn.SendError(null, 404);
|
||||
httpConnection.SendError(null, 404);
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn._lastListener != lsnr)
|
||||
if (httpConnection._lastListener != httpListener)
|
||||
{
|
||||
conn.removeConnection();
|
||||
if (!lsnr.AddConnection(conn))
|
||||
httpConnection.RemoveConnection();
|
||||
if (!httpListener.AddConnection(httpConnection))
|
||||
{
|
||||
conn.close();
|
||||
httpConnection.close();
|
||||
return;
|
||||
}
|
||||
|
||||
conn._lastListener = lsnr;
|
||||
httpConnection._lastListener = httpListener;
|
||||
}
|
||||
|
||||
conn._context.Listener = lsnr;
|
||||
if (!conn._context.Authenticate())
|
||||
httpConnection._context.Listener = httpListener;
|
||||
if (!httpConnection._context.Authenticate())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn._context.Register())
|
||||
if (httpConnection._context.Register())
|
||||
{
|
||||
conn._contextRegistered = true;
|
||||
httpConnection._contextRegistered = true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
conn.Stream.BeginRead(conn._buffer, 0, _bufferLength, onRead, conn);
|
||||
httpConnection.Stream.BeginRead(httpConnection._buffer, 0, _bufferLength, OnRead, httpConnection);
|
||||
}
|
||||
}
|
||||
|
||||
private static void onTimeout(object state)
|
||||
private static void OnTimeout(object state)
|
||||
{
|
||||
var conn = (HttpConnection)state;
|
||||
var current = conn.Reuses;
|
||||
if (conn._socket == null)
|
||||
var httpConnection = (HttpConnection)state;
|
||||
var current = httpConnection.Reuses;
|
||||
if (httpConnection._socket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (conn._sync)
|
||||
lock (httpConnection._lock)
|
||||
{
|
||||
if (conn._socket == null)
|
||||
if (httpConnection._socket == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn._timeoutCanceled[current])
|
||||
if (httpConnection._timeoutCanceled[current])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
conn.SendError(null, 408);
|
||||
httpConnection.SendError(null, 408);
|
||||
}
|
||||
}
|
||||
|
||||
private bool processInput(byte[] data, int length)
|
||||
private bool ProcessInput(byte[] data, int length)
|
||||
{
|
||||
_currentLine ??= new StringBuilder(64);
|
||||
|
||||
|
@ -323,7 +324,7 @@ namespace EonaCat.Network
|
|||
try
|
||||
{
|
||||
string line;
|
||||
while ((line = readLineFrom(data, _position, length, out nread)) != null)
|
||||
while ((line = ReadLineFrom(data, _position, length, out nread)) != null)
|
||||
{
|
||||
_position += nread;
|
||||
if (line.Length == 0)
|
||||
|
@ -358,9 +359,9 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception exception)
|
||||
{
|
||||
_context.ErrorMessage = ex.Message;
|
||||
_context.ErrorMessage = exception.Message;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -374,22 +375,22 @@ namespace EonaCat.Network
|
|||
return false;
|
||||
}
|
||||
|
||||
private string readLineFrom(byte[] buffer, int offset, int length, out int read)
|
||||
private string ReadLineFrom(byte[] buffer, int offset, int length, out int read)
|
||||
{
|
||||
read = 0;
|
||||
|
||||
for (var i = offset; i < length && _lineState != LineState.Lf; i++)
|
||||
for (var i = offset; i < length && _lineState != LineState.LineFeed; i++)
|
||||
{
|
||||
read++;
|
||||
|
||||
var b = buffer[i];
|
||||
if (b == 13)
|
||||
{
|
||||
_lineState = LineState.Cr;
|
||||
_lineState = LineState.CarriageReturn;
|
||||
}
|
||||
else if (b == 10)
|
||||
{
|
||||
_lineState = LineState.Lf;
|
||||
_lineState = LineState.LineFeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -397,7 +398,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
if (_lineState != LineState.Lf)
|
||||
if (_lineState != LineState.LineFeed)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -410,7 +411,7 @@ namespace EonaCat.Network
|
|||
return line;
|
||||
}
|
||||
|
||||
private void removeConnection()
|
||||
private void RemoveConnection()
|
||||
{
|
||||
if (_lastListener != null)
|
||||
{
|
||||
|
@ -422,7 +423,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
private void unregisterContext()
|
||||
private void UnregisterContext()
|
||||
{
|
||||
if (!_contextRegistered)
|
||||
{
|
||||
|
@ -444,7 +445,7 @@ namespace EonaCat.Network
|
|||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
lock (_lock)
|
||||
{
|
||||
if (_socket == null)
|
||||
{
|
||||
|
@ -458,17 +459,16 @@ namespace EonaCat.Network
|
|||
{
|
||||
// Don't close. Keep working.
|
||||
Reuses++;
|
||||
disposeRequestBuffer();
|
||||
unregisterContext();
|
||||
init();
|
||||
DisposeRequestBuffer();
|
||||
UnregisterContext();
|
||||
Setup();
|
||||
BeginReadRequest();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (_outputStream != null)
|
||||
else
|
||||
{
|
||||
_outputStream.Close(true);
|
||||
_outputStream?.Close(true);
|
||||
}
|
||||
|
||||
close();
|
||||
|
@ -484,14 +484,14 @@ namespace EonaCat.Network
|
|||
|
||||
if (Reuses == 1)
|
||||
{
|
||||
_timeout = 15000;
|
||||
_timeout = TIMEOUT_CONTINUE;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_timeoutCanceled.Add(Reuses, false);
|
||||
_timer.Change(_timeout, Timeout.Infinite);
|
||||
Stream.BeginRead(_buffer, 0, _bufferLength, onRead, this);
|
||||
Stream.BeginRead(_buffer, 0, _bufferLength, OnRead, this);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
@ -520,7 +520,7 @@ namespace EonaCat.Network
|
|||
return _inputStream;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
lock (_lock)
|
||||
{
|
||||
if (_socket == null)
|
||||
{
|
||||
|
@ -529,7 +529,7 @@ namespace EonaCat.Network
|
|||
|
||||
var buff = _requestBuffer.GetBuffer();
|
||||
var len = (int)_requestBuffer.Length;
|
||||
disposeRequestBuffer();
|
||||
DisposeRequestBuffer();
|
||||
if (chunked)
|
||||
{
|
||||
_context.Response.SendInChunks = true;
|
||||
|
@ -557,7 +557,7 @@ namespace EonaCat.Network
|
|||
return _outputStream;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
lock (_lock)
|
||||
{
|
||||
if (_socket == null)
|
||||
{
|
||||
|
@ -592,7 +592,7 @@ namespace EonaCat.Network
|
|||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
lock (_lock)
|
||||
{
|
||||
if (_socket == null)
|
||||
{
|
||||
|
@ -601,12 +601,12 @@ namespace EonaCat.Network
|
|||
|
||||
try
|
||||
{
|
||||
var res = _context.Response;
|
||||
res.StatusCode = status;
|
||||
res.ContentType = "text/html";
|
||||
var httpResponse = _context.Response;
|
||||
httpResponse.StatusCode = status;
|
||||
httpResponse.ContentType = "text/html";
|
||||
|
||||
var content = new StringBuilder(64);
|
||||
content.AppendFormat("<html><head><title>EonaCat.Network Error</title></head><body><h1>{0} {1}", status, res.StatusDescription);
|
||||
content.AppendFormat("<html><head><title>EonaCat.Network Error</title></head><body><h1>{0} {1}", status, httpResponse.StatusDescription);
|
||||
if (message != null && message.Length > 0)
|
||||
{
|
||||
content.AppendFormat(" ({0})</h1></body></html>", message);
|
||||
|
@ -616,12 +616,12 @@ namespace EonaCat.Network
|
|||
content.Append("</h1></body></html>");
|
||||
}
|
||||
|
||||
var enc = Encoding.UTF8;
|
||||
var entity = enc.GetBytes(content.ToString());
|
||||
res.ContentEncoding = enc;
|
||||
res.ContentLength64 = entity.LongLength;
|
||||
var encoding = Encoding.UTF8;
|
||||
var entity = encoding.GetBytes(content.ToString());
|
||||
httpResponse.ContentEncoding = encoding;
|
||||
httpResponse.ContentLength64 = entity.LongLength;
|
||||
|
||||
res.Close(entity, true);
|
||||
httpResponse.Close(entity, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
|
@ -80,11 +80,13 @@ namespace EonaCat.Network
|
|||
string password, string realm, string method, string entity
|
||||
)
|
||||
{
|
||||
var copied = new NameValueCollection(_parameters);
|
||||
copied["password"] = password;
|
||||
copied["realm"] = realm;
|
||||
copied["method"] = method;
|
||||
copied["entity"] = entity;
|
||||
var copied = new NameValueCollection(_parameters)
|
||||
{
|
||||
["password"] = password,
|
||||
["realm"] = realm,
|
||||
["method"] = method,
|
||||
["entity"] = entity
|
||||
};
|
||||
|
||||
var expected = AuthenticationResponse.CreateRequestDigest(copied);
|
||||
return _parameters["response"] == expected;
|
||||
|
|
|
@ -68,8 +68,7 @@ namespace EonaCat.Network
|
|||
/// <returns>True if the header is restricted, false otherwise.</returns>
|
||||
public bool IsRestricted(bool response)
|
||||
{
|
||||
return (Type & HttpHeaderType.Restricted) == HttpHeaderType.Restricted
|
||||
&& (response ? IsResponse : IsRequest);
|
||||
return (Type & HttpHeaderType.Restricted) == HttpHeaderType.Restricted && (response ? IsResponse : IsRequest);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,19 +18,19 @@ namespace EonaCat.Network
|
|||
private string _certFolderPath;
|
||||
private readonly Dictionary<HttpConnection, HttpConnection> _connections;
|
||||
private readonly object _connectionsSync;
|
||||
private readonly List<HttpListenerContext> _ctxQueue;
|
||||
private readonly object _ctxQueueSync;
|
||||
private readonly Dictionary<HttpListenerContext, HttpListenerContext> _ctxRegistry;
|
||||
private readonly object _ctxRegistrySync;
|
||||
private readonly List<HttpListenerContext> contextQueue;
|
||||
private readonly object _contextQueueLock;
|
||||
private readonly Dictionary<HttpListenerContext, HttpListenerContext> _contextRegistry;
|
||||
private readonly object _contextRegistryLock;
|
||||
private static readonly string _defaultRealm;
|
||||
private bool _ignoreWriteExceptions;
|
||||
private volatile bool _listening;
|
||||
private readonly HttpListenerPrefixCollection _prefixes;
|
||||
private string _realm;
|
||||
private SSLConfigurationServer _sslConfig;
|
||||
private SSLConfigServer _sslConfig;
|
||||
private Func<IIdentity, NetworkCredential> _userCredFinder;
|
||||
private readonly List<HttpListenerAsyncResult> _waitQueue;
|
||||
private readonly object _waitQueueSync;
|
||||
private readonly object _waitQueueLock;
|
||||
|
||||
static HttpListener()
|
||||
{
|
||||
|
@ -47,16 +47,16 @@ namespace EonaCat.Network
|
|||
_connections = new Dictionary<HttpConnection, HttpConnection>();
|
||||
_connectionsSync = ((ICollection)_connections).SyncRoot;
|
||||
|
||||
_ctxQueue = new List<HttpListenerContext>();
|
||||
_ctxQueueSync = ((ICollection)_ctxQueue).SyncRoot;
|
||||
contextQueue = new List<HttpListenerContext>();
|
||||
_contextQueueLock = ((ICollection)contextQueue).SyncRoot;
|
||||
|
||||
_ctxRegistry = new Dictionary<HttpListenerContext, HttpListenerContext>();
|
||||
_ctxRegistrySync = ((ICollection)_ctxRegistry).SyncRoot;
|
||||
_contextRegistry = new Dictionary<HttpListenerContext, HttpListenerContext>();
|
||||
_contextRegistryLock = ((ICollection)_contextRegistry).SyncRoot;
|
||||
|
||||
_prefixes = new HttpListenerPrefixCollection(this);
|
||||
|
||||
_waitQueue = new List<HttpListenerAsyncResult>();
|
||||
_waitQueueSync = ((ICollection)_waitQueue).SyncRoot;
|
||||
_waitQueueLock = ((ICollection)_waitQueue).SyncRoot;
|
||||
}
|
||||
|
||||
internal bool IsDisposed { get; private set; }
|
||||
|
@ -154,12 +154,12 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
public SSLConfigurationServer SslConfiguration
|
||||
public SSLConfigServer SslConfiguration
|
||||
{
|
||||
get
|
||||
{
|
||||
CheckDisposed();
|
||||
return _sslConfig ??= new SSLConfigurationServer();
|
||||
return _sslConfig ??= new SSLConfigServer();
|
||||
}
|
||||
|
||||
set
|
||||
|
@ -197,9 +197,9 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
private void cleanupConnections()
|
||||
private void CleanupConnections()
|
||||
{
|
||||
HttpConnection[] conns = null;
|
||||
HttpConnection[] httpConnections = null;
|
||||
lock (_connectionsSync)
|
||||
{
|
||||
if (_connections.Count == 0)
|
||||
|
@ -209,29 +209,29 @@ namespace EonaCat.Network
|
|||
|
||||
// Need to copy this since closing will call the RemoveConnection method.
|
||||
var keys = _connections.Keys;
|
||||
conns = new HttpConnection[keys.Count];
|
||||
keys.CopyTo(conns, 0);
|
||||
httpConnections = new HttpConnection[keys.Count];
|
||||
keys.CopyTo(httpConnections, 0);
|
||||
_connections.Clear();
|
||||
}
|
||||
|
||||
for (var i = conns.Length - 1; i >= 0; i--)
|
||||
for (var i = httpConnections.Length - 1; i >= 0; i--)
|
||||
{
|
||||
conns[i].Close(true);
|
||||
httpConnections[i].Close(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupContextQueue(bool sendServiceUnavailable)
|
||||
private void CleanupContextQueue(bool sendServiceUnavailable)
|
||||
{
|
||||
HttpListenerContext[] ctxs = null;
|
||||
lock (_ctxQueueSync)
|
||||
HttpListenerContext[] httpContextQueues = null;
|
||||
lock (_contextQueueLock)
|
||||
{
|
||||
if (_ctxQueue.Count == 0)
|
||||
if (contextQueue.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ctxs = _ctxQueue.ToArray();
|
||||
_ctxQueue.Clear();
|
||||
httpContextQueues = contextQueue.ToArray();
|
||||
contextQueue.Clear();
|
||||
}
|
||||
|
||||
if (!sendServiceUnavailable)
|
||||
|
@ -239,54 +239,54 @@ namespace EonaCat.Network
|
|||
return;
|
||||
}
|
||||
|
||||
foreach (var ctx in ctxs)
|
||||
foreach (var currentContext in httpContextQueues)
|
||||
{
|
||||
var res = ctx.Response;
|
||||
res.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
|
||||
res.Close();
|
||||
var response = currentContext.Response;
|
||||
response.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
|
||||
response.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupContextRegistry()
|
||||
private void CleanupContextRegistry()
|
||||
{
|
||||
HttpListenerContext[] ctxs = null;
|
||||
lock (_ctxRegistrySync)
|
||||
HttpListenerContext[] contexts = null;
|
||||
lock (_contextRegistryLock)
|
||||
{
|
||||
if (_ctxRegistry.Count == 0)
|
||||
if (_contextRegistry.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Need to copy this since closing will call the UnregisterContext method.
|
||||
var keys = _ctxRegistry.Keys;
|
||||
ctxs = new HttpListenerContext[keys.Count];
|
||||
keys.CopyTo(ctxs, 0);
|
||||
_ctxRegistry.Clear();
|
||||
var keys = _contextRegistry.Keys;
|
||||
contexts = new HttpListenerContext[keys.Count];
|
||||
keys.CopyTo(contexts, 0);
|
||||
_contextRegistry.Clear();
|
||||
}
|
||||
|
||||
for (var i = ctxs.Length - 1; i >= 0; i--)
|
||||
for (var i = contexts.Length - 1; i >= 0; i--)
|
||||
{
|
||||
ctxs[i].Connection.Close(true);
|
||||
contexts[i].Connection.Close(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupWaitQueue(Exception exception)
|
||||
private void CleanupWaitQueue(Exception exception)
|
||||
{
|
||||
HttpListenerAsyncResult[] aress = null;
|
||||
lock (_waitQueueSync)
|
||||
HttpListenerAsyncResult[] results = null;
|
||||
lock (_waitQueueLock)
|
||||
{
|
||||
if (_waitQueue.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
aress = _waitQueue.ToArray();
|
||||
results = _waitQueue.ToArray();
|
||||
_waitQueue.Clear();
|
||||
}
|
||||
|
||||
foreach (var ares in aress)
|
||||
foreach (var currentResult in results)
|
||||
{
|
||||
ares.Complete(exception);
|
||||
currentResult.Complete(exception);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,19 +298,19 @@ namespace EonaCat.Network
|
|||
EndPointManager.RemoveListener(this);
|
||||
}
|
||||
|
||||
lock (_ctxRegistrySync)
|
||||
lock (_contextRegistryLock)
|
||||
{
|
||||
cleanupContextQueue(!force);
|
||||
CleanupContextQueue(!force);
|
||||
}
|
||||
|
||||
cleanupContextRegistry();
|
||||
cleanupConnections();
|
||||
cleanupWaitQueue(new ObjectDisposedException(GetType().ToString()));
|
||||
CleanupContextRegistry();
|
||||
CleanupConnections();
|
||||
CleanupWaitQueue(new ObjectDisposedException(GetType().ToString()));
|
||||
|
||||
IsDisposed = true;
|
||||
}
|
||||
|
||||
private HttpListenerAsyncResult getAsyncResultFromQueue()
|
||||
private HttpListenerAsyncResult GetAsyncResultFromQueue()
|
||||
{
|
||||
if (_waitQueue.Count == 0)
|
||||
{
|
||||
|
@ -323,15 +323,15 @@ namespace EonaCat.Network
|
|||
return ares;
|
||||
}
|
||||
|
||||
private HttpListenerContext getContextFromQueue()
|
||||
private HttpListenerContext GetContextFromQueue()
|
||||
{
|
||||
if (_ctxQueue.Count == 0)
|
||||
if (contextQueue.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var ctx = _ctxQueue[0];
|
||||
_ctxQueue.RemoveAt(0);
|
||||
var ctx = contextQueue[0];
|
||||
contextQueue.RemoveAt(0);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
@ -357,14 +357,14 @@ namespace EonaCat.Network
|
|||
|
||||
internal HttpListenerAsyncResult BeginGetContext(HttpListenerAsyncResult asyncResult)
|
||||
{
|
||||
lock (_ctxRegistrySync)
|
||||
lock (_contextRegistryLock)
|
||||
{
|
||||
if (!_listening)
|
||||
{
|
||||
throw new HttpListenerException(995);
|
||||
}
|
||||
|
||||
var ctx = getContextFromQueue();
|
||||
var ctx = GetContextFromQueue();
|
||||
if (ctx == null)
|
||||
{
|
||||
_waitQueue.Add(asyncResult);
|
||||
|
@ -404,23 +404,23 @@ namespace EonaCat.Network
|
|||
return false;
|
||||
}
|
||||
|
||||
lock (_ctxRegistrySync)
|
||||
lock (_contextRegistryLock)
|
||||
{
|
||||
if (!_listening)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_ctxRegistry[context] = context;
|
||||
_contextRegistry[context] = context;
|
||||
|
||||
var ares = getAsyncResultFromQueue();
|
||||
if (ares == null)
|
||||
var result = GetAsyncResultFromQueue();
|
||||
if (result == null)
|
||||
{
|
||||
_ctxQueue.Add(context);
|
||||
contextQueue.Add(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
ares.Complete(context);
|
||||
result.Complete(context);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -455,9 +455,9 @@ namespace EonaCat.Network
|
|||
|
||||
internal void UnregisterContext(HttpListenerContext context)
|
||||
{
|
||||
lock (_ctxRegistrySync)
|
||||
lock (_contextRegistryLock)
|
||||
{
|
||||
_ctxRegistry.Remove(context);
|
||||
_contextRegistry.Remove(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -522,23 +522,23 @@ namespace EonaCat.Network
|
|||
throw new ArgumentNullException(nameof(asyncResult));
|
||||
}
|
||||
|
||||
if (asyncResult is not HttpListenerAsyncResult ares)
|
||||
if (asyncResult is not HttpListenerAsyncResult result)
|
||||
{
|
||||
throw new ArgumentException("A wrong IAsyncResult.", nameof(asyncResult));
|
||||
}
|
||||
|
||||
if (ares.EndCalled)
|
||||
if (result.EndCalled)
|
||||
{
|
||||
throw new InvalidOperationException("This IAsyncResult cannot be reused.");
|
||||
}
|
||||
|
||||
ares.EndCalled = true;
|
||||
if (!ares.IsCompleted)
|
||||
result.EndCalled = true;
|
||||
if (!result.IsCompleted)
|
||||
{
|
||||
ares.AsyncWaitHandle.WaitOne();
|
||||
result.AsyncWaitHandle.WaitOne();
|
||||
}
|
||||
|
||||
return ares.GetContext(); // This may throw an exception.
|
||||
return result.GetContext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -558,10 +558,10 @@ namespace EonaCat.Network
|
|||
throw new InvalidOperationException("The listener hasn't been started.");
|
||||
}
|
||||
|
||||
var ares = BeginGetContext(new HttpListenerAsyncResult(null, null));
|
||||
ares.InGet = true;
|
||||
var result = BeginGetContext(new HttpListenerAsyncResult(null, null));
|
||||
result.InGet = true;
|
||||
|
||||
return EndGetContext(ares);
|
||||
return EndGetContext(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -593,14 +593,14 @@ namespace EonaCat.Network
|
|||
_listening = false;
|
||||
EndPointManager.RemoveListener(this);
|
||||
|
||||
lock (_ctxRegistrySync)
|
||||
lock (_contextRegistryLock)
|
||||
{
|
||||
cleanupContextQueue(true);
|
||||
CleanupContextQueue(true);
|
||||
}
|
||||
|
||||
cleanupContextRegistry();
|
||||
cleanupConnections();
|
||||
cleanupWaitQueue(new HttpListenerException(995, "The listener is closed."));
|
||||
CleanupContextRegistry();
|
||||
CleanupConnections();
|
||||
CleanupWaitQueue(new HttpListenerException(995, "The listener is closed."));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -86,10 +86,7 @@ namespace EonaCat.Network
|
|||
asyncResult._completed = true;
|
||||
|
||||
var waitHandle = asyncResult._waitHandle;
|
||||
if (waitHandle != null)
|
||||
{
|
||||
waitHandle.Set();
|
||||
}
|
||||
waitHandle?.Set();
|
||||
}
|
||||
|
||||
var callback = asyncResult._callback;
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace EonaCat.Network
|
|||
/// </summary>
|
||||
public sealed class HttpListenerContext
|
||||
{
|
||||
private HttpListenerWebSocketContext _websocketContext;
|
||||
private HttpListenerWSContext _websocketContext;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpListenerContext"/> class.
|
||||
|
@ -124,8 +124,8 @@ namespace EonaCat.Network
|
|||
/// Accepts a WebSocket connection with the specified protocol.
|
||||
/// </summary>
|
||||
/// <param name="protocol">The WebSocket subprotocol to negotiate.</param>
|
||||
/// <returns>The <see cref="HttpListenerWebSocketContext"/> for the WebSocket connection.</returns>
|
||||
public HttpListenerWebSocketContext AcceptWebSocket(string protocol)
|
||||
/// <returns>The <see cref="HttpListenerWSContext"/> for the WebSocket connection.</returns>
|
||||
public HttpListenerWSContext AcceptWebSocket(string protocol)
|
||||
{
|
||||
if (_websocketContext != null)
|
||||
{
|
||||
|
@ -145,7 +145,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
_websocketContext = new HttpListenerWebSocketContext(this, protocol);
|
||||
_websocketContext = new HttpListenerWSContext(this, protocol);
|
||||
return _websocketContext;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -251,8 +251,7 @@ namespace EonaCat.Network
|
|||
|
||||
if (lower == "content-length")
|
||||
{
|
||||
long len;
|
||||
if (long.TryParse(val, out len) && len >= 0)
|
||||
if (long.TryParse(val, out long len) && len >= 0)
|
||||
{
|
||||
ContentLength64 = len;
|
||||
_contentLengthSet = true;
|
||||
|
@ -359,13 +358,13 @@ namespace EonaCat.Network
|
|||
{
|
||||
try
|
||||
{
|
||||
var ares = InputStream.BeginRead(buff, 0, len, null, null);
|
||||
if (!ares.IsCompleted && !ares.AsyncWaitHandle.WaitOne(100))
|
||||
var result = InputStream.BeginRead(buff, 0, len, null, null);
|
||||
if (!result.IsCompleted && !result.AsyncWaitHandle.WaitOne(100))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (InputStream.EndRead(ares) <= 0)
|
||||
if (InputStream.EndRead(result) <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -218,8 +218,7 @@ namespace EonaCat.Network
|
|||
return;
|
||||
}
|
||||
|
||||
Uri uri = null;
|
||||
if (!value.MaybeUri() || !Uri.TryCreate(value, UriKind.Absolute, out uri))
|
||||
if (!value.MaybeUri() || !Uri.TryCreate(value, UriKind.Absolute, out Uri uri))
|
||||
{
|
||||
throw new ArgumentException("Not an absolute URL.", nameof(value));
|
||||
}
|
||||
|
@ -405,10 +404,7 @@ namespace EonaCat.Network
|
|||
|
||||
if (templateResponse._headers != null)
|
||||
{
|
||||
if (_headers != null)
|
||||
{
|
||||
_headers.Clear();
|
||||
}
|
||||
_headers?.Clear();
|
||||
|
||||
Headers.Add(templateResponse._headers);
|
||||
}
|
||||
|
@ -447,8 +443,7 @@ namespace EonaCat.Network
|
|||
throw new ArgumentNullException(nameof(url));
|
||||
}
|
||||
|
||||
Uri uri = null;
|
||||
if (!url.MaybeUri() || !Uri.TryCreate(url, UriKind.Absolute, out uri))
|
||||
if (!url.MaybeUri() || !Uri.TryCreate(url, UriKind.Absolute, out Uri uri))
|
||||
{
|
||||
throw new ArgumentException("Not an absolute URL.", nameof(url));
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace EonaCat.Network
|
|||
internal class HttpStreamAsyncResult : IAsyncResult
|
||||
{
|
||||
private readonly AsyncCallback _callback;
|
||||
private bool _completed;
|
||||
private bool _isCompleted;
|
||||
private readonly object _sync;
|
||||
private ManualResetEvent _waitHandle;
|
||||
|
||||
|
@ -40,7 +40,7 @@ namespace EonaCat.Network
|
|||
{
|
||||
lock (_sync)
|
||||
{
|
||||
return _waitHandle ??= new ManualResetEvent(_completed);
|
||||
return _waitHandle ??= new ManualResetEvent(_isCompleted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ namespace EonaCat.Network
|
|||
{
|
||||
lock (_sync)
|
||||
{
|
||||
return _completed;
|
||||
return _isCompleted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,17 +62,14 @@ namespace EonaCat.Network
|
|||
{
|
||||
lock (_sync)
|
||||
{
|
||||
if (_completed)
|
||||
if (_isCompleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_completed = true;
|
||||
_isCompleted = true;
|
||||
|
||||
if (_waitHandle != null)
|
||||
{
|
||||
_waitHandle.Set();
|
||||
}
|
||||
_waitHandle?.Set();
|
||||
|
||||
_callback?.Invoke(this);
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (_entities == null)
|
||||
{
|
||||
initEntities();
|
||||
GenerateHtmlEntityRefrencesDictionary();
|
||||
}
|
||||
|
||||
return _entities;
|
||||
|
@ -90,10 +90,9 @@ namespace EonaCat.Network
|
|||
: -1;
|
||||
}
|
||||
|
||||
private static void initEntities()
|
||||
private static void GenerateHtmlEntityRefrencesDictionary()
|
||||
{
|
||||
// Build the dictionary of HTML entity references.
|
||||
// This list comes from the HTML 4.01 W3C recommendation.
|
||||
_entities = new Dictionary<string, char>
|
||||
{
|
||||
{ "nbsp", '\u00A0' },
|
||||
|
@ -491,8 +490,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
else if (requestUri.MaybeUri())
|
||||
{
|
||||
Uri uri;
|
||||
var valid = Uri.TryCreate(requestUri, UriKind.Absolute, out uri) &&
|
||||
var valid = Uri.TryCreate(requestUri, UriKind.Absolute, out Uri uri) &&
|
||||
(((schm = uri.Scheme).StartsWith("http") && !websocketRequest) ||
|
||||
(schm.StartsWith("ws") && websocketRequest));
|
||||
|
||||
|
@ -523,8 +521,7 @@ namespace EonaCat.Network
|
|||
|
||||
var url = string.Format("{0}://{1}{2}", schm, host, path);
|
||||
|
||||
Uri res;
|
||||
if (!Uri.TryCreate(url, UriKind.Absolute, out res))
|
||||
if (!Uri.TryCreate(url, UriKind.Absolute, out Uri res))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -5,12 +5,24 @@ using System;
|
|||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents HTTP versions.
|
||||
/// </summary>
|
||||
public class HttpVersion
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the HTTP version 1.0.
|
||||
/// </summary>
|
||||
public static readonly Version Version10 = new Version(1, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the HTTP version 1.1.
|
||||
/// </summary>
|
||||
public static readonly Version Version11 = new Version(1, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpVersion"/> class.
|
||||
/// </summary>
|
||||
public HttpVersion()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -6,7 +6,15 @@ namespace EonaCat.Network
|
|||
internal enum LineState
|
||||
{
|
||||
None,
|
||||
Cr,
|
||||
Lf
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor to the beginning of the current line
|
||||
/// </summary>
|
||||
CarriageReturn,
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor down to the next line and then to the beginning of the line
|
||||
/// </summary>
|
||||
LineFeed
|
||||
}
|
||||
}
|
|
@ -8,24 +8,24 @@ using System.Security.Cryptography.X509Certificates;
|
|||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
public class SSLConfigurationClient
|
||||
public class SSLConfigClient
|
||||
{
|
||||
private LocalCertificateSelectionCallback _clientCertSelectionCallback;
|
||||
private X509CertificateCollection _clientCertificates;
|
||||
private RemoteCertificateValidationCallback _serverCertValidationCallback;
|
||||
|
||||
public SSLConfigurationClient()
|
||||
public SSLConfigClient()
|
||||
{
|
||||
SslProtocols = SslProtocols.Tls12;
|
||||
}
|
||||
|
||||
public SSLConfigurationClient(string targetHost)
|
||||
public SSLConfigClient(string targetHost)
|
||||
{
|
||||
TargetHost = targetHost;
|
||||
SslProtocols = SslProtocols.Tls12;
|
||||
}
|
||||
|
||||
public SSLConfigurationClient(SSLConfigurationClient configuration)
|
||||
public SSLConfigClient(SSLConfigClient configuration)
|
||||
{
|
||||
if (configuration == null)
|
||||
{
|
|
@ -8,22 +8,22 @@ using System.Security.Cryptography.X509Certificates;
|
|||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
public class SSLConfigurationServer
|
||||
public class SSLConfigServer
|
||||
{
|
||||
private RemoteCertificateValidationCallback _clientCertValidationCallback;
|
||||
private RemoteCertificateValidationCallback _clientCertificationValidationCallback;
|
||||
|
||||
public SSLConfigurationServer()
|
||||
public SSLConfigServer()
|
||||
{
|
||||
SslProtocols = SslProtocols.Tls12;
|
||||
}
|
||||
|
||||
public SSLConfigurationServer(X509Certificate2 certificate)
|
||||
public SSLConfigServer(X509Certificate2 certificate)
|
||||
{
|
||||
Certificate = certificate;
|
||||
SslProtocols = SslProtocols.Tls12;
|
||||
}
|
||||
|
||||
public SSLConfigurationServer(SSLConfigurationServer configuration)
|
||||
public SSLConfigServer(SSLConfigServer configuration)
|
||||
{
|
||||
if (configuration == null)
|
||||
{
|
||||
|
@ -32,7 +32,7 @@ namespace EonaCat.Network
|
|||
|
||||
CheckForCertificateRevocation = configuration.CheckForCertificateRevocation;
|
||||
IsClientCertificateRequired = configuration.IsClientCertificateRequired;
|
||||
_clientCertValidationCallback = configuration._clientCertValidationCallback;
|
||||
_clientCertificationValidationCallback = configuration._clientCertificationValidationCallback;
|
||||
SslProtocols = configuration.SslProtocols;
|
||||
Certificate = configuration.Certificate;
|
||||
}
|
||||
|
@ -45,14 +45,14 @@ namespace EonaCat.Network
|
|||
{
|
||||
get
|
||||
{
|
||||
_clientCertValidationCallback ??= ValidateClientCertificate;
|
||||
_clientCertificationValidationCallback ??= ValidateClientCertificate;
|
||||
|
||||
return _clientCertValidationCallback;
|
||||
return _clientCertificationValidationCallback;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_clientCertValidationCallback = value;
|
||||
_clientCertificationValidationCallback = value;
|
||||
}
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ namespace EonaCat.Network
|
|||
// Returns 0 if we can keep reading from the base stream,
|
||||
// > 0 if we read something from the buffer,
|
||||
// -1 if we had a content length set and we finished reading that many bytes.
|
||||
private int fillFromBuffer(byte[] buffer, int offset, int count)
|
||||
private int FillFromBuffer(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
|
@ -71,8 +71,8 @@ namespace EonaCat.Network
|
|||
throw new ArgumentOutOfRangeException(nameof(count), "A negative value.");
|
||||
}
|
||||
|
||||
var len = buffer.Length;
|
||||
if (offset + count > len)
|
||||
var bufferLength = buffer.Length;
|
||||
if (offset + count > bufferLength)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"The sum of 'offset' and 'count' is greater than 'buffer' length.");
|
||||
|
@ -117,17 +117,16 @@ namespace EonaCat.Network
|
|||
throw new ObjectDisposedException(GetType().ToString());
|
||||
}
|
||||
|
||||
var nread = fillFromBuffer(buffer, offset, count);
|
||||
var nread = FillFromBuffer(buffer, offset, count);
|
||||
if (nread > 0 || nread == -1)
|
||||
{
|
||||
var ares = new HttpStreamAsyncResult(callback, state);
|
||||
ares.Buffer = buffer;
|
||||
ares.Offset = offset;
|
||||
ares.Count = count;
|
||||
ares.SyncRead = nread > 0 ? nread : 0;
|
||||
ares.Complete();
|
||||
|
||||
return ares;
|
||||
var result = new HttpStreamAsyncResult(callback, state);
|
||||
result.Buffer = buffer;
|
||||
result.Offset = offset;
|
||||
result.Count = count;
|
||||
result.SyncRead = nread > 0 ? nread : 0;
|
||||
result.Complete();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Avoid reading past the end of the request to allow for HTTP pipelining.
|
||||
|
@ -164,13 +163,13 @@ namespace EonaCat.Network
|
|||
|
||||
if (asyncResult is HttpStreamAsyncResult)
|
||||
{
|
||||
var ares = (HttpStreamAsyncResult)asyncResult;
|
||||
if (!ares.IsCompleted)
|
||||
var result = (HttpStreamAsyncResult)asyncResult;
|
||||
if (!result.IsCompleted)
|
||||
{
|
||||
ares.AsyncWaitHandle.WaitOne();
|
||||
result.AsyncWaitHandle.WaitOne();
|
||||
}
|
||||
|
||||
return ares.SyncRead;
|
||||
return result.SyncRead;
|
||||
}
|
||||
|
||||
// Close on exception?
|
||||
|
@ -200,7 +199,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
|
||||
// Call the fillFromBuffer method to check for buffer boundaries even when _bodyLeft is 0.
|
||||
var nread = fillFromBuffer(buffer, offset, count);
|
||||
var nread = FillFromBuffer(buffer, offset, count);
|
||||
if (nread == -1) // No more bytes available (Content-Length).
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -11,24 +11,24 @@ namespace EonaCat.Network
|
|||
private bool _dataSet;
|
||||
private readonly byte[] _rawData;
|
||||
|
||||
internal MessageEventArgs(WebSocketFrame frame)
|
||||
internal MessageEventArgs(WSFrame frame)
|
||||
{
|
||||
Opcode = frame.Opcode;
|
||||
_rawData = frame.PayloadData.ApplicationData;
|
||||
}
|
||||
|
||||
internal MessageEventArgs(Opcode opcode, byte[] rawData)
|
||||
internal MessageEventArgs(OperationCode opcode, byte[] rawData)
|
||||
{
|
||||
if ((ulong)rawData.LongLength > PayloadData.MaxLength)
|
||||
{
|
||||
throw new WebSocketException(CloseStatusCode.TooBig);
|
||||
throw new WSException(CloseStatusCode.TooBig);
|
||||
}
|
||||
|
||||
Opcode = opcode;
|
||||
_rawData = rawData;
|
||||
}
|
||||
|
||||
internal Opcode Opcode { get; }
|
||||
internal OperationCode Opcode { get; }
|
||||
|
||||
public string Data
|
||||
{
|
||||
|
@ -39,11 +39,11 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
public bool IsBinary => Opcode == Opcode.Binary;
|
||||
public bool IsBinary => Opcode == OperationCode.Binary;
|
||||
|
||||
public bool IsPing => Opcode == Opcode.Ping;
|
||||
public bool IsPing => Opcode == OperationCode.Ping;
|
||||
|
||||
public bool IsText => Opcode == Opcode.Text;
|
||||
public bool IsText => Opcode == OperationCode.Text;
|
||||
|
||||
public byte[] RawData
|
||||
{
|
||||
|
@ -61,7 +61,7 @@ namespace EonaCat.Network
|
|||
return;
|
||||
}
|
||||
|
||||
if (Opcode == Opcode.Binary)
|
||||
if (Opcode == OperationCode.Binary)
|
||||
{
|
||||
_dataSet = true;
|
||||
return;
|
||||
|
|
|
@ -406,9 +406,9 @@ namespace EonaCat.Network
|
|||
return opcode > 0x7 && opcode < 0x10;
|
||||
}
|
||||
|
||||
internal static bool IsControl(this Opcode opcode)
|
||||
internal static bool IsControl(this OperationCode opcode)
|
||||
{
|
||||
return opcode >= Opcode.Close;
|
||||
return opcode >= OperationCode.Close;
|
||||
}
|
||||
|
||||
internal static bool IsData(this byte opcode)
|
||||
|
@ -416,9 +416,9 @@ namespace EonaCat.Network
|
|||
return opcode == 0x1 || opcode == 0x2;
|
||||
}
|
||||
|
||||
internal static bool IsData(this Opcode opcode)
|
||||
internal static bool IsData(this OperationCode opcode)
|
||||
{
|
||||
return opcode == Opcode.Text || opcode == Opcode.Binary;
|
||||
return opcode == OperationCode.Text || opcode == OperationCode.Binary;
|
||||
}
|
||||
|
||||
internal static bool IsPortNumber(this int value)
|
||||
|
@ -428,10 +428,10 @@ namespace EonaCat.Network
|
|||
|
||||
internal static bool IsReserved(this ushort code)
|
||||
{
|
||||
return code == 1004
|
||||
|| code == 1005
|
||||
|| code == 1006
|
||||
|| code == 1015;
|
||||
return code == (ushort)CloseStatusCode.Undefined
|
||||
|| code == (ushort)CloseStatusCode.NoStatus
|
||||
|| code == (ushort)CloseStatusCode.Abnormal
|
||||
|| code == (ushort)CloseStatusCode.TlsHandshakeFailure;
|
||||
}
|
||||
|
||||
internal static bool IsReserved(this CloseStatusCode code)
|
||||
|
@ -444,7 +444,7 @@ namespace EonaCat.Network
|
|||
|
||||
internal static bool IsSupported(this byte opcode)
|
||||
{
|
||||
return Enum.IsDefined(typeof(Opcode), opcode);
|
||||
return Enum.IsDefined(typeof(OperationCode), opcode);
|
||||
}
|
||||
|
||||
internal static bool IsText(this string value)
|
||||
|
@ -855,8 +855,7 @@ namespace EonaCat.Network
|
|||
return null;
|
||||
}
|
||||
|
||||
System.Net.IPAddress addr;
|
||||
if (System.Net.IPAddress.TryParse(value, out addr))
|
||||
if (System.Net.IPAddress.TryParse(value, out System.Net.IPAddress addr))
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
|
@ -1542,7 +1541,7 @@ namespace EonaCat.Network
|
|||
? BitConverter.GetBytes((uint)(object)value)
|
||||
: type == typeof(ulong)
|
||||
? BitConverter.GetBytes((ulong)(object)value)
|
||||
: WebSocket.EmptyBytes;
|
||||
: WSClient.EmptyBytes;
|
||||
|
||||
if (bytes.Length > 1 && !order.IsHostOrder())
|
||||
{
|
||||
|
@ -1586,9 +1585,8 @@ namespace EonaCat.Network
|
|||
|
||||
public static Uri ToUri(this string value)
|
||||
{
|
||||
Uri ret;
|
||||
Uri.TryCreate(
|
||||
value, value.MaybeUri() ? UriKind.Absolute : UriKind.Relative, out ret
|
||||
value, value.MaybeUri() ? UriKind.Absolute : UriKind.Relative, out Uri ret
|
||||
);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
internal enum Opcode : byte
|
||||
internal enum OperationCode : byte
|
||||
{
|
||||
Cont = 0x0,
|
||||
|
|
@ -28,10 +28,10 @@ namespace EonaCat.Network
|
|||
|
||||
internal PayloadData()
|
||||
{
|
||||
_code = 1005;
|
||||
_code = (ushort)CloseStatusCode.NoStatus;
|
||||
_reason = string.Empty;
|
||||
|
||||
_data = WebSocket.EmptyBytes;
|
||||
_data = WSClient.EmptyBytes;
|
||||
|
||||
_codeSet = true;
|
||||
_reasonSet = true;
|
||||
|
@ -68,7 +68,7 @@ namespace EonaCat.Network
|
|||
{
|
||||
_code = _length > 1
|
||||
? _data.SubArray(0, 2).ToUInt16(ByteOrder.Big)
|
||||
: (ushort)1005;
|
||||
: (ushort)CloseStatusCode.NoStatus;
|
||||
|
||||
_codeSet = true;
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ namespace EonaCat.Network
|
|||
|
||||
public byte[] ExtensionData => ExtensionDataLength > 0
|
||||
? _data.SubArray(0, ExtensionDataLength)
|
||||
: WebSocket.EmptyBytes;
|
||||
: WSClient.EmptyBytes;
|
||||
|
||||
public ulong Length => (ulong)_length;
|
||||
|
||||
|
|
|
@ -74,8 +74,7 @@ namespace EonaCat.Network
|
|||
throw new ArgumentException("It contains '..'.", nameof(path));
|
||||
}
|
||||
|
||||
byte[] contents;
|
||||
tryReadFile(createFilePath(path), out contents);
|
||||
tryReadFile(createFilePath(path), out byte[] contents);
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
|
|
@ -40,11 +40,9 @@ namespace EonaCat.Network
|
|||
throw new ArgumentException("An empty string.", nameof(url));
|
||||
}
|
||||
|
||||
Uri uri;
|
||||
string msg;
|
||||
if (!tryCreateUri(url, out uri, out msg))
|
||||
if (!tryCreateUri(url, out Uri uri, out string message))
|
||||
{
|
||||
throw new ArgumentException(msg, nameof(url));
|
||||
throw new ArgumentException(message, nameof(url));
|
||||
}
|
||||
|
||||
var host = uri.GetDnsSafeHost(true);
|
||||
|
@ -52,14 +50,14 @@ namespace EonaCat.Network
|
|||
var addr = host.ToIPAddress();
|
||||
if (addr == null)
|
||||
{
|
||||
msg = "The host part could not be converted to an IP address.";
|
||||
throw new ArgumentException(msg, nameof(url));
|
||||
message = "The host part could not be converted to an IP address.";
|
||||
throw new ArgumentException(message, nameof(url));
|
||||
}
|
||||
|
||||
if (!addr.IsLocal())
|
||||
{
|
||||
msg = "The IP address of the host is not a local IP address.";
|
||||
throw new ArgumentException(msg, nameof(url));
|
||||
message = "The IP address of the host is not a local IP address.";
|
||||
throw new ArgumentException(message, nameof(url));
|
||||
}
|
||||
|
||||
init(host, addr, uri.Port, uri.Scheme == "https");
|
||||
|
@ -69,8 +67,8 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (!port.IsPortNumber())
|
||||
{
|
||||
var msg = "Less than 1 or greater than 65535.";
|
||||
throw new ArgumentOutOfRangeException(nameof(port), msg);
|
||||
var message = "Less than 1 or greater than 65535.";
|
||||
throw new ArgumentOutOfRangeException(nameof(port), message);
|
||||
}
|
||||
|
||||
init("*", System.Net.IPAddress.Any, port, secure);
|
||||
|
@ -95,8 +93,8 @@ namespace EonaCat.Network
|
|||
|
||||
if (!port.IsPortNumber())
|
||||
{
|
||||
var msg = "Less than 1 or greater than 65535.";
|
||||
throw new ArgumentOutOfRangeException(nameof(port), msg);
|
||||
var message = "Less than 1 or greater than 65535.";
|
||||
throw new ArgumentOutOfRangeException(nameof(port), message);
|
||||
}
|
||||
|
||||
init(address.ToString(true), address, port, secure);
|
||||
|
@ -113,18 +111,17 @@ namespace EonaCat.Network
|
|||
|
||||
set
|
||||
{
|
||||
string msg;
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out string message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -190,18 +187,17 @@ namespace EonaCat.Network
|
|||
throw new ArgumentException("An absolute root.", nameof(value));
|
||||
}
|
||||
|
||||
string msg;
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out string message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -240,18 +236,17 @@ namespace EonaCat.Network
|
|||
|
||||
set
|
||||
{
|
||||
string msg;
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out string message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -269,18 +264,17 @@ namespace EonaCat.Network
|
|||
|
||||
set
|
||||
{
|
||||
string msg;
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out string message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -289,14 +283,14 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
public SSLConfigurationServer SslConfiguration
|
||||
public SSLConfigServer SslConfiguration
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsSecure)
|
||||
{
|
||||
var msg = "This instance does not provide secure connections.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "This instance does not provide secure connections.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
return _listener.SslConfiguration;
|
||||
|
@ -312,18 +306,17 @@ namespace EonaCat.Network
|
|||
|
||||
set
|
||||
{
|
||||
string msg;
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out string message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -381,7 +374,7 @@ namespace EonaCat.Network
|
|||
{
|
||||
try
|
||||
{
|
||||
WebSocketServices.Stop(1006, string.Empty);
|
||||
WebSocketServices.Stop((ushort)CloseStatusCode.Abnormal, string.Empty);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -440,15 +433,6 @@ namespace EonaCat.Network
|
|||
return true;
|
||||
}
|
||||
|
||||
private string createFilePath(string childPath)
|
||||
{
|
||||
childPath = childPath.TrimStart('/', '\\');
|
||||
return new StringBuilder(_docRootPath, 32)
|
||||
.AppendFormat("/{0}", childPath)
|
||||
.ToString()
|
||||
.Replace('\\', '/');
|
||||
}
|
||||
|
||||
private static HttpListener createListener(
|
||||
string hostname, int port, bool secure
|
||||
)
|
||||
|
@ -512,12 +496,11 @@ namespace EonaCat.Network
|
|||
context.Response.Close();
|
||||
}
|
||||
|
||||
private void processRequest(HttpListenerWebSocketContext context)
|
||||
private void processRequest(HttpListenerWSContext context)
|
||||
{
|
||||
var path = context.RequestUri.AbsolutePath;
|
||||
|
||||
WSEndpointHost host;
|
||||
if (!WebSocketServices.InternalTryGetServiceHost(path, out host))
|
||||
if (!WebSocketServices.InternalTryGetServiceHost(path, out WSEndpointHost host))
|
||||
{
|
||||
context.Close(HttpStatusCode.NotImplemented);
|
||||
return;
|
||||
|
@ -572,10 +555,7 @@ namespace EonaCat.Network
|
|||
Logger.Error(ex.Message);
|
||||
Logger.Debug(ex.ToString());
|
||||
|
||||
if (ctx != null)
|
||||
{
|
||||
ctx.Connection.Close(true);
|
||||
}
|
||||
ctx?.Connection.Close(true);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -623,7 +603,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
catch
|
||||
{
|
||||
WebSocketServices.Stop(1011, string.Empty);
|
||||
WebSocketServices.Stop((ushort)CloseStatusCode.ServerError, string.Empty);
|
||||
throw;
|
||||
}
|
||||
|
||||
|
@ -637,10 +617,10 @@ namespace EonaCat.Network
|
|||
{
|
||||
_listener.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception exception)
|
||||
{
|
||||
var msg = "The underlying listener has failed to start.";
|
||||
throw new InvalidOperationException(msg, ex);
|
||||
var message = "The underlying listener has failed to start.";
|
||||
throw new InvalidOperationException(message, exception);
|
||||
}
|
||||
|
||||
_receiveThread = new Thread(new ThreadStart(receiveRequest));
|
||||
|
@ -650,7 +630,7 @@ namespace EonaCat.Network
|
|||
|
||||
private void stop(ushort code, string reason)
|
||||
{
|
||||
if (_state == ServerState.Ready)
|
||||
if (_state == ServerState.Started)
|
||||
{
|
||||
Logger.Info("The server is not started.");
|
||||
return;
|
||||
|
@ -796,10 +776,9 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (IsSecure)
|
||||
{
|
||||
string msg;
|
||||
if (!checkCertificate(out msg))
|
||||
if (!checkCertificate(out string message))
|
||||
{
|
||||
throw new InvalidOperationException(msg);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -808,42 +787,41 @@ namespace EonaCat.Network
|
|||
|
||||
public void Stop()
|
||||
{
|
||||
stop(1005, string.Empty);
|
||||
stop((ushort)CloseStatusCode.NoStatus, string.Empty);
|
||||
}
|
||||
|
||||
public void Stop(ushort code, string reason)
|
||||
{
|
||||
if (!code.IsCloseStatusCode())
|
||||
{
|
||||
var msg = "Less than 1000 or greater than 4999.";
|
||||
throw new ArgumentOutOfRangeException(nameof(code), msg);
|
||||
var message = "Less than 1000 or greater than 4999.";
|
||||
throw new ArgumentOutOfRangeException(nameof(code), message);
|
||||
}
|
||||
|
||||
if (code == 1010)
|
||||
if (code == (ushort)CloseStatusCode.MandatoryExtension)
|
||||
{
|
||||
var msg = "1010 cannot be used.";
|
||||
throw new ArgumentException(msg, nameof(code));
|
||||
var message = $"{(ushort)CloseStatusCode.MandatoryExtension} cannot be used.";
|
||||
throw new ArgumentException(message, nameof(code));
|
||||
}
|
||||
|
||||
if (!reason.IsNullOrEmpty())
|
||||
{
|
||||
if (code == 1005)
|
||||
if (code == (ushort)CloseStatusCode.NoStatus)
|
||||
{
|
||||
var msg = "1005 cannot be used.";
|
||||
throw new ArgumentException(msg, nameof(code));
|
||||
var message = $"{(ushort)CloseStatusCode.NoStatus} cannot be used.";
|
||||
throw new ArgumentException(message, nameof(code));
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
if (!reason.TryGetUTF8EncodedBytes(out bytes))
|
||||
if (!reason.TryGetUTF8EncodedBytes(out byte[] bytes))
|
||||
{
|
||||
var msg = "It could not be UTF-8-encoded.";
|
||||
throw new ArgumentException(msg, nameof(reason));
|
||||
var message = "It could not be UTF-8-encoded.";
|
||||
throw new ArgumentException(message, nameof(reason));
|
||||
}
|
||||
|
||||
if (bytes.Length > 123)
|
||||
{
|
||||
var msg = "Its size is greater than 123 bytes.";
|
||||
throw new ArgumentOutOfRangeException(nameof(reason), msg);
|
||||
var message = "Its size is greater than 123 bytes.";
|
||||
throw new ArgumentOutOfRangeException(nameof(reason), message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -854,29 +832,28 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (code == CloseStatusCode.MandatoryExtension)
|
||||
{
|
||||
var msg = "MandatoryExtension cannot be used.";
|
||||
throw new ArgumentException(msg, nameof(code));
|
||||
var message = "MandatoryExtension cannot be used.";
|
||||
throw new ArgumentException(message, nameof(code));
|
||||
}
|
||||
|
||||
if (!reason.IsNullOrEmpty())
|
||||
{
|
||||
if (code == CloseStatusCode.NoStatus)
|
||||
{
|
||||
var msg = "NoStatus cannot be used.";
|
||||
throw new ArgumentException(msg, nameof(code));
|
||||
var message = "NoStatus cannot be used.";
|
||||
throw new ArgumentException(message, nameof(code));
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
if (!reason.TryGetUTF8EncodedBytes(out bytes))
|
||||
if (!reason.TryGetUTF8EncodedBytes(out byte[] bytes))
|
||||
{
|
||||
var msg = "It could not be UTF-8-encoded.";
|
||||
throw new ArgumentException(msg, nameof(reason));
|
||||
var message = "It could not be UTF-8-encoded.";
|
||||
throw new ArgumentException(message, nameof(reason));
|
||||
}
|
||||
|
||||
if (bytes.Length > 123)
|
||||
{
|
||||
var msg = "Its size is greater than 123 bytes.";
|
||||
throw new ArgumentOutOfRangeException(nameof(reason), msg);
|
||||
var message = "Its size is greater than 123 bytes.";
|
||||
throw new ArgumentOutOfRangeException(nameof(reason), message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace EonaCat.Network
|
|||
{
|
||||
public interface IWSSession
|
||||
{
|
||||
WebSocketContext Context { get; }
|
||||
WSContext Context { get; }
|
||||
|
||||
string ID { get; }
|
||||
|
||||
|
@ -15,6 +15,6 @@ namespace EonaCat.Network
|
|||
|
||||
DateTime StartTime { get; }
|
||||
|
||||
WebSocketState State { get; }
|
||||
WSState State { get; }
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ namespace EonaCat.Network
|
|||
{
|
||||
internal enum ServerState
|
||||
{
|
||||
Ready,
|
||||
Started,
|
||||
Start,
|
||||
ShuttingDown,
|
||||
Stop
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace EonaCat.Network
|
|||
{
|
||||
private bool _emitOnPing;
|
||||
private string _protocol;
|
||||
private WebSocket _websocket;
|
||||
private WSClient _websocket;
|
||||
|
||||
protected WSEndpoint()
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ namespace EonaCat.Network
|
|||
|
||||
protected WSSessionManager Sessions { get; private set; }
|
||||
|
||||
public WebSocketContext Context { get; private set; }
|
||||
public WSContext Context { get; private set; }
|
||||
|
||||
public Func<CookieCollection, CookieCollection, bool> CookiesValidator { get; set; }
|
||||
|
||||
|
@ -57,7 +57,7 @@ namespace EonaCat.Network
|
|||
|
||||
set
|
||||
{
|
||||
if (State != WebSocketState.Connecting)
|
||||
if (State != WSState.Connecting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -73,9 +73,9 @@ namespace EonaCat.Network
|
|||
|
||||
public DateTime StartTime { get; private set; }
|
||||
|
||||
public WebSocketState State => _websocket != null ? _websocket.ReadyState : WebSocketState.Connecting;
|
||||
public WSState State => _websocket != null ? _websocket.ReadyState : WSState.Connecting;
|
||||
|
||||
private string checkHandshakeRequest(WebSocketContext context)
|
||||
private string checkHandshakeRequest(WSContext context)
|
||||
{
|
||||
return OriginValidator != null && !OriginValidator(context.Origin)
|
||||
? "Includes no Origin header, or it has an invalid value."
|
||||
|
@ -119,7 +119,7 @@ namespace EonaCat.Network
|
|||
OnOpen();
|
||||
}
|
||||
|
||||
internal void Start(WebSocketContext context, WSSessionManager sessions)
|
||||
internal void Start(WSContext context, WSSessionManager sessions)
|
||||
{
|
||||
if (_websocket != null)
|
||||
{
|
||||
|
@ -178,58 +178,37 @@ namespace EonaCat.Network
|
|||
|
||||
protected void Send(byte[] data)
|
||||
{
|
||||
if (_websocket != null)
|
||||
{
|
||||
_websocket.Send(data);
|
||||
}
|
||||
_websocket?.Send(data);
|
||||
}
|
||||
|
||||
protected void Send(FileInfo file)
|
||||
{
|
||||
if (_websocket != null)
|
||||
{
|
||||
_websocket.Send(file);
|
||||
}
|
||||
_websocket?.Send(file);
|
||||
}
|
||||
|
||||
protected void Send(string data)
|
||||
{
|
||||
if (_websocket != null)
|
||||
{
|
||||
_websocket.Send(data);
|
||||
}
|
||||
_websocket?.Send(data);
|
||||
}
|
||||
|
||||
protected void SendAsync(byte[] data, Action<bool> completed)
|
||||
{
|
||||
if (_websocket != null)
|
||||
{
|
||||
_websocket.SendAsync(data, completed);
|
||||
}
|
||||
_websocket?.SendAsync(data, completed);
|
||||
}
|
||||
|
||||
protected void SendAsync(FileInfo file, Action<bool> completed)
|
||||
{
|
||||
if (_websocket != null)
|
||||
{
|
||||
_websocket.SendAsync(file, completed);
|
||||
}
|
||||
_websocket?.SendAsync(file, completed);
|
||||
}
|
||||
|
||||
protected void SendAsync(string data, Action<bool> completed)
|
||||
{
|
||||
if (_websocket != null)
|
||||
{
|
||||
_websocket.SendAsync(data, completed);
|
||||
}
|
||||
_websocket?.SendAsync(data, completed);
|
||||
}
|
||||
|
||||
protected void SendAsync(Stream stream, int length, Action<bool> completed)
|
||||
{
|
||||
if (_websocket != null)
|
||||
{
|
||||
_websocket.SendAsync(stream, length, completed);
|
||||
}
|
||||
_websocket?.SendAsync(stream, length, completed);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,7 +52,7 @@ namespace EonaCat.Network
|
|||
Sessions.Start();
|
||||
}
|
||||
|
||||
internal void StartSession(WebSocketContext context)
|
||||
internal void StartSession(WSContext context)
|
||||
{
|
||||
CreateSession().Start(context, Sessions);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace EonaCat.Network
|
|||
{
|
||||
_clean = true;
|
||||
_hosts = new Dictionary<string, WSEndpointHost>();
|
||||
_state = ServerState.Ready;
|
||||
_state = ServerState.Started;
|
||||
_sync = ((ICollection)_hosts).SyncRoot;
|
||||
_waitTime = TimeSpan.FromSeconds(1);
|
||||
}
|
||||
|
@ -69,12 +69,11 @@ namespace EonaCat.Network
|
|||
|
||||
if (path.IndexOfAny(new[] { '?', '#' }) > -1)
|
||||
{
|
||||
var msg = "It includes either or both query and fragment components.";
|
||||
throw new ArgumentException(msg, nameof(path));
|
||||
var message = "It includes either or both query and fragment components.";
|
||||
throw new ArgumentException(message, nameof(path));
|
||||
}
|
||||
|
||||
WSEndpointHost host;
|
||||
InternalTryGetServiceHost(path, out host);
|
||||
InternalTryGetServiceHost(path, out WSEndpointHost host);
|
||||
|
||||
return host;
|
||||
}
|
||||
|
@ -89,18 +88,17 @@ namespace EonaCat.Network
|
|||
|
||||
set
|
||||
{
|
||||
string msg;
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out string message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -139,18 +137,17 @@ namespace EonaCat.Network
|
|||
throw new ArgumentOutOfRangeException(nameof(value), "Zero or less.");
|
||||
}
|
||||
|
||||
string msg;
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out string message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -164,7 +161,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
private void broadcast(Opcode opcode, byte[] data, Action completed)
|
||||
private void broadcast(OperationCode opcode, byte[] data, Action completed)
|
||||
{
|
||||
var cache = new Dictionary<CompressionMethod, byte[]>();
|
||||
|
||||
|
@ -196,7 +193,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
private void broadcast(Opcode opcode, Stream stream, Action completed)
|
||||
private void broadcast(OperationCode opcode, Stream stream, Action completed)
|
||||
{
|
||||
var cache = new Dictionary<CompressionMethod, Stream>();
|
||||
|
||||
|
@ -233,41 +230,6 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
private void broadcastAsync(Opcode opcode, byte[] data, Action completed)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(
|
||||
state => broadcast(opcode, data, completed)
|
||||
);
|
||||
}
|
||||
|
||||
private void broadcastAsync(Opcode opcode, Stream stream, Action completed)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(
|
||||
state => broadcast(opcode, stream, completed)
|
||||
);
|
||||
}
|
||||
|
||||
private Dictionary<string, Dictionary<string, bool>> broadping(
|
||||
byte[] frameAsBytes, TimeSpan timeout
|
||||
)
|
||||
{
|
||||
var ret = new Dictionary<string, Dictionary<string, bool>>();
|
||||
|
||||
foreach (var host in Hosts)
|
||||
{
|
||||
if (_state != ServerState.Start)
|
||||
{
|
||||
Logger.Error("The server is shutting down.");
|
||||
break;
|
||||
}
|
||||
|
||||
var res = host.Sessions.Broadping(frameAsBytes, timeout);
|
||||
ret.Add(host.Path, res);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool canSet(out string message)
|
||||
{
|
||||
message = null;
|
||||
|
@ -294,8 +256,7 @@ namespace EonaCat.Network
|
|||
|
||||
lock (_sync)
|
||||
{
|
||||
WSEndpointHost host;
|
||||
if (_hosts.TryGetValue(path, out host))
|
||||
if (_hosts.TryGetValue(path, out WSEndpointHost host))
|
||||
{
|
||||
throw new ArgumentException("Already in use.", nameof(path));
|
||||
}
|
||||
|
@ -385,16 +346,15 @@ namespace EonaCat.Network
|
|||
|
||||
if (path.IndexOfAny(new[] { '?', '#' }) > -1)
|
||||
{
|
||||
var msg = "It includes either or both query and fragment components.";
|
||||
throw new ArgumentException(msg, nameof(path));
|
||||
var message = "It includes either or both query and fragment components.";
|
||||
throw new ArgumentException(message, nameof(path));
|
||||
}
|
||||
|
||||
path = HttpUtility.UrlDecode(path).TrimSlashFromEnd();
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
WSEndpointHost host;
|
||||
if (_hosts.TryGetValue(path, out host))
|
||||
if (_hosts.TryGetValue(path, out WSEndpointHost host))
|
||||
{
|
||||
throw new ArgumentException("Already in use.", nameof(path));
|
||||
}
|
||||
|
@ -436,7 +396,7 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (host.State == ServerState.Start)
|
||||
{
|
||||
host.Stop(1001, string.Empty);
|
||||
host.Stop((ushort)CloseStatusCode.Away, string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -460,8 +420,8 @@ namespace EonaCat.Network
|
|||
|
||||
if (path.IndexOfAny(new[] { '?', '#' }) > -1)
|
||||
{
|
||||
var msg = "It includes either or both query and fragment components.";
|
||||
throw new ArgumentException(msg, nameof(path));
|
||||
var message = "It includes either or both query and fragment components.";
|
||||
throw new ArgumentException(message, nameof(path));
|
||||
}
|
||||
|
||||
path = HttpUtility.UrlDecode(path).TrimSlashFromEnd();
|
||||
|
@ -479,7 +439,7 @@ namespace EonaCat.Network
|
|||
|
||||
if (host.State == ServerState.Start)
|
||||
{
|
||||
host.Stop(1001, string.Empty);
|
||||
host.Stop((ushort)CloseStatusCode.Away, string.Empty);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -504,8 +464,8 @@ namespace EonaCat.Network
|
|||
|
||||
if (path.IndexOfAny(new[] { '?', '#' }) > -1)
|
||||
{
|
||||
var msg = "It includes either or both query and fragment components.";
|
||||
throw new ArgumentException(msg, nameof(path));
|
||||
var message = "It includes either or both query and fragment components.";
|
||||
throw new ArgumentException(message, nameof(path));
|
||||
}
|
||||
|
||||
return InternalTryGetServiceHost(path, out host);
|
||||
|
|
|
@ -22,8 +22,8 @@ namespace EonaCat.Network
|
|||
private string _realmInUse;
|
||||
private Thread _receiveThread;
|
||||
private bool _reuseAddress;
|
||||
private SSLConfigurationServer _sslConfig;
|
||||
private SSLConfigurationServer _sslConfigInUse;
|
||||
private SSLConfigServer _sslConfig;
|
||||
private SSLConfigServer _sslConfigInUse;
|
||||
private volatile ServerState _state;
|
||||
private object _sync;
|
||||
private Func<IIdentity, NetworkCredential> _userCredentialsFinder;
|
||||
|
@ -56,11 +56,9 @@ namespace EonaCat.Network
|
|||
throw new ArgumentException("An empty string.", nameof(url));
|
||||
}
|
||||
|
||||
Uri uri;
|
||||
string msg;
|
||||
if (!tryCreateUri(url, out uri, out msg))
|
||||
if (!tryCreateUri(url, out Uri uri, out string message))
|
||||
{
|
||||
throw new ArgumentException(msg, nameof(url));
|
||||
throw new ArgumentException(message, nameof(url));
|
||||
}
|
||||
|
||||
var host = uri.DnsSafeHost;
|
||||
|
@ -68,14 +66,14 @@ namespace EonaCat.Network
|
|||
var addr = host.ToIPAddress();
|
||||
if (addr == null)
|
||||
{
|
||||
msg = "The host part could not be converted to an IP address.";
|
||||
throw new ArgumentException(msg, nameof(url));
|
||||
message = "The host part could not be converted to an IP address.";
|
||||
throw new ArgumentException(message, nameof(url));
|
||||
}
|
||||
|
||||
if (!addr.IsLocal())
|
||||
{
|
||||
msg = "The IP address of the host is not a local IP address.";
|
||||
throw new ArgumentException(msg, nameof(url));
|
||||
message = "The IP address of the host is not a local IP address.";
|
||||
throw new ArgumentException(message, nameof(url));
|
||||
}
|
||||
|
||||
init(host, addr, uri.Port, uri.Scheme == "wss");
|
||||
|
@ -85,8 +83,8 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (!port.IsPortNumber())
|
||||
{
|
||||
var msg = "Less than 1 or greater than 65535.";
|
||||
throw new ArgumentOutOfRangeException(nameof(port), msg);
|
||||
var message = "Less than 1 or greater than 65535.";
|
||||
throw new ArgumentOutOfRangeException(nameof(port), message);
|
||||
}
|
||||
|
||||
var addr = System.Net.IPAddress.Any;
|
||||
|
@ -112,8 +110,8 @@ namespace EonaCat.Network
|
|||
|
||||
if (!port.IsPortNumber())
|
||||
{
|
||||
var msg = "Less than 1 or greater than 65535.";
|
||||
throw new ArgumentOutOfRangeException(nameof(port), msg);
|
||||
var message = "Less than 1 or greater than 65535.";
|
||||
throw new ArgumentOutOfRangeException(nameof(port), message);
|
||||
}
|
||||
|
||||
init(address.ToString(), address, port, secure);
|
||||
|
@ -130,18 +128,17 @@ namespace EonaCat.Network
|
|||
|
||||
set
|
||||
{
|
||||
string msg;
|
||||
if (!CanSet(out msg))
|
||||
if (!CanSet(out string message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!CanSet(out msg))
|
||||
if (!CanSet(out message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -159,18 +156,17 @@ namespace EonaCat.Network
|
|||
|
||||
set
|
||||
{
|
||||
string msg;
|
||||
if (!CanSet(out msg))
|
||||
if (!CanSet(out string message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!CanSet(out msg))
|
||||
if (!CanSet(out message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -210,18 +206,17 @@ namespace EonaCat.Network
|
|||
|
||||
set
|
||||
{
|
||||
string msg;
|
||||
if (!CanSet(out msg))
|
||||
if (!CanSet(out string message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!CanSet(out msg))
|
||||
if (!CanSet(out message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -239,18 +234,17 @@ namespace EonaCat.Network
|
|||
|
||||
set
|
||||
{
|
||||
string msg;
|
||||
if (!CanSet(out msg))
|
||||
if (!CanSet(out string message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!CanSet(out msg))
|
||||
if (!CanSet(out message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -259,14 +253,14 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
public SSLConfigurationServer SslConfiguration
|
||||
public SSLConfigServer SslConfiguration
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsSecure)
|
||||
{
|
||||
var msg = "This instance does not provide secure connections.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "This instance does not provide secure connections.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
return GetSslConfiguration();
|
||||
|
@ -282,8 +276,7 @@ namespace EonaCat.Network
|
|||
|
||||
set
|
||||
{
|
||||
string message;
|
||||
if (!CanSet(out message))
|
||||
if (!CanSet(out string message))
|
||||
{
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
|
@ -337,7 +330,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
finally
|
||||
{
|
||||
Endpoints.Stop(1006, string.Empty);
|
||||
Endpoints.Stop((ushort)CloseStatusCode.Abnormal, string.Empty);
|
||||
}
|
||||
}
|
||||
catch
|
||||
|
@ -374,7 +367,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
|
||||
private static bool CheckSslConfiguration(
|
||||
SSLConfigurationServer configuration, out string message
|
||||
SSLConfigServer configuration, out string message
|
||||
)
|
||||
{
|
||||
message = null;
|
||||
|
@ -394,9 +387,9 @@ namespace EonaCat.Network
|
|||
return realm != null && realm.Length > 0 ? realm : _defaultRealm;
|
||||
}
|
||||
|
||||
private SSLConfigurationServer GetSslConfiguration()
|
||||
private SSLConfigServer GetSslConfiguration()
|
||||
{
|
||||
_sslConfig ??= new SSLConfigurationServer();
|
||||
_sslConfig ??= new SSLConfigServer();
|
||||
|
||||
return _sslConfig;
|
||||
}
|
||||
|
@ -417,7 +410,7 @@ namespace EonaCat.Network
|
|||
_sync = new object();
|
||||
}
|
||||
|
||||
private void processRequest(TcpListenerWebSocketContext context)
|
||||
private void processRequest(TcpListenerWSContext context)
|
||||
{
|
||||
var uri = context.RequestUri;
|
||||
if (uri == null)
|
||||
|
@ -441,8 +434,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
WSEndpointHost host;
|
||||
if (!Endpoints.InternalTryGetServiceHost(uri.AbsolutePath, out host))
|
||||
if (!Endpoints.InternalTryGetServiceHost(uri.AbsolutePath, out WSEndpointHost host))
|
||||
{
|
||||
context.Close(HttpStatusCode.NotImplemented);
|
||||
return;
|
||||
|
@ -464,7 +456,7 @@ namespace EonaCat.Network
|
|||
{
|
||||
try
|
||||
{
|
||||
var ctx = new TcpListenerWebSocketContext(
|
||||
var ctx = new TcpListenerWSContext(
|
||||
cl, null, IsSecure, _sslConfigInUse);
|
||||
|
||||
if (!ctx.Authenticate(_authSchemes, _realmInUse, _userCredentialsFinder))
|
||||
|
@ -502,10 +494,7 @@ namespace EonaCat.Network
|
|||
Logger.Error(ex.Message);
|
||||
Logger.Debug(ex.ToString());
|
||||
|
||||
if (cl != null)
|
||||
{
|
||||
cl.Close();
|
||||
}
|
||||
cl?.Close();
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -517,7 +506,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
private void start(SSLConfigurationServer sslConfig)
|
||||
private void start(SSLConfigServer sslConfig)
|
||||
{
|
||||
Logger.IsLoggingEnabled = IsLoggingEnabled;
|
||||
Logger.DisableConsole = !IsConsoleLoggingEnabled;
|
||||
|
@ -558,7 +547,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
catch
|
||||
{
|
||||
Endpoints.Stop(1011, string.Empty);
|
||||
Endpoints.Stop((ushort)CloseStatusCode.ServerError, string.Empty);
|
||||
throw;
|
||||
}
|
||||
|
||||
|
@ -581,8 +570,8 @@ namespace EonaCat.Network
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var msg = "The underlying listener has failed to start.";
|
||||
throw new InvalidOperationException(msg, ex);
|
||||
var message = "The underlying listener has failed to start.";
|
||||
throw new InvalidOperationException(message, ex);
|
||||
}
|
||||
|
||||
_receiveThread = new Thread(new ThreadStart(receiveRequest));
|
||||
|
@ -592,7 +581,7 @@ namespace EonaCat.Network
|
|||
|
||||
private void stop(ushort code, string reason)
|
||||
{
|
||||
if (_state == ServerState.Ready)
|
||||
if (_state == ServerState.Started)
|
||||
{
|
||||
Logger.Info("The server is not started.");
|
||||
return;
|
||||
|
@ -668,8 +657,8 @@ namespace EonaCat.Network
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var msg = "The underlying listener has failed to stop.";
|
||||
throw new InvalidOperationException(msg, ex);
|
||||
var message = "The underlying listener has failed to stop.";
|
||||
throw new InvalidOperationException(message, ex);
|
||||
}
|
||||
|
||||
_receiveThread.Join(millisecondsTimeout);
|
||||
|
@ -712,14 +701,13 @@ namespace EonaCat.Network
|
|||
|
||||
public void Start()
|
||||
{
|
||||
SSLConfigurationServer sslConfig = null;
|
||||
SSLConfigServer sslConfig = null;
|
||||
|
||||
if (IsSecure)
|
||||
{
|
||||
sslConfig = new SSLConfigurationServer(GetSslConfiguration());
|
||||
sslConfig = new SSLConfigServer(GetSslConfiguration());
|
||||
|
||||
string message;
|
||||
if (!CheckSslConfiguration(sslConfig, out message))
|
||||
if (!CheckSslConfiguration(sslConfig, out string message))
|
||||
{
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
@ -730,42 +718,41 @@ namespace EonaCat.Network
|
|||
|
||||
public void Stop()
|
||||
{
|
||||
stop(1005, string.Empty);
|
||||
stop((ushort)CloseStatusCode.NoStatus, string.Empty);
|
||||
}
|
||||
|
||||
public void Stop(ushort code, string reason)
|
||||
{
|
||||
if (!code.IsCloseStatusCode())
|
||||
{
|
||||
var msg = "Less than 1000 or greater than 4999.";
|
||||
throw new ArgumentOutOfRangeException(nameof(code), msg);
|
||||
var message = "Less than 1000 or greater than 4999.";
|
||||
throw new ArgumentOutOfRangeException(nameof(code), message);
|
||||
}
|
||||
|
||||
if (code == 1010)
|
||||
if (code == (ushort)CloseStatusCode.MandatoryExtension)
|
||||
{
|
||||
var msg = "1010 cannot be used.";
|
||||
throw new ArgumentException(msg, nameof(code));
|
||||
var message = $"{(ushort)CloseStatusCode.MandatoryExtension} cannot be used.";
|
||||
throw new ArgumentException(message, nameof(code));
|
||||
}
|
||||
|
||||
if (!reason.IsNullOrEmpty())
|
||||
{
|
||||
if (code == 1005)
|
||||
if (code == (ushort)CloseStatusCode.NoStatus)
|
||||
{
|
||||
var msg = "1005 cannot be used.";
|
||||
throw new ArgumentException(msg, nameof(code));
|
||||
var message = $"{(ushort)CloseStatusCode.NoStatus} cannot be used.";
|
||||
throw new ArgumentException(message, nameof(code));
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
if (!reason.TryGetUTF8EncodedBytes(out bytes))
|
||||
if (!reason.TryGetUTF8EncodedBytes(out byte[] bytes))
|
||||
{
|
||||
var msg = "It could not be UTF-8-encoded.";
|
||||
throw new ArgumentException(msg, nameof(reason));
|
||||
var message = "It could not be UTF-8-encoded.";
|
||||
throw new ArgumentException(message, nameof(reason));
|
||||
}
|
||||
|
||||
if (bytes.Length > 123)
|
||||
{
|
||||
var msg = "Its size is greater than 123 bytes.";
|
||||
throw new ArgumentOutOfRangeException(nameof(reason), msg);
|
||||
var message = "Its size is greater than 123 bytes.";
|
||||
throw new ArgumentOutOfRangeException(nameof(reason), message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -776,29 +763,28 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (code == CloseStatusCode.MandatoryExtension)
|
||||
{
|
||||
var msg = "MandatoryExtension cannot be used.";
|
||||
throw new ArgumentException(msg, nameof(code));
|
||||
var message = "MandatoryExtension cannot be used.";
|
||||
throw new ArgumentException(message, nameof(code));
|
||||
}
|
||||
|
||||
if (!reason.IsNullOrEmpty())
|
||||
{
|
||||
if (code == CloseStatusCode.NoStatus)
|
||||
{
|
||||
var msg = "NoStatus cannot be used.";
|
||||
throw new ArgumentException(msg, nameof(code));
|
||||
var message = "NoStatus cannot be used.";
|
||||
throw new ArgumentException(message, nameof(code));
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
if (!reason.TryGetUTF8EncodedBytes(out bytes))
|
||||
if (!reason.TryGetUTF8EncodedBytes(out byte[] bytes))
|
||||
{
|
||||
var msg = "It could not be UTF-8-encoded.";
|
||||
throw new ArgumentException(msg, nameof(reason));
|
||||
var message = "It could not be UTF-8-encoded.";
|
||||
throw new ArgumentException(message, nameof(reason));
|
||||
}
|
||||
|
||||
if (bytes.Length > 123)
|
||||
{
|
||||
var msg = "Its size is greater than 123 bytes.";
|
||||
throw new ArgumentOutOfRangeException(nameof(reason), msg);
|
||||
var message = "Its size is greater than 123 bytes.";
|
||||
throw new ArgumentOutOfRangeException(nameof(reason), message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace EonaCat.Network
|
|||
_clean = true;
|
||||
_forSweep = new object();
|
||||
_sessions = new Dictionary<string, IWSSession>();
|
||||
_state = ServerState.Ready;
|
||||
_state = ServerState.Started;
|
||||
_sync = ((ICollection)_sessions).SyncRoot;
|
||||
_waitTime = TimeSpan.FromSeconds(1);
|
||||
|
||||
|
@ -39,7 +39,7 @@ namespace EonaCat.Network
|
|||
{
|
||||
get
|
||||
{
|
||||
foreach (var res in broadping(WebSocketFrame.EmptyPingBytes))
|
||||
foreach (var res in broadping(WSFrame.EmptyPingBytes))
|
||||
{
|
||||
if (res.Value)
|
||||
{
|
||||
|
@ -85,7 +85,7 @@ namespace EonaCat.Network
|
|||
{
|
||||
get
|
||||
{
|
||||
foreach (var res in broadping(WebSocketFrame.EmptyPingBytes))
|
||||
foreach (var res in broadping(WSFrame.EmptyPingBytes))
|
||||
{
|
||||
if (!res.Value)
|
||||
{
|
||||
|
@ -109,8 +109,7 @@ namespace EonaCat.Network
|
|||
throw new ArgumentException("An empty string.", nameof(id));
|
||||
}
|
||||
|
||||
IWSSession session;
|
||||
tryGetSession(id, out session);
|
||||
tryGetSession(id, out IWSSession session);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
@ -125,18 +124,17 @@ namespace EonaCat.Network
|
|||
|
||||
set
|
||||
{
|
||||
string msg;
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out string message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -180,18 +178,17 @@ namespace EonaCat.Network
|
|||
throw new ArgumentOutOfRangeException(nameof(value), "Zero or less.");
|
||||
}
|
||||
|
||||
string msg;
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out string message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!canSet(out msg))
|
||||
if (!canSet(out message))
|
||||
{
|
||||
Logger.Warning(msg);
|
||||
Logger.Warning(message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -200,7 +197,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
private void broadcast(Opcode opcode, byte[] data, Action completed)
|
||||
private void broadcast(OperationCode opcode, byte[] data, Action completed)
|
||||
{
|
||||
var cache = new Dictionary<CompressionMethod, byte[]>();
|
||||
|
||||
|
@ -233,7 +230,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
private void broadcast(Opcode opcode, Stream stream, Action completed)
|
||||
private void broadcast(OperationCode opcode, Stream stream, Action completed)
|
||||
{
|
||||
var cache = new Dictionary<CompressionMethod, Stream>();
|
||||
|
||||
|
@ -271,14 +268,14 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
private void broadcastAsync(Opcode opcode, byte[] data, Action completed)
|
||||
private void broadcastAsync(OperationCode opcode, byte[] data, Action completed)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(
|
||||
state => broadcast(opcode, data, completed)
|
||||
);
|
||||
}
|
||||
|
||||
private void broadcastAsync(Opcode opcode, Stream stream, Action completed)
|
||||
private void broadcastAsync(OperationCode opcode, Stream stream, Action completed)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(
|
||||
state => broadcast(opcode, stream, completed)
|
||||
|
@ -337,7 +334,7 @@ namespace EonaCat.Network
|
|||
private void stop(PayloadData payloadData, bool send)
|
||||
{
|
||||
var bytes = send
|
||||
? WebSocketFrame.CreateCloseFrame(payloadData, false).ToArray()
|
||||
? WSFrame.CreateCloseFrame(payloadData, false).ToArray()
|
||||
: null;
|
||||
|
||||
lock (_sync)
|
||||
|
@ -391,7 +388,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
|
||||
internal void Broadcast(
|
||||
Opcode opcode, byte[] data, Dictionary<CompressionMethod, byte[]> cache
|
||||
OperationCode opcode, byte[] data, Dictionary<CompressionMethod, byte[]> cache
|
||||
)
|
||||
{
|
||||
foreach (var session in Sessions)
|
||||
|
@ -407,7 +404,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
|
||||
internal void Broadcast(
|
||||
Opcode opcode, Stream stream, Dictionary<CompressionMethod, Stream> cache
|
||||
OperationCode opcode, Stream stream, Dictionary<CompressionMethod, Stream> cache
|
||||
)
|
||||
{
|
||||
foreach (var session in Sessions)
|
||||
|
@ -462,7 +459,7 @@ namespace EonaCat.Network
|
|||
|
||||
internal void Stop(ushort code, string reason)
|
||||
{
|
||||
if (code == 1005)
|
||||
if (code == (ushort)CloseStatusCode.NoStatus)
|
||||
{ // == no status
|
||||
stop(PayloadData.Empty, true);
|
||||
return;
|
||||
|
@ -475,8 +472,8 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (_state != ServerState.Start)
|
||||
{
|
||||
var msg = "The current state of the manager is not Start.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The current state of the manager is not Start.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
if (data == null)
|
||||
|
@ -484,13 +481,13 @@ namespace EonaCat.Network
|
|||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
|
||||
if (data.LongLength <= WebSocket.FragmentLength)
|
||||
if (data.LongLength <= WSClient.FragmentLength)
|
||||
{
|
||||
broadcast(Opcode.Binary, data, null);
|
||||
broadcast(OperationCode.Binary, data, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
broadcast(Opcode.Binary, new MemoryStream(data), null);
|
||||
broadcast(OperationCode.Binary, new MemoryStream(data), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -498,8 +495,8 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (_state != ServerState.Start)
|
||||
{
|
||||
var msg = "The current state of the manager is not Start.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The current state of the manager is not Start.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
if (data == null)
|
||||
|
@ -507,20 +504,19 @@ namespace EonaCat.Network
|
|||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
if (!data.TryGetUTF8EncodedBytes(out bytes))
|
||||
if (!data.TryGetUTF8EncodedBytes(out byte[] bytes))
|
||||
{
|
||||
var msg = "It could not be UTF-8-encoded.";
|
||||
throw new ArgumentException(msg, nameof(data));
|
||||
var message = "It could not be UTF-8-encoded.";
|
||||
throw new ArgumentException(message, nameof(data));
|
||||
}
|
||||
|
||||
if (bytes.LongLength <= WebSocket.FragmentLength)
|
||||
if (bytes.LongLength <= WSClient.FragmentLength)
|
||||
{
|
||||
broadcast(Opcode.Text, bytes, null);
|
||||
broadcast(OperationCode.Text, bytes, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
broadcast(Opcode.Text, new MemoryStream(bytes), null);
|
||||
broadcast(OperationCode.Text, new MemoryStream(bytes), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -528,8 +524,8 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (_state != ServerState.Start)
|
||||
{
|
||||
var msg = "The current state of the manager is not Start.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The current state of the manager is not Start.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
if (stream == null)
|
||||
|
@ -539,14 +535,14 @@ namespace EonaCat.Network
|
|||
|
||||
if (!stream.CanRead)
|
||||
{
|
||||
var msg = "It cannot be read.";
|
||||
throw new ArgumentException(msg, nameof(stream));
|
||||
var message = "It cannot be read.";
|
||||
throw new ArgumentException(message, nameof(stream));
|
||||
}
|
||||
|
||||
if (length < 1)
|
||||
{
|
||||
var msg = "Less than 1.";
|
||||
throw new ArgumentException(msg, nameof(length));
|
||||
var message = "Less than 1.";
|
||||
throw new ArgumentException(message, nameof(length));
|
||||
}
|
||||
|
||||
var bytes = stream.ReadBytes(length);
|
||||
|
@ -554,8 +550,8 @@ namespace EonaCat.Network
|
|||
var len = bytes.Length;
|
||||
if (len == 0)
|
||||
{
|
||||
var msg = "No data could be read from it.";
|
||||
throw new ArgumentException(msg, nameof(stream));
|
||||
var message = "No data could be read from it.";
|
||||
throw new ArgumentException(message, nameof(stream));
|
||||
}
|
||||
|
||||
if (len < length)
|
||||
|
@ -568,13 +564,13 @@ namespace EonaCat.Network
|
|||
);
|
||||
}
|
||||
|
||||
if (len <= WebSocket.FragmentLength)
|
||||
if (len <= WSClient.FragmentLength)
|
||||
{
|
||||
broadcast(Opcode.Binary, bytes, null);
|
||||
broadcast(OperationCode.Binary, bytes, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
broadcast(Opcode.Binary, new MemoryStream(bytes), null);
|
||||
broadcast(OperationCode.Binary, new MemoryStream(bytes), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -582,8 +578,8 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (_state != ServerState.Start)
|
||||
{
|
||||
var msg = "The current state of the manager is not Start.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The current state of the manager is not Start.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
if (data == null)
|
||||
|
@ -591,13 +587,13 @@ namespace EonaCat.Network
|
|||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
|
||||
if (data.LongLength <= WebSocket.FragmentLength)
|
||||
if (data.LongLength <= WSClient.FragmentLength)
|
||||
{
|
||||
broadcastAsync(Opcode.Binary, data, completed);
|
||||
broadcastAsync(OperationCode.Binary, data, completed);
|
||||
}
|
||||
else
|
||||
{
|
||||
broadcastAsync(Opcode.Binary, new MemoryStream(data), completed);
|
||||
broadcastAsync(OperationCode.Binary, new MemoryStream(data), completed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -605,8 +601,8 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (_state != ServerState.Start)
|
||||
{
|
||||
var msg = "The current state of the manager is not Start.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The current state of the manager is not Start.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
if (data == null)
|
||||
|
@ -614,20 +610,19 @@ namespace EonaCat.Network
|
|||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
if (!data.TryGetUTF8EncodedBytes(out bytes))
|
||||
if (!data.TryGetUTF8EncodedBytes(out byte[] bytes))
|
||||
{
|
||||
var msg = "It could not be UTF-8-encoded.";
|
||||
throw new ArgumentException(msg, nameof(data));
|
||||
var message = "It could not be UTF-8-encoded.";
|
||||
throw new ArgumentException(message, nameof(data));
|
||||
}
|
||||
|
||||
if (bytes.LongLength <= WebSocket.FragmentLength)
|
||||
if (bytes.LongLength <= WSClient.FragmentLength)
|
||||
{
|
||||
broadcastAsync(Opcode.Text, bytes, completed);
|
||||
broadcastAsync(OperationCode.Text, bytes, completed);
|
||||
}
|
||||
else
|
||||
{
|
||||
broadcastAsync(Opcode.Text, new MemoryStream(bytes), completed);
|
||||
broadcastAsync(OperationCode.Text, new MemoryStream(bytes), completed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -635,8 +630,8 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (_state != ServerState.Start)
|
||||
{
|
||||
var msg = "The current state of the manager is not Start.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The current state of the manager is not Start.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
if (stream == null)
|
||||
|
@ -646,14 +641,14 @@ namespace EonaCat.Network
|
|||
|
||||
if (!stream.CanRead)
|
||||
{
|
||||
var msg = "It cannot be read.";
|
||||
throw new ArgumentException(msg, nameof(stream));
|
||||
var message = "It cannot be read.";
|
||||
throw new ArgumentException(message, nameof(stream));
|
||||
}
|
||||
|
||||
if (length < 1)
|
||||
{
|
||||
var msg = "Less than 1.";
|
||||
throw new ArgumentException(msg, nameof(length));
|
||||
var message = "Less than 1.";
|
||||
throw new ArgumentException(message, nameof(length));
|
||||
}
|
||||
|
||||
var bytes = stream.ReadBytes(length);
|
||||
|
@ -661,8 +656,8 @@ namespace EonaCat.Network
|
|||
var len = bytes.Length;
|
||||
if (len == 0)
|
||||
{
|
||||
var msg = "No data could be read from it.";
|
||||
throw new ArgumentException(msg, nameof(stream));
|
||||
var message = "No data could be read from it.";
|
||||
throw new ArgumentException(message, nameof(stream));
|
||||
}
|
||||
|
||||
if (len < length)
|
||||
|
@ -675,23 +670,22 @@ namespace EonaCat.Network
|
|||
);
|
||||
}
|
||||
|
||||
if (len <= WebSocket.FragmentLength)
|
||||
if (len <= WSClient.FragmentLength)
|
||||
{
|
||||
broadcastAsync(Opcode.Binary, bytes, completed);
|
||||
broadcastAsync(OperationCode.Binary, bytes, completed);
|
||||
}
|
||||
else
|
||||
{
|
||||
broadcastAsync(Opcode.Binary, new MemoryStream(bytes), completed);
|
||||
broadcastAsync(OperationCode.Binary, new MemoryStream(bytes), completed);
|
||||
}
|
||||
}
|
||||
|
||||
public void CloseSession(string id)
|
||||
{
|
||||
IWSSession session;
|
||||
if (!TryGetSession(id, out session))
|
||||
if (!TryGetSession(id, out IWSSession session))
|
||||
{
|
||||
var msg = "The session could not be found.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The session could not be found.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
session.Context.WebSocket.Close();
|
||||
|
@ -699,11 +693,10 @@ namespace EonaCat.Network
|
|||
|
||||
public void CloseSession(string id, ushort code, string reason)
|
||||
{
|
||||
IWSSession session;
|
||||
if (!TryGetSession(id, out session))
|
||||
if (!TryGetSession(id, out IWSSession session))
|
||||
{
|
||||
var msg = "The session could not be found.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The session could not be found.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
session.Context.WebSocket.Close(code, reason);
|
||||
|
@ -711,11 +704,10 @@ namespace EonaCat.Network
|
|||
|
||||
public void CloseSession(string id, CloseStatusCode code, string reason)
|
||||
{
|
||||
IWSSession session;
|
||||
if (!TryGetSession(id, out session))
|
||||
if (!TryGetSession(id, out IWSSession session))
|
||||
{
|
||||
var msg = "The session could not be found.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The session could not be found.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
session.Context.WebSocket.Close(code, reason);
|
||||
|
@ -723,11 +715,10 @@ namespace EonaCat.Network
|
|||
|
||||
public bool PingTo(string id)
|
||||
{
|
||||
IWSSession session;
|
||||
if (!TryGetSession(id, out session))
|
||||
if (!TryGetSession(id, out IWSSession session))
|
||||
{
|
||||
var msg = "The session could not be found.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The session could not be found.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
return session.Context.WebSocket.Ping();
|
||||
|
@ -735,11 +726,10 @@ namespace EonaCat.Network
|
|||
|
||||
public bool PingTo(string message, string id)
|
||||
{
|
||||
IWSSession session;
|
||||
if (!TryGetSession(id, out session))
|
||||
if (!TryGetSession(id, out IWSSession session))
|
||||
{
|
||||
var msg = "The session could not be found.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var pingMessage = "The session could not be found.";
|
||||
throw new InvalidOperationException(pingMessage);
|
||||
}
|
||||
|
||||
return session.Context.WebSocket.Ping(message);
|
||||
|
@ -747,11 +737,10 @@ namespace EonaCat.Network
|
|||
|
||||
public void SendTo(byte[] data, string id)
|
||||
{
|
||||
IWSSession session;
|
||||
if (!TryGetSession(id, out session))
|
||||
if (!TryGetSession(id, out IWSSession session))
|
||||
{
|
||||
var msg = "The session could not be found.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The session could not be found.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
session.Context.WebSocket.Send(data);
|
||||
|
@ -759,11 +748,10 @@ namespace EonaCat.Network
|
|||
|
||||
public void SendTo(string data, string id)
|
||||
{
|
||||
IWSSession session;
|
||||
if (!TryGetSession(id, out session))
|
||||
if (!TryGetSession(id, out IWSSession session))
|
||||
{
|
||||
var msg = "The session could not be found.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The session could not be found.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
session.Context.WebSocket.Send(data);
|
||||
|
@ -771,11 +759,10 @@ namespace EonaCat.Network
|
|||
|
||||
public void SendTo(Stream stream, int length, string id)
|
||||
{
|
||||
IWSSession session;
|
||||
if (!TryGetSession(id, out session))
|
||||
if (!TryGetSession(id, out IWSSession session))
|
||||
{
|
||||
var msg = "The session could not be found.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The session could not be found.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
session.Context.WebSocket.Send(stream, length);
|
||||
|
@ -783,11 +770,10 @@ namespace EonaCat.Network
|
|||
|
||||
public void SendToAsync(byte[] data, string id, Action<bool> completed)
|
||||
{
|
||||
IWSSession session;
|
||||
if (!TryGetSession(id, out session))
|
||||
if (!TryGetSession(id, out IWSSession session))
|
||||
{
|
||||
var msg = "The session could not be found.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The session could not be found.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
session.Context.WebSocket.SendAsync(data, completed);
|
||||
|
@ -795,11 +781,10 @@ namespace EonaCat.Network
|
|||
|
||||
public void SendToAsync(string data, string id, Action<bool> completed)
|
||||
{
|
||||
IWSSession session;
|
||||
if (!TryGetSession(id, out session))
|
||||
if (!TryGetSession(id, out IWSSession session))
|
||||
{
|
||||
var msg = "The session could not be found.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The session could not be found.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
session.Context.WebSocket.SendAsync(data, completed);
|
||||
|
@ -809,11 +794,10 @@ namespace EonaCat.Network
|
|||
Stream stream, int length, string id, Action<bool> completed
|
||||
)
|
||||
{
|
||||
IWSSession session;
|
||||
if (!TryGetSession(id, out session))
|
||||
if (!TryGetSession(id, out IWSSession session))
|
||||
{
|
||||
var msg = "The session could not be found.";
|
||||
throw new InvalidOperationException(msg);
|
||||
var message = "The session could not be found.";
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
session.Context.WebSocket.SendAsync(stream, length, completed);
|
||||
|
@ -852,15 +836,14 @@ namespace EonaCat.Network
|
|||
break;
|
||||
}
|
||||
|
||||
IWSSession session;
|
||||
if (_sessions.TryGetValue(id, out session))
|
||||
if (_sessions.TryGetValue(id, out IWSSession session))
|
||||
{
|
||||
var state = session.State;
|
||||
if (state == WebSocketState.Open)
|
||||
if (state == WSState.Open)
|
||||
{
|
||||
session.Context.WebSocket.Close(CloseStatusCode.Abnormal);
|
||||
}
|
||||
else if (state == WebSocketState.Closing)
|
||||
else if (state == WSState.Closing)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,44 +5,44 @@ using System;
|
|||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
public class WebSocketException : Exception
|
||||
public class WSException : Exception
|
||||
{
|
||||
internal WebSocketException()
|
||||
internal WSException()
|
||||
: this(CloseStatusCode.Abnormal, null, null)
|
||||
{
|
||||
}
|
||||
|
||||
internal WebSocketException(Exception innerException)
|
||||
internal WSException(Exception innerException)
|
||||
: this(CloseStatusCode.Abnormal, null, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
internal WebSocketException(string message)
|
||||
internal WSException(string message)
|
||||
: this(CloseStatusCode.Abnormal, message, null)
|
||||
{
|
||||
}
|
||||
|
||||
internal WebSocketException(CloseStatusCode code)
|
||||
internal WSException(CloseStatusCode code)
|
||||
: this(code, null, null)
|
||||
{
|
||||
}
|
||||
|
||||
internal WebSocketException(string message, Exception innerException)
|
||||
internal WSException(string message, Exception innerException)
|
||||
: this(CloseStatusCode.Abnormal, message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
internal WebSocketException(CloseStatusCode code, Exception innerException)
|
||||
internal WSException(CloseStatusCode code, Exception innerException)
|
||||
: this(code, null, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
internal WebSocketException(CloseStatusCode code, string message)
|
||||
internal WSException(CloseStatusCode code, string message)
|
||||
: this(code, message, null)
|
||||
{
|
||||
}
|
||||
|
||||
internal WebSocketException(
|
||||
internal WSException(
|
||||
CloseStatusCode code, string message, Exception innerException
|
||||
)
|
||||
: base("EonaCat Network: " + (message ?? code.GetMessage()), innerException)
|
|
@ -9,33 +9,33 @@ using System.Text;
|
|||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
internal class WebSocketFrame : IEnumerable<byte>
|
||||
internal class WSFrame : IEnumerable<byte>
|
||||
{
|
||||
private const int BUFFER_SIZE = 1024;
|
||||
|
||||
internal static readonly byte[] EmptyPingBytes;
|
||||
|
||||
static WebSocketFrame()
|
||||
static WSFrame()
|
||||
{
|
||||
EmptyPingBytes = CreatePingFrame(false).ToArray();
|
||||
}
|
||||
|
||||
private WebSocketFrame()
|
||||
private WSFrame()
|
||||
{
|
||||
}
|
||||
|
||||
internal WebSocketFrame(Opcode opcode, PayloadData payloadData, bool mask)
|
||||
internal WSFrame(OperationCode opcode, PayloadData payloadData, bool mask)
|
||||
: this(FinalFrame.Final, opcode, payloadData, false, mask)
|
||||
{
|
||||
}
|
||||
|
||||
internal WebSocketFrame(FinalFrame finalFrame, Opcode 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)
|
||||
{
|
||||
}
|
||||
|
||||
internal WebSocketFrame(
|
||||
FinalFrame fin, Opcode opcode, PayloadData payloadData, bool compressed, bool mask)
|
||||
internal WSFrame(
|
||||
FinalFrame fin, OperationCode opcode, PayloadData payloadData, bool compressed, bool mask)
|
||||
{
|
||||
Fin = fin;
|
||||
Rsv1 = opcode.IsData() && compressed ? Rsv.On : Rsv.Off;
|
||||
|
@ -47,7 +47,7 @@ namespace EonaCat.Network
|
|||
if (len < 126)
|
||||
{
|
||||
PayloadLength = (byte)len;
|
||||
ExtendedPayloadLength = WebSocket.EmptyBytes;
|
||||
ExtendedPayloadLength = WSClient.EmptyBytes;
|
||||
}
|
||||
else if (len < 0x010000)
|
||||
{
|
||||
|
@ -69,7 +69,7 @@ namespace EonaCat.Network
|
|||
else
|
||||
{
|
||||
Mask = Mask.Off;
|
||||
MaskingKey = WebSocket.EmptyBytes;
|
||||
MaskingKey = WSClient.EmptyBytes;
|
||||
}
|
||||
|
||||
PayloadData = payloadData;
|
||||
|
@ -87,29 +87,29 @@ namespace EonaCat.Network
|
|||
|
||||
public FinalFrame Fin { get; private set; }
|
||||
|
||||
public bool IsBinary => Opcode == Opcode.Binary;
|
||||
public bool IsBinary => Opcode == OperationCode.Binary;
|
||||
|
||||
public bool IsClose => Opcode == Opcode.Close;
|
||||
public bool IsClose => Opcode == OperationCode.Close;
|
||||
|
||||
public bool IsCompressed => Rsv1 == Rsv.On;
|
||||
|
||||
public bool IsContinuation => Opcode == Opcode.Cont;
|
||||
public bool IsContinuation => Opcode == OperationCode.Cont;
|
||||
|
||||
public bool IsControl => Opcode >= Opcode.Close;
|
||||
public bool IsControl => Opcode >= OperationCode.Close;
|
||||
|
||||
public bool IsData => Opcode == Opcode.Text || Opcode == Opcode.Binary;
|
||||
public bool IsData => Opcode == OperationCode.Text || Opcode == OperationCode.Binary;
|
||||
|
||||
public bool IsFinal => Fin == FinalFrame.Final;
|
||||
|
||||
public bool IsFragment => Fin == FinalFrame.More || Opcode == Opcode.Cont;
|
||||
public bool IsFragment => Fin == FinalFrame.More || Opcode == OperationCode.Cont;
|
||||
|
||||
public bool IsMasked => Mask == Mask.On;
|
||||
|
||||
public bool IsPing => Opcode == Opcode.Ping;
|
||||
public bool IsPing => Opcode == OperationCode.Ping;
|
||||
|
||||
public bool IsPong => Opcode == Opcode.Pong;
|
||||
public bool IsPong => Opcode == OperationCode.Pong;
|
||||
|
||||
public bool IsText => Opcode == Opcode.Text;
|
||||
public bool IsText => Opcode == OperationCode.Text;
|
||||
|
||||
public ulong Length => 2 + (ulong)(ExtendedPayloadLength.Length + MaskingKey.Length) + PayloadData.Length;
|
||||
|
||||
|
@ -117,7 +117,7 @@ namespace EonaCat.Network
|
|||
|
||||
public byte[] MaskingKey { get; private set; }
|
||||
|
||||
public Opcode Opcode { get; private set; }
|
||||
public OperationCode Opcode { get; private set; }
|
||||
|
||||
public PayloadData PayloadData { get; private set; }
|
||||
|
||||
|
@ -132,12 +132,12 @@ namespace EonaCat.Network
|
|||
private static byte[] createMaskingKey()
|
||||
{
|
||||
var key = new byte[4];
|
||||
WebSocket.RandomNumber.GetBytes(key);
|
||||
WSClient.RandomNumber.GetBytes(key);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
private static string dump(WebSocketFrame frame)
|
||||
private static string dump(WSFrame frame)
|
||||
{
|
||||
var len = frame.Length;
|
||||
var cnt = (long)(len / 4);
|
||||
|
@ -213,7 +213,7 @@ namespace EonaCat.Network
|
|||
return output.ToString();
|
||||
}
|
||||
|
||||
private static string print(WebSocketFrame frame)
|
||||
private static string print(WSFrame frame)
|
||||
{
|
||||
// Payload Length
|
||||
var payloadLen = frame.PayloadLength;
|
||||
|
@ -259,11 +259,11 @@ Extended Payload Length: {7}
|
|||
payload);
|
||||
}
|
||||
|
||||
private static WebSocketFrame processHeader(byte[] header)
|
||||
private static WSFrame processHeader(byte[] header)
|
||||
{
|
||||
if (header.Length != 2)
|
||||
{
|
||||
throw new WebSocketException("The header of a frame cannot be read from the stream.");
|
||||
throw new WSException("The header of a frame cannot be read from the stream.");
|
||||
}
|
||||
|
||||
// FIN
|
||||
|
@ -299,34 +299,34 @@ Extended Payload Length: {7}
|
|||
|
||||
if (err != null)
|
||||
{
|
||||
throw new WebSocketException(CloseStatusCode.ProtocolError, err);
|
||||
throw new WSException(CloseStatusCode.ProtocolError, err);
|
||||
}
|
||||
|
||||
var frame = new WebSocketFrame();
|
||||
var frame = new WSFrame();
|
||||
frame.Fin = fin;
|
||||
frame.Rsv1 = rsv1;
|
||||
frame.Rsv2 = rsv2;
|
||||
frame.Rsv3 = rsv3;
|
||||
frame.Opcode = (Opcode)opcode;
|
||||
frame.Opcode = (OperationCode)opcode;
|
||||
frame.Mask = mask;
|
||||
frame.PayloadLength = payloadLen;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
private static WebSocketFrame readExtendedPayloadLength(Stream stream, WebSocketFrame frame)
|
||||
private static WSFrame readExtendedPayloadLength(Stream stream, WSFrame frame)
|
||||
{
|
||||
var len = frame.ExtendedPayloadLengthCount;
|
||||
if (len == 0)
|
||||
{
|
||||
frame.ExtendedPayloadLength = WebSocket.EmptyBytes;
|
||||
frame.ExtendedPayloadLength = WSClient.EmptyBytes;
|
||||
return frame;
|
||||
}
|
||||
|
||||
var bytes = stream.ReadBytes(len);
|
||||
if (bytes.Length != len)
|
||||
{
|
||||
throw new WebSocketException(
|
||||
throw new WSException(
|
||||
"The extended payload length of a frame cannot be read from the stream.");
|
||||
}
|
||||
|
||||
|
@ -336,14 +336,14 @@ Extended Payload Length: {7}
|
|||
|
||||
private static void readExtendedPayloadLengthAsync(
|
||||
Stream stream,
|
||||
WebSocketFrame frame,
|
||||
Action<WebSocketFrame> completed,
|
||||
WSFrame frame,
|
||||
Action<WSFrame> completed,
|
||||
Action<Exception> error)
|
||||
{
|
||||
var len = frame.ExtendedPayloadLengthCount;
|
||||
if (len == 0)
|
||||
{
|
||||
frame.ExtendedPayloadLength = WebSocket.EmptyBytes;
|
||||
frame.ExtendedPayloadLength = WSClient.EmptyBytes;
|
||||
completed(frame);
|
||||
|
||||
return;
|
||||
|
@ -355,7 +355,7 @@ Extended Payload Length: {7}
|
|||
{
|
||||
if (bytes.Length != len)
|
||||
{
|
||||
throw new WebSocketException(
|
||||
throw new WSException(
|
||||
"The extended payload length of a frame cannot be read from the stream.");
|
||||
}
|
||||
|
||||
|
@ -365,30 +365,30 @@ Extended Payload Length: {7}
|
|||
error);
|
||||
}
|
||||
|
||||
private static WebSocketFrame readHeader(Stream stream)
|
||||
private static WSFrame readHeader(Stream stream)
|
||||
{
|
||||
return processHeader(stream.ReadBytes(2));
|
||||
}
|
||||
|
||||
private static void readHeaderAsync(
|
||||
Stream stream, Action<WebSocketFrame> completed, Action<Exception> error)
|
||||
Stream stream, Action<WSFrame> completed, Action<Exception> error)
|
||||
{
|
||||
stream.ReadBytesAsync(2, bytes => completed(processHeader(bytes)), error);
|
||||
}
|
||||
|
||||
private static WebSocketFrame readMaskingKey(Stream stream, WebSocketFrame frame)
|
||||
private static WSFrame readMaskingKey(Stream stream, WSFrame frame)
|
||||
{
|
||||
var len = frame.IsMasked ? 4 : 0;
|
||||
if (len == 0)
|
||||
{
|
||||
frame.MaskingKey = WebSocket.EmptyBytes;
|
||||
frame.MaskingKey = WSClient.EmptyBytes;
|
||||
return frame;
|
||||
}
|
||||
|
||||
var bytes = stream.ReadBytes(len);
|
||||
if (bytes.Length != len)
|
||||
{
|
||||
throw new WebSocketException("The masking key of a frame cannot be read from the stream.");
|
||||
throw new WSException("The masking key of a frame cannot be read from the stream.");
|
||||
}
|
||||
|
||||
frame.MaskingKey = bytes;
|
||||
|
@ -397,14 +397,14 @@ Extended Payload Length: {7}
|
|||
|
||||
private static void readMaskingKeyAsync(
|
||||
Stream stream,
|
||||
WebSocketFrame frame,
|
||||
Action<WebSocketFrame> completed,
|
||||
WSFrame frame,
|
||||
Action<WSFrame> completed,
|
||||
Action<Exception> error)
|
||||
{
|
||||
var len = frame.IsMasked ? 4 : 0;
|
||||
if (len == 0)
|
||||
{
|
||||
frame.MaskingKey = WebSocket.EmptyBytes;
|
||||
frame.MaskingKey = WSClient.EmptyBytes;
|
||||
completed(frame);
|
||||
|
||||
return;
|
||||
|
@ -416,7 +416,7 @@ Extended Payload Length: {7}
|
|||
{
|
||||
if (bytes.Length != len)
|
||||
{
|
||||
throw new WebSocketException(
|
||||
throw new WSException(
|
||||
"The masking key of a frame cannot be read from the stream.");
|
||||
}
|
||||
|
||||
|
@ -426,7 +426,7 @@ Extended Payload Length: {7}
|
|||
error);
|
||||
}
|
||||
|
||||
private static WebSocketFrame readPayloadData(Stream stream, WebSocketFrame frame)
|
||||
private static WSFrame readPayloadData(Stream stream, WSFrame frame)
|
||||
{
|
||||
var len = frame.FullPayloadLength;
|
||||
if (len == 0)
|
||||
|
@ -437,7 +437,7 @@ Extended Payload Length: {7}
|
|||
|
||||
if (len > PayloadData.MaxLength)
|
||||
{
|
||||
throw new WebSocketException(CloseStatusCode.TooBig, "A frame has a long payload length.");
|
||||
throw new WSException(CloseStatusCode.TooBig, "A frame has a long payload length.");
|
||||
}
|
||||
|
||||
var llen = (long)len;
|
||||
|
@ -447,7 +447,7 @@ Extended Payload Length: {7}
|
|||
|
||||
if (bytes.LongLength != llen)
|
||||
{
|
||||
throw new WebSocketException(
|
||||
throw new WSException(
|
||||
"The payload data of a frame cannot be read from the stream.");
|
||||
}
|
||||
|
||||
|
@ -457,8 +457,8 @@ Extended Payload Length: {7}
|
|||
|
||||
private static void readPayloadDataAsync(
|
||||
Stream stream,
|
||||
WebSocketFrame frame,
|
||||
Action<WebSocketFrame> completed,
|
||||
WSFrame frame,
|
||||
Action<WSFrame> completed,
|
||||
Action<Exception> error)
|
||||
{
|
||||
var len = frame.FullPayloadLength;
|
||||
|
@ -472,7 +472,7 @@ Extended Payload Length: {7}
|
|||
|
||||
if (len > PayloadData.MaxLength)
|
||||
{
|
||||
throw new WebSocketException(CloseStatusCode.TooBig, "A frame has a long payload length.");
|
||||
throw new WSException(CloseStatusCode.TooBig, "A frame has a long payload length.");
|
||||
}
|
||||
|
||||
var llen = (long)len;
|
||||
|
@ -480,7 +480,7 @@ Extended Payload Length: {7}
|
|||
{
|
||||
if (bytes.LongLength != llen)
|
||||
{
|
||||
throw new WebSocketException(
|
||||
throw new WSException(
|
||||
"The payload data of a frame cannot be read from the stream.");
|
||||
}
|
||||
|
||||
|
@ -497,39 +497,39 @@ Extended Payload Length: {7}
|
|||
stream.ReadBytesAsync(llen, BUFFER_SIZE, compl, error);
|
||||
}
|
||||
|
||||
internal static WebSocketFrame CreateCloseFrame(
|
||||
internal static WSFrame CreateCloseFrame(
|
||||
PayloadData payloadData, bool mask
|
||||
)
|
||||
{
|
||||
return new WebSocketFrame(
|
||||
FinalFrame.Final, Opcode.Close, payloadData, false, mask
|
||||
return new WSFrame(
|
||||
FinalFrame.Final, OperationCode.Close, payloadData, false, mask
|
||||
);
|
||||
}
|
||||
|
||||
internal static WebSocketFrame CreatePingFrame(bool mask)
|
||||
internal static WSFrame CreatePingFrame(bool mask)
|
||||
{
|
||||
return new WebSocketFrame(
|
||||
FinalFrame.Final, Opcode.Ping, PayloadData.Empty, false, mask
|
||||
return new WSFrame(
|
||||
FinalFrame.Final, OperationCode.Ping, PayloadData.Empty, false, mask
|
||||
);
|
||||
}
|
||||
|
||||
internal static WebSocketFrame CreatePingFrame(byte[] data, bool mask)
|
||||
internal static WSFrame CreatePingFrame(byte[] data, bool mask)
|
||||
{
|
||||
return new WebSocketFrame(
|
||||
FinalFrame.Final, Opcode.Ping, new PayloadData(data), false, mask
|
||||
return new WSFrame(
|
||||
FinalFrame.Final, OperationCode.Ping, new PayloadData(data), false, mask
|
||||
);
|
||||
}
|
||||
|
||||
internal static WebSocketFrame CreatePongFrame(
|
||||
internal static WSFrame CreatePongFrame(
|
||||
PayloadData payloadData, bool mask
|
||||
)
|
||||
{
|
||||
return new WebSocketFrame(
|
||||
FinalFrame.Final, Opcode.Pong, payloadData, false, mask
|
||||
return new WSFrame(
|
||||
FinalFrame.Final, OperationCode.Pong, payloadData, false, mask
|
||||
);
|
||||
}
|
||||
|
||||
internal static WebSocketFrame ReadFrame(Stream stream, bool unmask)
|
||||
internal static WSFrame ReadFrame(Stream stream, bool unmask)
|
||||
{
|
||||
var frame = readHeader(stream);
|
||||
readExtendedPayloadLength(stream, frame);
|
||||
|
@ -547,7 +547,7 @@ Extended Payload Length: {7}
|
|||
internal static void ReadFrameAsync(
|
||||
Stream stream,
|
||||
bool unmask,
|
||||
Action<WebSocketFrame> completed,
|
||||
Action<WSFrame> completed,
|
||||
Action<Exception> error
|
||||
)
|
||||
{
|
||||
|
@ -593,7 +593,7 @@ Extended Payload Length: {7}
|
|||
|
||||
Mask = Mask.Off;
|
||||
PayloadData.Mask(MaskingKey);
|
||||
MaskingKey = WebSocket.EmptyBytes;
|
||||
MaskingKey = WSClient.EmptyBytes;
|
||||
}
|
||||
|
||||
public IEnumerator<byte> GetEnumerator()
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace EonaCat.Network
|
||||
{
|
||||
public enum WebSocketState : ushort
|
||||
public enum WSState : ushort
|
||||
{
|
||||
Connecting = 0,
|
||||
|
|
@ -50,8 +50,7 @@ namespace EonaCat.Network
|
|||
|
||||
private static byte[] readEntityBody(Stream stream, string length)
|
||||
{
|
||||
long len;
|
||||
if (!long.TryParse(length, out len))
|
||||
if (!long.TryParse(length, out long len))
|
||||
{
|
||||
throw new ArgumentException("Cannot be parsed.", nameof(length));
|
||||
}
|
||||
|
@ -98,7 +97,7 @@ namespace EonaCat.Network
|
|||
|
||||
if (!read)
|
||||
{
|
||||
throw new WebSocketException("The length of header part is greater than the max length.");
|
||||
throw new WSException("The length of header part is greater than the max length.");
|
||||
}
|
||||
|
||||
return Encoding.UTF8.GetString(buff.ToArray())
|
||||
|
@ -142,15 +141,15 @@ namespace EonaCat.Network
|
|||
timer.Dispose();
|
||||
}
|
||||
|
||||
var msg = timeout
|
||||
var message = timeout
|
||||
? "A timeout has occurred while reading an HTTP request/response."
|
||||
: exception != null
|
||||
? "An exception has occurred while reading an HTTP request/response."
|
||||
: null;
|
||||
|
||||
if (msg != null)
|
||||
if (message != null)
|
||||
{
|
||||
throw new WebSocketException(msg, exception);
|
||||
throw new WSException(message, exception);
|
||||
}
|
||||
|
||||
return http;
|
||||
|
|
|
@ -114,7 +114,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
NetworkHelper.Logger.Error(string.Format(" {0}: at {1} is close ,error msg :{2}", para.ip, para.port, e.Message));
|
||||
NetworkHelper.Logger.Error(string.Format(" {0}: at {1} is close ,error message :{2}", para.ip, para.port, e.Message));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -256,20 +256,5 @@ namespace EonaCat.Network
|
|||
_Routes.Add(route);
|
||||
}
|
||||
}
|
||||
|
||||
private void Remove(ContentRoute route)
|
||||
{
|
||||
if (route == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(route));
|
||||
}
|
||||
|
||||
lock (_Lock)
|
||||
{
|
||||
_Routes.Remove(route);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -137,12 +137,6 @@ namespace EonaCat.Network
|
|||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
private void Set204Response(HttpContext ctx)
|
||||
{
|
||||
ctx.Response.StatusCode = 204;
|
||||
ctx.Response.ContentLength = 0;
|
||||
}
|
||||
|
||||
private void Set404Response(HttpContext ctx)
|
||||
{
|
||||
ctx.Response.StatusCode = 404;
|
||||
|
|
|
@ -129,11 +129,10 @@ namespace EonaCat.Network
|
|||
throw new ArgumentNullException(nameof(rawUrl));
|
||||
}
|
||||
|
||||
object val = null;
|
||||
|
||||
if (Matcher.Match(
|
||||
BuildConsolidatedRegex(method, rawUrl),
|
||||
out val))
|
||||
out object val))
|
||||
{
|
||||
if (val == null)
|
||||
{
|
||||
|
|
|
@ -451,8 +451,7 @@ namespace EonaCat.Network
|
|||
|
||||
if (ctx.Request.Method == HttpMethod.GET || ctx.Request.Method == HttpMethod.HEAD)
|
||||
{
|
||||
ContentRoute cr = null;
|
||||
if (_Routes.Content.Match(ctx.Request.Url.RawWithoutQuery, out cr))
|
||||
if (_Routes.Content.Match(ctx.Request.Url.RawWithoutQuery, out ContentRoute cr))
|
||||
{
|
||||
if (_Settings.Debug.Routing)
|
||||
{
|
||||
|
@ -468,8 +467,7 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
StaticRoute sr = null;
|
||||
Func<HttpContext, Task> handler = _Routes.Static.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out sr);
|
||||
Func<HttpContext, Task> handler = _Routes.Static.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out StaticRoute sr);
|
||||
if (handler != null)
|
||||
{
|
||||
if (_Settings.Debug.Routing)
|
||||
|
@ -485,9 +483,7 @@ namespace EonaCat.Network
|
|||
return;
|
||||
}
|
||||
|
||||
ParameterRoute pr = null;
|
||||
Dictionary<string, string> parameters = null;
|
||||
handler = _Routes.Parameter.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out parameters, out pr);
|
||||
handler = _Routes.Parameter.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out Dictionary<string, string> parameters, out ParameterRoute pr);
|
||||
if (handler != null)
|
||||
{
|
||||
ctx.Request.Url.Parameters = new Dictionary<string, string>(parameters);
|
||||
|
@ -505,8 +501,7 @@ namespace EonaCat.Network
|
|||
return;
|
||||
}
|
||||
|
||||
DynamicRoute dr = null;
|
||||
handler = _Routes.Dynamic.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out dr);
|
||||
handler = _Routes.Dynamic.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out DynamicRoute dr);
|
||||
if (handler != null)
|
||||
{
|
||||
if (_Settings.Debug.Routing)
|
||||
|
|
|
@ -577,43 +577,6 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
private void ReadStreamFully()
|
||||
{
|
||||
if (Data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Data.CanRead)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_DataAsBytes == null)
|
||||
{
|
||||
if (!ChunkedTransfer)
|
||||
{
|
||||
_DataAsBytes = StreamToBytes(Data);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Chunk chunk = ReadChunk().Result;
|
||||
if (chunk.Data != null && chunk.Data.Length > 0)
|
||||
{
|
||||
_DataAsBytes = AppendBytes(_DataAsBytes, chunk.Data);
|
||||
}
|
||||
|
||||
if (chunk.IsFinalChunk)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] ReadStreamFully(Stream input)
|
||||
{
|
||||
if (input == null)
|
||||
|
|
|
@ -125,7 +125,7 @@ namespace EonaCat.Network
|
|||
private readonly HttpRequest _Request = null;
|
||||
private readonly System.Net.HttpListenerContext _Context = null;
|
||||
private readonly System.Net.HttpListenerResponse _Response = null;
|
||||
private readonly Stream _OutputStream = null;
|
||||
private readonly Stream _outputStream = null;
|
||||
private bool _HeadersSent = false;
|
||||
private readonly EonaCatWebserverSettings _Settings = new EonaCatWebserverSettings();
|
||||
private readonly EonaCatWebserverEvents _Events = new EonaCatWebserverEvents();
|
||||
|
@ -168,7 +168,7 @@ namespace EonaCat.Network
|
|||
_Settings = settings;
|
||||
_Events = events;
|
||||
|
||||
_OutputStream = _Response.OutputStream;
|
||||
_outputStream = _Response.OutputStream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -190,13 +190,10 @@ namespace EonaCat.Network
|
|||
SendHeaders();
|
||||
}
|
||||
|
||||
await _OutputStream.FlushAsync(token).ConfigureAwait(false);
|
||||
_OutputStream.Close();
|
||||
await _outputStream.FlushAsync(token).ConfigureAwait(false);
|
||||
_outputStream.Close();
|
||||
|
||||
if (_Response != null)
|
||||
{
|
||||
_Response.Close();
|
||||
}
|
||||
_Response?.Close();
|
||||
|
||||
ResponseSent = true;
|
||||
return true;
|
||||
|
@ -229,13 +226,10 @@ namespace EonaCat.Network
|
|||
SendHeaders();
|
||||
}
|
||||
|
||||
await _OutputStream.FlushAsync(token).ConfigureAwait(false);
|
||||
_OutputStream.Close();
|
||||
await _outputStream.FlushAsync(token).ConfigureAwait(false);
|
||||
_outputStream.Close();
|
||||
|
||||
if (_Response != null)
|
||||
{
|
||||
_Response.Close();
|
||||
}
|
||||
_Response?.Close();
|
||||
|
||||
ResponseSent = true;
|
||||
return true;
|
||||
|
@ -288,17 +282,14 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (bytes != null && bytes.Length > 0)
|
||||
{
|
||||
await _OutputStream.WriteAsync(bytes, 0, bytes.Length, token).ConfigureAwait(false);
|
||||
await _outputStream.WriteAsync(bytes, 0, bytes.Length, token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
await _OutputStream.FlushAsync(token).ConfigureAwait(false);
|
||||
_OutputStream.Close();
|
||||
await _outputStream.FlushAsync(token).ConfigureAwait(false);
|
||||
_outputStream.Close();
|
||||
|
||||
if (_Response != null)
|
||||
{
|
||||
_Response.Close();
|
||||
}
|
||||
_Response?.Close();
|
||||
|
||||
ResponseSent = true;
|
||||
return true;
|
||||
|
@ -347,17 +338,14 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (data != null && data.Length > 0)
|
||||
{
|
||||
await _OutputStream.WriteAsync(data, 0, data.Length, token).ConfigureAwait(false);
|
||||
await _outputStream.WriteAsync(data, 0, data.Length, token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
await _OutputStream.FlushAsync(token).ConfigureAwait(false);
|
||||
_OutputStream.Close();
|
||||
await _outputStream.FlushAsync(token).ConfigureAwait(false);
|
||||
_outputStream.Close();
|
||||
|
||||
if (_Response != null)
|
||||
{
|
||||
_Response.Close();
|
||||
}
|
||||
_Response?.Close();
|
||||
|
||||
ResponseSent = true;
|
||||
return true;
|
||||
|
@ -406,7 +394,7 @@ namespace EonaCat.Network
|
|||
if (bytesRead > 0)
|
||||
{
|
||||
await Data.WriteAsync(buffer, 0, bytesRead, token).ConfigureAwait(false);
|
||||
await _OutputStream.WriteAsync(buffer, 0, bytesRead, token).ConfigureAwait(false);
|
||||
await _outputStream.WriteAsync(buffer, 0, bytesRead, token).ConfigureAwait(false);
|
||||
bytesRemaining -= bytesRead;
|
||||
}
|
||||
}
|
||||
|
@ -418,13 +406,10 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
await _OutputStream.FlushAsync(token).ConfigureAwait(false);
|
||||
_OutputStream.Close();
|
||||
await _outputStream.FlushAsync(token).ConfigureAwait(false);
|
||||
_outputStream.Close();
|
||||
|
||||
if (_Response != null)
|
||||
{
|
||||
_Response.Close();
|
||||
}
|
||||
_Response?.Close();
|
||||
|
||||
ResponseSent = true;
|
||||
return true;
|
||||
|
@ -466,8 +451,8 @@ namespace EonaCat.Network
|
|||
chunk = new byte[0];
|
||||
}
|
||||
|
||||
await _OutputStream.WriteAsync(chunk, 0, numBytes, token).ConfigureAwait(false);
|
||||
await _OutputStream.FlushAsync(token).ConfigureAwait(false);
|
||||
await _outputStream.WriteAsync(chunk, 0, numBytes, token).ConfigureAwait(false);
|
||||
await _outputStream.FlushAsync(token).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
@ -504,19 +489,16 @@ namespace EonaCat.Network
|
|||
{
|
||||
if (chunk != null && chunk.Length > 0)
|
||||
{
|
||||
await _OutputStream.WriteAsync(chunk, 0, numBytes, token).ConfigureAwait(false);
|
||||
await _outputStream.WriteAsync(chunk, 0, numBytes, token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
byte[] endChunk = new byte[0];
|
||||
await _OutputStream.WriteAsync(endChunk, 0, endChunk.Length, token).ConfigureAwait(false);
|
||||
await _outputStream.WriteAsync(endChunk, 0, endChunk.Length, token).ConfigureAwait(false);
|
||||
|
||||
await _OutputStream.FlushAsync(token).ConfigureAwait(false);
|
||||
_OutputStream.Close();
|
||||
await _outputStream.FlushAsync(token).ConfigureAwait(false);
|
||||
_outputStream.Close();
|
||||
|
||||
if (_Response != null)
|
||||
{
|
||||
_Response.Close();
|
||||
}
|
||||
_Response?.Close();
|
||||
|
||||
ResponseSent = true;
|
||||
return true;
|
||||
|
@ -647,32 +629,6 @@ namespace EonaCat.Network
|
|||
}
|
||||
}
|
||||
|
||||
private byte[] PackageChunk(byte[] chunk)
|
||||
{
|
||||
if (chunk == null || chunk.Length < 1)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes("0\r\n\r\n");
|
||||
}
|
||||
|
||||
MemoryStream ms = new MemoryStream();
|
||||
|
||||
string newlineStr = "\r\n";
|
||||
byte[] newline = Encoding.UTF8.GetBytes(newlineStr);
|
||||
|
||||
string chunkLenHex = chunk.Length.ToString("X");
|
||||
byte[] chunkLen = Encoding.UTF8.GetBytes(chunkLenHex);
|
||||
|
||||
ms.Write(chunkLen, 0, chunkLen.Length);
|
||||
ms.Write(newline, 0, newline.Length);
|
||||
ms.Write(chunk, 0, chunk.Length);
|
||||
ms.Write(newline, 0, newline.Length);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
byte[] ret = ms.ToArray();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private byte[] ReadStreamFully(Stream input)
|
||||
{
|
||||
if (input == null)
|
||||
|
|
|
@ -613,8 +613,7 @@ namespace EonaCat.Network
|
|||
extension = "." + extension;
|
||||
}
|
||||
|
||||
string mime;
|
||||
return data.TryGetValue(extension.ToLower(), out mime) ? mime : "application/octet-stream";
|
||||
return data.TryGetValue(extension.ToLower(), out string mime) ? mime : "application/octet-stream";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -218,20 +218,5 @@ namespace EonaCat.Network
|
|||
_Routes.Add(route);
|
||||
}
|
||||
}
|
||||
|
||||
private void Remove(StaticRoute route)
|
||||
{
|
||||
if (route == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(route));
|
||||
}
|
||||
|
||||
lock (_Lock)
|
||||
{
|
||||
_Routes.Remove(route);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue