Compare commits

..

2 Commits

Author SHA1 Message Date
sta
9029714f17 fix WebSocket.cs 2010-10-28 16:28:08 +09:00
sta
fb0485faec branched to draft75 2010-10-28 16:20:17 +09:00
128 changed files with 537 additions and 34325 deletions

15
.gitignore vendored
View File

@ -1,15 +0,0 @@
## Ignore build results and temporary files.
Backup*
_UpgradeReport_Files
bin
obj
.idea
*.mdb
*.pdb
*.pidb
*.suo
*.user
*.userprefs
UpgradeLog*.*

View File

@ -1,121 +0,0 @@
using System;
using System.Threading;
using WebSocketSharp;
using WebSocketSharp.Net;
namespace Example
{
public class Program
{
public static void Main (string[] args)
{
// Create a new instance of the WebSocket class.
//
// The WebSocket class inherits the System.IDisposable interface, so you can
// use the using statement. And the WebSocket connection will be closed with
// close status 1001 (going away) when the control leaves the using block.
//
// If you would like to connect to the server with the secure connection,
// you should create a new instance with a wss scheme WebSocket URL.
using (var ws = new WebSocket ("ws://localhost:4649/Echo"))
//using (var ws = new WebSocket ("wss://localhost:5963/Echo"))
//using (var ws = new WebSocket ("ws://localhost:4649/Chat"))
//using (var ws = new WebSocket ("wss://localhost:5963/Chat"))
//using (var ws = new WebSocket ("ws://localhost:4649/Chat?name=nobita"))
//using (var ws = new WebSocket ("wss://localhost:5963/Chat?name=nobita"))
{
// Set the WebSocket events.
ws.OnOpen += (sender, e) => ws.Send ("Hi, there!");
ws.OnMessage += (sender, e) => {
var fmt = "WebSocket Message: {0}";
var body = !e.IsPing ? e.Data : "Received a ping.";
var msg = String.Format (fmt, body);
Console.WriteLine (msg);
};
ws.OnError += (sender, e) => {
var fmt = "WebSocket Error: {0}";
var msg = String.Format (fmt, e.Message);
Console.WriteLine (msg);
};
ws.OnClose += (sender, e) => {
var fmt = "WebSocket Close ({0}): {1}";
var msg = String.Format (fmt, e.Code, e.Reason);
Console.WriteLine (msg);
};
#if DEBUG
// To change the logging level.
ws.Log.Level = LogLevel.Trace;
// To change the wait time for the response to the Ping or Close.
//ws.WaitTime = TimeSpan.FromSeconds (10);
// To emit a WebSocket.OnMessage event when receives a ping.
//ws.EmitOnPing = true;
#endif
// To enable the Per-message Compression extension.
//ws.Compression = CompressionMethod.Deflate;
// To validate the server certificate.
/*
ws.SslConfiguration.ServerCertificateValidationCallback =
(sender, certificate, chain, sslPolicyErrors) => {
ws.Log.Debug (
String.Format (
"Certificate:\n- Issuer: {0}\n- Subject: {1}",
certificate.Issuer,
certificate.Subject
)
);
return true; // If the server certificate is valid.
};
*/
// To send the credentials for the HTTP Authentication (Basic/Digest).
//ws.SetCredentials ("nobita", "password", false);
// To send the Origin header.
//ws.Origin = "http://localhost:4649";
// To send the cookies.
//ws.SetCookie (new Cookie ("name", "nobita"));
//ws.SetCookie (new Cookie ("roles", "\"idiot, gunfighter\""));
// To connect through the HTTP Proxy server.
//ws.SetProxy ("http://localhost:3128", "nobita", "password");
// To enable the redirection.
//ws.EnableRedirection = true;
// Connect to the server.
ws.Connect ();
// Connect to the server asynchronously.
//ws.ConnectAsync ();
Console.WriteLine ("\nType 'exit' to exit.\n");
while (true) {
Thread.Sleep (1000);
Console.Write ("> ");
var msg = Console.ReadLine ();
if (msg == "exit")
break;
// Send a text message.
ws.Send (msg);
}
}
}
}
}

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="CertFilePassword" value="password"/>
<add key="ServerCertFile" value="/path/to/cert.pfx"/>
</appSettings>
</configuration>

View File

@ -1,26 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("Example2")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("sta.blockhead")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@ -1,70 +0,0 @@
using System;
using System.Threading;
using WebSocketSharp;
using WebSocketSharp.Server;
namespace Example2
{
public class Chat : WebSocketBehavior
{
private string _name;
private static int _number = 0;
private string _prefix;
public Chat ()
{
_prefix = "anon#";
}
public string Prefix {
get {
return _prefix;
}
set {
_prefix = !value.IsNullOrEmpty () ? value : "anon#";
}
}
private string getName ()
{
var name = QueryString["name"];
return !name.IsNullOrEmpty () ? name : _prefix + getNumber ();
}
private static int getNumber ()
{
return Interlocked.Increment (ref _number);
}
protected override void OnClose (CloseEventArgs e)
{
if (_name == null)
return;
var fmt = "{0} got logged off...";
var msg = String.Format (fmt, _name);
Sessions.Broadcast (msg);
}
protected override void OnMessage (MessageEventArgs e)
{
var fmt = "{0}: {1}";
var msg = String.Format (fmt, _name, e.Data);
Sessions.Broadcast (msg);
}
protected override void OnOpen ()
{
_name = getName ();
var fmt = "{0} has logged in!";
var msg = String.Format (fmt, _name);
Sessions.Broadcast (msg);
}
}
}

View File

@ -1,14 +0,0 @@
using System;
using WebSocketSharp;
using WebSocketSharp.Server;
namespace Example2
{
public class Echo : WebSocketBehavior
{
protected override void OnMessage (MessageEventArgs e)
{
Send (e.Data);
}
}
}

View File

@ -1,70 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Example2</RootNamespace>
<AssemblyName>example2</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_Ubuntu|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug_Ubuntu</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_Ubuntu|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release_Ubuntu</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Configuration" />
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Program.cs" />
<Compile Include="Echo.cs" />
<Compile Include="Chat.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<ProjectReference Include="..\websocket-sharp\websocket-sharp.csproj">
<Project>{B357BAC7-529E-4D81-A0D2-71041B19C8DE}</Project>
<Name>websocket-sharp</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
</Project>

View File

@ -1,143 +0,0 @@
using System;
using System.Configuration;
using System.Security.Cryptography.X509Certificates;
using WebSocketSharp;
using WebSocketSharp.Net;
using WebSocketSharp.Server;
namespace Example2
{
public class Program
{
public static void Main (string[] args)
{
// Create a new instance of the WebSocketServer class.
//
// If you would like to provide the secure connection, you should
// create a new instance with the 'secure' parameter set to true or
// with a wss scheme WebSocket URL.
var wssv = new WebSocketServer (4649);
//var wssv = new WebSocketServer (5963, true);
//var wssv = new WebSocketServer (System.Net.IPAddress.Any, 4649);
//var wssv = new WebSocketServer (System.Net.IPAddress.Any, 5963, true);
//var wssv = new WebSocketServer (System.Net.IPAddress.IPv6Any, 4649);
//var wssv = new WebSocketServer (System.Net.IPAddress.IPv6Any, 5963, true);
//var wssv = new WebSocketServer ("ws://0.0.0.0:4649");
//var wssv = new WebSocketServer ("wss://0.0.0.0:5963");
//var wssv = new WebSocketServer ("ws://[::0]:4649");
//var wssv = new WebSocketServer ("wss://[::0]:5963");
//var wssv = new WebSocketServer (System.Net.IPAddress.Loopback, 4649);
//var wssv = new WebSocketServer (System.Net.IPAddress.Loopback, 5963, true);
//var wssv = new WebSocketServer (System.Net.IPAddress.IPv6Loopback, 4649);
//var wssv = new WebSocketServer (System.Net.IPAddress.IPv6Loopback, 5963, true);
//var wssv = new WebSocketServer ("ws://localhost:4649");
//var wssv = new WebSocketServer ("wss://localhost:5963");
//var wssv = new WebSocketServer ("ws://127.0.0.1:4649");
//var wssv = new WebSocketServer ("wss://127.0.0.1:5963");
//var wssv = new WebSocketServer ("ws://[::1]:4649");
//var wssv = new WebSocketServer ("wss://[::1]:5963");
#if DEBUG
// To change the logging level.
wssv.Log.Level = LogLevel.Trace;
// To change the wait time for the response to the WebSocket Ping or Close.
//wssv.WaitTime = TimeSpan.FromSeconds (2);
// Not to remove the inactive sessions periodically.
//wssv.KeepClean = false;
#endif
// To provide the secure connection.
/*
var cert = ConfigurationManager.AppSettings["ServerCertFile"];
var passwd = ConfigurationManager.AppSettings["CertFilePassword"];
wssv.SslConfiguration.ServerCertificate = new X509Certificate2 (cert, passwd);
*/
// To provide the HTTP Authentication (Basic/Digest).
/*
wssv.AuthenticationSchemes = AuthenticationSchemes.Basic;
wssv.Realm = "WebSocket Test";
wssv.UserCredentialsFinder = id => {
var name = id.Name;
// Return user name, password, and roles.
return name == "nobita"
? new NetworkCredential (name, "password", "gunfighter")
: null; // If the user credentials are not found.
};
*/
// To resolve to wait for socket in TIME_WAIT state.
//wssv.ReuseAddress = true;
// Add the WebSocket services.
wssv.AddWebSocketService<Echo> ("/Echo");
wssv.AddWebSocketService<Chat> ("/Chat");
// Add the WebSocket service with initializing.
/*
wssv.AddWebSocketService<Chat> (
"/Chat",
s => {
s.Prefix = "Anon#";
// To send the Sec-WebSocket-Protocol header that has a subprotocol name.
s.Protocol = "chat";
// To ignore the Sec-WebSocket-Extensions header.
s.IgnoreExtensions = true;
// To emit a WebSocket.OnMessage event when receives a ping.
s.EmitOnPing = true;
// To validate the Origin header.
s.OriginValidator = val => {
// Check the value of the Origin header, and return true if valid.
Uri origin;
return !val.IsNullOrEmpty ()
&& Uri.TryCreate (val, UriKind.Absolute, out origin)
&& origin.Host == "localhost";
};
// To validate the cookies.
s.CookiesValidator = (req, res) => {
// Check the cookies in 'req', and set the cookies to send to
// the client with 'res' if necessary.
foreach (var cookie in req) {
cookie.Expired = true;
res.Add (cookie);
}
return true; // If valid.
};
}
);
*/
wssv.Start ();
if (wssv.IsListening) {
Console.WriteLine ("Listening on port {0}, and providing WebSocket services:", wssv.Port);
foreach (var path in wssv.WebSocketServices.Paths)
Console.WriteLine ("- {0}", path);
}
Console.WriteLine ("\nPress Enter key to stop the server...");
Console.ReadLine ();
wssv.Stop ();
}
}
}

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="CertFilePassword" value="password"/>
<add key="DocumentRootPath" value="../../Public"/>
<add key="ServerCertFile" value="/path/to/cert.pfx"/>
</appSettings>
</configuration>

View File

@ -1,26 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("Example3")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("sta.blockhead")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@ -1,70 +0,0 @@
using System;
using System.Threading;
using WebSocketSharp;
using WebSocketSharp.Server;
namespace Example3
{
public class Chat : WebSocketBehavior
{
private string _name;
private static int _number = 0;
private string _prefix;
public Chat ()
{
_prefix = "anon#";
}
public string Prefix {
get {
return _prefix;
}
set {
_prefix = !value.IsNullOrEmpty () ? value : "anon#";
}
}
private string getName ()
{
var name = QueryString["name"];
return !name.IsNullOrEmpty () ? name : _prefix + getNumber ();
}
private static int getNumber ()
{
return Interlocked.Increment (ref _number);
}
protected override void OnClose (CloseEventArgs e)
{
if (_name == null)
return;
var fmt = "{0} got logged off...";
var msg = String.Format (fmt, _name);
Sessions.Broadcast (msg);
}
protected override void OnMessage (MessageEventArgs e)
{
var fmt = "{0}: {1}";
var msg = String.Format (fmt, _name, e.Data);
Sessions.Broadcast (msg);
}
protected override void OnOpen ()
{
_name = getName ();
var fmt = "{0} has logged in!";
var msg = String.Format (fmt, _name);
Sessions.Broadcast (msg);
}
}
}

View File

@ -1,14 +0,0 @@
using System;
using WebSocketSharp;
using WebSocketSharp.Server;
namespace Example3
{
public class Echo : WebSocketBehavior
{
protected override void OnMessage (MessageEventArgs e)
{
Send (e.Data);
}
}
}

View File

@ -1,76 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{C648BA25-77E5-4A40-A97F-D0AA37B9FB26}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Example3</RootNamespace>
<AssemblyName>example3</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_Ubuntu|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug_Ubuntu</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_Ubuntu|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release_Ubuntu</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Configuration" />
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Program.cs" />
<Compile Include="Chat.cs" />
<Compile Include="Echo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<ProjectReference Include="..\websocket-sharp\websocket-sharp.csproj">
<Project>{B357BAC7-529E-4D81-A0D2-71041B19C8DE}</Project>
<Name>websocket-sharp</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="Public\index.html" />
<None Include="Public\Js\echotest.js" />
</ItemGroup>
<ItemGroup>
<Folder Include="Public\" />
<Folder Include="Public\Js\" />
</ItemGroup>
</Project>

View File

@ -1,179 +0,0 @@
using System;
using System.Configuration;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using WebSocketSharp;
using WebSocketSharp.Net;
using WebSocketSharp.Server;
namespace Example3
{
public class Program
{
public static void Main (string[] args)
{
// Create a new instance of the HttpServer class.
//
// If you would like to provide the secure connection, you should
// create a new instance with the 'secure' parameter set to true or
// with an https scheme HTTP URL.
var httpsv = new HttpServer (4649);
//var httpsv = new HttpServer (5963, true);
//var httpsv = new HttpServer (System.Net.IPAddress.Any, 4649);
//var httpsv = new HttpServer (System.Net.IPAddress.Any, 5963, true);
//var httpsv = new HttpServer (System.Net.IPAddress.IPv6Any, 4649);
//var httpsv = new HttpServer (System.Net.IPAddress.IPv6Any, 5963, true);
//var httpsv = new HttpServer ("http://0.0.0.0:4649");
//var httpsv = new HttpServer ("https://0.0.0.0:5963");
//var httpsv = new HttpServer ("http://[::0]:4649");
//var httpsv = new HttpServer ("https://[::0]:5963");
//var httpsv = new HttpServer (System.Net.IPAddress.Loopback, 4649);
//var httpsv = new HttpServer (System.Net.IPAddress.Loopback, 5963, true);
//var httpsv = new HttpServer (System.Net.IPAddress.IPv6Loopback, 4649);
//var httpsv = new HttpServer (System.Net.IPAddress.IPv6Loopback, 5963, true);
//var httpsv = new HttpServer ("http://localhost:4649");
//var httpsv = new HttpServer ("https://localhost:5963");
//var httpsv = new HttpServer ("http://127.0.0.1:4649");
//var httpsv = new HttpServer ("https://127.0.0.1:5963");
//var httpsv = new HttpServer ("http://[::1]:4649");
//var httpsv = new HttpServer ("https://[::1]:5963");
#if DEBUG
// To change the logging level.
httpsv.Log.Level = LogLevel.Trace;
// To change the wait time for the response to the WebSocket Ping or Close.
//httpsv.WaitTime = TimeSpan.FromSeconds (2);
// Not to remove the inactive WebSocket sessions periodically.
//httpsv.KeepClean = false;
#endif
// To provide the secure connection.
/*
var cert = ConfigurationManager.AppSettings["ServerCertFile"];
var passwd = ConfigurationManager.AppSettings["CertFilePassword"];
httpsv.SslConfiguration.ServerCertificate = new X509Certificate2 (cert, passwd);
*/
// To provide the HTTP Authentication (Basic/Digest).
/*
httpsv.AuthenticationSchemes = AuthenticationSchemes.Basic;
httpsv.Realm = "WebSocket Test";
httpsv.UserCredentialsFinder = id => {
var name = id.Name;
// Return user name, password, and roles.
return name == "nobita"
? new NetworkCredential (name, "password", "gunfighter")
: null; // If the user credentials are not found.
};
*/
// To resolve to wait for socket in TIME_WAIT state.
//httpsv.ReuseAddress = true;
// Set the document root path.
httpsv.DocumentRootPath = ConfigurationManager.AppSettings["DocumentRootPath"];
// Set the HTTP GET request event.
httpsv.OnGet += (sender, e) => {
var req = e.Request;
var res = e.Response;
var path = req.RawUrl;
if (path == "/")
path += "index.html";
byte[] contents;
if (!e.TryReadFile (path, out contents)) {
res.StatusCode = (int) HttpStatusCode.NotFound;
return;
}
if (path.EndsWith (".html")) {
res.ContentType = "text/html";
res.ContentEncoding = Encoding.UTF8;
}
else if (path.EndsWith (".js")) {
res.ContentType = "application/javascript";
res.ContentEncoding = Encoding.UTF8;
}
res.ContentLength64 = contents.LongLength;
res.Close (contents, true);
};
// Add the WebSocket services.
httpsv.AddWebSocketService<Echo> ("/Echo");
httpsv.AddWebSocketService<Chat> ("/Chat");
// Add the WebSocket service with initializing.
/*
httpsv.AddWebSocketService<Chat> (
"/Chat",
s => {
s.Prefix = "Anon#";
// To send the Sec-WebSocket-Protocol header that has a subprotocol name.
s.Protocol = "chat";
// To ignore the Sec-WebSocket-Extensions header.
s.IgnoreExtensions = true;
// To emit a WebSocket.OnMessage event when receives a ping.
s.EmitOnPing = true;
// To validate the Origin header.
s.OriginValidator = val => {
// Check the value of the Origin header, and return true if valid.
Uri origin;
return !val.IsNullOrEmpty ()
&& Uri.TryCreate (val, UriKind.Absolute, out origin)
&& origin.Host == "localhost";
};
// To validate the cookies.
s.CookiesValidator = (req, res) => {
// Check the cookies in 'req', and set the cookies to send to
// the client with 'res' if necessary.
foreach (var cookie in req) {
cookie.Expired = true;
res.Add (cookie);
}
return true; // If valid.
};
}
);
*/
httpsv.Start ();
if (httpsv.IsListening) {
Console.WriteLine ("Listening on port {0}, and providing WebSocket services:", httpsv.Port);
foreach (var path in httpsv.WebSocketServices.Paths)
Console.WriteLine ("- {0}", path);
}
Console.WriteLine ("\nPress Enter key to stop the server...");
Console.ReadLine ();
httpsv.Stop ();
}
}
}

View File

@ -1,68 +0,0 @@
/*
* echotest.js
*
* Derived from Echo Test of WebSocket.org (http://www.websocket.org/echo.html).
*
* Copyright (c) 2012 Kaazing Corporation.
*/
var url = "ws://localhost:4649/Echo";
//var url = "wss://localhost:5963/Echo";
var output;
function init () {
output = document.getElementById ("output");
doWebSocket ();
}
function doWebSocket () {
websocket = new WebSocket (url);
websocket.onopen = function (e) {
onOpen (e);
};
websocket.onmessage = function (e) {
onMessage (e);
};
websocket.onerror = function (e) {
onError (e);
};
websocket.onclose = function (e) {
onClose (e);
};
}
function onOpen (event) {
writeToScreen ("CONNECTED");
send ("WebSocket rocks");
}
function onMessage (event) {
writeToScreen ('<span style="color: blue;">RESPONSE: ' + event.data + '</span>');
websocket.close ();
}
function onError (event) {
writeToScreen ('<span style="color: red;">ERROR: ' + event.data + '</span>');
}
function onClose (event) {
writeToScreen ("DISCONNECTED");
}
function send (message) {
writeToScreen ("SENT: " + message);
websocket.send (message);
}
function writeToScreen (message) {
var pre = document.createElement ("p");
pre.style.wordWrap = "break-word";
pre.innerHTML = message;
output.appendChild (pre);
}
window.addEventListener ("load", init, false);

View File

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Echo Test</title>
<script type="text/javascript" src="/Js/echotest.js">
</script>
</head>
<body>
<h2>WebSocket Echo Test</h2>
<div id="output"></div>
</body>
</html>

View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2010-2022 sta.blockhead
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

706
README.md
View File

@ -1,708 +1,8 @@
![Logo](websocket-sharp_logo.png)
# websocket-sharp #
## Welcome to websocket-sharp! ##
websocket-sharp supports:
- [RFC 6455](#supported-websocket-specifications)
- [WebSocket Client](#websocket-client) and [Server](#websocket-server)
- [Per-message Compression](#per-message-compression) extension
- [Secure Connection](#secure-connection)
- [HTTP Authentication](#http-authentication)
- [Query string, Origin header, and Cookies](#query-string-origin-header-and-cookies)
- [Connecting through the HTTP proxy server](#connecting-through-the-http-proxy-server)
- .NET Framework **3.5** or later (includes compatible environment such as [Mono])
## Branches ##
- [master] for production releases.
- [hybi-00] for older [draft-ietf-hybi-thewebsocketprotocol-00]. No longer maintained.
- [draft75] for even more old [draft-hixie-thewebsocketprotocol-75]. No longer maintained.
## Build ##
websocket-sharp is built as a single assembly, **websocket-sharp.dll**.
websocket-sharp is developed with [MonoDevelop]. So a simple way to build is to open **websocket-sharp.sln** and run build for **websocket-sharp project** with any of the build configurations (e.g. `Debug`) in MonoDevelop.
## Install ##
### Self Build ###
You should add your websocket-sharp.dll (e.g. `/path/to/websocket-sharp/bin/Debug/websocket-sharp.dll`) to the library references of your project.
If you would like to use that dll in your [Unity] project, you should add it to any folder of your project (e.g. `Assets/Plugins`) in the **Unity Editor**.
### NuGet Gallery ###
websocket-sharp is available on the [NuGet Gallery], as still a **prerelease** version.
- [NuGet Gallery: websocket-sharp]
You can add websocket-sharp to your project with the NuGet Package Manager, by using the following command in the Package Manager Console.
PM> Install-Package WebSocketSharp -Pre
### Unity Asset Store ###
websocket-sharp is available on the Unity Asset Store (Sorry, Not available now).
- [WebSocket-Sharp for Unity]
It works with **Unity Free**, but there are some limitations:
- [Security Sandbox of the Webplayer] (The server is not available in Web Player)
- [WebGL Networking] (Not available in WebGL)
- Incompatible platform (Not available for such UWP)
- Lack of dll for the System.IO.Compression (The compression extension is not available on Windows)
- .NET Socket Support for iOS/Android (iOS/Android Pro is required if your Unity is earlier than Unity 5)
- .NET API 2.0 compatibility level for iOS/Android
.NET API 2.0 compatibility level for iOS/Android may require to fix lack of some features for later than .NET Framework 2.0, such as the `System.Func<...>` delegates (so i have added them in the asset package).
And it is priced at **US$15**. I believe your $15 makes this project more better, **Thank you!**
A C# implementation of a WebSocket protocol client.
## Usage ##
### WebSocket Client ###
Please refer to wsclient/wsclient.cs.
```csharp
using System;
using WebSocketSharp;
namespace Example
{
public class Program
{
public static void Main (string[] args)
{
using (var ws = new WebSocket ("ws://dragonsnest.far/Laputa")) {
ws.OnMessage += (sender, e) =>
Console.WriteLine ("Laputa says: " + e.Data);
ws.Connect ();
ws.Send ("BALUS");
Console.ReadKey (true);
}
}
}
}
```
#### Step 1 ####
Required namespace.
```csharp
using WebSocketSharp;
```
The `WebSocket` class exists in the `WebSocketSharp` namespace.
#### Step 2 ####
Creating a new instance of the `WebSocket` class with the WebSocket URL to connect.
```csharp
var ws = new WebSocket ("ws://example.com");
```
The `WebSocket` class inherits the `System.IDisposable` interface, so you can create it with the `using` statement.
```csharp
using (var ws = new WebSocket ("ws://example.com")) {
...
}
```
This will **close** the WebSocket connection with status code `1001` (going away) when the control leaves the `using` block.
#### Step 3 ####
Setting the `WebSocket` events.
##### WebSocket.OnOpen Event #####
This event occurs when the WebSocket connection has been established.
```csharp
ws.OnOpen += (sender, e) => {
...
};
```
`System.EventArgs.Empty` is passed as `e`, so you do not need to use it.
##### WebSocket.OnMessage Event #####
This event occurs when the `WebSocket` receives a message.
```csharp
ws.OnMessage += (sender, e) => {
...
};
```
A `WebSocketSharp.MessageEventArgs` instance is passed as `e`.
If you would like to get the message data, you should access `e.Data` or `e.RawData` property.
`e.Data` property returns a `string`, so it is mainly used to get the **text** message data.
`e.RawData` property returns a `byte[]`, so it is mainly used to get the **binary** message data.
```csharp
if (e.IsText) {
// Do something with e.Data.
...
return;
}
if (e.IsBinary) {
// Do something with e.RawData.
...
return;
}
```
And if you would like to notify that a **ping** has been received, via this event, you should set the `WebSocket.EmitOnPing` property to `true`.
```csharp
ws.EmitOnPing = true;
ws.OnMessage += (sender, e) => {
if (e.IsPing) {
// Do something to notify that a ping has been received.
...
return;
}
};
```
##### WebSocket.OnError Event #####
This event occurs when the `WebSocket` gets an error.
```csharp
ws.OnError += (sender, e) => {
...
};
```
A `WebSocketSharp.ErrorEventArgs` instance is passed as `e`.
If you would like to get the error message, you should access `e.Message` property.
`e.Message` property returns a `string` that represents the error message.
And `e.Exception` property returns a `System.Exception` instance that represents the cause of the error if it is due to an exception.
##### WebSocket.OnClose Event #####
This event occurs when the WebSocket connection has been closed.
```csharp
ws.OnClose += (sender, e) => {
...
};
```
A `WebSocketSharp.CloseEventArgs` instance is passed as `e`.
If you would like to get the reason for the close, you should access `e.Code` or `e.Reason` property.
`e.Code` property returns a `ushort` that represents the status code for the close.
`e.Reason` property returns a `string` that represents the reason for the close.
#### Step 4 ####
Connecting to the WebSocket server.
```csharp
ws.Connect ();
```
If you would like to connect to the server asynchronously, you should use the `WebSocket.ConnectAsync ()` method.
#### Step 5 ####
Sending data to the WebSocket server.
```csharp
ws.Send (data);
```
The `WebSocket.Send` method is overloaded.
You can use the `WebSocket.Send (string)`, `WebSocket.Send (byte[])`, or `WebSocket.Send (System.IO.FileInfo)` method to send the data.
If you would like to send the data asynchronously, you should use the `WebSocket.SendAsync` method.
```csharp
ws.SendAsync (data, completed);
```
And also if you would like to do something when the send is complete, you should set `completed` to any `Action<bool>` delegate.
#### Step 6 ####
Closing the WebSocket connection.
```csharp
ws.Close (code, reason);
```
If you would like to close the connection explicitly, you should use the `WebSocket.Close` method.
The `WebSocket.Close` method is overloaded.
You can use the `WebSocket.Close ()`, `WebSocket.Close (ushort)`, `WebSocket.Close (WebSocketSharp.CloseStatusCode)`, `WebSocket.Close (ushort, string)`, or `WebSocket.Close (WebSocketSharp.CloseStatusCode, string)` method to close the connection.
If you would like to close the connection asynchronously, you should use the `WebSocket.CloseAsync` method.
### WebSocket Server ###
```csharp
using System;
using WebSocketSharp;
using WebSocketSharp.Server;
namespace Example
{
public class Laputa : WebSocketBehavior
{
protected override void OnMessage (MessageEventArgs e)
{
var msg = e.Data == "BALUS"
? "Are you kidding?"
: "I'm not available now.";
Send (msg);
}
}
public class Program
{
public static void Main (string[] args)
{
var wssv = new WebSocketServer ("ws://dragonsnest.far");
wssv.AddWebSocketService<Laputa> ("/Laputa");
wssv.Start ();
Console.ReadKey (true);
wssv.Stop ();
}
}
}
```
#### Step 1 ####
Required namespace.
```csharp
using WebSocketSharp.Server;
```
The `WebSocketBehavior` and `WebSocketServer` classes exist in the `WebSocketSharp.Server` namespace.
#### Step 2 ####
Creating the class that inherits the `WebSocketBehavior` class.
For example, if you would like to provide an echo service,
```csharp
using System;
using WebSocketSharp;
using WebSocketSharp.Server;
public class Echo : WebSocketBehavior
{
protected override void OnMessage (MessageEventArgs e)
{
Send (e.Data);
}
}
```
And if you would like to provide a chat service,
```csharp
using System;
using WebSocketSharp;
using WebSocketSharp.Server;
public class Chat : WebSocketBehavior
{
private string _suffix;
public Chat ()
{
_suffix = String.Empty;
}
public string Suffix {
get {
return _suffix;
}
set {
_suffix = value ?? String.Empty;
}
}
protected override void OnMessage (MessageEventArgs e)
{
Sessions.Broadcast (e.Data + _suffix);
}
}
```
You can define the behavior of any WebSocket service by creating the class that inherits the `WebSocketBehavior` class.
If you override the `WebSocketBehavior.OnMessage (MessageEventArgs)` method, it will be called when the `WebSocket` used in a session in the service receives a message.
And if you override the `WebSocketBehavior.OnOpen ()`, `WebSocketBehavior.OnError (ErrorEventArgs)`, and `WebSocketBehavior.OnClose (CloseEventArgs)` methods, each of them will be called when each of the `WebSocket` events (`OnOpen`, `OnError`, and `OnClose`) occurs.
The `WebSocketBehavior.Send` method can send data to the client on a session in the service.
If you would like to get the sessions in the service, you should access the `WebSocketBehavior.Sessions` property (returns a `WebSocketSharp.Server.WebSocketSessionManager`).
The `WebSocketBehavior.Sessions.Broadcast` method can send data to every client in the service.
#### Step 3 ####
Creating a new instance of the `WebSocketServer` class.
```csharp
var wssv = new WebSocketServer (4649);
wssv.AddWebSocketService<Echo> ("/Echo");
wssv.AddWebSocketService<Chat> ("/Chat");
wssv.AddWebSocketService<Chat> ("/ChatWithNyan", s => s.Suffix = " Nyan!");
```
You can add any WebSocket service to your `WebSocketServer` with the specified behavior and absolute path to the service, by using the `WebSocketServer.AddWebSocketService<TBehavior> (string)` or `WebSocketServer.AddWebSocketService<TBehavior> (string, Action<TBehavior>)` method.
The type of `TBehavior` must inherit the `WebSocketBehavior` class, and must have a public parameterless constructor.
So you can use a class in the above Step 2 to add the service.
If you create a new instance of the `WebSocketServer` class without a port number, it sets the port number to **80**. So it is necessary to run with root permission.
$ sudo mono example2.exe
#### Step 4 ####
Starting the WebSocket server.
```csharp
wssv.Start ();
```
#### Step 5 ####
Stopping the WebSocket server.
```csharp
wssv.Stop ();
```
### HTTP Server with the WebSocket ###
I have modified the `System.Net.HttpListener`, `System.Net.HttpListenerContext`, and some other classes from **[Mono]** to create an HTTP server that allows to accept the WebSocket handshake requests.
So websocket-sharp provides the `WebSocketSharp.Server.HttpServer` class.
You can add any WebSocket service to your `HttpServer` with the specified behavior and path to the service, by using the `HttpServer.AddWebSocketService<TBehavior> (string)` or `HttpServer.AddWebSocketService<TBehavior> (string, Action<TBehavior>)` method.
```csharp
var httpsv = new HttpServer (4649);
httpsv.AddWebSocketService<Echo> ("/Echo");
httpsv.AddWebSocketService<Chat> ("/Chat");
httpsv.AddWebSocketService<Chat> ("/ChatWithNyan", s => s.Suffix = " Nyan!");
```
For more information, would you see **[Example3]**?
### WebSocket Extensions ###
#### Per-message Compression ####
websocket-sharp supports the [Per-message Compression][compression] extension (but does not support it with the [context take over]).
As a WebSocket client, if you would like to enable this extension, you should set the `WebSocket.Compression` property to a compression method before calling the connect method.
```csharp
ws.Compression = CompressionMethod.Deflate;
```
And then the client will send the following header in the handshake request to the server.
Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover
If the server supports this extension, it will return the same header which has the corresponding value.
So eventually this extension will be available when the client receives the header in the handshake response.
#### Ignoring the extensions ####
As a WebSocket server, if you would like to ignore the extensions requested from a client, you should set the `WebSocketBehavior.IgnoreExtensions` property to `true` in your `WebSocketBehavior` constructor or initializing it, such as the following.
```csharp
wssv.AddWebSocketService<Chat> (
"/Chat",
s => s.IgnoreExtensions = true // To ignore the extensions requested from a client.
);
```
If it is set to `true`, the service will not return the Sec-WebSocket-Extensions header in its handshake response.
I think this is useful when you get something error in connecting the server and exclude the extensions as a cause of the error.
### Secure Connection ###
websocket-sharp supports the secure connection with **SSL/TLS**.
As a WebSocket client, you should create a new instance of the `WebSocket` class with a **wss** scheme WebSocket URL.
```csharp
var ws = new WebSocket ("wss://example.com");
```
If you would like to set a custom validation for the server certificate, you should set the `WebSocket.SslConfiguration.ServerCertificateValidationCallback` property to a callback for it.
```csharp
ws.SslConfiguration.ServerCertificateValidationCallback =
(sender, certificate, chain, sslPolicyErrors) => {
// Do something to validate the server certificate.
...
return true; // If the server certificate is valid.
};
```
The default callback always returns `true`.
As a WebSocket server, you should create a new instance of the `WebSocketServer` or `HttpServer` class with some settings for the secure connection, such as the following.
```csharp
var wssv = new WebSocketServer (5963, true);
wssv.SslConfiguration.ServerCertificate = new X509Certificate2 (
"/path/to/cert.pfx", "password for cert.pfx"
);
```
### HTTP Authentication ###
websocket-sharp supports the [HTTP Authentication (Basic/Digest)][rfc2617].
As a WebSocket client, you should set a pair of user name and password for the HTTP authentication, by using the `WebSocket.SetCredentials (string, string, bool)` method before calling the connect method.
```csharp
ws.SetCredentials ("nobita", "password", preAuth);
```
If `preAuth` is `true`, the client will send the credentials for the Basic authentication in the first handshake request to the server.
Otherwise, it will send the credentials for either the Basic or Digest (determined by the unauthorized response to the first handshake request) authentication in the second handshake request to the server.
As a WebSocket server, you should set an HTTP authentication scheme, a realm, and any function to find the user credentials before calling the start method, such as the following.
```csharp
wssv.AuthenticationSchemes = AuthenticationSchemes.Basic;
wssv.Realm = "WebSocket Test";
wssv.UserCredentialsFinder = id => {
var name = id.Name;
// Return user name, password, and roles.
return name == "nobita"
? new NetworkCredential (name, "password", "gunfighter")
: null; // If the user credentials are not found.
};
```
If you would like to provide the Digest authentication, you should set such as the following.
```csharp
wssv.AuthenticationSchemes = AuthenticationSchemes.Digest;
```
### Query string, Origin header, and Cookies ###
As a WebSocket client, if you would like to send the query string in the handshake request, you should create a new instance of the `WebSocket` class with a WebSocket URL that includes the [Query] string parameters.
```csharp
var ws = new WebSocket ("ws://example.com/?name=nobita");
```
If you would like to send the Origin header in the handshake request, you should set the `WebSocket.Origin` property to an allowable value as the [Origin] header before calling the connect method.
```csharp
ws.Origin = "http://example.com";
```
And if you would like to send the cookies in the handshake request, you should set any cookie by using the `WebSocket.SetCookie (WebSocketSharp.Net.Cookie)` method before calling the connect method.
```csharp
ws.SetCookie (new Cookie ("name", "nobita"));
```
As a WebSocket server, if you would like to get the query string included in a handshake request, you should access the `WebSocketBehavior.QueryString` property, such as the following.
```csharp
public class Chat : WebSocketBehavior
{
private string _name;
...
protected override void OnOpen ()
{
_name = QueryString["name"];
}
...
}
```
If you would like to get the value of the Origin header included in a handshake request, you should access the `WebSocketBehavior.Context.Origin` property.
If you would like to get the cookies included in a handshake request, you should access the `WebSocketBehavior.Context.CookieCollection` property.
And if you would like to validate the Origin header, cookies, or both, you should set each validation for it with your `WebSocketBehavior`, for example, by using the `WebSocketServer.AddWebSocketService<TBehavior> (string, Action<TBehavior>)` method with initializing, such as the following.
```csharp
wssv.AddWebSocketService<Chat> (
"/Chat",
s => {
s.OriginValidator = val => {
// Check the value of the Origin header, and return true if valid.
Uri origin;
return !val.IsNullOrEmpty ()
&& Uri.TryCreate (val, UriKind.Absolute, out origin)
&& origin.Host == "example.com";
};
s.CookiesValidator = (req, res) => {
// Check the cookies in 'req', and set the cookies to send to
// the client with 'res' if necessary.
foreach (var cookie in req) {
cookie.Expired = true;
res.Add (cookie);
}
return true; // If valid.
};
}
);
```
### Connecting through the HTTP proxy server ###
websocket-sharp supports to connect through the HTTP proxy server.
If you would like to connect to a WebSocket server through the HTTP proxy server, you should set the proxy server URL, and if necessary, a pair of user name and password for the proxy server authentication (Basic/Digest), by using the `WebSocket.SetProxy (string, string, string)` method before calling the connect method.
```csharp
var ws = new WebSocket ("ws://example.com");
ws.SetProxy ("http://localhost:3128", "nobita", "password");
```
I have tested this with **[Squid]**. It is necessary to disable the following option in **squid.conf** (e.g. `/etc/squid/squid.conf`).
```
# Deny CONNECT to other than SSL ports
#http_access deny CONNECT !SSL_ports
```
### Logging ###
The `WebSocket` class has the own logging function.
You can use it with the `WebSocket.Log` property (returns a `WebSocketSharp.Logger`).
So if you would like to change the current logging level (`WebSocketSharp.LogLevel.Error` as the default), you should set the `WebSocket.Log.Level` property to any of the `LogLevel` enum values.
```csharp
ws.Log.Level = LogLevel.Debug;
```
The above means a log with lower than `LogLevel.Debug` cannot be outputted.
And if you would like to output a log, you should use any of the output methods. The following outputs a log with `LogLevel.Debug`.
```csharp
ws.Log.Debug ("This is a debug message.");
```
The `WebSocketServer` and `HttpServer` classes have the same logging function.
## Examples ##
Examples using websocket-sharp.
### Example ###
[Example] connects to the server executed by [Example2] or [Example3].
### Example2 ###
[Example2] starts a WebSocket server.
### Example3 ###
[Example3] starts an HTTP server that allows to accept the WebSocket handshake requests.
Would you access to [http://localhost:4649](http://localhost:4649) to do **WebSocket Echo Test** with your web browser while Example3 is running?
## Supported WebSocket Specifications ##
websocket-sharp supports **RFC 6455**, and it is based on the following references:
- [The WebSocket Protocol][rfc6455]
- [The WebSocket API][api]
- [Compression Extensions for WebSocket][compression]
Thanks for translating to japanese.
- [The WebSocket Protocol 日本語訳][rfc6455_ja]
- [The WebSocket API 日本語訳][api_ja]
## License ##
websocket-sharp is provided under [The MIT License].
[Example]: https://github.com/sta/websocket-sharp/tree/master/Example
[Example2]: https://github.com/sta/websocket-sharp/tree/master/Example2
[Example3]: https://github.com/sta/websocket-sharp/tree/master/Example3
[Mono]: http://www.mono-project.com
[MonoDevelop]: http://monodevelop.com
[NuGet Gallery]: http://www.nuget.org
[NuGet Gallery: websocket-sharp]: http://www.nuget.org/packages/WebSocketSharp
[Origin]: http://tools.ietf.org/html/rfc6454#section-7
[Query]: http://tools.ietf.org/html/rfc3986#section-3.4
[Security Sandbox of the Webplayer]: http://docs.unity3d.com/Manual/SecuritySandbox.html
[Squid]: http://www.squid-cache.org
[The MIT License]: https://raw.github.com/sta/websocket-sharp/master/LICENSE.txt
[Unity]: http://unity3d.com
[WebGL Networking]: http://docs.unity3d.com/Manual/webgl-networking.html
[WebSocket-Sharp for Unity]: http://u3d.as/content/sta-blockhead/websocket-sharp-for-unity
[api]: http://www.w3.org/TR/websockets
[api_ja]: http://www.hcn.zaq.ne.jp/___/WEB/WebSocket-ja.html
[compression]: http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-19
[context take over]: http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-19#section-8.1.1
[draft-hixie-thewebsocketprotocol-75]: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
[draft-ietf-hybi-thewebsocketprotocol-00]: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
[draft75]: https://github.com/sta/websocket-sharp/tree/draft75
[hybi-00]: https://github.com/sta/websocket-sharp/tree/hybi-00
[master]: https://github.com/sta/websocket-sharp/tree/master
[rfc2617]: http://tools.ietf.org/html/rfc2617
[rfc6455]: http://tools.ietf.org/html/rfc6455
[rfc6455_ja]: http://www.hcn.zaq.ne.jp/___/WEB/RFC6455-ja.html

View File

@ -3,11 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "websocket-sharp", "websocket-sharp\websocket-sharp.csproj", "{B357BAC7-529E-4D81-A0D2-71041B19C8DE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example2", "Example2\Example2.csproj", "{B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example3", "Example3\Example3.csproj", "{C648BA25-77E5-4A40-A97F-D0AA37B9FB26}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wsclient", "wsclient\wsclient.csproj", "{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -33,22 +29,6 @@ Global
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release|Any CPU.Build.0 = Release|Any CPU
{B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
{B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
{B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Release_Ubuntu|Any CPU.ActiveCfg = Release_Ubuntu|Any CPU
{B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU
{B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B81A24C8-25BB-42B2-AF99-1E1EACCE74C7}.Release|Any CPU.Build.0 = Release|Any CPU
{C648BA25-77E5-4A40-A97F-D0AA37B9FB26}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
{C648BA25-77E5-4A40-A97F-D0AA37B9FB26}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
{C648BA25-77E5-4A40-A97F-D0AA37B9FB26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C648BA25-77E5-4A40-A97F-D0AA37B9FB26}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C648BA25-77E5-4A40-A97F-D0AA37B9FB26}.Release_Ubuntu|Any CPU.ActiveCfg = Release_Ubuntu|Any CPU
{C648BA25-77E5-4A40-A97F-D0AA37B9FB26}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU
{C648BA25-77E5-4A40-A97F-D0AA37B9FB26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C648BA25-77E5-4A40-A97F-D0AA37B9FB26}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = websocket-sharp\websocket-sharp.csproj

12
websocket-sharp.userprefs Normal file
View File

@ -0,0 +1,12 @@
<Properties>
<MonoDevelop.Ide.Workspace ActiveConfiguration="Debug_Ubuntu" ctype="Workspace" />
<MonoDevelop.Ide.Workbench ActiveDocument="websocket-sharp/WebSocket.cs" ctype="Workbench">
<Files>
<File FileName="websocket-sharp/WebSocket.cs" Line="247" Column="31" />
</Files>
</MonoDevelop.Ide.Workbench>
<MonoDevelop.Ide.DebuggingService.Breakpoints>
<BreakpointStore />
</MonoDevelop.Ide.DebuggingService.Breakpoints>
<MonoDevelop.Ide.DebuggingService.PinnedWatches ctype="PinnedWatchStore" />
</Properties>

View File

@ -5,7 +5,7 @@ using System.Runtime.CompilerServices;
// Change them to the values specific to your project.
[assembly: AssemblyTitle("websocket-sharp")]
[assembly: AssemblyDescription("A C# implementation of the WebSocket protocol client and server")]
[assembly: AssemblyDescription("A C# implementation of a WebSocket protocol client")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("websocket-sharp.dll")]
@ -17,10 +17,11 @@ using System.Runtime.CompilerServices;
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.2.*")]
[assembly: AssemblyVersion("0.9.9.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@ -1,113 +0,0 @@
#region License
/*
* CloseEventArgs.cs
*
* The MIT License
*
* Copyright (c) 2012-2019 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp
{
/// <summary>
/// Represents the event data for the <see cref="WebSocket.OnClose"/> event.
/// </summary>
/// <remarks>
/// <para>
/// That event occurs when the WebSocket connection has been closed.
/// </para>
/// <para>
/// If you would like to get the reason for the connection close, you should
/// access the <see cref="Code"/> or <see cref="Reason"/> property.
/// </para>
/// </remarks>
public class CloseEventArgs : EventArgs
{
#region Private Fields
private bool _clean;
private PayloadData _payloadData;
#endregion
#region Internal Constructors
internal CloseEventArgs (PayloadData payloadData, bool clean)
{
_payloadData = payloadData;
_clean = clean;
}
internal CloseEventArgs (ushort code, string reason, bool clean)
{
_payloadData = new PayloadData (code, reason);
_clean = clean;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the status code for the connection close.
/// </summary>
/// <value>
/// A <see cref="ushort"/> that represents the status code for
/// the connection close if present.
/// </value>
public ushort Code {
get {
return _payloadData.Code;
}
}
/// <summary>
/// Gets the reason for the connection close.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the reason for
/// the connection close if present.
/// </value>
public string Reason {
get {
return _payloadData.Reason;
}
}
/// <summary>
/// Gets a value indicating whether the connection has been closed cleanly.
/// </summary>
/// <value>
/// <c>true</c> if the connection has been closed cleanly; otherwise,
/// <c>false</c>.
/// </value>
public bool WasClean {
get {
return _clean;
}
}
#endregion
}
}

View File

@ -1,120 +0,0 @@
#region License
/*
* CloseStatusCode.cs
*
* The MIT License
*
* Copyright (c) 2012-2016 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp
{
/// <summary>
/// Indicates the status code for the WebSocket connection close.
/// </summary>
/// <remarks>
/// <para>
/// The values of this enumeration are defined in
/// <see href="http://tools.ietf.org/html/rfc6455#section-7.4">
/// Section 7.4</see> of RFC 6455.
/// </para>
/// <para>
/// "Reserved value" cannot be sent as a status code in
/// closing handshake by an endpoint.
/// </para>
/// </remarks>
public enum CloseStatusCode : ushort
{
/// <summary>
/// Equivalent to close status 1000. Indicates normal close.
/// </summary>
Normal = 1000,
/// <summary>
/// Equivalent to close status 1001. Indicates that an endpoint is
/// going away.
/// </summary>
Away = 1001,
/// <summary>
/// Equivalent to close status 1002. Indicates that an endpoint is
/// terminating the connection due to a protocol error.
/// </summary>
ProtocolError = 1002,
/// <summary>
/// Equivalent to close status 1003. Indicates that an endpoint is
/// terminating the connection because it has received a type of
/// data that it cannot accept.
/// </summary>
UnsupportedData = 1003,
/// <summary>
/// Equivalent to close status 1004. Still undefined. A Reserved value.
/// </summary>
Undefined = 1004,
/// <summary>
/// Equivalent to close status 1005. Indicates that no status code was
/// actually present. A Reserved value.
/// </summary>
NoStatus = 1005,
/// <summary>
/// Equivalent to close status 1006. Indicates that the connection was
/// closed abnormally. A Reserved value.
/// </summary>
Abnormal = 1006,
/// <summary>
/// Equivalent to close status 1007. Indicates that an endpoint is
/// terminating the connection because it has received a message that
/// contains data that is not consistent with the type of the message.
/// </summary>
InvalidData = 1007,
/// <summary>
/// Equivalent to close status 1008. Indicates that an endpoint is
/// terminating the connection because it has received a message that
/// violates its policy.
/// </summary>
PolicyViolation = 1008,
/// <summary>
/// Equivalent to close status 1009. Indicates that an endpoint is
/// terminating the connection because it has received a message that
/// is too big to process.
/// </summary>
TooBig = 1009,
/// <summary>
/// Equivalent to close status 1010. Indicates that a client is
/// terminating the connection because it has expected the server to
/// negotiate one or more extension, but the server did not return
/// them in the handshake response.
/// </summary>
MandatoryExtension = 1010,
/// <summary>
/// Equivalent to close status 1011. Indicates that a server is
/// terminating the connection because it has encountered an unexpected
/// condition that prevented it from fulfilling the request.
/// </summary>
ServerError = 1011,
/// <summary>
/// Equivalent to close status 1015. Indicates that the connection was
/// closed due to a failure to perform a TLS handshake. A Reserved value.
/// </summary>
TlsHandshakeFailure = 1015
}
}

View File

@ -1,52 +0,0 @@
#region License
/*
* CompressionMethod.cs
*
* The MIT License
*
* Copyright (c) 2013-2017 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp
{
/// <summary>
/// Specifies the method for compression.
/// </summary>
/// <remarks>
/// The methods are defined in
/// <see href="https://tools.ietf.org/html/rfc7692">
/// Compression Extensions for WebSocket</see>.
/// </remarks>
public enum CompressionMethod : byte
{
/// <summary>
/// Specifies no compression.
/// </summary>
None,
/// <summary>
/// Specifies DEFLATE.
/// </summary>
Deflate
}
}

View File

@ -1,109 +0,0 @@
#region License
/*
* ErrorEventArgs.cs
*
* The MIT License
*
* Copyright (c) 2012-2016 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Contributors
/*
* Contributors:
* - Frank Razenberg <frank@zzattack.org>
*/
#endregion
using System;
namespace WebSocketSharp
{
/// <summary>
/// Represents the event data for the <see cref="WebSocket.OnError"/> event.
/// </summary>
/// <remarks>
/// <para>
/// That event occurs when the <see cref="WebSocket"/> gets an error.
/// </para>
/// <para>
/// If you would like to get the error message, you should access
/// the <see cref="ErrorEventArgs.Message"/> property.
/// </para>
/// <para>
/// And if the error is due to an exception, you can get it by accessing
/// the <see cref="ErrorEventArgs.Exception"/> property.
/// </para>
/// </remarks>
public class ErrorEventArgs : EventArgs
{
#region Private Fields
private Exception _exception;
private string _message;
#endregion
#region Internal Constructors
internal ErrorEventArgs (string message)
: this (message, null)
{
}
internal ErrorEventArgs (string message, Exception exception)
{
_message = message;
_exception = exception;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the exception that caused the error.
/// </summary>
/// <value>
/// An <see cref="System.Exception"/> instance that represents the cause of
/// the error if it is due to an exception; otherwise, <see langword="null"/>.
/// </value>
public Exception Exception {
get {
return _exception;
}
}
/// <summary>
/// Gets the error message.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the error message.
/// </value>
public string Message {
get {
return _message;
}
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,51 +0,0 @@
#region License
/*
* Fin.cs
*
* The MIT License
*
* Copyright (c) 2012-2015 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp
{
/// <summary>
/// Indicates whether a WebSocket frame is the final frame of a message.
/// </summary>
/// <remarks>
/// The values of this enumeration are defined in
/// <see href="http://tools.ietf.org/html/rfc6455#section-5.2">Section 5.2</see> of RFC 6455.
/// </remarks>
internal enum Fin : byte
{
/// <summary>
/// Equivalent to numeric value 0. Indicates more frames of a message follow.
/// </summary>
More = 0x0,
/// <summary>
/// Equivalent to numeric value 1. Indicates the final frame of a message.
/// </summary>
Final = 0x1
}
}

View File

@ -1,208 +0,0 @@
#region License
/*
* HttpBase.cs
*
* The MIT License
*
* Copyright (c) 2012-2014 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using System.Threading;
using WebSocketSharp.Net;
namespace WebSocketSharp
{
internal abstract class HttpBase
{
#region Private Fields
private NameValueCollection _headers;
private const int _headersMaxLength = 8192;
private Version _version;
#endregion
#region Internal Fields
internal byte[] EntityBodyData;
#endregion
#region Protected Fields
protected const string CrLf = "\r\n";
#endregion
#region Protected Constructors
protected HttpBase (Version version, NameValueCollection headers)
{
_version = version;
_headers = headers;
}
#endregion
#region Public Properties
public string EntityBody {
get {
if (EntityBodyData == null || EntityBodyData.LongLength == 0)
return String.Empty;
Encoding enc = null;
var contentType = _headers["Content-Type"];
if (contentType != null && contentType.Length > 0)
enc = HttpUtility.GetEncoding (contentType);
return (enc ?? Encoding.UTF8).GetString (EntityBodyData);
}
}
public NameValueCollection Headers {
get {
return _headers;
}
}
public Version ProtocolVersion {
get {
return _version;
}
}
#endregion
#region Private Methods
private static byte[] readEntityBody (Stream stream, string length)
{
long len;
if (!Int64.TryParse (length, out len))
throw new ArgumentException ("Cannot be parsed.", "length");
if (len < 0)
throw new ArgumentOutOfRangeException ("length", "Less than zero.");
return len > 1024
? stream.ReadBytes (len, 1024)
: len > 0
? stream.ReadBytes ((int) len)
: null;
}
private static string[] readHeaders (Stream stream, int maxLength)
{
var buff = new List<byte> ();
var cnt = 0;
Action<int> add = i => {
if (i == -1)
throw new EndOfStreamException ("The header cannot be read from the data source.");
buff.Add ((byte) i);
cnt++;
};
var read = false;
while (cnt < maxLength) {
if (stream.ReadByte ().EqualsWith ('\r', add) &&
stream.ReadByte ().EqualsWith ('\n', add) &&
stream.ReadByte ().EqualsWith ('\r', add) &&
stream.ReadByte ().EqualsWith ('\n', add)) {
read = true;
break;
}
}
if (!read)
throw new WebSocketException ("The length of header part is greater than the max length.");
return Encoding.UTF8.GetString (buff.ToArray ())
.Replace (CrLf + " ", " ")
.Replace (CrLf + "\t", " ")
.Split (new[] { CrLf }, StringSplitOptions.RemoveEmptyEntries);
}
#endregion
#region Protected Methods
protected static T Read<T> (Stream stream, Func<string[], T> parser, int millisecondsTimeout)
where T : HttpBase
{
var timeout = false;
var timer = new Timer (
state => {
timeout = true;
stream.Close ();
},
null,
millisecondsTimeout,
-1);
T http = null;
Exception exception = null;
try {
http = parser (readHeaders (stream, _headersMaxLength));
var contentLen = http.Headers["Content-Length"];
if (contentLen != null && contentLen.Length > 0)
http.EntityBodyData = readEntityBody (stream, contentLen);
}
catch (Exception ex) {
exception = ex;
}
finally {
timer.Change (-1, -1);
timer.Dispose ();
}
var msg = timeout
? "A timeout has occurred while reading an HTTP request/response."
: exception != null
? "An exception has occurred while reading an HTTP request/response."
: null;
if (msg != null)
throw new WebSocketException (msg, exception);
return http;
}
#endregion
#region Public Methods
public byte[] ToByteArray ()
{
return Encoding.UTF8.GetBytes (ToString ());
}
#endregion
}
}

View File

@ -1,217 +0,0 @@
#region License
/*
* HttpRequest.cs
*
* The MIT License
*
* Copyright (c) 2012-2015 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Contributors
/*
* Contributors:
* - David Burhans
*/
#endregion
using System;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using WebSocketSharp.Net;
namespace WebSocketSharp
{
internal class HttpRequest : HttpBase
{
#region Private Fields
private CookieCollection _cookies;
private string _method;
private string _uri;
#endregion
#region Private Constructors
private HttpRequest (string method, string uri, Version version, NameValueCollection headers)
: base (version, headers)
{
_method = method;
_uri = uri;
}
#endregion
#region Internal Constructors
internal HttpRequest (string method, string uri)
: this (method, uri, HttpVersion.Version11, new NameValueCollection ())
{
Headers["User-Agent"] = "websocket-sharp/1.0";
}
#endregion
#region Public Properties
public AuthenticationResponse AuthenticationResponse {
get {
var res = Headers["Authorization"];
return res != null && res.Length > 0
? AuthenticationResponse.Parse (res)
: null;
}
}
public CookieCollection Cookies {
get {
if (_cookies == null)
_cookies = Headers.GetCookies (false);
return _cookies;
}
}
public string HttpMethod {
get {
return _method;
}
}
public bool IsWebSocketRequest {
get {
return _method == "GET"
&& ProtocolVersion > HttpVersion.Version10
&& Headers.Upgrades ("websocket");
}
}
public string RequestUri {
get {
return _uri;
}
}
#endregion
#region Internal Methods
internal static HttpRequest CreateConnectRequest (Uri uri)
{
var host = uri.DnsSafeHost;
var port = uri.Port;
var authority = String.Format ("{0}:{1}", host, port);
var req = new HttpRequest ("CONNECT", authority);
req.Headers["Host"] = port == 80 ? host : authority;
return req;
}
internal static HttpRequest CreateWebSocketRequest (Uri uri)
{
var req = new HttpRequest ("GET", uri.PathAndQuery);
var headers = req.Headers;
// Only includes a port number in the Host header value if it's non-default.
// See: https://tools.ietf.org/html/rfc6455#page-17
var port = uri.Port;
var schm = uri.Scheme;
headers["Host"] = (port == 80 && schm == "ws") || (port == 443 && schm == "wss")
? uri.DnsSafeHost
: uri.Authority;
headers["Upgrade"] = "websocket";
headers["Connection"] = "Upgrade";
return req;
}
internal HttpResponse GetResponse (Stream stream, int millisecondsTimeout)
{
var buff = ToByteArray ();
stream.Write (buff, 0, buff.Length);
return Read<HttpResponse> (stream, HttpResponse.Parse, millisecondsTimeout);
}
internal static HttpRequest Parse (string[] headerParts)
{
var requestLine = headerParts[0].Split (new[] { ' ' }, 3);
if (requestLine.Length != 3)
throw new ArgumentException ("Invalid request line: " + headerParts[0]);
var headers = new WebHeaderCollection ();
for (int i = 1; i < headerParts.Length; i++)
headers.InternalSet (headerParts[i], false);
return new HttpRequest (
requestLine[0], requestLine[1], new Version (requestLine[2].Substring (5)), headers);
}
internal static HttpRequest Read (Stream stream, int millisecondsTimeout)
{
return Read<HttpRequest> (stream, Parse, millisecondsTimeout);
}
#endregion
#region Public Methods
public void SetCookies (CookieCollection cookies)
{
if (cookies == null || cookies.Count == 0)
return;
var buff = new StringBuilder (64);
foreach (var cookie in cookies.Sorted)
if (!cookie.Expired)
buff.AppendFormat ("{0}; ", cookie.ToString ());
var len = buff.Length;
if (len > 2) {
buff.Length = len - 2;
Headers["Cookie"] = buff.ToString ();
}
}
public override string ToString ()
{
var output = new StringBuilder (64);
output.AppendFormat ("{0} {1} HTTP/{2}{3}", _method, _uri, ProtocolVersion, CrLf);
var headers = Headers;
foreach (var key in headers.AllKeys)
output.AppendFormat ("{0}: {1}{2}", key, headers[key], CrLf);
output.Append (CrLf);
var entity = EntityBody;
if (entity.Length > 0)
output.Append (entity);
return output.ToString ();
}
#endregion
}
}

View File

@ -1,209 +0,0 @@
#region License
/*
* HttpResponse.cs
*
* The MIT License
*
* Copyright (c) 2012-2014 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using WebSocketSharp.Net;
namespace WebSocketSharp
{
internal class HttpResponse : HttpBase
{
#region Private Fields
private string _code;
private string _reason;
#endregion
#region Private Constructors
private HttpResponse (string code, string reason, Version version, NameValueCollection headers)
: base (version, headers)
{
_code = code;
_reason = reason;
}
#endregion
#region Internal Constructors
internal HttpResponse (HttpStatusCode code)
: this (code, code.GetDescription ())
{
}
internal HttpResponse (HttpStatusCode code, string reason)
: this (((int) code).ToString (), reason, HttpVersion.Version11, new NameValueCollection ())
{
Headers["Server"] = "websocket-sharp/1.0";
}
#endregion
#region Public Properties
public CookieCollection Cookies {
get {
return Headers.GetCookies (true);
}
}
public bool HasConnectionClose {
get {
var comparison = StringComparison.OrdinalIgnoreCase;
return Headers.Contains ("Connection", "close", comparison);
}
}
public bool IsProxyAuthenticationRequired {
get {
return _code == "407";
}
}
public bool IsRedirect {
get {
return _code == "301" || _code == "302";
}
}
public bool IsUnauthorized {
get {
return _code == "401";
}
}
public bool IsWebSocketResponse {
get {
return ProtocolVersion > HttpVersion.Version10
&& _code == "101"
&& Headers.Upgrades ("websocket");
}
}
public string Reason {
get {
return _reason;
}
}
public string StatusCode {
get {
return _code;
}
}
#endregion
#region Internal Methods
internal static HttpResponse CreateCloseResponse (HttpStatusCode code)
{
var res = new HttpResponse (code);
res.Headers["Connection"] = "close";
return res;
}
internal static HttpResponse CreateUnauthorizedResponse (string challenge)
{
var res = new HttpResponse (HttpStatusCode.Unauthorized);
res.Headers["WWW-Authenticate"] = challenge;
return res;
}
internal static HttpResponse CreateWebSocketResponse ()
{
var res = new HttpResponse (HttpStatusCode.SwitchingProtocols);
var headers = res.Headers;
headers["Upgrade"] = "websocket";
headers["Connection"] = "Upgrade";
return res;
}
internal static HttpResponse Parse (string[] headerParts)
{
var statusLine = headerParts[0].Split (new[] { ' ' }, 3);
if (statusLine.Length != 3)
throw new ArgumentException ("Invalid status line: " + headerParts[0]);
var headers = new WebHeaderCollection ();
for (int i = 1; i < headerParts.Length; i++)
headers.InternalSet (headerParts[i], true);
return new HttpResponse (
statusLine[1], statusLine[2], new Version (statusLine[0].Substring (5)), headers);
}
internal static HttpResponse Read (Stream stream, int millisecondsTimeout)
{
return Read<HttpResponse> (stream, Parse, millisecondsTimeout);
}
#endregion
#region Public Methods
public void SetCookies (CookieCollection cookies)
{
if (cookies == null || cookies.Count == 0)
return;
var headers = Headers;
foreach (var cookie in cookies.Sorted)
headers.Add ("Set-Cookie", cookie.ToResponseString ());
}
public override string ToString ()
{
var output = new StringBuilder (64);
output.AppendFormat ("HTTP/{0} {1} {2}{3}", ProtocolVersion, _code, _reason, CrLf);
var headers = Headers;
foreach (var key in headers.AllKeys)
output.AppendFormat ("{0}: {1}{2}", key, headers[key], CrLf);
output.Append (CrLf);
var entity = EntityBody;
if (entity.Length > 0)
output.Append (entity);
return output.ToString ();
}
#endregion
}
}

View File

@ -1,11 +1,11 @@
#region License
/*
* ByteOrder.cs
#region MIT License
/**
* IWsStream.cs
*
* The MIT License
*
* Copyright (c) 2012-2015 sta.blockhead
*
* Copyright (c) 2010 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
@ -15,7 +15,7 @@
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -30,18 +30,12 @@ using System;
namespace WebSocketSharp
{
/// <summary>
/// Specifies the byte order.
/// </summary>
public enum ByteOrder
public interface IWsStream : IDisposable
{
/// <summary>
/// Specifies Little-endian.
/// </summary>
Little,
/// <summary>
/// Specifies Big-endian.
/// </summary>
Big
void Close();
int Read(byte[] buffer, int offset, int size);
int ReadByte();
void Write(byte[] buffer, int offset, int count);
void WriteByte(byte value);
}
}

View File

@ -1,149 +0,0 @@
#region License
/*
* LogData.cs
*
* The MIT License
*
* Copyright (c) 2013-2015 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Diagnostics;
using System.Text;
namespace WebSocketSharp
{
/// <summary>
/// Represents a log data used by the <see cref="Logger"/> class.
/// </summary>
public class LogData
{
#region Private Fields
private StackFrame _caller;
private DateTime _date;
private LogLevel _level;
private string _message;
#endregion
#region Internal Constructors
internal LogData (LogLevel level, StackFrame caller, string message)
{
_level = level;
_caller = caller;
_message = message ?? String.Empty;
_date = DateTime.Now;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the information of the logging method caller.
/// </summary>
/// <value>
/// A <see cref="StackFrame"/> that provides the information of the logging method caller.
/// </value>
public StackFrame Caller {
get {
return _caller;
}
}
/// <summary>
/// Gets the date and time when the log data was created.
/// </summary>
/// <value>
/// A <see cref="DateTime"/> that represents the date and time when the log data was created.
/// </value>
public DateTime Date {
get {
return _date;
}
}
/// <summary>
/// Gets the logging level of the log data.
/// </summary>
/// <value>
/// One of the <see cref="LogLevel"/> enum values, indicates the logging level of the log data.
/// </value>
public LogLevel Level {
get {
return _level;
}
}
/// <summary>
/// Gets the message of the log data.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the message of the log data.
/// </value>
public string Message {
get {
return _message;
}
}
#endregion
#region Public Methods
/// <summary>
/// Returns a <see cref="string"/> that represents the current <see cref="LogData"/>.
/// </summary>
/// <returns>
/// A <see cref="string"/> that represents the current <see cref="LogData"/>.
/// </returns>
public override string ToString ()
{
var header = String.Format ("{0}|{1,-5}|", _date, _level);
var method = _caller.GetMethod ();
var type = method.DeclaringType;
#if DEBUG
var lineNum = _caller.GetFileLineNumber ();
var headerAndCaller =
String.Format ("{0}{1}.{2}:{3}|", header, type.Name, method.Name, lineNum);
#else
var headerAndCaller = String.Format ("{0}{1}.{2}|", header, type.Name, method.Name);
#endif
var msgs = _message.Replace ("\r\n", "\n").TrimEnd ('\n').Split ('\n');
if (msgs.Length <= 1)
return String.Format ("{0}{1}", headerAndCaller, _message);
var buff = new StringBuilder (String.Format ("{0}{1}\n", headerAndCaller, msgs[0]), 64);
var fmt = String.Format ("{{0,{0}}}{{1}}\n", header.Length);
for (var i = 1; i < msgs.Length; i++)
buff.AppendFormat (fmt, "", msgs[i]);
buff.Length--;
return buff.ToString ();
}
#endregion
}
}

View File

@ -1,63 +0,0 @@
#region License
/*
* LogLevel.cs
*
* The MIT License
*
* Copyright (c) 2013-2015 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp
{
/// <summary>
/// Specifies the logging level.
/// </summary>
public enum LogLevel
{
/// <summary>
/// Specifies the bottom logging level.
/// </summary>
Trace,
/// <summary>
/// Specifies the 2nd logging level from the bottom.
/// </summary>
Debug,
/// <summary>
/// Specifies the 3rd logging level from the bottom.
/// </summary>
Info,
/// <summary>
/// Specifies the 3rd logging level from the top.
/// </summary>
Warn,
/// <summary>
/// Specifies the 2nd logging level from the top.
/// </summary>
Error,
/// <summary>
/// Specifies the top logging level.
/// </summary>
Fatal
}
}

View File

@ -1,330 +0,0 @@
#region License
/*
* Logger.cs
*
* The MIT License
*
* Copyright (c) 2013-2015 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Diagnostics;
using System.IO;
namespace WebSocketSharp
{
/// <summary>
/// Provides a set of methods and properties for logging.
/// </summary>
/// <remarks>
/// <para>
/// If you output a log with lower than the value of the <see cref="Logger.Level"/> property,
/// it cannot be outputted.
/// </para>
/// <para>
/// The default output action writes a log to the standard output stream and the log file
/// if the <see cref="Logger.File"/> property has a valid path to it.
/// </para>
/// <para>
/// If you would like to use the custom output action, you should set
/// the <see cref="Logger.Output"/> property to any <c>Action&lt;LogData, string&gt;</c>
/// delegate.
/// </para>
/// </remarks>
public class Logger
{
#region Private Fields
private volatile string _file;
private volatile LogLevel _level;
private Action<LogData, string> _output;
private object _sync;
#endregion
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="Logger"/> class.
/// </summary>
/// <remarks>
/// This constructor initializes the current logging level with <see cref="LogLevel.Error"/>.
/// </remarks>
public Logger ()
: this (LogLevel.Error, null, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Logger"/> class with
/// the specified logging <paramref name="level"/>.
/// </summary>
/// <param name="level">
/// One of the <see cref="LogLevel"/> enum values.
/// </param>
public Logger (LogLevel level)
: this (level, null, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Logger"/> class with
/// the specified logging <paramref name="level"/>, path to the log <paramref name="file"/>,
/// and <paramref name="output"/> action.
/// </summary>
/// <param name="level">
/// One of the <see cref="LogLevel"/> enum values.
/// </param>
/// <param name="file">
/// A <see cref="string"/> that represents the path to the log file.
/// </param>
/// <param name="output">
/// An <c>Action&lt;LogData, string&gt;</c> delegate that references the method(s) used to
/// output a log. A <see cref="string"/> parameter passed to this delegate is
/// <paramref name="file"/>.
/// </param>
public Logger (LogLevel level, string file, Action<LogData, string> output)
{
_level = level;
_file = file;
_output = output ?? defaultOutput;
_sync = new object ();
}
#endregion
#region Public Properties
/// <summary>
/// Gets or sets the current path to the log file.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the current path to the log file if any.
/// </value>
public string File {
get {
return _file;
}
set {
lock (_sync) {
_file = value;
Warn (
String.Format ("The current path to the log file has been changed to {0}.", _file));
}
}
}
/// <summary>
/// Gets or sets the current logging level.
/// </summary>
/// <remarks>
/// A log with lower than the value of this property cannot be outputted.
/// </remarks>
/// <value>
/// One of the <see cref="LogLevel"/> enum values, specifies the current logging level.
/// </value>
public LogLevel Level {
get {
return _level;
}
set {
lock (_sync) {
_level = value;
Warn (String.Format ("The current logging level has been changed to {0}.", _level));
}
}
}
/// <summary>
/// Gets or sets the current output action used to output a log.
/// </summary>
/// <value>
/// <para>
/// An <c>Action&lt;LogData, string&gt;</c> delegate that references the method(s) used to
/// output a log. A <see cref="string"/> parameter passed to this delegate is the value of
/// the <see cref="Logger.File"/> property.
/// </para>
/// <para>
/// If the value to set is <see langword="null"/>, the current output action is changed to
/// the default output action.
/// </para>
/// </value>
public Action<LogData, string> Output {
get {
return _output;
}
set {
lock (_sync) {
_output = value ?? defaultOutput;
Warn ("The current output action has been changed.");
}
}
}
#endregion
#region Private Methods
private static void defaultOutput (LogData data, string path)
{
var log = data.ToString ();
Console.WriteLine (log);
if (path != null && path.Length > 0)
writeToFile (log, path);
}
private void output (string message, LogLevel level)
{
lock (_sync) {
if (_level > level)
return;
LogData data = null;
try {
data = new LogData (level, new StackFrame (2, true), message);
_output (data, _file);
}
catch (Exception ex) {
data = new LogData (LogLevel.Fatal, new StackFrame (0, true), ex.Message);
Console.WriteLine (data.ToString ());
}
}
}
private static void writeToFile (string value, string path)
{
using (var writer = new StreamWriter (path, true))
using (var syncWriter = TextWriter.Synchronized (writer))
syncWriter.WriteLine (value);
}
#endregion
#region Public Methods
/// <summary>
/// Outputs <paramref name="message"/> as a log with <see cref="LogLevel.Debug"/>.
/// </summary>
/// <remarks>
/// If the current logging level is higher than <see cref="LogLevel.Debug"/>,
/// this method doesn't output <paramref name="message"/> as a log.
/// </remarks>
/// <param name="message">
/// A <see cref="string"/> that represents the message to output as a log.
/// </param>
public void Debug (string message)
{
if (_level > LogLevel.Debug)
return;
output (message, LogLevel.Debug);
}
/// <summary>
/// Outputs <paramref name="message"/> as a log with <see cref="LogLevel.Error"/>.
/// </summary>
/// <remarks>
/// If the current logging level is higher than <see cref="LogLevel.Error"/>,
/// this method doesn't output <paramref name="message"/> as a log.
/// </remarks>
/// <param name="message">
/// A <see cref="string"/> that represents the message to output as a log.
/// </param>
public void Error (string message)
{
if (_level > LogLevel.Error)
return;
output (message, LogLevel.Error);
}
/// <summary>
/// Outputs <paramref name="message"/> as a log with <see cref="LogLevel.Fatal"/>.
/// </summary>
/// <param name="message">
/// A <see cref="string"/> that represents the message to output as a log.
/// </param>
public void Fatal (string message)
{
output (message, LogLevel.Fatal);
}
/// <summary>
/// Outputs <paramref name="message"/> as a log with <see cref="LogLevel.Info"/>.
/// </summary>
/// <remarks>
/// If the current logging level is higher than <see cref="LogLevel.Info"/>,
/// this method doesn't output <paramref name="message"/> as a log.
/// </remarks>
/// <param name="message">
/// A <see cref="string"/> that represents the message to output as a log.
/// </param>
public void Info (string message)
{
if (_level > LogLevel.Info)
return;
output (message, LogLevel.Info);
}
/// <summary>
/// Outputs <paramref name="message"/> as a log with <see cref="LogLevel.Trace"/>.
/// </summary>
/// <remarks>
/// If the current logging level is higher than <see cref="LogLevel.Trace"/>,
/// this method doesn't output <paramref name="message"/> as a log.
/// </remarks>
/// <param name="message">
/// A <see cref="string"/> that represents the message to output as a log.
/// </param>
public void Trace (string message)
{
if (_level > LogLevel.Trace)
return;
output (message, LogLevel.Trace);
}
/// <summary>
/// Outputs <paramref name="message"/> as a log with <see cref="LogLevel.Warn"/>.
/// </summary>
/// <remarks>
/// If the current logging level is higher than <see cref="LogLevel.Warn"/>,
/// this method doesn't output <paramref name="message"/> as a log.
/// </remarks>
/// <param name="message">
/// A <see cref="string"/> that represents the message to output as a log.
/// </param>
public void Warn (string message)
{
if (_level > LogLevel.Warn)
return;
output (message, LogLevel.Warn);
}
#endregion
}
}

View File

@ -1,51 +0,0 @@
#region License
/*
* Mask.cs
*
* The MIT License
*
* Copyright (c) 2012-2015 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp
{
/// <summary>
/// Indicates whether the payload data of a WebSocket frame is masked.
/// </summary>
/// <remarks>
/// The values of this enumeration are defined in
/// <see href="http://tools.ietf.org/html/rfc6455#section-5.2">Section 5.2</see> of RFC 6455.
/// </remarks>
internal enum Mask : byte
{
/// <summary>
/// Equivalent to numeric value 0. Indicates not masked.
/// </summary>
Off = 0x0,
/// <summary>
/// Equivalent to numeric value 1. Indicates masked.
/// </summary>
On = 0x1
}
}

View File

@ -1,183 +0,0 @@
#region License
/*
* MessageEventArgs.cs
*
* The MIT License
*
* Copyright (c) 2012-2016 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp
{
/// <summary>
/// Represents the event data for the <see cref="WebSocket.OnMessage"/> event.
/// </summary>
/// <remarks>
/// <para>
/// That event occurs when the <see cref="WebSocket"/> receives
/// a message or a ping if the <see cref="WebSocket.EmitOnPing"/>
/// property is set to <c>true</c>.
/// </para>
/// <para>
/// If you would like to get the message data, you should access
/// the <see cref="Data"/> or <see cref="RawData"/> property.
/// </para>
/// </remarks>
public class MessageEventArgs : EventArgs
{
#region Private Fields
private string _data;
private bool _dataSet;
private Opcode _opcode;
private byte[] _rawData;
#endregion
#region Internal Constructors
internal MessageEventArgs (WebSocketFrame frame)
{
_opcode = frame.Opcode;
_rawData = frame.PayloadData.ApplicationData;
}
internal MessageEventArgs (Opcode opcode, byte[] rawData)
{
if ((ulong) rawData.LongLength > PayloadData.MaxLength)
throw new WebSocketException (CloseStatusCode.TooBig);
_opcode = opcode;
_rawData = rawData;
}
#endregion
#region Internal Properties
/// <summary>
/// Gets the opcode for the message.
/// </summary>
/// <value>
/// <see cref="Opcode.Text"/>, <see cref="Opcode.Binary"/>,
/// or <see cref="Opcode.Ping"/>.
/// </value>
internal Opcode Opcode {
get {
return _opcode;
}
}
#endregion
#region Public Properties
/// <summary>
/// Gets the message data as a <see cref="string"/>.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the message data if its type is
/// text or ping and if decoding it to a string has successfully done;
/// otherwise, <see langword="null"/>.
/// </value>
public string Data {
get {
setData ();
return _data;
}
}
/// <summary>
/// Gets a value indicating whether the message type is binary.
/// </summary>
/// <value>
/// <c>true</c> if the message type is binary; otherwise, <c>false</c>.
/// </value>
public bool IsBinary {
get {
return _opcode == Opcode.Binary;
}
}
/// <summary>
/// Gets a value indicating whether the message type is ping.
/// </summary>
/// <value>
/// <c>true</c> if the message type is ping; otherwise, <c>false</c>.
/// </value>
public bool IsPing {
get {
return _opcode == Opcode.Ping;
}
}
/// <summary>
/// Gets a value indicating whether the message type is text.
/// </summary>
/// <value>
/// <c>true</c> if the message type is text; otherwise, <c>false</c>.
/// </value>
public bool IsText {
get {
return _opcode == Opcode.Text;
}
}
/// <summary>
/// Gets the message data as an array of <see cref="byte"/>.
/// </summary>
/// <value>
/// An array of <see cref="byte"/> that represents the message data.
/// </value>
public byte[] RawData {
get {
setData ();
return _rawData;
}
}
#endregion
#region Private Methods
private void setData ()
{
if (_dataSet)
return;
if (_opcode == Opcode.Binary) {
_dataSet = true;
return;
}
string data;
if (_rawData.TryGetUTF8DecodedString (out data))
_data = data;
_dataSet = true;
}
#endregion
}
}

View File

@ -1,151 +0,0 @@
#region License
/*
* AuthenticationBase.cs
*
* The MIT License
*
* Copyright (c) 2014 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Collections.Specialized;
using System.Text;
namespace WebSocketSharp.Net
{
internal abstract class AuthenticationBase
{
#region Private Fields
private AuthenticationSchemes _scheme;
#endregion
#region Internal Fields
internal NameValueCollection Parameters;
#endregion
#region Protected Constructors
protected AuthenticationBase (AuthenticationSchemes scheme, NameValueCollection parameters)
{
_scheme = scheme;
Parameters = parameters;
}
#endregion
#region Public Properties
public string Algorithm {
get {
return Parameters["algorithm"];
}
}
public string Nonce {
get {
return Parameters["nonce"];
}
}
public string Opaque {
get {
return Parameters["opaque"];
}
}
public string Qop {
get {
return Parameters["qop"];
}
}
public string Realm {
get {
return Parameters["realm"];
}
}
public AuthenticationSchemes Scheme {
get {
return _scheme;
}
}
#endregion
#region Internal Methods
internal static string CreateNonceValue ()
{
var src = new byte[16];
var rand = new Random ();
rand.NextBytes (src);
var res = new StringBuilder (32);
foreach (var b in src)
res.Append (b.ToString ("x2"));
return res.ToString ();
}
internal static NameValueCollection ParseParameters (string value)
{
var res = 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;
res.Add (name, val);
}
return res;
}
internal abstract string ToBasicString ();
internal abstract string ToDigestString ();
#endregion
#region Public Methods
public override string ToString ()
{
return _scheme == AuthenticationSchemes.Basic
? ToBasicString ()
: _scheme == AuthenticationSchemes.Digest
? ToDigestString ()
: String.Empty;
}
#endregion
}
}

View File

@ -1,146 +0,0 @@
#region License
/*
* AuthenticationChallenge.cs
*
* The MIT License
*
* Copyright (c) 2013-2014 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Collections.Specialized;
using System.Text;
namespace WebSocketSharp.Net
{
internal class AuthenticationChallenge : AuthenticationBase
{
#region Private Constructors
private AuthenticationChallenge (AuthenticationSchemes scheme, NameValueCollection parameters)
: base (scheme, parameters)
{
}
#endregion
#region Internal Constructors
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";
}
}
#endregion
#region Public Properties
public string Domain {
get {
return Parameters["domain"];
}
}
public string Stale {
get {
return Parameters["stale"];
}
}
#endregion
#region Internal Methods
internal static AuthenticationChallenge CreateBasicChallenge (string realm)
{
return new AuthenticationChallenge (AuthenticationSchemes.Basic, realm);
}
internal static AuthenticationChallenge CreateDigestChallenge (string realm)
{
return new AuthenticationChallenge (AuthenticationSchemes.Digest, realm);
}
internal static AuthenticationChallenge Parse (string value)
{
var chal = value.Split (new[] { ' ' }, 2);
if (chal.Length != 2)
return null;
var schm = chal[0].ToLower ();
return schm == "basic"
? new AuthenticationChallenge (
AuthenticationSchemes.Basic, ParseParameters (chal[1]))
: schm == "digest"
? new AuthenticationChallenge (
AuthenticationSchemes.Digest, ParseParameters (chal[1]))
: null;
}
internal override string ToBasicString ()
{
return String.Format ("Basic realm=\"{0}\"", Parameters["realm"]);
}
internal override string ToDigestString ()
{
var output = new StringBuilder (128);
var domain = Parameters["domain"];
if (domain != null)
output.AppendFormat (
"Digest realm=\"{0}\", domain=\"{1}\", nonce=\"{2}\"",
Parameters["realm"],
domain,
Parameters["nonce"]);
else
output.AppendFormat (
"Digest realm=\"{0}\", nonce=\"{1}\"", Parameters["realm"], Parameters["nonce"]);
var opaque = Parameters["opaque"];
if (opaque != null)
output.AppendFormat (", opaque=\"{0}\"", opaque);
var stale = Parameters["stale"];
if (stale != null)
output.AppendFormat (", stale={0}", stale);
var algo = Parameters["algorithm"];
if (algo != null)
output.AppendFormat (", algorithm={0}", algo);
var qop = Parameters["qop"];
if (qop != null)
output.AppendFormat (", qop=\"{0}\"", qop);
return output.ToString ();
}
#endregion
}
}

View File

@ -1,323 +0,0 @@
#region License
/*
* AuthenticationResponse.cs
*
* ParseBasicCredentials is derived from System.Net.HttpListenerContext.cs of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2013-2014 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Collections.Specialized;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
namespace WebSocketSharp.Net
{
internal class AuthenticationResponse : AuthenticationBase
{
#region Private Fields
private uint _nonceCount;
#endregion
#region Private Constructors
private AuthenticationResponse (AuthenticationSchemes scheme, NameValueCollection parameters)
: base (scheme, parameters)
{
}
#endregion
#region Internal Constructors
internal AuthenticationResponse (NetworkCredential credentials)
: this (AuthenticationSchemes.Basic, new NameValueCollection (), credentials, 0)
{
}
internal AuthenticationResponse (
AuthenticationChallenge challenge, NetworkCredential credentials, uint nonceCount)
: this (challenge.Scheme, challenge.Parameters, credentials, nonceCount)
{
}
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 ();
}
#endregion
#region Internal Properties
internal uint NonceCount {
get {
return _nonceCount < UInt32.MaxValue
? _nonceCount
: 0;
}
}
#endregion
#region Public Properties
public string Cnonce {
get {
return Parameters["cnonce"];
}
}
public string Nc {
get {
return Parameters["nc"];
}
}
public string Password {
get {
return Parameters["password"];
}
}
public string Response {
get {
return Parameters["response"];
}
}
public string Uri {
get {
return Parameters["uri"];
}
}
public string UserName {
get {
return Parameters["username"];
}
}
#endregion
#region Private Methods
private static string createA1 (string username, string password, string realm)
{
return String.Format ("{0}:{1}:{2}", username, realm, password);
}
private static string createA1 (
string username, string password, string realm, string nonce, string cnonce)
{
return String.Format (
"{0}:{1}:{2}", hash (createA1 (username, password, realm)), nonce, cnonce);
}
private static string createA2 (string method, string uri)
{
return String.Format ("{0}:{1}", method, uri);
}
private static string createA2 (string method, string uri, string entity)
{
return String.Format ("{0}:{1}:{2}", method, uri, hash (entity));
}
private static string hash (string value)
{
var src = Encoding.UTF8.GetBytes (value);
var md5 = MD5.Create ();
var hashed = md5.ComputeHash (src);
var res = new StringBuilder (64);
foreach (var b in hashed)
res.Append (b.ToString ("x2"));
return res.ToString ();
}
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);
}
#endregion
#region Internal Methods
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));
}
internal static AuthenticationResponse Parse (string value)
{
try {
var cred = value.Split (new[] { ' ' }, 2);
if (cred.Length != 2)
return null;
var schm = cred[0].ToLower ();
return schm == "basic"
? new AuthenticationResponse (
AuthenticationSchemes.Basic, ParseBasicCredentials (cred[1]))
: schm == "digest"
? new AuthenticationResponse (
AuthenticationSchemes.Digest, ParseParameters (cred[1]))
: null;
}
catch {
}
return null;
}
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 [<domain>\]<username>:<password>.
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 ();
res["username"] = user;
res["password"] = pass;
return res;
}
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;
}
internal override string ToDigestString ()
{
var output = new StringBuilder (256);
output.AppendFormat (
"Digest username=\"{0}\", realm=\"{1}\", nonce=\"{2}\", uri=\"{3}\", response=\"{4}\"",
Parameters["username"],
Parameters["realm"],
Parameters["nonce"],
Parameters["uri"],
Parameters["response"]);
var opaque = Parameters["opaque"];
if (opaque != null)
output.AppendFormat (", opaque=\"{0}\"", opaque);
var algo = Parameters["algorithm"];
if (algo != null)
output.AppendFormat (", algorithm={0}", algo);
var qop = Parameters["qop"];
if (qop != null)
output.AppendFormat (
", qop={0}, cnonce=\"{1}\", nc={2}", qop, Parameters["cnonce"], Parameters["nc"]);
return output.ToString ();
}
#endregion
#region Public Methods
public IIdentity ToIdentity ()
{
var schm = Scheme;
return schm == AuthenticationSchemes.Basic
? new HttpBasicIdentity (Parameters["username"], Parameters["password"]) as IIdentity
: schm == AuthenticationSchemes.Digest
? new HttpDigestIdentity (Parameters)
: null;
}
#endregion
}
}

View File

@ -1,66 +0,0 @@
#region License
/*
* AuthenticationSchemes.cs
*
* This code is derived from AuthenticationSchemes.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2016 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Atsushi Enomoto <atsushi@ximian.com>
*/
#endregion
using System;
namespace WebSocketSharp.Net
{
/// <summary>
/// Specifies the scheme for authentication.
/// </summary>
public enum AuthenticationSchemes
{
/// <summary>
/// No authentication is allowed.
/// </summary>
None,
/// <summary>
/// Specifies digest authentication.
/// </summary>
Digest = 1,
/// <summary>
/// Specifies basic authentication.
/// </summary>
Basic = 8,
/// <summary>
/// Specifies anonymous authentication.
/// </summary>
Anonymous = 0x8000
}
}

View File

@ -1,93 +0,0 @@
#region License
/*
* Chunk.cs
*
* This code is derived from ChunkStream.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2003 Ximian, Inc (http://www.ximian.com)
* Copyright (c) 2014-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@ximian.com>
*/
#endregion
using System;
namespace WebSocketSharp.Net
{
internal class Chunk
{
#region Private Fields
private byte[] _data;
private int _offset;
#endregion
#region Public Constructors
public Chunk (byte[] data)
{
_data = data;
}
#endregion
#region Public Properties
public int ReadLeft {
get {
return _data.Length - _offset;
}
}
#endregion
#region Public Methods
public int Read (byte[] buffer, int offset, int count)
{
var left = _data.Length - _offset;
if (left == 0)
return 0;
if (count > left)
count = left;
Buffer.BlockCopy (_data, _offset, buffer, offset, count);
_offset += count;
return count;
}
#endregion
}
}

View File

@ -1,383 +0,0 @@
#region License
/*
* ChunkStream.cs
*
* This code is derived from ChunkStream.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2003 Ximian, Inc (http://www.ximian.com)
* Copyright (c) 2012-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@ximian.com>
*/
#endregion
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
using System.Text;
namespace WebSocketSharp.Net
{
internal class ChunkStream
{
#region Private Fields
private int _chunkRead;
private int _chunkSize;
private List<Chunk> _chunks;
private bool _gotIt;
private WebHeaderCollection _headers;
private StringBuilder _saved;
private bool _sawCr;
private InputChunkState _state;
private int _trailerState;
#endregion
#region Public Constructors
public ChunkStream (WebHeaderCollection headers)
{
_headers = headers;
_chunkSize = -1;
_chunks = new List<Chunk> ();
_saved = new StringBuilder ();
}
#endregion
#region Public Properties
public WebHeaderCollection Headers {
get {
return _headers;
}
}
public bool WantsMore {
get {
return _state < InputChunkState.End;
}
}
#endregion
#region Private Methods
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 (!_sawCr) {
if (buffer[offset++] != 13)
throwProtocolViolation ("CR is expected.");
_sawCr = 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 b = 0;
while (offset < length) {
b = buffer[offset++];
if (_sawCr) {
if (b != 10)
throwProtocolViolation ("LF is expected.");
break;
}
if (b == 13) {
_sawCr = true;
continue;
}
if (b == 10)
throwProtocolViolation ("LF is unexpected.");
if (_gotIt)
continue;
if (b == 32 || b == 59) { // SP or ';'
_gotIt = true;
continue;
}
_saved.Append ((char) b);
}
if (_saved.Length > 20)
throwProtocolViolation ("The chunk size is too big.");
if (b != 10)
return InputChunkState.None;
var s = _saved.ToString ();
try {
_chunkSize = Int32.Parse (s, NumberStyles.HexNumber);
}
catch {
throwProtocolViolation ("The chunk size cannot be parsed.");
}
_chunkRead = 0;
if (_chunkSize == 0) {
_trailerState = 2;
return InputChunkState.Trailer;
}
return InputChunkState.Data;
}
private InputChunkState setTrailer (
byte[] buffer, ref int offset, int length
)
{
while (offset < length) {
if (_trailerState == 4) // CR LF CR LF
break;
var b = buffer[offset++];
_saved.Append ((char) b);
if (_trailerState == 1 || _trailerState == 3) { // CR or CR LF CR
if (b != 10)
throwProtocolViolation ("LF is expected.");
_trailerState++;
continue;
}
if (b == 13) {
_trailerState++;
continue;
}
if (b == 10)
throwProtocolViolation ("LF is unexpected.");
_trailerState = 0;
}
var len = _saved.Length;
if (len > 4196)
throwProtocolViolation ("The trailer is too long.");
if (_trailerState < 4)
return InputChunkState.Trailer;
if (len == 2)
return InputChunkState.End;
_saved.Length = len - 2;
var val = _saved.ToString ();
var reader = new StringReader (val);
while (true) {
var line = reader.ReadLine ();
if (line == null || line.Length == 0)
break;
_headers.Add (line);
}
return InputChunkState.End;
}
private static void throwProtocolViolation (string message)
{
throw new WebException (
message, null, WebExceptionStatus.ServerProtocolViolation, null
);
}
private void write (byte[] buffer, 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;
_sawCr = false;
_gotIt = false;
}
if (_state == InputChunkState.Data) {
if (offset >= length)
return;
_state = writeData (buffer, ref offset, length);
if (_state == InputChunkState.Data)
return;
}
if (_state == InputChunkState.DataEnded) {
if (offset >= length)
return;
_state = seekCrLf (buffer, ref offset, length);
if (_state == InputChunkState.DataEnded)
return;
_sawCr = false;
}
if (_state == InputChunkState.Trailer) {
if (offset >= length)
return;
_state = setTrailer (buffer, ref offset, length);
if (_state == InputChunkState.Trailer)
return;
_saved.Length = 0;
}
if (offset >= length)
return;
write (buffer, 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);
var chunk = new Chunk (data);
_chunks.Add (chunk);
offset += cnt;
_chunkRead += cnt;
return _chunkRead == _chunkSize
? InputChunkState.DataEnded
: InputChunkState.Data;
}
#endregion
#region Internal Methods
internal void ResetBuffer ()
{
_chunkRead = 0;
_chunkSize = -1;
_chunks.Clear ();
}
#endregion
#region Public Methods
public int Read (byte[] buffer, int offset, int count)
{
if (count <= 0)
return 0;
return read (buffer, offset, count);
}
public void Write (byte[] buffer, int offset, int count)
{
if (count <= 0)
return;
write (buffer, offset, offset + count);
}
#endregion
}
}

View File

@ -1,249 +0,0 @@
#region License
/*
* ChunkedRequestStream.cs
*
* This code is derived from ChunkedInputStream.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
using System;
using System.IO;
namespace WebSocketSharp.Net
{
internal class ChunkedRequestStream : RequestStream
{
#region Private Fields
private static readonly int _bufferLength;
private HttpListenerContext _context;
private ChunkStream _decoder;
private bool _disposed;
private bool _noMoreData;
#endregion
#region Static Constructor
static ChunkedRequestStream ()
{
_bufferLength = 8192;
}
#endregion
#region Internal Constructors
internal ChunkedRequestStream (
Stream stream,
byte[] buffer,
int offset,
int count,
HttpListenerContext context
)
: base (stream, buffer, offset, count, -1)
{
_context = context;
_decoder = new ChunkStream (
(WebHeaderCollection) context.Request.Headers
);
}
#endregion
#region Private Methods
private void onRead (IAsyncResult asyncResult)
{
var rstate = (ReadBufferState) asyncResult.AsyncState;
var ares = rstate.AsyncResult;
try {
var nread = base.EndRead (asyncResult);
_decoder.Write (ares.Buffer, ares.Offset, nread);
nread = _decoder.Read (rstate.Buffer, rstate.Offset, rstate.Count);
rstate.Offset += nread;
rstate.Count -= nread;
if (rstate.Count == 0 || !_decoder.WantsMore || nread == 0) {
_noMoreData = !_decoder.WantsMore && nread == 0;
ares.Count = rstate.InitialCount - rstate.Count;
ares.Complete ();
return;
}
base.BeginRead (ares.Buffer, ares.Offset, ares.Count, onRead, rstate);
}
catch (Exception ex) {
_context.ErrorMessage = "I/O operation aborted";
_context.SendError ();
ares.Complete (ex);
}
}
#endregion
#region Public Methods
public override IAsyncResult BeginRead (
byte[] buffer, int offset, int count, AsyncCallback callback, object state
)
{
if (_disposed) {
var name = GetType ().ToString ();
throw new ObjectDisposedException (name);
}
if (buffer == null)
throw new ArgumentNullException ("buffer");
if (offset < 0) {
var msg = "A negative value.";
throw new ArgumentOutOfRangeException ("offset", msg);
}
if (count < 0) {
var msg = "A negative value.";
throw new ArgumentOutOfRangeException ("count", msg);
}
var len = buffer.Length;
if (offset + count > len) {
var msg = "The sum of 'offset' and 'count' is greater than the length of 'buffer'.";
throw new ArgumentException (msg);
}
var ares = new HttpStreamAsyncResult (callback, state);
if (_noMoreData) {
ares.Complete ();
return ares;
}
var nread = _decoder.Read (buffer, offset, count);
offset += nread;
count -= nread;
if (count == 0) {
ares.Count = nread;
ares.Complete ();
return ares;
}
if (!_decoder.WantsMore) {
_noMoreData = nread == 0;
ares.Count = nread;
ares.Complete ();
return ares;
}
ares.Buffer = new byte[_bufferLength];
ares.Offset = 0;
ares.Count = _bufferLength;
var rstate = new ReadBufferState (buffer, offset, count, ares);
rstate.InitialCount += nread;
base.BeginRead (ares.Buffer, ares.Offset, ares.Count, onRead, rstate);
return ares;
}
public override void Close ()
{
if (_disposed)
return;
_disposed = true;
base.Close ();
}
public override int EndRead (IAsyncResult asyncResult)
{
if (_disposed) {
var name = GetType ().ToString ();
throw new ObjectDisposedException (name);
}
if (asyncResult == null)
throw new ArgumentNullException ("asyncResult");
var ares = asyncResult as HttpStreamAsyncResult;
if (ares == null) {
var msg = "A wrong IAsyncResult instance.";
throw new ArgumentException (msg, "asyncResult");
}
if (!ares.IsCompleted)
ares.AsyncWaitHandle.WaitOne ();
if (ares.HasException) {
var msg = "The I/O operation has been aborted.";
throw new HttpListenerException (995, msg);
}
return ares.Count;
}
public override int Read (byte[] buffer, int offset, int count)
{
var ares = BeginRead (buffer, offset, count, null, null);
return EndRead (ares);
}
#endregion
}
}

View File

@ -1,303 +0,0 @@
#region License
/*
* ClientSslConfiguration.cs
*
* The MIT License
*
* Copyright (c) 2014 liryna
* Copyright (c) 2014-2020 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Liryna <liryna.stark@gmail.com>
*/
#endregion
using System;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
namespace WebSocketSharp.Net
{
/// <summary>
/// Stores the parameters for the <see cref="SslStream"/> used by clients.
/// </summary>
public class ClientSslConfiguration
{
#region Private Fields
private bool _checkCertRevocation;
private LocalCertificateSelectionCallback _clientCertSelectionCallback;
private X509CertificateCollection _clientCerts;
private SslProtocols _enabledSslProtocols;
private RemoteCertificateValidationCallback _serverCertValidationCallback;
private string _targetHost;
#endregion
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ClientSslConfiguration"/>
/// class with the specified target host server name.
/// </summary>
/// <param name="targetHost">
/// A <see cref="string"/> that specifies the target host server name.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="targetHost"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="targetHost"/> is an empty string.
/// </exception>
public ClientSslConfiguration (string targetHost)
{
if (targetHost == null)
throw new ArgumentNullException ("targetHost");
if (targetHost.Length == 0)
throw new ArgumentException ("An empty string.", "targetHost");
_targetHost = targetHost;
_enabledSslProtocols = SslProtocols.None;
}
/// <summary>
/// Initializes a new instance of the <see cref="ClientSslConfiguration"/>
/// class that stores the parameters copied from the specified configuration.
/// </summary>
/// <param name="configuration">
/// A <see cref="ClientSslConfiguration"/> from which to copy.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="configuration"/> is <see langword="null"/>.
/// </exception>
public ClientSslConfiguration (ClientSslConfiguration configuration)
{
if (configuration == null)
throw new ArgumentNullException ("configuration");
_checkCertRevocation = configuration._checkCertRevocation;
_clientCertSelectionCallback = configuration._clientCertSelectionCallback;
_clientCerts = configuration._clientCerts;
_enabledSslProtocols = configuration._enabledSslProtocols;
_serverCertValidationCallback = configuration._serverCertValidationCallback;
_targetHost = configuration._targetHost;
}
#endregion
#region Public Properties
/// <summary>
/// Gets or sets a value indicating whether the certificate revocation
/// list is checked during authentication.
/// </summary>
/// <value>
/// <para>
/// <c>true</c> if the certificate revocation list is checked during
/// authentication; otherwise, <c>false</c>.
/// </para>
/// <para>
/// The default value is <c>false</c>.
/// </para>
/// </value>
public bool CheckCertificateRevocation {
get {
return _checkCertRevocation;
}
set {
_checkCertRevocation = value;
}
}
/// <summary>
/// Gets or sets the collection of client certificates from which to select
/// one to supply to the server.
/// </summary>
/// <value>
/// <para>
/// A <see cref="X509CertificateCollection"/> or <see langword="null"/>.
/// </para>
/// <para>
/// The collection contains client certificates from which to select.
/// </para>
/// <para>
/// The default value is <see langword="null"/>.
/// </para>
/// </value>
public X509CertificateCollection ClientCertificates {
get {
return _clientCerts;
}
set {
_clientCerts = value;
}
}
/// <summary>
/// Gets or sets the callback used to select the certificate to supply to
/// the server.
/// </summary>
/// <remarks>
/// No certificate is supplied if the callback returns <see langword="null"/>.
/// </remarks>
/// <value>
/// <para>
/// A <see cref="LocalCertificateSelectionCallback"/> delegate that
/// invokes the method called for selecting the certificate.
/// </para>
/// <para>
/// The default value is a delegate that invokes a method that only
/// returns <see langword="null"/>.
/// </para>
/// </value>
public LocalCertificateSelectionCallback ClientCertificateSelectionCallback {
get {
if (_clientCertSelectionCallback == null)
_clientCertSelectionCallback = defaultSelectClientCertificate;
return _clientCertSelectionCallback;
}
set {
_clientCertSelectionCallback = value;
}
}
/// <summary>
/// Gets or sets the protocols used for authentication.
/// </summary>
/// <value>
/// <para>
/// Any of the <see cref="SslProtocols"/> enum values.
/// </para>
/// <para>
/// It represents the protocols used for authentication.
/// </para>
/// <para>
/// The default value is <see cref="SslProtocols.None"/>.
/// </para>
/// </value>
public SslProtocols EnabledSslProtocols {
get {
return _enabledSslProtocols;
}
set {
_enabledSslProtocols = value;
}
}
/// <summary>
/// Gets or sets the callback used to validate the certificate supplied by
/// the server.
/// </summary>
/// <remarks>
/// The certificate is valid if the callback returns <c>true</c>.
/// </remarks>
/// <value>
/// <para>
/// A <see cref="RemoteCertificateValidationCallback"/> delegate that
/// invokes the method called for validating the certificate.
/// </para>
/// <para>
/// The default value is a delegate that invokes a method that only
/// returns <c>true</c>.
/// </para>
/// </value>
public RemoteCertificateValidationCallback ServerCertificateValidationCallback {
get {
if (_serverCertValidationCallback == null)
_serverCertValidationCallback = defaultValidateServerCertificate;
return _serverCertValidationCallback;
}
set {
_serverCertValidationCallback = value;
}
}
/// <summary>
/// Gets or sets the target host server name.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the name of the server that
/// will share a secure connection with a client.
/// </value>
/// <exception cref="ArgumentNullException">
/// The value specified for a set operation is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// The value specified for a set operation is an empty string.
/// </exception>
public string TargetHost {
get {
return _targetHost;
}
set {
if (value == null)
throw new ArgumentNullException ("value");
if (value.Length == 0)
throw new ArgumentException ("An empty string.", "value");
_targetHost = value;
}
}
#endregion
#region Private Methods
private static X509Certificate defaultSelectClientCertificate (
object sender,
string targetHost,
X509CertificateCollection clientCertificates,
X509Certificate serverCertificate,
string[] acceptableIssuers
)
{
return null;
}
private static bool defaultValidateServerCertificate (
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors
)
{
return true;
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,821 +0,0 @@
#region License
/*
* CookieCollection.cs
*
* This code is derived from CookieCollection.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2004,2009 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2019 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Lawrence Pit <loz@cable.a2000.nl>
* - Gonzalo Paniagua Javier <gonzalo@ximian.com>
* - Sebastien Pouliot <sebastien@ximian.com>
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace WebSocketSharp.Net
{
/// <summary>
/// Provides a collection of instances of the <see cref="Cookie"/> class.
/// </summary>
[Serializable]
public class CookieCollection : ICollection<Cookie>
{
#region Private Fields
private List<Cookie> _list;
private bool _readOnly;
private object _sync;
#endregion
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="CookieCollection"/> class.
/// </summary>
public CookieCollection ()
{
_list = new List<Cookie> ();
_sync = ((ICollection) _list).SyncRoot;
}
#endregion
#region Internal Properties
internal IList<Cookie> List {
get {
return _list;
}
}
internal IEnumerable<Cookie> Sorted {
get {
var list = new List<Cookie> (_list);
if (list.Count > 1)
list.Sort (compareForSorted);
return list;
}
}
#endregion
#region Public Properties
/// <summary>
/// Gets the number of cookies in the collection.
/// </summary>
/// <value>
/// An <see cref="int"/> that represents the number of cookies in
/// the collection.
/// </value>
public int Count {
get {
return _list.Count;
}
}
/// <summary>
/// Gets a value indicating whether the collection is read-only.
/// </summary>
/// <value>
/// <para>
/// <c>true</c> if the collection is read-only; otherwise, <c>false</c>.
/// </para>
/// <para>
/// The default value is <c>false</c>.
/// </para>
/// </value>
public bool IsReadOnly {
get {
return _readOnly;
}
internal set {
_readOnly = value;
}
}
/// <summary>
/// Gets a value indicating whether the access to the collection is
/// thread safe.
/// </summary>
/// <value>
/// <para>
/// <c>true</c> if the access to the collection is thread safe;
/// otherwise, <c>false</c>.
/// </para>
/// <para>
/// The default value is <c>false</c>.
/// </para>
/// </value>
public bool IsSynchronized {
get {
return false;
}
}
/// <summary>
/// Gets the cookie at the specified index from the collection.
/// </summary>
/// <value>
/// A <see cref="Cookie"/> at the specified index in the collection.
/// </value>
/// <param name="index">
/// An <see cref="int"/> that specifies the zero-based index of the cookie
/// to find.
/// </param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of allowable range for the collection.
/// </exception>
public Cookie this[int index] {
get {
if (index < 0 || index >= _list.Count)
throw new ArgumentOutOfRangeException ("index");
return _list[index];
}
}
/// <summary>
/// Gets the cookie with the specified name from the collection.
/// </summary>
/// <value>
/// <para>
/// A <see cref="Cookie"/> with the specified name in the collection.
/// </para>
/// <para>
/// <see langword="null"/> if not found.
/// </para>
/// </value>
/// <param name="name">
/// A <see cref="string"/> that specifies the name of the cookie to find.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="name"/> is <see langword="null"/>.
/// </exception>
public Cookie this[string name] {
get {
if (name == null)
throw new ArgumentNullException ("name");
var caseInsensitive = StringComparison.InvariantCultureIgnoreCase;
foreach (var cookie in Sorted) {
if (cookie.Name.Equals (name, caseInsensitive))
return cookie;
}
return null;
}
}
/// <summary>
/// Gets an object used to synchronize access to the collection.
/// </summary>
/// <value>
/// An <see cref="object"/> used to synchronize access to the collection.
/// </value>
public object SyncRoot {
get {
return _sync;
}
}
#endregion
#region Private Methods
private void add (Cookie cookie)
{
var idx = search (cookie);
if (idx == -1) {
_list.Add (cookie);
return;
}
_list[idx] = cookie;
}
private static int compareForSort (Cookie x, Cookie y)
{
return (x.Name.Length + x.Value.Length)
- (y.Name.Length + y.Value.Length);
}
private static int compareForSorted (Cookie x, Cookie y)
{
var ret = x.Version - y.Version;
return ret != 0
? ret
: (ret = x.Name.CompareTo (y.Name)) != 0
? ret
: y.Path.Length - x.Path.Length;
}
private static CookieCollection parseRequest (string value)
{
var ret = new CookieCollection ();
Cookie cookie = null;
var ver = 0;
var caseInsensitive = StringComparison.InvariantCultureIgnoreCase;
var pairs = value.SplitHeaderValue (',', ';').ToList ();
for (var i = 0; i < pairs.Count; i++) {
var pair = pairs[i].Trim ();
if (pair.Length == 0)
continue;
var idx = pair.IndexOf ('=');
if (idx == -1) {
if (cookie == null)
continue;
if (pair.Equals ("$port", caseInsensitive)) {
cookie.Port = "\"\"";
continue;
}
continue;
}
if (idx == 0) {
if (cookie != null) {
ret.add (cookie);
cookie = null;
}
continue;
}
var name = pair.Substring (0, idx).TrimEnd (' ');
var val = idx < pair.Length - 1
? pair.Substring (idx + 1).TrimStart (' ')
: String.Empty;
if (name.Equals ("$version", caseInsensitive)) {
if (val.Length == 0)
continue;
int num;
if (!Int32.TryParse (val.Unquote (), out num))
continue;
ver = num;
continue;
}
if (name.Equals ("$path", caseInsensitive)) {
if (cookie == null)
continue;
if (val.Length == 0)
continue;
cookie.Path = val;
continue;
}
if (name.Equals ("$domain", caseInsensitive)) {
if (cookie == null)
continue;
if (val.Length == 0)
continue;
cookie.Domain = val;
continue;
}
if (name.Equals ("$port", caseInsensitive)) {
if (cookie == null)
continue;
if (val.Length == 0)
continue;
cookie.Port = val;
continue;
}
if (cookie != null)
ret.add (cookie);
if (!Cookie.TryCreate (name, val, out cookie))
continue;
if (ver != 0)
cookie.Version = ver;
}
if (cookie != null)
ret.add (cookie);
return ret;
}
private static CookieCollection parseResponse (string value)
{
var ret = new CookieCollection ();
Cookie cookie = null;
var caseInsensitive = StringComparison.InvariantCultureIgnoreCase;
var pairs = value.SplitHeaderValue (',', ';').ToList ();
for (var i = 0; i < pairs.Count; i++) {
var pair = pairs[i].Trim ();
if (pair.Length == 0)
continue;
var idx = pair.IndexOf ('=');
if (idx == -1) {
if (cookie == null)
continue;
if (pair.Equals ("port", caseInsensitive)) {
cookie.Port = "\"\"";
continue;
}
if (pair.Equals ("discard", caseInsensitive)) {
cookie.Discard = true;
continue;
}
if (pair.Equals ("secure", caseInsensitive)) {
cookie.Secure = true;
continue;
}
if (pair.Equals ("httponly", caseInsensitive)) {
cookie.HttpOnly = true;
continue;
}
continue;
}
if (idx == 0) {
if (cookie != null) {
ret.add (cookie);
cookie = null;
}
continue;
}
var name = pair.Substring (0, idx).TrimEnd (' ');
var val = idx < pair.Length - 1
? pair.Substring (idx + 1).TrimStart (' ')
: String.Empty;
if (name.Equals ("version", caseInsensitive)) {
if (cookie == null)
continue;
if (val.Length == 0)
continue;
int num;
if (!Int32.TryParse (val.Unquote (), out num))
continue;
cookie.Version = num;
continue;
}
if (name.Equals ("expires", caseInsensitive)) {
if (val.Length == 0)
continue;
if (i == pairs.Count - 1)
break;
i++;
if (cookie == null)
continue;
if (cookie.Expires != DateTime.MinValue)
continue;
var buff = new StringBuilder (val, 32);
buff.AppendFormat (", {0}", pairs[i].Trim ());
DateTime expires;
if (
!DateTime.TryParseExact (
buff.ToString (),
new[] { "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'", "r" },
CultureInfo.CreateSpecificCulture ("en-US"),
DateTimeStyles.AdjustToUniversal
| DateTimeStyles.AssumeUniversal,
out expires
)
)
continue;
cookie.Expires = expires.ToLocalTime ();
continue;
}
if (name.Equals ("max-age", caseInsensitive)) {
if (cookie == null)
continue;
if (val.Length == 0)
continue;
int num;
if (!Int32.TryParse (val.Unquote (), out num))
continue;
cookie.MaxAge = num;
continue;
}
if (name.Equals ("path", caseInsensitive)) {
if (cookie == null)
continue;
if (val.Length == 0)
continue;
cookie.Path = val;
continue;
}
if (name.Equals ("domain", caseInsensitive)) {
if (cookie == null)
continue;
if (val.Length == 0)
continue;
cookie.Domain = val;
continue;
}
if (name.Equals ("port", caseInsensitive)) {
if (cookie == null)
continue;
if (val.Length == 0)
continue;
cookie.Port = val;
continue;
}
if (name.Equals ("comment", caseInsensitive)) {
if (cookie == null)
continue;
if (val.Length == 0)
continue;
cookie.Comment = urlDecode (val, Encoding.UTF8);
continue;
}
if (name.Equals ("commenturl", caseInsensitive)) {
if (cookie == null)
continue;
if (val.Length == 0)
continue;
cookie.CommentUri = val.Unquote ().ToUri ();
continue;
}
if (name.Equals ("samesite", caseInsensitive)) {
if (cookie == null)
continue;
if (val.Length == 0)
continue;
cookie.SameSite = val.Unquote ();
continue;
}
if (cookie != null)
ret.add (cookie);
Cookie.TryCreate (name, val, out cookie);
}
if (cookie != null)
ret.add (cookie);
return ret;
}
private int search (Cookie cookie)
{
for (var i = _list.Count - 1; i >= 0; i--) {
if (_list[i].EqualsWithoutValue (cookie))
return i;
}
return -1;
}
private static string urlDecode (string s, Encoding encoding)
{
if (s.IndexOfAny (new[] { '%', '+' }) == -1)
return s;
try {
return HttpUtility.UrlDecode (s, encoding);
}
catch {
return null;
}
}
#endregion
#region Internal Methods
internal static CookieCollection Parse (string value, bool response)
{
try {
return response
? parseResponse (value)
: parseRequest (value);
}
catch (Exception ex) {
throw new CookieException ("It could not be parsed.", ex);
}
}
internal void SetOrRemove (Cookie cookie)
{
var idx = search (cookie);
if (idx == -1) {
if (cookie.Expired)
return;
_list.Add (cookie);
return;
}
if (cookie.Expired) {
_list.RemoveAt (idx);
return;
}
_list[idx] = cookie;
}
internal void SetOrRemove (CookieCollection cookies)
{
foreach (var cookie in cookies._list)
SetOrRemove (cookie);
}
internal void Sort ()
{
if (_list.Count > 1)
_list.Sort (compareForSort);
}
#endregion
#region Public Methods
/// <summary>
/// Adds the specified cookie to the collection.
/// </summary>
/// <param name="cookie">
/// A <see cref="Cookie"/> to add.
/// </param>
/// <exception cref="InvalidOperationException">
/// The collection is read-only.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="cookie"/> is <see langword="null"/>.
/// </exception>
public void Add (Cookie cookie)
{
if (_readOnly) {
var msg = "The collection is read-only.";
throw new InvalidOperationException (msg);
}
if (cookie == null)
throw new ArgumentNullException ("cookie");
add (cookie);
}
/// <summary>
/// Adds the specified cookies to the collection.
/// </summary>
/// <param name="cookies">
/// A <see cref="CookieCollection"/> that contains the cookies to add.
/// </param>
/// <exception cref="InvalidOperationException">
/// The collection is read-only.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="cookies"/> is <see langword="null"/>.
/// </exception>
public void Add (CookieCollection cookies)
{
if (_readOnly) {
var msg = "The collection is read-only.";
throw new InvalidOperationException (msg);
}
if (cookies == null)
throw new ArgumentNullException ("cookies");
foreach (var cookie in cookies._list)
add (cookie);
}
/// <summary>
/// Removes all cookies from the collection.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The collection is read-only.
/// </exception>
public void Clear ()
{
if (_readOnly) {
var msg = "The collection is read-only.";
throw new InvalidOperationException (msg);
}
_list.Clear ();
}
/// <summary>
/// Determines whether the collection contains the specified cookie.
/// </summary>
/// <returns>
/// <c>true</c> if the cookie is found in the collection; otherwise,
/// <c>false</c>.
/// </returns>
/// <param name="cookie">
/// A <see cref="Cookie"/> to find.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="cookie"/> is <see langword="null"/>.
/// </exception>
public bool Contains (Cookie cookie)
{
if (cookie == null)
throw new ArgumentNullException ("cookie");
return search (cookie) > -1;
}
/// <summary>
/// Copies the elements of the collection to the specified array,
/// starting at the specified index.
/// </summary>
/// <param name="array">
/// An array of <see cref="Cookie"/> that specifies the destination of
/// the elements copied from the collection.
/// </param>
/// <param name="index">
/// An <see cref="int"/> that specifies the zero-based index in
/// the array at which copying starts.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="array"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="index"/> is less than zero.
/// </exception>
/// <exception cref="ArgumentException">
/// The space from <paramref name="index"/> to the end of
/// <paramref name="array"/> is not enough to copy to.
/// </exception>
public void CopyTo (Cookie[] array, int index)
{
if (array == null)
throw new ArgumentNullException ("array");
if (index < 0)
throw new ArgumentOutOfRangeException ("index", "Less than zero.");
if (array.Length - index < _list.Count) {
var msg = "The available space of the array is not enough to copy to.";
throw new ArgumentException (msg);
}
_list.CopyTo (array, index);
}
/// <summary>
/// Gets the enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.Generic.IEnumerator{Cookie}"/>
/// instance that can be used to iterate through the collection.
/// </returns>
public IEnumerator<Cookie> GetEnumerator ()
{
return _list.GetEnumerator ();
}
/// <summary>
/// Removes the specified cookie from the collection.
/// </summary>
/// <returns>
/// <para>
/// <c>true</c> if the cookie is successfully removed; otherwise,
/// <c>false</c>.
/// </para>
/// <para>
/// <c>false</c> if the cookie is not found in the collection.
/// </para>
/// </returns>
/// <param name="cookie">
/// A <see cref="Cookie"/> to remove.
/// </param>
/// <exception cref="InvalidOperationException">
/// The collection is read-only.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="cookie"/> is <see langword="null"/>.
/// </exception>
public bool Remove (Cookie cookie)
{
if (_readOnly) {
var msg = "The collection is read-only.";
throw new InvalidOperationException (msg);
}
if (cookie == null)
throw new ArgumentNullException ("cookie");
var idx = search (cookie);
if (idx == -1)
return false;
_list.RemoveAt (idx);
return true;
}
#endregion
#region Explicit Interface Implementations
/// <summary>
/// Gets the enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// An <see cref="IEnumerator"/> instance that can be used to iterate
/// through the collection.
/// </returns>
IEnumerator IEnumerable.GetEnumerator ()
{
return _list.GetEnumerator ();
}
#endregion
}
}

View File

@ -1,165 +0,0 @@
#region License
/*
* CookieException.cs
*
* This code is derived from CookieException.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2012-2019 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Lawrence Pit <loz@cable.a2000.nl>
*/
#endregion
using System;
using System.Runtime.Serialization;
using System.Security.Permissions;
namespace WebSocketSharp.Net
{
/// <summary>
/// The exception that is thrown when a <see cref="Cookie"/> gets an error.
/// </summary>
[Serializable]
public class CookieException : FormatException, ISerializable
{
#region Internal Constructors
internal CookieException (string message)
: base (message)
{
}
internal CookieException (string message, Exception innerException)
: base (message, innerException)
{
}
#endregion
#region Protected Constructors
/// <summary>
/// Initializes a new instance of the <see cref="CookieException"/> class
/// with the serialized data.
/// </summary>
/// <param name="serializationInfo">
/// A <see cref="SerializationInfo"/> that holds the serialized object data.
/// </param>
/// <param name="streamingContext">
/// A <see cref="StreamingContext"/> that specifies the source for
/// the deserialization.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="serializationInfo"/> is <see langword="null"/>.
/// </exception>
protected CookieException (
SerializationInfo serializationInfo, StreamingContext streamingContext
)
: base (serializationInfo, streamingContext)
{
}
#endregion
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="CookieException"/> class.
/// </summary>
public CookieException ()
: base ()
{
}
#endregion
#region Public Methods
/// <summary>
/// Populates the specified <see cref="SerializationInfo"/> instance with
/// the data needed to serialize the current instance.
/// </summary>
/// <param name="serializationInfo">
/// A <see cref="SerializationInfo"/> that holds the serialized object data.
/// </param>
/// <param name="streamingContext">
/// A <see cref="StreamingContext"/> that specifies the destination for
/// the serialization.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="serializationInfo"/> is <see langword="null"/>.
/// </exception>
[
SecurityPermission (
SecurityAction.LinkDemand,
Flags = SecurityPermissionFlag.SerializationFormatter
)
]
public override void GetObjectData (
SerializationInfo serializationInfo, StreamingContext streamingContext
)
{
base.GetObjectData (serializationInfo, streamingContext);
}
#endregion
#region Explicit Interface Implementation
/// <summary>
/// Populates the specified <see cref="SerializationInfo"/> instance with
/// the data needed to serialize the current instance.
/// </summary>
/// <param name="serializationInfo">
/// A <see cref="SerializationInfo"/> that holds the serialized object data.
/// </param>
/// <param name="streamingContext">
/// A <see cref="StreamingContext"/> that specifies the destination for
/// the serialization.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="serializationInfo"/> is <see langword="null"/>.
/// </exception>
[
SecurityPermission (
SecurityAction.LinkDemand,
Flags = SecurityPermissionFlag.SerializationFormatter,
SerializationFormatter = true
)
]
void ISerializable.GetObjectData (
SerializationInfo serializationInfo, StreamingContext streamingContext
)
{
base.GetObjectData (serializationInfo, streamingContext);
}
#endregion
}
}

View File

@ -1,582 +0,0 @@
#region License
/*
* EndPointListener.cs
*
* This code is derived from EndPointListener.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2020 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
#region Contributors
/*
* Contributors:
* - Liryna <liryna.stark@gmail.com>
* - Nicholas Devenish
*/
#endregion
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 WebSocketSharp.Net
{
internal sealed class EndPointListener
{
#region Private Fields
private List<HttpListenerPrefix> _all; // host == '+'
private Dictionary<HttpConnection, HttpConnection> _connections;
private object _connectionsSync;
private static readonly string _defaultCertFolderPath;
private IPEndPoint _endpoint;
private List<HttpListenerPrefix> _prefixes;
private bool _secure;
private Socket _socket;
private ServerSslConfiguration _sslConfig;
private List<HttpListenerPrefix> _unhandled; // host == '*'
#endregion
#region Static Constructor
static EndPointListener ()
{
_defaultCertFolderPath = Environment.GetFolderPath (
Environment.SpecialFolder.ApplicationData
);
}
#endregion
#region Internal Constructors
internal EndPointListener (
IPEndPoint endpoint,
bool secure,
string certificateFolderPath,
ServerSslConfiguration sslConfig,
bool reuseAddress
)
{
_endpoint = endpoint;
if (secure) {
var cert = getCertificate (
endpoint.Port,
certificateFolderPath,
sslConfig.ServerCertificate
);
if (cert == null) {
var msg = "No server certificate could be found.";
throw new ArgumentException (msg);
}
_secure = true;
_sslConfig = new ServerSslConfiguration (sslConfig);
_sslConfig.ServerCertificate = cert;
}
_prefixes = new List<HttpListenerPrefix> ();
_connections = new Dictionary<HttpConnection, HttpConnection> ();
_connectionsSync = ((ICollection) _connections).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);
}
#endregion
#region Public Properties
public IPAddress Address {
get {
return _endpoint.Address;
}
}
public bool IsSecure {
get {
return _secure;
}
}
public int Port {
get {
return _endpoint.Port;
}
}
public ServerSslConfiguration SslConfiguration {
get {
return _sslConfig;
}
}
#endregion
#region Private Methods
private static void addSpecial (
List<HttpListenerPrefix> prefixes, HttpListenerPrefix prefix
)
{
var path = prefix.Path;
foreach (var pref in prefixes) {
if (pref.Path == path) {
var msg = "The prefix is already in use.";
throw new HttpListenerException (87, msg);
}
}
prefixes.Add (prefix);
}
private void clearConnections ()
{
HttpConnection[] conns = null;
lock (_connectionsSync) {
var cnt = _connections.Count;
if (cnt == 0)
return;
conns = new HttpConnection[cnt];
var vals = _connections.Values;
vals.CopyTo (conns, 0);
_connections.Clear ();
}
foreach (var conn in conns)
conn.Close (true);
}
private static RSACryptoServiceProvider createRSAFromFile (string path)
{
var rsa = new RSACryptoServiceProvider ();
var key = File.ReadAllBytes (path);
rsa.ImportCspBlob (key);
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 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;
Close ();
}
private static void onAccept (IAsyncResult asyncResult)
{
var lsnr = (EndPointListener) asyncResult.AsyncState;
Socket sock = null;
try {
sock = lsnr._socket.EndAccept (asyncResult);
}
catch (ObjectDisposedException) {
return;
}
catch (Exception) {
// TODO: Logging.
}
try {
lsnr._socket.BeginAccept (onAccept, lsnr);
}
catch (Exception) {
// TODO: Logging.
if (sock != null)
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);
}
catch (Exception) {
// TODO: Logging.
socket.Close ();
return;
}
lock (listener._connectionsSync)
listener._connections.Add (conn, conn);
conn.BeginReadRequest ();
}
private static bool removeSpecial (
List<HttpListenerPrefix> 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<HttpListenerPrefix> prefixes
)
{
if (prefixes == null)
return null;
HttpListener ret = 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, StringComparison.Ordinal)) {
bestLen = len;
ret = pref.Listener;
}
}
return ret;
}
#endregion
#region Internal Methods
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 (_connectionsSync)
_connections.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);
if (path[path.Length - 1] != '/')
path += "/";
if (host != null && host.Length > 0) {
var prefs = _prefixes;
var bestLen = -1;
foreach (var pref in prefs) {
if (dns) {
var prefHost = pref.Host;
var prefDns = Uri.CheckHostName (prefHost) == UriHostNameType.Dns;
if (prefDns) {
if (prefHost != host)
continue;
}
}
if (pref.Port != port)
continue;
var prefPath = pref.Path;
var len = prefPath.Length;
if (len < bestLen)
continue;
if (path.StartsWith (prefPath, StringComparison.Ordinal)) {
bestLen = len;
listener = pref.Listener;
}
}
if (bestLen != -1)
return true;
}
listener = searchHttpListenerFromSpecial (path, _unhandled);
if (listener != null)
return true;
listener = searchHttpListenerFromSpecial (path, _all);
return listener != null;
}
#endregion
#region Public Methods
public void AddPrefix (HttpListenerPrefix prefix)
{
List<HttpListenerPrefix> current, future;
if (prefix.Host == "*") {
do {
current = _unhandled;
future = current != null
? new List<HttpListenerPrefix> (current)
: new List<HttpListenerPrefix> ();
addSpecial (future, prefix);
}
while (
Interlocked.CompareExchange (ref _unhandled, future, current) != current
);
return;
}
if (prefix.Host == "+") {
do {
current = _all;
future = current != null
? new List<HttpListenerPrefix> (current)
: new List<HttpListenerPrefix> ();
addSpecial (future, prefix);
}
while (
Interlocked.CompareExchange (ref _all, future, current) != current
);
return;
}
do {
current = _prefixes;
var idx = current.IndexOf (prefix);
if (idx > -1) {
if (current[idx].Listener != prefix.Listener) {
var msg = String.Format (
"There is another listener for {0}.", prefix
);
throw new HttpListenerException (87, msg);
}
return;
}
future = new List<HttpListenerPrefix> (current);
future.Add (prefix);
}
while (
Interlocked.CompareExchange (ref _prefixes, future, current) != current
);
}
public void Close ()
{
_socket.Close ();
clearConnections ();
EndPointManager.RemoveEndPoint (_endpoint);
}
public void RemovePrefix (HttpListenerPrefix prefix)
{
List<HttpListenerPrefix> current, future;
if (prefix.Host == "*") {
do {
current = _unhandled;
if (current == null)
break;
future = new List<HttpListenerPrefix> (current);
if (!removeSpecial (future, prefix))
break;
}
while (
Interlocked.CompareExchange (ref _unhandled, future, current) != current
);
leaveIfNoPrefix ();
return;
}
if (prefix.Host == "+") {
do {
current = _all;
if (current == null)
break;
future = new List<HttpListenerPrefix> (current);
if (!removeSpecial (future, prefix))
break;
}
while (
Interlocked.CompareExchange (ref _all, future, current) != current
);
leaveIfNoPrefix ();
return;
}
do {
current = _prefixes;
if (!current.Contains (prefix))
break;
future = new List<HttpListenerPrefix> (current);
future.Remove (prefix);
}
while (
Interlocked.CompareExchange (ref _prefixes, future, current) != current
);
leaveIfNoPrefix ();
}
#endregion
}
}

View File

@ -1,261 +0,0 @@
#region License
/*
* EndPointManager.cs
*
* This code is derived from EndPointManager.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2020 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@ximian.com>
*/
#endregion
#region Contributors
/*
* Contributors:
* - Liryna <liryna.stark@gmail.com>
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
namespace WebSocketSharp.Net
{
internal sealed class EndPointManager
{
#region Private Fields
private static readonly Dictionary<IPEndPoint, EndPointListener> _endpoints;
#endregion
#region Static Constructor
static EndPointManager ()
{
_endpoints = new Dictionary<IPEndPoint, EndPointListener> ();
}
#endregion
#region Private Constructors
private EndPointManager ()
{
}
#endregion
#region Private Methods
private static void addPrefix (string uriPrefix, HttpListener listener)
{
var pref = new HttpListenerPrefix (uriPrefix, listener);
var addr = convertToIPAddress (pref.Host);
if (addr == null) {
var msg = "The URI prefix includes an invalid host.";
throw new HttpListenerException (87, msg);
}
if (!addr.IsLocal ()) {
var msg = "The URI prefix includes an invalid host.";
throw new HttpListenerException (87, msg);
}
int port;
if (!Int32.TryParse (pref.Port, out port)) {
var msg = "The URI prefix includes an invalid port.";
throw new HttpListenerException (87, msg);
}
if (!port.IsPortNumber ()) {
var msg = "The URI prefix includes an invalid port.";
throw new HttpListenerException (87, msg);
}
var path = pref.Path;
if (path.IndexOf ('%') != -1) {
var msg = "The URI prefix includes an invalid path.";
throw new HttpListenerException (87, msg);
}
if (path.IndexOf ("//", StringComparison.Ordinal) != -1) {
var msg = "The URI prefix includes an invalid path.";
throw new HttpListenerException (87, msg);
}
var endpoint = new IPEndPoint (addr, port);
EndPointListener lsnr;
if (_endpoints.TryGetValue (endpoint, out lsnr)) {
if (lsnr.IsSecure ^ pref.IsSecure) {
var msg = "The URI prefix includes an invalid scheme.";
throw new HttpListenerException (87, msg);
}
}
else {
lsnr = new EndPointListener (
endpoint,
pref.IsSecure,
listener.CertificateFolderPath,
listener.SslConfiguration,
listener.ReuseAddress
);
_endpoints.Add (endpoint, lsnr);
}
lsnr.AddPrefix (pref);
}
private static IPAddress convertToIPAddress (string hostname)
{
if (hostname == "*")
return IPAddress.Any;
if (hostname == "+")
return IPAddress.Any;
return hostname.ToIPAddress ();
}
private static void removePrefix (string uriPrefix, HttpListener listener)
{
var pref = new HttpListenerPrefix (uriPrefix, listener);
var addr = convertToIPAddress (pref.Host);
if (addr == null)
return;
if (!addr.IsLocal ())
return;
int port;
if (!Int32.TryParse (pref.Port, out 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);
EndPointListener lsnr;
if (!_endpoints.TryGetValue (endpoint, out lsnr))
return;
if (lsnr.IsSecure ^ pref.IsSecure)
return;
lsnr.RemovePrefix (pref);
}
#endregion
#region Internal Methods
internal static bool RemoveEndPoint (IPEndPoint endpoint)
{
lock (((ICollection) _endpoints).SyncRoot)
return _endpoints.Remove (endpoint);
}
#endregion
#region Public Methods
public static void AddListener (HttpListener listener)
{
var added = new List<string> ();
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;
}
}
}
public static void AddPrefix (string uriPrefix, HttpListener listener)
{
lock (((ICollection) _endpoints).SyncRoot)
addPrefix (uriPrefix, listener);
}
public static void RemoveListener (HttpListener listener)
{
lock (((ICollection) _endpoints).SyncRoot) {
foreach (var pref in listener.Prefixes)
removePrefix (pref, listener);
}
}
public static void RemovePrefix (string uriPrefix, HttpListener listener)
{
lock (((ICollection) _endpoints).SyncRoot)
removePrefix (uriPrefix, listener);
}
#endregion
}
}

View File

@ -1,82 +0,0 @@
#region License
/*
* HttpBasicIdentity.cs
*
* This code is derived from HttpListenerBasicIdentity.cs (System.Net) of
* Mono (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2014-2017 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
using System;
using System.Security.Principal;
namespace WebSocketSharp.Net
{
/// <summary>
/// Holds the username and password from an HTTP Basic authentication attempt.
/// </summary>
public class HttpBasicIdentity : GenericIdentity
{
#region Private Fields
private string _password;
#endregion
#region Internal Constructors
internal HttpBasicIdentity (string username, string password)
: base (username, "Basic")
{
_password = password;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the password from a basic authentication attempt.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the password.
/// </value>
public virtual string Password {
get {
return _password;
}
}
#endregion
}
}

View File

@ -1,571 +0,0 @@
#region License
/*
* HttpConnection.cs
*
* This code is derived from HttpConnection.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
#region Contributors
/*
* Contributors:
* - Liryna <liryna.stark@gmail.com>
* - Rohan Singh <rohan-singh@hotmail.com>
*/
#endregion
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 WebSocketSharp.Net
{
internal sealed class HttpConnection
{
#region Private Fields
private int _attempts;
private byte[] _buffer;
private static readonly int _bufferLength;
private HttpListenerContext _context;
private StringBuilder _currentLine;
private InputState _inputState;
private RequestStream _inputStream;
private LineState _lineState;
private EndPointListener _listener;
private EndPoint _localEndPoint;
private static readonly int _maxInputLength;
private ResponseStream _outputStream;
private int _position;
private EndPoint _remoteEndPoint;
private MemoryStream _requestBuffer;
private int _reuses;
private bool _secure;
private Socket _socket;
private Stream _stream;
private object _sync;
private int _timeout;
private Dictionary<int, bool> _timeoutCanceled;
private Timer _timer;
#endregion
#region Static Constructor
static HttpConnection ()
{
_bufferLength = 8192;
_maxInputLength = 32768;
}
#endregion
#region Internal Constructors
internal HttpConnection (Socket socket, EndPointListener listener)
{
_socket = socket;
_listener = listener;
var netStream = new NetworkStream (socket, false);
if (listener.IsSecure) {
var sslConf = listener.SslConfiguration;
var sslStream = new SslStream (
netStream,
false,
sslConf.ClientCertificateValidationCallback
);
sslStream.AuthenticateAsServer (
sslConf.ServerCertificate,
sslConf.ClientCertificateRequired,
sslConf.EnabledSslProtocols,
sslConf.CheckCertificateRevocation
);
_secure = true;
_stream = sslStream;
}
else {
_stream = netStream;
}
_buffer = new byte[_bufferLength];
_localEndPoint = socket.LocalEndPoint;
_remoteEndPoint = socket.RemoteEndPoint;
_sync = new object ();
_timeoutCanceled = new Dictionary<int, bool> ();
_timer = new Timer (onTimeout, this, Timeout.Infinite, Timeout.Infinite);
init (90000); // 90k ms for first request, 15k ms from then on.
}
#endregion
#region Public Properties
public bool IsClosed {
get {
return _socket == null;
}
}
public bool IsLocal {
get {
return ((IPEndPoint) _remoteEndPoint).Address.IsLocal ();
}
}
public bool IsSecure {
get {
return _secure;
}
}
public IPEndPoint LocalEndPoint {
get {
return (IPEndPoint) _localEndPoint;
}
}
public IPEndPoint RemoteEndPoint {
get {
return (IPEndPoint) _remoteEndPoint;
}
}
public int Reuses {
get {
return _reuses;
}
}
public Stream Stream {
get {
return _stream;
}
}
#endregion
#region Private Methods
private void close ()
{
lock (_sync) {
if (_socket == null)
return;
disposeTimer ();
disposeRequestBuffer ();
disposeStream ();
closeSocket ();
}
_context.Unregister ();
_listener.RemoveConnection (this);
}
private void closeSocket ()
{
try {
_socket.Shutdown (SocketShutdown.Both);
}
catch {
}
_socket.Close ();
_socket = null;
}
private void disposeRequestBuffer ()
{
if (_requestBuffer == null)
return;
_requestBuffer.Dispose ();
_requestBuffer = null;
}
private void disposeStream ()
{
if (_stream == null)
return;
_stream.Dispose ();
_stream = null;
}
private void disposeTimer ()
{
if (_timer == null)
return;
try {
_timer.Change (Timeout.Infinite, Timeout.Infinite);
}
catch {
}
_timer.Dispose ();
_timer = null;
}
private void init (int timeout)
{
_timeout = timeout;
_context = new HttpListenerContext (this);
_currentLine = new StringBuilder (64);
_inputState = InputState.RequestLine;
_inputStream = null;
_lineState = LineState.None;
_outputStream = null;
_position = 0;
_requestBuffer = new MemoryStream ();
}
private static void onRead (IAsyncResult asyncResult)
{
var conn = (HttpConnection) asyncResult.AsyncState;
var current = conn._attempts;
if (conn._socket == null)
return;
lock (conn._sync) {
if (conn._socket == null)
return;
conn._timer.Change (Timeout.Infinite, Timeout.Infinite);
conn._timeoutCanceled[current] = true;
var nread = 0;
try {
nread = conn._stream.EndRead (asyncResult);
}
catch (Exception) {
// TODO: Logging.
conn.close ();
return;
}
if (nread <= 0) {
conn.close ();
return;
}
conn._requestBuffer.Write (conn._buffer, 0, nread);
var len = (int) conn._requestBuffer.Length;
if (conn.processInput (conn._requestBuffer.GetBuffer (), len)) {
if (!conn._context.HasErrorMessage)
conn._context.Request.FinishInitialization ();
if (conn._context.HasErrorMessage) {
conn._context.SendError ();
return;
}
var url = conn._context.Request.Url;
HttpListener lsnr;
if (conn._listener.TrySearchHttpListener (url, out lsnr)) {
if (!lsnr.AuthenticateContext (conn._context))
return;
if (!lsnr.RegisterContext (conn._context)) {
conn._context.ErrorStatusCode = 503;
conn._context.SendError ();
return;
}
return;
}
conn._context.ErrorStatusCode = 404;
conn._context.SendError ();
return;
}
conn.BeginReadRequest ();
}
}
private static void onTimeout (object state)
{
var conn = (HttpConnection) state;
var current = conn._attempts;
if (conn._socket == null)
return;
lock (conn._sync) {
if (conn._socket == null)
return;
if (conn._timeoutCanceled[current])
return;
conn._context.ErrorStatusCode = 408;
conn._context.SendError ();
}
}
private bool processInput (byte[] data, int length)
{
// This method returns a bool:
// - true Done processing
// - false Need more input
try {
while (true) {
int nread;
var line = readLineFrom (data, _position, length, out nread);
_position += nread;
if (line == null)
break;
if (line.Length == 0) {
if (_inputState == InputState.RequestLine)
continue;
if (_position > _maxInputLength)
_context.ErrorMessage = "Headers too long";
return true;
}
if (_inputState == InputState.RequestLine) {
_context.Request.SetRequestLine (line);
_inputState = InputState.Headers;
}
else {
_context.Request.AddHeader (line);
}
if (_context.HasErrorMessage)
return true;
}
}
catch (Exception ex) {
_context.ErrorMessage = ex.Message;
return true;
}
if (_position >= _maxInputLength) {
_context.ErrorMessage = "Headers too long";
return true;
}
return false;
}
private string readLineFrom (
byte[] buffer, int offset, int length, out int nread
)
{
nread = 0;
for (var i = offset; i < length; i++) {
nread++;
var b = buffer[i];
if (b == 13) {
_lineState = LineState.Cr;
continue;
}
if (b == 10) {
_lineState = LineState.Lf;
break;
}
_currentLine.Append ((char) b);
}
if (_lineState != LineState.Lf)
return null;
var ret = _currentLine.ToString ();
_currentLine.Length = 0;
_lineState = LineState.None;
return ret;
}
#endregion
#region Internal Methods
internal void BeginReadRequest ()
{
_attempts++;
_timeoutCanceled.Add (_attempts, false);
_timer.Change (_timeout, Timeout.Infinite);
try {
_stream.BeginRead (_buffer, 0, _bufferLength, onRead, this);
}
catch (Exception) {
// TODO: Logging.
close ();
}
}
internal void Close (bool force)
{
if (_socket == null)
return;
lock (_sync) {
if (_socket == null)
return;
if (force) {
if (_outputStream != null)
_outputStream.Close (true);
close ();
return;
}
GetResponseStream ().Close (false);
if (_context.Response.CloseConnection) {
close ();
return;
}
if (!_context.Request.FlushInput ()) {
close ();
return;
}
disposeRequestBuffer ();
_context.Unregister ();
_reuses++;
init (15000);
BeginReadRequest ();
}
}
#endregion
#region Public Methods
public void Close ()
{
Close (false);
}
public RequestStream GetRequestStream (long contentLength, bool chunked)
{
lock (_sync) {
if (_socket == null)
return null;
if (_inputStream != null)
return _inputStream;
var buff = _requestBuffer.GetBuffer ();
var len = (int) _requestBuffer.Length;
var cnt = len - _position;
disposeRequestBuffer ();
_inputStream = chunked
? new ChunkedRequestStream (
_stream, buff, _position, cnt, _context
)
: new RequestStream (
_stream, buff, _position, cnt, contentLength
);
return _inputStream;
}
}
public ResponseStream GetResponseStream ()
{
lock (_sync) {
if (_socket == null)
return null;
if (_outputStream != null)
return _outputStream;
var lsnr = _context.Listener;
var ignore = lsnr != null ? lsnr.IgnoreWriteExceptions : true;
_outputStream = new ResponseStream (_stream, _context.Response, ignore);
return _outputStream;
}
}
#endregion
}
}

View File

@ -1,187 +0,0 @@
#region License
/*
* HttpDigestIdentity.cs
*
* The MIT License
*
* Copyright (c) 2014-2017 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Collections.Specialized;
using System.Security.Principal;
namespace WebSocketSharp.Net
{
/// <summary>
/// Holds the username and other parameters from
/// an HTTP Digest authentication attempt.
/// </summary>
public class HttpDigestIdentity : GenericIdentity
{
#region Private Fields
private NameValueCollection _parameters;
#endregion
#region Internal Constructors
internal HttpDigestIdentity (NameValueCollection parameters)
: base (parameters["username"], "Digest")
{
_parameters = parameters;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the algorithm parameter from a digest authentication attempt.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the algorithm parameter.
/// </value>
public string Algorithm {
get {
return _parameters["algorithm"];
}
}
/// <summary>
/// Gets the cnonce parameter from a digest authentication attempt.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the cnonce parameter.
/// </value>
public string Cnonce {
get {
return _parameters["cnonce"];
}
}
/// <summary>
/// Gets the nc parameter from a digest authentication attempt.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the nc parameter.
/// </value>
public string Nc {
get {
return _parameters["nc"];
}
}
/// <summary>
/// Gets the nonce parameter from a digest authentication attempt.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the nonce parameter.
/// </value>
public string Nonce {
get {
return _parameters["nonce"];
}
}
/// <summary>
/// Gets the opaque parameter from a digest authentication attempt.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the opaque parameter.
/// </value>
public string Opaque {
get {
return _parameters["opaque"];
}
}
/// <summary>
/// Gets the qop parameter from a digest authentication attempt.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the qop parameter.
/// </value>
public string Qop {
get {
return _parameters["qop"];
}
}
/// <summary>
/// Gets the realm parameter from a digest authentication attempt.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the realm parameter.
/// </value>
public string Realm {
get {
return _parameters["realm"];
}
}
/// <summary>
/// Gets the response parameter from a digest authentication attempt.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the response parameter.
/// </value>
public string Response {
get {
return _parameters["response"];
}
}
/// <summary>
/// Gets the uri parameter from a digest authentication attempt.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the uri parameter.
/// </value>
public string Uri {
get {
return _parameters["uri"];
}
}
#endregion
#region Internal Methods
internal bool IsValid (
string password, string realm, string method, string entity
)
{
var copied = new NameValueCollection (_parameters);
copied["password"] = password;
copied["realm"] = realm;
copied["method"] = method;
copied["entity"] = entity;
var expected = AuthenticationResponse.CreateRequestDigest (copied);
return _parameters["response"] == expected;
}
#endregion
}
}

View File

@ -1,128 +0,0 @@
#region License
/*
* HttpHeaderInfo.cs
*
* The MIT License
*
* Copyright (c) 2013-2020 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp.Net
{
internal class HttpHeaderInfo
{
#region Private Fields
private string _headerName;
private HttpHeaderType _headerType;
#endregion
#region Internal Constructors
internal HttpHeaderInfo (string headerName, HttpHeaderType headerType)
{
_headerName = headerName;
_headerType = headerType;
}
#endregion
#region Internal Properties
internal bool IsMultiValueInRequest {
get {
var headerType = _headerType & HttpHeaderType.MultiValueInRequest;
return headerType == HttpHeaderType.MultiValueInRequest;
}
}
internal bool IsMultiValueInResponse {
get {
var headerType = _headerType & HttpHeaderType.MultiValueInResponse;
return headerType == HttpHeaderType.MultiValueInResponse;
}
}
#endregion
#region Public Properties
public string HeaderName {
get {
return _headerName;
}
}
public HttpHeaderType HeaderType {
get {
return _headerType;
}
}
public bool IsRequest {
get {
var headerType = _headerType & HttpHeaderType.Request;
return headerType == HttpHeaderType.Request;
}
}
public bool IsResponse {
get {
var headerType = _headerType & HttpHeaderType.Response;
return headerType == HttpHeaderType.Response;
}
}
#endregion
#region Public Methods
public bool IsMultiValue (bool response)
{
var headerType = _headerType & HttpHeaderType.MultiValue;
if (headerType != HttpHeaderType.MultiValue)
return response ? IsMultiValueInResponse : IsMultiValueInRequest;
return response ? IsResponse : IsRequest;
}
public bool IsRestricted (bool response)
{
var headerType = _headerType & HttpHeaderType.Restricted;
if (headerType != HttpHeaderType.Restricted)
return false;
return response ? IsResponse : IsRequest;
}
#endregion
}
}

View File

@ -1,44 +0,0 @@
#region License
/*
* HttpHeaderType.cs
*
* The MIT License
*
* Copyright (c) 2013-2014 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp.Net
{
[Flags]
internal enum HttpHeaderType
{
Unspecified = 0,
Request = 1,
Response = 1 << 1,
Restricted = 1 << 2,
MultiValue = 1 << 3,
MultiValueInRequest = 1 << 4,
MultiValueInResponse = 1 << 5
}
}

View File

@ -1,973 +0,0 @@
#region License
/*
* HttpListener.cs
*
* This code is derived from HttpListener.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
#region Contributors
/*
* Contributors:
* - Liryna <liryna.stark@gmail.com>
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using System.Security.Principal;
using System.Threading;
// TODO: Logging.
namespace WebSocketSharp.Net
{
/// <summary>
/// Provides a simple, programmatically controlled HTTP listener.
/// </summary>
public sealed class HttpListener : IDisposable
{
#region Private Fields
private AuthenticationSchemes _authSchemes;
private Func<HttpListenerRequest, AuthenticationSchemes> _authSchemeSelector;
private string _certFolderPath;
private Queue<HttpListenerContext> _contextQueue;
private LinkedList<HttpListenerContext> _contextRegistry;
private object _contextRegistrySync;
private static readonly string _defaultRealm;
private bool _disposed;
private bool _ignoreWriteExceptions;
private volatile bool _listening;
private Logger _log;
private string _objectName;
private HttpListenerPrefixCollection _prefixes;
private string _realm;
private bool _reuseAddress;
private ServerSslConfiguration _sslConfig;
private Func<IIdentity, NetworkCredential> _userCredFinder;
private Queue<HttpListenerAsyncResult> _waitQueue;
#endregion
#region Static Constructor
static HttpListener ()
{
_defaultRealm = "SECRET AREA";
}
#endregion
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="HttpListener"/> class.
/// </summary>
public HttpListener ()
{
_authSchemes = AuthenticationSchemes.Anonymous;
_contextQueue = new Queue<HttpListenerContext> ();
_contextRegistry = new LinkedList<HttpListenerContext> ();
_contextRegistrySync = ((ICollection) _contextRegistry).SyncRoot;
_log = new Logger ();
_objectName = GetType ().ToString ();
_prefixes = new HttpListenerPrefixCollection (this);
_waitQueue = new Queue<HttpListenerAsyncResult> ();
}
#endregion
#region Internal Properties
internal bool ReuseAddress {
get {
return _reuseAddress;
}
set {
_reuseAddress = value;
}
}
#endregion
#region Public Properties
/// <summary>
/// Gets or sets the scheme used to authenticate the clients.
/// </summary>
/// <value>
/// <para>
/// One of the <see cref="WebSocketSharp.Net.AuthenticationSchemes"/>
/// enum values.
/// </para>
/// <para>
/// It represents the scheme used to authenticate the clients.
/// </para>
/// <para>
/// The default value is
/// <see cref="WebSocketSharp.Net.AuthenticationSchemes.Anonymous"/>.
/// </para>
/// </value>
/// <exception cref="ObjectDisposedException">
/// This listener has been closed.
/// </exception>
public AuthenticationSchemes AuthenticationSchemes {
get {
if (_disposed)
throw new ObjectDisposedException (_objectName);
return _authSchemes;
}
set {
if (_disposed)
throw new ObjectDisposedException (_objectName);
_authSchemes = value;
}
}
/// <summary>
/// Gets or sets the delegate called to select the scheme used to
/// authenticate the clients.
/// </summary>
/// <remarks>
/// <para>
/// If this property is set, the listener uses the authentication
/// scheme selected by the delegate for each request.
/// </para>
/// <para>
/// Or if this property is not set, the listener uses the value of
/// the <see cref="HttpListener.AuthenticationSchemes"/> property
/// as the authentication scheme for all requests.
/// </para>
/// </remarks>
/// <value>
/// <para>
/// A <c>Func&lt;<see cref="HttpListenerRequest"/>,
/// <see cref="AuthenticationSchemes"/>&gt;</c> delegate or
/// <see langword="null"/> if not needed.
/// </para>
/// <para>
/// The delegate references the method used to select
/// an authentication scheme.
/// </para>
/// <para>
/// The default value is <see langword="null"/>.
/// </para>
/// </value>
/// <exception cref="ObjectDisposedException">
/// This listener has been closed.
/// </exception>
public Func<HttpListenerRequest, AuthenticationSchemes> AuthenticationSchemeSelector {
get {
if (_disposed)
throw new ObjectDisposedException (_objectName);
return _authSchemeSelector;
}
set {
if (_disposed)
throw new ObjectDisposedException (_objectName);
_authSchemeSelector = value;
}
}
/// <summary>
/// Gets or sets the path to the folder in which stores the certificate
/// files used to authenticate the server on the secure connection.
/// </summary>
/// <remarks>
/// <para>
/// This property represents the path to the folder in which stores
/// the certificate files associated with each port number of added
/// URI prefixes.
/// </para>
/// <para>
/// A set of the certificate files is a pair of &lt;port number&gt;.cer
/// (DER) and &lt;port number&gt;.key (DER, RSA Private Key).
/// </para>
/// <para>
/// If this property is <see langword="null"/> or an empty string,
/// the result of <c>System.Environment.GetFolderPath (<see
/// cref="Environment.SpecialFolder.ApplicationData"/>)</c>
/// is used as the default path.
/// </para>
/// </remarks>
/// <value>
/// <para>
/// A <see cref="string"/> that represents the path to the folder
/// in which stores the certificate files.
/// </para>
/// <para>
/// The default value is <see langword="null"/>.
/// </para>
/// </value>
/// <exception cref="ObjectDisposedException">
/// This listener has been closed.
/// </exception>
public string CertificateFolderPath {
get {
if (_disposed)
throw new ObjectDisposedException (_objectName);
return _certFolderPath;
}
set {
if (_disposed)
throw new ObjectDisposedException (_objectName);
_certFolderPath = value;
}
}
/// <summary>
/// Gets or sets a value indicating whether the listener returns
/// exceptions that occur when sending the response to the client.
/// </summary>
/// <value>
/// <para>
/// <c>true</c> if the listener should not return those exceptions;
/// otherwise, <c>false</c>.
/// </para>
/// <para>
/// The default value is <c>false</c>.
/// </para>
/// </value>
/// <exception cref="ObjectDisposedException">
/// This listener has been closed.
/// </exception>
public bool IgnoreWriteExceptions {
get {
if (_disposed)
throw new ObjectDisposedException (_objectName);
return _ignoreWriteExceptions;
}
set {
if (_disposed)
throw new ObjectDisposedException (_objectName);
_ignoreWriteExceptions = value;
}
}
/// <summary>
/// Gets a value indicating whether the listener has been started.
/// </summary>
/// <value>
/// <c>true</c> if the listener has been started; otherwise, <c>false</c>.
/// </value>
public bool IsListening {
get {
return _listening;
}
}
/// <summary>
/// Gets a value indicating whether the listener can be used with
/// the current operating system.
/// </summary>
/// <value>
/// <c>true</c>.
/// </value>
public static bool IsSupported {
get {
return true;
}
}
/// <summary>
/// Gets the logging functions.
/// </summary>
/// <remarks>
/// <para>
/// The default logging level is <see cref="LogLevel.Error"/>.
/// </para>
/// <para>
/// If you would like to change it, you should set the <c>Log.Level</c>
/// property to any of the <see cref="LogLevel"/> enum values.
/// </para>
/// </remarks>
/// <value>
/// A <see cref="Logger"/> that provides the logging functions.
/// </value>
public Logger Log {
get {
return _log;
}
}
/// <summary>
/// Gets the URI prefixes handled by the listener.
/// </summary>
/// <value>
/// A <see cref="HttpListenerPrefixCollection"/> that contains the URI
/// prefixes.
/// </value>
/// <exception cref="ObjectDisposedException">
/// This listener has been closed.
/// </exception>
public HttpListenerPrefixCollection Prefixes {
get {
if (_disposed)
throw new ObjectDisposedException (_objectName);
return _prefixes;
}
}
/// <summary>
/// Gets or sets the name of the realm associated with the listener.
/// </summary>
/// <remarks>
/// If this property is <see langword="null"/> or an empty string,
/// "SECRET AREA" will be used as the name of the realm.
/// </remarks>
/// <value>
/// <para>
/// A <see cref="string"/> that represents the name of the realm.
/// </para>
/// <para>
/// The default value is <see langword="null"/>.
/// </para>
/// </value>
/// <exception cref="ObjectDisposedException">
/// This listener has been closed.
/// </exception>
public string Realm {
get {
if (_disposed)
throw new ObjectDisposedException (_objectName);
return _realm;
}
set {
if (_disposed)
throw new ObjectDisposedException (_objectName);
_realm = value;
}
}
/// <summary>
/// Gets the SSL configuration used to authenticate the server and
/// optionally the client for secure connection.
/// </summary>
/// <value>
/// A <see cref="ServerSslConfiguration"/> that represents the SSL
/// configuration for secure connection.
/// </value>
/// <exception cref="ObjectDisposedException">
/// This listener has been closed.
/// </exception>
public ServerSslConfiguration SslConfiguration {
get {
if (_disposed)
throw new ObjectDisposedException (_objectName);
if (_sslConfig == null)
_sslConfig = new ServerSslConfiguration ();
return _sslConfig;
}
}
/// <summary>
/// Gets or sets a value indicating whether, when NTLM authentication is used,
/// the authentication information of first request is used to authenticate
/// additional requests on the same connection.
/// </summary>
/// <remarks>
/// This property is not currently supported and always throws
/// a <see cref="NotSupportedException"/>.
/// </remarks>
/// <value>
/// <c>true</c> if the authentication information of first request is used;
/// otherwise, <c>false</c>.
/// </value>
/// <exception cref="NotSupportedException">
/// Any use of this property.
/// </exception>
public bool UnsafeConnectionNtlmAuthentication {
get {
throw new NotSupportedException ();
}
set {
throw new NotSupportedException ();
}
}
/// <summary>
/// Gets or sets the delegate called to find the credentials for
/// an identity used to authenticate a client.
/// </summary>
/// <value>
/// <para>
/// A <c>Func&lt;<see cref="IIdentity"/>,
/// <see cref="NetworkCredential"/>&gt;</c> delegate or
/// <see langword="null"/> if not needed.
/// </para>
/// <para>
/// It references the method used to find the credentials.
/// </para>
/// <para>
/// The default value is <see langword="null"/>.
/// </para>
/// </value>
/// <exception cref="ObjectDisposedException">
/// This listener has been closed.
/// </exception>
public Func<IIdentity, NetworkCredential> UserCredentialsFinder {
get {
if (_disposed)
throw new ObjectDisposedException (_objectName);
return _userCredFinder;
}
set {
if (_disposed)
throw new ObjectDisposedException (_objectName);
_userCredFinder = value;
}
}
#endregion
#region Private Methods
private HttpListenerAsyncResult beginGetContext (
AsyncCallback callback, object state
)
{
lock (_contextRegistrySync) {
if (!_listening) {
var msg = _disposed
? "The listener is closed."
: "The listener is stopped.";
throw new HttpListenerException (995, msg);
}
var ares = new HttpListenerAsyncResult (callback, state);
if (_contextQueue.Count == 0) {
_waitQueue.Enqueue (ares);
}
else {
var ctx = _contextQueue.Dequeue ();
ares.Complete (ctx, true);
}
return ares;
}
}
private void cleanupContextQueue (bool force)
{
if (_contextQueue.Count == 0)
return;
if (force) {
_contextQueue.Clear ();
return;
}
var ctxs = _contextQueue.ToArray ();
_contextQueue.Clear ();
foreach (var ctx in ctxs) {
ctx.ErrorStatusCode = 503;
ctx.SendError ();
}
}
private void cleanupContextRegistry ()
{
var cnt = _contextRegistry.Count;
if (cnt == 0)
return;
var ctxs = new HttpListenerContext[cnt];
_contextRegistry.CopyTo (ctxs, 0);
_contextRegistry.Clear ();
foreach (var ctx in ctxs)
ctx.Connection.Close (true);
}
private void cleanupWaitQueue (string message)
{
if (_waitQueue.Count == 0)
return;
var aress = _waitQueue.ToArray ();
_waitQueue.Clear ();
foreach (var ares in aress) {
var ex = new HttpListenerException (995, message);
ares.Complete (ex);
}
}
private void close (bool force)
{
if (!_listening) {
_disposed = true;
return;
}
_listening = false;
cleanupContextQueue (force);
cleanupContextRegistry ();
var msg = "The listener is closed.";
cleanupWaitQueue (msg);
EndPointManager.RemoveListener (this);
_disposed = true;
}
private string getRealm ()
{
var realm = _realm;
return realm != null && realm.Length > 0 ? realm : _defaultRealm;
}
private AuthenticationSchemes selectAuthenticationScheme (
HttpListenerRequest request
)
{
var selector = _authSchemeSelector;
if (selector == null)
return _authSchemes;
try {
return selector (request);
}
catch {
return AuthenticationSchemes.None;
}
}
#endregion
#region Internal Methods
internal bool AuthenticateContext (HttpListenerContext context)
{
var req = context.Request;
var schm = selectAuthenticationScheme (req);
if (schm == AuthenticationSchemes.Anonymous)
return true;
if (schm == AuthenticationSchemes.None) {
context.ErrorStatusCode = 403;
context.ErrorMessage = "Authentication not allowed";
context.SendError ();
return false;
}
var realm = getRealm ();
var user = HttpUtility.CreateUser (
req.Headers["Authorization"],
schm,
realm,
req.HttpMethod,
_userCredFinder
);
var authenticated = user != null && user.Identity.IsAuthenticated;
if (!authenticated) {
context.SendAuthenticationChallenge (schm, realm);
return false;
}
context.User = user;
return true;
}
internal void CheckDisposed ()
{
if (_disposed)
throw new ObjectDisposedException (_objectName);
}
internal bool RegisterContext (HttpListenerContext context)
{
if (!_listening)
return false;
lock (_contextRegistrySync) {
if (!_listening)
return false;
context.Listener = this;
_contextRegistry.AddLast (context);
if (_waitQueue.Count == 0) {
_contextQueue.Enqueue (context);
}
else {
var ares = _waitQueue.Dequeue ();
ares.Complete (context, false);
}
return true;
}
}
internal void UnregisterContext (HttpListenerContext context)
{
lock (_contextRegistrySync)
_contextRegistry.Remove (context);
}
#endregion
#region Public Methods
/// <summary>
/// Shuts down the listener immediately.
/// </summary>
public void Abort ()
{
if (_disposed)
return;
lock (_contextRegistrySync) {
if (_disposed)
return;
close (true);
}
}
/// <summary>
/// Begins getting an incoming request asynchronously.
/// </summary>
/// <remarks>
/// <para>
/// This asynchronous operation must be completed by calling
/// the EndGetContext method.
/// </para>
/// <para>
/// Typically, the EndGetContext method is called by
/// <paramref name="callback"/>.
/// </para>
/// </remarks>
/// <returns>
/// An <see cref="IAsyncResult"/> that represents the status of
/// the asynchronous operation.
/// </returns>
/// <param name="callback">
/// An <see cref="AsyncCallback"/> delegate that references the method to
/// invoke when the asynchronous operation completes.
/// </param>
/// <param name="state">
/// An <see cref="object"/> that represents a user defined object to
/// pass to <paramref name="callback"/>.
/// </param>
/// <exception cref="InvalidOperationException">
/// <para>
/// This listener has no URI prefix on which listens.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// This listener has not been started or is currently stopped.
/// </para>
/// </exception>
/// <exception cref="HttpListenerException">
/// This method is canceled.
/// </exception>
/// <exception cref="ObjectDisposedException">
/// This listener has been closed.
/// </exception>
public IAsyncResult BeginGetContext (AsyncCallback callback, object state)
{
if (_disposed)
throw new ObjectDisposedException (_objectName);
if (_prefixes.Count == 0) {
var msg = "The listener has no URI prefix on which listens.";
throw new InvalidOperationException (msg);
}
if (!_listening) {
var msg = "The listener has not been started.";
throw new InvalidOperationException (msg);
}
return beginGetContext (callback, state);
}
/// <summary>
/// Shuts down the listener.
/// </summary>
public void Close ()
{
if (_disposed)
return;
lock (_contextRegistrySync) {
if (_disposed)
return;
close (false);
}
}
/// <summary>
/// Ends an asynchronous operation to get an incoming request.
/// </summary>
/// <remarks>
/// This method completes an asynchronous operation started by calling
/// the BeginGetContext method.
/// </remarks>
/// <returns>
/// A <see cref="HttpListenerContext"/> that represents a request.
/// </returns>
/// <param name="asyncResult">
/// An <see cref="IAsyncResult"/> instance obtained by calling
/// the BeginGetContext method.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="asyncResult"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="asyncResult"/> was not obtained by calling
/// the BeginGetContext method.
/// </exception>
/// <exception cref="InvalidOperationException">
/// This method was already called for <paramref name="asyncResult"/>.
/// </exception>
/// <exception cref="HttpListenerException">
/// This method is canceled.
/// </exception>
/// <exception cref="ObjectDisposedException">
/// This listener has been closed.
/// </exception>
public HttpListenerContext EndGetContext (IAsyncResult asyncResult)
{
if (_disposed)
throw new ObjectDisposedException (_objectName);
if (asyncResult == null)
throw new ArgumentNullException ("asyncResult");
var ares = asyncResult as HttpListenerAsyncResult;
if (ares == null) {
var msg = "A wrong IAsyncResult instance.";
throw new ArgumentException (msg, "asyncResult");
}
lock (ares.SyncRoot) {
if (ares.EndCalled) {
var msg = "This IAsyncResult instance cannot be reused.";
throw new InvalidOperationException (msg);
}
ares.EndCalled = true;
}
if (!ares.IsCompleted)
ares.AsyncWaitHandle.WaitOne ();
return ares.Context;
}
/// <summary>
/// Gets an incoming request.
/// </summary>
/// <remarks>
/// This method waits for an incoming request and returns when a request is
/// received.
/// </remarks>
/// <returns>
/// A <see cref="HttpListenerContext"/> that represents a request.
/// </returns>
/// <exception cref="InvalidOperationException">
/// <para>
/// This listener has no URI prefix on which listens.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// This listener has not been started or is currently stopped.
/// </para>
/// </exception>
/// <exception cref="HttpListenerException">
/// This method is canceled.
/// </exception>
/// <exception cref="ObjectDisposedException">
/// This listener has been closed.
/// </exception>
public HttpListenerContext GetContext ()
{
if (_disposed)
throw new ObjectDisposedException (_objectName);
if (_prefixes.Count == 0) {
var msg = "The listener has no URI prefix on which listens.";
throw new InvalidOperationException (msg);
}
if (!_listening) {
var msg = "The listener has not been started.";
throw new InvalidOperationException (msg);
}
var ares = beginGetContext (null, null);
ares.EndCalled = true;
if (!ares.IsCompleted)
ares.AsyncWaitHandle.WaitOne ();
return ares.Context;
}
/// <summary>
/// Starts receiving incoming requests.
/// </summary>
/// <exception cref="ObjectDisposedException">
/// This listener has been closed.
/// </exception>
public void Start ()
{
if (_disposed)
throw new ObjectDisposedException (_objectName);
lock (_contextRegistrySync) {
if (_disposed)
throw new ObjectDisposedException (_objectName);
if (_listening)
return;
EndPointManager.AddListener (this);
_listening = true;
}
}
/// <summary>
/// Stops receiving incoming requests.
/// </summary>
/// <exception cref="ObjectDisposedException">
/// This listener has been closed.
/// </exception>
public void Stop ()
{
if (_disposed)
throw new ObjectDisposedException (_objectName);
lock (_contextRegistrySync) {
if (!_listening)
return;
_listening = false;
cleanupContextQueue (false);
cleanupContextRegistry ();
var msg = "The listener is stopped.";
cleanupWaitQueue (msg);
EndPointManager.RemoveListener (this);
}
}
#endregion
#region Explicit Interface Implementations
/// <summary>
/// Releases all resources used by the listener.
/// </summary>
void IDisposable.Dispose ()
{
if (_disposed)
return;
lock (_contextRegistrySync) {
if (_disposed)
return;
close (true);
}
}
#endregion
}
}

View File

@ -1,193 +0,0 @@
#region License
/*
* HttpListenerAsyncResult.cs
*
* This code is derived from ListenerAsyncResult.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Ximian, Inc. (http://www.ximian.com)
* Copyright (c) 2012-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@ximian.com>
*/
#endregion
#region Contributors
/*
* Contributors:
* - Nicholas Devenish
*/
#endregion
using System;
using System.Threading;
namespace WebSocketSharp.Net
{
internal class HttpListenerAsyncResult : IAsyncResult
{
#region Private Fields
private AsyncCallback _callback;
private bool _completed;
private bool _completedSynchronously;
private HttpListenerContext _context;
private bool _endCalled;
private Exception _exception;
private object _state;
private object _sync;
private ManualResetEvent _waitHandle;
#endregion
#region Internal Constructors
internal HttpListenerAsyncResult (AsyncCallback callback, object state)
{
_callback = callback;
_state = state;
_sync = new object ();
}
#endregion
#region Internal Properties
internal HttpListenerContext Context
{
get {
if (_exception != null)
throw _exception;
return _context;
}
}
internal bool EndCalled {
get {
return _endCalled;
}
set {
_endCalled = value;
}
}
internal object SyncRoot {
get {
return _sync;
}
}
#endregion
#region Public Properties
public object AsyncState {
get {
return _state;
}
}
public WaitHandle AsyncWaitHandle {
get {
lock (_sync) {
if (_waitHandle == null)
_waitHandle = new ManualResetEvent (_completed);
return _waitHandle;
}
}
}
public bool CompletedSynchronously {
get {
return _completedSynchronously;
}
}
public bool IsCompleted {
get {
lock (_sync)
return _completed;
}
}
#endregion
#region Private Methods
private void complete ()
{
lock (_sync) {
_completed = true;
if (_waitHandle != null)
_waitHandle.Set ();
}
if (_callback == null)
return;
ThreadPool.QueueUserWorkItem (
state => {
try {
_callback (this);
}
catch {
}
},
null
);
}
#endregion
#region Internal Methods
internal void Complete (Exception exception)
{
_exception = exception;
complete ();
}
internal void Complete (
HttpListenerContext context, bool completedSynchronously
)
{
_context = context;
_completedSynchronously = completedSynchronously;
complete ();
}
#endregion
}
}

View File

@ -1,311 +0,0 @@
#region License
/*
* HttpListenerContext.cs
*
* This code is derived from HttpListenerContext.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2020 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
using System;
using System.Security.Principal;
using System.Text;
using WebSocketSharp.Net.WebSockets;
namespace WebSocketSharp.Net
{
/// <summary>
/// Provides the access to the HTTP request and response objects used by
/// the <see cref="HttpListener"/> class.
/// </summary>
/// <remarks>
/// This class cannot be inherited.
/// </remarks>
public sealed class HttpListenerContext
{
#region Private Fields
private HttpConnection _connection;
private string _errorMessage;
private int _errorStatusCode;
private HttpListener _listener;
private HttpListenerRequest _request;
private HttpListenerResponse _response;
private IPrincipal _user;
private HttpListenerWebSocketContext _websocketContext;
#endregion
#region Internal Constructors
internal HttpListenerContext (HttpConnection connection)
{
_connection = connection;
_errorStatusCode = 400;
_request = new HttpListenerRequest (this);
_response = new HttpListenerResponse (this);
}
#endregion
#region Internal Properties
internal HttpConnection Connection {
get {
return _connection;
}
}
internal string ErrorMessage {
get {
return _errorMessage;
}
set {
_errorMessage = value;
}
}
internal int ErrorStatusCode {
get {
return _errorStatusCode;
}
set {
_errorStatusCode = value;
}
}
internal bool HasErrorMessage {
get {
return _errorMessage != null;
}
}
internal HttpListener Listener {
get {
return _listener;
}
set {
_listener = value;
}
}
#endregion
#region Public Properties
/// <summary>
/// Gets the HTTP request object that represents a client request.
/// </summary>
/// <value>
/// A <see cref="HttpListenerRequest"/> that represents the client request.
/// </value>
public HttpListenerRequest Request {
get {
return _request;
}
}
/// <summary>
/// Gets the HTTP response object used to send a response to the client.
/// </summary>
/// <value>
/// A <see cref="HttpListenerResponse"/> that represents a response to
/// the client request.
/// </value>
public HttpListenerResponse Response {
get {
return _response;
}
}
/// <summary>
/// Gets the client information (identity, authentication, and security
/// roles).
/// </summary>
/// <value>
/// <para>
/// A <see cref="IPrincipal"/> instance or <see langword="null"/>
/// if not authenticated.
/// </para>
/// <para>
/// The instance describes the client.
/// </para>
/// </value>
public IPrincipal User {
get {
return _user;
}
internal set {
_user = value;
}
}
#endregion
#region Private Methods
private static string createErrorContent (
int statusCode, string statusDescription, string message
)
{
return message != null && message.Length > 0
? String.Format (
"<html><body><h1>{0} {1} ({2})</h1></body></html>",
statusCode,
statusDescription,
message
)
: String.Format (
"<html><body><h1>{0} {1}</h1></body></html>",
statusCode,
statusDescription
);
}
#endregion
#region Internal Methods
internal HttpListenerWebSocketContext GetWebSocketContext (string protocol)
{
_websocketContext = new HttpListenerWebSocketContext (this, protocol);
return _websocketContext;
}
internal void SendAuthenticationChallenge (
AuthenticationSchemes scheme, string realm
)
{
var chal = new AuthenticationChallenge (scheme, realm).ToString ();
_response.StatusCode = 401;
_response.Headers.InternalSet ("WWW-Authenticate", chal, true);
_response.Close ();
}
internal void SendError ()
{
try {
_response.StatusCode = _errorStatusCode;
_response.ContentType = "text/html";
var content = createErrorContent (
_errorStatusCode,
_response.StatusDescription,
_errorMessage
);
var enc = Encoding.UTF8;
var entity = enc.GetBytes (content);
_response.ContentEncoding = enc;
_response.ContentLength64 = entity.LongLength;
_response.Close (entity, true);
}
catch {
_connection.Close (true);
}
}
internal void Unregister ()
{
if (_listener == null)
return;
_listener.UnregisterContext (this);
}
#endregion
#region Public Methods
/// <summary>
/// Accepts a WebSocket handshake request.
/// </summary>
/// <returns>
/// A <see cref="HttpListenerWebSocketContext"/> that represents
/// the WebSocket handshake request.
/// </returns>
/// <param name="protocol">
/// A <see cref="string"/> that specifies the subprotocol supported on
/// the WebSocket connection.
/// </param>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="protocol"/> is empty.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="protocol"/> contains an invalid character.
/// </para>
/// </exception>
/// <exception cref="InvalidOperationException">
/// This method has already been called.
/// </exception>
public HttpListenerWebSocketContext AcceptWebSocket (string protocol)
{
if (_websocketContext != null) {
var msg = "The accepting is already in progress.";
throw new InvalidOperationException (msg);
}
if (protocol != null) {
if (protocol.Length == 0) {
var msg = "An empty string.";
throw new ArgumentException (msg, "protocol");
}
if (!protocol.IsToken ()) {
var msg = "It contains an invalid character.";
throw new ArgumentException (msg, "protocol");
}
}
return GetWebSocketContext (protocol);
}
#endregion
}
}

View File

@ -1,137 +0,0 @@
#region License
/*
* HttpListenerException.cs
*
* This code is derived from HttpListenerException.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
using System;
using System.ComponentModel;
using System.Runtime.Serialization;
namespace WebSocketSharp.Net
{
/// <summary>
/// The exception that is thrown when an error occurs processing
/// an HTTP request.
/// </summary>
[Serializable]
public class HttpListenerException : Win32Exception
{
#region Protected Constructors
/// <summary>
/// Initializes a new instance of the <see cref="HttpListenerException"/>
/// class from the specified instances of the <see cref="SerializationInfo"/>
/// and <see cref="StreamingContext"/> classes.
/// </summary>
/// <param name="serializationInfo">
/// A <see cref="SerializationInfo"/> that contains the serialized
/// object data.
/// </param>
/// <param name="streamingContext">
/// A <see cref="StreamingContext"/> that specifies the source for
/// the deserialization.
/// </param>
protected HttpListenerException (
SerializationInfo serializationInfo, StreamingContext streamingContext
)
: base (serializationInfo, streamingContext)
{
}
#endregion
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="HttpListenerException"/>
/// class.
/// </summary>
public HttpListenerException ()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="HttpListenerException"/>
/// class with the specified error code.
/// </summary>
/// <param name="errorCode">
/// An <see cref="int"/> that specifies the error code.
/// </param>
public HttpListenerException (int errorCode)
: base (errorCode)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="HttpListenerException"/>
/// class with the specified error code and message.
/// </summary>
/// <param name="errorCode">
/// An <see cref="int"/> that specifies the error code.
/// </param>
/// <param name="message">
/// A <see cref="string"/> that specifies the message.
/// </param>
public HttpListenerException (int errorCode, string message)
: base (errorCode, message)
{
}
#endregion
#region Public Properties
/// <summary>
/// Gets the error code that identifies the error that occurred.
/// </summary>
/// <value>
/// <para>
/// An <see cref="int"/> that represents the error code.
/// </para>
/// <para>
/// It is any of the Win32 error codes.
/// </para>
/// </value>
public override int ErrorCode {
get {
return NativeErrorCode;
}
}
#endregion
}
}

View File

@ -1,273 +0,0 @@
#region License
/*
* HttpListenerPrefix.cs
*
* This code is derived from ListenerPrefix.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2020 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
* - Oleg Mihailik <mihailik@gmail.com>
*/
#endregion
using System;
namespace WebSocketSharp.Net
{
internal sealed class HttpListenerPrefix
{
#region Private Fields
private string _host;
private HttpListener _listener;
private string _original;
private string _path;
private string _port;
private string _prefix;
private bool _secure;
#endregion
#region Internal Constructors
/// <summary>
/// Initializes a new instance of the <see cref="HttpListenerPrefix"/> class
/// with the specified URI prefix and HTTP listener.
/// </summary>
/// <remarks>
/// This constructor must be called after calling the CheckPrefix method.
/// </remarks>
/// <param name="uriPrefix">
/// A <see cref="string"/> that specifies the URI prefix.
/// </param>
/// <param name="listener">
/// A <see cref="HttpListener"/> that specifies the HTTP listener.
/// </param>
internal HttpListenerPrefix (string uriPrefix, HttpListener listener)
{
_original = uriPrefix;
_listener = listener;
parse (uriPrefix);
}
#endregion
#region Public Properties
public string Host {
get {
return _host;
}
}
public bool IsSecure {
get {
return _secure;
}
}
public HttpListener Listener {
get {
return _listener;
}
}
public string Original {
get {
return _original;
}
}
public string Path {
get {
return _path;
}
}
public string Port {
get {
return _port;
}
}
#endregion
#region Private Methods
private void parse (string uriPrefix)
{
if (uriPrefix.StartsWith ("https"))
_secure = true;
var len = uriPrefix.Length;
var host = uriPrefix.IndexOf (':') + 3;
var root = uriPrefix.IndexOf ('/', host + 1, len - host - 1);
var colon = uriPrefix.LastIndexOf (':', root - 1, root - host - 1);
if (uriPrefix[root - 1] != ']' && colon > host) {
_host = uriPrefix.Substring (host, colon - host);
_port = uriPrefix.Substring (colon + 1, root - colon - 1);
}
else {
_host = uriPrefix.Substring (host, root - host);
_port = _secure ? "443" : "80";
}
_path = uriPrefix.Substring (root);
_prefix = String.Format (
"{0}://{1}:{2}{3}",
_secure ? "https" : "http",
_host,
_port,
_path
);
}
#endregion
#region Public Methods
public static void CheckPrefix (string uriPrefix)
{
if (uriPrefix == null)
throw new ArgumentNullException ("uriPrefix");
var len = uriPrefix.Length;
if (len == 0) {
var msg = "An empty string.";
throw new ArgumentException (msg, "uriPrefix");
}
var schm = uriPrefix.StartsWith ("http://")
|| uriPrefix.StartsWith ("https://");
if (!schm) {
var msg = "The scheme is not 'http' or 'https'.";
throw new ArgumentException (msg, "uriPrefix");
}
var end = len - 1;
if (uriPrefix[end] != '/') {
var msg = "It ends without '/'.";
throw new ArgumentException (msg, "uriPrefix");
}
var host = uriPrefix.IndexOf (':') + 3;
if (host >= end) {
var msg = "No host is specified.";
throw new ArgumentException (msg, "uriPrefix");
}
if (uriPrefix[host] == ':') {
var msg = "No host is specified.";
throw new ArgumentException (msg, "uriPrefix");
}
var root = uriPrefix.IndexOf ('/', host, len - host);
if (root == host) {
var msg = "No host is specified.";
throw new ArgumentException (msg, "uriPrefix");
}
if (uriPrefix[root - 1] == ':') {
var msg = "No port is specified.";
throw new ArgumentException (msg, "uriPrefix");
}
if (root == end - 1) {
var msg = "No path is specified.";
throw new ArgumentException (msg, "uriPrefix");
}
}
/// <summary>
/// Determines whether the current instance is equal to the specified
/// <see cref="object"/> instance.
/// </summary>
/// <remarks>
/// This method will be required to detect duplicates in any collection.
/// </remarks>
/// <param name="obj">
/// <para>
/// An <see cref="object"/> instance to compare to the current instance.
/// </para>
/// <para>
/// An reference to a <see cref="HttpListenerPrefix"/> instance.
/// </para>
/// </param>
/// <returns>
/// <c>true</c> if the current instance and <paramref name="obj"/> have
/// the same URI prefix; otherwise, <c>false</c>.
/// </returns>
public override bool Equals (object obj)
{
var pref = obj as HttpListenerPrefix;
return pref != null && _prefix.Equals (pref._prefix);
}
/// <summary>
/// Gets the hash code for the current instance.
/// </summary>
/// <remarks>
/// This method will be required to detect duplicates in any collection.
/// </remarks>
/// <returns>
/// An <see cref="int"/> that represents the hash code.
/// </returns>
public override int GetHashCode ()
{
return _prefix.GetHashCode ();
}
public override string ToString ()
{
return _prefix;
}
#endregion
}
}

View File

@ -1,294 +0,0 @@
#region License
/*
* HttpListenerPrefixCollection.cs
*
* This code is derived from HttpListenerPrefixCollection.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2020 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
namespace WebSocketSharp.Net
{
/// <summary>
/// Provides a collection used to store the URI prefixes for a instance of
/// the <see cref="HttpListener"/> class.
/// </summary>
/// <remarks>
/// The <see cref="HttpListener"/> instance responds to the request which has
/// a requested URI that the prefixes most closely match.
/// </remarks>
public class HttpListenerPrefixCollection : ICollection<string>
{
#region Private Fields
private HttpListener _listener;
private List<string> _prefixes;
#endregion
#region Internal Constructors
internal HttpListenerPrefixCollection (HttpListener listener)
{
_listener = listener;
_prefixes = new List<string> ();
}
#endregion
#region Public Properties
/// <summary>
/// Gets the number of prefixes in the collection.
/// </summary>
/// <value>
/// An <see cref="int"/> that represents the number of prefixes.
/// </value>
public int Count {
get {
return _prefixes.Count;
}
}
/// <summary>
/// Gets a value indicating whether the access to the collection is
/// read-only.
/// </summary>
/// <value>
/// Always returns <c>false</c>.
/// </value>
public bool IsReadOnly {
get {
return false;
}
}
/// <summary>
/// Gets a value indicating whether the access to the collection is
/// synchronized.
/// </summary>
/// <value>
/// Always returns <c>false</c>.
/// </value>
public bool IsSynchronized {
get {
return false;
}
}
#endregion
#region Public Methods
/// <summary>
/// Adds the specified URI prefix to the collection.
/// </summary>
/// <param name="uriPrefix">
/// <para>
/// A <see cref="string"/> that specifies the URI prefix to add.
/// </para>
/// <para>
/// It must be a well-formed URI prefix with http or https scheme,
/// and must end with a '/'.
/// </para>
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="uriPrefix"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="uriPrefix"/> is invalid.
/// </exception>
/// <exception cref="ObjectDisposedException">
/// The <see cref="HttpListener"/> instance associated with this
/// collection is closed.
/// </exception>
public void Add (string uriPrefix)
{
_listener.CheckDisposed ();
HttpListenerPrefix.CheckPrefix (uriPrefix);
if (_prefixes.Contains (uriPrefix))
return;
if (_listener.IsListening)
EndPointManager.AddPrefix (uriPrefix, _listener);
_prefixes.Add (uriPrefix);
}
/// <summary>
/// Removes all URI prefixes from the collection.
/// </summary>
/// <exception cref="ObjectDisposedException">
/// The <see cref="HttpListener"/> instance associated with this
/// collection is closed.
/// </exception>
public void Clear ()
{
_listener.CheckDisposed ();
if (_listener.IsListening)
EndPointManager.RemoveListener (_listener);
_prefixes.Clear ();
}
/// <summary>
/// Returns a value indicating whether the collection contains the
/// specified URI prefix.
/// </summary>
/// <returns>
/// <c>true</c> if the collection contains the URI prefix; otherwise,
/// <c>false</c>.
/// </returns>
/// <param name="uriPrefix">
/// A <see cref="string"/> that specifies the URI prefix to test.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="uriPrefix"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ObjectDisposedException">
/// The <see cref="HttpListener"/> instance associated with this
/// collection is closed.
/// </exception>
public bool Contains (string uriPrefix)
{
_listener.CheckDisposed ();
if (uriPrefix == null)
throw new ArgumentNullException ("uriPrefix");
return _prefixes.Contains (uriPrefix);
}
/// <summary>
/// Copies the contents of the collection to the specified array of string.
/// </summary>
/// <param name="array">
/// An array of <see cref="string"/> that specifies the destination of
/// the URI prefix strings copied from the collection.
/// </param>
/// <param name="offset">
/// An <see cref="int"/> that specifies the zero-based index in
/// the array at which copying begins.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="array"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="offset"/> is less than zero.
/// </exception>
/// <exception cref="ArgumentException">
/// The space from <paramref name="offset"/> to the end of
/// <paramref name="array"/> is not enough to copy to.
/// </exception>
/// <exception cref="ObjectDisposedException">
/// The <see cref="HttpListener"/> instance associated with this
/// collection is closed.
/// </exception>
public void CopyTo (string[] array, int offset)
{
_listener.CheckDisposed ();
_prefixes.CopyTo (array, offset);
}
/// <summary>
/// Gets the enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.Generic.IEnumerator{string}"/>
/// instance that can be used to iterate through the collection.
/// </returns>
public IEnumerator<string> GetEnumerator ()
{
return _prefixes.GetEnumerator ();
}
/// <summary>
/// Removes the specified URI prefix from the collection.
/// </summary>
/// <returns>
/// <c>true</c> if the URI prefix is successfully removed; otherwise,
/// <c>false</c>.
/// </returns>
/// <param name="uriPrefix">
/// A <see cref="string"/> that specifies the URI prefix to remove.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="uriPrefix"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ObjectDisposedException">
/// The <see cref="HttpListener"/> instance associated with this
/// collection is closed.
/// </exception>
public bool Remove (string uriPrefix)
{
_listener.CheckDisposed ();
if (uriPrefix == null)
throw new ArgumentNullException ("uriPrefix");
if (!_prefixes.Contains (uriPrefix))
return false;
if (_listener.IsListening)
EndPointManager.RemovePrefix (uriPrefix, _listener);
return _prefixes.Remove (uriPrefix);
}
#endregion
#region Explicit Interface Implementations
/// <summary>
/// Gets the enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// An <see cref="IEnumerator"/> instance that can be used to iterate
/// through the collection.
/// </returns>
IEnumerator IEnumerable.GetEnumerator ()
{
return _prefixes.GetEnumerator ();
}
#endregion
}
}

View File

@ -1,928 +0,0 @@
#region License
/*
* HttpListenerRequest.cs
*
* This code is derived from HttpListenerRequest.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace WebSocketSharp.Net
{
/// <summary>
/// Represents an incoming HTTP request to a <see cref="HttpListener"/>
/// instance.
/// </summary>
/// <remarks>
/// This class cannot be inherited.
/// </remarks>
public sealed class HttpListenerRequest
{
#region Private Fields
private static readonly byte[] _100continue;
private string[] _acceptTypes;
private bool _chunked;
private HttpConnection _connection;
private Encoding _contentEncoding;
private long _contentLength;
private HttpListenerContext _context;
private CookieCollection _cookies;
private WebHeaderCollection _headers;
private string _httpMethod;
private Stream _inputStream;
private Version _protocolVersion;
private NameValueCollection _queryString;
private string _rawUrl;
private Guid _requestTraceIdentifier;
private Uri _url;
private Uri _urlReferrer;
private bool _urlSet;
private string _userHostName;
private string[] _userLanguages;
#endregion
#region Static Constructor
static HttpListenerRequest ()
{
_100continue = Encoding.ASCII.GetBytes ("HTTP/1.1 100 Continue\r\n\r\n");
}
#endregion
#region Internal Constructors
internal HttpListenerRequest (HttpListenerContext context)
{
_context = context;
_connection = context.Connection;
_contentLength = -1;
_headers = new WebHeaderCollection ();
_requestTraceIdentifier = Guid.NewGuid ();
}
#endregion
#region Public Properties
/// <summary>
/// Gets the media types that are acceptable for the client.
/// </summary>
/// <value>
/// <para>
/// An array of <see cref="string"/> that contains the names of the media
/// types specified in the value of the Accept header.
/// </para>
/// <para>
/// <see langword="null"/> if the header is not present.
/// </para>
/// </value>
public string[] AcceptTypes {
get {
var val = _headers["Accept"];
if (val == null)
return null;
if (_acceptTypes == null) {
_acceptTypes = val
.SplitHeaderValue (',')
.TrimEach ()
.ToList ()
.ToArray ();
}
return _acceptTypes;
}
}
/// <summary>
/// Gets an error code that identifies a problem with the certificate
/// provided by the client.
/// </summary>
/// <value>
/// An <see cref="int"/> that represents an error code.
/// </value>
/// <exception cref="NotSupportedException">
/// This property is not supported.
/// </exception>
public int ClientCertificateError {
get {
throw new NotSupportedException ();
}
}
/// <summary>
/// Gets the encoding for the entity body data included in the request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="Encoding"/> converted from the charset value of the
/// Content-Type header.
/// </para>
/// <para>
/// <see cref="Encoding.UTF8"/> if the charset value is not available.
/// </para>
/// </value>
public Encoding ContentEncoding {
get {
if (_contentEncoding == null)
_contentEncoding = getContentEncoding ();
return _contentEncoding;
}
}
/// <summary>
/// Gets the length in bytes of the entity body data included in the
/// request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="long"/> converted from the value of the Content-Length
/// header.
/// </para>
/// <para>
/// -1 if the header is not present.
/// </para>
/// </value>
public long ContentLength64 {
get {
return _contentLength;
}
}
/// <summary>
/// Gets the media type of the entity body data included in the request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="string"/> that represents the value of the Content-Type
/// header.
/// </para>
/// <para>
/// <see langword="null"/> if the header is not present.
/// </para>
/// </value>
public string ContentType {
get {
return _headers["Content-Type"];
}
}
/// <summary>
/// Gets the cookies included in the request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="CookieCollection"/> that contains the cookies.
/// </para>
/// <para>
/// An empty collection if not included.
/// </para>
/// </value>
public CookieCollection Cookies {
get {
if (_cookies == null)
_cookies = _headers.GetCookies (false);
return _cookies;
}
}
/// <summary>
/// Gets a value indicating whether the request has the entity body data.
/// </summary>
/// <value>
/// <c>true</c> if the request has the entity body data; otherwise,
/// <c>false</c>.
/// </value>
public bool HasEntityBody {
get {
return _contentLength > 0 || _chunked;
}
}
/// <summary>
/// Gets the headers included in the request.
/// </summary>
/// <value>
/// A <see cref="NameValueCollection"/> that contains the headers.
/// </value>
public NameValueCollection Headers {
get {
return _headers;
}
}
/// <summary>
/// Gets the HTTP method specified by the client.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the HTTP method specified in
/// the request line.
/// </value>
public string HttpMethod {
get {
return _httpMethod;
}
}
/// <summary>
/// Gets a stream that contains the entity body data included in
/// the request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="Stream"/> that contains the entity body data.
/// </para>
/// <para>
/// <see cref="Stream.Null"/> if the entity body data is not available.
/// </para>
/// </value>
public Stream InputStream {
get {
if (_inputStream == null) {
_inputStream = _contentLength > 0 || _chunked
? _connection
.GetRequestStream (_contentLength, _chunked)
: Stream.Null;
}
return _inputStream;
}
}
/// <summary>
/// Gets a value indicating whether the client is authenticated.
/// </summary>
/// <value>
/// <c>true</c> if the client is authenticated; otherwise, <c>false</c>.
/// </value>
public bool IsAuthenticated {
get {
return _context.User != null;
}
}
/// <summary>
/// Gets a value indicating whether the request is sent from the local
/// computer.
/// </summary>
/// <value>
/// <c>true</c> if the request is sent from the same computer as the server;
/// otherwise, <c>false</c>.
/// </value>
public bool IsLocal {
get {
return _connection.IsLocal;
}
}
/// <summary>
/// Gets a value indicating whether a secure connection is used to send
/// the request.
/// </summary>
/// <value>
/// <c>true</c> if the connection is secure; otherwise, <c>false</c>.
/// </value>
public bool IsSecureConnection {
get {
return _connection.IsSecure;
}
}
/// <summary>
/// Gets a value indicating whether the request is a WebSocket handshake
/// request.
/// </summary>
/// <value>
/// <c>true</c> if the request is a WebSocket handshake request; otherwise,
/// <c>false</c>.
/// </value>
public bool IsWebSocketRequest {
get {
return _httpMethod == "GET" && _headers.Upgrades ("websocket");
}
}
/// <summary>
/// Gets a value indicating whether a persistent connection is requested.
/// </summary>
/// <value>
/// <c>true</c> if the request specifies that the connection is kept open;
/// otherwise, <c>false</c>.
/// </value>
public bool KeepAlive {
get {
return _headers.KeepsAlive (_protocolVersion);
}
}
/// <summary>
/// Gets the endpoint to which the request is sent.
/// </summary>
/// <value>
/// A <see cref="System.Net.IPEndPoint"/> that represents the server IP
/// address and port number.
/// </value>
public System.Net.IPEndPoint LocalEndPoint {
get {
return _connection.LocalEndPoint;
}
}
/// <summary>
/// Gets the HTTP version specified by the client.
/// </summary>
/// <value>
/// A <see cref="Version"/> that represents the HTTP version specified in
/// the request line.
/// </value>
public Version ProtocolVersion {
get {
return _protocolVersion;
}
}
/// <summary>
/// Gets the query string included in the request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="NameValueCollection"/> that contains the query
/// parameters.
/// </para>
/// <para>
/// An empty collection if not included.
/// </para>
/// </value>
public NameValueCollection QueryString {
get {
if (_queryString == null) {
var url = Url;
_queryString = QueryStringCollection
.Parse (
url != null ? url.Query : null,
Encoding.UTF8
);
}
return _queryString;
}
}
/// <summary>
/// Gets the raw URL specified by the client.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the request target specified in
/// the request line.
/// </value>
public string RawUrl {
get {
return _rawUrl;
}
}
/// <summary>
/// Gets the endpoint from which the request is sent.
/// </summary>
/// <value>
/// A <see cref="System.Net.IPEndPoint"/> that represents the client IP
/// address and port number.
/// </value>
public System.Net.IPEndPoint RemoteEndPoint {
get {
return _connection.RemoteEndPoint;
}
}
/// <summary>
/// Gets the trace identifier of the request.
/// </summary>
/// <value>
/// A <see cref="Guid"/> that represents the trace identifier.
/// </value>
public Guid RequestTraceIdentifier {
get {
return _requestTraceIdentifier;
}
}
/// <summary>
/// Gets the URL requested by the client.
/// </summary>
/// <value>
/// <para>
/// A <see cref="Uri"/> that represents the URL parsed from the request.
/// </para>
/// <para>
/// <see langword="null"/> if the URL cannot be parsed.
/// </para>
/// </value>
public Uri Url {
get {
if (!_urlSet) {
_url = HttpUtility
.CreateRequestUrl (
_rawUrl,
_userHostName ?? UserHostAddress,
IsWebSocketRequest,
IsSecureConnection
);
_urlSet = true;
}
return _url;
}
}
/// <summary>
/// Gets the URI of the resource from which the requested URL was obtained.
/// </summary>
/// <value>
/// <para>
/// A <see cref="Uri"/> converted from the value of the Referer header.
/// </para>
/// <para>
/// <see langword="null"/> if the header value is not available.
/// </para>
/// </value>
public Uri UrlReferrer {
get {
var val = _headers["Referer"];
if (val == null)
return null;
if (_urlReferrer == null)
_urlReferrer = val.ToUri ();
return _urlReferrer;
}
}
/// <summary>
/// Gets the user agent from which the request is originated.
/// </summary>
/// <value>
/// <para>
/// A <see cref="string"/> that represents the value of the User-Agent
/// header.
/// </para>
/// <para>
/// <see langword="null"/> if the header is not present.
/// </para>
/// </value>
public string UserAgent {
get {
return _headers["User-Agent"];
}
}
/// <summary>
/// Gets the IP address and port number to which the request is sent.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the server IP address and port
/// number.
/// </value>
public string UserHostAddress {
get {
return _connection.LocalEndPoint.ToString ();
}
}
/// <summary>
/// Gets the server host name requested by the client.
/// </summary>
/// <value>
/// <para>
/// A <see cref="string"/> that represents the value of the Host header.
/// </para>
/// <para>
/// It includes the port number if provided.
/// </para>
/// <para>
/// <see langword="null"/> if the header is not present.
/// </para>
/// </value>
public string UserHostName {
get {
return _userHostName;
}
}
/// <summary>
/// Gets the natural languages that are acceptable for the client.
/// </summary>
/// <value>
/// <para>
/// An array of <see cref="string"/> that contains the names of the
/// natural languages specified in the value of the Accept-Language
/// header.
/// </para>
/// <para>
/// <see langword="null"/> if the header is not present.
/// </para>
/// </value>
public string[] UserLanguages {
get {
var val = _headers["Accept-Language"];
if (val == null)
return null;
if (_userLanguages == null)
_userLanguages = val.Split (',').TrimEach ().ToList ().ToArray ();
return _userLanguages;
}
}
#endregion
#region Private Methods
private Encoding getContentEncoding ()
{
var val = _headers["Content-Type"];
if (val == null)
return Encoding.UTF8;
Encoding ret;
return HttpUtility.TryGetEncoding (val, out ret)
? ret
: Encoding.UTF8;
}
#endregion
#region Internal Methods
internal void AddHeader (string headerField)
{
var start = headerField[0];
if (start == ' ' || start == '\t') {
_context.ErrorMessage = "Invalid header field";
return;
}
var colon = headerField.IndexOf (':');
if (colon < 1) {
_context.ErrorMessage = "Invalid header field";
return;
}
var name = headerField.Substring (0, colon).Trim ();
if (name.Length == 0 || !name.IsToken ()) {
_context.ErrorMessage = "Invalid header name";
return;
}
var val = colon < headerField.Length - 1
? headerField.Substring (colon + 1).Trim ()
: String.Empty;
_headers.InternalSet (name, val, false);
var lower = name.ToLower (CultureInfo.InvariantCulture);
if (lower == "host") {
if (_userHostName != null) {
_context.ErrorMessage = "Invalid Host header";
return;
}
if (val.Length == 0) {
_context.ErrorMessage = "Invalid Host header";
return;
}
_userHostName = val;
return;
}
if (lower == "content-length") {
if (_contentLength > -1) {
_context.ErrorMessage = "Invalid Content-Length header";
return;
}
long len;
if (!Int64.TryParse (val, out len)) {
_context.ErrorMessage = "Invalid Content-Length header";
return;
}
if (len < 0) {
_context.ErrorMessage = "Invalid Content-Length header";
return;
}
_contentLength = len;
return;
}
}
internal void FinishInitialization ()
{
if (_userHostName == null) {
_context.ErrorMessage = "Host header required";
return;
}
var transferEnc = _headers["Transfer-Encoding"];
if (transferEnc != null) {
var comparison = StringComparison.OrdinalIgnoreCase;
if (!transferEnc.Equals ("chunked", comparison)) {
_context.ErrorMessage = "Invalid Transfer-Encoding header";
_context.ErrorStatusCode = 501;
return;
}
_chunked = true;
}
if (_httpMethod == "POST" || _httpMethod == "PUT") {
if (_contentLength <= 0 && !_chunked) {
_context.ErrorMessage = String.Empty;
_context.ErrorStatusCode = 411;
return;
}
}
var expect = _headers["Expect"];
if (expect != null) {
var comparison = StringComparison.OrdinalIgnoreCase;
if (!expect.Equals ("100-continue", comparison)) {
_context.ErrorMessage = "Invalid Expect header";
return;
}
var output = _connection.GetResponseStream ();
output.InternalWrite (_100continue, 0, _100continue.Length);
}
}
internal bool FlushInput ()
{
var input = InputStream;
if (input == Stream.Null)
return true;
var len = 2048;
if (_contentLength > 0 && _contentLength < len)
len = (int) _contentLength;
var buff = new byte[len];
while (true) {
try {
var ares = input.BeginRead (buff, 0, len, null, null);
if (!ares.IsCompleted) {
var timeout = 100;
if (!ares.AsyncWaitHandle.WaitOne (timeout))
return false;
}
if (input.EndRead (ares) <= 0)
return true;
}
catch {
return false;
}
}
}
internal bool IsUpgradeRequest (string protocol)
{
return _headers.Upgrades (protocol);
}
internal void SetRequestLine (string requestLine)
{
var parts = requestLine.Split (new[] { ' ' }, 3);
if (parts.Length < 3) {
_context.ErrorMessage = "Invalid request line (parts)";
return;
}
var method = parts[0];
if (method.Length == 0) {
_context.ErrorMessage = "Invalid request line (method)";
return;
}
var target = parts[1];
if (target.Length == 0) {
_context.ErrorMessage = "Invalid request line (target)";
return;
}
var rawVer = parts[2];
if (rawVer.Length != 8) {
_context.ErrorMessage = "Invalid request line (version)";
return;
}
if (!rawVer.StartsWith ("HTTP/", StringComparison.Ordinal)) {
_context.ErrorMessage = "Invalid request line (version)";
return;
}
Version ver;
if (!rawVer.Substring (5).TryCreateVersion (out ver)) {
_context.ErrorMessage = "Invalid request line (version)";
return;
}
if (ver != HttpVersion.Version11) {
_context.ErrorMessage = "Invalid request line (version)";
_context.ErrorStatusCode = 505;
return;
}
if (!method.IsHttpMethod (ver)) {
_context.ErrorMessage = "Invalid request line (method)";
_context.ErrorStatusCode = 501;
return;
}
_httpMethod = method;
_rawUrl = target;
_protocolVersion = ver;
}
#endregion
#region Public Methods
/// <summary>
/// Begins getting the certificate provided by the client asynchronously.
/// </summary>
/// <returns>
/// An <see cref="IAsyncResult"/> instance that indicates the status of the
/// operation.
/// </returns>
/// <param name="requestCallback">
/// An <see cref="AsyncCallback"/> delegate that invokes the method called
/// when the operation is complete.
/// </param>
/// <param name="state">
/// An <see cref="object"/> that represents a user defined object to pass to
/// the callback delegate.
/// </param>
/// <exception cref="NotSupportedException">
/// This method is not supported.
/// </exception>
public IAsyncResult BeginGetClientCertificate (
AsyncCallback requestCallback, object state
)
{
throw new NotSupportedException ();
}
/// <summary>
/// Ends an asynchronous operation to get the certificate provided by the
/// client.
/// </summary>
/// <returns>
/// A <see cref="X509Certificate2"/> that represents an X.509 certificate
/// provided by the client.
/// </returns>
/// <param name="asyncResult">
/// An <see cref="IAsyncResult"/> instance returned when the operation
/// started.
/// </param>
/// <exception cref="NotSupportedException">
/// This method is not supported.
/// </exception>
public X509Certificate2 EndGetClientCertificate (IAsyncResult asyncResult)
{
throw new NotSupportedException ();
}
/// <summary>
/// Gets the certificate provided by the client.
/// </summary>
/// <returns>
/// A <see cref="X509Certificate2"/> that represents an X.509 certificate
/// provided by the client.
/// </returns>
/// <exception cref="NotSupportedException">
/// This method is not supported.
/// </exception>
public X509Certificate2 GetClientCertificate ()
{
throw new NotSupportedException ();
}
/// <summary>
/// Returns a string that represents the current instance.
/// </summary>
/// <returns>
/// A <see cref="string"/> that contains the request line and headers
/// included in the request.
/// </returns>
public override string ToString ()
{
var buff = new StringBuilder (64);
buff
.AppendFormat (
"{0} {1} HTTP/{2}\r\n", _httpMethod, _rawUrl, _protocolVersion
)
.Append (_headers.ToString ());
return buff.ToString ();
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,233 +0,0 @@
#region License
/*
* HttpRequestHeader.cs
*
* This code is derived from HttpRequestHeader.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2014-2020 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
namespace WebSocketSharp.Net
{
/// <summary>
/// Indicates the HTTP header that may be specified in a client request.
/// </summary>
/// <remarks>
/// The headers of this enumeration are defined in
/// <see href="http://tools.ietf.org/html/rfc2616#section-14">RFC 2616</see> or
/// <see href="http://tools.ietf.org/html/rfc6455#section-11.3">RFC 6455</see>.
/// </remarks>
public enum HttpRequestHeader
{
/// <summary>
/// Indicates the Cache-Control header.
/// </summary>
CacheControl,
/// <summary>
/// Indicates the Connection header.
/// </summary>
Connection,
/// <summary>
/// Indicates the Date header.
/// </summary>
Date,
/// <summary>
/// Indicates the Keep-Alive header.
/// </summary>
KeepAlive,
/// <summary>
/// Indicates the Pragma header.
/// </summary>
Pragma,
/// <summary>
/// Indicates the Trailer header.
/// </summary>
Trailer,
/// <summary>
/// Indicates the Transfer-Encoding header.
/// </summary>
TransferEncoding,
/// <summary>
/// Indicates the Upgrade header.
/// </summary>
Upgrade,
/// <summary>
/// Indicates the Via header.
/// </summary>
Via,
/// <summary>
/// Indicates the Warning header.
/// </summary>
Warning,
/// <summary>
/// Indicates the Allow header.
/// </summary>
Allow,
/// <summary>
/// Indicates the Content-Length header.
/// </summary>
ContentLength,
/// <summary>
/// Indicates the Content-Type header.
/// </summary>
ContentType,
/// <summary>
/// Indicates the Content-Encoding header.
/// </summary>
ContentEncoding,
/// <summary>
/// Indicates the Content-Language header.
/// </summary>
ContentLanguage,
/// <summary>
/// Indicates the Content-Location header.
/// </summary>
ContentLocation,
/// <summary>
/// Indicates the Content-MD5 header.
/// </summary>
ContentMd5,
/// <summary>
/// Indicates the Content-Range header.
/// </summary>
ContentRange,
/// <summary>
/// Indicates the Expires header.
/// </summary>
Expires,
/// <summary>
/// Indicates the Last-Modified header.
/// </summary>
LastModified,
/// <summary>
/// Indicates the Accept header.
/// </summary>
Accept,
/// <summary>
/// Indicates the Accept-Charset header.
/// </summary>
AcceptCharset,
/// <summary>
/// Indicates the Accept-Encoding header.
/// </summary>
AcceptEncoding,
/// <summary>
/// Indicates the Accept-Language header.
/// </summary>
AcceptLanguage,
/// <summary>
/// Indicates the Authorization header.
/// </summary>
Authorization,
/// <summary>
/// Indicates the Cookie header.
/// </summary>
Cookie,
/// <summary>
/// Indicates the Expect header.
/// </summary>
Expect,
/// <summary>
/// Indicates the From header.
/// </summary>
From,
/// <summary>
/// Indicates the Host header.
/// </summary>
Host,
/// <summary>
/// Indicates the If-Match header.
/// </summary>
IfMatch,
/// <summary>
/// Indicates the If-Modified-Since header.
/// </summary>
IfModifiedSince,
/// <summary>
/// Indicates the If-None-Match header.
/// </summary>
IfNoneMatch,
/// <summary>
/// Indicates the If-Range header.
/// </summary>
IfRange,
/// <summary>
/// Indicates the If-Unmodified-Since header.
/// </summary>
IfUnmodifiedSince,
/// <summary>
/// Indicates the Max-Forwards header.
/// </summary>
MaxForwards,
/// <summary>
/// Indicates the Proxy-Authorization header.
/// </summary>
ProxyAuthorization,
/// <summary>
/// Indicates the Referer header.
/// </summary>
Referer,
/// <summary>
/// Indicates the Range header.
/// </summary>
Range,
/// <summary>
/// Indicates the TE header.
/// </summary>
Te,
/// <summary>
/// Indicates the Translate header.
/// </summary>
Translate,
/// <summary>
/// Indicates the User-Agent header.
/// </summary>
UserAgent,
/// <summary>
/// Indicates the Sec-WebSocket-Key header.
/// </summary>
SecWebSocketKey,
/// <summary>
/// Indicates the Sec-WebSocket-Extensions header.
/// </summary>
SecWebSocketExtensions,
/// <summary>
/// Indicates the Sec-WebSocket-Protocol header.
/// </summary>
SecWebSocketProtocol,
/// <summary>
/// Indicates the Sec-WebSocket-Version header.
/// </summary>
SecWebSocketVersion
}
}

View File

@ -1,189 +0,0 @@
#region License
/*
* HttpResponseHeader.cs
*
* This code is derived from HttpResponseHeader.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2014-2020 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
namespace WebSocketSharp.Net
{
/// <summary>
/// Indicates the HTTP header that can be specified in a server response.
/// </summary>
/// <remarks>
/// The headers of this enumeration are defined in
/// <see href="http://tools.ietf.org/html/rfc2616#section-14">RFC 2616</see> or
/// <see href="http://tools.ietf.org/html/rfc6455#section-11.3">RFC 6455</see>.
/// </remarks>
public enum HttpResponseHeader
{
/// <summary>
/// Indicates the Cache-Control header.
/// </summary>
CacheControl,
/// <summary>
/// Indicates the Connection header.
/// </summary>
Connection,
/// <summary>
/// Indicates the Date header.
/// </summary>
Date,
/// <summary>
/// Indicates the Keep-Alive header.
/// </summary>
KeepAlive,
/// <summary>
/// Indicates the Pragma header.
/// </summary>
Pragma,
/// <summary>
/// Indicates the Trailer header.
/// </summary>
Trailer,
/// <summary>
/// Indicates the Transfer-Encoding header.
/// </summary>
TransferEncoding,
/// <summary>
/// Indicates the Upgrade header.
/// </summary>
Upgrade,
/// <summary>
/// Indicates the Via header.
/// </summary>
Via,
/// <summary>
/// Indicates the Warning header.
/// </summary>
Warning,
/// <summary>
/// Indicates the Allow header.
/// </summary>
Allow,
/// <summary>
/// Indicates the Content-Length header.
/// </summary>
ContentLength,
/// <summary>
/// Indicates the Content-Type header.
/// </summary>
ContentType,
/// <summary>
/// Indicates the Content-Encoding header.
/// </summary>
ContentEncoding,
/// <summary>
/// Indicates the Content-Language header.
/// </summary>
ContentLanguage,
/// <summary>
/// Indicates the Content-Location header.
/// </summary>
ContentLocation,
/// <summary>
/// Indicates the Content-MD5 header.
/// </summary>
ContentMd5,
/// <summary>
/// Indicates the Content-Range header.
/// </summary>
ContentRange,
/// <summary>
/// Indicates the Expires header.
/// </summary>
Expires,
/// <summary>
/// Indicates the Last-Modified header.
/// </summary>
LastModified,
/// <summary>
/// Indicates the Accept-Ranges header.
/// </summary>
AcceptRanges,
/// <summary>
/// Indicates the Age header.
/// </summary>
Age,
/// <summary>
/// Indicates the ETag header.
/// </summary>
ETag,
/// <summary>
/// Indicates the Location header.
/// </summary>
Location,
/// <summary>
/// Indicates the Proxy-Authenticate header.
/// </summary>
ProxyAuthenticate,
/// <summary>
/// Indicates the Retry-After header.
/// </summary>
RetryAfter,
/// <summary>
/// Indicates the Server header.
/// </summary>
Server,
/// <summary>
/// Indicates the Set-Cookie header.
/// </summary>
SetCookie,
/// <summary>
/// Indicates the Vary header.
/// </summary>
Vary,
/// <summary>
/// Indicates the WWW-Authenticate header.
/// </summary>
WwwAuthenticate,
/// <summary>
/// Indicates the Sec-WebSocket-Extensions header.
/// </summary>
SecWebSocketExtensions,
/// <summary>
/// Indicates the Sec-WebSocket-Accept header.
/// </summary>
SecWebSocketAccept,
/// <summary>
/// Indicates the Sec-WebSocket-Protocol header.
/// </summary>
SecWebSocketProtocol,
/// <summary>
/// Indicates the Sec-WebSocket-Version header.
/// </summary>
SecWebSocketVersion
}
}

View File

@ -1,346 +0,0 @@
#region License
/*
* HttpStatusCode.cs
*
* This code is derived from HttpStatusCode.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* It was automatically generated from ECMA CLI XML Library Specification.
* Generator: libgen.xsl [1.0; (C) Sergey Chaban (serge@wildwestsoftware.com)]
* Created: Wed, 5 Sep 2001 06:32:05 UTC
* Source file: AllTypes.xml
* URL: http://msdn.microsoft.com/net/ecma/AllTypes.xml
*
* The MIT License
*
* Copyright (c) 2001 Ximian, Inc. (http://www.ximian.com)
* Copyright (c) 2012-2020 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
namespace WebSocketSharp.Net
{
/// <summary>
/// Indicates the HTTP status code that can be specified in a server response.
/// </summary>
/// <remarks>
/// The values of this enumeration are defined in
/// <see href="http://tools.ietf.org/html/rfc2616#section-10">RFC 2616</see>.
/// </remarks>
public enum HttpStatusCode
{
/// <summary>
/// Equivalent to status code 100. Indicates that the client should continue
/// with its request.
/// </summary>
Continue = 100,
/// <summary>
/// Equivalent to status code 101. Indicates that the server is switching
/// the HTTP version or protocol on the connection.
/// </summary>
SwitchingProtocols = 101,
/// <summary>
/// Equivalent to status code 200. Indicates that the client's request has
/// succeeded.
/// </summary>
OK = 200,
/// <summary>
/// Equivalent to status code 201. Indicates that the client's request has
/// been fulfilled and resulted in a new resource being created.
/// </summary>
Created = 201,
/// <summary>
/// Equivalent to status code 202. Indicates that the client's request has
/// been accepted for processing, but the processing has not been completed.
/// </summary>
Accepted = 202,
/// <summary>
/// Equivalent to status code 203. Indicates that the returned metainformation
/// is from a local or a third-party copy instead of the origin server.
/// </summary>
NonAuthoritativeInformation = 203,
/// <summary>
/// Equivalent to status code 204. Indicates that the server has fulfilled
/// the client's request but does not need to return an entity-body.
/// </summary>
NoContent = 204,
/// <summary>
/// Equivalent to status code 205. Indicates that the server has fulfilled
/// the client's request, and the user agent should reset the document view
/// which caused the request to be sent.
/// </summary>
ResetContent = 205,
/// <summary>
/// Equivalent to status code 206. Indicates that the server has fulfilled
/// the partial GET request for the resource.
/// </summary>
PartialContent = 206,
/// <summary>
/// <para>
/// Equivalent to status code 300. Indicates that the requested resource
/// corresponds to any of multiple representations.
/// </para>
/// <para>
/// MultipleChoices is a synonym for Ambiguous.
/// </para>
/// </summary>
MultipleChoices = 300,
/// <summary>
/// <para>
/// Equivalent to status code 300. Indicates that the requested resource
/// corresponds to any of multiple representations.
/// </para>
/// <para>
/// Ambiguous is a synonym for MultipleChoices.
/// </para>
/// </summary>
Ambiguous = 300,
/// <summary>
/// <para>
/// Equivalent to status code 301. Indicates that the requested resource
/// has been assigned a new permanent URI and any future references to
/// this resource should use one of the returned URIs.
/// </para>
/// <para>
/// MovedPermanently is a synonym for Moved.
/// </para>
/// </summary>
MovedPermanently = 301,
/// <summary>
/// <para>
/// Equivalent to status code 301. Indicates that the requested resource
/// has been assigned a new permanent URI and any future references to
/// this resource should use one of the returned URIs.
/// </para>
/// <para>
/// Moved is a synonym for MovedPermanently.
/// </para>
/// </summary>
Moved = 301,
/// <summary>
/// <para>
/// Equivalent to status code 302. Indicates that the requested resource
/// is located temporarily under a different URI.
/// </para>
/// <para>
/// Found is a synonym for Redirect.
/// </para>
/// </summary>
Found = 302,
/// <summary>
/// <para>
/// Equivalent to status code 302. Indicates that the requested resource
/// is located temporarily under a different URI.
/// </para>
/// <para>
/// Redirect is a synonym for Found.
/// </para>
/// </summary>
Redirect = 302,
/// <summary>
/// <para>
/// Equivalent to status code 303. Indicates that the response to
/// the request can be found under a different URI and should be
/// retrieved using a GET method on that resource.
/// </para>
/// <para>
/// SeeOther is a synonym for RedirectMethod.
/// </para>
/// </summary>
SeeOther = 303,
/// <summary>
/// <para>
/// Equivalent to status code 303. Indicates that the response to
/// the request can be found under a different URI and should be
/// retrieved using a GET method on that resource.
/// </para>
/// <para>
/// RedirectMethod is a synonym for SeeOther.
/// </para>
/// </summary>
RedirectMethod = 303,
/// <summary>
/// Equivalent to status code 304. Indicates that the client has performed
/// a conditional GET request and access is allowed, but the document has
/// not been modified.
/// </summary>
NotModified = 304,
/// <summary>
/// Equivalent to status code 305. Indicates that the requested resource
/// must be accessed through the proxy given by the Location field.
/// </summary>
UseProxy = 305,
/// <summary>
/// Equivalent to status code 306. This status code was used in a previous
/// version of the specification, is no longer used, and is reserved for
/// future use.
/// </summary>
Unused = 306,
/// <summary>
/// <para>
/// Equivalent to status code 307. Indicates that the requested resource
/// is located temporarily under a different URI.
/// </para>
/// <para>
/// TemporaryRedirect is a synonym for RedirectKeepVerb.
/// </para>
/// </summary>
TemporaryRedirect = 307,
/// <summary>
/// <para>
/// Equivalent to status code 307. Indicates that the requested resource
/// is located temporarily under a different URI.
/// </para>
/// <para>
/// RedirectKeepVerb is a synonym for TemporaryRedirect.
/// </para>
/// </summary>
RedirectKeepVerb = 307,
/// <summary>
/// Equivalent to status code 400. Indicates that the client's request could
/// not be understood by the server due to malformed syntax.
/// </summary>
BadRequest = 400,
/// <summary>
/// Equivalent to status code 401. Indicates that the client's request
/// requires user authentication.
/// </summary>
Unauthorized = 401,
/// <summary>
/// Equivalent to status code 402. This status code is reserved for future
/// use.
/// </summary>
PaymentRequired = 402,
/// <summary>
/// Equivalent to status code 403. Indicates that the server understood
/// the client's request but is refusing to fulfill it.
/// </summary>
Forbidden = 403,
/// <summary>
/// Equivalent to status code 404. Indicates that the server has not found
/// anything matching the request URI.
/// </summary>
NotFound = 404,
/// <summary>
/// Equivalent to status code 405. Indicates that the method specified
/// in the request line is not allowed for the resource identified by
/// the request URI.
/// </summary>
MethodNotAllowed = 405,
/// <summary>
/// Equivalent to status code 406. Indicates that the server does not
/// have the appropriate resource to respond to the Accept headers in
/// the client's request.
/// </summary>
NotAcceptable = 406,
/// <summary>
/// Equivalent to status code 407. Indicates that the client must first
/// authenticate itself with the proxy.
/// </summary>
ProxyAuthenticationRequired = 407,
/// <summary>
/// Equivalent to status code 408. Indicates that the client did not produce
/// a request within the time that the server was prepared to wait.
/// </summary>
RequestTimeout = 408,
/// <summary>
/// Equivalent to status code 409. Indicates that the client's request could
/// not be completed due to a conflict on the server.
/// </summary>
Conflict = 409,
/// <summary>
/// Equivalent to status code 410. Indicates that the requested resource is
/// no longer available at the server and no forwarding address is known.
/// </summary>
Gone = 410,
/// <summary>
/// Equivalent to status code 411. Indicates that the server refuses to
/// accept the client's request without a defined Content-Length.
/// </summary>
LengthRequired = 411,
/// <summary>
/// Equivalent to status code 412. Indicates that the precondition given in
/// one or more of the request headers evaluated to false when it was tested
/// on the server.
/// </summary>
PreconditionFailed = 412,
/// <summary>
/// Equivalent to status code 413. Indicates that the entity of the client's
/// request is larger than the server is willing or able to process.
/// </summary>
RequestEntityTooLarge = 413,
/// <summary>
/// Equivalent to status code 414. Indicates that the request URI is longer
/// than the server is willing to interpret.
/// </summary>
RequestUriTooLong = 414,
/// <summary>
/// Equivalent to status code 415. Indicates that the entity of the client's
/// request is in a format not supported by the requested resource for the
/// requested method.
/// </summary>
UnsupportedMediaType = 415,
/// <summary>
/// Equivalent to status code 416. Indicates that none of the range
/// specifier values in a Range request header overlap the current
/// extent of the selected resource.
/// </summary>
RequestedRangeNotSatisfiable = 416,
/// <summary>
/// Equivalent to status code 417. Indicates that the expectation given in
/// an Expect request header could not be met by the server.
/// </summary>
ExpectationFailed = 417,
/// <summary>
/// Equivalent to status code 500. Indicates that the server encountered
/// an unexpected condition which prevented it from fulfilling the client's
/// request.
/// </summary>
InternalServerError = 500,
/// <summary>
/// Equivalent to status code 501. Indicates that the server does not
/// support the functionality required to fulfill the client's request.
/// </summary>
NotImplemented = 501,
/// <summary>
/// Equivalent to status code 502. Indicates that a gateway or proxy server
/// received an invalid response from the upstream server.
/// </summary>
BadGateway = 502,
/// <summary>
/// Equivalent to status code 503. Indicates that the server is currently
/// unable to handle the client's request due to a temporary overloading
/// or maintenance of the server.
/// </summary>
ServiceUnavailable = 503,
/// <summary>
/// Equivalent to status code 504. Indicates that a gateway or proxy server
/// did not receive a timely response from the upstream server or some other
/// auxiliary server.
/// </summary>
GatewayTimeout = 504,
/// <summary>
/// Equivalent to status code 505. Indicates that the server does not
/// support the HTTP version used in the client's request.
/// </summary>
HttpVersionNotSupported = 505,
}
}

View File

@ -1,201 +0,0 @@
#region License
/*
* HttpStreamAsyncResult.cs
*
* This code is derived from HttpStreamAsyncResult.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
using System;
using System.Threading;
namespace WebSocketSharp.Net
{
internal class HttpStreamAsyncResult : IAsyncResult
{
#region Private Fields
private byte[] _buffer;
private AsyncCallback _callback;
private bool _completed;
private int _count;
private Exception _exception;
private int _offset;
private object _state;
private object _sync;
private int _syncRead;
private ManualResetEvent _waitHandle;
#endregion
#region Internal Constructors
internal HttpStreamAsyncResult (AsyncCallback callback, object state)
{
_callback = callback;
_state = state;
_sync = new object ();
}
#endregion
#region Internal Properties
internal byte[] Buffer {
get {
return _buffer;
}
set {
_buffer = value;
}
}
internal int Count {
get {
return _count;
}
set {
_count = value;
}
}
internal Exception Exception {
get {
return _exception;
}
}
internal bool HasException {
get {
return _exception != null;
}
}
internal int Offset {
get {
return _offset;
}
set {
_offset = value;
}
}
internal int SyncRead {
get {
return _syncRead;
}
set {
_syncRead = value;
}
}
#endregion
#region Public Properties
public object AsyncState {
get {
return _state;
}
}
public WaitHandle AsyncWaitHandle {
get {
lock (_sync) {
if (_waitHandle == null)
_waitHandle = new ManualResetEvent (_completed);
return _waitHandle;
}
}
}
public bool CompletedSynchronously {
get {
return _syncRead == _count;
}
}
public bool IsCompleted {
get {
lock (_sync)
return _completed;
}
}
#endregion
#region Internal Methods
internal void Complete ()
{
lock (_sync) {
if (_completed)
return;
_completed = true;
if (_waitHandle != null)
_waitHandle.Set ();
if (_callback != null)
_callback.BeginInvoke (this, ar => _callback.EndInvoke (ar), null);
}
}
internal void Complete (Exception exception)
{
lock (_sync) {
if (_completed)
return;
_completed = true;
_exception = exception;
if (_waitHandle != null)
_waitHandle.Set ();
if (_callback != null)
_callback.BeginInvoke (this, ar => _callback.EndInvoke (ar), null);
}
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,73 +0,0 @@
#region License
/*
* HttpVersion.cs
*
* This code is derived from System.Net.HttpVersion.cs of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2012-2014 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Lawrence Pit <loz@cable.a2000.nl>
*/
#endregion
using System;
namespace WebSocketSharp.Net
{
/// <summary>
/// Provides the HTTP version numbers.
/// </summary>
public class HttpVersion
{
#region Public Fields
/// <summary>
/// Provides a <see cref="Version"/> instance for the HTTP/1.0.
/// </summary>
public static readonly Version Version10 = new Version (1, 0);
/// <summary>
/// Provides a <see cref="Version"/> instance for the HTTP/1.1.
/// </summary>
public static readonly Version Version11 = new Version (1, 1);
#endregion
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="HttpVersion"/> class.
/// </summary>
public HttpVersion ()
{
}
#endregion
}
}

View File

@ -1,52 +0,0 @@
#region License
/*
* InputChunkState.cs
*
* This code is derived from ChunkStream.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2003 Ximian, Inc (http://www.ximian.com)
* Copyright (c) 2014-2015 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@ximian.com>
*/
#endregion
using System;
namespace WebSocketSharp.Net
{
internal enum InputChunkState
{
None,
Data,
DataEnded,
Trailer,
End
}
}

View File

@ -1,49 +0,0 @@
#region License
/*
* InputState.cs
*
* This code is derived from HttpConnection.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2014-2015 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
using System;
namespace WebSocketSharp.Net
{
internal enum InputState
{
RequestLine,
Headers
}
}

View File

@ -1,50 +0,0 @@
#region License
/*
* LineState.cs
*
* This code is derived from HttpConnection.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2014-2015 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
using System;
namespace WebSocketSharp.Net
{
internal enum LineState
{
None,
Cr,
Lf
}
}

View File

@ -1,209 +0,0 @@
#region License
/*
* NetworkCredential.cs
*
* The MIT License
*
* Copyright (c) 2014-2017 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp.Net
{
/// <summary>
/// Provides the credentials for the password-based authentication.
/// </summary>
public class NetworkCredential
{
#region Private Fields
private string _domain;
private static readonly string[] _noRoles;
private string _password;
private string[] _roles;
private string _username;
#endregion
#region Static Constructor
static NetworkCredential ()
{
_noRoles = new string[0];
}
#endregion
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="NetworkCredential"/> class with
/// the specified <paramref name="username"/> and <paramref name="password"/>.
/// </summary>
/// <param name="username">
/// A <see cref="string"/> that represents the username associated with
/// the credentials.
/// </param>
/// <param name="password">
/// A <see cref="string"/> that represents the password for the username
/// associated with the credentials.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="username"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="username"/> is empty.
/// </exception>
public NetworkCredential (string username, string password)
: this (username, password, null, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="NetworkCredential"/> class with
/// the specified <paramref name="username"/>, <paramref name="password"/>,
/// <paramref name="domain"/> and <paramref name="roles"/>.
/// </summary>
/// <param name="username">
/// A <see cref="string"/> that represents the username associated with
/// the credentials.
/// </param>
/// <param name="password">
/// A <see cref="string"/> that represents the password for the username
/// associated with the credentials.
/// </param>
/// <param name="domain">
/// A <see cref="string"/> that represents the domain associated with
/// the credentials.
/// </param>
/// <param name="roles">
/// An array of <see cref="string"/> that represents the roles
/// associated with the credentials if any.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="username"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="username"/> is empty.
/// </exception>
public NetworkCredential (
string username, string password, string domain, params string[] roles
)
{
if (username == null)
throw new ArgumentNullException ("username");
if (username.Length == 0)
throw new ArgumentException ("An empty string.", "username");
_username = username;
_password = password;
_domain = domain;
_roles = roles;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the domain associated with the credentials.
/// </summary>
/// <remarks>
/// This property returns an empty string if the domain was
/// initialized with <see langword="null"/>.
/// </remarks>
/// <value>
/// A <see cref="string"/> that represents the domain name
/// to which the username belongs.
/// </value>
public string Domain {
get {
return _domain ?? String.Empty;
}
internal set {
_domain = value;
}
}
/// <summary>
/// Gets the password for the username associated with the credentials.
/// </summary>
/// <remarks>
/// This property returns an empty string if the password was
/// initialized with <see langword="null"/>.
/// </remarks>
/// <value>
/// A <see cref="string"/> that represents the password.
/// </value>
public string Password {
get {
return _password ?? String.Empty;
}
internal set {
_password = value;
}
}
/// <summary>
/// Gets the roles associated with the credentials.
/// </summary>
/// <remarks>
/// This property returns an empty array if the roles were
/// initialized with <see langword="null"/>.
/// </remarks>
/// <value>
/// An array of <see cref="string"/> that represents the role names
/// to which the username belongs.
/// </value>
public string[] Roles {
get {
return _roles ?? _noRoles;
}
internal set {
_roles = value;
}
}
/// <summary>
/// Gets the username associated with the credentials.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the username.
/// </value>
public string Username {
get {
return _username;
}
internal set {
_username = value;
}
}
#endregion
}
}

View File

@ -1,150 +0,0 @@
#region License
/*
* QueryStringCollection.cs
*
* This code is derived from HttpUtility.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005-2009 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2018 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Patrik Torstensson <Patrik.Torstensson@labs2.com>
* - Wictor Wilén (decode/encode functions) <wictor@ibizkit.se>
* - Tim Coleman <tim@timcoleman.com>
* - Gonzalo Paniagua Javier <gonzalo@ximian.com>
*/
#endregion
using System;
using System.Collections.Specialized;
using System.Text;
namespace WebSocketSharp.Net
{
internal sealed class QueryStringCollection : NameValueCollection
{
#region Public Constructors
public QueryStringCollection ()
{
}
public QueryStringCollection (int capacity)
: base (capacity)
{
}
#endregion
#region Private Methods
private static string urlDecode (string s, Encoding encoding)
{
return s.IndexOfAny (new[] { '%', '+' }) > -1
? HttpUtility.UrlDecode (s, encoding)
: s;
}
#endregion
#region Public Methods
public static QueryStringCollection Parse (string query)
{
return Parse (query, Encoding.UTF8);
}
public static QueryStringCollection Parse (string query, Encoding encoding)
{
if (query == null)
return new QueryStringCollection (1);
var len = query.Length;
if (len == 0)
return new QueryStringCollection (1);
if (query == "?")
return new QueryStringCollection (1);
if (query[0] == '?')
query = query.Substring (1);
if (encoding == null)
encoding = Encoding.UTF8;
var ret = new QueryStringCollection ();
var components = query.Split ('&');
foreach (var component in components) {
len = component.Length;
if (len == 0)
continue;
if (component == "=")
continue;
var i = component.IndexOf ('=');
if (i < 0) {
ret.Add (null, urlDecode (component, encoding));
continue;
}
if (i == 0) {
ret.Add (null, urlDecode (component.Substring (1), encoding));
continue;
}
var name = urlDecode (component.Substring (0, i), encoding);
var start = i + 1;
var val = start < len
? urlDecode (component.Substring (start), encoding)
: String.Empty;
ret.Add (name, val);
}
return ret;
}
public override string ToString ()
{
var buff = new StringBuilder ();
foreach (var key in AllKeys)
buff.AppendFormat ("{0}={1}&", key, this[key]);
if (buff.Length > 0)
buff.Length--;
return buff.ToString ();
}
#endregion
}
}

View File

@ -1,126 +0,0 @@
#region License
/*
* ReadBufferState.cs
*
* This code is derived from ChunkedInputStream.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2014-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
using System;
namespace WebSocketSharp.Net
{
internal class ReadBufferState
{
#region Private Fields
private HttpStreamAsyncResult _asyncResult;
private byte[] _buffer;
private int _count;
private int _initialCount;
private int _offset;
#endregion
#region Public Constructors
public ReadBufferState (
byte[] buffer, int offset, int count, HttpStreamAsyncResult asyncResult
)
{
_buffer = buffer;
_offset = offset;
_count = count;
_asyncResult = asyncResult;
_initialCount = count;
}
#endregion
#region Public Properties
public HttpStreamAsyncResult AsyncResult {
get {
return _asyncResult;
}
set {
_asyncResult = value;
}
}
public byte[] Buffer {
get {
return _buffer;
}
set {
_buffer = value;
}
}
public int Count {
get {
return _count;
}
set {
_count = value;
}
}
public int InitialCount {
get {
return _initialCount;
}
set {
_initialCount = value;
}
}
public int Offset {
get {
return _offset;
}
set {
_offset = value;
}
}
#endregion
}
}

View File

@ -1,318 +0,0 @@
#region License
/*
* RequestStream.cs
*
* This code is derived from RequestStream.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
using System;
using System.IO;
namespace WebSocketSharp.Net
{
internal class RequestStream : Stream
{
#region Private Fields
private long _bodyLeft;
private byte[] _buffer;
private int _count;
private bool _disposed;
private int _offset;
private Stream _stream;
#endregion
#region Internal Constructors
internal RequestStream (
Stream stream, byte[] buffer, int offset, int count, long contentLength
)
{
_stream = stream;
_buffer = buffer;
_offset = offset;
_count = count;
_bodyLeft = contentLength;
}
#endregion
#region Public Properties
public override bool CanRead {
get {
return true;
}
}
public override bool CanSeek {
get {
return false;
}
}
public override bool CanWrite {
get {
return false;
}
}
public override long Length {
get {
throw new NotSupportedException ();
}
}
public override long Position {
get {
throw new NotSupportedException ();
}
set {
throw new NotSupportedException ();
}
}
#endregion
#region Private Methods
private int fillFromBuffer (byte[] buffer, int offset, int count)
{
// This method returns a int:
// - > 0 The number of bytes read from the internal buffer
// - 0 No more bytes read from the internal buffer
// - -1 No more content data
if (_bodyLeft == 0)
return -1;
if (_count == 0)
return 0;
if (count > _count)
count = _count;
if (_bodyLeft > 0 && _bodyLeft < count)
count = (int) _bodyLeft;
Buffer.BlockCopy (_buffer, _offset, buffer, offset, count);
_offset += count;
_count -= count;
if (_bodyLeft > 0)
_bodyLeft -= count;
return count;
}
#endregion
#region Public Methods
public override IAsyncResult BeginRead (
byte[] buffer, int offset, int count, AsyncCallback callback, object state
)
{
if (_disposed) {
var name = GetType ().ToString ();
throw new ObjectDisposedException (name);
}
if (buffer == null)
throw new ArgumentNullException ("buffer");
if (offset < 0) {
var msg = "A negative value.";
throw new ArgumentOutOfRangeException ("offset", msg);
}
if (count < 0) {
var msg = "A negative value.";
throw new ArgumentOutOfRangeException ("count", msg);
}
var len = buffer.Length;
if (offset + count > len) {
var msg = "The sum of 'offset' and 'count' is greater than the length of 'buffer'.";
throw new ArgumentException (msg);
}
if (count == 0)
return _stream.BeginRead (buffer, offset, 0, callback, state);
var nread = fillFromBuffer (buffer, offset, count);
if (nread != 0) {
var ares = new HttpStreamAsyncResult (callback, state);
ares.Buffer = buffer;
ares.Offset = offset;
ares.Count = count;
ares.SyncRead = nread > 0 ? nread : 0;
ares.Complete ();
return ares;
}
if (_bodyLeft >= 0 && _bodyLeft < count)
count = (int) _bodyLeft;
return _stream.BeginRead (buffer, offset, count, callback, state);
}
public override IAsyncResult BeginWrite (
byte[] buffer, int offset, int count, AsyncCallback callback, object state
)
{
throw new NotSupportedException ();
}
public override void Close ()
{
_disposed = true;
}
public override int EndRead (IAsyncResult asyncResult)
{
if (_disposed) {
var name = GetType ().ToString ();
throw new ObjectDisposedException (name);
}
if (asyncResult == null)
throw new ArgumentNullException ("asyncResult");
if (asyncResult is HttpStreamAsyncResult) {
var ares = (HttpStreamAsyncResult) asyncResult;
if (!ares.IsCompleted)
ares.AsyncWaitHandle.WaitOne ();
return ares.SyncRead;
}
var nread = _stream.EndRead (asyncResult);
if (nread > 0 && _bodyLeft > 0)
_bodyLeft -= nread;
return nread;
}
public override void EndWrite (IAsyncResult asyncResult)
{
throw new NotSupportedException ();
}
public override void Flush ()
{
}
public override int Read (byte[] buffer, int offset, int count)
{
if (_disposed) {
var name = GetType ().ToString ();
throw new ObjectDisposedException (name);
}
if (buffer == null)
throw new ArgumentNullException ("buffer");
if (offset < 0) {
var msg = "A negative value.";
throw new ArgumentOutOfRangeException ("offset", msg);
}
if (count < 0) {
var msg = "A negative value.";
throw new ArgumentOutOfRangeException ("count", msg);
}
var len = buffer.Length;
if (offset + count > len) {
var msg = "The sum of 'offset' and 'count' is greater than the length of 'buffer'.";
throw new ArgumentException (msg);
}
if (count == 0)
return 0;
var nread = fillFromBuffer (buffer, offset, count);
if (nread == -1)
return 0;
if (nread > 0)
return nread;
nread = _stream.Read (buffer, offset, count);
if (nread > 0 && _bodyLeft > 0)
_bodyLeft -= nread;
return nread;
}
public override long Seek (long offset, SeekOrigin origin)
{
throw new NotSupportedException ();
}
public override void SetLength (long value)
{
throw new NotSupportedException ();
}
public override void Write (byte[] buffer, int offset, int count)
{
throw new NotSupportedException ();
}
#endregion
}
}

View File

@ -1,403 +0,0 @@
#region License
/*
* ResponseStream.cs
*
* This code is derived from ResponseStream.cs (System.Net) of Mono
* (http://www.mono-project.com).
*
* The MIT License
*
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
* Copyright (c) 2012-2020 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
*/
#endregion
using System;
using System.IO;
using System.Text;
namespace WebSocketSharp.Net
{
internal class ResponseStream : Stream
{
#region Private Fields
private MemoryStream _bodyBuffer;
private static readonly byte[] _crlf;
private bool _disposed;
private Stream _innerStream;
private static readonly byte[] _lastChunk;
private static readonly int _maxHeadersLength;
private HttpListenerResponse _response;
private bool _sendChunked;
private Action<byte[], int, int> _write;
private Action<byte[], int, int> _writeBody;
private Action<byte[], int, int> _writeChunked;
#endregion
#region Static Constructor
static ResponseStream ()
{
_crlf = new byte[] { 13, 10 }; // "\r\n"
_lastChunk = new byte[] { 48, 13, 10, 13, 10 }; // "0\r\n\r\n"
_maxHeadersLength = 32768;
}
#endregion
#region Internal Constructors
internal ResponseStream (
Stream innerStream,
HttpListenerResponse response,
bool ignoreWriteExceptions
)
{
_innerStream = innerStream;
_response = response;
if (ignoreWriteExceptions) {
_write = writeWithoutThrowingException;
_writeChunked = writeChunkedWithoutThrowingException;
}
else {
_write = innerStream.Write;
_writeChunked = writeChunked;
}
_bodyBuffer = new MemoryStream ();
}
#endregion
#region Public Properties
public override bool CanRead {
get {
return false;
}
}
public override bool CanSeek {
get {
return false;
}
}
public override bool CanWrite {
get {
return !_disposed;
}
}
public override long Length {
get {
throw new NotSupportedException ();
}
}
public override long Position {
get {
throw new NotSupportedException ();
}
set {
throw new NotSupportedException ();
}
}
#endregion
#region Private Methods
private bool flush (bool closing)
{
if (!_response.HeadersSent) {
if (!flushHeaders ())
return false;
_response.HeadersSent = true;
_sendChunked = _response.SendChunked;
_writeBody = _sendChunked ? _writeChunked : _write;
}
flushBody (closing);
return true;
}
private void flushBody (bool closing)
{
using (_bodyBuffer) {
var len = _bodyBuffer.Length;
if (len > Int32.MaxValue) {
_bodyBuffer.Position = 0;
var buffLen = 1024;
var buff = new byte[buffLen];
var nread = 0;
while (true) {
nread = _bodyBuffer.Read (buff, 0, buffLen);
if (nread <= 0)
break;
_writeBody (buff, 0, nread);
}
}
else if (len > 0) {
_writeBody (_bodyBuffer.GetBuffer (), 0, (int) len);
}
}
if (!closing) {
_bodyBuffer = new MemoryStream ();
return;
}
if (_sendChunked)
_write (_lastChunk, 0, 5);
_bodyBuffer = null;
}
private bool flushHeaders ()
{
if (!_response.SendChunked) {
if (_response.ContentLength64 != _bodyBuffer.Length)
return false;
}
var statusLine = _response.StatusLine;
var headers = _response.FullHeaders;
var buff = new MemoryStream ();
var enc = Encoding.UTF8;
using (var writer = new StreamWriter (buff, enc, 256)) {
writer.Write (statusLine);
writer.Write (headers.ToStringMultiValue (true));
writer.Flush ();
var start = enc.GetPreamble ().Length;
var len = buff.Length - start;
if (len > _maxHeadersLength)
return false;
_write (buff.GetBuffer (), start, (int) len);
}
_response.CloseConnection = headers["Connection"] == "close";
return true;
}
private static byte[] getChunkSizeBytes (int size)
{
var chunkSize = String.Format ("{0:x}\r\n", size);
return Encoding.ASCII.GetBytes (chunkSize);
}
private void writeChunked (byte[] buffer, int offset, int count)
{
var size = getChunkSizeBytes (count);
_innerStream.Write (size, 0, size.Length);
_innerStream.Write (buffer, offset, count);
_innerStream.Write (_crlf, 0, 2);
}
private void writeChunkedWithoutThrowingException (
byte[] buffer, int offset, int count
)
{
try {
writeChunked (buffer, offset, count);
}
catch {
}
}
private void writeWithoutThrowingException (
byte[] buffer, int offset, int count
)
{
try {
_innerStream.Write (buffer, offset, count);
}
catch {
}
}
#endregion
#region Internal Methods
internal void Close (bool force)
{
if (_disposed)
return;
_disposed = true;
if (!force) {
if (flush (true)) {
_response.Close ();
_response = null;
_innerStream = null;
return;
}
_response.CloseConnection = true;
}
if (_sendChunked)
_write (_lastChunk, 0, 5);
_bodyBuffer.Dispose ();
_response.Abort ();
_bodyBuffer = null;
_response = null;
_innerStream = null;
}
internal void InternalWrite (byte[] buffer, int offset, int count)
{
_write (buffer, offset, count);
}
#endregion
#region Public Methods
public override IAsyncResult BeginRead (
byte[] buffer,
int offset,
int count,
AsyncCallback callback,
object state
)
{
throw new NotSupportedException ();
}
public override IAsyncResult BeginWrite (
byte[] buffer,
int offset,
int count,
AsyncCallback callback,
object state
)
{
if (_disposed) {
var name = GetType ().ToString ();
throw new ObjectDisposedException (name);
}
return _bodyBuffer.BeginWrite (buffer, offset, count, callback, state);
}
public override void Close ()
{
Close (false);
}
protected override void Dispose (bool disposing)
{
Close (!disposing);
}
public override int EndRead (IAsyncResult asyncResult)
{
throw new NotSupportedException ();
}
public override void EndWrite (IAsyncResult asyncResult)
{
if (_disposed) {
var name = GetType ().ToString ();
throw new ObjectDisposedException (name);
}
_bodyBuffer.EndWrite (asyncResult);
}
public override void Flush ()
{
if (_disposed)
return;
var sendChunked = _sendChunked || _response.SendChunked;
if (!sendChunked)
return;
flush (false);
}
public override int Read (byte[] buffer, int offset, int count)
{
throw new NotSupportedException ();
}
public override long Seek (long offset, SeekOrigin origin)
{
throw new NotSupportedException ();
}
public override void SetLength (long value)
{
throw new NotSupportedException ();
}
public override void Write (byte[] buffer, int offset, int count)
{
if (_disposed) {
var name = GetType ().ToString ();
throw new ObjectDisposedException (name);
}
_bodyBuffer.Write (buffer, offset, count);
}
#endregion
}
}

View File

@ -1,236 +0,0 @@
#region License
/*
* ServerSslConfiguration.cs
*
* The MIT License
*
* Copyright (c) 2014 liryna
* Copyright (c) 2014-2020 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Authors
/*
* Authors:
* - Liryna <liryna.stark@gmail.com>
*/
#endregion
using System;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
namespace WebSocketSharp.Net
{
/// <summary>
/// Stores the parameters for the <see cref="SslStream"/> used by servers.
/// </summary>
public class ServerSslConfiguration
{
#region Private Fields
private bool _checkCertRevocation;
private bool _clientCertRequired;
private RemoteCertificateValidationCallback _clientCertValidationCallback;
private SslProtocols _enabledSslProtocols;
private X509Certificate2 _serverCert;
#endregion
#region Public Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ServerSslConfiguration"/>
/// class.
/// </summary>
public ServerSslConfiguration ()
{
_enabledSslProtocols = SslProtocols.None;
}
/// <summary>
/// Initializes a new instance of the <see cref="ServerSslConfiguration"/>
/// class that stores the parameters copied from the specified configuration.
/// </summary>
/// <param name="configuration">
/// A <see cref="ServerSslConfiguration"/> from which to copy.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="configuration"/> is <see langword="null"/>.
/// </exception>
public ServerSslConfiguration (ServerSslConfiguration configuration)
{
if (configuration == null)
throw new ArgumentNullException ("configuration");
_checkCertRevocation = configuration._checkCertRevocation;
_clientCertRequired = configuration._clientCertRequired;
_clientCertValidationCallback = configuration._clientCertValidationCallback;
_enabledSslProtocols = configuration._enabledSslProtocols;
_serverCert = configuration._serverCert;
}
#endregion
#region Public Properties
/// <summary>
/// Gets or sets a value indicating whether the certificate revocation
/// list is checked during authentication.
/// </summary>
/// <value>
/// <para>
/// <c>true</c> if the certificate revocation list is checked during
/// authentication; otherwise, <c>false</c>.
/// </para>
/// <para>
/// The default value is <c>false</c>.
/// </para>
/// </value>
public bool CheckCertificateRevocation {
get {
return _checkCertRevocation;
}
set {
_checkCertRevocation = value;
}
}
/// <summary>
/// Gets or sets a value indicating whether the client is asked for
/// a certificate for authentication.
/// </summary>
/// <value>
/// <para>
/// <c>true</c> if the client is asked for a certificate for
/// authentication; otherwise, <c>false</c>.
/// </para>
/// <para>
/// The default value is <c>false</c>.
/// </para>
/// </value>
public bool ClientCertificateRequired {
get {
return _clientCertRequired;
}
set {
_clientCertRequired = value;
}
}
/// <summary>
/// Gets or sets the callback used to validate the certificate supplied by
/// the client.
/// </summary>
/// <remarks>
/// The certificate is valid if the callback returns <c>true</c>.
/// </remarks>
/// <value>
/// <para>
/// A <see cref="RemoteCertificateValidationCallback"/> delegate that
/// invokes the method called for validating the certificate.
/// </para>
/// <para>
/// The default value is a delegate that invokes a method that only
/// returns <c>true</c>.
/// </para>
/// </value>
public RemoteCertificateValidationCallback ClientCertificateValidationCallback {
get {
if (_clientCertValidationCallback == null)
_clientCertValidationCallback = defaultValidateClientCertificate;
return _clientCertValidationCallback;
}
set {
_clientCertValidationCallback = value;
}
}
/// <summary>
/// Gets or sets the protocols used for authentication.
/// </summary>
/// <value>
/// <para>
/// Any of the <see cref="SslProtocols"/> enum values.
/// </para>
/// <para>
/// It represents the protocols used for authentication.
/// </para>
/// <para>
/// The default value is <see cref="SslProtocols.None"/>.
/// </para>
/// </value>
public SslProtocols EnabledSslProtocols {
get {
return _enabledSslProtocols;
}
set {
_enabledSslProtocols = value;
}
}
/// <summary>
/// Gets or sets the certificate used to authenticate the server.
/// </summary>
/// <value>
/// <para>
/// A <see cref="X509Certificate2"/> or <see langword="null"/>.
/// </para>
/// <para>
/// The certificate represents an X.509 certificate.
/// </para>
/// <para>
/// The default value is <see langword="null"/>.
/// </para>
/// </value>
public X509Certificate2 ServerCertificate {
get {
return _serverCert;
}
set {
_serverCert = value;
}
}
#endregion
#region Private Methods
private static bool defaultValidateClientCertificate (
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors
)
{
return true;
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,395 +0,0 @@
#region License
/*
* HttpListenerWebSocketContext.cs
*
* The MIT License
*
* Copyright (c) 2012-2018 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Security.Principal;
namespace WebSocketSharp.Net.WebSockets
{
/// <summary>
/// Provides the access to the information in a WebSocket handshake request to
/// a <see cref="HttpListener"/> instance.
/// </summary>
public class HttpListenerWebSocketContext : WebSocketContext
{
#region Private Fields
private HttpListenerContext _context;
private WebSocket _websocket;
#endregion
#region Internal Constructors
internal HttpListenerWebSocketContext (
HttpListenerContext context, string protocol
)
{
_context = context;
_websocket = new WebSocket (this, protocol);
}
#endregion
#region Internal Properties
internal Logger Log {
get {
return _context.Listener.Log;
}
}
internal Stream Stream {
get {
return _context.Connection.Stream;
}
}
#endregion
#region Public Properties
/// <summary>
/// Gets the HTTP cookies included in the handshake request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="WebSocketSharp.Net.CookieCollection"/> that contains
/// the cookies.
/// </para>
/// <para>
/// An empty collection if not included.
/// </para>
/// </value>
public override CookieCollection CookieCollection {
get {
return _context.Request.Cookies;
}
}
/// <summary>
/// Gets the HTTP headers included in the handshake request.
/// </summary>
/// <value>
/// A <see cref="NameValueCollection"/> that contains the headers.
/// </value>
public override NameValueCollection Headers {
get {
return _context.Request.Headers;
}
}
/// <summary>
/// Gets the value of the Host header included in the handshake request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="string"/> that represents the server host name requested
/// by the client.
/// </para>
/// <para>
/// It includes the port number if provided.
/// </para>
/// </value>
public override string Host {
get {
return _context.Request.UserHostName;
}
}
/// <summary>
/// Gets a value indicating whether the client is authenticated.
/// </summary>
/// <value>
/// <c>true</c> if the client is authenticated; otherwise, <c>false</c>.
/// </value>
public override bool IsAuthenticated {
get {
return _context.Request.IsAuthenticated;
}
}
/// <summary>
/// Gets a value indicating whether the handshake request is sent from
/// the local computer.
/// </summary>
/// <value>
/// <c>true</c> if the handshake request is sent from the same computer
/// as the server; otherwise, <c>false</c>.
/// </value>
public override bool IsLocal {
get {
return _context.Request.IsLocal;
}
}
/// <summary>
/// Gets a value indicating whether a secure connection is used to send
/// the handshake request.
/// </summary>
/// <value>
/// <c>true</c> if the connection is secure; otherwise, <c>false</c>.
/// </value>
public override bool IsSecureConnection {
get {
return _context.Request.IsSecureConnection;
}
}
/// <summary>
/// Gets a value indicating whether the request is a WebSocket handshake
/// request.
/// </summary>
/// <value>
/// <c>true</c> if the request is a WebSocket handshake request; otherwise,
/// <c>false</c>.
/// </value>
public override bool IsWebSocketRequest {
get {
return _context.Request.IsWebSocketRequest;
}
}
/// <summary>
/// Gets the value of the Origin header included in the handshake request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="string"/> that represents the value of the Origin header.
/// </para>
/// <para>
/// <see langword="null"/> if the header is not present.
/// </para>
/// </value>
public override string Origin {
get {
return _context.Request.Headers["Origin"];
}
}
/// <summary>
/// Gets the query string included in the handshake request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="NameValueCollection"/> that contains the query
/// parameters.
/// </para>
/// <para>
/// An empty collection if not included.
/// </para>
/// </value>
public override NameValueCollection QueryString {
get {
return _context.Request.QueryString;
}
}
/// <summary>
/// Gets the URI requested by the client.
/// </summary>
/// <value>
/// <para>
/// A <see cref="Uri"/> that represents the URI parsed from the request.
/// </para>
/// <para>
/// <see langword="null"/> if the URI cannot be parsed.
/// </para>
/// </value>
public override Uri RequestUri {
get {
return _context.Request.Url;
}
}
/// <summary>
/// Gets the value of the Sec-WebSocket-Key header included in
/// the handshake request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="string"/> that represents the value of
/// the Sec-WebSocket-Key header.
/// </para>
/// <para>
/// The value is used to prove that the server received
/// a valid WebSocket handshake request.
/// </para>
/// <para>
/// <see langword="null"/> if the header is not present.
/// </para>
/// </value>
public override string SecWebSocketKey {
get {
return _context.Request.Headers["Sec-WebSocket-Key"];
}
}
/// <summary>
/// Gets the names of the subprotocols from the Sec-WebSocket-Protocol
/// header included in the handshake request.
/// </summary>
/// <value>
/// <para>
/// An <see cref="T:System.Collections.Generic.IEnumerable{string}"/>
/// instance.
/// </para>
/// <para>
/// It provides an enumerator which supports the iteration over
/// the collection of the names of the subprotocols.
/// </para>
/// </value>
public override IEnumerable<string> SecWebSocketProtocols {
get {
var val = _context.Request.Headers["Sec-WebSocket-Protocol"];
if (val == null || val.Length == 0)
yield break;
foreach (var elm in val.Split (',')) {
var protocol = elm.Trim ();
if (protocol.Length == 0)
continue;
yield return protocol;
}
}
}
/// <summary>
/// Gets the value of the Sec-WebSocket-Version header included in
/// the handshake request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="string"/> that represents the WebSocket protocol
/// version specified by the client.
/// </para>
/// <para>
/// <see langword="null"/> if the header is not present.
/// </para>
/// </value>
public override string SecWebSocketVersion {
get {
return _context.Request.Headers["Sec-WebSocket-Version"];
}
}
/// <summary>
/// Gets the endpoint to which the handshake request is sent.
/// </summary>
/// <value>
/// A <see cref="System.Net.IPEndPoint"/> that represents the server IP
/// address and port number.
/// </value>
public override System.Net.IPEndPoint ServerEndPoint {
get {
return _context.Request.LocalEndPoint;
}
}
/// <summary>
/// Gets the client information.
/// </summary>
/// <value>
/// <para>
/// A <see cref="IPrincipal"/> instance that represents identity,
/// authentication, and security roles for the client.
/// </para>
/// <para>
/// <see langword="null"/> if the client is not authenticated.
/// </para>
/// </value>
public override IPrincipal User {
get {
return _context.User;
}
}
/// <summary>
/// Gets the endpoint from which the handshake request is sent.
/// </summary>
/// <value>
/// A <see cref="System.Net.IPEndPoint"/> that represents the client IP
/// address and port number.
/// </value>
public override System.Net.IPEndPoint UserEndPoint {
get {
return _context.Request.RemoteEndPoint;
}
}
/// <summary>
/// Gets the WebSocket instance used for two-way communication between
/// the client and server.
/// </summary>
/// <value>
/// A <see cref="WebSocketSharp.WebSocket"/>.
/// </value>
public override WebSocket WebSocket {
get {
return _websocket;
}
}
#endregion
#region Internal Methods
internal void Close ()
{
_context.Connection.Close (true);
}
internal void Close (HttpStatusCode code)
{
_context.Response.StatusCode = (int) code;
_context.Response.Close ();
}
#endregion
#region Public Methods
/// <summary>
/// Returns a string that represents the current instance.
/// </summary>
/// <returns>
/// A <see cref="string"/> that contains the request line and headers
/// included in the handshake request.
/// </returns>
public override string ToString ()
{
return _context.Request.ToString ();
}
#endregion
}
}

View File

@ -1,518 +0,0 @@
#region License
/*
* TcpListenerWebSocketContext.cs
*
* The MIT License
*
* Copyright (c) 2012-2018 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Contributors
/*
* Contributors:
* - Liryna <liryna.stark@gmail.com>
*/
#endregion
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 WebSocketSharp.Net.WebSockets
{
/// <summary>
/// Provides the access to the information in a WebSocket handshake request to
/// a <see cref="TcpListener"/> instance.
/// </summary>
internal class TcpListenerWebSocketContext : WebSocketContext
{
#region Private Fields
private Logger _log;
private NameValueCollection _queryString;
private HttpRequest _request;
private Uri _requestUri;
private bool _secure;
private System.Net.EndPoint _serverEndPoint;
private Stream _stream;
private TcpClient _tcpClient;
private IPrincipal _user;
private System.Net.EndPoint _userEndPoint;
private WebSocket _websocket;
#endregion
#region Internal Constructors
internal TcpListenerWebSocketContext (
TcpClient tcpClient,
string protocol,
bool secure,
ServerSslConfiguration sslConfig,
Logger log
)
{
_tcpClient = tcpClient;
_secure = secure;
_log = log;
var netStream = tcpClient.GetStream ();
if (secure) {
var sslStream = new SslStream (
netStream,
false,
sslConfig.ClientCertificateValidationCallback
);
sslStream.AuthenticateAsServer (
sslConfig.ServerCertificate,
sslConfig.ClientCertificateRequired,
sslConfig.EnabledSslProtocols,
sslConfig.CheckCertificateRevocation
);
_stream = sslStream;
}
else {
_stream = netStream;
}
var sock = tcpClient.Client;
_serverEndPoint = sock.LocalEndPoint;
_userEndPoint = sock.RemoteEndPoint;
_request = HttpRequest.Read (_stream, 90000);
_websocket = new WebSocket (this, protocol);
}
#endregion
#region Internal Properties
internal Logger Log {
get {
return _log;
}
}
internal Stream Stream {
get {
return _stream;
}
}
#endregion
#region Public Properties
/// <summary>
/// Gets the HTTP cookies included in the handshake request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="WebSocketSharp.Net.CookieCollection"/> that contains
/// the cookies.
/// </para>
/// <para>
/// An empty collection if not included.
/// </para>
/// </value>
public override CookieCollection CookieCollection {
get {
return _request.Cookies;
}
}
/// <summary>
/// Gets the HTTP headers included in the handshake request.
/// </summary>
/// <value>
/// A <see cref="NameValueCollection"/> that contains the headers.
/// </value>
public override NameValueCollection Headers {
get {
return _request.Headers;
}
}
/// <summary>
/// Gets the value of the Host header included in the handshake request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="string"/> that represents the server host name requested
/// by the client.
/// </para>
/// <para>
/// It includes the port number if provided.
/// </para>
/// </value>
public override string Host {
get {
return _request.Headers["Host"];
}
}
/// <summary>
/// Gets a value indicating whether the client is authenticated.
/// </summary>
/// <value>
/// <c>true</c> if the client is authenticated; otherwise, <c>false</c>.
/// </value>
public override bool IsAuthenticated {
get {
return _user != null;
}
}
/// <summary>
/// Gets a value indicating whether the handshake request is sent from
/// the local computer.
/// </summary>
/// <value>
/// <c>true</c> if the handshake request is sent from the same computer
/// as the server; otherwise, <c>false</c>.
/// </value>
public override bool IsLocal {
get {
return UserEndPoint.Address.IsLocal ();
}
}
/// <summary>
/// Gets a value indicating whether a secure connection is used to send
/// the handshake request.
/// </summary>
/// <value>
/// <c>true</c> if the connection is secure; otherwise, <c>false</c>.
/// </value>
public override bool IsSecureConnection {
get {
return _secure;
}
}
/// <summary>
/// Gets a value indicating whether the request is a WebSocket handshake
/// request.
/// </summary>
/// <value>
/// <c>true</c> if the request is a WebSocket handshake request; otherwise,
/// <c>false</c>.
/// </value>
public override bool IsWebSocketRequest {
get {
return _request.IsWebSocketRequest;
}
}
/// <summary>
/// Gets the value of the Origin header included in the handshake request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="string"/> that represents the value of the Origin header.
/// </para>
/// <para>
/// <see langword="null"/> if the header is not present.
/// </para>
/// </value>
public override string Origin {
get {
return _request.Headers["Origin"];
}
}
/// <summary>
/// Gets the query string included in the handshake request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="NameValueCollection"/> that contains the query
/// parameters.
/// </para>
/// <para>
/// An empty collection if not included.
/// </para>
/// </value>
public override NameValueCollection QueryString {
get {
if (_queryString == null) {
var uri = RequestUri;
_queryString = QueryStringCollection.Parse (
uri != null ? uri.Query : null,
Encoding.UTF8
);
}
return _queryString;
}
}
/// <summary>
/// Gets the URI requested by the client.
/// </summary>
/// <value>
/// <para>
/// A <see cref="Uri"/> that represents the URI parsed from the request.
/// </para>
/// <para>
/// <see langword="null"/> if the URI cannot be parsed.
/// </para>
/// </value>
public override Uri RequestUri {
get {
if (_requestUri == null) {
_requestUri = HttpUtility.CreateRequestUrl (
_request.RequestUri,
_request.Headers["Host"],
_request.IsWebSocketRequest,
_secure
);
}
return _requestUri;
}
}
/// <summary>
/// Gets the value of the Sec-WebSocket-Key header included in
/// the handshake request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="string"/> that represents the value of
/// the Sec-WebSocket-Key header.
/// </para>
/// <para>
/// The value is used to prove that the server received
/// a valid WebSocket handshake request.
/// </para>
/// <para>
/// <see langword="null"/> if the header is not present.
/// </para>
/// </value>
public override string SecWebSocketKey {
get {
return _request.Headers["Sec-WebSocket-Key"];
}
}
/// <summary>
/// Gets the names of the subprotocols from the Sec-WebSocket-Protocol
/// header included in the handshake request.
/// </summary>
/// <value>
/// <para>
/// An <see cref="T:System.Collections.Generic.IEnumerable{string}"/>
/// instance.
/// </para>
/// <para>
/// It provides an enumerator which supports the iteration over
/// the collection of the names of the subprotocols.
/// </para>
/// </value>
public override IEnumerable<string> SecWebSocketProtocols {
get {
var val = _request.Headers["Sec-WebSocket-Protocol"];
if (val == null || val.Length == 0)
yield break;
foreach (var elm in val.Split (',')) {
var protocol = elm.Trim ();
if (protocol.Length == 0)
continue;
yield return protocol;
}
}
}
/// <summary>
/// Gets the value of the Sec-WebSocket-Version header included in
/// the handshake request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="string"/> that represents the WebSocket protocol
/// version specified by the client.
/// </para>
/// <para>
/// <see langword="null"/> if the header is not present.
/// </para>
/// </value>
public override string SecWebSocketVersion {
get {
return _request.Headers["Sec-WebSocket-Version"];
}
}
/// <summary>
/// Gets the endpoint to which the handshake request is sent.
/// </summary>
/// <value>
/// A <see cref="System.Net.IPEndPoint"/> that represents the server IP
/// address and port number.
/// </value>
public override System.Net.IPEndPoint ServerEndPoint {
get {
return (System.Net.IPEndPoint) _serverEndPoint;
}
}
/// <summary>
/// Gets the client information.
/// </summary>
/// <value>
/// <para>
/// A <see cref="IPrincipal"/> instance that represents identity,
/// authentication, and security roles for the client.
/// </para>
/// <para>
/// <see langword="null"/> if the client is not authenticated.
/// </para>
/// </value>
public override IPrincipal User {
get {
return _user;
}
}
/// <summary>
/// Gets the endpoint from which the handshake request is sent.
/// </summary>
/// <value>
/// A <see cref="System.Net.IPEndPoint"/> that represents the client IP
/// address and port number.
/// </value>
public override System.Net.IPEndPoint UserEndPoint {
get {
return (System.Net.IPEndPoint) _userEndPoint;
}
}
/// <summary>
/// Gets the WebSocket instance used for two-way communication between
/// the client and server.
/// </summary>
/// <value>
/// A <see cref="WebSocketSharp.WebSocket"/>.
/// </value>
public override WebSocket WebSocket {
get {
return _websocket;
}
}
#endregion
#region Private Methods
private HttpRequest sendAuthenticationChallenge (string challenge)
{
var res = HttpResponse.CreateUnauthorizedResponse (challenge);
var bytes = res.ToByteArray ();
_stream.Write (bytes, 0, bytes.Length);
return HttpRequest.Read (_stream, 15000);
}
#endregion
#region Internal Methods
internal bool Authenticate (
AuthenticationSchemes scheme,
string realm,
Func<IIdentity, NetworkCredential> credentialsFinder
)
{
var chal = new AuthenticationChallenge (scheme, realm).ToString ();
var retry = -1;
Func<bool> auth = null;
auth =
() => {
retry++;
if (retry > 99)
return false;
var user = HttpUtility.CreateUser (
_request.Headers["Authorization"],
scheme,
realm,
_request.HttpMethod,
credentialsFinder
);
if (user != null && user.Identity.IsAuthenticated) {
_user = user;
return true;
}
_request = sendAuthenticationChallenge (chal);
return auth ();
};
return auth ();
}
internal void Close ()
{
_stream.Close ();
_tcpClient.Close ();
}
internal void Close (HttpStatusCode code)
{
var res = HttpResponse.CreateCloseResponse (code);
var bytes = res.ToByteArray ();
_stream.Write (bytes, 0, bytes.Length);
_stream.Close ();
_tcpClient.Close ();
}
#endregion
#region Public Methods
/// <summary>
/// Returns a string that represents the current instance.
/// </summary>
/// <returns>
/// A <see cref="string"/> that contains the request line and headers
/// included in the handshake request.
/// </returns>
public override string ToString ()
{
return _request.ToString ();
}
#endregion
}
}

View File

@ -1,224 +0,0 @@
#region License
/*
* WebSocketContext.cs
*
* The MIT License
*
* Copyright (c) 2012-2018 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Security.Principal;
namespace WebSocketSharp.Net.WebSockets
{
/// <summary>
/// Exposes the access to the information in a WebSocket handshake request.
/// </summary>
/// <remarks>
/// This class is an abstract class.
/// </remarks>
public abstract class WebSocketContext
{
#region Protected Constructors
/// <summary>
/// Initializes a new instance of the <see cref="WebSocketContext"/> class.
/// </summary>
protected WebSocketContext ()
{
}
#endregion
#region Public Properties
/// <summary>
/// Gets the HTTP cookies included in the handshake request.
/// </summary>
/// <value>
/// A <see cref="WebSocketSharp.Net.CookieCollection"/> that contains
/// the cookies.
/// </value>
public abstract CookieCollection CookieCollection { get; }
/// <summary>
/// Gets the HTTP headers included in the handshake request.
/// </summary>
/// <value>
/// A <see cref="NameValueCollection"/> that contains the headers.
/// </value>
public abstract NameValueCollection Headers { get; }
/// <summary>
/// Gets the value of the Host header included in the handshake request.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the server host name requested
/// by the client.
/// </value>
public abstract string Host { get; }
/// <summary>
/// Gets a value indicating whether the client is authenticated.
/// </summary>
/// <value>
/// <c>true</c> if the client is authenticated; otherwise, <c>false</c>.
/// </value>
public abstract bool IsAuthenticated { get; }
/// <summary>
/// Gets a value indicating whether the handshake request is sent from
/// the local computer.
/// </summary>
/// <value>
/// <c>true</c> if the handshake request is sent from the same computer
/// as the server; otherwise, <c>false</c>.
/// </value>
public abstract bool IsLocal { get; }
/// <summary>
/// Gets a value indicating whether a secure connection is used to send
/// the handshake request.
/// </summary>
/// <value>
/// <c>true</c> if the connection is secure; otherwise, <c>false</c>.
/// </value>
public abstract bool IsSecureConnection { get; }
/// <summary>
/// Gets a value indicating whether the request is a WebSocket handshake
/// request.
/// </summary>
/// <value>
/// <c>true</c> if the request is a WebSocket handshake request; otherwise,
/// <c>false</c>.
/// </value>
public abstract bool IsWebSocketRequest { get; }
/// <summary>
/// Gets the value of the Origin header included in the handshake request.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the value of the Origin header.
/// </value>
public abstract string Origin { get; }
/// <summary>
/// Gets the query string included in the handshake request.
/// </summary>
/// <value>
/// A <see cref="NameValueCollection"/> that contains the query parameters.
/// </value>
public abstract NameValueCollection QueryString { get; }
/// <summary>
/// Gets the URI requested by the client.
/// </summary>
/// <value>
/// A <see cref="Uri"/> that represents the URI parsed from the request.
/// </value>
public abstract Uri RequestUri { get; }
/// <summary>
/// Gets the value of the Sec-WebSocket-Key header included in
/// the handshake request.
/// </summary>
/// <value>
/// <para>
/// A <see cref="string"/> that represents the value of
/// the Sec-WebSocket-Key header.
/// </para>
/// <para>
/// The value is used to prove that the server received
/// a valid WebSocket handshake request.
/// </para>
/// </value>
public abstract string SecWebSocketKey { get; }
/// <summary>
/// Gets the names of the subprotocols from the Sec-WebSocket-Protocol
/// header included in the handshake request.
/// </summary>
/// <value>
/// <para>
/// An <see cref="T:System.Collections.Generic.IEnumerable{string}"/>
/// instance.
/// </para>
/// <para>
/// It provides an enumerator which supports the iteration over
/// the collection of the names of the subprotocols.
/// </para>
/// </value>
public abstract IEnumerable<string> SecWebSocketProtocols { get; }
/// <summary>
/// Gets the value of the Sec-WebSocket-Version header included in
/// the handshake request.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the WebSocket protocol
/// version specified by the client.
/// </value>
public abstract string SecWebSocketVersion { get; }
/// <summary>
/// Gets the endpoint to which the handshake request is sent.
/// </summary>
/// <value>
/// A <see cref="System.Net.IPEndPoint"/> that represents the server IP
/// address and port number.
/// </value>
public abstract System.Net.IPEndPoint ServerEndPoint { get; }
/// <summary>
/// Gets the client information.
/// </summary>
/// <value>
/// A <see cref="IPrincipal"/> instance that represents identity,
/// authentication, and security roles for the client.
/// </value>
public abstract IPrincipal User { get; }
/// <summary>
/// Gets the endpoint from which the handshake request is sent.
/// </summary>
/// <value>
/// A <see cref="System.Net.IPEndPoint"/> that represents the client IP
/// address and port number.
/// </value>
public abstract System.Net.IPEndPoint UserEndPoint { get; }
/// <summary>
/// Gets the WebSocket instance used for two-way communication between
/// the client and server.
/// </summary>
/// <value>
/// A <see cref="WebSocketSharp.WebSocket"/>.
/// </value>
public abstract WebSocket WebSocket { get; }
#endregion
}
}

View File

@ -1,68 +0,0 @@
#region License
/*
* Opcode.cs
*
* The MIT License
*
* Copyright (c) 2012-2016 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp
{
/// <summary>
/// Indicates the WebSocket frame type.
/// </summary>
/// <remarks>
/// The values of this enumeration are defined in
/// <see href="http://tools.ietf.org/html/rfc6455#section-5.2">
/// Section 5.2</see> of RFC 6455.
/// </remarks>
internal enum Opcode : byte
{
/// <summary>
/// Equivalent to numeric value 0. Indicates continuation frame.
/// </summary>
Cont = 0x0,
/// <summary>
/// Equivalent to numeric value 1. Indicates text frame.
/// </summary>
Text = 0x1,
/// <summary>
/// Equivalent to numeric value 2. Indicates binary frame.
/// </summary>
Binary = 0x2,
/// <summary>
/// Equivalent to numeric value 8. Indicates connection close frame.
/// </summary>
Close = 0x8,
/// <summary>
/// Equivalent to numeric value 9. Indicates ping frame.
/// </summary>
Ping = 0x9,
/// <summary>
/// Equivalent to numeric value 10. Indicates pong frame.
/// </summary>
Pong = 0xa
}
}

View File

@ -1,15 +0,0 @@
using System;
namespace WebSocketSharp
{
public class OpenEventArgs : EventArgs
{
public string LocalIP { get; private set; }
public string RemoteIP { get; private set; }
public OpenEventArgs(string localIp, string remoteIp)
{
LocalIP = localIp;
RemoteIP = remoteIp;
}
}
}

View File

@ -1,208 +0,0 @@
#region License
/*
* PayloadData.cs
*
* The MIT License
*
* Copyright (c) 2012-2019 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
namespace WebSocketSharp
{
internal class PayloadData : IEnumerable<byte>
{
#region Private Fields
private byte[] _data;
private long _extDataLength;
private long _length;
#endregion
#region Public Fields
/// <summary>
/// Represents the empty payload data.
/// </summary>
public static readonly PayloadData Empty;
/// <summary>
/// Represents the allowable max length of payload data.
/// </summary>
/// <remarks>
/// <para>
/// A <see cref="WebSocketException"/> will occur when the length of
/// incoming payload data is greater than the value of this field.
/// </para>
/// <para>
/// If you would like to change the value of this field, it must be
/// a number between <see cref="WebSocket.FragmentLength"/> and
/// <see cref="Int64.MaxValue"/> inclusive.
/// </para>
/// </remarks>
public static readonly ulong MaxLength;
#endregion
#region Static Constructor
static PayloadData ()
{
Empty = new PayloadData (WebSocket.EmptyBytes, 0);
MaxLength = Int64.MaxValue;
}
#endregion
#region Internal Constructors
internal PayloadData (byte[] data)
: this (data, data.LongLength)
{
}
internal PayloadData (byte[] data, long length)
{
_data = data;
_length = length;
}
internal PayloadData (ushort code, string reason)
{
_data = code.Append (reason);
_length = _data.LongLength;
}
#endregion
#region Internal Properties
internal ushort Code {
get {
return _length >= 2
? _data.SubArray (0, 2).ToUInt16 (ByteOrder.Big)
: (ushort) 1005;
}
}
internal long ExtensionDataLength {
get {
return _extDataLength;
}
set {
_extDataLength = value;
}
}
internal bool HasReservedCode {
get {
return _length >= 2 && Code.IsReserved ();
}
}
internal string Reason {
get {
if (_length <= 2)
return String.Empty;
var raw = _data.SubArray (2, _length - 2);
string reason;
return raw.TryGetUTF8DecodedString (out reason)
? reason
: String.Empty;
}
}
#endregion
#region Public Properties
public byte[] ApplicationData {
get {
return _extDataLength > 0
? _data.SubArray (_extDataLength, _length - _extDataLength)
: _data;
}
}
public byte[] ExtensionData {
get {
return _extDataLength > 0
? _data.SubArray (0, _extDataLength)
: WebSocket.EmptyBytes;
}
}
public ulong Length {
get {
return (ulong) _length;
}
}
#endregion
#region Internal Methods
internal void Mask (byte[] key)
{
for (long i = 0; i < _length; i++)
_data[i] = (byte) (_data[i] ^ key[i % 4]);
}
#endregion
#region Public Methods
public IEnumerator<byte> GetEnumerator ()
{
foreach (var b in _data)
yield return b;
}
public byte[] ToArray ()
{
return _data;
}
public override string ToString ()
{
return BitConverter.ToString (_data);
}
#endregion
#region Explicit Interface Implementations
IEnumerator IEnumerable.GetEnumerator ()
{
return GetEnumerator ();
}
#endregion
}
}

View File

@ -1,51 +0,0 @@
#region License
/*
* Rsv.cs
*
* The MIT License
*
* Copyright (c) 2012-2015 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp
{
/// <summary>
/// Indicates whether each RSV (RSV1, RSV2, and RSV3) of a WebSocket frame is non-zero.
/// </summary>
/// <remarks>
/// The values of this enumeration are defined in
/// <see href="http://tools.ietf.org/html/rfc6455#section-5.2">Section 5.2</see> of RFC 6455.
/// </remarks>
internal enum Rsv : byte
{
/// <summary>
/// Equivalent to numeric value 0. Indicates zero.
/// </summary>
Off = 0x0,
/// <summary>
/// Equivalent to numeric value 1. Indicates non-zero.
/// </summary>
On = 0x1
}
}

View File

@ -1,260 +0,0 @@
#region License
/*
* HttpRequestEventArgs.cs
*
* The MIT License
*
* Copyright (c) 2012-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.IO;
using System.Security.Principal;
using System.Text;
using WebSocketSharp.Net;
namespace WebSocketSharp.Server
{
/// <summary>
/// Represents the event data for the HTTP request events of the
/// <see cref="HttpServer"/> class.
/// </summary>
/// <remarks>
/// <para>
/// An HTTP request event occurs when the <see cref="HttpServer"/>
/// instance receives an HTTP request.
/// </para>
/// <para>
/// You should access the <see cref="Request"/> property if you would
/// like to get the request data sent from a client.
/// </para>
/// <para>
/// And you should access the <see cref="Response"/> property if you
/// would like to get the response data to return to the client.
/// </para>
/// </remarks>
public class HttpRequestEventArgs : EventArgs
{
#region Private Fields
private HttpListenerContext _context;
private string _docRootPath;
#endregion
#region Internal Constructors
internal HttpRequestEventArgs (
HttpListenerContext context, string documentRootPath
)
{
_context = context;
_docRootPath = documentRootPath;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the request data sent from a client.
/// </summary>
/// <value>
/// A <see cref="HttpListenerRequest"/> that provides the methods and
/// properties for the request data.
/// </value>
public HttpListenerRequest Request {
get {
return _context.Request;
}
}
/// <summary>
/// Gets the response data to return to the client.
/// </summary>
/// <value>
/// A <see cref="HttpListenerResponse"/> that provides the methods and
/// properties for the response data.
/// </value>
public HttpListenerResponse Response {
get {
return _context.Response;
}
}
/// <summary>
/// Gets the information for the client.
/// </summary>
/// <value>
/// <para>
/// A <see cref="IPrincipal"/> instance or <see langword="null"/>
/// if not authenticated.
/// </para>
/// <para>
/// That instance describes the identity, authentication scheme,
/// and security roles for the client.
/// </para>
/// </value>
public IPrincipal User {
get {
return _context.User;
}
}
#endregion
#region Private Methods
private string createFilePath (string childPath)
{
childPath = childPath.TrimStart ('/', '\\');
return new StringBuilder (_docRootPath, 32)
.AppendFormat ("/{0}", childPath)
.ToString ()
.Replace ('\\', '/');
}
private static bool tryReadFile (string path, out byte[] contents)
{
contents = null;
if (!File.Exists (path))
return false;
try {
contents = File.ReadAllBytes (path);
}
catch {
return false;
}
return true;
}
#endregion
#region Public Methods
/// <summary>
/// Reads the specified file from the document folder of the
/// <see cref="HttpServer"/> class.
/// </summary>
/// <returns>
/// <para>
/// An array of <see cref="byte"/> or <see langword="null"/>
/// if it fails.
/// </para>
/// <para>
/// That array receives the contents of the file.
/// </para>
/// </returns>
/// <param name="path">
/// A <see cref="string"/> that specifies a virtual path to
/// find the file from the document folder.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="path"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="path"/> is an empty string.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="path"/> contains "..".
/// </para>
/// </exception>
public byte[] ReadFile (string path)
{
if (path == null)
throw new ArgumentNullException ("path");
if (path.Length == 0)
throw new ArgumentException ("An empty string.", "path");
if (path.IndexOf ("..") > -1)
throw new ArgumentException ("It contains '..'.", "path");
path = createFilePath (path);
byte[] contents;
tryReadFile (path, out contents);
return contents;
}
/// <summary>
/// Tries to read the specified file from the document folder of
/// the <see cref="HttpServer"/> class.
/// </summary>
/// <returns>
/// <c>true</c> if it succeeds to read; otherwise, <c>false</c>.
/// </returns>
/// <param name="path">
/// A <see cref="string"/> that specifies a virtual path to find
/// the file from the document folder.
/// </param>
/// <param name="contents">
/// <para>
/// When this method returns, an array of <see cref="byte"/> or
/// <see langword="null"/> if it fails.
/// </para>
/// <para>
/// That array receives the contents of the file.
/// </para>
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="path"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="path"/> is an empty string.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="path"/> contains "..".
/// </para>
/// </exception>
public bool TryReadFile (string path, out byte[] contents)
{
if (path == null)
throw new ArgumentNullException ("path");
if (path.Length == 0)
throw new ArgumentException ("An empty string.", "path");
if (path.IndexOf ("..") > -1)
throw new ArgumentException ("It contains '..'.", "path");
path = createFilePath (path);
return tryReadFile (path, out contents);
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,91 +0,0 @@
#region License
/*
* IWebSocketSession.cs
*
* The MIT License
*
* Copyright (c) 2013-2018 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using WebSocketSharp.Net.WebSockets;
namespace WebSocketSharp.Server
{
/// <summary>
/// Exposes the access to the information in a WebSocket session.
/// </summary>
public interface IWebSocketSession
{
#region Properties
/// <summary>
/// Gets the current state of the WebSocket connection for the session.
/// </summary>
/// <value>
/// <para>
/// One of the <see cref="WebSocketState"/> enum values.
/// </para>
/// <para>
/// It indicates the current state of the connection.
/// </para>
/// </value>
WebSocketState ConnectionState { get; }
/// <summary>
/// Gets the information in the WebSocket handshake request.
/// </summary>
/// <value>
/// A <see cref="WebSocketContext"/> instance that provides the access to
/// the information in the handshake request.
/// </value>
WebSocketContext Context { get; }
/// <summary>
/// Gets the unique ID of the session.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the unique ID of the session.
/// </value>
string ID { get; }
/// <summary>
/// Gets the name of the WebSocket subprotocol for the session.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the name of the subprotocol
/// if present.
/// </value>
string Protocol { get; }
/// <summary>
/// Gets the time that the session has started.
/// </summary>
/// <value>
/// A <see cref="DateTime"/> that represents the time that the session
/// has started.
/// </value>
DateTime StartTime { get; }
#endregion
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,226 +0,0 @@
#region License
/*
* WebSocketServiceHost.cs
*
* The MIT License
*
* Copyright (c) 2012-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Contributors
/*
* Contributors:
* - Juan Manuel Lallana <juan.manuel.lallana@gmail.com>
*/
#endregion
using System;
using WebSocketSharp.Net.WebSockets;
namespace WebSocketSharp.Server
{
/// <summary>
/// Exposes the methods and properties used to access the information in
/// a WebSocket service provided by the <see cref="WebSocketServer"/> or
/// <see cref="HttpServer"/> class.
/// </summary>
/// <remarks>
/// This class is an abstract class.
/// </remarks>
public abstract class WebSocketServiceHost
{
#region Private Fields
private Logger _log;
private string _path;
private WebSocketSessionManager _sessions;
#endregion
#region Protected Constructors
/// <summary>
/// Initializes a new instance of the <see cref="WebSocketServiceHost"/>
/// class with the specified path and logging function.
/// </summary>
/// <param name="path">
/// A <see cref="string"/> that specifies the absolute path to
/// the service.
/// </param>
/// <param name="log">
/// A <see cref="Logger"/> that specifies the logging function for
/// the service.
/// </param>
protected WebSocketServiceHost (string path, Logger log)
{
_path = path;
_log = log;
_sessions = new WebSocketSessionManager (log);
}
#endregion
#region Internal Properties
internal ServerState State {
get {
return _sessions.State;
}
}
#endregion
#region Protected Properties
/// <summary>
/// Gets the logging function for the service.
/// </summary>
/// <value>
/// A <see cref="Logger"/> that provides the logging function.
/// </value>
protected Logger Log {
get {
return _log;
}
}
#endregion
#region Public Properties
/// <summary>
/// Gets or sets a value indicating whether the service cleans up the
/// inactive sessions periodically.
/// </summary>
/// <remarks>
/// The set operation does nothing if the service has already started or
/// it is shutting down.
/// </remarks>
/// <value>
/// <c>true</c> if the service cleans up the inactive sessions every
/// 60 seconds; otherwise, <c>false</c>.
/// </value>
public bool KeepClean {
get {
return _sessions.KeepClean;
}
set {
_sessions.KeepClean = value;
}
}
/// <summary>
/// Gets the path to the service.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the absolute path to
/// the service.
/// </value>
public string Path {
get {
return _path;
}
}
/// <summary>
/// Gets the management function for the sessions in the service.
/// </summary>
/// <value>
/// A <see cref="WebSocketSessionManager"/> that manages the sessions in
/// the service.
/// </value>
public WebSocketSessionManager Sessions {
get {
return _sessions;
}
}
/// <summary>
/// Gets the type of the behavior of the service.
/// </summary>
/// <value>
/// A <see cref="Type"/> that represents the type of the behavior of
/// the service.
/// </value>
public abstract Type BehaviorType { get; }
/// <summary>
/// Gets or sets the time to wait for the response to the WebSocket Ping
/// or Close.
/// </summary>
/// <remarks>
/// The set operation does nothing if the service has already started or
/// it is shutting down.
/// </remarks>
/// <value>
/// A <see cref="TimeSpan"/> to wait for the response.
/// </value>
/// <exception cref="ArgumentOutOfRangeException">
/// The value specified for a set operation is zero or less.
/// </exception>
public TimeSpan WaitTime {
get {
return _sessions.WaitTime;
}
set {
_sessions.WaitTime = value;
}
}
#endregion
#region Internal Methods
internal void Start ()
{
_sessions.Start ();
}
internal void StartSession (WebSocketContext context)
{
CreateSession ().Start (context, _sessions);
}
internal void Stop (ushort code, string reason)
{
_sessions.Stop (code, reason);
}
#endregion
#region Protected Methods
/// <summary>
/// Creates a new session for the service.
/// </summary>
/// <returns>
/// A <see cref="WebSocketBehavior"/> instance that represents
/// the new session.
/// </returns>
protected abstract WebSocketBehavior CreateSession ();
#endregion
}
}

View File

@ -1,93 +0,0 @@
#region License
/*
* WebSocketServiceHost`1.cs
*
* The MIT License
*
* Copyright (c) 2015-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp.Server
{
internal class WebSocketServiceHost<TBehavior> : WebSocketServiceHost
where TBehavior : WebSocketBehavior, new ()
{
#region Private Fields
private Func<TBehavior> _creator;
#endregion
#region Internal Constructors
internal WebSocketServiceHost (
string path, Action<TBehavior> initializer, Logger log
)
: base (path, log)
{
_creator = createSessionCreator (initializer);
}
#endregion
#region Public Properties
public override Type BehaviorType {
get {
return typeof (TBehavior);
}
}
#endregion
#region Private Methods
private static Func<TBehavior> createSessionCreator (
Action<TBehavior> initializer
)
{
if (initializer == null)
return () => new TBehavior ();
return () => {
var ret = new TBehavior ();
initializer (ret);
return ret;
};
}
#endregion
#region Protected Methods
protected override WebSocketBehavior CreateSession ()
{
return _creator ();
}
#endregion
}
}

View File

@ -1,609 +0,0 @@
#region License
/*
* WebSocketServiceManager.cs
*
* The MIT License
*
* Copyright (c) 2012-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using WebSocketSharp.Net;
namespace WebSocketSharp.Server
{
/// <summary>
/// Provides the management function for the WebSocket services.
/// </summary>
/// <remarks>
/// This class manages the WebSocket services provided by
/// the <see cref="WebSocketServer"/> or <see cref="HttpServer"/> class.
/// </remarks>
public class WebSocketServiceManager
{
#region Private Fields
private Dictionary<string, WebSocketServiceHost> _hosts;
private volatile bool _keepClean;
private Logger _log;
private volatile ServerState _state;
private object _sync;
private TimeSpan _waitTime;
#endregion
#region Internal Constructors
internal WebSocketServiceManager (Logger log)
{
_log = log;
_hosts = new Dictionary<string, WebSocketServiceHost> ();
_keepClean = true;
_state = ServerState.Ready;
_sync = ((ICollection) _hosts).SyncRoot;
_waitTime = TimeSpan.FromSeconds (1);
}
#endregion
#region Public Properties
/// <summary>
/// Gets the number of the WebSocket services.
/// </summary>
/// <value>
/// An <see cref="int"/> that represents the number of the services.
/// </value>
public int Count {
get {
lock (_sync)
return _hosts.Count;
}
}
/// <summary>
/// Gets the service host instances for the WebSocket services.
/// </summary>
/// <value>
/// <para>
/// An <c>IEnumerable&lt;WebSocketServiceHost&gt;</c> instance.
/// </para>
/// <para>
/// It provides an enumerator which supports the iteration over
/// the collection of the service host instances.
/// </para>
/// </value>
public IEnumerable<WebSocketServiceHost> Hosts {
get {
lock (_sync)
return _hosts.Values.ToList ();
}
}
/// <summary>
/// Gets the service host instance for a WebSocket service with
/// the specified path.
/// </summary>
/// <value>
/// <para>
/// A <see cref="WebSocketServiceHost"/> instance or
/// <see langword="null"/> if not found.
/// </para>
/// <para>
/// The service host instance provides the function to access
/// the information in the service.
/// </para>
/// </value>
/// <param name="path">
/// <para>
/// A <see cref="string"/> that specifies an absolute path to
/// the service to find.
/// </para>
/// <para>
/// / is trimmed from the end of the string if present.
/// </para>
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="path"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="path"/> is an empty string.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="path"/> is not an absolute path.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="path"/> includes either or both
/// query and fragment components.
/// </para>
/// </exception>
public WebSocketServiceHost this[string path] {
get {
if (path == null)
throw new ArgumentNullException ("path");
if (path.Length == 0)
throw new ArgumentException ("An empty string.", "path");
if (path[0] != '/') {
var msg = "It is not an absolute path.";
throw new ArgumentException (msg, "path");
}
if (path.IndexOfAny (new[] { '?', '#' }) > -1) {
var msg = "It includes either or both query and fragment components.";
throw new ArgumentException (msg, "path");
}
WebSocketServiceHost host;
InternalTryGetServiceHost (path, out host);
return host;
}
}
/// <summary>
/// Gets or sets a value indicating whether the inactive sessions in
/// the WebSocket services are cleaned up periodically.
/// </summary>
/// <remarks>
/// The set operation does nothing if the server has already started or
/// it is shutting down.
/// </remarks>
/// <value>
/// <para>
/// <c>true</c> if the inactive sessions are cleaned up every 60
/// seconds; otherwise, <c>false</c>.
/// </para>
/// <para>
/// The default value is <c>true</c>.
/// </para>
/// </value>
public bool KeepClean {
get {
return _keepClean;
}
set {
lock (_sync) {
if (!canSet ())
return;
foreach (var host in _hosts.Values)
host.KeepClean = value;
_keepClean = value;
}
}
}
/// <summary>
/// Gets the paths for the WebSocket services.
/// </summary>
/// <value>
/// <para>
/// An <c>IEnumerable&lt;string&gt;</c> instance.
/// </para>
/// <para>
/// It provides an enumerator which supports the iteration over
/// the collection of the paths.
/// </para>
/// </value>
public IEnumerable<string> Paths {
get {
lock (_sync)
return _hosts.Keys.ToList ();
}
}
/// <summary>
/// Gets or sets the time to wait for the response to the WebSocket Ping
/// or Close.
/// </summary>
/// <remarks>
/// The set operation does nothing if the server has already started or
/// it is shutting down.
/// </remarks>
/// <value>
/// <para>
/// A <see cref="TimeSpan"/> to wait for the response.
/// </para>
/// <para>
/// The default value is the same as 1 second.
/// </para>
/// </value>
/// <exception cref="ArgumentOutOfRangeException">
/// The value specified for a set operation is zero or less.
/// </exception>
public TimeSpan WaitTime {
get {
return _waitTime;
}
set {
if (value <= TimeSpan.Zero) {
var msg = "It is zero or less.";
throw new ArgumentOutOfRangeException ("value", msg);
}
lock (_sync) {
if (!canSet ())
return;
foreach (var host in _hosts.Values)
host.WaitTime = value;
_waitTime = value;
}
}
}
#endregion
#region Private Methods
private bool canSet ()
{
return _state == ServerState.Ready || _state == ServerState.Stop;
}
#endregion
#region Internal Methods
internal bool InternalTryGetServiceHost (
string path, out WebSocketServiceHost host
)
{
path = path.TrimSlashFromEnd ();
lock (_sync)
return _hosts.TryGetValue (path, out host);
}
internal void Start ()
{
lock (_sync) {
foreach (var host in _hosts.Values)
host.Start ();
_state = ServerState.Start;
}
}
internal void Stop (ushort code, string reason)
{
lock (_sync) {
_state = ServerState.ShuttingDown;
foreach (var host in _hosts.Values)
host.Stop (code, reason);
_state = ServerState.Stop;
}
}
#endregion
#region Public Methods
/// <summary>
/// Adds a WebSocket service with the specified behavior, path,
/// and delegate.
/// </summary>
/// <param name="path">
/// <para>
/// A <see cref="string"/> that specifies an absolute path to
/// the service to add.
/// </para>
/// <para>
/// / is trimmed from the end of the string if present.
/// </para>
/// </param>
/// <param name="initializer">
/// <para>
/// An <c>Action&lt;TBehavior&gt;</c> delegate or
/// <see langword="null"/> if not needed.
/// </para>
/// <para>
/// The delegate invokes the method called when initializing
/// a new session instance for the service.
/// </para>
/// </param>
/// <typeparam name="TBehavior">
/// <para>
/// The type of the behavior for the service.
/// </para>
/// <para>
/// It must inherit the <see cref="WebSocketBehavior"/> class.
/// </para>
/// <para>
/// And also, it must have a public parameterless constructor.
/// </para>
/// </typeparam>
/// <exception cref="ArgumentNullException">
/// <paramref name="path"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="path"/> is an empty string.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="path"/> is not an absolute path.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="path"/> includes either or both
/// query and fragment components.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="path"/> is already in use.
/// </para>
/// </exception>
public void AddService<TBehavior> (
string path, Action<TBehavior> initializer
)
where TBehavior : WebSocketBehavior, new ()
{
if (path == null)
throw new ArgumentNullException ("path");
if (path.Length == 0)
throw new ArgumentException ("An empty string.", "path");
if (path[0] != '/') {
var msg = "It is not an absolute path.";
throw new ArgumentException (msg, "path");
}
if (path.IndexOfAny (new[] { '?', '#' }) > -1) {
var msg = "It includes either or both query and fragment components.";
throw new ArgumentException (msg, "path");
}
path = path.TrimSlashFromEnd ();
lock (_sync) {
WebSocketServiceHost host;
if (_hosts.TryGetValue (path, out host)) {
var msg = "It is already in use.";
throw new ArgumentException (msg, "path");
}
host = new WebSocketServiceHost<TBehavior> (path, initializer, _log);
if (!_keepClean)
host.KeepClean = false;
if (_waitTime != host.WaitTime)
host.WaitTime = _waitTime;
if (_state == ServerState.Start)
host.Start ();
_hosts.Add (path, host);
}
}
/// <summary>
/// Removes all WebSocket services managed by the manager.
/// </summary>
/// <remarks>
/// A service is stopped with close status 1001 (going away)
/// if it has already started.
/// </remarks>
public void Clear ()
{
List<WebSocketServiceHost> hosts = null;
lock (_sync) {
hosts = _hosts.Values.ToList ();
_hosts.Clear ();
}
foreach (var host in hosts) {
if (host.State == ServerState.Start)
host.Stop (1001, String.Empty);
}
}
/// <summary>
/// Removes a WebSocket service with the specified path.
/// </summary>
/// <remarks>
/// The service is stopped with close status 1001 (going away)
/// if it has already started.
/// </remarks>
/// <returns>
/// <c>true</c> if the service is successfully found and removed;
/// otherwise, <c>false</c>.
/// </returns>
/// <param name="path">
/// <para>
/// A <see cref="string"/> that specifies an absolute path to
/// the service to remove.
/// </para>
/// <para>
/// / is trimmed from the end of the string if present.
/// </para>
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="path"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="path"/> is an empty string.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="path"/> is not an absolute path.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="path"/> includes either or both
/// query and fragment components.
/// </para>
/// </exception>
public bool RemoveService (string path)
{
if (path == null)
throw new ArgumentNullException ("path");
if (path.Length == 0)
throw new ArgumentException ("An empty string.", "path");
if (path[0] != '/') {
var msg = "It is not an absolute path.";
throw new ArgumentException (msg, "path");
}
if (path.IndexOfAny (new[] { '?', '#' }) > -1) {
var msg = "It includes either or both query and fragment components.";
throw new ArgumentException (msg, "path");
}
path = path.TrimSlashFromEnd ();
WebSocketServiceHost host;
lock (_sync) {
if (!_hosts.TryGetValue (path, out host))
return false;
_hosts.Remove (path);
}
if (host.State == ServerState.Start)
host.Stop (1001, String.Empty);
return true;
}
/// <summary>
/// Tries to get the service host instance for a WebSocket service with
/// the specified path.
/// </summary>
/// <returns>
/// <c>true</c> if the service is successfully found; otherwise,
/// <c>false</c>.
/// </returns>
/// <param name="path">
/// <para>
/// A <see cref="string"/> that specifies an absolute path to
/// the service to find.
/// </para>
/// <para>
/// / is trimmed from the end of the string if present.
/// </para>
/// </param>
/// <param name="host">
/// <para>
/// When this method returns, a <see cref="WebSocketServiceHost"/>
/// instance or <see langword="null"/> if not found.
/// </para>
/// <para>
/// The service host instance provides the function to access
/// the information in the service.
/// </para>
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="path"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentException">
/// <para>
/// <paramref name="path"/> is an empty string.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="path"/> is not an absolute path.
/// </para>
/// <para>
/// -or-
/// </para>
/// <para>
/// <paramref name="path"/> includes either or both
/// query and fragment components.
/// </para>
/// </exception>
public bool TryGetServiceHost (string path, out WebSocketServiceHost host)
{
if (path == null)
throw new ArgumentNullException ("path");
if (path.Length == 0)
throw new ArgumentException ("An empty string.", "path");
if (path[0] != '/') {
var msg = "It is not an absolute path.";
throw new ArgumentException (msg, "path");
}
if (path.IndexOfAny (new[] { '?', '#' }) > -1) {
var msg = "It includes either or both query and fragment components.";
throw new ArgumentException (msg, "path");
}
return InternalTryGetServiceHost (path, out host);
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,109 +0,0 @@
#region License
/*
* WebSocketException.cs
*
* The MIT License
*
* Copyright (c) 2012-2016 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp
{
/// <summary>
/// The exception that is thrown when a fatal error occurs in
/// the WebSocket communication.
/// </summary>
public class WebSocketException : Exception
{
#region Private Fields
private CloseStatusCode _code;
#endregion
#region Internal Constructors
internal WebSocketException ()
: this (CloseStatusCode.Abnormal, null, null)
{
}
internal WebSocketException (Exception innerException)
: this (CloseStatusCode.Abnormal, null, innerException)
{
}
internal WebSocketException (string message)
: this (CloseStatusCode.Abnormal, message, null)
{
}
internal WebSocketException (CloseStatusCode code)
: this (code, null, null)
{
}
internal WebSocketException (string message, Exception innerException)
: this (CloseStatusCode.Abnormal, message, innerException)
{
}
internal WebSocketException (CloseStatusCode code, Exception innerException)
: this (code, null, innerException)
{
}
internal WebSocketException (CloseStatusCode code, string message)
: this (code, message, null)
{
}
internal WebSocketException (
CloseStatusCode code, string message, Exception innerException
)
: base (message ?? code.GetMessage (), innerException)
{
_code = code;
}
#endregion
#region Public Properties
/// <summary>
/// Gets the status code indicating the cause of the exception.
/// </summary>
/// <value>
/// One of the <see cref="CloseStatusCode"/> enum values that represents
/// the status code indicating the cause of the exception.
/// </value>
public CloseStatusCode Code {
get {
return _code;
}
}
#endregion
}
}

View File

@ -1,929 +0,0 @@
#region License
/*
* WebSocketFrame.cs
*
* The MIT License
*
* Copyright (c) 2012-2021 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
#region Contributors
/*
* Contributors:
* - Chris Swiedler
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace WebSocketSharp
{
internal class WebSocketFrame : IEnumerable<byte>
{
#region Private Fields
private byte[] _extPayloadLength;
private Fin _fin;
private Mask _mask;
private byte[] _maskingKey;
private Opcode _opcode;
private PayloadData _payloadData;
private byte _payloadLength;
private Rsv _rsv1;
private Rsv _rsv2;
private Rsv _rsv3;
#endregion
#region Private Constructors
private WebSocketFrame ()
{
}
#endregion
#region Internal Constructors
internal WebSocketFrame (Opcode opcode, PayloadData payloadData, bool mask)
: this (Fin.Final, opcode, payloadData, false, mask)
{
}
internal WebSocketFrame (
Fin fin, Opcode opcode, byte[] data, bool compressed, bool mask
)
: this (fin, opcode, new PayloadData (data), compressed, mask)
{
}
internal WebSocketFrame (
Fin fin,
Opcode opcode,
PayloadData payloadData,
bool compressed,
bool mask
)
{
_fin = fin;
_opcode = opcode;
_rsv1 = opcode.IsData () && compressed ? Rsv.On : Rsv.Off;
_rsv2 = Rsv.Off;
_rsv3 = Rsv.Off;
var len = payloadData.Length;
if (len < 126) {
_payloadLength = (byte) len;
_extPayloadLength = WebSocket.EmptyBytes;
}
else if (len < 0x010000) {
_payloadLength = (byte) 126;
_extPayloadLength = ((ushort) len).InternalToByteArray (ByteOrder.Big);
}
else {
_payloadLength = (byte) 127;
_extPayloadLength = len.InternalToByteArray (ByteOrder.Big);
}
if (mask) {
_mask = Mask.On;
_maskingKey = createMaskingKey ();
payloadData.Mask (_maskingKey);
}
else {
_mask = Mask.Off;
_maskingKey = WebSocket.EmptyBytes;
}
_payloadData = payloadData;
}
#endregion
#region Internal Properties
internal ulong ExactPayloadLength {
get {
return _payloadLength < 126
? _payloadLength
: _payloadLength == 126
? _extPayloadLength.ToUInt16 (ByteOrder.Big)
: _extPayloadLength.ToUInt64 (ByteOrder.Big);
}
}
internal int ExtendedPayloadLengthWidth {
get {
return _payloadLength < 126
? 0
: _payloadLength == 126
? 2
: 8;
}
}
#endregion
#region Public Properties
public byte[] ExtendedPayloadLength {
get {
return _extPayloadLength;
}
}
public Fin Fin {
get {
return _fin;
}
}
public bool IsBinary {
get {
return _opcode == Opcode.Binary;
}
}
public bool IsClose {
get {
return _opcode == Opcode.Close;
}
}
public bool IsCompressed {
get {
return _rsv1 == Rsv.On;
}
}
public bool IsContinuation {
get {
return _opcode == Opcode.Cont;
}
}
public bool IsControl {
get {
return _opcode >= Opcode.Close;
}
}
public bool IsData {
get {
return _opcode == Opcode.Text || _opcode == Opcode.Binary;
}
}
public bool IsFinal {
get {
return _fin == Fin.Final;
}
}
public bool IsFragment {
get {
return _fin == Fin.More || _opcode == Opcode.Cont;
}
}
public bool IsMasked {
get {
return _mask == Mask.On;
}
}
public bool IsPing {
get {
return _opcode == Opcode.Ping;
}
}
public bool IsPong {
get {
return _opcode == Opcode.Pong;
}
}
public bool IsText {
get {
return _opcode == Opcode.Text;
}
}
public ulong Length {
get {
return 2
+ (ulong) (_extPayloadLength.Length + _maskingKey.Length)
+ _payloadData.Length;
}
}
public Mask Mask {
get {
return _mask;
}
}
public byte[] MaskingKey {
get {
return _maskingKey;
}
}
public Opcode Opcode {
get {
return _opcode;
}
}
public PayloadData PayloadData {
get {
return _payloadData;
}
}
public byte PayloadLength {
get {
return _payloadLength;
}
}
public Rsv Rsv1 {
get {
return _rsv1;
}
}
public Rsv Rsv2 {
get {
return _rsv2;
}
}
public Rsv Rsv3 {
get {
return _rsv3;
}
}
#endregion
#region Private Methods
private static byte[] createMaskingKey ()
{
var key = new byte[4];
WebSocket.RandomNumber.GetBytes (key);
return key;
}
private static string dump (WebSocketFrame frame)
{
var len = frame.Length;
var cnt = (long) (len / 4);
var rem = (int) (len % 4);
int cntDigit;
string cntFmt;
if (cnt < 10000) {
cntDigit = 4;
cntFmt = "{0,4}";
}
else if (cnt < 0x010000) {
cntDigit = 4;
cntFmt = "{0,4:X}";
}
else if (cnt < 0x0100000000) {
cntDigit = 8;
cntFmt = "{0,8:X}";
}
else {
cntDigit = 16;
cntFmt = "{0,16:X}";
}
var spFmt = String.Format ("{{0,{0}}}", cntDigit);
var headerFmt = String.Format (
@"
{0} 01234567 89ABCDEF 01234567 89ABCDEF
{0}+--------+--------+--------+--------+\n",
spFmt
);
var lineFmt = String.Format (
"{0}|{{1,8}} {{2,8}} {{3,8}} {{4,8}}|\n", cntFmt
);
var footerFmt = String.Format (
"{0}+--------+--------+--------+--------+", spFmt
);
var buff = new StringBuilder (64);
Func<Action<string, string, string, string>> linePrinter =
() => {
long lineCnt = 0;
return (arg1, arg2, arg3, arg4) => {
buff.AppendFormat (
lineFmt, ++lineCnt, arg1, arg2, arg3, arg4
);
};
};
var printLine = linePrinter ();
var bytes = frame.ToArray ();
buff.AppendFormat (headerFmt, String.Empty);
for (long i = 0; i <= cnt; i++) {
var j = i * 4;
if (i < cnt) {
printLine (
Convert.ToString (bytes[j], 2).PadLeft (8, '0'),
Convert.ToString (bytes[j + 1], 2).PadLeft (8, '0'),
Convert.ToString (bytes[j + 2], 2).PadLeft (8, '0'),
Convert.ToString (bytes[j + 3], 2).PadLeft (8, '0')
);
continue;
}
if (rem > 0) {
printLine (
Convert.ToString (bytes[j], 2).PadLeft (8, '0'),
rem >= 2
? Convert.ToString (bytes[j + 1], 2).PadLeft (8, '0')
: String.Empty,
rem == 3
? Convert.ToString (bytes[j + 2], 2).PadLeft (8, '0')
: String.Empty,
String.Empty
);
}
}
buff.AppendFormat (footerFmt, String.Empty);
return buff.ToString ();
}
private static string print (WebSocketFrame frame)
{
// Payload Length
var payloadLen = frame._payloadLength;
// Extended Payload Length
var extPayloadLen = payloadLen > 125
? frame.ExactPayloadLength.ToString ()
: String.Empty;
// Masking Key
var maskingKey = BitConverter.ToString (frame._maskingKey);
// Payload Data
var payload = payloadLen == 0
? String.Empty
: payloadLen > 125
? "---"
: !frame.IsText
|| frame.IsFragment
|| frame.IsMasked
|| frame.IsCompressed
? frame._payloadData.ToString ()
: utf8Decode (frame._payloadData.ApplicationData);
var fmt = @"
FIN: {0}
RSV1: {1}
RSV2: {2}
RSV3: {3}
Opcode: {4}
MASK: {5}
Payload Length: {6}
Extended Payload Length: {7}
Masking Key: {8}
Payload Data: {9}";
return String.Format (
fmt,
frame._fin,
frame._rsv1,
frame._rsv2,
frame._rsv3,
frame._opcode,
frame._mask,
payloadLen,
extPayloadLen,
maskingKey,
payload
);
}
private static WebSocketFrame processHeader (byte[] header)
{
if (header.Length != 2) {
var msg = "The header part of a frame could not be read.";
throw new WebSocketException (msg);
}
// FIN
var fin = (header[0] & 0x80) == 0x80 ? Fin.Final : Fin.More;
// RSV1
var rsv1 = (header[0] & 0x40) == 0x40 ? Rsv.On : Rsv.Off;
// RSV2
var rsv2 = (header[0] & 0x20) == 0x20 ? Rsv.On : Rsv.Off;
// RSV3
var rsv3 = (header[0] & 0x10) == 0x10 ? Rsv.On : Rsv.Off;
// Opcode
var opcode = (byte) (header[0] & 0x0f);
// MASK
var mask = (header[1] & 0x80) == 0x80 ? Mask.On : Mask.Off;
// Payload Length
var payloadLen = (byte) (header[1] & 0x7f);
if (!opcode.IsSupported ()) {
var msg = "A frame has an unsupported opcode.";
throw new WebSocketException (CloseStatusCode.ProtocolError, msg);
}
if (!opcode.IsData () && rsv1 == Rsv.On) {
var msg = "A non data frame is compressed.";
throw new WebSocketException (CloseStatusCode.ProtocolError, msg);
}
if (opcode.IsControl ()) {
if (fin == Fin.More) {
var msg = "A control frame is fragmented.";
throw new WebSocketException (CloseStatusCode.ProtocolError, msg);
}
if (payloadLen > 125) {
var msg = "A control frame has too long payload length.";
throw new WebSocketException (CloseStatusCode.ProtocolError, msg);
}
}
var frame = new WebSocketFrame ();
frame._fin = fin;
frame._rsv1 = rsv1;
frame._rsv2 = rsv2;
frame._rsv3 = rsv3;
frame._opcode = (Opcode) opcode;
frame._mask = mask;
frame._payloadLength = payloadLen;
return frame;
}
private static WebSocketFrame readExtendedPayloadLength (
Stream stream, WebSocketFrame frame
)
{
var len = frame.ExtendedPayloadLengthWidth;
if (len == 0) {
frame._extPayloadLength = WebSocket.EmptyBytes;
return frame;
}
var bytes = stream.ReadBytes (len);
if (bytes.Length != len) {
var msg = "The extended payload length of a frame could not be read.";
throw new WebSocketException (msg);
}
frame._extPayloadLength = bytes;
return frame;
}
private static void readExtendedPayloadLengthAsync (
Stream stream,
WebSocketFrame frame,
Action<WebSocketFrame> completed,
Action<Exception> error
)
{
var len = frame.ExtendedPayloadLengthWidth;
if (len == 0) {
frame._extPayloadLength = WebSocket.EmptyBytes;
completed (frame);
return;
}
stream.ReadBytesAsync (
len,
bytes => {
if (bytes.Length != len) {
var msg = "The extended payload length of a frame could not be read.";
throw new WebSocketException (msg);
}
frame._extPayloadLength = bytes;
completed (frame);
},
error
);
}
private static WebSocketFrame readHeader (Stream stream)
{
var bytes = stream.ReadBytes (2);
return processHeader (bytes);
}
private static void readHeaderAsync (
Stream stream, Action<WebSocketFrame> completed, Action<Exception> error
)
{
stream.ReadBytesAsync (
2,
bytes => {
var frame = processHeader (bytes);
completed (frame);
},
error
);
}
private static WebSocketFrame readMaskingKey (
Stream stream, WebSocketFrame frame
)
{
if (!frame.IsMasked) {
frame._maskingKey = WebSocket.EmptyBytes;
return frame;
}
var len = 4;
var bytes = stream.ReadBytes (len);
if (bytes.Length != len) {
var msg = "The masking key of a frame could not be read.";
throw new WebSocketException (msg);
}
frame._maskingKey = bytes;
return frame;
}
private static void readMaskingKeyAsync (
Stream stream,
WebSocketFrame frame,
Action<WebSocketFrame> completed,
Action<Exception> error
)
{
if (!frame.IsMasked) {
frame._maskingKey = WebSocket.EmptyBytes;
completed (frame);
return;
}
var len = 4;
stream.ReadBytesAsync (
len,
bytes => {
if (bytes.Length != len) {
var msg = "The masking key of a frame could not be read.";
throw new WebSocketException (msg);
}
frame._maskingKey = bytes;
completed (frame);
},
error
);
}
private static WebSocketFrame readPayloadData (
Stream stream, WebSocketFrame frame
)
{
var exactLen = frame.ExactPayloadLength;
if (exactLen > PayloadData.MaxLength) {
var msg = "A frame has too long payload length.";
throw new WebSocketException (CloseStatusCode.TooBig, msg);
}
if (exactLen == 0) {
frame._payloadData = PayloadData.Empty;
return frame;
}
var len = (long) exactLen;
var bytes = frame._payloadLength < 127
? stream.ReadBytes ((int) exactLen)
: stream.ReadBytes (len, 1024);
if (bytes.LongLength != len) {
var msg = "The payload data of a frame could not be read.";
throw new WebSocketException (msg);
}
frame._payloadData = new PayloadData (bytes, len);
return frame;
}
private static void readPayloadDataAsync (
Stream stream,
WebSocketFrame frame,
Action<WebSocketFrame> completed,
Action<Exception> error
)
{
var exactLen = frame.ExactPayloadLength;
if (exactLen > PayloadData.MaxLength) {
var msg = "A frame has too long payload length.";
throw new WebSocketException (CloseStatusCode.TooBig, msg);
}
if (exactLen == 0) {
frame._payloadData = PayloadData.Empty;
completed (frame);
return;
}
var len = (long) exactLen;
Action<byte[]> comp =
bytes => {
if (bytes.LongLength != len) {
var msg = "The payload data of a frame could not be read.";
throw new WebSocketException (msg);
}
frame._payloadData = new PayloadData (bytes, len);
completed (frame);
};
if (frame._payloadLength < 127) {
stream.ReadBytesAsync ((int) exactLen, comp, error);
return;
}
stream.ReadBytesAsync (len, 1024, comp, error);
}
private static string utf8Decode (byte[] bytes)
{
try {
return Encoding.UTF8.GetString (bytes);
}
catch {
return null;
}
}
#endregion
#region Internal Methods
internal static WebSocketFrame CreateCloseFrame (
PayloadData payloadData, bool mask
)
{
return new WebSocketFrame (
Fin.Final, Opcode.Close, payloadData, false, mask
);
}
internal static WebSocketFrame CreatePingFrame (bool mask)
{
return new WebSocketFrame (
Fin.Final, Opcode.Ping, PayloadData.Empty, false, mask
);
}
internal static WebSocketFrame CreatePingFrame (byte[] data, bool mask)
{
return new WebSocketFrame (
Fin.Final, Opcode.Ping, new PayloadData (data), false, mask
);
}
internal static WebSocketFrame CreatePongFrame (
PayloadData payloadData, bool mask
)
{
return new WebSocketFrame (
Fin.Final, Opcode.Pong, payloadData, false, mask
);
}
internal static WebSocketFrame ReadFrame (Stream stream, bool unmask)
{
var frame = readHeader (stream);
readExtendedPayloadLength (stream, frame);
readMaskingKey (stream, frame);
readPayloadData (stream, frame);
if (unmask)
frame.Unmask ();
return frame;
}
internal static void ReadFrameAsync (
Stream stream,
bool unmask,
Action<WebSocketFrame> completed,
Action<Exception> error
)
{
readHeaderAsync (
stream,
frame =>
readExtendedPayloadLengthAsync (
stream,
frame,
frame1 =>
readMaskingKeyAsync (
stream,
frame1,
frame2 =>
readPayloadDataAsync (
stream,
frame2,
frame3 => {
if (unmask)
frame3.Unmask ();
completed (frame3);
},
error
),
error
),
error
),
error
);
}
internal void Unmask ()
{
if (_mask == Mask.Off)
return;
_payloadData.Mask (_maskingKey);
_maskingKey = WebSocket.EmptyBytes;
_mask = Mask.Off;
}
#endregion
#region Public Methods
public IEnumerator<byte> GetEnumerator ()
{
foreach (var b in ToArray ())
yield return b;
}
public void Print (bool dumped)
{
var val = dumped ? dump (this) : print (this);
Console.WriteLine (val);
}
public string PrintToString (bool dumped)
{
return dumped ? dump (this) : print (this);
}
public byte[] ToArray ()
{
using (var buff = new MemoryStream ()) {
var header = (int) _fin;
header = (header << 1) + (int) _rsv1;
header = (header << 1) + (int) _rsv2;
header = (header << 1) + (int) _rsv3;
header = (header << 4) + (int) _opcode;
header = (header << 1) + (int) _mask;
header = (header << 7) + (int) _payloadLength;
var headerAsUshort = (ushort) header;
var headerAsBytes = headerAsUshort.InternalToByteArray (ByteOrder.Big);
buff.Write (headerAsBytes, 0, 2);
if (_payloadLength > 125) {
var cnt = _payloadLength == 126 ? 2 : 8;
buff.Write (_extPayloadLength, 0, cnt);
}
if (_mask == Mask.On)
buff.Write (_maskingKey, 0, 4);
if (_payloadLength > 0) {
var bytes = _payloadData.ToArray ();
if (_payloadLength < 127)
buff.Write (bytes, 0, bytes.Length);
else
buff.WriteBytes (bytes, 1024);
}
buff.Close ();
return buff.ToArray ();
}
}
public override string ToString ()
{
var val = ToArray ();
return BitConverter.ToString (val);
}
#endregion
#region Explicit Interface Implementations
IEnumerator IEnumerable.GetEnumerator ()
{
return GetEnumerator ();
}
#endregion
}
}

View File

@ -1,65 +0,0 @@
#region License
/*
* WebSocketState.cs
*
* The MIT License
*
* Copyright (c) 2010-2016 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp
{
/// <summary>
/// Indicates the state of a WebSocket connection.
/// </summary>
/// <remarks>
/// The values of this enumeration are defined in
/// <see href="http://www.w3.org/TR/websockets/#dom-websocket-readystate">
/// The WebSocket API</see>.
/// </remarks>
public enum WebSocketState : ushort
{
/// <summary>
/// Equivalent to numeric value 0. Indicates that the connection has not
/// yet been established.
/// </summary>
Connecting = 0,
/// <summary>
/// Equivalent to numeric value 1. Indicates that the connection has
/// been established, and the communication is possible.
/// </summary>
Open = 1,
/// <summary>
/// Equivalent to numeric value 2. Indicates that the connection is
/// going through the closing handshake, or the close method has
/// been invoked.
/// </summary>
Closing = 2,
/// <summary>
/// Equivalent to numeric value 3. Indicates that the connection has
/// been closed or could not be established.
/// </summary>
Closed = 3
}
}

View File

@ -1,11 +1,11 @@
#region License
/*
* ServerState.cs
#region MIT License
/**
* WsState.cs
*
* The MIT License
*
* Copyright (c) 2013-2014 sta.blockhead
*
* Copyright (c) 2010 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
@ -15,7 +15,7 @@
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -28,13 +28,13 @@
using System;
namespace WebSocketSharp.Server
namespace WebSocketSharp
{
internal enum ServerState
public enum WsState
{
Ready,
Start,
ShuttingDown,
Stop
CONNECTING,
OPEN,
CLOSING,
CLOSED
}
}

View File

@ -0,0 +1,90 @@
#region MIT License
/**
* WsStream.cs
*
* The MIT License
*
* Copyright (c) 2010 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Security;
using System.Net.Sockets;
using System.Reflection;
namespace WebSocketSharp
{
public class WsStream<T> : IWsStream
where T : Stream
{
private T innerStream;
public WsStream(T innerStream)
{
Type streamType = typeof(T);
if (streamType != typeof(NetworkStream) &&
streamType != typeof(SslStream))
{
throw new NotSupportedException("Unsupported Stream type: " + streamType.ToString());
}
if (innerStream == null)
{
throw new ArgumentNullException("innerStream");
}
this.innerStream = innerStream;
}
public void Close()
{
innerStream.Close();
}
public void Dispose()
{
innerStream.Dispose();
}
public int Read(byte[] buffer, int offset, int size)
{
return innerStream.Read(buffer, offset, size);
}
public int ReadByte()
{
return innerStream.ReadByte();
}
public void Write(byte[] buffer, int offset, int count)
{
innerStream.Write(buffer, offset, count);
}
public void WriteByte(byte value)
{
innerStream.WriteByte(value);
}
}
}

Some files were not shown because too many files have changed in this diff Show More