diff --git a/EonaCat.Network/EonaCat.Network.csproj b/EonaCat.Network/EonaCat.Network.csproj
index d9a3590..97a170b 100644
--- a/EonaCat.Network/EonaCat.Network.csproj
+++ b/EonaCat.Network/EonaCat.Network.csproj
@@ -1,28 +1,27 @@
-
- Latest
-
- netstandard2.1;
- net6.0;
- net7.0;
-
- true
- EonaCat.Network
- EonaCat (Jeroen Saey)
- EonaCat (Jeroen Saey)
- EonaCat.Network
- EonaCat (Jeroen Saey)
- https://www.nuget.org/packages/EonaCat.Network/
- EonaCat, Network, .NET Standard, EonaCatHelpers, Jeroen, Saey, Protocol, Quic, UDP, TCP, Web, Server
-
- EonaCat Networking library with Quic, TCP, UDP, WebSockets and a Webserver
- 1.1.4
- 1.1.4
- 1.1.4
- icon.png
-
+ Latest
+ net48;netstandard2.1;net6.0;net7.0;net8.0
+ true
+ EonaCat.Network
+ EonaCat (Jeroen Saey)
+ EonaCat (Jeroen Saey)
+ EonaCat.Network
+ EonaCat (Jeroen Saey)
+ https://www.nuget.org/packages/EonaCat.Network/
+ EonaCat, Network, .NET Standard, EonaCatHelpers, Jeroen, Saey, Protocol, Quic, UDP, TCP, Web, Server
+
+ EonaCat Networking library with Quic, TCP, UDP, WebSockets and a Webserver
+ 1.1.5
+ 1.1.5
+ 1.1.5
+ icon.png
+ README.md
+ LICENSE
+
+
+
false
True
README.md
@@ -30,29 +29,36 @@
EonaCat.Network
True
LICENSE
+
-
-
-
- True
- \
-
-
- True
- \
-
-
- True
- \
-
+
+
+
+ True
+ \
+
+
+ True
+ \
+
+
+ True
+ \
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/EonaCat.Network/System/BlockChain/Block.cs b/EonaCat.Network/System/BlockChain/Block.cs
deleted file mode 100644
index dc93b1d..0000000
--- a/EonaCat.Network/System/BlockChain/Block.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using EonaCat.Json;
-using System;
-using System.Collections.Generic;
-using System.Security.Cryptography;
-using System.Text;
-
-namespace EonaCat.BlockChain
-{
- public class Block
- {
- public int Index { get; set; }
- private DateTime TimeStamp { get; set; }
- public string PreviousHash { get; set; }
- public string Hash { get; set; }
- public IList Transactions { get; set; }
- private int Nonce { get; set; }
-
- public Block(DateTime timeStamp, string previousHash, IList transactions)
- {
- Index = 0;
- TimeStamp = timeStamp;
- PreviousHash = previousHash;
- Transactions = transactions;
- }
-
- ///
- /// Calculate the hash of the block
- ///
- ///
- public string CalculateHash()
- {
- var sha256 = SHA256.Create();
-
- var inputBytes = Encoding.ASCII.GetBytes($"{TimeStamp}-{PreviousHash ?? ""}-{JsonHelper.ToJson(Transactions)}-{Nonce}");
- var outputBytes = sha256.ComputeHash(inputBytes);
-
- return Convert.ToBase64String(outputBytes);
- }
-
- ///
- /// Mine the block
- ///
- ///
- public void Mine(int difficulty)
- {
- var leadingZeros = new string('0', difficulty);
- while (Hash == null || Hash.Substring(0, difficulty) != leadingZeros)
- {
- Nonce++;
- Hash = CalculateHash();
- }
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/BlockChain/BlockChain.cs b/EonaCat.Network/System/BlockChain/BlockChain.cs
deleted file mode 100644
index e1c3779..0000000
--- a/EonaCat.Network/System/BlockChain/BlockChain.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace EonaCat.BlockChain
-{
- public class BlockChain
- {
- public IList PendingTransactions = new List();
- public IList Chain { set; get; }
- private int Difficulty { set; get; } = 2;
- private readonly int _reward = 1; //1 cryptocurrency
-
- public void InitializeChain()
- {
- Chain = new List();
- AddGenesisBlock();
- }
-
- private Block CreateGenesisBlock()
- {
- Block block = new Block(DateTime.Now, null, PendingTransactions);
- block.Mine(Difficulty);
- PendingTransactions = new List();
- return block;
- }
-
- private void AddGenesisBlock()
- {
- Chain.Add(CreateGenesisBlock());
- }
-
- private Block GetLatestBlock()
- {
- return Chain[Chain.Count - 1];
- }
-
- public void CreateTransaction(Transaction transaction)
- {
- PendingTransactions.Add(transaction);
- }
-
- public void ProcessPendingTransactions(string minerAddress)
- {
- Block block = new Block(DateTime.Now, GetLatestBlock().Hash, PendingTransactions);
- AddBlock(block);
-
- PendingTransactions = new List();
- CreateTransaction(new Transaction(null, minerAddress, _reward));
- }
-
- private void AddBlock(Block block)
- {
- Block latestBlock = GetLatestBlock();
- block.Index = latestBlock.Index + 1;
- block.PreviousHash = latestBlock.Hash;
- //block.Hash = block.CalculateHash();
- block.Mine(Difficulty);
- Chain.Add(block);
- }
-
- public bool IsValid()
- {
- for (int i = 1; i < Chain.Count; i++)
- {
- Block currentBlock = Chain[i];
- Block previousBlock = Chain[i - 1];
-
- if (currentBlock.Hash != currentBlock.CalculateHash())
- {
- return false;
- }
-
- if (currentBlock.PreviousHash != previousBlock.Hash)
- {
- return false;
- }
- }
- return true;
- }
-
- public int GetBalance(string address)
- {
- int balance = 0;
-
- for (int i = 0; i < Chain.Count; i++)
- {
- for (int j = 0; j < Chain[i].Transactions.Count; j++)
- {
- var transaction = Chain[i].Transactions[j];
-
- if (transaction.FromAddress == address)
- {
- balance -= transaction.Amount;
- }
-
- if (transaction.ToAddress == address)
- {
- balance += transaction.Amount;
- }
- }
- }
-
- return balance;
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/BlockChain/ClientServerExample.cs b/EonaCat.Network/System/BlockChain/ClientServerExample.cs
deleted file mode 100644
index 1dacfad..0000000
--- a/EonaCat.Network/System/BlockChain/ClientServerExample.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using EonaCat.Json;
-using System;
-
-namespace EonaCat.BlockChain
-{
- public static class ClientServerExample
- {
- public static int ServerPort;
- private static P2PServer _server;
- private static readonly P2PClient Client = new P2PClient();
- public static BlockChain BlockChain = new BlockChain();
- private static string _clientUsername = "Unknown";
-
- public static void Run(int serverPort, string clientUsername)
- {
- BlockChain.InitializeChain();
-
- ServerPort = serverPort;
- _clientUsername = clientUsername;
-
- if (ServerPort > 0)
- {
- _server = new P2PServer();
- _server.Start();
- }
-
- if (_clientUsername != "Unknown")
- {
- Console.WriteLine($"Current user is {_clientUsername}");
- }
-
- Console.WriteLine("=========================");
- Console.WriteLine("EonaCat BlockChain");
- Console.WriteLine("1. Connect to a server");
- Console.WriteLine("2. Add a transaction");
- Console.WriteLine("3. Display BlockChain");
- Console.WriteLine("4. Exit");
- Console.WriteLine("=========================");
-
- int selection = 0;
- while (selection != 4)
- {
- switch (selection)
- {
- case 1:
- Console.WriteLine("Please enter the server URL");
- string serverUrl = Console.ReadLine();
- Client.Connect($"{serverUrl}/BlockChain");
- break;
-
- case 2:
- Console.WriteLine("Please enter the receiver name");
- string receiverName = Console.ReadLine();
- Console.WriteLine("Please enter the amount");
- string amount = Console.ReadLine();
- BlockChain.CreateTransaction(new Transaction(_clientUsername, receiverName, int.Parse(amount)));
- BlockChain.ProcessPendingTransactions(_clientUsername);
- Client.Broadcast(JsonHelper.ToJson(BlockChain));
- break;
-
- case 3:
- Console.WriteLine("BlockChain");
- Console.WriteLine(JsonHelper.ToJson(BlockChain, Formatting.Indented));
- break;
- }
-
- Console.WriteLine("Please select an action");
- string action = Console.ReadLine();
- selection = int.Parse(action);
- }
-
- Client.Close();
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/BlockChain/P2PClient.cs b/EonaCat.Network/System/BlockChain/P2PClient.cs
deleted file mode 100644
index 3a4ba3a..0000000
--- a/EonaCat.Network/System/BlockChain/P2PClient.cs
+++ /dev/null
@@ -1,83 +0,0 @@
-using EonaCat.Json;
-using EonaCat.Network;
-using System;
-using System.Collections.Generic;
-
-namespace EonaCat.BlockChain
-{
- public class P2PClient
- {
- private readonly IDictionary wsDict = new Dictionary();
-
- public void Connect(string url)
- {
- if (!wsDict.ContainsKey(url))
- {
- WSClient webSocket = new WSClient(url);
- webSocket.OnMessageReceived += (sender, e) =>
- {
- if (e.Data == "Hi Client")
- {
- Console.WriteLine(e.Data);
- }
- else
- {
- var newChain = JsonHelper.ToObject(e.Data);
- if (!newChain.IsValid() || newChain.Chain.Count <= ClientServerExample.BlockChain.Chain.Count)
- {
- return;
- }
-
- var newTransactions = new List();
- newTransactions.AddRange(newChain.PendingTransactions);
- newTransactions.AddRange(ClientServerExample.BlockChain.PendingTransactions);
-
- newChain.PendingTransactions = newTransactions;
- ClientServerExample.BlockChain = newChain;
- }
- };
- webSocket.Connect();
- webSocket.Send("Hi Server");
- webSocket.Send(JsonHelper.ToJson(ClientServerExample.BlockChain));
- wsDict.Add(url, webSocket);
- }
- }
-
- public void Send(string url, string data)
- {
- foreach (var item in wsDict)
- {
- if (item.Key == url)
- {
- item.Value.Send(data);
- }
- }
- }
-
- public void Broadcast(string data)
- {
- foreach (var item in wsDict)
- {
- item.Value.Send(data);
- }
- }
-
- public IList GetServers()
- {
- IList servers = new List();
- foreach (var item in wsDict)
- {
- servers.Add(item.Key);
- }
- return servers;
- }
-
- public void Close()
- {
- foreach (var item in wsDict)
- {
- item.Value.Close();
- }
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/BlockChain/P2PServer.cs b/EonaCat.Network/System/BlockChain/P2PServer.cs
deleted file mode 100644
index 824e79d..0000000
--- a/EonaCat.Network/System/BlockChain/P2PServer.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using EonaCat.Json;
-using EonaCat.Network;
-using System;
-using System.Collections.Generic;
-
-namespace EonaCat.BlockChain
-{
- public class P2PServer : WSEndpoint
- {
- private bool _chainSynched;
- private WSServer _wss;
-
- public void Start(string webSocketAddress = null)
- {
- webSocketAddress ??= $"ws://127.0.0.1:{ClientServerExample.ServerPort}";
- _wss = new WSServer(webSocketAddress);
- _wss.AddEndpoint("/BlockChain");
- _wss.Start();
- Console.WriteLine($"Started server at {webSocketAddress}");
- }
-
- protected override void OnMessage(MessageEventArgs e)
- {
- if (e.Data == "Hi Server")
- {
- Console.WriteLine(e.Data);
- Send("Hi Client");
- }
- else
- {
- BlockChain newChain = JsonHelper.ToObject(e.Data);
-
- if (newChain.IsValid() && newChain.Chain.Count > ClientServerExample.BlockChain.Chain.Count)
- {
- List newTransactions = new List();
- newTransactions.AddRange(newChain.PendingTransactions);
- newTransactions.AddRange(ClientServerExample.BlockChain.PendingTransactions);
-
- newChain.PendingTransactions = newTransactions;
- ClientServerExample.BlockChain = newChain;
- }
-
- if (!_chainSynched)
- {
- Send(JsonHelper.ToJson(ClientServerExample.BlockChain));
- _chainSynched = true;
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/BlockChain/Transaction.cs b/EonaCat.Network/System/BlockChain/Transaction.cs
deleted file mode 100644
index a34fa96..0000000
--- a/EonaCat.Network/System/BlockChain/Transaction.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace EonaCat.BlockChain
-{
- public class Transaction
- {
- public string FromAddress { get; set; }
- public string ToAddress { get; set; }
- public int Amount { get; set; }
-
- public Transaction(string fromAddress, string toAddress, int amount)
- {
- FromAddress = fromAddress;
- ToAddress = toAddress;
- Amount = amount;
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/RemoteInfo.cs b/EonaCat.Network/System/Sockets/RemoteInfo.cs
index 26508b7..6780127 100644
--- a/EonaCat.Network/System/Sockets/RemoteInfo.cs
+++ b/EonaCat.Network/System/Sockets/RemoteInfo.cs
@@ -1,11 +1,11 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System.Net;
+using System.Net;
using System.Net.Sockets;
namespace EonaCat.Network
{
+ // This file is part of the EonaCat project(s) which is released under the Apache License.
+ // See the LICENSE file or go to https://EonaCat.com/License for full license details.
+
public class RemoteInfo
{
public bool IsTcp { get; set; }
diff --git a/EonaCat.Network/System/Sockets/Tcp/SocketTcpServer.cs b/EonaCat.Network/System/Sockets/Tcp/SocketTcpServer.cs
index 75297b1..767cda4 100644
--- a/EonaCat.Network/System/Sockets/Tcp/SocketTcpServer.cs
+++ b/EonaCat.Network/System/Sockets/Tcp/SocketTcpServer.cs
@@ -104,7 +104,7 @@ namespace EonaCat.Network
{
try
{
- int received = await socket.ReceiveAsync(new Memory(buffer), SocketFlags.None, cancellationToken).ConfigureAwait(false);
+ int received = await ReceiveAsync(socket, buffer, cancellationToken).ConfigureAwait(false);
if (received > 0)
{
byte[] data = new byte[received];
@@ -139,6 +139,13 @@ namespace EonaCat.Network
});
}
+ private Task ReceiveAsync(Socket socket, byte[] buffer, CancellationToken cancellationToken)
+ {
+ return Task.Factory.FromAsync(socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, null, socket),
+ socket.EndReceive);
+ }
+
+
///
/// Send data to socket
///
diff --git a/EonaCat.Network/System/Sockets/Web/ByteOrder.cs b/EonaCat.Network/System/Sockets/Web/ByteOrder.cs
deleted file mode 100644
index 5e784d6..0000000
--- a/EonaCat.Network/System/Sockets/Web/ByteOrder.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-namespace EonaCat.Network
-{
- public enum ByteOrder
- {
- Little,
-
- Big
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/CloseStatusCode.cs b/EonaCat.Network/System/Sockets/Web/CloseStatusCode.cs
deleted file mode 100644
index 9763359..0000000
--- a/EonaCat.Network/System/Sockets/Web/CloseStatusCode.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-namespace EonaCat.Network
-{
- public enum CloseStatusCode : ushort
- {
- //1000: Normal Closure
- //Indicates a normal closure, meaning that the purpose for which the connection was established has been fulfilled.
-
- //1001: Going Away
- //The endpoint is going away, such as a server going down or a browser tab is closing.
-
- //1002: Protocol Error
- //Indicates that the endpoint is terminating the connection due to a protocol error.
-
- //1003: Unsupported Data
- //Indicates that the endpoint is terminating the connection because it received data that it cannot process.
-
- //1005: No Status Received
- //Reserved. It indicates that no status code was received.
-
- //1006: Abnormal Closure
- //Reserved. It is a reserved value and should not be set as a status code in a Close control frame by an endpoint.
-
- //1007: Invalid frame payload data
- //Indicates that an endpoint is terminating the connection because it has received data within a message that was not consistent with the type of the message.
-
- //1008: Policy Violation
- //Indicates that an endpoint is terminating the connection because it has received a message that violates its policy.
-
- //1009: Message Too Big
- //Indicates that an endpoint is terminating the connection because it has received a message that is too big for it to process.
-
- //1010: Missing Extension
- //Indicates that an endpoint is terminating the connection because it has received a message that requires negotiation of an extension, and the client did not offer that extension.
-
- //1011: Internal Error
- //Indicates that a server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request.
-
- //1012: Service Restart
- //Reserved. It indicates that the service is restarting.
-
- //1013: Try Again Later
- //Reserved. It indicates that the server is temporarily unable to process the request.
-
- //1014: Bad Gateway
- //Reserved. It indicates that an intermediate server failed to fulfill a request.
-
- //1015: TLS Handshake Failure
- //Reserved. It indicates that the connection was closed due to a failure to perform a TLS handshake.
-
- Normal = 1000,
-
- Away = 1001,
-
- ProtocolError = 1002,
-
- UnsupportedData = 1003,
-
- Undefined = 1004,
-
- NoStatus = 1005,
-
- Abnormal = 1006,
-
- InvalidData = 1007,
-
- PolicyViolation = 1008,
-
- TooBig = 1009,
-
- MissingExtension = 1010,
-
- ServerError = 1011,
-
- ServiceRestart = 1012,
-
- TryAgainLater = 1013,
-
- BadGateway = 1014,
-
- TlsHandshakeFailure = 1015
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/CompressionMethod.cs b/EonaCat.Network/System/Sockets/Web/CompressionMethod.cs
deleted file mode 100644
index ada0444..0000000
--- a/EonaCat.Network/System/Sockets/Web/CompressionMethod.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-namespace EonaCat.Network
-{
- public enum CompressionMethod : byte
- {
- None,
-
- Deflate
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Authentication/AuthenticationBase.cs b/EonaCat.Network/System/Sockets/Web/Core/Authentication/AuthenticationBase.cs
deleted file mode 100644
index 35c4d75..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Authentication/AuthenticationBase.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-using System.Collections.Specialized;
-using System.Text;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents the base class for authentication in the EonaCat network library.
- ///
- internal abstract class AuthenticationBase
- {
- ///
- /// Gets or sets the collection of authentication parameters.
- ///
- internal NameValueCollection Parameters;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The authentication scheme.
- /// The collection of authentication parameters.
- protected AuthenticationBase(AuthenticationSchemes scheme, NameValueCollection parameters)
- {
- Scheme = scheme;
- Parameters = parameters;
- }
-
- ///
- /// Gets the algorithm used for authentication.
- ///
- public string Algorithm => Parameters["algorithm"];
-
- ///
- /// Gets the nonce value for authentication.
- ///
- public string Nonce => Parameters["nonce"];
-
- ///
- /// Gets the opaque value for authentication.
- ///
- public string Opaque => Parameters["opaque"];
-
- ///
- /// Gets the quality of protection for authentication.
- ///
- public string Qop => Parameters["qop"];
-
- ///
- /// Gets the realm for authentication.
- ///
- public string Realm => Parameters["realm"];
-
- ///
- /// Gets the authentication scheme.
- ///
- public AuthenticationSchemes Scheme { get; }
-
- ///
- /// Creates a nonce value for authentication.
- ///
- /// A string representing the generated nonce value.
- internal static string CreateNonceValue()
- {
- var buffer = new byte[16];
- var random = new Random();
- random.NextBytes(buffer);
-
- var result = new StringBuilder(32);
- foreach (var currentByte in buffer)
- {
- result.Append(currentByte.ToString("x2"));
- }
-
- return result.ToString();
- }
-
- ///
- /// Parses the authentication parameters from the specified string value.
- ///
- /// The string containing authentication parameters.
- /// A collection of authentication parameters.
- internal static NameValueCollection ParseParameters(string value)
- {
- var result = new NameValueCollection();
- foreach (var param in value.SplitHeaderValue(','))
- {
- var i = param.IndexOf('=');
- var name = i > 0 ? param.Substring(0, i).Trim() : null;
- var val = i < 0
- ? param.Trim().Trim('"')
- : i < param.Length - 1
- ? param.Substring(i + 1).Trim().Trim('"')
- : string.Empty;
-
- result.Add(name, val);
- }
-
- return result;
- }
-
- ///
- /// Gets the authentication string for Basic authentication.
- ///
- /// A string representing the Basic authentication.
- internal abstract string ToBasicString();
-
- ///
- /// Gets the authentication string for Digest authentication.
- ///
- /// A string representing the Digest authentication.
- internal abstract string ToDigestString();
-
- ///
- /// Returns a string representation of the authentication information.
- ///
- /// A string representation of the authentication information.
- public override string ToString()
- {
- return Scheme == AuthenticationSchemes.Basic
- ? ToBasicString()
- : Scheme == AuthenticationSchemes.Digest
- ? ToDigestString()
- : string.Empty;
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Authentication/AuthenticationChallenge.cs b/EonaCat.Network/System/Sockets/Web/Core/Authentication/AuthenticationChallenge.cs
deleted file mode 100644
index ad9eaf9..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Authentication/AuthenticationChallenge.cs
+++ /dev/null
@@ -1,136 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System.Collections.Specialized;
-using System.Text;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents an authentication challenge in the EonaCat network library.
- ///
- internal class AuthenticationChallenge : AuthenticationBase
- {
- private const string BASIC = "basic";
- private const string DIGEST = "digest";
- private const int DIGEST_SIZE = 128;
-
- ///
- /// Initializes a new instance of the class for Basic or Digest authentication.
- ///
- /// The authentication scheme.
- /// The authentication realm.
- internal AuthenticationChallenge(AuthenticationSchemes scheme, string realm)
- : base(scheme, new NameValueCollection())
- {
- Parameters["realm"] = realm;
- if (scheme == AuthenticationSchemes.Digest)
- {
- Parameters["nonce"] = CreateNonceValue();
- Parameters["algorithm"] = "MD5";
- Parameters["qop"] = "auth";
- }
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The authentication scheme.
- /// The collection of authentication parameters.
- private AuthenticationChallenge(AuthenticationSchemes scheme, NameValueCollection parameters)
- : base(scheme, parameters)
- {
- }
-
- ///
- /// Gets the domain for Digest authentication.
- ///
- public string Domain => Parameters["domain"];
-
- ///
- /// Gets the stale parameter for Digest authentication.
- ///
- public string Stale => Parameters["stale"];
-
- ///
- /// Creates a Basic authentication challenge with the specified realm.
- ///
- /// The authentication realm.
- /// An instance of for Basic authentication.
-
- internal static AuthenticationChallenge CreateBasicChallenge(string realm)
- {
- return new AuthenticationChallenge(AuthenticationSchemes.Basic, realm);
- }
-
- ///
- /// Creates a Digest authentication challenge with the specified realm.
- ///
- /// The authentication realm.
- /// An instance of for Digest authentication.
- internal static AuthenticationChallenge CreateDigestChallenge(string realm)
- {
- return new AuthenticationChallenge(AuthenticationSchemes.Digest, realm);
- }
-
- ///
- /// Parses an authentication challenge from the specified string value.
- ///
- /// The string containing the authentication challenge.
- /// An instance of if successful; otherwise, null.
- internal static AuthenticationChallenge Parse(string value)
- {
- var challenge = value.Split(new[] { ' ' }, 2);
- if (challenge.Length != 2)
- {
- return null;
- }
-
- var scheme = challenge[0].ToLower();
- return scheme == BASIC
- ? new AuthenticationChallenge(
- AuthenticationSchemes.Basic, ParseParameters(challenge[1]))
- : scheme == DIGEST
- ? new AuthenticationChallenge(
- AuthenticationSchemes.Digest, ParseParameters(challenge[1]))
- : null;
- }
-
- ///
- /// Gets the Basic authentication string representation of the authentication challenge.
- ///
- /// A string representing the Basic authentication challenge.
- internal override string ToBasicString()
- {
- return string.Format($"Basic realm=\"{{0}}\"", Parameters["realm"]);
- }
-
- internal override string ToDigestString()
- {
- var output = new StringBuilder(DIGEST_SIZE);
- var realm = Parameters["realm"];
- var nonce = Parameters["nonce"];
-
- if (realm != null)
- {
- output.AppendFormat("Digest realm=\"{0}\", nonce=\"{1}\"", realm, nonce);
-
- AppendIfNotNull(output, "domain", Parameters["domain"]);
- AppendIfNotNull(output, "opaque", Parameters["opaque"]);
- AppendIfNotNull(output, "stale", Parameters["stale"]);
- AppendIfNotNull(output, "algorithm", Parameters["algorithm"]);
- AppendIfNotNull(output, "qop", Parameters["qop"]);
- }
-
- return output.ToString();
- }
-
- private static void AppendIfNotNull(StringBuilder output, string key, string value)
- {
- if (value != null)
- {
- output.AppendFormat(", {0}=\"{1}\"", key, value);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Authentication/AuthenticationResponse.cs b/EonaCat.Network/System/Sockets/Web/Core/Authentication/AuthenticationResponse.cs
deleted file mode 100644
index 64ccdf0..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Authentication/AuthenticationResponse.cs
+++ /dev/null
@@ -1,359 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-using System.Collections.Specialized;
-using System.Security.Cryptography;
-using System.Security.Principal;
-using System.Text;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents an authentication response in the EonaCat network library.
- ///
- internal class AuthenticationResponse : AuthenticationBase
- {
- private const string BASIC = "basic";
- private const string DIGEST = "digest";
- private uint _nonceCount;
-
- ///
- /// Initializes a new instance of the class for Basic authentication.
- ///
- /// The network credentials.
- internal AuthenticationResponse(NetworkCredential credentials)
- : this(AuthenticationSchemes.Basic, new NameValueCollection(), credentials, 0)
- {
- }
-
- ///
- /// Initializes a new instance of the class for Digest authentication.
- ///
- /// The authentication challenge.
- /// The network credentials.
- /// The nonce count.
- internal AuthenticationResponse(
- AuthenticationChallenge challenge, NetworkCredential credentials, uint nonceCount)
- : this(challenge.Scheme, challenge.Parameters, credentials, nonceCount)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The authentication scheme.
- /// The collection of authentication parameters.
- /// The network credentials.
- /// The nonce count.
- internal AuthenticationResponse(
- AuthenticationSchemes scheme,
- NameValueCollection parameters,
- NetworkCredential credentials,
- uint nonceCount)
- : base(scheme, parameters)
- {
- Parameters["username"] = credentials.Username;
- Parameters["password"] = credentials.Password;
- Parameters["uri"] = credentials.Domain;
- _nonceCount = nonceCount;
- if (scheme == AuthenticationSchemes.Digest)
- {
- InitAsDigest();
- }
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The authentication scheme.
- /// The collection of authentication parameters.
- private AuthenticationResponse(AuthenticationSchemes scheme, NameValueCollection parameters)
- : base(scheme, parameters)
- {
- }
-
- ///
- /// Gets the cnonce value for Digest authentication.
- ///
- public string Cnonce => Parameters["cnonce"];
-
- ///
- /// Gets the nonce count for Digest authentication.
- ///
- public string Nc => Parameters["nc"];
-
- ///
- /// Gets the password for authentication.
- ///
- public string Password => Parameters["password"];
-
- ///
- /// Gets the response value for authentication.
- ///
- public string Response => Parameters["response"];
-
- ///
- /// Gets the URI for authentication.
- ///
- public string Uri => Parameters["uri"];
-
- ///
- /// Gets the username for authentication.
- ///
- public string UserName => Parameters["username"];
-
- ///
- /// Gets the nonce count.
- ///
- internal uint NonceCount => _nonceCount < uint.MaxValue
- ? _nonceCount
- : 0;
-
- ///
- /// Converts the authentication response to an identity.
- ///
- /// An instance of .
- public IIdentity ToIdentity()
- {
- var scheme = Scheme;
- return scheme == AuthenticationSchemes.Basic
- ? new HttpBasicIdentity(Parameters["username"], Parameters["password"])
- : scheme == AuthenticationSchemes.Digest
- ? new HttpDigestIdentity(Parameters)
- : null;
- }
-
- ///
- /// Creates the request digest for Digest authentication.
- ///
- /// The authentication parameters.
- /// The request digest.
- internal static string CreateRequestDigest(NameValueCollection parameters)
- {
- var user = parameters["username"];
- var pass = parameters["password"];
- var realm = parameters["realm"];
- var nonce = parameters["nonce"];
- var uri = parameters["uri"];
- var algo = parameters["algorithm"];
- var qop = parameters["qop"];
- var cnonce = parameters["cnonce"];
- var nc = parameters["nc"];
- var method = parameters["method"];
-
- var a1 = algo != null && algo.ToLower() == "md5-sess"
- ? CreateA1(user, pass, realm, nonce, cnonce)
- : CreateA1(user, pass, realm);
-
- var a2 = qop != null && qop.ToLower() == "auth-int"
- ? CreateA2(method, uri, parameters["entity"])
- : CreateA2(method, uri);
-
- var secret = Hash(a1);
- var data = qop != null
- ? string.Format("{0}:{1}:{2}:{3}:{4}", nonce, nc, cnonce, qop, Hash(a2))
- : string.Format("{0}:{1}", nonce, Hash(a2));
-
- return Hash(string.Format("{0}:{1}", secret, data));
- }
-
- ///
- /// Parses an authentication response from the specified string value.
- ///
- /// The string containing the authentication response.
- /// An instance of if successful; otherwise, null.
- internal static AuthenticationResponse Parse(string value)
- {
- try
- {
- var cred = value.Split(new[] { ' ' }, 2);
- if (cred.Length != 2)
- {
- return null;
- }
-
- var scheme = cred[0].ToLower();
- return scheme == BASIC
- ? new AuthenticationResponse(
- AuthenticationSchemes.Basic, ParseBasicCredentials(cred[1]))
- : scheme == DIGEST
- ? new AuthenticationResponse(
- AuthenticationSchemes.Digest, ParseParameters(cred[1]))
- : null;
- }
- catch
- {
- }
-
- return null;
- }
-
- ///
- /// Parses the basic credentials from the specified string value.
- ///
- /// The string containing basic credentials.
- /// A collection of basic credentials.
- internal static NameValueCollection ParseBasicCredentials(string value)
- {
- // Decode the basic-credentials (a Base64 encoded string).
- var userPass = Encoding.Default.GetString(Convert.FromBase64String(value));
-
- // The format is [\]:.
- var i = userPass.IndexOf(':');
- var user = userPass.Substring(0, i);
- var pass = i < userPass.Length - 1 ? userPass.Substring(i + 1) : string.Empty;
-
- // Check if 'domain' exists.
- i = user.IndexOf('\\');
- if (i > -1)
- {
- user = user.Substring(i + 1);
- }
-
- var res = new NameValueCollection
- {
- ["username"] = user,
- ["password"] = pass
- };
-
- return res;
- }
-
- ///
- /// Gets the Basic authentication string representation of the authentication response.
- ///
- /// A string representing the Basic authentication response.
- internal override string ToBasicString()
- {
- var userPass = string.Format("{0}:{1}", Parameters["username"], Parameters["password"]);
- var cred = Convert.ToBase64String(Encoding.UTF8.GetBytes(userPass));
-
- return "Basic " + cred;
- }
-
- ///
- /// Gets the Digest authentication string representation of the authentication response.
- ///
- /// A string representing the Digest authentication response.
- internal override string ToDigestString()
- {
- var output = new StringBuilder(256);
- output.AppendFormat($"Digest username=\"{Parameters["username"]}\", realm=\"{Parameters["realm"]}\", nonce=\"{Parameters["nonce"]}\", uri=\"{Parameters["uri"]}\", response=\"{Parameters["response"]}\"");
-
- var opaque = Parameters["opaque"];
- if (opaque != null)
- {
- output.AppendFormat($", opaque=\"{opaque}\"");
- }
-
- var algorithm = Parameters["algorithm"];
- if (algorithm != null)
- {
- output.AppendFormat($", algorithm={algorithm}");
- }
-
- var qop = Parameters["qop"];
- if (qop != null)
- {
- output.AppendFormat($", qop={qop}, cnonce=\"{Parameters["cnonce"]}\", nc={Parameters["nc"]}");
- }
-
- return output.ToString();
- }
-
- ///
- /// Creates the A1 value for Digest authentication.
- ///
- /// The username.
- /// The password.
- /// The realm.
- /// The A1 value.
- private static string CreateA1(string username, string password, string realm)
- {
- return $"{username}:{realm}:{password}";
- }
-
- ///
- /// Creates the A1 value for Digest authentication with cnonce and nonce.
- ///
- /// The username.
- /// The password.
- /// The realm.
- /// The nonce.
- /// The cnonce.
- /// The A1 value.
- private static string CreateA1(
- string username, string password, string realm, string nonce, string cnonce)
- {
- return $"{Hash(CreateA1(username, password, realm))}:{nonce}:{cnonce}";
- }
-
- ///
- /// Creates the A2 value for Digest authentication.
- ///
- /// The HTTP method.
- /// The URI.
- /// The A2 value.
- private static string CreateA2(string method, string uri)
- {
- return $"{method}:{uri}";
- }
-
- ///
- /// Creates the A2 value for Digest authentication with an entity.
- ///
- /// The HTTP method.
- /// The URI.
- /// The entity.
- /// The A2 value.
- private static string CreateA2(string method, string uri, string entity)
- {
- return $"{method}:{uri}:{Hash(entity)}";
- }
-
- ///
- /// Computes the MD5 hash of the given value.
- ///
- /// The value to hash.
- /// The MD5 hash.
- private static string Hash(string value)
- {
- var source = Encoding.UTF8.GetBytes(value);
- var md5 = MD5.Create();
- var hashed = md5.ComputeHash(source);
-
- var result = new StringBuilder(64);
- foreach (var currentByte in hashed)
- {
- result.Append(currentByte.ToString("x2"));
- }
-
- return result.ToString();
- }
-
- ///
- /// Initializes the authentication as Digest.
- ///
- private void InitAsDigest()
- {
- var qops = Parameters["qop"];
- if (qops != null)
- {
- if (qops.Split(',').Contains(qop => qop.Trim().ToLower() == "auth"))
- {
- Parameters["qop"] = "auth";
- Parameters["cnonce"] = CreateNonceValue();
- Parameters["nc"] = string.Format("{0:x8}", ++_nonceCount);
- }
- else
- {
- Parameters["qop"] = null;
- }
- }
-
- Parameters["method"] = "GET";
- Parameters["response"] = CreateRequestDigest(Parameters);
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Authentication/AuthenticationSchemes.cs b/EonaCat.Network/System/Sockets/Web/Core/Authentication/AuthenticationSchemes.cs
deleted file mode 100644
index be5cbc0..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Authentication/AuthenticationSchemes.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-namespace EonaCat.Network
-{
- ///
- /// Enumerates the possible authentication schemes in the EonaCat network library.
- ///
- public enum AuthenticationSchemes
- {
- ///
- /// No authentication scheme.
- ///
- None,
-
- ///
- /// Digest authentication scheme.
- ///
- Digest = 1,
-
- ///
- /// Basic authentication scheme.
- ///
- Basic = 8,
-
- ///
- /// Anonymous authentication scheme.
- ///
- Anonymous = 0x8000
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Authentication/NetworkCredential.cs b/EonaCat.Network/System/Sockets/Web/Core/Authentication/NetworkCredential.cs
deleted file mode 100644
index ce6e467..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Authentication/NetworkCredential.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents network credentials used for authentication in the EonaCat network library.
- ///
- public class NetworkCredential
- {
- private static readonly string[] _noRoles;
- private string _domain;
- private string _password;
- private string[] _roles;
-
- static NetworkCredential()
- {
- _noRoles = new string[0];
- }
-
- ///
- /// Initializes a new instance of the class with the specified username and password.
- ///
- /// The username.
- /// The password.
- public NetworkCredential(string username, string password)
- : this(username, password, null, null)
- {
- }
-
- ///
- /// Initializes a new instance of the class with the specified username, password, domain, and roles.
- ///
- /// The username.
- /// The password.
- /// The domain.
- /// The roles.
- public NetworkCredential(
- string username, string password, string domain, params string[] roles
- )
- {
- if (username == null)
- {
- throw new ArgumentNullException(nameof(username));
- }
-
- if (username.Length == 0)
- {
- throw new ArgumentException("An empty string.", nameof(username));
- }
-
- Username = username;
- _password = password;
- _domain = domain;
- _roles = roles;
- }
-
- ///
- /// Gets or sets the domain associated with the network credentials.
- ///
- public string Domain
- {
- get
- {
- return _domain ?? string.Empty;
- }
-
- internal set
- {
- _domain = value;
- }
- }
-
- ///
- /// Gets or sets the password associated with the network credentials.
- ///
- public string Password
- {
- get
- {
- return _password ?? string.Empty;
- }
-
- internal set
- {
- _password = value;
- }
- }
-
- ///
- /// Gets or sets the roles associated with the network credentials.
- ///
- public string[] Roles
- {
- get
- {
- return _roles ?? _noRoles;
- }
-
- internal set
- {
- _roles = value;
- }
- }
-
- ///
- /// Gets the username associated with the network credentials.
- ///
- public string Username { get; internal set; }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Chunks/Chunk.cs b/EonaCat.Network/System/Sockets/Web/Core/Chunks/Chunk.cs
deleted file mode 100644
index 3942cfb..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Chunks/Chunk.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents a chunk of data in the EonaCat network library.
- ///
- internal class WebChunk
- {
- private readonly byte[] _data;
- private int _offset;
-
- ///
- /// Initializes a new instance of the class with the specified data.
- ///
- /// The byte array representing the data.
- public WebChunk(byte[] data)
- {
- _data = data;
- }
-
- ///
- /// Gets the remaining bytes to read in the chunk.
- ///
- public int ReadLeft => _data.Length - _offset;
-
- ///
- /// Reads a specified number of bytes from the chunk into a buffer.
- ///
- /// The destination buffer.
- /// The zero-based byte offset in the buffer at which to begin storing the data.
- /// The maximum number of bytes to read.
- /// The actual number of bytes read.
- public int Read(byte[] buffer, int offset, int count)
- {
- var left = _data.Length - _offset;
- if (left == 0)
- {
- return left;
- }
-
- if (count > left)
- {
- count = left;
- }
-
- Buffer.BlockCopy(_data, _offset, buffer, offset, count);
- _offset += count;
-
- return count;
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Chunks/ChunkStream.cs b/EonaCat.Network/System/Sockets/Web/Core/Chunks/ChunkStream.cs
deleted file mode 100644
index 0ba330c..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Chunks/ChunkStream.cs
+++ /dev/null
@@ -1,398 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Net;
-using System.Text;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents a stream for handling chunked data in the EonaCat network library.
- ///
- internal class ChunkStream
- {
- private readonly List _chunks;
- private readonly StringBuilder _saved;
- private int _chunkRead;
- private int _chunkSize;
- private bool _foundSPCode;
- private bool _gotChunck;
- private InputChunkState _state;
- private int _trailerState;
-
- ///
- /// Initializes a new instance of the class with the specified headers.
- ///
- /// The web headers associated with the chunk stream.
- public ChunkStream(WebHeaderCollection headers)
- {
- Headers = headers;
- _chunkSize = -1;
- _chunks = new List();
- _saved = new StringBuilder();
- }
-
- ///
- /// Initializes a new instance of the class with the specified buffer, offset, count, and headers.
- ///
- /// The byte array containing chunked data.
- /// The offset in the buffer at which to begin reading.
- /// The number of bytes to read from the buffer.
- /// The web headers associated with the chunk stream.
- public ChunkStream(byte[] buffer, int offset, int count, WebHeaderCollection headers)
- : this(headers)
- {
- Write(buffer, offset, count);
- }
-
- ///
- /// Gets the number of bytes left in the current chunk.
- ///
- public int ChunkLeft => _chunkSize - _chunkRead;
-
- ///
- /// Gets a value indicating whether more data is expected.
- ///
- public bool WantMore => _state != InputChunkState.End;
-
- ///
- /// Gets the web headers associated with the chunk stream.
- ///
- internal WebHeaderCollection Headers { get; }
-
- ///
- /// Reads a specified amount of data from the chunk stream.
- ///
- /// The destination buffer.
- /// The zero-based byte offset in the buffer at which to begin storing the data.
- /// The maximum number of bytes to read.
- /// The total number of bytes read into the buffer.
- public int Read(byte[] buffer, int offset, int count)
- {
- if (count <= 0)
- {
- return 0;
- }
-
- return read(buffer, offset, count);
- }
-
- ///
- /// Writes a specified amount of data to the chunk stream.
- ///
- /// The byte array containing data to be written to the chunk stream.
- /// The offset in the buffer at which to begin writing.
- /// The number of bytes to write to the chunk stream.
- public void Write(byte[] buffer, int offset, int count)
- {
- if (count <= 0)
- {
- return;
- }
-
- Write(buffer, ref offset, offset + count);
- }
-
- ///
- /// Resets the internal buffer and state of the chunk stream.
- ///
- internal void ResetBuffer()
- {
- _chunkRead = 0;
- _chunkSize = -1;
- _chunks.Clear();
- }
-
- ///
- /// Writes a specified amount of data to the chunk stream and reads it back.
- ///
- /// The byte array containing data to be written to the chunk stream.
- /// The offset in the buffer at which to begin writing.
- /// The number of bytes to write to the chunk stream.
- /// The number of bytes to read back from the chunk stream.
- /// The number of bytes read from the chunk stream.
- internal int WriteAndReadBack(byte[] buffer, int offset, int writeCount, int readCount)
- {
- Write(buffer, offset, writeCount);
- return Read(buffer, offset, readCount);
- }
-
- private static string RemoveChunkExtension(string value)
- {
- var index = value.IndexOf(';');
- return index > -1 ? value.Substring(0, index) : value;
- }
-
- private static void ThrowProtocolViolation(string message)
- {
- throw new WebException($"EonaCat Network: {message}", null, WebExceptionStatus.ServerProtocolViolation, null);
- }
-
- private int read(byte[] buffer, int offset, int count)
- {
- var nread = 0;
-
- var cnt = _chunks.Count;
- for (var i = 0; i < cnt; i++)
- {
- var chunk = _chunks[i];
- if (chunk == null)
- {
- continue;
- }
-
- if (chunk.ReadLeft == 0)
- {
- _chunks[i] = null;
- continue;
- }
-
- nread += chunk.Read(buffer, offset + nread, count - nread);
- if (nread == count)
- {
- break;
- }
- }
-
- return nread;
- }
-
- private InputChunkState SeekCrLf(byte[] buffer, ref int offset, int length)
- {
- if (!_gotChunck)
- {
- if (buffer[offset++] != 13)
- {
- ThrowProtocolViolation("CR is expected.");
- }
-
- _gotChunck = true;
- if (offset == length)
- {
- return InputChunkState.DataEnded;
- }
- }
-
- if (buffer[offset++] != 10)
- {
- ThrowProtocolViolation("LF is expected.");
- }
-
- return InputChunkState.None;
- }
-
- private InputChunkState SetChunkSize(byte[] buffer, ref int offset, int length)
- {
- byte currentByte = 0;
- while (offset < length)
- {
- currentByte = buffer[offset++];
- if (_gotChunck)
- {
- if (currentByte != 10)
- {
- ThrowProtocolViolation("LF is expected.");
- }
-
- break;
- }
-
- if (currentByte == 13)
- {
- _gotChunck = true;
- continue;
- }
-
- if (currentByte == 10)
- {
- ThrowProtocolViolation("LF is unexpected.");
- }
-
- if (currentByte == 32) // SP
- {
- _foundSPCode = true;
- }
-
- if (!_foundSPCode)
- {
- _saved.Append((char)currentByte);
- }
-
- if (_saved.Length > 20)
- {
- ThrowProtocolViolation("The chunk size is too long.");
- }
- }
-
- if (!_gotChunck || currentByte != 10)
- {
- return InputChunkState.None;
- }
-
- _chunkRead = 0;
- try
- {
- _chunkSize = int.Parse(
- RemoveChunkExtension(_saved.ToString()), NumberStyles.HexNumber);
- }
- catch
- {
- ThrowProtocolViolation("The chunk size cannot be parsed.");
- }
-
- if (_chunkSize == 0)
- {
- _trailerState = 2;
- return InputChunkState.Trailer;
- }
-
- return InputChunkState.Data;
- }
-
- private InputChunkState setTrailer(byte[] buffer, ref int offset, int length)
- {
- // Check if no trailer.
- if (_trailerState == 2 && buffer[offset] == 13 && _saved.Length == 0)
- {
- offset++;
- if (offset < length && buffer[offset] == 10)
- {
- offset++;
- return InputChunkState.End;
- }
-
- offset--;
- }
-
- while (offset < length && _trailerState < 4)
- {
- var currentByte = buffer[offset++];
- _saved.Append((char)currentByte);
- if (_saved.Length > 4196)
- {
- ThrowProtocolViolation("The trailer is too long.");
- }
-
- if (_trailerState == 1 || _trailerState == 3)
- {
- if (currentByte != 10)
- {
- ThrowProtocolViolation("LF is expected.");
- }
-
- _trailerState++;
- continue;
- }
-
- if (currentByte == 13)
- {
- _trailerState++;
- continue;
- }
-
- if (currentByte == 10)
- {
- ThrowProtocolViolation("LF is unexpected.");
- }
-
- _trailerState = 0;
- }
-
- if (_trailerState < 4)
- {
- return InputChunkState.Trailer;
- }
-
- _saved.Length -= 2;
- var reader = new StringReader(_saved.ToString());
-
- string line;
- while ((line = reader.ReadLine()) != null && line.Length > 0)
- {
- Headers.Add(line);
- }
-
- return InputChunkState.End;
- }
-
- private void Write(byte[] buffer, ref int offset, int length)
- {
- if (_state == InputChunkState.End)
- {
- ThrowProtocolViolation("The chunks were ended.");
- }
-
- if (_state == InputChunkState.None)
- {
- _state = SetChunkSize(buffer, ref offset, length);
- if (_state == InputChunkState.None)
- {
- return;
- }
-
- _saved.Length = 0;
- _gotChunck = false;
- _foundSPCode = false;
- }
-
- if (_state == InputChunkState.Data && offset < length)
- {
- _state = WriteData(buffer, ref offset, length);
- if (_state == InputChunkState.Data)
- {
- return;
- }
- }
-
- if (_state == InputChunkState.DataEnded && offset < length)
- {
- _state = SeekCrLf(buffer, ref offset, length);
- if (_state == InputChunkState.DataEnded)
- {
- return;
- }
-
- _gotChunck = false;
- }
-
- if (_state == InputChunkState.Trailer && offset < length)
- {
- _state = setTrailer(buffer, ref offset, length);
- if (_state == InputChunkState.Trailer)
- {
- return;
- }
-
- _saved.Length = 0;
- }
-
- if (offset < length)
- {
- Write(buffer, ref offset, length);
- }
- }
-
- private InputChunkState WriteData(byte[] buffer, ref int offset, int length)
- {
- var cnt = length - offset;
- var left = _chunkSize - _chunkRead;
- if (cnt > left)
- {
- cnt = left;
- }
-
- var data = new byte[cnt];
- Buffer.BlockCopy(buffer, offset, data, 0, cnt);
- _chunks.Add(new WebChunk(data));
-
- offset += cnt;
- _chunkRead += cnt;
-
- return _chunkRead == _chunkSize ? InputChunkState.DataEnded : InputChunkState.Data;
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Chunks/ChunkedRequestStream.cs b/EonaCat.Network/System/Sockets/Web/Core/Chunks/ChunkedRequestStream.cs
deleted file mode 100644
index d62b77d..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Chunks/ChunkedRequestStream.cs
+++ /dev/null
@@ -1,208 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-using System.IO;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents a stream for handling chunked requests in the EonaCat network library.
- ///
- internal class ChunkedRequestStream : RequestStream
- {
- private const int _bufferLength = 8192;
- private readonly HttpListenerContext _context;
- private bool _disposed;
- private bool _noMoreData;
-
- ///
- /// Initializes a new instance of the class with the specified stream, buffer, offset, count, and context.
- ///
- /// The underlying stream.
- /// The byte array used for buffering.
- /// The offset in the buffer at which to begin reading.
- /// The maximum number of bytes to read.
- /// The HTTP listener context.
- internal ChunkedRequestStream(Stream stream, byte[] buffer, int offset, int count, HttpListenerContext context)
- : base(stream, buffer, offset, count)
- {
- _context = context;
- Decoder = new ChunkStream((WebHeaderCollection)context.Request.Headers);
- }
-
- ///
- /// Gets or sets the chunk stream decoder associated with the chunked request stream.
- ///
- internal ChunkStream Decoder { get; set; }
-
- ///
- /// Begins an asynchronous read operation from the stream.
- ///
- /// The destination buffer.
- /// The zero-based byte offset in the buffer at which to begin storing the data.
- /// The maximum number of bytes to read.
- /// An optional asynchronous callback, to be called when the read is complete.
- /// A user-provided object that distinguishes this particular asynchronous read request from other requests.
- /// An that represents the asynchronous read operation.
- public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
- {
- if (_disposed)
- {
- throw new ObjectDisposedException(GetType().ToString());
- }
-
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer));
- }
-
- if (offset < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(offset), "A negative value.");
- }
-
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(count), "A negative value.");
- }
-
- var len = buffer.Length;
- if (offset + count > len)
- {
- throw new ArgumentException(
- "The sum of 'offset' and 'count' is greater than 'buffer' length.");
- }
-
- var result = new HttpStreamAsyncResult(callback, state);
- if (_noMoreData)
- {
- result.Complete();
- return result;
- }
-
- var nread = Decoder.Read(buffer, offset, count);
- offset += nread;
- count -= nread;
- if (count == 0)
- {
- result.Count = nread;
- result.Complete();
-
- return result;
- }
-
- if (!Decoder.WantMore)
- {
- _noMoreData = nread == 0;
- result.Count = nread;
- result.Complete();
-
- return result;
- }
-
- result.Buffer = new byte[_bufferLength];
- result.Offset = 0;
- result.Count = _bufferLength;
-
- var readBufferState = new ReadBufferState(buffer, offset, count, result);
- readBufferState.InitialCount += nread;
- base.BeginRead(result.Buffer, result.Offset, result.Count, OnRead, readBufferState);
-
- return result;
- }
-
- ///
- /// Closes the stream.
- ///
- public override void Close()
- {
- if (_disposed)
- {
- return;
- }
-
- _disposed = true;
- base.Close();
- }
-
- ///
- /// Ends an asynchronous read operation from the stream.
- ///
- /// The result of the asynchronous operation.
- /// The number of bytes read from the stream, between zero (0) and the number of bytes you requested. Streams return zero (0) only at the end of the stream, otherwise, they should block until at least one byte is available.
- public override int EndRead(IAsyncResult asyncResult)
- {
- if (_disposed)
- {
- throw new ObjectDisposedException(GetType().ToString());
- }
-
- if (asyncResult == null)
- {
- throw new ArgumentNullException(nameof(asyncResult));
- }
-
- if (asyncResult is not HttpStreamAsyncResult result)
- {
- throw new ArgumentException("A wrong IAsyncResult.", nameof(asyncResult));
- }
-
- if (!result.IsCompleted)
- {
- result.AsyncWaitHandle.WaitOne();
- }
-
- if (result.HasException)
- {
- throw new HttpListenerException(400, "I/O operation aborted.");
- }
-
- return result.Count;
- }
-
- ///
- /// Reads a sequence of bytes from the stream and advances the position within the stream by the number of bytes read.
- ///
- /// The byte array to read data into.
- /// The zero-based byte offset in buffer at which to begin storing the data.
- /// The maximum number of bytes to be read from the stream.
- /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.
- public override int Read(byte[] buffer, int offset, int count)
- {
- var result = BeginRead(buffer, offset, count, null, null);
- return EndRead(result);
- }
-
- private void OnRead(IAsyncResult asyncResult)
- {
- var readBufferState = (ReadBufferState)asyncResult.AsyncState;
- var result = readBufferState.AsyncResult;
- try
- {
- var nread = base.EndRead(asyncResult);
- Decoder.Write(result.Buffer, result.Offset, nread);
- nread = Decoder.Read(readBufferState.Buffer, readBufferState.Offset, readBufferState.Count);
- readBufferState.Offset += nread;
- readBufferState.Count -= nread;
- if (readBufferState.Count == 0 || !Decoder.WantMore || nread == 0)
- {
- _noMoreData = !Decoder.WantMore && nread == 0;
- result.Count = readBufferState.InitialCount - readBufferState.Count;
- result.Complete();
-
- return;
- }
-
- result.Offset = 0;
- result.Count = Math.Min(_bufferLength, Decoder.ChunkLeft + 6);
- base.BeginRead(result.Buffer, result.Offset, result.Count, OnRead, readBufferState);
- }
- catch (Exception ex)
- {
- _context.Connection.SendError(ex.Message, 400);
- result.Complete(ex);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Collections/QueryStringCollection.cs b/EonaCat.Network/System/Sockets/Web/Core/Collections/QueryStringCollection.cs
deleted file mode 100644
index 692a5d1..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Collections/QueryStringCollection.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System.Collections.Specialized;
-using System.Text;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents a collection of query string parameters in the EonaCat network library.
- ///
- internal sealed class QueryStringCollection : NameValueCollection
- {
- ///
- /// Converts the collection to its string representation.
- ///
- /// A string representation of the query string parameters.
- public override string ToString()
- {
- var count = Count;
- if (count == 0)
- {
- return string.Empty;
- }
-
- var output = new StringBuilder();
- var keys = AllKeys;
- foreach (var key in keys)
- {
- output.AppendFormat($"{key}={this[key]}&");
- }
-
- if (output.Length > 0)
- {
- output.Length--;
- }
-
- return output.ToString();
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Collections/WebHeaderCollection.cs b/EonaCat.Network/System/Sockets/Web/Core/Collections/WebHeaderCollection.cs
deleted file mode 100644
index 6a872ed..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Collections/WebHeaderCollection.cs
+++ /dev/null
@@ -1,599 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Runtime.InteropServices;
-using System.Runtime.Serialization;
-using System.Security.Permissions;
-using System.Text;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents a collection of HTTP headers in the EonaCat Network library.
- ///
- [Serializable]
- [ComVisible(true)]
- public class WebHeaderCollection : NameValueCollection, ISerializable
- {
- private const int BUFFER_SIZE = 65535;
- private static readonly Dictionary _headers;
- private readonly bool _internallyUsed;
- private HttpHeaderType _state;
-
- static WebHeaderCollection()
- {
- _headers = new Dictionary(StringComparer.InvariantCultureIgnoreCase)
- {
- { "Accept", new HttpHeaderInfo("Accept", HttpHeaderType.Request | HttpHeaderType.Restricted | HttpHeaderType.MultiValue) },
- { "AcceptCharset", new HttpHeaderInfo("Accept-Charset", HttpHeaderType.Request | HttpHeaderType.MultiValue) },
- { "AcceptEncoding", new HttpHeaderInfo("Accept-Encoding", HttpHeaderType.Request | HttpHeaderType.MultiValue) },
- { "AcceptLanguage", new HttpHeaderInfo("Accept-Language", HttpHeaderType.Request | HttpHeaderType.MultiValue) },
- { "AcceptRanges", new HttpHeaderInfo("Accept-Ranges", HttpHeaderType.Response | HttpHeaderType.MultiValue) },
- { "Age", new HttpHeaderInfo("Age", HttpHeaderType.Response) },
- { "Allow", new HttpHeaderInfo("Allow", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.MultiValue) },
- { "Authorization", new HttpHeaderInfo("Authorization", HttpHeaderType.Request | HttpHeaderType.MultiValue) },
- { "CacheControl", new HttpHeaderInfo("Cache-Control", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.MultiValue) },
- { "Connection", new HttpHeaderInfo("Connection", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.Restricted | HttpHeaderType.MultiValue) },
- { "ContentEncoding", new HttpHeaderInfo("Content-Encoding", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.MultiValue) },
- { "ContentLanguage", new HttpHeaderInfo("Content-Language", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.MultiValue) },
- { "ContentLength", new HttpHeaderInfo("Content-Length", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.Restricted) },
- { "ContentLocation", new HttpHeaderInfo("Content-Location", HttpHeaderType.Request | HttpHeaderType.Response) },
- { "ContentMd5", new HttpHeaderInfo("Content-MD5", HttpHeaderType.Request | HttpHeaderType.Response) },
- { "ContentRange", new HttpHeaderInfo("Content-Range", HttpHeaderType.Request | HttpHeaderType.Response) },
- { "ContentType", new HttpHeaderInfo("Content-Type", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.Restricted) },
- { "Cookie", new HttpHeaderInfo("Cookie", HttpHeaderType.Request) },
- { "Cookie2", new HttpHeaderInfo("Cookie2", HttpHeaderType.Request) },
- { "Date", new HttpHeaderInfo("Date", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.Restricted) },
- { "Expect", new HttpHeaderInfo("Expect", HttpHeaderType.Request | HttpHeaderType.Restricted | HttpHeaderType.MultiValue) },
- { "Expires", new HttpHeaderInfo("Expires", HttpHeaderType.Request | HttpHeaderType.Response) },
- { "ETag", new HttpHeaderInfo("ETag", HttpHeaderType.Response) },
- { "From", new HttpHeaderInfo("From", HttpHeaderType.Request) },
- { "Host", new HttpHeaderInfo("Host", HttpHeaderType.Request | HttpHeaderType.Restricted) },
- { "IfMatch", new HttpHeaderInfo("If-Match", HttpHeaderType.Request | HttpHeaderType.MultiValue) },
- { "IfModifiedSince", new HttpHeaderInfo("If-Modified-Since", HttpHeaderType.Request | HttpHeaderType.Restricted) },
- { "IfNoneMatch", new HttpHeaderInfo("If-None-Match", HttpHeaderType.Request | HttpHeaderType.MultiValue) },
- { "IfRange", new HttpHeaderInfo("If-Range", HttpHeaderType.Request) },
- { "IfUnmodifiedSince", new HttpHeaderInfo("If-Unmodified-Since", HttpHeaderType.Request) },
- { "KeepAlive", new HttpHeaderInfo("Keep-Alive", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.MultiValue) },
- { "LastModified", new HttpHeaderInfo("Last-Modified", HttpHeaderType.Request | HttpHeaderType.Response) },
- { "Location", new HttpHeaderInfo("Location", HttpHeaderType.Response) },
- { "MaxForwards", new HttpHeaderInfo("Max-Forwards", HttpHeaderType.Request) },
- { "Pragma", new HttpHeaderInfo("Pragma", HttpHeaderType.Request | HttpHeaderType.Response) },
- { "ProxyAuthenticate", new HttpHeaderInfo("Proxy-Authenticate", HttpHeaderType.Response | HttpHeaderType.MultiValue) },
- { "ProxyAuthorization", new HttpHeaderInfo("Proxy-Authorization", HttpHeaderType.Request) },
- { "ProxyConnection", new HttpHeaderInfo("Proxy-Connection", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.Restricted) },
- { "Public", new HttpHeaderInfo("Public", HttpHeaderType.Response | HttpHeaderType.MultiValue) },
- { "Range", new HttpHeaderInfo("Range", HttpHeaderType.Request | HttpHeaderType.Restricted | HttpHeaderType.MultiValue) },
- { "Referer", new HttpHeaderInfo("Referer", HttpHeaderType.Request | HttpHeaderType.Restricted) },
- { "RetryAfter", new HttpHeaderInfo("Retry-After", HttpHeaderType.Response) },
- { "SecWebSocketAccept", new HttpHeaderInfo("Sec-WebSocket-Accept", HttpHeaderType.Response | HttpHeaderType.Restricted) },
- { "SecWebSocketExtensions", new HttpHeaderInfo("Sec-WebSocket-Extensions", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.Restricted | HttpHeaderType.MultiValueInRequest) },
- { "SecWebSocketKey", new HttpHeaderInfo("Sec-WebSocket-Key", HttpHeaderType.Request | HttpHeaderType.Restricted) },
- { "SecWebSocketProtocol", new HttpHeaderInfo("Sec-WebSocket-Protocol", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.MultiValueInRequest) },
- { "SecWebSocketVersion", new HttpHeaderInfo("Sec-WebSocket-Version", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.Restricted | HttpHeaderType.MultiValueInResponse) },
- { "Server", new HttpHeaderInfo("Server", HttpHeaderType.Response) },
- { "SetCookie", new HttpHeaderInfo("Set-Cookie", HttpHeaderType.Response | HttpHeaderType.MultiValue) },
- { "SetCookie2", new HttpHeaderInfo("Set-Cookie2", HttpHeaderType.Response | HttpHeaderType.MultiValue) },
- { "Te", new HttpHeaderInfo("TE", HttpHeaderType.Request) },
- { "Trailer", new HttpHeaderInfo("Trailer", HttpHeaderType.Request | HttpHeaderType.Response) },
- { "TransferEncoding", new HttpHeaderInfo("Transfer-Encoding", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.Restricted | HttpHeaderType.MultiValue) },
- { "Translate", new HttpHeaderInfo("Translate", HttpHeaderType.Request) },
- { "Upgrade", new HttpHeaderInfo("Upgrade", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.MultiValue) },
- { "UserAgent", new HttpHeaderInfo("User-Agent", HttpHeaderType.Request | HttpHeaderType.Restricted) },
- { "Vary", new HttpHeaderInfo("Vary", HttpHeaderType.Response | HttpHeaderType.MultiValue) },
- { "Via", new HttpHeaderInfo("Via", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.MultiValue) },
- { "Warning", new HttpHeaderInfo("Warning", HttpHeaderType.Request | HttpHeaderType.Response | HttpHeaderType.MultiValue) },
- { "WwwAuthenticate", new HttpHeaderInfo("WWW-Authenticate", HttpHeaderType.Response | HttpHeaderType.Restricted | HttpHeaderType.MultiValue) }
- };
- }
-
- public WebHeaderCollection()
- {
- }
-
- ///
- /// Initializes a new instance of the WebHeaderCollection class with the specified parameters.
- ///
- /// The HTTP header type.
- /// A boolean indicating whether the collection is internally used.
- internal WebHeaderCollection(HttpHeaderType state, bool internallyUsed)
- {
- _state = state;
- _internallyUsed = internallyUsed;
- }
-
- ///
- /// Initializes a new instance of the WebHeaderCollection class with serialization information.
- ///
- /// The SerializationInfo containing the data needed to serialize the WebHeaderCollection.
- /// The StreamingContext containing the source and destination of the serialized stream associated with the WebHeaderCollection.
- protected WebHeaderCollection(
- SerializationInfo serializationInfo, StreamingContext streamingContext)
- {
- if (serializationInfo == null)
- {
- throw new ArgumentNullException(nameof(serializationInfo));
- }
-
- try
- {
- _internallyUsed = serializationInfo.GetBoolean("InternallyUsed");
- _state = (HttpHeaderType)serializationInfo.GetInt32("State");
-
- var cnt = serializationInfo.GetInt32("Count");
- for (var i = 0; i < cnt; i++)
- {
- base.Add(
- serializationInfo.GetString(i.ToString()),
- serializationInfo.GetString((cnt + i).ToString()));
- }
- }
- catch (SerializationException ex)
- {
- throw new ArgumentException(ex.Message, nameof(serializationInfo), ex);
- }
- }
-
- public override string[] AllKeys => base.AllKeys;
- public override int Count => base.Count;
- public override KeysCollection Keys => base.Keys;
- internal HttpHeaderType State => _state;
-
- public string this[HttpRequestHeader header]
- {
- get
- {
- return Get(Convert(header));
- }
-
- set
- {
- Add(header, value);
- }
- }
-
- public string this[HttpResponseHeader header]
- {
- get
- {
- return Get(Convert(header));
- }
-
- set
- {
- Add(header, value);
- }
- }
-
- public static bool IsRestricted(string headerName)
- {
- return isRestricted(CheckName(headerName), false);
- }
-
- public static bool IsRestricted(string headerName, bool response)
- {
- return isRestricted(CheckName(headerName), response);
- }
-
- public void Add(string header)
- {
- if (header == null || header.Length == 0)
- {
- throw new ArgumentNullException(nameof(header));
- }
-
- var pos = checkColonSeparated(header);
- add(header.Substring(0, pos), header.Substring(pos + 1), false);
- }
-
- public void Add(HttpRequestHeader header, string value)
- {
- DoWithCheckingState(addWithoutCheckingName, Convert(header), value, false, true);
- }
-
- public void Add(HttpResponseHeader header, string value)
- {
- DoWithCheckingState(addWithoutCheckingName, Convert(header), value, true, true);
- }
-
- public override void Add(string name, string value)
- {
- add(name, value, false);
- }
-
- public override void Clear()
- {
- base.Clear();
- _state = HttpHeaderType.Unspecified;
- }
-
- public override string Get(int index)
- {
- return base.Get(index);
- }
-
- public override string Get(string name)
- {
- return base.Get(name);
- }
-
- public override IEnumerator GetEnumerator()
- {
- return base.GetEnumerator();
- }
-
- public override string GetKey(int index)
- {
- return base.GetKey(index);
- }
-
- [SecurityPermission(
- SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
- public override void GetObjectData(
- SerializationInfo serializationInfo, StreamingContext streamingContext)
- {
- if (serializationInfo == null)
- {
- throw new ArgumentNullException(nameof(serializationInfo));
- }
-
- serializationInfo.AddValue("InternallyUsed", _internallyUsed);
- serializationInfo.AddValue("State", (int)_state);
-
- var cnt = Count;
- serializationInfo.AddValue("Count", cnt);
- cnt.Times(
- i =>
- {
- serializationInfo.AddValue(i.ToString(), GetKey(i));
- serializationInfo.AddValue((cnt + i).ToString(), Get(i));
- });
- }
-
- [SecurityPermission(
- SecurityAction.LinkDemand,
- Flags = SecurityPermissionFlag.SerializationFormatter,
- SerializationFormatter = true)]
- void ISerializable.GetObjectData(
- SerializationInfo serializationInfo, StreamingContext streamingContext)
- {
- GetObjectData(serializationInfo, streamingContext);
- }
-
- public override string[] GetValues(int index)
- {
- var vals = base.GetValues(index);
- return vals != null && vals.Length > 0 ? vals : null;
- }
-
- public override string[] GetValues(string header)
- {
- var vals = base.GetValues(header);
- return vals != null && vals.Length > 0 ? vals : null;
- }
-
- public override void OnDeserialization(object sender)
- {
- }
-
- public void Remove(HttpRequestHeader header)
- {
- DoWithCheckingState(removeWithoutCheckingName, Convert(header), null, false, false);
- }
-
- public void Remove(HttpResponseHeader header)
- {
- DoWithCheckingState(removeWithoutCheckingName, Convert(header), null, true, false);
- }
-
- public override void Remove(string name)
- {
- DoWithCheckingState(removeWithoutCheckingName, CheckName(name), null, false);
- }
-
- public void Set(HttpRequestHeader header, string value)
- {
- DoWithCheckingState(setWithoutCheckingName, Convert(header), value, false, true);
- }
-
- public void Set(HttpResponseHeader header, string value)
- {
- DoWithCheckingState(setWithoutCheckingName, Convert(header), value, true, true);
- }
-
- public override void Set(string name, string value)
- {
- DoWithCheckingState(setWithoutCheckingName, CheckName(name), value, true);
- }
-
- ///
- /// Returns a byte array representing the WebHeaderCollection in UTF-8 encoding.
- ///
- /// A byte array representing the WebHeaderCollection.
- public byte[] ToByteArray()
- {
- return Encoding.UTF8.GetBytes(ToString());
- }
-
- ///
- /// Returns a string representation of the WebHeaderCollection.
- ///
- /// A string representing the WebHeaderCollection.
- public override string ToString()
- {
- var buff = new StringBuilder();
- Count.Times(i => buff.AppendFormat($"{GetKey(i)}: {Get(i)}\r\n"));
-
- return buff.Append("\r\n").ToString();
- }
-
- ///
- /// Converts the specified HttpRequestHeader to a string.
- ///
- /// The HttpRequestHeader to convert.
- /// A string representing the converted HttpRequestHeader.
- internal static string Convert(HttpRequestHeader header)
- {
- return Convert(header.ToString());
- }
-
- internal static string Convert(HttpResponseHeader header)
- {
- return Convert(header.ToString());
- }
-
- internal static bool IsHeaderName(string name)
- {
- return name != null && name.Length > 0 && name.IsToken();
- }
-
- internal static bool IsHeaderValue(string value)
- {
- return value.IsText();
- }
-
- internal static bool IsMultiValue(string headerName, bool response)
- {
- if (headerName == null || headerName.Length == 0)
- {
- return false;
- }
-
- var info = GetHeaderInfo(headerName);
- return info != null && info.IsMultiValue(response);
- }
-
- internal void InternalRemove(string name)
- {
- base.Remove(name);
- }
-
- internal void InternalSet(string header, bool response)
- {
- var pos = checkColonSeparated(header);
- InternalSet(header.Substring(0, pos), header.Substring(pos + 1), response);
- }
-
- internal void InternalSet(string name, string value, bool response)
- {
- value = CheckValue(value);
- if (IsMultiValue(name, response))
- {
- base.Add(name, value);
- }
- else
- {
- base.Set(name, value);
- }
- }
-
- internal string ToStringMultiValue(bool response)
- {
- var buff = new StringBuilder();
- Count.Times(
- i =>
- {
- var key = GetKey(i);
- if (IsMultiValue(key, response))
- {
- foreach (var val in GetValues(i))
- {
- buff.AppendFormat($"{key}: {val}\r\n");
- }
- }
- else
- {
- buff.AppendFormat($"{key}: {Get(i)}\r\n");
- }
- });
-
- return buff.Append("\r\n").ToString();
- }
-
- protected void AddWithoutValidate(string headerName, string headerValue)
- {
- add(headerName, headerValue, true);
- }
-
- private static int checkColonSeparated(string header)
- {
- var idx = header.IndexOf(':');
- if (idx == -1)
- {
- throw new ArgumentException("No colon could be found.", nameof(header));
- }
-
- return idx;
- }
-
- private static HttpHeaderType CheckHeaderType(string name)
- {
- var info = GetHeaderInfo(name);
- return info == null
- ? HttpHeaderType.Unspecified
- : info.IsRequest && !info.IsResponse
- ? HttpHeaderType.Request
- : !info.IsRequest && info.IsResponse
- ? HttpHeaderType.Response
- : HttpHeaderType.Unspecified;
- }
-
- private static string CheckName(string name)
- {
- if (name == null || name.Length == 0)
- {
- throw new ArgumentNullException(nameof(name));
- }
-
- name = name.Trim();
- if (!IsHeaderName(name))
- {
- throw new ArgumentException("Contains invalid characters.", nameof(name));
- }
-
- return name;
- }
-
- private static string CheckValue(string value)
- {
- if (value == null || value.Length == 0)
- {
- return string.Empty;
- }
-
- value = value.Trim();
- if (value.Length > BUFFER_SIZE)
- {
- throw new ArgumentOutOfRangeException(nameof(value), "Greater than 65,535 characters.");
- }
-
- if (!IsHeaderValue(value))
- {
- throw new ArgumentException("Contains invalid characters.", nameof(value));
- }
-
- return value;
- }
-
- private static string Convert(string key)
- {
- return _headers.TryGetValue(key, out HttpHeaderInfo info) ? info.Name : string.Empty;
- }
-
- private static HttpHeaderInfo GetHeaderInfo(string name)
- {
- foreach (var info in _headers.Values)
- {
- if (info.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
- {
- return info;
- }
- }
-
- return null;
- }
-
- private static bool isRestricted(string name, bool response)
- {
- var info = GetHeaderInfo(name);
- return info != null && info.IsRestricted(response);
- }
-
- private void add(string name, string value, bool ignoreRestricted)
- {
- var act = ignoreRestricted
- ? (Action)addWithoutCheckingNameAndRestricted
- : addWithoutCheckingName;
-
- DoWithCheckingState(act, CheckName(name), value, true);
- }
-
- private void addWithoutCheckingName(string name, string value)
- {
- DoWithoutCheckingName(base.Add, name, value);
- }
-
- private void addWithoutCheckingNameAndRestricted(string name, string value)
- {
- base.Add(name, CheckValue(value));
- }
-
- private void CheckRestricted(string name)
- {
- if (!_internallyUsed && isRestricted(name, true))
- {
- throw new ArgumentException("This header must be modified with the appropiate property.");
- }
- }
-
- private void CheckState(bool response)
- {
- if (_state == HttpHeaderType.Unspecified)
- {
- return;
- }
-
- if (response && _state == HttpHeaderType.Request)
- {
- throw new InvalidOperationException(
- "This collection has already been used to store the request headers.");
- }
-
- if (!response && _state == HttpHeaderType.Response)
- {
- throw new InvalidOperationException(
- "This collection has already been used to store the response headers.");
- }
- }
-
- private void DoWithCheckingState(
- Action action, string name, string value, bool setState)
- {
- var type = CheckHeaderType(name);
- if (type == HttpHeaderType.Request)
- {
- DoWithCheckingState(action, name, value, false, setState);
- }
- else if (type == HttpHeaderType.Response)
- {
- DoWithCheckingState(action, name, value, true, setState);
- }
- else
- {
- action(name, value);
- }
- }
-
- private void DoWithCheckingState(
- Action action, string name, string value, bool response, bool setState)
- {
- CheckState(response);
- action(name, value);
- if (setState && _state == HttpHeaderType.Unspecified)
- {
- _state = response ? HttpHeaderType.Response : HttpHeaderType.Request;
- }
- }
-
- private void DoWithoutCheckingName(Action action, string name, string value)
- {
- CheckRestricted(name);
- action(name, CheckValue(value));
- }
-
- private void removeWithoutCheckingName(string name, string unuse)
- {
- CheckRestricted(name);
- base.Remove(name);
- }
-
- private void setWithoutCheckingName(string name, string value)
- {
- DoWithoutCheckingName(base.Set, name, value);
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Context/HttpListenerWSContext.cs b/EonaCat.Network/System/Sockets/Web/Core/Context/HttpListenerWSContext.cs
deleted file mode 100644
index 543fcfe..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Context/HttpListenerWSContext.cs
+++ /dev/null
@@ -1,111 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.IO;
-using System.Security.Principal;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents the context of a WebSocket connection within an .
- ///
- ///
- /// 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 .
- ///
- ///
- public class HttpListenerWSContext : WSContext
- {
- private readonly HttpListenerContext _context;
- private readonly WSClient _websocket;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The associated with the WebSocket connection.
- /// The WebSocket protocol negotiated during the connection.
- internal HttpListenerWSContext(HttpListenerContext context, string protocol)
- {
- _context = context;
- _websocket = new WSClient(this, protocol);
- }
-
- public override CookieCollection CookieCollection => _context.Request.Cookies;
-
- public override NameValueCollection Headers => _context.Request.Headers;
-
- public override string Host => _context.Request.Headers["Host"];
-
- public override bool IsAuthenticated => _context.User != null;
-
- public override bool IsLocal => _context.Request.IsLocal;
-
- public override bool IsSecureConnection => _context.Connection.IsSecure;
-
- public override bool IsWebSocketRequest => _context.Request.IsWebSocketRequest;
-
- public override string Origin => _context.Request.Headers["Origin"];
-
- public override NameValueCollection QueryString => _context.Request.QueryString;
-
- public override Uri RequestUri => _context.Request.Url;
-
- public override string SecWebSocketKey => _context.Request.Headers["Sec-WebSocket-Key"];
-
- public override IEnumerable SecWebSocketProtocols
- {
- get
- {
- var protocols = _context.Request.Headers["Sec-WebSocket-Protocol"];
- if (protocols != null)
- {
- foreach (var protocol in protocols.Split(','))
- {
- yield return protocol.Trim();
- }
- }
- }
- }
-
- public override string SecWebSocketVersion => _context.Request.Headers["Sec-WebSocket-Version"];
-
- public override System.Net.IPEndPoint ServerEndPoint => _context.Connection.LocalEndPoint;
-
- public override IPrincipal User => _context.User;
-
- public override System.Net.IPEndPoint UserEndPoint => _context.Connection.RemoteEndPoint;
-
- public override WSClient WebSocket => _websocket;
-
- ///
- /// Gets the stream of the underlying TCP connection.
- ///
- internal Stream Stream => _context.Connection.Stream;
-
- ///
- public override string ToString()
- {
- return _context.Request.ToString();
- }
-
- ///
- /// Closes the WebSocket connection.
- ///
- internal void Close()
- {
- _context.Connection.Close(true);
- }
-
- ///
- /// Closes the WebSocket connection with the specified HTTP status code.
- ///
- /// The HTTP status code indicating the reason for closure.
- internal void Close(HttpStatusCode code)
- {
- _context.Response.Close(code);
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Context/TcpListenerWSContext.cs b/EonaCat.Network/System/Sockets/Web/Core/Context/TcpListenerWSContext.cs
deleted file mode 100644
index 6d53f66..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Context/TcpListenerWSContext.cs
+++ /dev/null
@@ -1,230 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.IO;
-using System.Net.Security;
-using System.Net.Sockets;
-using System.Security.Principal;
-using System.Text;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents the context of a WebSocket connection within a .
- ///
- ///
- /// This internal class provides access to various properties and methods for interacting with the WebSocket connection
- /// within the context of a TCP listener.
- ///
- internal class TcpListenerWSContext : WSContext
- {
- private readonly bool _secure;
- private readonly TcpClient _tcpClient;
- private readonly Uri _uri;
- private readonly WSClient _websocket;
- private CookieCollection _cookies;
- private NameValueCollection _queryString;
- private WebRequest _request;
- private IPrincipal _user;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The associated with the WebSocket connection.
- /// The WebSocket protocol negotiated during the connection.
- /// A boolean indicating whether the connection is secure.
- /// The SSL config for secure connections.
- internal TcpListenerWSContext(
- TcpClient tcpClient,
- string protocol,
- bool secure,
- SSLConfigServer sslConfig
- )
- {
- _tcpClient = tcpClient;
- _secure = secure;
-
- var netStream = tcpClient.GetStream();
- if (secure)
- {
- var sslStream =
- new SslStream(netStream, false, sslConfig.ClientCertificateValidationCallback);
-
- sslStream.AuthenticateAsServer(
- sslConfig.Certificate,
- sslConfig.IsClientCertificateRequired,
- sslConfig.SslProtocols,
- sslConfig.CheckForCertificateRevocation
- );
-
- Stream = sslStream;
- }
- else
- {
- Stream = netStream;
- }
-
- _request = WebRequest.Read(Stream, 90000);
- _uri =
- HttpUtility.CreateRequestUrl(
- _request.RequestUri, _request.Headers["Host"], _request.IsWebSocketRequest, secure
- );
-
- _websocket = new WSClient(this, protocol);
- }
-
- public override CookieCollection CookieCollection => _cookies ??= _request.Cookies;
-
- public override NameValueCollection Headers => _request.Headers;
-
- public override string Host => _request.Headers["Host"];
-
- public override bool IsAuthenticated => _user != null;
-
- public override bool IsLocal => UserEndPoint.Address.IsLocal();
-
- public override bool IsSecureConnection => _secure;
-
- public override bool IsWebSocketRequest => _request.IsWebSocketRequest;
-
- public override string Origin => _request.Headers["Origin"];
-
- public override NameValueCollection QueryString => _queryString ??=
- HttpUtility.InternalParseQueryString(
- _uri?.Query, Encoding.UTF8
- )
- ;
-
- public override Uri RequestUri => _uri;
-
- public override string SecWebSocketKey => _request.Headers["Sec-WebSocket-Key"];
-
- public override IEnumerable SecWebSocketProtocols
- {
- get
- {
- var protocols = _request.Headers["Sec-WebSocket-Protocol"];
- if (protocols != null)
- {
- foreach (var protocol in protocols.Split(','))
- {
- yield return protocol.Trim();
- }
- }
- }
- }
-
- public override string SecWebSocketVersion => _request.Headers["Sec-WebSocket-Version"];
-
- public override System.Net.IPEndPoint ServerEndPoint => (System.Net.IPEndPoint)_tcpClient.Client.LocalEndPoint;
-
- public override IPrincipal User => _user;
-
- public override System.Net.IPEndPoint UserEndPoint => (System.Net.IPEndPoint)_tcpClient.Client.RemoteEndPoint;
-
- public override WSClient WebSocket => _websocket;
-
- ///
- /// Gets the stream of the underlying TCP connection.
- ///
- internal Stream Stream { get; }
-
- ///
- public override string ToString()
- {
- return _request.ToString();
- }
-
- ///
- /// Authenticates the WebSocket connection based on the specified authentication scheme.
- ///
- /// The authentication scheme to use.
- /// The authentication realm.
- /// A function to find network credentials based on identity.
- /// True if authentication is successful; otherwise, false.
- internal bool Authenticate(
- AuthenticationSchemes scheme,
- string realm,
- Func credentialsFinder
- )
- {
- if (scheme == AuthenticationSchemes.Anonymous)
- {
- return true;
- }
-
- if (scheme == AuthenticationSchemes.None)
- {
- Close(HttpStatusCode.Forbidden);
- return false;
- }
-
- var chal = new AuthenticationChallenge(scheme, realm).ToString();
-
- var retry = -1;
- Func auth = null;
- auth =
- () =>
- {
- retry++;
- if (retry > 99)
- {
- Close(HttpStatusCode.Forbidden);
- return false;
- }
-
- var user =
- HttpUtility.CreateUser(
- _request.Headers["Authorization"],
- scheme,
- realm,
- _request.HttpMethod,
- credentialsFinder
- );
-
- if (user == null || !user.Identity.IsAuthenticated)
- {
- SendAuthenticationChallenge(chal);
- return auth();
- }
-
- _user = user;
- return true;
- };
-
- return auth();
- }
-
- ///
- /// Closes the WebSocket connection.
- ///
- internal void Close()
- {
- Stream.Close();
- _tcpClient.Close();
- }
-
- ///
- /// Closes the WebSocket connection with the specified HTTP status code.
- ///
- /// The HTTP status code indicating the reason for closure.
- internal void Close(HttpStatusCode code)
- {
- _websocket.Close(WebResponse.CreateCloseResponse(code));
- }
-
- ///
- /// Sends an authentication challenge to the WebSocket client.
- ///
- /// The authentication challenge.
- internal void SendAuthenticationChallenge(string challenge)
- {
- var buff = WebResponse.CreateUnauthorizedResponse(challenge).ToByteArray();
- Stream.Write(buff, 0, buff.Length);
- _request = WebRequest.Read(Stream, 15000);
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Context/WSContext.cs b/EonaCat.Network/System/Sockets/Web/Core/Context/WSContext.cs
deleted file mode 100644
index 5b84bb4..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Context/WSContext.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Security.Principal;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents the context of a WebSocket connection.
- ///
- ///
- /// This abstract class defines properties and methods for accessing information related to a WebSocket connection,
- /// such as headers, cookies, authentication status, and more.
- ///
- public abstract class WSContext
- {
- ///
- /// Initializes a new instance of the class.
- ///
- protected WSContext()
- {
- }
-
- ///
- /// Gets the collection of cookies associated with the WebSocket connection.
- ///
- public abstract CookieCollection CookieCollection { get; }
-
- ///
- /// Gets the collection of headers associated with the WebSocket connection.
- ///
- public abstract NameValueCollection Headers { get; }
-
- ///
- /// Gets the host information from the WebSocket connection.
- ///
- public abstract string Host { get; }
-
- ///
- /// Gets a value indicating whether the WebSocket connection is authenticated.
- ///
- public abstract bool IsAuthenticated { get; }
-
- ///
- /// Gets a value indicating whether the WebSocket connection is local.
- ///
- public abstract bool IsLocal { get; }
-
- ///
- /// Gets a value indicating whether the WebSocket connection is secure.
- ///
- public abstract bool IsSecureConnection { get; }
-
- ///
- /// Gets a value indicating whether the request is a WebSocket request.
- ///
- public abstract bool IsWebSocketRequest { get; }
-
- ///
- /// Gets the origin of the WebSocket connection.
- ///
- public abstract string Origin { get; }
-
- ///
- /// Gets the query string information from the WebSocket connection.
- ///
- public abstract NameValueCollection QueryString { get; }
-
- ///
- /// Gets the URI of the WebSocket request.
- ///
- public abstract Uri RequestUri { get; }
-
- ///
- /// Gets the value of the 'Sec-WebSocket-Key' header from the WebSocket connection.
- ///
- public abstract string SecWebSocketKey { get; }
-
- ///
- /// Gets the protocols specified in the 'Sec-WebSocket-Protocol' header from the WebSocket connection.
- ///
- public abstract IEnumerable SecWebSocketProtocols { get; }
-
- ///
- /// Gets the value of the 'Sec-WebSocket-Version' header from the WebSocket connection.
- ///
- public abstract string SecWebSocketVersion { get; }
-
- ///
- /// Gets the local endpoint of the WebSocket server.
- ///
- public abstract System.Net.IPEndPoint ServerEndPoint { get; }
-
- ///
- /// Gets the user associated with the WebSocket connection.
- ///
- public abstract IPrincipal User { get; }
-
- ///
- /// Gets the remote endpoint of the WebSocket user.
- ///
- public abstract System.Net.IPEndPoint UserEndPoint { get; }
-
- ///
- /// Gets the WebSocket instance associated with the context.
- ///
- public abstract WSClient WebSocket { get; }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Cookies/Cookie.cs b/EonaCat.Network/System/Sockets/Web/Core/Cookies/Cookie.cs
deleted file mode 100644
index 2419fdb..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Cookies/Cookie.cs
+++ /dev/null
@@ -1,590 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-using System.Globalization;
-using System.Text;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents an HTTP cookie.
- ///
- [Serializable]
- public sealed class Cookie
- {
- private static readonly char[] _reservedCharsForName;
- private static readonly char[] _reservedCharsForValue;
- private readonly DateTime _timestamp;
- private string _comment;
- private Uri _commentUri;
- private bool _discard;
- private string _domain;
- private DateTime _expires;
- private bool _httpOnly;
- private string _name;
- private string _path;
- private string _port;
- private int[] _ports;
- private bool _secure;
- private string _value;
- private int _version;
-
- static Cookie()
- {
- _reservedCharsForName = new[] { ' ', '=', ';', ',', '\n', '\r', '\t' };
- _reservedCharsForValue = new[] { ';', ',' };
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- public Cookie()
- {
- _comment = string.Empty;
- _domain = string.Empty;
- _expires = DateTime.MinValue;
- _name = string.Empty;
- _path = string.Empty;
- _port = string.Empty;
- _ports = new int[0];
- _timestamp = DateTime.Now;
- _value = string.Empty;
- _version = 0;
- }
-
- ///
- /// Initializes a new instance of the class with the specified name and value.
- ///
- /// The name of the cookie.
- /// The value of the cookie.
- public Cookie(string name, string value)
- : this()
- {
- Name = name;
- Value = value;
- }
-
- ///
- /// Initializes a new instance of the class with the specified name, value, and path.
- ///
- /// The name of the cookie.
- /// The value of the cookie.
- /// The path for which the cookie is valid.
- public Cookie(string name, string value, string path)
- : this(name, value)
- {
- Path = path;
- }
-
- ///
- /// Initializes a new instance of the class with the specified name, value, path, and domain.
- ///
- /// The name of the cookie.
- /// The value of the cookie.
- /// The path for which the cookie is valid.
- /// The domain to which the cookie belongs.
- public Cookie(string name, string value, string path, string domain)
- : this(name, value, path)
- {
- Domain = domain;
- }
-
- public string Comment
- {
- get
- {
- return _comment;
- }
-
- set
- {
- _comment = value ?? string.Empty;
- }
- }
-
- public Uri CommentUri
- {
- get
- {
- return _commentUri;
- }
-
- set
- {
- _commentUri = value;
- }
- }
-
- public bool Discard
- {
- get
- {
- return _discard;
- }
-
- set
- {
- _discard = value;
- }
- }
-
- public string Domain
- {
- get
- {
- return _domain;
- }
-
- set
- {
- if (value.IsNullOrEmpty())
- {
- _domain = string.Empty;
- ExactDomain = true;
- }
- else
- {
- _domain = value;
- ExactDomain = value[0] != '.';
- }
- }
- }
-
- public bool Expired
- {
- get
- {
- return _expires != DateTime.MinValue && _expires <= DateTime.Now;
- }
-
- set
- {
- _expires = value ? DateTime.Now : DateTime.MinValue;
- }
- }
-
- public DateTime Expires
- {
- get
- {
- return _expires;
- }
-
- set
- {
- _expires = value;
- }
- }
-
- public bool HttpOnly
- {
- get
- {
- return _httpOnly;
- }
-
- set
- {
- _httpOnly = value;
- }
- }
-
- public string Name
- {
- get
- {
- return _name;
- }
-
- set
- {
- if (!canSetName(value, out string message))
- {
- throw new CookieException(message);
- }
-
- _name = value;
- }
- }
-
- public string Path
- {
- get
- {
- return _path;
- }
-
- set
- {
- _path = value ?? string.Empty;
- }
- }
-
- public string Port
- {
- get
- {
- return _port;
- }
-
- set
- {
- if (value.IsNullOrEmpty())
- {
- _port = string.Empty;
- _ports = new int[0];
-
- return;
- }
-
- if (!value.IsEnclosedIn('"'))
- {
- throw new CookieException(
- "The value specified for the Port attribute isn't enclosed in double quotes.");
- }
-
- if (!tryCreatePorts(value, out _ports, out string err))
- {
- throw new CookieException(
- string.Format(
- "The value specified for the Port attribute contains an invalid value: {0}", err));
- }
-
- _port = value;
- }
- }
-
- public bool Secure
- {
- get
- {
- return _secure;
- }
-
- set
- {
- _secure = value;
- }
- }
-
- public DateTime TimeStamp => _timestamp;
-
- public string Value
- {
- get
- {
- return _value;
- }
-
- set
- {
- if (!canSetValue(value, out string message))
- {
- throw new CookieException(message);
- }
-
- _value = value.Length > 0 ? value : "\"\"";
- }
- }
-
- public int Version
- {
- get
- {
- return _version;
- }
-
- set
- {
- if (value < 0 || value > 1)
- {
- throw new ArgumentOutOfRangeException(nameof(value), "Not 0 or 1.");
- }
-
- _version = value;
- }
- }
-
- internal bool ExactDomain
- {
- get; set;
- }
-
- internal int MaxAge
- {
- get
- {
- if (_expires == DateTime.MinValue)
- {
- return 0;
- }
-
- var expires = _expires.Kind != DateTimeKind.Local
- ? _expires.ToLocalTime()
- : _expires;
-
- var span = expires - DateTime.Now;
- return span > TimeSpan.Zero
- ? (int)span.TotalSeconds
- : 0;
- }
- }
-
- internal int[] Ports => _ports;
-
- ///
- public override bool Equals(object comparand)
- {
- return comparand is Cookie cookie &&
- _name.Equals(cookie.Name, StringComparison.InvariantCultureIgnoreCase) &&
- _value.Equals(cookie.Value, StringComparison.InvariantCulture) &&
- _path.Equals(cookie.Path, StringComparison.InvariantCulture) &&
- _domain.Equals(cookie.Domain, StringComparison.InvariantCultureIgnoreCase) &&
- _version == cookie.Version;
- }
-
- ///
- public override int GetHashCode()
- {
- return hash(
- StringComparer.InvariantCultureIgnoreCase.GetHashCode(_name),
- _value.GetHashCode(),
- _path.GetHashCode(),
- StringComparer.InvariantCultureIgnoreCase.GetHashCode(_domain),
- _version);
- }
-
- ///
- public override string ToString()
- {
- return ToRequestString(null);
- }
-
- // From client to server
- internal string ToRequestString(Uri uri)
- {
- if (_name.Length == 0)
- {
- return string.Empty;
- }
-
- if (_version == 0)
- {
- return string.Format("{0}={1}", _name, _value);
- }
-
- var output = new StringBuilder(64);
- output.AppendFormat("$Version={0}; {1}={2}", _version, _name, _value);
-
- if (!_path.IsNullOrEmpty())
- {
- output.AppendFormat("; $Path={0}", _path);
- }
- else if (uri != null)
- {
- output.AppendFormat("; $Path={0}", uri.GetAbsolutePath());
- }
- else
- {
- output.Append("; $Path=/");
- }
-
- var appendDomain = uri == null || uri.Host != _domain;
- if (appendDomain && !_domain.IsNullOrEmpty())
- {
- output.AppendFormat("; $Domain={0}", _domain);
- }
-
- if (!_port.IsNullOrEmpty())
- {
- if (_port == "\"\"")
- {
- output.Append("; $Port");
- }
- else
- {
- output.AppendFormat("; $Port={0}", _port);
- }
- }
-
- return output.ToString();
- }
-
- // From server to client
- internal string ToResponseString()
- {
- return _name.Length > 0
- ? (_version == 0 ? ToResponseStringVersion0() : ToResponseStringVersion1())
- : string.Empty;
- }
-
- private static bool canSetName(string name, out string message)
- {
- if (name.IsNullOrEmpty())
- {
- message = "The value specified for the Name is null or empty.";
- return false;
- }
-
- if (name[0] == '$' || name.Contains(_reservedCharsForName))
- {
- message = "The value specified for the Name contains an invalid character.";
- return false;
- }
-
- message = string.Empty;
- return true;
- }
-
- private static bool canSetValue(string value, out string message)
- {
- if (value == null)
- {
- message = "The value specified for the Value is null.";
- return false;
- }
-
- if (value.Contains(_reservedCharsForValue) && !value.IsEnclosedIn('"'))
- {
- message = "The value specified for the Value contains an invalid character.";
- return false;
- }
-
- message = string.Empty;
- return true;
- }
-
- private static int hash(int i, int j, int k, int l, int m)
- {
- return i ^
- (j << 13 | j >> 19) ^
- (k << 26 | k >> 6) ^
- (l << 7 | l >> 25) ^
- (m << 20 | m >> 12);
- }
-
- private static bool tryCreatePorts(string value, out int[] result, out string parseError)
- {
- var ports = value.Trim('"').Split(',');
- var len = ports.Length;
- var res = new int[len];
- for (var i = 0; i < len; i++)
- {
- res[i] = int.MinValue;
-
- var port = ports[i].Trim();
- if (port.Length == 0)
- {
- continue;
- }
-
- if (!int.TryParse(port, out res[i]))
- {
- result = new int[0];
- parseError = port;
-
- return false;
- }
- }
-
- result = res;
- parseError = string.Empty;
-
- return true;
- }
-
- private string ToResponseStringVersion0()
- {
- var output = new StringBuilder(64);
- output.AppendFormat("{0}={1}", _name, _value);
-
- if (_expires != DateTime.MinValue)
- {
- output.AppendFormat(
- "; Expires={0}",
- _expires.ToUniversalTime().ToString(
- "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'",
- CultureInfo.CreateSpecificCulture("en-US")));
- }
-
- if (!_path.IsNullOrEmpty())
- {
- output.AppendFormat("; Path={0}", _path);
- }
-
- if (!_domain.IsNullOrEmpty())
- {
- output.AppendFormat("; Domain={0}", _domain);
- }
-
- if (_secure)
- {
- output.Append("; Secure");
- }
-
- if (_httpOnly)
- {
- output.Append("; HttpOnly");
- }
-
- return output.ToString();
- }
-
- private string ToResponseStringVersion1()
- {
- var output = new StringBuilder(64);
- output.AppendFormat("{0}={1}; Version={2}", _name, _value, _version);
-
- if (_expires != DateTime.MinValue)
- {
- output.AppendFormat("; Max-Age={0}", MaxAge);
- }
-
- if (!_path.IsNullOrEmpty())
- {
- output.AppendFormat("; Path={0}", _path);
- }
-
- if (!_domain.IsNullOrEmpty())
- {
- output.AppendFormat("; Domain={0}", _domain);
- }
-
- if (!_port.IsNullOrEmpty())
- {
- if (_port == "\"\"")
- {
- output.Append("; Port");
- }
- else
- {
- output.AppendFormat("; Port={0}", _port);
- }
- }
-
- if (!_comment.IsNullOrEmpty())
- {
- output.AppendFormat("; Comment={0}", _comment.UrlEncode());
- }
-
- if (_commentUri != null)
- {
- var url = _commentUri.OriginalString;
- output.AppendFormat("; CommentURL={0}", url.IsToken() ? url : url.Quote());
- }
-
- if (_discard)
- {
- output.Append("; Discard");
- }
-
- if (_secure)
- {
- output.Append("; Secure");
- }
-
- return output.ToString();
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Cookies/CookieCollection.cs b/EonaCat.Network/System/Sockets/Web/Core/Cookies/CookieCollection.cs
deleted file mode 100644
index 14b0ee8..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Cookies/CookieCollection.cs
+++ /dev/null
@@ -1,545 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Text;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents a collection of HTTP cookies.
- ///
- [Serializable]
- public class CookieCollection : ICollection, IEnumerable
- {
- private readonly List _list;
- private object _locker;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public CookieCollection()
- {
- _list = new List();
- }
-
- ///
- /// Gets the number of cookies in the collection.
- ///
- public int Count => _list.Count;
-
- ///
- /// Gets a value indicating whether the collection is read-only. Always returns true.
- ///
- public bool IsReadOnly => true;
-
- ///
- /// Gets a value indicating whether access to the collection is synchronized (thread-safe). Always returns false.
- ///
- public bool IsSynchronized => false;
-
- ///
- /// Gets an object that can be used to synchronize access to the collection.
- ///
- public object SyncRoot => _locker ??= ((ICollection)_list).SyncRoot;
-
- internal IList List => _list;
-
- internal IEnumerable Sorted
- {
- get
- {
- var list = new List(_list);
- if (list.Count > 1)
- {
- list.Sort(compareCookieWithinSorted);
- }
-
- return list;
- }
- }
-
- ///
- /// Gets or sets the cookie at the specified index.
- ///
- /// The index of the cookie to get or set.
- /// The cookie at the specified index.
- public Cookie this[int index]
- {
- get
- {
- if (index < 0 || index >= _list.Count)
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
-
- return _list[index];
- }
- }
-
- ///
- /// Gets the cookie with the specified name.
- ///
- /// The name of the cookie to retrieve.
- /// The cookie with the specified name, or null if the cookie is not found.
- public Cookie this[string name]
- {
- get
- {
- if (name == null)
- {
- throw new ArgumentNullException(nameof(name));
- }
-
- foreach (var cookie in Sorted)
- {
- if (cookie.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
- {
- return cookie;
- }
- }
-
- return null;
- }
- }
-
- ///
- /// Adds the specified cookie to the collection, updating it if it already exists.
- ///
- /// The cookie to add or update.
- public void Add(Cookie cookie)
- {
- if (cookie == null)
- {
- throw new ArgumentNullException(nameof(cookie));
- }
-
- var pos = searchCookie(cookie);
- if (pos == -1)
- {
- _list.Add(cookie);
- return;
- }
-
- _list[pos] = cookie;
- }
-
- ///
- /// Adds the cookies from the specified to this collection, updating existing cookies.
- ///
- /// The to add or update from.
- public void Add(CookieCollection cookies)
- {
- if (cookies == null)
- {
- throw new ArgumentNullException(nameof(cookies));
- }
-
- foreach (Cookie cookie in cookies)
- {
- Add(cookie);
- }
- }
-
- ///
- /// Copies the cookies in the collection to the specified array, starting at the specified index.
- ///
- /// The destination array.
- /// The index in the destination array at which copying begins.
- public void CopyTo(Array array, int index)
- {
- if (array == null)
- {
- throw new ArgumentNullException(nameof(array));
- }
-
- if (index < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(index), "Less than zero.");
- }
-
- if (array.Rank > 1)
- {
- throw new ArgumentException("Multidimensional.", nameof(array));
- }
-
- if (array.Length - index < _list.Count)
- {
- throw new ArgumentException(
- "The number of elements in this collection is greater than the available space of the destination array.");
- }
-
- if (!array.GetType().GetElementType().IsAssignableFrom(typeof(Cookie)))
- {
- throw new InvalidCastException(
- "The elements in this collection cannot be cast automatically to the type of the destination array.");
- } ((IList)_list).CopyTo(array, index);
- }
-
- ///
- /// Copies the cookies in the collection to the specified array, starting at the specified index.
- ///
- /// The destination array.
- /// The index in the destination array at which copying begins.
- public void CopyTo(Cookie[] array, int index)
- {
- if (array == null)
- {
- throw new ArgumentNullException(nameof(array));
- }
-
- if (index < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(index), "Less than zero.");
- }
-
- if (array.Length - index < _list.Count)
- {
- throw new ArgumentException(
- "The number of elements in this collection is greater than the available space of the destination array.");
- }
-
- _list.CopyTo(array, index);
- }
-
- ///
- /// Returns an enumerator that iterates through the collection.
- ///
- /// An enumerator for the collection.
- public IEnumerator GetEnumerator()
- {
- return _list.GetEnumerator();
- }
-
- ///
- /// Parses the specified cookie string, creating a .
- ///
- /// The cookie string to parse.
- /// True if parsing a response header; otherwise, false.
- /// A instance representing the parsed cookies.
- internal static CookieCollection Parse(string value, bool response)
- {
- return response
- ? parseResponse(value)
- : parseRequest(value);
- }
-
- internal void SetOrRemove(Cookie cookie)
- {
- var pos = searchCookie(cookie);
- if (pos == -1)
- {
- if (!cookie.Expired)
- {
- _list.Add(cookie);
- }
-
- return;
- }
-
- if (!cookie.Expired)
- {
- _list[pos] = cookie;
- return;
- }
-
- _list.RemoveAt(pos);
- }
-
- internal void SetOrRemove(CookieCollection cookies)
- {
- foreach (Cookie cookie in cookies)
- {
- SetOrRemove(cookie);
- }
- }
-
- internal void Sort()
- {
- if (_list.Count > 1)
- {
- _list.Sort(compareCookieWithinSort);
- }
- }
-
- private static int compareCookieWithinSort(Cookie x, Cookie y)
- {
- return (x.Name.Length + x.Value.Length) - (y.Name.Length + y.Value.Length);
- }
-
- private static int compareCookieWithinSorted(Cookie x, Cookie y)
- {
- var ret = 0;
- return (ret = x.Version - y.Version) != 0
- ? ret
- : (ret = x.Name.CompareTo(y.Name)) != 0
- ? ret
- : y.Path.Length - x.Path.Length;
- }
-
- private static CookieCollection parseRequest(string value)
- {
- var cookies = new CookieCollection();
-
- Cookie cookie = null;
- var ver = 0;
- var pairs = splitCookieHeaderValue(value);
- for (var i = 0; i < pairs.Length; i++)
- {
- var pair = pairs[i].Trim();
- if (pair.Length == 0)
- {
- continue;
- }
-
- if (pair.StartsWith("$version", StringComparison.InvariantCultureIgnoreCase))
- {
- ver = int.Parse(pair.GetValue('=', true));
- }
- else if (pair.StartsWith("$path", StringComparison.InvariantCultureIgnoreCase))
- {
- if (cookie != null)
- {
- cookie.Path = pair.GetValue('=');
- }
- }
- else if (pair.StartsWith("$domain", StringComparison.InvariantCultureIgnoreCase))
- {
- if (cookie != null)
- {
- cookie.Domain = pair.GetValue('=');
- }
- }
- else if (pair.StartsWith("$port", StringComparison.InvariantCultureIgnoreCase))
- {
- var port = pair.Equals("$port", StringComparison.InvariantCultureIgnoreCase)
- ? "\"\""
- : pair.GetValue('=');
-
- if (cookie != null)
- {
- cookie.Port = port;
- }
- }
- else
- {
- if (cookie != null)
- {
- cookies.Add(cookie);
- }
-
- string name;
- string val = string.Empty;
-
- var pos = pair.IndexOf('=');
- if (pos == -1)
- {
- name = pair;
- }
- else if (pos == pair.Length - 1)
- {
- name = pair.Substring(0, pos).TrimEnd(' ');
- }
- else
- {
- name = pair.Substring(0, pos).TrimEnd(' ');
- val = pair.Substring(pos + 1).TrimStart(' ');
- }
-
- cookie = new Cookie(name, val);
- if (ver != 0)
- {
- cookie.Version = ver;
- }
- }
- }
-
- if (cookie != null)
- {
- cookies.Add(cookie);
- }
-
- return cookies;
- }
-
- private static CookieCollection parseResponse(string value)
- {
- var cookies = new CookieCollection();
-
- Cookie cookie = null;
- var pairs = splitCookieHeaderValue(value);
- for (var i = 0; i < pairs.Length; i++)
- {
- var pair = pairs[i].Trim();
- if (pair.Length == 0)
- {
- continue;
- }
-
- if (pair.StartsWith("version", StringComparison.InvariantCultureIgnoreCase))
- {
- if (cookie != null)
- {
- cookie.Version = int.Parse(pair.GetValue('=', true));
- }
- }
- else if (pair.StartsWith("expires", StringComparison.InvariantCultureIgnoreCase))
- {
- var buff = new StringBuilder(pair.GetValue('='), 32);
- if (i < pairs.Length - 1)
- {
- buff.AppendFormat(", {0}", pairs[++i].Trim());
- }
-
- if (!DateTime.TryParseExact(
- buff.ToString(),
- new[] { "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'", "r" },
- CultureInfo.CreateSpecificCulture("en-US"),
- DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal,
- out DateTime expires))
- {
- expires = DateTime.Now;
- }
-
- if (cookie != null && cookie.Expires == DateTime.MinValue)
- {
- cookie.Expires = expires.ToLocalTime();
- }
- }
- else if (pair.StartsWith("max-age", StringComparison.InvariantCultureIgnoreCase))
- {
- var max = int.Parse(pair.GetValue('=', true));
- var expires = DateTime.Now.AddSeconds(max);
- if (cookie != null)
- {
- cookie.Expires = expires;
- }
- }
- else if (pair.StartsWith("path", StringComparison.InvariantCultureIgnoreCase))
- {
- if (cookie != null)
- {
- cookie.Path = pair.GetValue('=');
- }
- }
- else if (pair.StartsWith("domain", StringComparison.InvariantCultureIgnoreCase))
- {
- if (cookie != null)
- {
- cookie.Domain = pair.GetValue('=');
- }
- }
- else if (pair.StartsWith("port", StringComparison.InvariantCultureIgnoreCase))
- {
- var port = pair.Equals("port", StringComparison.InvariantCultureIgnoreCase)
- ? "\"\""
- : pair.GetValue('=');
-
- if (cookie != null)
- {
- cookie.Port = port;
- }
- }
- else if (pair.StartsWith("comment", StringComparison.InvariantCultureIgnoreCase))
- {
- if (cookie != null)
- {
- cookie.Comment = pair.GetValue('=').UrlDecode();
- }
- }
- else if (pair.StartsWith("commenturl", StringComparison.InvariantCultureIgnoreCase))
- {
- if (cookie != null)
- {
- cookie.CommentUri = pair.GetValue('=', true).ToUri();
- }
- }
- else if (pair.StartsWith("discard", StringComparison.InvariantCultureIgnoreCase))
- {
- if (cookie != null)
- {
- cookie.Discard = true;
- }
- }
- else if (pair.StartsWith("secure", StringComparison.InvariantCultureIgnoreCase))
- {
- if (cookie != null)
- {
- cookie.Secure = true;
- }
- }
- else if (pair.StartsWith("httponly", StringComparison.InvariantCultureIgnoreCase))
- {
- if (cookie != null)
- {
- cookie.HttpOnly = true;
- }
- }
- else
- {
- if (cookie != null)
- {
- cookies.Add(cookie);
- }
-
- string name;
- string val = string.Empty;
-
- var pos = pair.IndexOf('=');
- if (pos == -1)
- {
- name = pair;
- }
- else if (pos == pair.Length - 1)
- {
- name = pair.Substring(0, pos).TrimEnd(' ');
- }
- else
- {
- name = pair.Substring(0, pos).TrimEnd(' ');
- val = pair.Substring(pos + 1).TrimStart(' ');
- }
-
- cookie = new Cookie(name, val);
- }
- }
-
- if (cookie != null)
- {
- cookies.Add(cookie);
- }
-
- return cookies;
- }
-
- private static string[] splitCookieHeaderValue(string value)
- {
- return new List(value.SplitHeaderValue(',', ';')).ToArray();
- }
-
- private int searchCookie(Cookie cookie)
- {
- var name = cookie.Name;
- var path = cookie.Path;
- var domain = cookie.Domain;
- var ver = cookie.Version;
-
- for (var i = _list.Count - 1; i >= 0; i--)
- {
- var c = _list[i];
- if (c.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase) &&
- c.Path.Equals(path, StringComparison.InvariantCulture) &&
- c.Domain.Equals(domain, StringComparison.InvariantCultureIgnoreCase) &&
- c.Version == ver)
- {
- return i;
- }
- }
-
- return -1;
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Cookies/CookieException.cs b/EonaCat.Network/System/Sockets/Web/Core/Cookies/CookieException.cs
deleted file mode 100644
index ccd19b1..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Cookies/CookieException.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-using System.Runtime.Serialization;
-using System.Security.Permissions;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents an exception specific to EonaCat Network cookies.
- ///
- [Serializable]
- public class CookieException : FormatException, ISerializable
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public CookieException()
- : base()
- {
- }
-
- ///
- /// Initializes a new instance of the class with a specified error message.
- ///
- /// The error message that explains the reason for the exception.
- internal CookieException(string message)
- : base($"EonaCat Network: {message}")
- {
- }
-
- ///
- /// Initializes a new instance of the class with a specified error message
- /// and a reference to the inner exception that is the cause of this exception.
- ///
- /// The error message that explains the reason for the exception.
- /// The exception that is the cause of the current exception.
- internal CookieException(string message, Exception innerException)
- : base($"EonaCat Network: {message}", innerException)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- protected CookieException(
- SerializationInfo serializationInfo, StreamingContext streamingContext)
- : base(serializationInfo, streamingContext)
- {
- }
-
- ///
- /// Populates a with the data needed to serialize the exception.
- ///
- /// The to populate with data.
- /// The destination (see ) for this serialization.
- [SecurityPermission(
- SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
- public override void GetObjectData(
- SerializationInfo serializationInfo, StreamingContext streamingContext)
- {
- base.GetObjectData(serializationInfo, streamingContext);
- }
-
- ///
- /// Populates a with the data needed to serialize the exception.
- ///
- /// The to populate with data.
- /// The destination (see ) for this serialization.
- [SecurityPermission(
- SecurityAction.LinkDemand,
- Flags = SecurityPermissionFlag.SerializationFormatter,
- SerializationFormatter = true)]
- void ISerializable.GetObjectData(
- SerializationInfo serializationInfo, StreamingContext streamingContext)
- {
- base.GetObjectData(serializationInfo, streamingContext);
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Endpoints/EndPointListener.cs b/EonaCat.Network/System/Sockets/Web/Core/Endpoints/EndPointListener.cs
deleted file mode 100644
index d624e99..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Endpoints/EndPointListener.cs
+++ /dev/null
@@ -1,532 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using System.Net.Sockets;
-using System.Security.Cryptography;
-using System.Security.Cryptography.X509Certificates;
-using System.Threading;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents an endpoint listener for managing HTTP connections.
- ///
- internal sealed class EndPointListener
- {
- private static readonly string _defaultCertFolderPath;
- private readonly IPEndPoint _endpoint;
- private readonly Socket _socket;
- private readonly Dictionary _unregistered;
- private readonly object _unregisteredSync;
- private List _all; // host == '+'
- private Dictionary _prefixes;
- private List _unhandled; // host == '*'
-
- static EndPointListener()
- {
- _defaultCertFolderPath =
- Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
- }
-
- internal EndPointListener(
- IPEndPoint endpoint,
- bool secure,
- string certificateFolderPath,
- SSLConfigServer sslConfig,
- bool reuseAddress
- )
- {
- if (secure)
- {
- var cert =
- getCertificate(endpoint.Port, certificateFolderPath, sslConfig.Certificate);
-
- if (cert == null)
- {
- throw new ArgumentException("No server certificate could be found.");
- }
-
- IsSecure = true;
- SSL = new SSLConfigServer(sslConfig);
- SSL.Certificate = cert;
- }
-
- _endpoint = endpoint;
- _prefixes = new Dictionary();
- _unregistered = new Dictionary();
- _unregisteredSync = ((ICollection)_unregistered).SyncRoot;
- _socket =
- new Socket(endpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
-
- if (reuseAddress)
- {
- _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
- }
-
- _socket.Bind(endpoint);
- _socket.Listen(500);
- _socket.BeginAccept(onAccept, this);
- }
-
- ///
- /// Gets the IP address of the endpoint.
- ///
- public IPAddress Address => _endpoint.Address;
-
- ///
- /// Gets a value indicating whether the endpoint is secure.
- ///
- public bool IsSecure { get; }
-
- ///
- /// Gets the port number of the endpoint.
- ///
- public int Port => _endpoint.Port;
-
- ///
- /// Gets the SSL config for the secure endpoint.
- ///
- public SSLConfigServer SSL { get; }
-
- public void AddPrefix(HttpListenerPrefix prefix, HttpListener listener)
- {
- List current, future;
- if (prefix.Host == "*")
- {
- do
- {
- current = _unhandled;
- future = current != null
- ? new List(current)
- : new List();
-
- prefix.Listener = listener;
- addSpecial(future, prefix);
- }
- while (Interlocked.CompareExchange(ref _unhandled, future, current) != current);
-
- return;
- }
-
- if (prefix.Host == "+")
- {
- do
- {
- current = _all;
- future = current != null
- ? new List(current)
- : new List();
-
- prefix.Listener = listener;
- addSpecial(future, prefix);
- }
- while (Interlocked.CompareExchange(ref _all, future, current) != current);
-
- return;
- }
-
- Dictionary prefs, prefs2;
- do
- {
- prefs = _prefixes;
- if (prefs.ContainsKey(prefix))
- {
- if (prefs[prefix] != listener)
- {
- throw new HttpListenerException(
- 87, string.Format("There's another listener for {0}.", prefix)
- );
- }
-
- return;
- }
-
- prefs2 = new Dictionary(prefs)
- {
- [prefix] = listener
- };
- }
- while (Interlocked.CompareExchange(ref _prefixes, prefs2, prefs) != prefs);
- }
-
- public void Close()
- {
- _socket.Close();
-
- HttpConnection[] conns = null;
- lock (_unregisteredSync)
- {
- if (_unregistered.Count == 0)
- {
- return;
- }
-
- var keys = _unregistered.Keys;
- conns = new HttpConnection[keys.Count];
- keys.CopyTo(conns, 0);
- _unregistered.Clear();
- }
-
- for (var i = conns.Length - 1; i >= 0; i--)
- {
- conns[i].Close(true);
- }
- }
-
- public void RemovePrefix(HttpListenerPrefix prefix, HttpListener listener)
- {
- List current, future;
- if (prefix.Host == "*")
- {
- do
- {
- current = _unhandled;
- if (current == null)
- {
- break;
- }
-
- future = new List(current);
- if (!removeSpecial(future, prefix))
- {
- break; // The prefix wasn't found.
- }
- }
- while (Interlocked.CompareExchange(ref _unhandled, future, current) != current);
-
- leaveIfNoPrefix();
- return;
- }
-
- if (prefix.Host == "+")
- {
- do
- {
- current = _all;
- if (current == null)
- {
- break;
- }
-
- future = new List(current);
- if (!removeSpecial(future, prefix))
- {
- break; // The prefix wasn't found.
- }
- }
- while (Interlocked.CompareExchange(ref _all, future, current) != current);
-
- leaveIfNoPrefix();
- return;
- }
-
- Dictionary prefs, prefs2;
- do
- {
- prefs = _prefixes;
- if (!prefs.ContainsKey(prefix))
- {
- break;
- }
-
- prefs2 = new Dictionary(prefs);
- prefs2.Remove(prefix);
- }
- while (Interlocked.CompareExchange(ref _prefixes, prefs2, prefs) != prefs);
-
- leaveIfNoPrefix();
- }
-
- internal static bool CertificateExists(int port, string folderPath)
- {
- if (folderPath == null || folderPath.Length == 0)
- {
- folderPath = _defaultCertFolderPath;
- }
-
- var cer = Path.Combine(folderPath, string.Format("{0}.cer", port));
- var key = Path.Combine(folderPath, string.Format("{0}.key", port));
-
- return File.Exists(cer) && File.Exists(key);
- }
-
- internal void RemoveConnection(HttpConnection connection)
- {
- lock (_unregisteredSync)
- {
- _unregistered.Remove(connection);
- }
- }
-
- internal bool TrySearchHttpListener(Uri uri, out HttpListener listener)
- {
- listener = null;
-
- if (uri == null)
- {
- return false;
- }
-
- var host = uri.Host;
- var dns = Uri.CheckHostName(host) == UriHostNameType.Dns;
- var port = uri.Port.ToString();
- var path = HttpUtility.UrlDecode(uri.AbsolutePath);
- var pathSlash = path[path.Length - 1] != '/' ? path + "/" : path;
-
- if (host != null && host.Length > 0)
- {
- var bestLen = -1;
- foreach (var pref in _prefixes.Keys)
- {
- if (dns)
- {
- var prefHost = pref.Host;
- if (Uri.CheckHostName(prefHost) == UriHostNameType.Dns && prefHost != host)
- {
- continue;
- }
- }
-
- if (pref.Port != port && !_prefixes[pref].AllowForwardedRequest)
- {
- continue;
- }
-
- var prefPath = pref.Path;
-
- var len = prefPath.Length;
- if (len < bestLen)
- {
- continue;
- }
-
- if (path.StartsWith(prefPath) || pathSlash.StartsWith(prefPath))
- {
- bestLen = len;
- listener = _prefixes[pref];
- }
- }
-
- if (bestLen != -1)
- {
- return true;
- }
- }
-
- var prefs = _unhandled;
- listener = searchHttpListenerFromSpecial(path, prefs);
- if (listener == null && pathSlash != path)
- {
- listener = searchHttpListenerFromSpecial(pathSlash, prefs);
- }
-
- if (listener != null)
- {
- return true;
- }
-
- prefs = _all;
- listener = searchHttpListenerFromSpecial(path, prefs);
- if (listener == null && pathSlash != path)
- {
- listener = searchHttpListenerFromSpecial(pathSlash, prefs);
- }
-
- return listener != null;
- }
-
- private static void addSpecial(List prefixes, HttpListenerPrefix prefix)
- {
- var path = prefix.Path;
- foreach (var pref in prefixes)
- {
- if (pref.Path == path)
- {
- throw new HttpListenerException(87, "The prefix is already in use.");
- }
- }
-
- prefixes.Add(prefix);
- }
-
- private static RSACryptoServiceProvider createRSAFromFile(string filename)
- {
- byte[] pvk = null;
- using (var fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
- {
- pvk = new byte[fs.Length];
- fs.Read(pvk, 0, pvk.Length);
- }
-
- var rsa = new RSACryptoServiceProvider();
- rsa.ImportCspBlob(pvk);
-
- return rsa;
- }
-
- private static X509Certificate2 getCertificate(
- int port, string folderPath, X509Certificate2 defaultCertificate
- )
- {
- if (folderPath == null || folderPath.Length == 0)
- {
- folderPath = _defaultCertFolderPath;
- }
-
- try
- {
- var cer = Path.Combine(folderPath, string.Format("{0}.cer", port));
- var key = Path.Combine(folderPath, string.Format("{0}.key", port));
- if (File.Exists(cer) && File.Exists(key))
- {
- var cert = new X509Certificate2(cer);
- cert.PrivateKey = createRSAFromFile(key);
-
- return cert;
- }
- }
- catch
- {
- }
-
- return defaultCertificate;
- }
-
- private static void onAccept(IAsyncResult asyncResult)
- {
- var lsnr = (EndPointListener)asyncResult.AsyncState;
-
- Socket sock = null;
- try
- {
- sock = lsnr._socket.EndAccept(asyncResult);
- }
- catch (SocketException)
- {
- // Do nothing
- }
- catch (ObjectDisposedException)
- {
- return;
- }
-
- try
- {
- lsnr._socket.BeginAccept(onAccept, lsnr);
- }
- catch
- {
- sock?.Close();
-
- return;
- }
-
- if (sock == null)
- {
- return;
- }
-
- processAccepted(sock, lsnr);
- }
-
- private static void processAccepted(Socket socket, EndPointListener listener)
- {
- HttpConnection conn = null;
- try
- {
- conn = new HttpConnection(socket, listener);
- lock (listener._unregisteredSync)
- {
- listener._unregistered[conn] = conn;
- }
-
- conn.BeginReadRequest();
- }
- catch
- {
- if (conn != null)
- {
- conn.Close(true);
- return;
- }
-
- socket.Close();
- }
- }
-
- private static bool removeSpecial(List prefixes, HttpListenerPrefix prefix)
- {
- var path = prefix.Path;
- var cnt = prefixes.Count;
- for (var i = 0; i < cnt; i++)
- {
- if (prefixes[i].Path == path)
- {
- prefixes.RemoveAt(i);
- return true;
- }
- }
-
- return false;
- }
-
- private static HttpListener searchHttpListenerFromSpecial(
- string path, List prefixes
- )
- {
- if (prefixes == null)
- {
- return null;
- }
-
- HttpListener bestMatch = null;
-
- var bestLen = -1;
- foreach (var pref in prefixes)
- {
- var prefPath = pref.Path;
-
- var len = prefPath.Length;
- if (len < bestLen)
- {
- continue;
- }
-
- if (path.StartsWith(prefPath))
- {
- bestLen = len;
- bestMatch = pref.Listener;
- }
- }
-
- return bestMatch;
- }
-
- private void leaveIfNoPrefix()
- {
- if (_prefixes.Count > 0)
- {
- return;
- }
-
- var prefs = _unhandled;
- if (prefs != null && prefs.Count > 0)
- {
- return;
- }
-
- prefs = _all;
- if (prefs != null && prefs.Count > 0)
- {
- return;
- }
-
- EndPointManager.RemoveEndPoint(_endpoint);
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Endpoints/EndPointManager.cs b/EonaCat.Network/System/Sockets/Web/Core/Endpoints/EndPointManager.cs
deleted file mode 100644
index f2aa2a2..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Endpoints/EndPointManager.cs
+++ /dev/null
@@ -1,232 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Net;
-
-namespace EonaCat.Network
-{
- ///
- /// Manages HTTP endpoint listeners and their prefixes.
- ///
- internal sealed class EndPointManager
- {
- private static readonly Dictionary _endpoints;
-
- ///
- /// Initializes static members of the class.
- ///
- static EndPointManager()
- {
- _endpoints = new Dictionary();
- }
-
- ///
- /// Prevents a default instance of the class from being created.
- ///
- private EndPointManager()
- {
- }
-
- ///
- /// Adds an HTTP listener and its associated prefixes.
- ///
- /// The HTTP listener to be added.
- public static void AddListener(HttpListener listener)
- {
- var added = new List();
- lock (((ICollection)_endpoints).SyncRoot)
- {
- try
- {
- foreach (var pref in listener.Prefixes)
- {
- addPrefix(pref, listener);
- added.Add(pref);
- }
- }
- catch
- {
- foreach (var pref in added)
- {
- removePrefix(pref, listener);
- }
-
- throw;
- }
- }
- }
-
- ///
- /// Adds an HTTP listener prefix.
- ///
- /// The URI prefix to be added.
- /// The HTTP listener associated with the prefix.
- public static void AddPrefix(string uriPrefix, HttpListener listener)
- {
- lock (((ICollection)_endpoints).SyncRoot)
- {
- addPrefix(uriPrefix, listener);
- }
- }
-
- ///
- /// Removes an HTTP listener and its associated prefixes.
- ///
- /// The HTTP listener to be removed.
- public static void RemoveListener(HttpListener listener)
- {
- lock (((ICollection)_endpoints).SyncRoot)
- {
- foreach (var pref in listener.Prefixes)
- {
- removePrefix(pref, listener);
- }
- }
- }
-
- ///
- /// Removes an HTTP listener prefix.
- ///
- /// The URI prefix to be removed.
- /// The HTTP listener associated with the prefix.
- public static void RemovePrefix(string uriPrefix, HttpListener listener)
- {
- lock (((ICollection)_endpoints).SyncRoot)
- {
- removePrefix(uriPrefix, listener);
- }
- }
-
- ///
- /// Removes an endpoint and closes its associated listener.
- ///
- /// The endpoint to be removed.
- /// true if the endpoint is successfully removed; otherwise, false.
- internal static bool RemoveEndPoint(IPEndPoint endpoint)
- {
- lock (((ICollection)_endpoints).SyncRoot)
- {
- if (!_endpoints.TryGetValue(endpoint, out EndPointListener lsnr))
- {
- return false;
- }
-
- _endpoints.Remove(endpoint);
- lsnr.Close();
-
- return true;
- }
- }
-
- private static void addPrefix(string uriPrefix, HttpListener listener)
- {
- var pref = new HttpListenerPrefix(uriPrefix);
-
- var addr = convertToIPAddress(pref.Host);
- if (!addr.IsLocal())
- {
- throw new HttpListenerException(87, "Includes an invalid host.");
- }
-
- if (!int.TryParse(pref.Port, out int port))
- {
- throw new HttpListenerException(87, "Includes an invalid port.");
- }
-
- if (!port.IsPortNumber())
- {
- throw new HttpListenerException(87, "Includes an invalid port.");
- }
-
- var path = pref.Path;
- if (path.IndexOf('%') != -1)
- {
- throw new HttpListenerException(87, "Includes an invalid path.");
- }
-
- if (path.IndexOf("//", StringComparison.Ordinal) != -1)
- {
- throw new HttpListenerException(87, "Includes an invalid path.");
- }
-
- var endpoint = new IPEndPoint(addr, port);
-
- if (_endpoints.TryGetValue(endpoint, out EndPointListener lsnr))
- {
- if (lsnr.IsSecure ^ pref.IsSecure)
- {
- throw new HttpListenerException(87, "Includes an invalid scheme.");
- }
- }
- else
- {
- lsnr =
- new EndPointListener(
- endpoint,
- pref.IsSecure,
- listener.CertificateFolderPath,
- listener.SSL,
- listener.ReuseAddress
- );
-
- _endpoints.Add(endpoint, lsnr);
- }
-
- lsnr.AddPrefix(pref, listener);
- }
-
- private static IPAddress convertToIPAddress(string hostname)
- {
- return hostname == "*" || hostname == "+" ? IPAddress.Any : hostname.ToIPAddress();
- }
-
- private static void removePrefix(string uriPrefix, HttpListener listener)
- {
- var pref = new HttpListenerPrefix(uriPrefix);
-
- var addr = convertToIPAddress(pref.Host);
- if (!addr.IsLocal())
- {
- return;
- }
-
- if (!int.TryParse(pref.Port, out int port))
- {
- return;
- }
-
- if (!port.IsPortNumber())
- {
- return;
- }
-
- var path = pref.Path;
- if (path.IndexOf('%') != -1)
- {
- return;
- }
-
- if (path.IndexOf("//", StringComparison.Ordinal) != -1)
- {
- return;
- }
-
- var endpoint = new IPEndPoint(addr, port);
-
- if (!_endpoints.TryGetValue(endpoint, out EndPointListener lsnr))
- {
- return;
- }
-
- if (lsnr.IsSecure ^ pref.IsSecure)
- {
- return;
- }
-
- lsnr.RemovePrefix(pref, listener);
- }
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Http/HttpBasicIdentity.cs b/EonaCat.Network/System/Sockets/Web/Core/Http/HttpBasicIdentity.cs
deleted file mode 100644
index b770b76..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Http/HttpBasicIdentity.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System.Security.Principal;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents a basic HTTP identity with a username and password.
- ///
- public class HttpBasicIdentity : GenericIdentity
- {
- private readonly string _password;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The username associated with the identity.
- /// The password associated with the identity.
- internal HttpBasicIdentity(string username, string password)
- : base(username, "Basic")
- {
- _password = password;
- }
-
- ///
- /// Gets the password associated with the identity.
- ///
- public virtual string Password => _password;
- }
-}
\ No newline at end of file
diff --git a/EonaCat.Network/System/Sockets/Web/Core/Http/HttpConnection.cs b/EonaCat.Network/System/Sockets/Web/Core/Http/HttpConnection.cs
deleted file mode 100644
index 42b604b..0000000
--- a/EonaCat.Network/System/Sockets/Web/Core/Http/HttpConnection.cs
+++ /dev/null
@@ -1,633 +0,0 @@
-// This file is part of the EonaCat project(s) which is released under the Apache License.
-// See the LICENSE file or go to https://EonaCat.com/License for full license details.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using System.Net.Security;
-using System.Net.Sockets;
-using System.Text;
-using System.Threading;
-
-namespace EonaCat.Network
-{
- ///
- /// Represents an HTTP connection.
- ///
- internal sealed class HttpConnection
- {
- private const int _bufferLength = 8192;
- private const int TIMEOUT_CONTINUE = 15000;
- private const int TIMEOUT_INITIAL = 90000;
- private readonly EndPointListener _listener;
- private readonly object _lock;
- private readonly Dictionary _timeoutCanceled;
- private byte[] _buffer;
- private HttpListenerContext _context;
- private bool _contextRegistered;
- private StringBuilder _currentLine;
- private InputState _inputState;
- private RequestStream _inputStream;
- private HttpListener _lastListener;
- private LineState _lineState;
- private ResponseStream _outputStream;
- private int _position;
- private MemoryStream _requestBuffer;
- private Socket _socket;
- private int _timeout;
- private Timer _timer;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The socket associated with the connection.
- /// The endpoint listener.
- internal HttpConnection(Socket socket, EndPointListener listener)
- {
- _socket = socket;
- _listener = listener;
- IsSecure = listener.IsSecure;
-
- var networkStream = new NetworkStream(socket, false);
- if (IsSecure)
- {
- var conf = listener.SSL;
- var sslStream = new SslStream(networkStream, false, conf.ClientCertificateValidationCallback);
- sslStream.AuthenticateAsServer(
- conf.Certificate,
- conf.IsClientCertificateRequired,
- conf.SslProtocols,
- conf.CheckForCertificateRevocation
- );
-
- Stream = sslStream;
- }
- else
- {
- Stream = networkStream;
- }
-
- _lock = new object();
- _timeout = TIMEOUT_INITIAL;
- _timeoutCanceled = new Dictionary();
- _timer = new Timer(OnTimeout, this, Timeout.Infinite, Timeout.Infinite);
-
- Setup();
- }
-
- ///
- /// Gets a value indicating whether the connection is closed.
- ///
- public bool IsClosed => _socket == null;
-
- ///
- /// Gets a value indicating whether the connection is secure.
- ///
- public bool IsSecure { get; }
-
- ///
- /// Gets the local endpoint.
- ///
- public IPEndPoint LocalEndPoint => (IPEndPoint)_socket.LocalEndPoint;
-
- ///
- /// Gets the remote endpoint.
- ///
- public IPEndPoint RemoteEndPoint => (IPEndPoint)_socket.RemoteEndPoint;
-
- ///
- /// Gets or sets the number of reuses.
- ///
- public int Reuses { get; private set; }
-
- ///
- /// Gets the network stream associated with the connection.
- ///
- public Stream Stream { get; private set; }
-
- ///
- /// Initiates reading the request.
- ///
- public void BeginReadRequest()
- {
- _buffer ??= new byte[_bufferLength];
-
- if (Reuses == 1)
- {
- _timeout = TIMEOUT_CONTINUE;
- }
-
- try
- {
- _timeoutCanceled.Add(Reuses, false);
- _timer.Change(_timeout, Timeout.Infinite);
- Stream.BeginRead(_buffer, 0, _bufferLength, OnRead, this);
- }
- catch
- {
- close();
- }
- }
-
- ///
- /// Closes the connection.
- ///
- public void Close()
- {
- Close(false);
- }
-
- ///
- /// Gets the request stream.
- ///
- /// The length of the content.
- /// True if chunked, false otherwise.
- /// The request stream.
- public RequestStream GetRequestStream(long contentLength, bool chunked)
- {
- if (_inputStream != null || _socket == null)
- {
- return _inputStream;
- }
-
- lock (_lock)
- {
- if (_socket == null)
- {
- return _inputStream;
- }
-
- var buff = _requestBuffer.GetBuffer();
- var len = (int)_requestBuffer.Length;
- DisposeRequestBuffer();
- if (chunked)
- {
- _context.Response.SendInChunks = true;
- _inputStream =
- new ChunkedRequestStream(Stream, buff, _position, len - _position, _context);
- }
- else
- {
- _inputStream =
- new RequestStream(Stream, buff, _position, len - _position, contentLength);
- }
-
- return _inputStream;
- }
- }
-
- ///
- /// Gets the response stream.
- ///
- /// The response stream.
- public ResponseStream GetResponseStream()
- {
- if (_outputStream != null || _socket == null)
- {
- return _outputStream;
- }
-
- lock (_lock)
- {
- if (_socket == null)
- {
- return _outputStream;
- }
-
- var lsnr = _context.Listener;
- var ignore = lsnr == null || lsnr.IgnoreWriteExceptions;
- _outputStream = new ResponseStream(Stream, _context.Response, ignore);
-
- return _outputStream;
- }
- }
-
- ///
- /// Sends an error response.
- ///
- public void SendError()
- {
- SendError(_context.ErrorMessage, _context.ErrorStatus);
- }
-
- ///
- /// Sends an error response with the specified message and status code.
- ///
- /// The error message.
- /// The HTTP status code.
- public void SendError(string message, int status)
- {
- if (_socket == null)
- {
- return;
- }
-
- lock (_lock)
- {
- if (_socket == null)
- {
- return;
- }
-
- try
- {
- var httpResponse = _context.Response;
- httpResponse.StatusCode = status;
- httpResponse.ContentType = "text/html";
-
- var content = new StringBuilder(64);
- content.AppendFormat("EonaCat.Network Error{0} {1}", status, httpResponse.StatusDescription);
- if (message != null && message.Length > 0)
- {
- content.AppendFormat(" ({0})
", message);
- }
- else
- {
- content.Append("