Merge branch 'feature/files' of github.com:ONLYOFFICE/AppServer into feature/files
This commit is contained in:
commit
20cefbf1e4
BIN
.nuget/packages/WebSocketSharp.1.0.3-rc11.nupkg
Normal file
BIN
.nuget/packages/WebSocketSharp.1.0.3-rc11.nupkg
Normal file
Binary file not shown.
@ -60,6 +60,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Data.Backup", "common\s
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Files.Core", "products\ASC.Files\Core\ASC.Files.Core.csproj", "{F0A39728-940D-4DBE-A37A-05D4EB57F342}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Socket.IO.Svc", "common\services\ASC.Socket.IO.Svc\ASC.Socket.IO.Svc.csproj", "{2DADEAD3-0FE9-4199-9817-41A32E6BF450}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -174,6 +176,10 @@ Global
|
||||
{F0A39728-940D-4DBE-A37A-05D4EB57F342}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F0A39728-940D-4DBE-A37A-05D4EB57F342}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F0A39728-940D-4DBE-A37A-05D4EB57F342}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2DADEAD3-0FE9-4199-9817-41A32E6BF450}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2DADEAD3-0FE9-4199-9817-41A32E6BF450}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2DADEAD3-0FE9-4199-9817-41A32E6BF450}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2DADEAD3-0FE9-4199-9817-41A32E6BF450}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -27,6 +27,9 @@ call build\scripts\urlshortener.sh
|
||||
echo "ASC.Thumbnails"
|
||||
call build\scripts\thumbnails.sh
|
||||
|
||||
echo "ASC.Socket.IO"
|
||||
call build\scripts\socket.sh
|
||||
|
||||
echo "ASC.Web.sln"
|
||||
call dotnet build ASC.Web.sln /fl1 /flp1:LogFile=build/ASC.Web.log;Verbosity=Normal
|
||||
|
||||
|
@ -140,43 +140,45 @@ RUN cd /app/onlyoffice/src/ && \
|
||||
cp -f config/nginx/onlyoffice*.conf /etc/nginx/conf.d/ && \
|
||||
mkdir -p /etc/nginx/includes/ && cp -f config/nginx/includes/onlyoffice*.conf /etc/nginx/includes/ && \
|
||||
sed -e 's/#//' -i /etc/nginx/conf.d/onlyoffice.conf && \
|
||||
dotnet restore ASC.Web.sln --configfile .nuget/NuGet.Config && \
|
||||
dotnet build -r linux-x64 ASC.Web.sln && \
|
||||
cd products/ASC.People/Server && \
|
||||
dotnet -d publish -o /var/www/products/ASC.People/server && \
|
||||
dotnet -d publish --no-build --self-contained -r linux-x64 -o /var/www/products/ASC.People/server && \
|
||||
cd ../../../ && \
|
||||
cd products/ASC.Files/Server && \
|
||||
dotnet -d publish -o /var/www/products/ASC.Files/server && \
|
||||
dotnet -d publish --no-build --self-contained -r linux-x64 -o /var/www/products/ASC.Files/server && \
|
||||
cp -avrf DocStore /var/www/products/ASC.Files/server/ && \
|
||||
cd ../../../ && \
|
||||
cd products/ASC.Files/Service && \
|
||||
dotnet -d publish -o /var/www/products/ASC.Files/service && \
|
||||
dotnet -d publish --no-build --self-contained -r linux-x64 -o /var/www/products/ASC.Files/service && \
|
||||
cd ../../../ && \
|
||||
cd web/ASC.Web.Api && \
|
||||
dotnet -d publish -o /var/www/studio/api && \
|
||||
dotnet -d publish --no-build --self-contained -r linux-x64 -o /var/www/studio/api && \
|
||||
cd ../../ && \
|
||||
cd web/ASC.Web.Studio && \
|
||||
dotnet -d publish -o /var/www/studio/server && \
|
||||
dotnet -d publish --no-build --self-contained -r linux-x64 -o /var/www/studio/server && \
|
||||
cd ../../ && \
|
||||
cd common/services/ASC.Data.Backup && \
|
||||
dotnet -d publish -o /var/www/services/backup && \
|
||||
dotnet -d publish --no-build --self-contained -r linux-x64 -o /var/www/services/backup && \
|
||||
cd ../../../ && \
|
||||
cd common/services/ASC.Notify && \
|
||||
dotnet -d publish -o /var/www/services/notify && \
|
||||
dotnet -d publish --no-build --self-contained -r linux-x64 -o /var/www/services/notify && \
|
||||
cd ../../../ && \
|
||||
cd common/services/ASC.ApiSystem && \
|
||||
dotnet -d publish -o /var/www/services/apisystem && \
|
||||
dotnet -d publish --no-build --self-contained -r linux-x64 -o /var/www/services/apisystem && \
|
||||
cd ../../../ && \
|
||||
cd common/services/ASC.Thumbnails.Svc && \
|
||||
dotnet -d publish -o /services/thumb/service && \
|
||||
dotnet -d publish --no-build --self-contained -r linux-x64 -o /services/thumb/service && \
|
||||
cd ../../../ && \
|
||||
yarn install --cwd common/ASC.Thumbnails --frozen-lockfile && \
|
||||
mkdir -p /var/www/services/thumb/client && cp -Rf common/ASC.Thumbnails/* /var/www/services/thumb/client && \
|
||||
cd common/services/ASC.UrlShortener.Svc && \
|
||||
dotnet -d publish -o /services/urlshortener/service && \
|
||||
dotnet -d publish --no-build --self-contained -r linux-x64 -o /services/urlshortener/service && \
|
||||
cd ../../../ && \
|
||||
yarn install --cwd common/ASC.UrlShortener --frozen-lockfile && \
|
||||
mkdir -p /var/www/services/urlshortener/client && cp -Rf common/ASC.UrlShortener/* /var/www/services/urlshortener/client && \
|
||||
cd common/services/ASC.Studio.Notify && \
|
||||
dotnet -d publish -o /var/www/services/studio.notify
|
||||
dotnet -d publish --no-build --self-contained -r linux-x64 -o /var/www/services/studio.notify
|
||||
|
||||
COPY config/mysql/conf.d/mysql.cnf /etc/mysql/conf.d/mysql.cnf
|
||||
COPY config/supervisor/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
|
2
build/run/Socket.IO.bat
Normal file
2
build/run/Socket.IO.bat
Normal file
@ -0,0 +1,2 @@
|
||||
echo "RUN ASC.Socket.IO.Svc"
|
||||
call dotnet run --project ..\..\common\services\ASC.Socket.IO.Svc\ASC.Socket.IO.Svc.csproj --no-build --$STORAGE_ROOT=..\..\Data --log__dir=..\..\Logs --log__name=socket
|
@ -1,2 +1,2 @@
|
||||
echo "RUN ASC.Web.Studio"
|
||||
echo "RUN ASC.Thumbnails.Svc"
|
||||
call dotnet run --project ..\..\common\services\ASC.Thumbnails.Svc\ASC.Thumbnails.Svc.csproj --no-build --$STORAGE_ROOT=..\..\Data --log__dir=..\..\Logs --log__name=thumbnails
|
1
build/scripts/socket.sh
Normal file
1
build/scripts/socket.sh
Normal file
@ -0,0 +1 @@
|
||||
yarn install --cwd common/ASC.Socket.IO --frozen-lockfile
|
@ -144,7 +144,7 @@ namespace ASC.Core.Common.Configuration
|
||||
IConfiguration configuration,
|
||||
ICacheNotify<ConsumerCacheItem> cache,
|
||||
ConsumerFactory consumerFactory,
|
||||
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional)
|
||||
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
|
||||
: this(tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory)
|
||||
{
|
||||
Name = name;
|
||||
@ -409,7 +409,7 @@ namespace ASC.Core.Common.Configuration
|
||||
}
|
||||
|
||||
return new T();
|
||||
}
|
||||
}
|
||||
|
||||
public T Get<T>() where T : Consumer, new()
|
||||
{
|
||||
|
@ -397,7 +397,7 @@ namespace ASC.Core.Notify.Signalr
|
||||
{
|
||||
if (services.TryAddScoped<SignalrServiceClient>())
|
||||
{
|
||||
services.TryAddScoped<IConfigureOptions<SignalrServiceClient>, ConfigureSignalrServiceClient>();
|
||||
services.TryAddScoped<IConfigureNamedOptions<SignalrServiceClient>, ConfigureSignalrServiceClient>();
|
||||
|
||||
return services
|
||||
.AddTenantManagerService()
|
||||
|
@ -33,9 +33,7 @@ using System.Xml.XPath;
|
||||
|
||||
using ASC.Common.Caching;
|
||||
using ASC.Core;
|
||||
using ASC.Core.Common;
|
||||
using ASC.Core.Common.Configuration;
|
||||
using ASC.Core.Tenants;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
@ -72,7 +70,7 @@ namespace ASC.FederatedLogin.LoginProviders
|
||||
{
|
||||
}
|
||||
|
||||
public bool ValidateKeys(AuthContext authContext, TenantUtil tenantUtil, SecurityContext securityContext, TenantManager tenantManager, BaseCommonLinkUtility baseCommonLinkUtility)
|
||||
public bool ValidateKeys()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -23,15 +23,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using ASC.Core;
|
||||
using ASC.Core.Common;
|
||||
using ASC.Core.Tenants;
|
||||
|
||||
namespace ASC.FederatedLogin.LoginProviders
|
||||
{
|
||||
public interface IValidateKeysProvider
|
||||
{
|
||||
bool ValidateKeys(AuthContext authContext, TenantUtil tenantUtil, SecurityContext securityContext, TenantManager tenantManager, BaseCommonLinkUtility baseCommonLinkUtility);
|
||||
bool ValidateKeys();
|
||||
}
|
||||
}
|
@ -16,9 +16,10 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="3.1.7" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ASC.Common\ASC.Common.csproj" />
|
||||
<ProjectReference Include="..\ASC.Core.Common\ASC.Core.Common.csproj" />
|
||||
|
@ -5,6 +5,10 @@ VisualStudioVersion = 16.0.30406.217
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Resource.Manager", "ASC.Resource.Manager.csproj", "{D93E320F-84CC-4BBF-ADBA-9080EDCB3977}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Common", "..\ASC.Common\ASC.Common.csproj", "{0EAD2A16-007A-4436-86AA-FE8765595251}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Core.Common", "..\ASC.Core.Common\ASC.Core.Common.csproj", "{A51D0454-4AFA-46DE-89D4-B03D37E1816C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -15,6 +19,14 @@ Global
|
||||
{D93E320F-84CC-4BBF-ADBA-9080EDCB3977}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D93E320F-84CC-4BBF-ADBA-9080EDCB3977}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D93E320F-84CC-4BBF-ADBA-9080EDCB3977}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0EAD2A16-007A-4436-86AA-FE8765595251}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0EAD2A16-007A-4436-86AA-FE8765595251}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0EAD2A16-007A-4436-86AA-FE8765595251}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0EAD2A16-007A-4436-86AA-FE8765595251}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A51D0454-4AFA-46DE-89D4-B03D37E1816C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A51D0454-4AFA-46DE-89D4-B03D37E1816C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A51D0454-4AFA-46DE-89D4-B03D37E1816C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A51D0454-4AFA-46DE-89D4-B03D37E1816C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
145
common/ASC.Socket.IO/ASC.Socket.IO.njsproj
Normal file
145
common/ASC.Socket.IO/ASC.Socket.IO.njsproj
Normal file
@ -0,0 +1,145 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">11.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<Name>ASC.Socket.IO</Name>
|
||||
<RootNamespace>ASC.Socket.IO</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>325ae82f-b416-4f29-94df-c5b18fc4926d</ProjectGuid>
|
||||
<ProjectHome>.</ProjectHome>
|
||||
<StartupFile>app.js</StartupFile>
|
||||
<SearchPath>
|
||||
</SearchPath>
|
||||
<WorkingDirectory>.</WorkingDirectory>
|
||||
<OutputPath>.</OutputPath>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<ProjectTypeGuids>{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}</ProjectTypeGuids>
|
||||
<ProjectView>ShowAllFiles</ProjectView>
|
||||
<NodejsPort>3000</NodejsPort>
|
||||
<StartWebBrowser>true</StartWebBrowser>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="app.js" />
|
||||
<Compile Include="app\apiRequestManager.js" />
|
||||
<Compile Include="app\controllers\chat.js" />
|
||||
<Compile Include="app\controllers\counters.js" />
|
||||
<Compile Include="app\controllers\files.js" />
|
||||
<Compile Include="app\controllers\index.js" />
|
||||
<Compile Include="app\controllers\mail.js" />
|
||||
<Compile Include="app\controllers\voip.js" />
|
||||
<Compile Include="app\hubs\chat.js" />
|
||||
<Compile Include="app\hubs\counters.js" />
|
||||
<Compile Include="app\hubs\files.js" />
|
||||
<Compile Include="app\hubs\voip.js" />
|
||||
<Compile Include="app\hubs\voipListPhones.js" />
|
||||
<Compile Include="app\hubs\voipPhone.js" />
|
||||
<Compile Include="app\log.js" />
|
||||
<Compile Include="app\middleware\auth.js" />
|
||||
<Compile Include="app\middleware\authService.js" />
|
||||
<Compile Include="app\portalManager.js" />
|
||||
<Compile Include="config\index.js" />
|
||||
<Compile Include="bin\www" />
|
||||
<Content Include="config\config.json" />
|
||||
<Content Include="package.json" />
|
||||
<Content Include="README.md" />
|
||||
<Content Include="typings.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="app\middleware\" />
|
||||
<Folder Include="app\hubs\" />
|
||||
<Folder Include="app\controllers\" />
|
||||
<Folder Include="bin\" />
|
||||
<Folder Include="app\" />
|
||||
<Folder Include="config\" />
|
||||
<Folder Include="public\" />
|
||||
<Folder Include="public\images\" />
|
||||
<Folder Include="public\javascripts\" />
|
||||
<Folder Include="public\stylesheets\" />
|
||||
<Folder Include="typings\" />
|
||||
<Folder Include="typings\globals\" />
|
||||
<Folder Include="typings\globals\body-parser\" />
|
||||
<Folder Include="typings\globals\cookie-parser\" />
|
||||
<Folder Include="typings\globals\debug\" />
|
||||
<Folder Include="typings\globals\express-serve-static-core\" />
|
||||
<Folder Include="typings\globals\express\" />
|
||||
<Folder Include="typings\globals\jade\" />
|
||||
<Folder Include="typings\globals\mime\" />
|
||||
<Folder Include="typings\globals\moment\" />
|
||||
<Folder Include="typings\globals\morgan\" />
|
||||
<Folder Include="typings\globals\node\" />
|
||||
<Folder Include="typings\globals\serve-favicon\" />
|
||||
<Folder Include="typings\globals\serve-static\" />
|
||||
<Folder Include="typings\globals\socket.io\" />
|
||||
<Folder Include="typings\globals\stylus\" />
|
||||
<Folder Include="views\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<TypeScriptCompile Include="typings\globals\body-parser\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\cookie-parser\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\debug\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\express-serve-static-core\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\express\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\jade\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\mime\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\moment\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\morgan\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\node\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\serve-favicon\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\serve-static\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\socket.io\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\stylus\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\index.d.ts" />
|
||||
</ItemGroup>
|
||||
<!-- Do not delete the following Import Project. While this appears to do nothing it is a marker for setting TypeScript properties before our import that depends on them. -->
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets" Condition="False" />
|
||||
<Import Project="$(VSToolsPath)\Node.js Tools\Microsoft.NodejsTools.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<UseIIS>False</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>0</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:48022/</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>True</UseCustomServer>
|
||||
<CustomServerUrl>http://localhost:1337</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}" User="">
|
||||
<WebProjectProperties>
|
||||
<StartPageUrl>
|
||||
</StartPageUrl>
|
||||
<StartAction>CurrentPage</StartAction>
|
||||
<AspNetDebugging>True</AspNetDebugging>
|
||||
<SilverlightDebugging>False</SilverlightDebugging>
|
||||
<NativeDebugging>False</NativeDebugging>
|
||||
<SQLDebugging>False</SQLDebugging>
|
||||
<ExternalProgram>
|
||||
</ExternalProgram>
|
||||
<StartExternalURL>
|
||||
</StartExternalURL>
|
||||
<StartCmdLineArguments>
|
||||
</StartCmdLineArguments>
|
||||
<StartWorkingDirectory>
|
||||
</StartWorkingDirectory>
|
||||
<EnableENC>False</EnableENC>
|
||||
<AlwaysStartWebServerOnDebug>False</AlwaysStartWebServerOnDebug>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
3
common/ASC.Socket.IO/README.md
Normal file
3
common/ASC.Socket.IO/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# ASC.Socket.IO
|
||||
|
||||
|
92
common/ASC.Socket.IO/app.js
Normal file
92
common/ASC.Socket.IO/app.js
Normal file
@ -0,0 +1,92 @@
|
||||
const express = require('express');
|
||||
const logger = require('morgan');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const expressSession = require("express-session");
|
||||
const sharedsession = require("express-socket.io-session");
|
||||
const RedisStore = require('connect-redis')(expressSession);
|
||||
const MemoryStore = require('memorystore')(expressSession);
|
||||
const config = require('./config');
|
||||
const winston = require('./app/log.js');
|
||||
const app = express();
|
||||
|
||||
const secret = config.get("core.machinekey") + (new Date()).getTime();
|
||||
const secretCookieParser = cookieParser(secret);
|
||||
const baseCookieParser = cookieParser();
|
||||
|
||||
winston.stream = {
|
||||
write: (message) => winston.info(message)
|
||||
};
|
||||
|
||||
const redis = {
|
||||
host: config.get("redis:host"),
|
||||
port: config.get("redis:port"),
|
||||
ttl: 3600
|
||||
}
|
||||
|
||||
let store;
|
||||
if(redis.host && redis.port){
|
||||
store = new RedisStore(redis);
|
||||
} else {
|
||||
store = new MemoryStore();
|
||||
}
|
||||
|
||||
const session = expressSession({
|
||||
store: store,
|
||||
secret: secret,
|
||||
resave: true,
|
||||
saveUninitialized: true,
|
||||
cookie: {
|
||||
path: '/',
|
||||
httpOnly: true,
|
||||
secure: false,
|
||||
maxAge: null
|
||||
},
|
||||
cookieParser: secretCookieParser,
|
||||
name: "socketio.sid"
|
||||
});
|
||||
|
||||
app.set('port', config.get('port') || 3000);
|
||||
app.use(logger("dev", { "stream": winston.stream }));
|
||||
app.use(session);
|
||||
app.get('/', (req, res) => { res.send('<h1>Hello world</h1>'); });
|
||||
|
||||
const server = app.listen(app.get('port'), () => {
|
||||
//log.info('Express server listening on port ' + server.address().port);
|
||||
});
|
||||
|
||||
const io = require('socket.io')(server, {
|
||||
perMessageDeflate : false,
|
||||
cookie: false,
|
||||
handlePreflightRequest: function (req, res) {
|
||||
session(req, res, ()=>{});
|
||||
res.writeHead(200, {'Content-Type': 'text/html'});
|
||||
res.end();
|
||||
},
|
||||
allowRequest : function(req, fn){
|
||||
var cookies = baseCookieParser(req, null, ()=>{});
|
||||
if(!req.cookies || (!req.cookies['asc_auth_key'] && !req.cookies['authorization'])){
|
||||
return fn('auth', false);
|
||||
}
|
||||
|
||||
return io.checkRequest(req, fn);
|
||||
}
|
||||
});
|
||||
const auth = require('./app/middleware/auth.js');
|
||||
|
||||
io
|
||||
.use(sharedsession(session, secretCookieParser, {autoSave: true}))
|
||||
.use((socket, next) => {
|
||||
baseCookieParser(socket.client.request, null, next);
|
||||
})
|
||||
.use((socket, next) => {
|
||||
auth(socket, next);
|
||||
});
|
||||
|
||||
const countersHub = require('./app/hubs/counters.js')(io);
|
||||
const voipHub = require('./app/hubs/voip.js')(io);
|
||||
const chatHub = require('./app/hubs/chat.js')(io);
|
||||
const filesHub = require('./app/hubs/files.js')(io);
|
||||
|
||||
app.use("/controller", require('./app/controllers')(countersHub, chatHub, voipHub, filesHub));
|
||||
|
||||
module.exports = app;
|
147
common/ASC.Socket.IO/app/apiRequestManager.js
Normal file
147
common/ASC.Socket.IO/app/apiRequestManager.js
Normal file
@ -0,0 +1,147 @@
|
||||
const apiBasePath = "/api/2.0/",
|
||||
portalManager = require('./portalManager.js'),
|
||||
request = require('request'),
|
||||
log = require("./log.js");
|
||||
|
||||
function makeRequest(apiMethod, req, options, onSuccess){
|
||||
makeHeaders(req, options);
|
||||
options.uri = getBasePath(req) + apiMethod;
|
||||
log.info(options.uri);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
request(options, (error, response, body) => {
|
||||
let result = {};
|
||||
try {
|
||||
result = typeof body === "string" ? JSON.parse(body) : body;
|
||||
} catch (err) {
|
||||
log.error(options.uri, err);
|
||||
}
|
||||
|
||||
error = checkError(error, response, result);
|
||||
if(error) {
|
||||
log.error(options.uri, error);
|
||||
if (error == 401 && req.session) {
|
||||
req.session.destroy(() => reject(error));
|
||||
return
|
||||
} else {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
resolve(onSuccess(result));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function makeHeaders(req, options) {
|
||||
options.headers = {};
|
||||
|
||||
if (req.cookies && req.cookies['asc_auth_key']) {
|
||||
options.headers["Authorization"] = req.cookies['asc_auth_key'];
|
||||
}
|
||||
|
||||
if (req.headers) {
|
||||
const xRewriterUrlHeader = 'x-rewriter-url',
|
||||
xForwardedForHeader = 'x-forwarded-for';
|
||||
|
||||
if (req.headers[xRewriterUrlHeader]) {
|
||||
options.headers[xRewriterUrlHeader] = req.headers[xRewriterUrlHeader];
|
||||
}
|
||||
if (req.headers[xForwardedForHeader]) {
|
||||
options.headers[xForwardedForHeader] = req.headers[xForwardedForHeader];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getBasePath(req) {
|
||||
return portalManager(req).replace(/\/$/g, '') + apiBasePath;
|
||||
}
|
||||
|
||||
function checkError(error, response, result) {
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (result && result.error && result.error.message) {
|
||||
return result.error.message;
|
||||
}
|
||||
|
||||
if (response.statusCode > 400) {
|
||||
return response.statusCode;
|
||||
}
|
||||
}
|
||||
|
||||
class RequestManager {
|
||||
constructor() { }
|
||||
|
||||
makeRequest(apiMethod, req, options) {
|
||||
return makeRequest(apiMethod, req, options, (result) => {
|
||||
return typeof result.response !== "undefined" ? result.response : result;
|
||||
});
|
||||
}
|
||||
get(apiMethod, req, body) {
|
||||
if (body) {
|
||||
apiMethod = `${apiMethod}?`;
|
||||
for (const item in body) {
|
||||
if (body.hasOwnProperty(item)) {
|
||||
apiMethod = `${apiMethod}${item}=${body[item]}&`;
|
||||
}
|
||||
}
|
||||
apiMethod = apiMethod.substring(0, apiMethod.length - 1);
|
||||
}
|
||||
return this.makeRequest(apiMethod, req, { method: "GET" });
|
||||
}
|
||||
post(apiMethod, req, body) {
|
||||
return this.makeRequest(apiMethod, req, { method: "POST", body, json: true });
|
||||
}
|
||||
put(apiMethod, req, body) {
|
||||
return this.makeRequest(apiMethod, req, { method: "PUT", body, json: true });
|
||||
}
|
||||
dlt(apiMethod, req, body) {
|
||||
const options = { method: "DELETE" };
|
||||
if (typeof body !== "undefined") {
|
||||
options.body = req.body;
|
||||
options.json = true;
|
||||
}
|
||||
return this.makeRequest(apiMethod, req, options);
|
||||
}
|
||||
batch(batchMethod, req){
|
||||
const options = {
|
||||
method: "POST",
|
||||
form:{ batch: JSON.stringify(batchMethod.methods) },
|
||||
json: true
|
||||
};
|
||||
|
||||
return makeRequest("batch.json", req, options, (result) => {
|
||||
const resultResponse = result.response;
|
||||
if(result.response !== "undefined" && Array.isArray(result.response)) {
|
||||
let data = [];
|
||||
|
||||
for(let i = 0, j = resultResponse.length; i < j; i++){
|
||||
const dataItem = typeof resultResponse[i].data === "string" ? JSON.parse(resultResponse[i].data) : resultResponse[i].data
|
||||
data.push(dataItem.response);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
batchFactory(){
|
||||
return new batchFactory();
|
||||
}
|
||||
}
|
||||
|
||||
class batchFactory {
|
||||
constructor() {
|
||||
this.methods = [];
|
||||
}
|
||||
get(url) {
|
||||
this.methods.push({method: "get", RelativeUrl: `${apiBasePath}${url}`});
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new RequestManager();
|
23
common/ASC.Socket.IO/app/controllers/chat.js
Normal file
23
common/ASC.Socket.IO/app/controllers/chat.js
Normal file
@ -0,0 +1,23 @@
|
||||
module.exports = (chat) => {
|
||||
const router = require('express').Router();
|
||||
|
||||
router
|
||||
.post("/send", (req, res) => {
|
||||
chat.send(req.body);
|
||||
res.end();
|
||||
})
|
||||
.post("/sendInvite", (req, res) => {
|
||||
chat.sendInvite(req.body);
|
||||
res.end();
|
||||
})
|
||||
.post("/setState", (req, res) => {
|
||||
chat.setState(req.body);
|
||||
res.end();
|
||||
})
|
||||
.post("/sendOfflineMessages", (req, res) => {
|
||||
chat.sendOfflineMessages(req.body);
|
||||
res.end();
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
15
common/ASC.Socket.IO/app/controllers/counters.js
Normal file
15
common/ASC.Socket.IO/app/controllers/counters.js
Normal file
@ -0,0 +1,15 @@
|
||||
module.exports = (counters) => {
|
||||
const router = require('express').Router();
|
||||
|
||||
router
|
||||
.post("/sendUnreadUsers", (req, res) => {
|
||||
counters.sendUnreadUsers(req.body);
|
||||
res.end();
|
||||
})
|
||||
.post("/sendUnreadCounts", (req, res) => {
|
||||
counters.sendUnreadCounts(req.body);
|
||||
res.end();
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
11
common/ASC.Socket.IO/app/controllers/files.js
Normal file
11
common/ASC.Socket.IO/app/controllers/files.js
Normal file
@ -0,0 +1,11 @@
|
||||
module.exports = (files) => {
|
||||
const router = require('express').Router();
|
||||
|
||||
router
|
||||
.post("/changeEditors", (req, res) => {
|
||||
files.changeEditors(req.body);
|
||||
res.end();
|
||||
});
|
||||
|
||||
return router;
|
||||
};
|
26
common/ASC.Socket.IO/app/controllers/index.js
Normal file
26
common/ASC.Socket.IO/app/controllers/index.js
Normal file
@ -0,0 +1,26 @@
|
||||
module.exports = (counters, chat, voip, files) => {
|
||||
const router = require('express').Router(),
|
||||
bodyParser = require('body-parser'),
|
||||
authService = require('../middleware/authService.js')();
|
||||
|
||||
router.use(bodyParser.json());
|
||||
router.use(bodyParser.urlencoded({ extended: false }));
|
||||
router.use(require('cookie-parser')());
|
||||
router.use((req, res, next) => {
|
||||
if (!authService(req)) {
|
||||
res.sendStatus(403);
|
||||
return;
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
router
|
||||
.use("/counters", require(`./counters.js`)(counters))
|
||||
.use("/mail", require(`./mail.js`)(counters))
|
||||
.use("/chat", require(`./chat.js`)(chat))
|
||||
.use("/voip", require(`./voip.js`)(voip))
|
||||
.use("/files", require(`./files.js`)(files));
|
||||
|
||||
return router;
|
||||
}
|
15
common/ASC.Socket.IO/app/controllers/mail.js
Normal file
15
common/ASC.Socket.IO/app/controllers/mail.js
Normal file
@ -0,0 +1,15 @@
|
||||
module.exports = (counters) => {
|
||||
const router = require('express').Router();
|
||||
|
||||
router
|
||||
.post("/updateFolders", (req, res) => {
|
||||
counters.updateFolders(req.body);
|
||||
res.end();
|
||||
})
|
||||
.post("/sendMailNotification", (req, res) => {
|
||||
counters.sendMailNotification(req.body);
|
||||
res.end();
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
32
common/ASC.Socket.IO/app/controllers/voip.js
Normal file
32
common/ASC.Socket.IO/app/controllers/voip.js
Normal file
@ -0,0 +1,32 @@
|
||||
module.exports = (voip) => {
|
||||
const router = require('express').Router();
|
||||
|
||||
router
|
||||
.post("/enqueue", (req, res) => {
|
||||
const { numberId, callId, agent } = req.body;
|
||||
voip.enqueue(numberId, callId, agent);
|
||||
res.end();
|
||||
})
|
||||
.post("/incoming", (req, res) => {
|
||||
const { callId, agent } = req.body;
|
||||
voip.incoming(callId, agent);
|
||||
res.end();
|
||||
})
|
||||
.post("/miss", (req, res) => {
|
||||
const { numberId, callId, agent } = req.body;
|
||||
voip.miss(numberId, callId, agent);
|
||||
res.end();
|
||||
})
|
||||
.post("/getAgent", (req, res) => {
|
||||
const { numberId, contactsResponsibles } = req.body;
|
||||
const result = voip.getAgent(numberId, contactsResponsibles);
|
||||
res.send(JSON.stringify({item1: result.result, item2: result.isAnyNotOffline}));
|
||||
})
|
||||
.post("/reload", (req, res) => {
|
||||
const { numberRoom, agentId } = req.body;
|
||||
voip.reload(numberRoom, agentId);
|
||||
res.end();
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
219
common/ASC.Socket.IO/app/hubs/chat.js
Normal file
219
common/ASC.Socket.IO/app/hubs/chat.js
Normal file
@ -0,0 +1,219 @@
|
||||
module.exports = (io, countersHub) => {
|
||||
const apiRequestManager = require('../apiRequestManager.js');
|
||||
const co = require('co');
|
||||
const baseTalkApiUrl = 'portal/talk/';
|
||||
const chat = io.of("/chat");
|
||||
const onlineUsers = [];
|
||||
|
||||
chat.on('connection', (socket) => {
|
||||
const request = socket.client.request;
|
||||
if(!request.user || !request.user.id) return;
|
||||
const user = request.user;
|
||||
const portal = request.portal;
|
||||
const userId = user.id;
|
||||
const userName = user.userName.toLowerCase();
|
||||
const tenantId = portal.tenantId;
|
||||
const tenantDomain = portal.tenantDomain;
|
||||
|
||||
socket
|
||||
.on('disconnect', onDisconnectUser)
|
||||
.on('connectUser', onConnectUser)
|
||||
.on('disconnectUser', onDisconnectUser)
|
||||
.on('send', onSend)
|
||||
.on('getStates', onGetStates)
|
||||
.on('getContactInfo', onGetContactInfo)
|
||||
.on('getInitData', onGetInitData)
|
||||
.on('sendTyping', onSendTyping)
|
||||
.on('sendStateToTenant', onSendStateToTenant)
|
||||
.on('getRecentMessages', onGetRecentMessages)
|
||||
.on('chatPing', onPing);
|
||||
|
||||
function onDisconnectUser(change, fn) {
|
||||
co(function *() {
|
||||
let state;
|
||||
|
||||
if (!onlineUsers[tenantId]) return;
|
||||
if (!onlineUsers[tenantId][userId] || !socket.onConnectUser) {
|
||||
if(typeof fn == "function") fn();
|
||||
return;
|
||||
}
|
||||
|
||||
if (change === true || onlineUsers[tenantId][userId].counter === 1) {
|
||||
delete onlineUsers[tenantId][userId];
|
||||
state = yield apiRequestManager.dlt(`${baseTalkApiUrl}connection?connectionId=${userId}`, request);
|
||||
socket.emit("disconnectUser");
|
||||
} else {
|
||||
onlineUsers[tenantId][userId].counter--;
|
||||
state = yield apiRequestManager.get(`${baseTalkApiUrl}state`, request, { userName });
|
||||
if (state !== 4) {
|
||||
// setStatus
|
||||
socket.broadcast.to(`${tenantId}-${userName}`).emit('setStatus', state);
|
||||
}
|
||||
}
|
||||
|
||||
socket.broadcast.to(tenantId).emit('setState', userName, state);
|
||||
})
|
||||
.catch((err)=>{
|
||||
if(typeof fn == "function") fn(err);
|
||||
});
|
||||
}
|
||||
|
||||
function onConnectUser(state) {
|
||||
socket.join([tenantId, `${tenantId}-${userName}`]);
|
||||
socket.onConnectUser = true;
|
||||
|
||||
if (!onlineUsers[tenantId]) {
|
||||
onlineUsers[tenantId] = {};
|
||||
}
|
||||
|
||||
var counter = onlineUsers[tenantId][userId];
|
||||
if (!counter) {
|
||||
counter = onlineUsers[tenantId][userId] = { counter: 1 };
|
||||
} else {
|
||||
counter.counter++;
|
||||
}
|
||||
|
||||
co(function* () {
|
||||
if (counter.counter === 1) {
|
||||
state = yield apiRequestManager.post(`${baseTalkApiUrl}connection`, request, { connectionId: userId, state });
|
||||
} else {
|
||||
state = yield apiRequestManager.post(`${baseTalkApiUrl}state`, request, { state });
|
||||
|
||||
if (state !== 4) {
|
||||
socket.broadcast.to(`${tenantId}-${userName}`).emit('setStatus', state);
|
||||
}
|
||||
}
|
||||
socket.broadcast.to(tenantId).emit('setState', userName, state, false);
|
||||
chat.to(`${tenantId}-${userName}`).emit("connectUser");
|
||||
})
|
||||
.catch((err)=>{
|
||||
chat.to(`${tenantId}-${userName}`).emit("connectUser", err);
|
||||
});
|
||||
}
|
||||
|
||||
function onSend(calleeUserName, messageText) {
|
||||
co(function* () {
|
||||
const message = { u: userName, t: messageText };
|
||||
|
||||
if (calleeUserName) {
|
||||
chat.to(`${tenantId}-${calleeUserName}`).emit('send', message, calleeUserName);
|
||||
socket.broadcast.to(`${tenantId}-${userName}`).emit('send', message, calleeUserName);
|
||||
}
|
||||
yield apiRequestManager.post(`${baseTalkApiUrl}message`, request, { to: calleeUserName, text: messageText });
|
||||
});
|
||||
}
|
||||
|
||||
function onGetStates(fn) {
|
||||
apiRequestManager.get(`${baseTalkApiUrl}states`, request)
|
||||
.then((result) => {
|
||||
socket.emit('statesRetrieved', result);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (typeof fn === "function") fn(err);
|
||||
});;
|
||||
}
|
||||
|
||||
function onGetContactInfo(calleeUserName, fn) {
|
||||
co(function* () {
|
||||
const calleeUser = yield apiRequestManager.get('people/' + calleeUserName, request);
|
||||
if (!calleeUser || calleeUser.id === "4A515A15-D4D6-4b8e-828E-E0586F18F3A3") throw "Can't get UserInfo";
|
||||
|
||||
const calleeUserState = yield apiRequestManager.get(`${baseTalkApiUrl}state`, request, { userName: calleeUserName });
|
||||
if(typeof fn === "function") fn(calleeUserName, calleeUserState);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err && typeof fn === "function") fn(null, null, err);
|
||||
});
|
||||
}
|
||||
|
||||
function onGetInitData(fn) {
|
||||
co(function* () {
|
||||
const states = yield apiRequestManager.get(`${baseTalkApiUrl}states`, request);
|
||||
const users = yield apiRequestManager.get('people', request);
|
||||
const result = users
|
||||
.filter((item) => item.id !== userId)
|
||||
.sort((item1, item2) => {
|
||||
if (item1.displayName < item2.displayName) return -1;
|
||||
if (item1.displayName > item2.displayName) return 1;
|
||||
return 0;
|
||||
})
|
||||
.map((item) => {
|
||||
const uName = item.userName.toLowerCase();
|
||||
return { u: uName, d: item.displayName, s: states[uName] || 4}
|
||||
});
|
||||
|
||||
socket.emit('initDataRetrieved', userName, user.displayName, result, tenantId, tenantDomain);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (typeof fn === "function") fn(err);
|
||||
});
|
||||
}
|
||||
|
||||
function onSendTyping(calleeUserName) {
|
||||
chat.to(`${tenantId}-${calleeUserName}`).emit('sendTypingSignal', userName);
|
||||
}
|
||||
|
||||
function onSendStateToTenant(state) {
|
||||
apiRequestManager.post(`${baseTalkApiUrl}state`, request, { state })
|
||||
.then((result) => {
|
||||
socket.broadcast.to(tenantId).emit('setState', userName, result, false);
|
||||
});
|
||||
}
|
||||
|
||||
function onGetRecentMessages(calleeUserName, id, fn) {
|
||||
apiRequestManager.get(`${baseTalkApiUrl}recentMessages`, request, { calleeUserName, id })
|
||||
.then((recentMessages) => {
|
||||
if (typeof fn === "function") fn(recentMessages);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (typeof fn === "function") fn(null, err);
|
||||
});
|
||||
}
|
||||
|
||||
function onPing(state) {
|
||||
apiRequestManager.post(`${baseTalkApiUrl}ping`, request, { state: state });
|
||||
}
|
||||
});
|
||||
|
||||
function tenantPlusUserRoom(tenantId, userName) {
|
||||
return chat.to(`${tenantId}-${userName}`);
|
||||
}
|
||||
|
||||
function send({ tenantId, callerUserName, calleeUserName, message, isTenantUser } = {}) {
|
||||
if (typeof tenantId === "undefined" || !calleeUserName || !message) {
|
||||
return;
|
||||
}
|
||||
|
||||
tenantPlusUserRoom(tenantId, calleeUserName).emit('send', message, calleeUserName, isTenantUser);
|
||||
|
||||
if (!isTenantUser) {
|
||||
tenantPlusUserRoom(tenantId, callerUserName).emit('send', message, calleeUserName, isTenantUser);
|
||||
}
|
||||
}
|
||||
|
||||
function sendInvite({ tenantId, calleeUserName, message } = {}) {
|
||||
if (typeof tenantId === "undefined" || !calleeUserName || !message) {
|
||||
return;
|
||||
}
|
||||
|
||||
tenantPlusUserRoom(tenantId, calleeUserName).emit('sendInvite', message);
|
||||
}
|
||||
|
||||
function setState({ tenantId, from, state } = {}) {
|
||||
if (typeof tenantId === "undefined" || !from) {
|
||||
return;
|
||||
}
|
||||
|
||||
chat.to(`${tenantId}`).emit('setState', from, state);
|
||||
}
|
||||
|
||||
function sendOfflineMessages({ tenantId, callerUserName, users } = {}) {
|
||||
if (typeof tenantId === "undefined" || !callerUserName || !users) {
|
||||
return;
|
||||
}
|
||||
|
||||
tenantPlusUserRoom(tenantId, callerUserName).emit('sendOfflineMessages', users);
|
||||
}
|
||||
|
||||
return { send, sendInvite, setState, sendOfflineMessages };
|
||||
}
|
209
common/ASC.Socket.IO/app/hubs/counters.js
Normal file
209
common/ASC.Socket.IO/app/hubs/counters.js
Normal file
@ -0,0 +1,209 @@
|
||||
module.exports = (io) => {
|
||||
const apiRequestManager = require('../apiRequestManager.js');
|
||||
const co = require('co');
|
||||
const counters = io.of('/counters');
|
||||
const onlineUsers = [];
|
||||
const uaParser = require('ua-parser-js');
|
||||
|
||||
counters.on('connection', (socket) => {
|
||||
const request = socket.client.request;
|
||||
if(!request.user || !request.user.id) return;
|
||||
const userId = request.user.id;
|
||||
const tenantId = request.portal.tenantId;
|
||||
let ipAddress = socket.handshake.headers['x-forwarded-for'];
|
||||
const userAgent = socket.request.headers['user-agent'];
|
||||
const parser = new uaParser();
|
||||
parser.setUA(userAgent);
|
||||
|
||||
const [os, browser] = [parser.getOS(), parser.getBrowser()];
|
||||
const operationSystem = os.version !== undefined ? `${os.name} ${os.version}` : `${os.name}`;
|
||||
const browserVersion = browser.version ? browser.version : '';
|
||||
|
||||
ipAddress = getCleanIP(ipAddress);
|
||||
const browserName = `${browser.name} ${browserVersion}`;
|
||||
const userName = (request.user.userName || "").toLowerCase();
|
||||
getCityByIP(ipAddress);
|
||||
|
||||
socket.join([tenantId, `${tenantId}-${userId}`, `${tenantId}-${userName}`]);
|
||||
|
||||
getNewMessagesCount();
|
||||
|
||||
socket
|
||||
.on('disconnect', () => {
|
||||
if (!onlineUsers[tenantId]) return;
|
||||
if (!onlineUsers[tenantId][userId]) return;
|
||||
if (!onlineUsers[tenantId][userId].browsers) return;
|
||||
if (!onlineUsers[tenantId][userId].browsers[browserName]) return;
|
||||
|
||||
onlineUsers[tenantId][userId].browsers[browserName].counter--;
|
||||
if (onlineUsers[tenantId][userId].browsers[browserName].counter === 0) {
|
||||
delete onlineUsers[tenantId][userId].browsers[browserName];
|
||||
}
|
||||
if (Object.keys(onlineUsers[tenantId][userId].browsers).length === 0) {
|
||||
delete onlineUsers[tenantId][userId];
|
||||
counters.to(tenantId).emit('renderOfflineUser', userId);
|
||||
updateMailUserActivity(socket.client.request, false);
|
||||
console.log(`a user ${userName} in portal ${tenantId} disconnected`);
|
||||
}
|
||||
})
|
||||
.on('renderOnlineUsers', () => {
|
||||
counters.to(tenantId).emit('renderOnlineUsers', onlineUsers[tenantId] || []);
|
||||
})
|
||||
.on('sendMessagesCount', (count) => {
|
||||
socket.broadcast.to(`${tenantId}-${userId}`).emit('sendMessagesCount', count);
|
||||
})
|
||||
.on('sendFeedsCount', () => {
|
||||
socket.broadcast.to(`${tenantId}-${userId}`).emit('sendFeedsCount', 0);
|
||||
})
|
||||
.on('updateFolders', (shouldUpdateMailBox) => {
|
||||
counters.in(`${tenantId}-${userId}`).clients((error, clients) => {
|
||||
if (error) return;
|
||||
if (clients.length > 1) {
|
||||
getMessageCount().then((count) => {
|
||||
socket.broadcast.to(`${tenantId}-${userId}`).emit('updateFolders', count, shouldUpdateMailBox);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function updateMailUserActivity(request, userOnline = true) {
|
||||
if(!request.mailEnabled) return;
|
||||
|
||||
setTimeout(function(){
|
||||
if((!userOnline && typeof onlineUsers[tenantId][userId] != "undefined") ||
|
||||
(userOnline && !onlineUsers[tenantId][userId])) return;
|
||||
|
||||
apiRequestManager.put("mail/accounts/updateuseractivity.json", request, { userOnline });
|
||||
console.log(`updateuseractivity ${userOnline}`);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
function getNewMessagesCount() {
|
||||
co(function* () {
|
||||
let mailMessageFolders = [], feedCount = 0, messageCount = 0, mailCount = 0;
|
||||
var batchRequest = apiRequestManager.batchFactory()
|
||||
.get("feed/newfeedscount.json")
|
||||
.get("portal/talk/unreadmessages.json");
|
||||
|
||||
if(!request.mailEnabled){
|
||||
[feedCount, messageCount] = yield apiRequestManager.batch(batchRequest,request);
|
||||
}else{
|
||||
[feedCount, messageCount, mailMessageFolders] = yield apiRequestManager.batch(batchRequest.get("mail/folders.json"), request);
|
||||
}
|
||||
|
||||
mailCount = getInreadMessageCount(mailMessageFolders);
|
||||
|
||||
counters.to(`${tenantId}-${userId}`).emit('getNewMessagesCount',
|
||||
{
|
||||
me: messageCount,
|
||||
f: feedCount,
|
||||
ma: mailCount
|
||||
});
|
||||
})
|
||||
.catch((err)=>{
|
||||
});
|
||||
}
|
||||
|
||||
function getMessageCount() {
|
||||
if(!request.mailEnabled) return new Promise((resolve) => { resolve(0)});
|
||||
return apiRequestManager.get("mail/folders.json", request).then(getInreadMessageCount);
|
||||
}
|
||||
|
||||
function getCityByIP (ip){
|
||||
apiRequestManager.get("portal/ip/" + ip, request, false)
|
||||
.then((result) => {
|
||||
const city = result.city;
|
||||
console.log(`a user ${userName} in portal ${tenantId} connected, IP ${ipAddress}, city ${city}, OS ${operationSystem}, browser ${browserName}`);
|
||||
console.log("-----");
|
||||
if (!onlineUsers[tenantId]) {
|
||||
onlineUsers[tenantId] = {};
|
||||
}
|
||||
if (!onlineUsers[tenantId][userId]) {
|
||||
onlineUsers[tenantId][userId] = {browsers: {},FirstConnection: new Date(), LastConnection: new Date() };
|
||||
socket.broadcast.to(tenantId).emit('renderOnlineUser', userId);
|
||||
updateMailUserActivity(socket.client.request);
|
||||
}
|
||||
else {
|
||||
onlineUsers[tenantId][userId].LastConnection = new Date();
|
||||
}
|
||||
|
||||
if (!onlineUsers[tenantId][userId].browsers[browserName]) {
|
||||
onlineUsers[tenantId][userId].browsers[browserName] = {counter:1, ipAddress: ipAddress, city: city, operationSystem: operationSystem };
|
||||
} else {
|
||||
onlineUsers[tenantId][userId].browsers[browserName].counter++;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
function getCleanIP (ipAddress) {
|
||||
const indexOfColon = ipAddress.indexOf(':');
|
||||
if (indexOfColon === -1){
|
||||
return ipAddress;
|
||||
} else if (indexOfColon > 3){
|
||||
return ipAddress.substring(0, indexOfColon);
|
||||
}
|
||||
else {
|
||||
return "127.0.0.1";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function getInreadMessageCount(mailMessageFolders){
|
||||
let mailMessageFoldersCount = mailMessageFolders.length;
|
||||
while (mailMessageFoldersCount--) {
|
||||
const mailMessageFolder = mailMessageFolders[mailMessageFoldersCount];
|
||||
if (mailMessageFolder && mailMessageFolder.id === 1) {
|
||||
return mailMessageFolder.unread_messages;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
function sendUnreadUsers(unreadUsers) {
|
||||
if (!unreadUsers) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let tenant in unreadUsers) {
|
||||
if (!unreadUsers.hasOwnProperty(tenant)) continue;
|
||||
|
||||
for (let user in unreadUsers[tenant]) {
|
||||
if (!unreadUsers[tenant].hasOwnProperty(user)) continue;
|
||||
|
||||
counters.to(`${tenant}-${user}`).emit('sendFeedsCount', unreadUsers[tenant][user]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sendUnreadCounts({ tenantId, unreadCounts } = {}) {
|
||||
if (typeof tenantId === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let user in unreadCounts) {
|
||||
if (unreadCounts.hasOwnProperty(user)) {
|
||||
counters.to(`${tenantId}-${user}`).emit('sendMessagesCount', unreadCounts[user]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateFolders({ tenant, userId, count } = {}) {
|
||||
if (typeof tenant === "undefined" || !userId || !count) {
|
||||
return;
|
||||
}
|
||||
|
||||
counters.to(`${tenant}-${userId}`).emit('updateFolders', count);
|
||||
}
|
||||
|
||||
function sendMailNotification({ tenant, userId, state } = {}) {
|
||||
if (typeof tenant === "undefined" || !userId || typeof state === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
counters.to(`${tenant}-${userId}`).emit('sendMailNotification', state);
|
||||
}
|
||||
|
||||
return { sendUnreadUsers, sendUnreadCounts, updateFolders, sendMailNotification };
|
||||
}
|
51
common/ASC.Socket.IO/app/hubs/files.js
Normal file
51
common/ASC.Socket.IO/app/hubs/files.js
Normal file
@ -0,0 +1,51 @@
|
||||
module.exports = (io) => {
|
||||
const log = require("../log.js");
|
||||
const files = io.of("/files");
|
||||
|
||||
files.on("connection", (socket) => {
|
||||
const request = socket.client.request;
|
||||
if (!request.user || !request.user.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tenantId = request.portal.tenantId;
|
||||
|
||||
socket
|
||||
.on("subscribeChangeEditors", (fileIds) => {
|
||||
if (typeof fileIds != "object") {
|
||||
fileIds = [fileIds];
|
||||
}
|
||||
|
||||
fileIds.forEach(function(fileId) {
|
||||
let room = `${tenantId}-${fileId}`;
|
||||
|
||||
socket.join(room);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function changeEditors({ tenantId, fileId, finish } = {}) {
|
||||
if (typeof tenantId === "undefined" || typeof fileId === "undefined") {
|
||||
log.error(`files: changeEditors without arguments`);
|
||||
return;
|
||||
}
|
||||
|
||||
let room = `${tenantId}-${fileId}`;
|
||||
|
||||
files.to(room).emit("changeEditors", fileId);
|
||||
|
||||
if (finish) {
|
||||
files.in(room).clients((error, clients) => {
|
||||
if (error) throw error;
|
||||
clients.forEach(function(client) {
|
||||
let clientSocket = files.connected[client];
|
||||
if(clientSocket){
|
||||
clientSocket.leave(room);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { changeEditors };
|
||||
};
|
119
common/ASC.Socket.IO/app/hubs/voip.js
Normal file
119
common/ASC.Socket.IO/app/hubs/voip.js
Normal file
@ -0,0 +1,119 @@
|
||||
module.exports = (io) => {
|
||||
const phones = new (require("./voipListPhones.js"))();
|
||||
const numberIdKey = "numberId";
|
||||
const voip = io.of("/voip");
|
||||
|
||||
voip.on('connection', (socket) => {
|
||||
const request = socket.client.request;
|
||||
if(!request.user || !request.user.id) return;
|
||||
const user = request.user;
|
||||
const userId = user.id;
|
||||
const numberId = getNumberId(request);
|
||||
const numberRoom = request.portal.tenantId + numberId;
|
||||
|
||||
socket.join([numberRoom, userId]);
|
||||
|
||||
phones.addPhone(numberId);
|
||||
|
||||
socket
|
||||
.on("status", status)
|
||||
.on("miss", miss.bind(null, numberId))
|
||||
.on("enqueue", enqueue.bind(null, numberId))
|
||||
.on("Dequeue", dequeue)
|
||||
.on("OnlineAgents", onlineAgents)
|
||||
.on("getStatus", getStatus)
|
||||
.on("getAgent", getAgent.bind(null, numberId))
|
||||
.on("incoming", incoming)
|
||||
.on("start", start)
|
||||
.on("end", end);
|
||||
|
||||
function getNumberId(request) {
|
||||
let result = request._query[numberIdKey];
|
||||
if (!result) {
|
||||
result = request.headers[numberIdKey];
|
||||
}
|
||||
|
||||
return result || "";
|
||||
}
|
||||
|
||||
function status(agentStatus, fn) {
|
||||
voip.to(userId).emit("status", agentStatus);
|
||||
|
||||
switch (agentStatus) {
|
||||
case 0:
|
||||
socket.once('disconnect', () => {
|
||||
status(2);
|
||||
});
|
||||
if (phones.anyCalls(numberId)) {
|
||||
dequeue();
|
||||
} else {
|
||||
phones.addOrUpdateAgent(numberId, { id: userId, status: agentStatus });
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
phones.addOrUpdateAgent(numberId, { id: userId, status: agentStatus });
|
||||
break;
|
||||
case 2:
|
||||
phones.removeAgent(numberId, userId);
|
||||
break;
|
||||
}
|
||||
onlineAgents();
|
||||
if(fn) fn();
|
||||
|
||||
}
|
||||
|
||||
function dequeue() {
|
||||
voip.to(userId).emit('dequeue', phones.dequeueCall(numberId));
|
||||
}
|
||||
|
||||
function onlineAgents() {
|
||||
voip.to(numberRoom).emit('onlineAgents', phones.onlineAgents(numberId));
|
||||
}
|
||||
|
||||
function getStatus(fn) {
|
||||
const getStatusResult = phones.getStatus(numberId, userId);
|
||||
fn(getStatusResult);
|
||||
}
|
||||
|
||||
function start() {
|
||||
voip.to(userId).emit('start');
|
||||
}
|
||||
|
||||
function end() {
|
||||
voip.to(userId).emit('end');
|
||||
}
|
||||
});
|
||||
|
||||
function enqueue(numberId, callId, agent) {
|
||||
const result = phones.enqueue(numberId, callId, agent);
|
||||
if (result) {
|
||||
voip.to(result).emit('dequeue', callId);
|
||||
}
|
||||
}
|
||||
|
||||
function incoming(callId, agent) {
|
||||
voip.to(agent).emit('dequeue', callId);
|
||||
}
|
||||
|
||||
function miss(numberId, callId, agent) {
|
||||
phones.removeCall(numberId, callId);
|
||||
|
||||
voip.to(agent).emit('miss', callId);
|
||||
}
|
||||
|
||||
function getAgent(numberId, contactsResponsibles, fn) {
|
||||
const result = phones.getAgent(numberId, contactsResponsibles);
|
||||
if (typeof fn === "function") fn(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
function reload(numberRoom, agent) {
|
||||
if (agent) {
|
||||
voip.to(agent).emit('reload');
|
||||
}else{
|
||||
voip.to(numberRoom).emit('reload');
|
||||
}
|
||||
}
|
||||
|
||||
return { enqueue, incoming, miss, getAgent, reload };
|
||||
}
|
74
common/ASC.Socket.IO/app/hubs/voipListPhones.js
Normal file
74
common/ASC.Socket.IO/app/hubs/voipListPhones.js
Normal file
@ -0,0 +1,74 @@
|
||||
const VoipPhone = require('./voipPhone.js');
|
||||
|
||||
class ListVoipPhone {
|
||||
constructor() {
|
||||
this.phones = [];
|
||||
}
|
||||
|
||||
addPhone(numberId) {
|
||||
const existingPhone = this.phones.find((item) => item.numberId === numberId);
|
||||
if (!existingPhone) {
|
||||
this.phones.push(new VoipPhone(numberId));
|
||||
}
|
||||
}
|
||||
|
||||
getPhone(numberId) {
|
||||
return this.phones.find((item) => item.numberId === numberId);
|
||||
}
|
||||
|
||||
addOrUpdateAgent(numberId, agent) {
|
||||
const phone = this.getPhone(numberId);
|
||||
if (!phone) return;
|
||||
phone.addOrUpdateAgent(agent);
|
||||
}
|
||||
|
||||
removeAgent(numberId, agentId) {
|
||||
const phone = this.getPhone(numberId);
|
||||
if (!phone) return;
|
||||
phone.removeAgent(agentId);
|
||||
}
|
||||
|
||||
anyCalls(numberId) {
|
||||
const phone = this.getPhone(numberId);
|
||||
if (!phone) return false;
|
||||
return phone.anyCalls();
|
||||
}
|
||||
|
||||
dequeueCall(numberId) {
|
||||
const phone = this.getPhone(numberId);
|
||||
if (!phone) return "";
|
||||
return phone.dequeueCall();
|
||||
}
|
||||
|
||||
removeCall(numberId, callId) {
|
||||
const phone = this.getPhone(numberId);
|
||||
if (!phone) return;
|
||||
phone.removeCall(callId);
|
||||
}
|
||||
|
||||
enqueue(numberId, callId, agent) {
|
||||
const phone = this.getPhone(numberId);
|
||||
if (!phone) return "";
|
||||
return phone.enqueue(callId, agent);
|
||||
}
|
||||
|
||||
onlineAgents(numberId) {
|
||||
const phone = this.getPhone(numberId);
|
||||
if (!phone) return [];
|
||||
return phone.onlineAgents();
|
||||
}
|
||||
|
||||
getStatus(numberId, agentId) {
|
||||
const phone = this.getPhone(numberId);
|
||||
if (!phone) return 2;
|
||||
return phone.getAgentStatus(agentId);
|
||||
}
|
||||
|
||||
getAgent(numberId, contactResponsibles) {
|
||||
const phone = this.getPhone(numberId);
|
||||
if (!phone) return null;
|
||||
return phone.getAgent(contactResponsibles);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ListVoipPhone;
|
87
common/ASC.Socket.IO/app/hubs/voipPhone.js
Normal file
87
common/ASC.Socket.IO/app/hubs/voipPhone.js
Normal file
@ -0,0 +1,87 @@
|
||||
function findAgent(agentId, item) {
|
||||
return item.id === agentId;
|
||||
}
|
||||
class VoipPhone {
|
||||
constructor(numberId) {
|
||||
this.agents = [];
|
||||
this.calls = [];
|
||||
this.numberId = numberId;
|
||||
}
|
||||
|
||||
addOrUpdateAgent(agent) {
|
||||
const existingAgent = this.agents.find(findAgent.bind(null, agent.Id));
|
||||
if (existingAgent) {
|
||||
existingAgent.status = agent.status;
|
||||
} else {
|
||||
this.agents.push(agent);
|
||||
}
|
||||
}
|
||||
|
||||
removeAgent(agentId) {
|
||||
const existingAgent = this.agents.some(findAgent.bind(null, agentId));
|
||||
if (!existingAgent) return false;
|
||||
|
||||
this.agents = this.agents.filter((item) => item.id !== agentId);
|
||||
return true;
|
||||
}
|
||||
|
||||
addCall(callId) {
|
||||
if (this.calls.some((item) => item === callId)) return;
|
||||
this.calls.push(callId);
|
||||
}
|
||||
|
||||
removeCall(callId) {
|
||||
if (!callId || !this.calls.some((item) => item === callId)) return;
|
||||
this.calls = this.calls.filter((item) => item !== callId);
|
||||
}
|
||||
|
||||
anyCalls() {
|
||||
return !!this.calls.length;
|
||||
}
|
||||
|
||||
dequeueCall() {
|
||||
return this.calls.pop();
|
||||
}
|
||||
|
||||
enqueue(callId, agent) {
|
||||
if (agent && this.removeAgent(agent)) {
|
||||
return agent;
|
||||
}
|
||||
|
||||
const agents = this.agents.filter((item) =>item.status === 0 );
|
||||
if (agents.length) {
|
||||
return agents[0].id;
|
||||
}
|
||||
|
||||
this.addCall(callId);
|
||||
return "";
|
||||
}
|
||||
|
||||
onlineAgents() {
|
||||
return this.agents.filter((item) => item.status === 0).map((item) => item.id);
|
||||
}
|
||||
|
||||
getAgentStatus(agentId) {
|
||||
const agent = this.agents.find(findAgent.bind(null, agentId));
|
||||
return agent ? agent.status : 2;
|
||||
}
|
||||
|
||||
getAgent(contactResponsibles) {
|
||||
const isAnyNotOffline = !!this.agents.length;
|
||||
let result = this.agents.find((item) => {
|
||||
return item.status === 0 && contactResponsibles.includes(item.id);
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
result = this.agents.find((item) => item.status === 0);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
result.status = 1;
|
||||
}
|
||||
|
||||
return { result, isAnyNotOffline };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = VoipPhone;
|
32
common/ASC.Socket.IO/app/log.js
Normal file
32
common/ASC.Socket.IO/app/log.js
Normal file
@ -0,0 +1,32 @@
|
||||
const winston = require('winston');
|
||||
require('winston-daily-rotate-file')
|
||||
|
||||
const path = require('path');
|
||||
const config = require('../config');
|
||||
const fs = require('fs');
|
||||
const fileName = config.get("logPath") || path.join(__dirname, "..", "..", "Logs", "web.socketio.%DATE%.log");
|
||||
const dirName = path.dirname(fileName);
|
||||
|
||||
if (!fs.existsSync(dirName)) {
|
||||
fs.mkdirSync(dirName);
|
||||
}
|
||||
|
||||
const fileTransport = new (winston.transports.DailyRotateFile)(
|
||||
{
|
||||
filename: fileName,
|
||||
datePattern: 'MM-DD',
|
||||
handleExceptions: true,
|
||||
humanReadableUnhandledException: true,
|
||||
zippedArchive: true,
|
||||
maxSize: '50m',
|
||||
maxFiles: '30d'
|
||||
});
|
||||
|
||||
const transports = [
|
||||
new (winston.transports.Console)(),
|
||||
fileTransport
|
||||
];
|
||||
|
||||
winston.handleExceptions(fileTransport);
|
||||
|
||||
module.exports = new winston.Logger({ transports: transports, exitOnError: false});
|
49
common/ASC.Socket.IO/app/middleware/auth.js
Normal file
49
common/ASC.Socket.IO/app/middleware/auth.js
Normal file
@ -0,0 +1,49 @@
|
||||
module.exports = function (socket, next) {
|
||||
const apiRequestManager = require('../apiRequestManager.js');
|
||||
const req = socket.client.request;
|
||||
const authService = require('./authService.js')();
|
||||
const co = require('co');
|
||||
const session = socket.handshake.session;
|
||||
|
||||
if (req.user) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!req.cookies || (!req.cookies['asc_auth_key'] && !req.cookies['authorization'])) {
|
||||
socket.disconnect('unauthorized');
|
||||
next(new Error('Authentication error'));
|
||||
return;
|
||||
}
|
||||
|
||||
if(session && session.user && session.portal && typeof(session.mailEnabled) !== "undefined") {
|
||||
req.user = session.user;
|
||||
req.portal = session.portal;
|
||||
req.mailEnabled = session.mailEnabled;
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
if(req.cookies['authorization']){
|
||||
if(!authService(req)){
|
||||
next(new Error('Authentication error'));
|
||||
} else{
|
||||
next();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
co(function*(){
|
||||
var batchRequest = apiRequestManager.batchFactory()
|
||||
.get("people/@self.json?fields=id,userName,displayName")
|
||||
.get("portal.json?fields=tenantId,tenantDomain")
|
||||
.get("settings/security/2A923037-8B2D-487b-9A22-5AC0918ACF3F");
|
||||
|
||||
[session.user, session.portal, session.mailEnabled] = [req.user, req.portal, req.mailEnabled] = yield apiRequestManager.batch(batchRequest, req);
|
||||
session.save();
|
||||
next();
|
||||
}).catch((err) => {
|
||||
socket.disconnect('unauthorized');
|
||||
next(new Error('Authentication error'));
|
||||
});
|
||||
}
|
37
common/ASC.Socket.IO/app/middleware/authService.js
Normal file
37
common/ASC.Socket.IO/app/middleware/authService.js
Normal file
@ -0,0 +1,37 @@
|
||||
module.exports = () => {
|
||||
const
|
||||
config = require('../../config'),
|
||||
crypto = require('crypto'),
|
||||
moment = require('moment');
|
||||
|
||||
const skey = config.get("core.machinekey");
|
||||
const trustInterval = 5 * 60 * 1000;
|
||||
|
||||
function check(req) {
|
||||
const authHeader = req.headers["authorization"] || req.cookies["authorization"];
|
||||
if(!authHeader) return false;
|
||||
|
||||
const splitted = authHeader.split(':');
|
||||
if (splitted.length < 3) return false;
|
||||
|
||||
const pkey = splitted[0].substr(4);
|
||||
const date = splitted[1];
|
||||
const orighash = splitted[2];
|
||||
|
||||
const timestamp = moment.utc(date, "YYYYMMDDHHmmss");
|
||||
if (moment.utc() - timestamp > trustInterval) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const hasher = crypto.createHmac('sha1', skey);
|
||||
const hash = hasher.update(date + "\n" + pkey);
|
||||
|
||||
if (hash.digest('base64') !== orighash) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return check;
|
||||
};
|
16
common/ASC.Socket.IO/app/portalManager.js
Normal file
16
common/ASC.Socket.IO/app/portalManager.js
Normal file
@ -0,0 +1,16 @@
|
||||
const portalInternalUrl = require('../config').get("portal.internal.url")
|
||||
module.exports = (req) => {
|
||||
if(portalInternalUrl) return portalInternalUrl;
|
||||
|
||||
const xRewriterUrlInternalHeader = 'x-rewriter-url-internal';
|
||||
if (req.headers && req.headers[xRewriterUrlInternalHeader]) {
|
||||
return req.headers[xRewriterUrlInternalHeader];
|
||||
}
|
||||
|
||||
const xRewriterUrlHeader = 'x-rewriter-url';
|
||||
if (req.headers && req.headers[xRewriterUrlHeader]) {
|
||||
return req.headers[xRewriterUrlHeader];
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
12
common/ASC.Socket.IO/config/config.json
Normal file
12
common/ASC.Socket.IO/config/config.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"port": 9899,
|
||||
"core.machinekey": "1123askdasjklasbnd",
|
||||
"portal.internal.url": "",
|
||||
"redis":{
|
||||
"host": "localhost",
|
||||
"port": 6379,
|
||||
"db": 0,
|
||||
"pass":"",
|
||||
"ttl":84600
|
||||
}
|
||||
}
|
8
common/ASC.Socket.IO/config/index.js
Normal file
8
common/ASC.Socket.IO/config/index.js
Normal file
@ -0,0 +1,8 @@
|
||||
const nconf = require('nconf');
|
||||
const path = require('path');
|
||||
|
||||
nconf.argv()
|
||||
.env()
|
||||
.file({ file: path.join(__dirname, 'config.json') });
|
||||
|
||||
module.exports = nconf;
|
32
common/ASC.Socket.IO/package.json
Normal file
32
common/ASC.Socket.IO/package.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "asc.socket.io",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node ./bin/www"
|
||||
},
|
||||
"description": "ASC.Socket.IO",
|
||||
"author": {
|
||||
"name": "Pavel"
|
||||
},
|
||||
"dependencies": {
|
||||
"connect-redis": "~3.4.0",
|
||||
"body-parser": "~1.18.2",
|
||||
"co": "^4.6.0",
|
||||
"cookie-parser": "~1.4.3",
|
||||
"debug": "~3.1.0",
|
||||
"express": "~4.16.4",
|
||||
"express-session": "~1.15.6",
|
||||
"express-socket.io-session": "~1.3.5",
|
||||
"memorystore": "^1.6.0",
|
||||
"moment": "^2.24.0",
|
||||
"morgan": "~1.9.1",
|
||||
"nconf": "^0.10.0",
|
||||
"redis": "^2.8.0",
|
||||
"request": "^2.88.0",
|
||||
"socket.io": "^2.2.0",
|
||||
"ua-parser-js": "^0.7.19",
|
||||
"winston": "^2.4.1",
|
||||
"winston-daily-rotate-file": "^3.2.0"
|
||||
}
|
||||
}
|
15
common/ASC.Socket.IO/typings.json
Normal file
15
common/ASC.Socket.IO/typings.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"globalDependencies": {
|
||||
"body-parser": "registry:dt/body-parser#0.0.0+20160317120654",
|
||||
"cookie-parser": "registry:dt/cookie-parser#1.3.4+20160316155526",
|
||||
"debug": "registry:dt/debug#0.0.0+20160317120654",
|
||||
"express": "registry:dt/express#4.0.0+20160317120654",
|
||||
"express-serve-static-core": "registry:dt/express-serve-static-core#0.0.0+20160602151406",
|
||||
"jade": "registry:dt/jade#0.0.0+20160316155526",
|
||||
"mime": "registry:dt/mime#0.0.0+20160316155526",
|
||||
"morgan": "registry:dt/morgan#1.7.0+20160524142355",
|
||||
"serve-favicon": "registry:dt/serve-favicon#0.0.0+20160316155526",
|
||||
"serve-static": "registry:dt/serve-static#0.0.0+20160606155157",
|
||||
"stylus": "registry:dt/stylus#0.0.0+20160317120654"
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@ using ASC.Common.Caching;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Core;
|
||||
using ASC.Core.Common;
|
||||
using ASC.Core.Notify.Signalr;
|
||||
using ASC.Feed.Aggregator.Modules;
|
||||
using ASC.Feed.Configuration;
|
||||
using ASC.Feed.Data;
|
||||
@ -51,7 +52,7 @@ namespace ASC.Feed.Aggregator
|
||||
public class FeedAggregatorService : IHostedService
|
||||
{
|
||||
private ILog Log { get; set; }
|
||||
//private static readonly SignalrServiceClient signalrServiceClient = new SignalrServiceClient("counters");//TODO
|
||||
private SignalrServiceClient SignalrServiceClient { get; }
|
||||
|
||||
private Timer aggregateTimer;
|
||||
private Timer removeTimer;
|
||||
@ -68,12 +69,16 @@ namespace ASC.Feed.Aggregator
|
||||
IConfiguration configuration,
|
||||
IServiceProvider serviceProvider,
|
||||
IContainer container,
|
||||
IOptionsMonitor<ILog> optionsMonitor)
|
||||
IOptionsMonitor<ILog> optionsMonitor,
|
||||
SignalrServiceClient signalrServiceClient,
|
||||
IConfigureNamedOptions<SignalrServiceClient> configureOptions)
|
||||
{
|
||||
Configuration = configuration;
|
||||
ServiceProvider = serviceProvider;
|
||||
Container = container;
|
||||
Log = optionsMonitor.Get("ASC.Feed.Agregator");
|
||||
SignalrServiceClient = signalrServiceClient;
|
||||
configureOptions.Configure("counters", SignalrServiceClient);
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
@ -220,7 +225,7 @@ namespace ASC.Feed.Aggregator
|
||||
}
|
||||
}
|
||||
|
||||
//signalrServiceClient.SendUnreadUsers(unreadUsers);
|
||||
SignalrServiceClient.SendUnreadUsers(unreadUsers);
|
||||
|
||||
Log.DebugFormat("Time of collecting news: {0}", DateTime.UtcNow - start);
|
||||
}
|
||||
@ -300,7 +305,8 @@ namespace ASC.Feed.Aggregator
|
||||
.AddUserManagerService()
|
||||
.AddSecurityContextService()
|
||||
.AddAuthManager()
|
||||
.AddFeedAggregateDataProvider();
|
||||
.AddFeedAggregateDataProvider()
|
||||
.AddSignalrServiceClient();
|
||||
}
|
||||
}
|
||||
}
|
27
common/services/ASC.Socket.IO.Svc/ASC.Socket.IO.Svc.csproj
Normal file
27
common/services/ASC.Socket.IO.Svc/ASC.Socket.IO.Svc.csproj
Normal file
@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<ApplicationIcon />
|
||||
<OutputType>Exe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="WebSocketSharp" Version="1.0.3-rc11" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\ASC.Common\ASC.Common.csproj" />
|
||||
<ProjectReference Include="..\..\ASC.Core.Common\ASC.Core.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
95
common/services/ASC.Socket.IO.Svc/Program.cs
Normal file
95
common/services/ASC.Socket.IO.Svc/Program.cs
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2020
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
|
||||
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
|
||||
*
|
||||
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.DependencyInjection;
|
||||
using ASC.Common.Logging;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
|
||||
namespace ASC.Socket.IO.Svc
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
var host = Host.CreateDefaultBuilder(args)
|
||||
.ConfigureAppConfiguration((hostContext, config) =>
|
||||
{
|
||||
var buided = config.Build();
|
||||
var path = buided["pathToConf"];
|
||||
if (!Path.IsPathRooted(path))
|
||||
{
|
||||
path = Path.GetFullPath(Path.Combine(hostContext.HostingEnvironment.ContentRootPath, path));
|
||||
}
|
||||
config.SetBasePath(path);
|
||||
var env = hostContext.Configuration.GetValue("ENVIRONMENT", "Production");
|
||||
config
|
||||
.AddInMemoryCollection(new Dictionary<string, string>
|
||||
{
|
||||
{"pathToConf", path }
|
||||
}
|
||||
)
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddJsonFile("storage.json")
|
||||
.AddJsonFile("kafka.json")
|
||||
.AddJsonFile("socket.json")
|
||||
.AddJsonFile($"kafka.{env}.json", true)
|
||||
.AddJsonFile($"appsettings.{env}.json", true)
|
||||
.AddJsonFile($"socket.{env}.json", true)
|
||||
.AddEnvironmentVariables()
|
||||
.AddCommandLine(args);
|
||||
})
|
||||
.ConfigureServices((hostContext, services) =>
|
||||
{
|
||||
var diHelper = new DIHelper(services);
|
||||
diHelper.AddNLogManager("ASC.Socket.IO.Svc");
|
||||
services.AddHostedService<SocketServiceLauncher>();
|
||||
diHelper.AddSocketServiceLauncher();
|
||||
|
||||
services.AddAutofac(hostContext.Configuration, hostContext.HostingEnvironment.ContentRootPath, false, false);
|
||||
})
|
||||
.UseConsoleLifetime()
|
||||
.Build();
|
||||
|
||||
using (host)
|
||||
{
|
||||
// Start the host
|
||||
await host.StartAsync();
|
||||
|
||||
// Wait for the host to shutdown
|
||||
await host.WaitForShutdownAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:5017/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": false,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"$STORAGE_ROOT": "../../../Data",
|
||||
"log__name": "socket",
|
||||
"log__dir": "../../../Logs",
|
||||
"core__products__folder": "../../../products"
|
||||
}
|
||||
},
|
||||
"ASC.Socket.IO.Svc": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": false,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"$STORAGE_ROOT": "../../../Data",
|
||||
"log__name": "socket",
|
||||
"log__dir": "../../../Logs",
|
||||
"core__products__folder": "../../../products"
|
||||
},
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000"
|
||||
}
|
||||
}
|
||||
}
|
253
common/services/ASC.Socket.IO.Svc/SocketServiceLauncher.cs
Normal file
253
common/services/ASC.Socket.IO.Svc/SocketServiceLauncher.cs
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
|
||||
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
|
||||
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
|
||||
*
|
||||
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
|
||||
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
|
||||
* relevant author attributions when distributing the software. If the display of the logo in its graphic
|
||||
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
|
||||
* in every copy of the program you distribute.
|
||||
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ASC.Common;
|
||||
|
||||
using ASC.Common.Utils;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Core;
|
||||
using ASC.Core.Notify.Signalr;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using WebSocketSharp;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ASC.Socket.IO.Svc
|
||||
{
|
||||
public class SocketServiceLauncher : IHostedService
|
||||
{
|
||||
private const int PingInterval = 10000;
|
||||
|
||||
private Process Proc { get; set; }
|
||||
private ProcessStartInfo StartInfo { get; set; }
|
||||
private WebSocket WebSocket { get; set; }
|
||||
private CancellationTokenSource CancellationTokenSource { get; set; }
|
||||
private ILog Logger { get; set; }
|
||||
private string LogDir { get; set; }
|
||||
private IConfiguration Configuration { get; set; }
|
||||
private CoreBaseSettings CoreBaseSettings { get; set; }
|
||||
private SignalrServiceClient SignalrServiceClient { get; set; }
|
||||
private IHostEnvironment HostEnvironment { get; set; }
|
||||
|
||||
public SocketServiceLauncher(IOptionsMonitor<ILog> options, IConfiguration configuration, CoreBaseSettings coreBaseSettings, SignalrServiceClient signalrServiceClient, IHostEnvironment hostEnvironment, IConfigureNamedOptions<SignalrServiceClient> configureOptions)
|
||||
{
|
||||
Logger = options.CurrentValue;
|
||||
CancellationTokenSource = new CancellationTokenSource();
|
||||
Configuration = configuration;
|
||||
CoreBaseSettings = coreBaseSettings;
|
||||
SignalrServiceClient = signalrServiceClient;
|
||||
HostEnvironment = hostEnvironment;
|
||||
|
||||
configureOptions.Configure(SignalrServiceClient);
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = Configuration.GetSetting<SocketSettings>("socket");
|
||||
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
CreateNoWindow = false,
|
||||
UseShellExecute = false,
|
||||
FileName = "node",
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
Arguments = string.Format("\"{0}\"", Path.GetFullPath(Path.Combine(HostEnvironment.ContentRootPath, settings.Path, "app.js"))),
|
||||
WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory
|
||||
};
|
||||
StartInfo.EnvironmentVariables.Add("core.machinekey", Configuration["core:machinekey"]);
|
||||
StartInfo.EnvironmentVariables.Add("port", settings.Port);
|
||||
|
||||
if (!string.IsNullOrEmpty(settings.RedisHost) && !string.IsNullOrEmpty(settings.RedisPort))
|
||||
{
|
||||
StartInfo.EnvironmentVariables.Add("redis:host", settings.RedisHost);
|
||||
StartInfo.EnvironmentVariables.Add("redis:port", settings.RedisPort);
|
||||
}
|
||||
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
StartInfo.EnvironmentVariables.Add("portal.internal.url", "http://localhost");
|
||||
}
|
||||
|
||||
LogDir = Logger.LogDirectory;
|
||||
StartInfo.EnvironmentVariables.Add("logPath", Path.Combine(LogDir, "web.socketio.log"));
|
||||
StartNode();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
StopPing();
|
||||
StopNode();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void StartNode()
|
||||
{
|
||||
StopNode();
|
||||
Proc = Process.Start(StartInfo);
|
||||
|
||||
var task = new Task(StartPing, CancellationTokenSource.Token, TaskCreationOptions.LongRunning);
|
||||
task.Start(TaskScheduler.Default);
|
||||
}
|
||||
|
||||
private void StopNode()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Proc != null && !Proc.HasExited)
|
||||
{
|
||||
Proc.Kill();
|
||||
if (!Proc.WaitForExit(10000)) /* wait 10 seconds */
|
||||
{
|
||||
Logger.Warn("The process does not wait for completion.");
|
||||
}
|
||||
Proc.Close();
|
||||
Proc.Dispose();
|
||||
Proc = null;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error("SocketIO failed stop", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void StartPing()
|
||||
{
|
||||
Thread.Sleep(PingInterval);
|
||||
|
||||
var error = false;
|
||||
WebSocket = new WebSocket(string.Format("ws://127.0.0.1:{0}/socket.io/?EIO=3&transport=websocket", StartInfo.EnvironmentVariables["port"]));
|
||||
WebSocket.SetCookie(new WebSocketSharp.Net.Cookie("authorization", SignalrServiceClient.CreateAuthToken()));
|
||||
WebSocket.EmitOnPing = true;
|
||||
|
||||
WebSocket.Log.Level = WebSocketSharp.LogLevel.Trace;
|
||||
|
||||
WebSocket.Log.Output = (logData, filePath) =>
|
||||
{
|
||||
if (logData.Message.Contains("SocketException"))
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
|
||||
Logger.Debug(logData.Message);
|
||||
};
|
||||
|
||||
WebSocket.OnOpen += (sender, e) =>
|
||||
{
|
||||
Logger.Info("Open");
|
||||
error = false;
|
||||
|
||||
Thread.Sleep(PingInterval);
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (WebSocket.Ping())
|
||||
{
|
||||
Logger.Debug("Ping " + WebSocket.ReadyState);
|
||||
Thread.Sleep(PingInterval);
|
||||
}
|
||||
Logger.Debug("Reconnect" + WebSocket.ReadyState);
|
||||
|
||||
}, CancellationTokenSource.Token);
|
||||
};
|
||||
|
||||
WebSocket.OnClose += (sender, e) =>
|
||||
{
|
||||
Logger.Info("Close");
|
||||
if (CancellationTokenSource.IsCancellationRequested) return;
|
||||
|
||||
if (error)
|
||||
{
|
||||
Process.GetCurrentProcess().Kill();
|
||||
}
|
||||
else
|
||||
{
|
||||
WebSocket.Connect();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
WebSocket.OnMessage += (sender, e) =>
|
||||
{
|
||||
if (e.Data.Contains("error"))
|
||||
{
|
||||
Logger.Error("Auth error");
|
||||
CancellationTokenSource.Cancel();
|
||||
}
|
||||
};
|
||||
|
||||
WebSocket.OnError += (sender, e) =>
|
||||
{
|
||||
Logger.Error("Error", e.Exception);
|
||||
};
|
||||
|
||||
WebSocket.Connect();
|
||||
}
|
||||
|
||||
private void StopPing()
|
||||
{
|
||||
try
|
||||
{
|
||||
CancellationTokenSource.Cancel();
|
||||
if (WebSocket.IsAlive)
|
||||
{
|
||||
WebSocket.Close();
|
||||
WebSocket = null;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Logger.Error("Ping failed stop");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class SocketServiceLauncherExtension
|
||||
{
|
||||
public static DIHelper AddSocketServiceLauncher(this DIHelper services)
|
||||
{
|
||||
services.TryAddScoped<SocketServiceLauncher>();
|
||||
return services
|
||||
.AddCoreBaseSettingsService()
|
||||
.AddSignalrServiceClient();
|
||||
}
|
||||
}
|
||||
}
|
10
common/services/ASC.Socket.IO.Svc/SocketSettings.cs
Normal file
10
common/services/ASC.Socket.IO.Svc/SocketSettings.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace ASC.Socket.IO.Svc
|
||||
{
|
||||
public class SocketSettings
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public string Port { get; set; }
|
||||
public string RedisHost { get; set; }
|
||||
public string RedisPort { get; set; }
|
||||
}
|
||||
}
|
3
common/services/ASC.Socket.IO.Svc/appsettings.json
Normal file
3
common/services/ASC.Socket.IO.Svc/appsettings.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"pathToConf": "..\\..\\..\\config"
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"$STORAGE_ROOT": "../../../Data",
|
||||
"log__name": "urlshortener",
|
||||
"log__name": "thumbnails",
|
||||
"log__dir": "../../../Logs",
|
||||
"core__products__folder": "../../../products"
|
||||
}
|
||||
@ -25,7 +25,7 @@
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"$STORAGE_ROOT": "../../../Data",
|
||||
"log__name": "urlshortener",
|
||||
"log__name": "thumbnails",
|
||||
"log__dir": "../../../Logs",
|
||||
"core__products__folder": "../../../products"
|
||||
},
|
||||
|
@ -90,8 +90,8 @@
|
||||
"images": "images",
|
||||
"hide-settings": "Monitoring,LdapSettings,DocService,MailService,PublicPortal,ProxyHttpContent,SpamSubscription,FullTextSearch",
|
||||
"hub": {
|
||||
"url": "",
|
||||
"internal": ""
|
||||
"url": "/socketio/socket.io/",
|
||||
"internal": "http://localhost:9899/"
|
||||
},
|
||||
"cultures": "en-US,ru-RU",
|
||||
"url-shortener": {
|
||||
|
6
config/socket.json
Normal file
6
config/socket.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"socket": {
|
||||
"path": "../../ASC.Socket.IO",
|
||||
"port": "9899",
|
||||
}
|
||||
}
|
@ -1,37 +1,43 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30104.148
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30104.148
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppLimit.CloudComputing.SharpBox", "thirdparty\AppLimit.CloudComputing.SharpBox\AppLimit.CloudComputing.SharpBox.csproj", "{2CBD1C65-D521-4160-950D-875B3443174D}"
|
||||
EndProject
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Graph.Core", "thirdparty\Microsoft.Graph.Core\Microsoft.Graph.Core.csproj", "{81E1084E-8325-4C99-9566-ECEEC80AFD44}"
|
||||
EndProject
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.OneDrive.Sdk", "thirdparty\onedrive-sdk-csharp-master\src\OneDriveSdk\Microsoft.OneDrive.Sdk.csproj", "{915C6FCA-E465-49E3-9A47-2700478DB8AB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2CBD1C65-D521-4160-950D-875B3443174D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2CBD1C65-D521-4160-950D-875B3443174D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2CBD1C65-D521-4160-950D-875B3443174D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2CBD1C65-D521-4160-950D-875B3443174D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{81E1084E-8325-4C99-9566-ECEEC80AFD44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{81E1084E-8325-4C99-9566-ECEEC80AFD44}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{81E1084E-8325-4C99-9566-ECEEC80AFD44}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{81E1084E-8325-4C99-9566-ECEEC80AFD44}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{915C6FCA-E465-49E3-9A47-2700478DB8AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{915C6FCA-E465-49E3-9A47-2700478DB8AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{915C6FCA-E465-49E3-9A47-2700478DB8AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{915C6FCA-E465-49E3-9A47-2700478DB8AB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {97CB107C-6CBC-4C10-8ED4-5C8AEF2C8913}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "websocket-sharp", "websocket-sharp-master\websocket-sharp\websocket-sharp.csproj", "{B357BAC7-529E-4D81-A0D2-71041B19C8DE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2CBD1C65-D521-4160-950D-875B3443174D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2CBD1C65-D521-4160-950D-875B3443174D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2CBD1C65-D521-4160-950D-875B3443174D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2CBD1C65-D521-4160-950D-875B3443174D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{81E1084E-8325-4C99-9566-ECEEC80AFD44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{81E1084E-8325-4C99-9566-ECEEC80AFD44}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{81E1084E-8325-4C99-9566-ECEEC80AFD44}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{81E1084E-8325-4C99-9566-ECEEC80AFD44}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{915C6FCA-E465-49E3-9A47-2700478DB8AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{915C6FCA-E465-49E3-9A47-2700478DB8AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{915C6FCA-E465-49E3-9A47-2700478DB8AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{915C6FCA-E465-49E3-9A47-2700478DB8AB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug|Any CPU.Build.0 = Debug|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
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {97CB107C-6CBC-4C10-8ED4-5C8AEF2C8913}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -12,6 +12,9 @@
|
||||
<WarningsAsErrors></WarningsAsErrors>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Version>1.1.0.451</Version>
|
||||
<PackageLicenseExpression></PackageLicenseExpression>
|
||||
<AssemblyVersion>1.1.0.450</AssemblyVersion>
|
||||
<FileVersion>1.1.0.450</FileVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
|
14
thirdparty/websocket-sharp-master/.gitignore
vendored
Normal file
14
thirdparty/websocket-sharp-master/.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
## Ignore build results and temporary files.
|
||||
|
||||
Backup*
|
||||
_UpgradeReport_Files
|
||||
bin
|
||||
obj
|
||||
|
||||
*.mdb
|
||||
*.pdb
|
||||
*.pidb
|
||||
*.suo
|
||||
*.user
|
||||
*.userprefs
|
||||
UpgradeLog*.*
|
21
thirdparty/websocket-sharp-master/LICENSE.txt
vendored
Normal file
21
thirdparty/websocket-sharp-master/LICENSE.txt
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2010-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.
|
709
thirdparty/websocket-sharp-master/README.md
vendored
Normal file
709
thirdparty/websocket-sharp-master/README.md
vendored
Normal file
@ -0,0 +1,709 @@
|
||||
![Logo](websocket-sharp_logo.png)
|
||||
|
||||
## 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!**
|
||||
|
||||
## Usage ##
|
||||
|
||||
### WebSocket Client ###
|
||||
|
||||
```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"
|
||||
? "I've been balused already..."
|
||||
: "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 ()
|
||||
: this (null)
|
||||
{
|
||||
}
|
||||
|
||||
public Chat (string suffix)
|
||||
{
|
||||
_suffix = suffix ?? 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", () => new Chat (" 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<TBehaviorWithNew> (string)` or `WebSocketServer.AddWebSocketService<TBehavior> (string, Func<TBehavior>)` method.
|
||||
|
||||
The type of `TBehaviorWithNew` must inherit the `WebSocketBehavior` class, and must have a public parameterless constructor.
|
||||
|
||||
The type of `TBehavior` must inherit the `WebSocketBehavior` class.
|
||||
|
||||
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 (code, reason);
|
||||
```
|
||||
|
||||
The `WebSocketServer.Stop` method is overloaded.
|
||||
|
||||
You can use the `WebSocketServer.Stop ()`, `WebSocketServer.Stop (ushort, string)`, or `WebSocketServer.Stop (WebSocketSharp.CloseStatusCode, string)` method to stop the server.
|
||||
|
||||
### 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<TBehaviorWithNew> (string)` or `HttpServer.AddWebSocketService<TBehavior> (string, Func<TBehavior>)` method.
|
||||
|
||||
```csharp
|
||||
var httpsv = new HttpServer (4649);
|
||||
httpsv.AddWebSocketService<Echo> ("/Echo");
|
||||
httpsv.AddWebSocketService<Chat> ("/Chat");
|
||||
httpsv.AddWebSocketService<Chat> ("/ChatWithNyan", () => new Chat (" 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",
|
||||
() =>
|
||||
new Chat () {
|
||||
// To ignore the extensions requested from a client.
|
||||
IgnoreExtensions = true
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
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.Context.QueryString` property, such as the following.
|
||||
|
||||
```csharp
|
||||
public class Chat : WebSocketBehavior
|
||||
{
|
||||
private string _name;
|
||||
...
|
||||
|
||||
protected override void OnOpen ()
|
||||
{
|
||||
_name = Context.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, Func<TBehavior>)` method with initializing, such as the following.
|
||||
|
||||
```csharp
|
||||
wssv.AddWebSocketService<Chat> (
|
||||
"/Chat",
|
||||
() =>
|
||||
new Chat () {
|
||||
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";
|
||||
},
|
||||
CookiesValidator = (req, res) => {
|
||||
// Check the cookies in 'req', and set the cookies to send to
|
||||
// the client with 'res' if necessary.
|
||||
foreach (Cookie 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 [Echo server].
|
||||
|
||||
### 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].
|
||||
|
||||
|
||||
[Echo server]: http://www.websocket.org/echo.html
|
||||
[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
|
74
thirdparty/websocket-sharp-master/websocket-sharp.sln
vendored
Normal file
74
thirdparty/websocket-sharp-master/websocket-sharp.sln
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
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}") = "Example1", "Example1\Example1.csproj", "{390E2568-57B7-4D17-91E5-C29336368CCF}"
|
||||
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}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Debug_Ubuntu|Any CPU = Debug_Ubuntu|Any CPU
|
||||
Release_Ubuntu|Any CPU = Release_Ubuntu|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{390E2568-57B7-4D17-91E5-C29336368CCF}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
|
||||
{390E2568-57B7-4D17-91E5-C29336368CCF}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
|
||||
{390E2568-57B7-4D17-91E5-C29336368CCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{390E2568-57B7-4D17-91E5-C29336368CCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{390E2568-57B7-4D17-91E5-C29336368CCF}.Release_Ubuntu|Any CPU.ActiveCfg = Release_Ubuntu|Any CPU
|
||||
{390E2568-57B7-4D17-91E5-C29336368CCF}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU
|
||||
{390E2568-57B7-4D17-91E5-C29336368CCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{390E2568-57B7-4D17-91E5-C29336368CCF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
|
||||
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
|
||||
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Release_Ubuntu|Any CPU.ActiveCfg = Release_Ubuntu|Any CPU
|
||||
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU
|
||||
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
|
||||
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
|
||||
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release_Ubuntu|Any CPU.ActiveCfg = Release_Ubuntu|Any CPU
|
||||
{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
|
||||
Policies = $0
|
||||
$0.TextStylePolicy = $1
|
||||
$1.inheritsSet = null
|
||||
$1.scope = text/x-csharp
|
||||
$0.CSharpFormattingPolicy = $2
|
||||
$2.inheritsSet = Mono
|
||||
$2.inheritsScope = text/x-csharp
|
||||
$2.scope = text/x-csharp
|
||||
EndGlobalSection
|
||||
EndGlobal
|
47
thirdparty/websocket-sharp-master/websocket-sharp/ByteOrder.cs
vendored
Normal file
47
thirdparty/websocket-sharp-master/websocket-sharp/ByteOrder.cs
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
#region License
|
||||
/*
|
||||
* ByteOrder.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>
|
||||
/// Specifies the byte order.
|
||||
/// </summary>
|
||||
public enum ByteOrder
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies Little-endian.
|
||||
/// </summary>
|
||||
Little,
|
||||
/// <summary>
|
||||
/// Specifies Big-endian.
|
||||
/// </summary>
|
||||
Big
|
||||
}
|
||||
}
|
113
thirdparty/websocket-sharp-master/websocket-sharp/CloseEventArgs.cs
vendored
Normal file
113
thirdparty/websocket-sharp-master/websocket-sharp/CloseEventArgs.cs
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
#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
|
||||
}
|
||||
}
|
120
thirdparty/websocket-sharp-master/websocket-sharp/CloseStatusCode.cs
vendored
Normal file
120
thirdparty/websocket-sharp-master/websocket-sharp/CloseStatusCode.cs
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
#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
|
||||
}
|
||||
}
|
52
thirdparty/websocket-sharp-master/websocket-sharp/CompressionMethod.cs
vendored
Normal file
52
thirdparty/websocket-sharp-master/websocket-sharp/CompressionMethod.cs
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
#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
|
||||
}
|
||||
}
|
109
thirdparty/websocket-sharp-master/websocket-sharp/ErrorEventArgs.cs
vendored
Normal file
109
thirdparty/websocket-sharp-master/websocket-sharp/ErrorEventArgs.cs
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
#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
|
||||
}
|
||||
}
|
2259
thirdparty/websocket-sharp-master/websocket-sharp/Ext.cs
vendored
Normal file
2259
thirdparty/websocket-sharp-master/websocket-sharp/Ext.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
51
thirdparty/websocket-sharp-master/websocket-sharp/Fin.cs
vendored
Normal file
51
thirdparty/websocket-sharp-master/websocket-sharp/Fin.cs
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
#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
|
||||
}
|
||||
}
|
208
thirdparty/websocket-sharp-master/websocket-sharp/HttpBase.cs
vendored
Normal file
208
thirdparty/websocket-sharp-master/websocket-sharp/HttpBase.cs
vendored
Normal file
@ -0,0 +1,208 @@
|
||||
#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
|
||||
}
|
||||
}
|
217
thirdparty/websocket-sharp-master/websocket-sharp/HttpRequest.cs
vendored
Normal file
217
thirdparty/websocket-sharp-master/websocket-sharp/HttpRequest.cs
vendored
Normal file
@ -0,0 +1,217 @@
|
||||
#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
|
||||
}
|
||||
}
|
209
thirdparty/websocket-sharp-master/websocket-sharp/HttpResponse.cs
vendored
Normal file
209
thirdparty/websocket-sharp-master/websocket-sharp/HttpResponse.cs
vendored
Normal file
@ -0,0 +1,209 @@
|
||||
#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
|
||||
}
|
||||
}
|
149
thirdparty/websocket-sharp-master/websocket-sharp/LogData.cs
vendored
Normal file
149
thirdparty/websocket-sharp-master/websocket-sharp/LogData.cs
vendored
Normal file
@ -0,0 +1,149 @@
|
||||
#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
|
||||
}
|
||||
}
|
63
thirdparty/websocket-sharp-master/websocket-sharp/LogLevel.cs
vendored
Normal file
63
thirdparty/websocket-sharp-master/websocket-sharp/LogLevel.cs
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
#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
|
||||
}
|
||||
}
|
330
thirdparty/websocket-sharp-master/websocket-sharp/Logger.cs
vendored
Normal file
330
thirdparty/websocket-sharp-master/websocket-sharp/Logger.cs
vendored
Normal file
@ -0,0 +1,330 @@
|
||||
#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<LogData, string></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<LogData, string></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<LogData, string></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
|
||||
}
|
||||
}
|
51
thirdparty/websocket-sharp-master/websocket-sharp/Mask.cs
vendored
Normal file
51
thirdparty/websocket-sharp-master/websocket-sharp/Mask.cs
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
#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
|
||||
}
|
||||
}
|
183
thirdparty/websocket-sharp-master/websocket-sharp/MessageEventArgs.cs
vendored
Normal file
183
thirdparty/websocket-sharp-master/websocket-sharp/MessageEventArgs.cs
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
#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
|
||||
}
|
||||
}
|
151
thirdparty/websocket-sharp-master/websocket-sharp/Net/AuthenticationBase.cs
vendored
Normal file
151
thirdparty/websocket-sharp-master/websocket-sharp/Net/AuthenticationBase.cs
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
#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
|
||||
}
|
||||
}
|
146
thirdparty/websocket-sharp-master/websocket-sharp/Net/AuthenticationChallenge.cs
vendored
Normal file
146
thirdparty/websocket-sharp-master/websocket-sharp/Net/AuthenticationChallenge.cs
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
#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
|
||||
}
|
||||
}
|
323
thirdparty/websocket-sharp-master/websocket-sharp/Net/AuthenticationResponse.cs
vendored
Normal file
323
thirdparty/websocket-sharp-master/websocket-sharp/Net/AuthenticationResponse.cs
vendored
Normal file
@ -0,0 +1,323 @@
|
||||
#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
|
||||
}
|
||||
}
|
66
thirdparty/websocket-sharp-master/websocket-sharp/Net/AuthenticationSchemes.cs
vendored
Normal file
66
thirdparty/websocket-sharp-master/websocket-sharp/Net/AuthenticationSchemes.cs
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
#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
|
||||
}
|
||||
}
|
91
thirdparty/websocket-sharp-master/websocket-sharp/Net/Chunk.cs
vendored
Normal file
91
thirdparty/websocket-sharp-master/websocket-sharp/Net/Chunk.cs
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
#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-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 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 left;
|
||||
|
||||
if (count > left)
|
||||
count = left;
|
||||
|
||||
Buffer.BlockCopy (_data, _offset, buffer, offset, count);
|
||||
_offset += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
360
thirdparty/websocket-sharp-master/websocket-sharp/Net/ChunkStream.cs
vendored
Normal file
360
thirdparty/websocket-sharp-master/websocket-sharp/Net/ChunkStream.cs
vendored
Normal file
@ -0,0 +1,360 @@
|
||||
#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-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;
|
||||
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 ();
|
||||
}
|
||||
|
||||
public ChunkStream (byte[] buffer, int offset, int count, WebHeaderCollection headers)
|
||||
: this (headers)
|
||||
{
|
||||
Write (buffer, offset, count);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Properties
|
||||
|
||||
internal WebHeaderCollection Headers {
|
||||
get {
|
||||
return _headers;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
public int ChunkLeft {
|
||||
get {
|
||||
return _chunkSize - _chunkRead;
|
||||
}
|
||||
}
|
||||
|
||||
public bool WantMore {
|
||||
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 static string removeChunkExtension (string value)
|
||||
{
|
||||
var idx = value.IndexOf (';');
|
||||
return idx > -1 ? value.Substring (0, idx) : value;
|
||||
}
|
||||
|
||||
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 (b == 32) // SP
|
||||
_gotIt = true;
|
||||
|
||||
if (!_gotIt)
|
||||
_saved.Append ((char) b);
|
||||
|
||||
if (_saved.Length > 20)
|
||||
throwProtocolViolation ("The chunk size is too long.");
|
||||
}
|
||||
|
||||
if (!_sawCr || b != 10)
|
||||
return InputChunkState.None;
|
||||
|
||||
_chunkRead = 0;
|
||||
try {
|
||||
_chunkSize = Int32.Parse (
|
||||
removeChunkExtension (_saved.ToString ()), NumberStyles.HexNumber);
|
||||
}
|
||||
catch {
|
||||
throwProtocolViolation ("The chunk size cannot be parsed.");
|
||||
}
|
||||
|
||||
if (_chunkSize == 0) {
|
||||
_trailerState = 2;
|
||||
return InputChunkState.Trailer;
|
||||
}
|
||||
|
||||
return InputChunkState.Data;
|
||||
}
|
||||
|
||||
private InputChunkState setTrailer (byte[] buffer, ref int offset, int length)
|
||||
{
|
||||
// Check if no trailer.
|
||||
if (_trailerState == 2 && buffer[offset] == 13 && _saved.Length == 0) {
|
||||
offset++;
|
||||
if (offset < length && buffer[offset] == 10) {
|
||||
offset++;
|
||||
return InputChunkState.End;
|
||||
}
|
||||
|
||||
offset--;
|
||||
}
|
||||
|
||||
while (offset < length && _trailerState < 4) {
|
||||
var b = buffer[offset++];
|
||||
_saved.Append ((char) b);
|
||||
if (_saved.Length > 4196)
|
||||
throwProtocolViolation ("The trailer is too long.");
|
||||
|
||||
if (_trailerState == 1 || _trailerState == 3) {
|
||||
if (b != 10)
|
||||
throwProtocolViolation ("LF is expected.");
|
||||
|
||||
_trailerState++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b == 13) {
|
||||
_trailerState++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b == 10)
|
||||
throwProtocolViolation ("LF is unexpected.");
|
||||
|
||||
_trailerState = 0;
|
||||
}
|
||||
|
||||
if (_trailerState < 4)
|
||||
return InputChunkState.Trailer;
|
||||
|
||||
_saved.Length -= 2;
|
||||
var reader = new StringReader (_saved.ToString ());
|
||||
|
||||
string line;
|
||||
while ((line = reader.ReadLine ()) != null && line.Length > 0)
|
||||
_headers.Add (line);
|
||||
|
||||
return InputChunkState.End;
|
||||
}
|
||||
|
||||
private static void throwProtocolViolation (string message)
|
||||
{
|
||||
throw new WebException (message, null, WebExceptionStatus.ServerProtocolViolation, null);
|
||||
}
|
||||
|
||||
private void write (byte[] buffer, ref int offset, int length)
|
||||
{
|
||||
if (_state == InputChunkState.End)
|
||||
throwProtocolViolation ("The chunks were ended.");
|
||||
|
||||
if (_state == InputChunkState.None) {
|
||||
_state = setChunkSize (buffer, ref offset, length);
|
||||
if (_state == InputChunkState.None)
|
||||
return;
|
||||
|
||||
_saved.Length = 0;
|
||||
_sawCr = false;
|
||||
_gotIt = false;
|
||||
}
|
||||
|
||||
if (_state == InputChunkState.Data && offset < length) {
|
||||
_state = writeData (buffer, ref offset, length);
|
||||
if (_state == InputChunkState.Data)
|
||||
return;
|
||||
}
|
||||
|
||||
if (_state == InputChunkState.DataEnded && offset < length) {
|
||||
_state = seekCrLf (buffer, ref offset, length);
|
||||
if (_state == InputChunkState.DataEnded)
|
||||
return;
|
||||
|
||||
_sawCr = false;
|
||||
}
|
||||
|
||||
if (_state == InputChunkState.Trailer && offset < length) {
|
||||
_state = setTrailer (buffer, ref offset, length);
|
||||
if (_state == InputChunkState.Trailer)
|
||||
return;
|
||||
|
||||
_saved.Length = 0;
|
||||
}
|
||||
|
||||
if (offset < length)
|
||||
write (buffer, ref offset, length);
|
||||
}
|
||||
|
||||
private InputChunkState writeData (byte[] buffer, ref int offset, int length)
|
||||
{
|
||||
var cnt = length - offset;
|
||||
var left = _chunkSize - _chunkRead;
|
||||
if (cnt > left)
|
||||
cnt = left;
|
||||
|
||||
var data = new byte[cnt];
|
||||
Buffer.BlockCopy (buffer, offset, data, 0, cnt);
|
||||
_chunks.Add (new Chunk (data));
|
||||
|
||||
offset += cnt;
|
||||
_chunkRead += cnt;
|
||||
|
||||
return _chunkRead == _chunkSize ? InputChunkState.DataEnded : InputChunkState.Data;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
internal void ResetBuffer ()
|
||||
{
|
||||
_chunkRead = 0;
|
||||
_chunkSize = -1;
|
||||
_chunks.Clear ();
|
||||
}
|
||||
|
||||
internal int WriteAndReadBack (byte[] buffer, int offset, int writeCount, int readCount)
|
||||
{
|
||||
Write (buffer, offset, writeCount);
|
||||
return Read (buffer, offset, readCount);
|
||||
}
|
||||
|
||||
#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, ref offset, offset + count);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
211
thirdparty/websocket-sharp-master/websocket-sharp/Net/ChunkedRequestStream.cs
vendored
Normal file
211
thirdparty/websocket-sharp-master/websocket-sharp/Net/ChunkedRequestStream.cs
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
#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-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;
|
||||
using System.IO;
|
||||
|
||||
namespace WebSocketSharp.Net
|
||||
{
|
||||
internal class ChunkedRequestStream : RequestStream
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private const int _bufferLength = 8192;
|
||||
private HttpListenerContext _context;
|
||||
private ChunkStream _decoder;
|
||||
private bool _disposed;
|
||||
private bool _noMoreData;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Constructors
|
||||
|
||||
internal ChunkedRequestStream (
|
||||
Stream stream, byte[] buffer, int offset, int count, HttpListenerContext context)
|
||||
: base (stream, buffer, offset, count)
|
||||
{
|
||||
_context = context;
|
||||
_decoder = new ChunkStream ((WebHeaderCollection) context.Request.Headers);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Properties
|
||||
|
||||
internal ChunkStream Decoder {
|
||||
get {
|
||||
return _decoder;
|
||||
}
|
||||
|
||||
set {
|
||||
_decoder = value;
|
||||
}
|
||||
}
|
||||
|
||||
#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.WantMore || nread == 0) {
|
||||
_noMoreData = !_decoder.WantMore && nread == 0;
|
||||
ares.Count = rstate.InitialCount - rstate.Count;
|
||||
ares.Complete ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ares.Offset = 0;
|
||||
ares.Count = Math.Min (_bufferLength, _decoder.ChunkLeft + 6);
|
||||
base.BeginRead (ares.Buffer, ares.Offset, ares.Count, onRead, rstate);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_context.Connection.SendError (ex.Message, 400);
|
||||
ares.Complete (ex);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public override IAsyncResult BeginRead (
|
||||
byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException (GetType ().ToString ());
|
||||
|
||||
if (buffer == null)
|
||||
throw new ArgumentNullException ("buffer");
|
||||
|
||||
if (offset < 0)
|
||||
throw new ArgumentOutOfRangeException ("offset", "A negative value.");
|
||||
|
||||
if (count < 0)
|
||||
throw new ArgumentOutOfRangeException ("count", "A negative value.");
|
||||
|
||||
var len = buffer.Length;
|
||||
if (offset + count > len)
|
||||
throw new ArgumentException (
|
||||
"The sum of 'offset' and 'count' is greater than 'buffer' length.");
|
||||
|
||||
var 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) {
|
||||
// Got all we wanted, no need to bother the decoder yet.
|
||||
ares.Count = nread;
|
||||
ares.Complete ();
|
||||
|
||||
return ares;
|
||||
}
|
||||
|
||||
if (!_decoder.WantMore) {
|
||||
_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)
|
||||
throw new ObjectDisposedException (GetType ().ToString ());
|
||||
|
||||
if (asyncResult == null)
|
||||
throw new ArgumentNullException ("asyncResult");
|
||||
|
||||
var ares = asyncResult as HttpStreamAsyncResult;
|
||||
if (ares == null)
|
||||
throw new ArgumentException ("A wrong IAsyncResult.", "asyncResult");
|
||||
|
||||
if (!ares.IsCompleted)
|
||||
ares.AsyncWaitHandle.WaitOne ();
|
||||
|
||||
if (ares.HasException)
|
||||
throw new HttpListenerException (400, "I/O operation aborted.");
|
||||
|
||||
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
|
||||
}
|
||||
}
|
291
thirdparty/websocket-sharp-master/websocket-sharp/Net/ClientSslConfiguration.cs
vendored
Normal file
291
thirdparty/websocket-sharp-master/websocket-sharp/Net/ClientSslConfiguration.cs
vendored
Normal file
@ -0,0 +1,291 @@
|
||||
#region License
|
||||
/*
|
||||
* ClientSslConfiguration.cs
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2014 liryna
|
||||
* 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:
|
||||
* - 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.
|
||||
/// </summary>
|
||||
public ClientSslConfiguration ()
|
||||
{
|
||||
_enabledSslProtocols = SslProtocols.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ClientSslConfiguration"/> class
|
||||
/// with the specified <paramref name="targetHost"/>.
|
||||
/// </summary>
|
||||
/// <param name="targetHost">
|
||||
/// A <see cref="string"/> that represents the target host server name.
|
||||
/// </param>
|
||||
public ClientSslConfiguration (string targetHost)
|
||||
{
|
||||
_targetHost = targetHost;
|
||||
_enabledSslProtocols = SslProtocols.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the parameters from the specified <paramref name="configuration"/> to
|
||||
/// a new instance of the <see cref="ClientSslConfiguration"/> class.
|
||||
/// </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 certificates from which to select one to
|
||||
/// supply to the server.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <para>
|
||||
/// A <see cref="X509CertificateCollection"/> or <see langword="null"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// That 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>
|
||||
/// The <see cref="SslProtocols"/> enum values that represent
|
||||
/// the protocols used for authentication.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The default value is <see cref="SslProtocols.Default"/>.
|
||||
/// </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>
|
||||
/// <para>
|
||||
/// A <see cref="string"/> or <see langword="null"/>
|
||||
/// if not specified.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// That string represents the name of the server that
|
||||
/// will share a secure connection with a client.
|
||||
/// </para>
|
||||
/// </value>
|
||||
public string TargetHost {
|
||||
get {
|
||||
return _targetHost;
|
||||
}
|
||||
|
||||
set {
|
||||
_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
|
||||
}
|
||||
}
|
1016
thirdparty/websocket-sharp-master/websocket-sharp/Net/Cookie.cs
vendored
Normal file
1016
thirdparty/websocket-sharp-master/websocket-sharp/Net/Cookie.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
821
thirdparty/websocket-sharp-master/websocket-sharp/Net/CookieCollection.cs
vendored
Normal file
821
thirdparty/websocket-sharp-master/websocket-sharp/Net/CookieCollection.cs
vendored
Normal file
@ -0,0 +1,821 @@
|
||||
#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
|
||||
}
|
||||
}
|
165
thirdparty/websocket-sharp-master/websocket-sharp/Net/CookieException.cs
vendored
Normal file
165
thirdparty/websocket-sharp-master/websocket-sharp/Net/CookieException.cs
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
#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
|
||||
}
|
||||
}
|
515
thirdparty/websocket-sharp-master/websocket-sharp/Net/EndPointListener.cs
vendored
Normal file
515
thirdparty/websocket-sharp-master/websocket-sharp/Net/EndPointListener.cs
vendored
Normal file
@ -0,0 +1,515 @@
|
||||
#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-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:
|
||||
* - 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 static readonly string _defaultCertFolderPath;
|
||||
private IPEndPoint _endpoint;
|
||||
private Dictionary<HttpListenerPrefix, HttpListener> _prefixes;
|
||||
private bool _secure;
|
||||
private Socket _socket;
|
||||
private ServerSslConfiguration _sslConfig;
|
||||
private List<HttpListenerPrefix> _unhandled; // host == '*'
|
||||
private Dictionary<HttpConnection, HttpConnection> _unregistered;
|
||||
private object _unregisteredSync;
|
||||
|
||||
#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
|
||||
)
|
||||
{
|
||||
if (secure) {
|
||||
var cert =
|
||||
getCertificate (endpoint.Port, certificateFolderPath, sslConfig.ServerCertificate);
|
||||
|
||||
if (cert == null)
|
||||
throw new ArgumentException ("No server certificate could be found.");
|
||||
|
||||
_secure = true;
|
||||
_sslConfig = new ServerSslConfiguration (sslConfig);
|
||||
_sslConfig.ServerCertificate = cert;
|
||||
}
|
||||
|
||||
_endpoint = endpoint;
|
||||
_prefixes = new Dictionary<HttpListenerPrefix, HttpListener> ();
|
||||
_unregistered = new Dictionary<HttpConnection, HttpConnection> ();
|
||||
_unregisteredSync = ((ICollection) _unregistered).SyncRoot;
|
||||
_socket =
|
||||
new Socket (endpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
|
||||
if (reuseAddress)
|
||||
_socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||
|
||||
_socket.Bind (endpoint);
|
||||
_socket.Listen (500);
|
||||
_socket.BeginAccept (onAccept, this);
|
||||
}
|
||||
|
||||
#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)
|
||||
throw new HttpListenerException (87, "The prefix is already in use.");
|
||||
}
|
||||
|
||||
prefixes.Add (prefix);
|
||||
}
|
||||
|
||||
private static RSACryptoServiceProvider createRSAFromFile (string filename)
|
||||
{
|
||||
byte[] pvk = null;
|
||||
using (var fs = File.Open (filename, FileMode.Open, FileAccess.Read, FileShare.Read)) {
|
||||
pvk = new byte[fs.Length];
|
||||
fs.Read (pvk, 0, pvk.Length);
|
||||
}
|
||||
|
||||
var rsa = new RSACryptoServiceProvider ();
|
||||
rsa.ImportCspBlob (pvk);
|
||||
|
||||
return rsa;
|
||||
}
|
||||
|
||||
private static X509Certificate2 getCertificate (
|
||||
int port, string folderPath, X509Certificate2 defaultCertificate
|
||||
)
|
||||
{
|
||||
if (folderPath == null || folderPath.Length == 0)
|
||||
folderPath = _defaultCertFolderPath;
|
||||
|
||||
try {
|
||||
var cer = Path.Combine (folderPath, String.Format ("{0}.cer", port));
|
||||
var key = Path.Combine (folderPath, String.Format ("{0}.key", port));
|
||||
if (File.Exists (cer) && File.Exists (key)) {
|
||||
var cert = new X509Certificate2 (cer);
|
||||
cert.PrivateKey = createRSAFromFile (key);
|
||||
|
||||
return cert;
|
||||
}
|
||||
}
|
||||
catch {
|
||||
}
|
||||
|
||||
return defaultCertificate;
|
||||
}
|
||||
|
||||
private void leaveIfNoPrefix ()
|
||||
{
|
||||
if (_prefixes.Count > 0)
|
||||
return;
|
||||
|
||||
var prefs = _unhandled;
|
||||
if (prefs != null && prefs.Count > 0)
|
||||
return;
|
||||
|
||||
prefs = _all;
|
||||
if (prefs != null && prefs.Count > 0)
|
||||
return;
|
||||
|
||||
EndPointManager.RemoveEndPoint (_endpoint);
|
||||
}
|
||||
|
||||
private static void onAccept (IAsyncResult asyncResult)
|
||||
{
|
||||
var lsnr = (EndPointListener) asyncResult.AsyncState;
|
||||
|
||||
Socket sock = null;
|
||||
try {
|
||||
sock = lsnr._socket.EndAccept (asyncResult);
|
||||
}
|
||||
catch (SocketException) {
|
||||
// TODO: Should log the error code when this class has a logging.
|
||||
}
|
||||
catch (ObjectDisposedException) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
lsnr._socket.BeginAccept (onAccept, lsnr);
|
||||
}
|
||||
catch {
|
||||
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);
|
||||
lock (listener._unregisteredSync)
|
||||
listener._unregistered[conn] = conn;
|
||||
|
||||
conn.BeginReadRequest ();
|
||||
}
|
||||
catch {
|
||||
if (conn != null) {
|
||||
conn.Close (true);
|
||||
return;
|
||||
}
|
||||
|
||||
socket.Close ();
|
||||
}
|
||||
}
|
||||
|
||||
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 bestMatch = null;
|
||||
|
||||
var bestLen = -1;
|
||||
foreach (var pref in prefixes) {
|
||||
var prefPath = pref.Path;
|
||||
|
||||
var len = prefPath.Length;
|
||||
if (len < bestLen)
|
||||
continue;
|
||||
|
||||
if (path.StartsWith (prefPath)) {
|
||||
bestLen = len;
|
||||
bestMatch = pref.Listener;
|
||||
}
|
||||
}
|
||||
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
#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 (_unregisteredSync)
|
||||
_unregistered.Remove (connection);
|
||||
}
|
||||
|
||||
internal bool TrySearchHttpListener (Uri uri, out HttpListener listener)
|
||||
{
|
||||
listener = null;
|
||||
|
||||
if (uri == null)
|
||||
return false;
|
||||
|
||||
var host = uri.Host;
|
||||
var dns = Uri.CheckHostName (host) == UriHostNameType.Dns;
|
||||
var port = uri.Port.ToString ();
|
||||
var path = HttpUtility.UrlDecode (uri.AbsolutePath);
|
||||
var pathSlash = path[path.Length - 1] != '/' ? path + "/" : path;
|
||||
|
||||
if (host != null && host.Length > 0) {
|
||||
var bestLen = -1;
|
||||
foreach (var pref in _prefixes.Keys) {
|
||||
if (dns) {
|
||||
var prefHost = pref.Host;
|
||||
if (Uri.CheckHostName (prefHost) == UriHostNameType.Dns && prefHost != host)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pref.Port != port)
|
||||
continue;
|
||||
|
||||
var prefPath = pref.Path;
|
||||
|
||||
var len = prefPath.Length;
|
||||
if (len < bestLen)
|
||||
continue;
|
||||
|
||||
if (path.StartsWith (prefPath) || pathSlash.StartsWith (prefPath)) {
|
||||
bestLen = len;
|
||||
listener = _prefixes[pref];
|
||||
}
|
||||
}
|
||||
|
||||
if (bestLen != -1)
|
||||
return true;
|
||||
}
|
||||
|
||||
var prefs = _unhandled;
|
||||
listener = searchHttpListenerFromSpecial (path, prefs);
|
||||
if (listener == null && pathSlash != path)
|
||||
listener = searchHttpListenerFromSpecial (pathSlash, prefs);
|
||||
|
||||
if (listener != null)
|
||||
return true;
|
||||
|
||||
prefs = _all;
|
||||
listener = searchHttpListenerFromSpecial (path, prefs);
|
||||
if (listener == null && pathSlash != path)
|
||||
listener = searchHttpListenerFromSpecial (pathSlash, prefs);
|
||||
|
||||
return listener != null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void AddPrefix (HttpListenerPrefix prefix, HttpListener listener)
|
||||
{
|
||||
List<HttpListenerPrefix> current, future;
|
||||
if (prefix.Host == "*") {
|
||||
do {
|
||||
current = _unhandled;
|
||||
future = current != null
|
||||
? new List<HttpListenerPrefix> (current)
|
||||
: new List<HttpListenerPrefix> ();
|
||||
|
||||
prefix.Listener = listener;
|
||||
addSpecial (future, prefix);
|
||||
}
|
||||
while (Interlocked.CompareExchange (ref _unhandled, future, current) != current);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (prefix.Host == "+") {
|
||||
do {
|
||||
current = _all;
|
||||
future = current != null
|
||||
? new List<HttpListenerPrefix> (current)
|
||||
: new List<HttpListenerPrefix> ();
|
||||
|
||||
prefix.Listener = listener;
|
||||
addSpecial (future, prefix);
|
||||
}
|
||||
while (Interlocked.CompareExchange (ref _all, future, current) != current);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<HttpListenerPrefix, HttpListener> prefs, prefs2;
|
||||
do {
|
||||
prefs = _prefixes;
|
||||
if (prefs.ContainsKey (prefix)) {
|
||||
if (prefs[prefix] != listener) {
|
||||
throw new HttpListenerException (
|
||||
87, String.Format ("There's another listener for {0}.", prefix)
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
prefs2 = new Dictionary<HttpListenerPrefix, HttpListener> (prefs);
|
||||
prefs2[prefix] = listener;
|
||||
}
|
||||
while (Interlocked.CompareExchange (ref _prefixes, prefs2, prefs) != prefs);
|
||||
}
|
||||
|
||||
public void Close ()
|
||||
{
|
||||
_socket.Close ();
|
||||
|
||||
HttpConnection[] conns = null;
|
||||
lock (_unregisteredSync) {
|
||||
if (_unregistered.Count == 0)
|
||||
return;
|
||||
|
||||
var keys = _unregistered.Keys;
|
||||
conns = new HttpConnection[keys.Count];
|
||||
keys.CopyTo (conns, 0);
|
||||
_unregistered.Clear ();
|
||||
}
|
||||
|
||||
for (var i = conns.Length - 1; i >= 0; i--)
|
||||
conns[i].Close (true);
|
||||
}
|
||||
|
||||
public void RemovePrefix (HttpListenerPrefix prefix, HttpListener listener)
|
||||
{
|
||||
List<HttpListenerPrefix> current, future;
|
||||
if (prefix.Host == "*") {
|
||||
do {
|
||||
current = _unhandled;
|
||||
if (current == null)
|
||||
break;
|
||||
|
||||
future = new List<HttpListenerPrefix> (current);
|
||||
if (!removeSpecial (future, prefix))
|
||||
break; // The prefix wasn't found.
|
||||
}
|
||||
while (Interlocked.CompareExchange (ref _unhandled, future, current) != current);
|
||||
|
||||
leaveIfNoPrefix ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (prefix.Host == "+") {
|
||||
do {
|
||||
current = _all;
|
||||
if (current == null)
|
||||
break;
|
||||
|
||||
future = new List<HttpListenerPrefix> (current);
|
||||
if (!removeSpecial (future, prefix))
|
||||
break; // The prefix wasn't found.
|
||||
}
|
||||
while (Interlocked.CompareExchange (ref _all, future, current) != current);
|
||||
|
||||
leaveIfNoPrefix ();
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<HttpListenerPrefix, HttpListener> prefs, prefs2;
|
||||
do {
|
||||
prefs = _prefixes;
|
||||
if (!prefs.ContainsKey (prefix))
|
||||
break;
|
||||
|
||||
prefs2 = new Dictionary<HttpListenerPrefix, HttpListener> (prefs);
|
||||
prefs2.Remove (prefix);
|
||||
}
|
||||
while (Interlocked.CompareExchange (ref _prefixes, prefs2, prefs) != prefs);
|
||||
|
||||
leaveIfNoPrefix ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
240
thirdparty/websocket-sharp-master/websocket-sharp/Net/EndPointManager.cs
vendored
Normal file
240
thirdparty/websocket-sharp-master/websocket-sharp/Net/EndPointManager.cs
vendored
Normal file
@ -0,0 +1,240 @@
|
||||
#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-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:
|
||||
* - 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);
|
||||
|
||||
var addr = convertToIPAddress (pref.Host);
|
||||
if (addr == null)
|
||||
throw new HttpListenerException (87, "Includes an invalid host.");
|
||||
|
||||
if (!addr.IsLocal ())
|
||||
throw new HttpListenerException (87, "Includes an invalid host.");
|
||||
|
||||
int port;
|
||||
if (!Int32.TryParse (pref.Port, out port))
|
||||
throw new HttpListenerException (87, "Includes an invalid port.");
|
||||
|
||||
if (!port.IsPortNumber ())
|
||||
throw new HttpListenerException (87, "Includes an invalid port.");
|
||||
|
||||
var path = pref.Path;
|
||||
if (path.IndexOf ('%') != -1)
|
||||
throw new HttpListenerException (87, "Includes an invalid path.");
|
||||
|
||||
if (path.IndexOf ("//", StringComparison.Ordinal) != -1)
|
||||
throw new HttpListenerException (87, "Includes an invalid path.");
|
||||
|
||||
var endpoint = new IPEndPoint (addr, port);
|
||||
|
||||
EndPointListener lsnr;
|
||||
if (_endpoints.TryGetValue (endpoint, out lsnr)) {
|
||||
if (lsnr.IsSecure ^ pref.IsSecure)
|
||||
throw new HttpListenerException (87, "Includes an invalid scheme.");
|
||||
}
|
||||
else {
|
||||
lsnr =
|
||||
new EndPointListener (
|
||||
endpoint,
|
||||
pref.IsSecure,
|
||||
listener.CertificateFolderPath,
|
||||
listener.SslConfiguration,
|
||||
listener.ReuseAddress
|
||||
);
|
||||
|
||||
_endpoints.Add (endpoint, lsnr);
|
||||
}
|
||||
|
||||
lsnr.AddPrefix (pref, listener);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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, listener);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
internal static bool RemoveEndPoint (IPEndPoint endpoint)
|
||||
{
|
||||
lock (((ICollection) _endpoints).SyncRoot) {
|
||||
EndPointListener lsnr;
|
||||
if (!_endpoints.TryGetValue (endpoint, out lsnr))
|
||||
return false;
|
||||
|
||||
_endpoints.Remove (endpoint);
|
||||
lsnr.Close ();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
}
|
||||
}
|
82
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpBasicIdentity.cs
vendored
Normal file
82
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpBasicIdentity.cs
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
#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
|
||||
}
|
||||
}
|
597
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpConnection.cs
vendored
Normal file
597
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpConnection.cs
vendored
Normal file
@ -0,0 +1,597 @@
|
||||
#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-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:
|
||||
* - 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 byte[] _buffer;
|
||||
private const int _bufferLength = 8192;
|
||||
private HttpListenerContext _context;
|
||||
private bool _contextRegistered;
|
||||
private StringBuilder _currentLine;
|
||||
private InputState _inputState;
|
||||
private RequestStream _inputStream;
|
||||
private HttpListener _lastListener;
|
||||
private LineState _lineState;
|
||||
private EndPointListener _listener;
|
||||
private EndPoint _localEndPoint;
|
||||
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 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;
|
||||
}
|
||||
|
||||
_localEndPoint = socket.LocalEndPoint;
|
||||
_remoteEndPoint = socket.RemoteEndPoint;
|
||||
_sync = new object ();
|
||||
_timeout = 90000; // 90k ms for first request, 15k ms from then on.
|
||||
_timeoutCanceled = new Dictionary<int, bool> ();
|
||||
_timer = new Timer (onTimeout, this, Timeout.Infinite, Timeout.Infinite);
|
||||
|
||||
init ();
|
||||
}
|
||||
|
||||
#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 ();
|
||||
}
|
||||
|
||||
unregisterContext ();
|
||||
removeConnection ();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
_inputStream = null;
|
||||
_outputStream = null;
|
||||
|
||||
_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 ()
|
||||
{
|
||||
_context = new HttpListenerContext (this);
|
||||
_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;
|
||||
if (conn._socket == null)
|
||||
return;
|
||||
|
||||
lock (conn._sync) {
|
||||
if (conn._socket == null)
|
||||
return;
|
||||
|
||||
var nread = -1;
|
||||
var len = 0;
|
||||
try {
|
||||
var current = conn._reuses;
|
||||
if (!conn._timeoutCanceled[current]) {
|
||||
conn._timer.Change (Timeout.Infinite, Timeout.Infinite);
|
||||
conn._timeoutCanceled[current] = true;
|
||||
}
|
||||
|
||||
nread = conn._stream.EndRead (asyncResult);
|
||||
conn._requestBuffer.Write (conn._buffer, 0, nread);
|
||||
len = (int) conn._requestBuffer.Length;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (conn._requestBuffer != null && conn._requestBuffer.Length > 0) {
|
||||
conn.SendError (ex.Message, 400);
|
||||
return;
|
||||
}
|
||||
|
||||
conn.close ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (nread <= 0) {
|
||||
conn.close ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn.processInput (conn._requestBuffer.GetBuffer (), len)) {
|
||||
if (!conn._context.HasError)
|
||||
conn._context.Request.FinishInitialization ();
|
||||
|
||||
if (conn._context.HasError) {
|
||||
conn.SendError ();
|
||||
return;
|
||||
}
|
||||
|
||||
HttpListener lsnr;
|
||||
if (!conn._listener.TrySearchHttpListener (conn._context.Request.Url, out lsnr)) {
|
||||
conn.SendError (null, 404);
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn._lastListener != lsnr) {
|
||||
conn.removeConnection ();
|
||||
if (!lsnr.AddConnection (conn)) {
|
||||
conn.close ();
|
||||
return;
|
||||
}
|
||||
|
||||
conn._lastListener = lsnr;
|
||||
}
|
||||
|
||||
conn._context.Listener = lsnr;
|
||||
if (!conn._context.Authenticate ())
|
||||
return;
|
||||
|
||||
if (conn._context.Register ())
|
||||
conn._contextRegistered = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
conn._stream.BeginRead (conn._buffer, 0, _bufferLength, onRead, conn);
|
||||
}
|
||||
}
|
||||
|
||||
private static void onTimeout (object state)
|
||||
{
|
||||
var conn = (HttpConnection) state;
|
||||
var current = conn._reuses;
|
||||
if (conn._socket == null)
|
||||
return;
|
||||
|
||||
lock (conn._sync) {
|
||||
if (conn._socket == null)
|
||||
return;
|
||||
|
||||
if (conn._timeoutCanceled[current])
|
||||
return;
|
||||
|
||||
conn.SendError (null, 408);
|
||||
}
|
||||
}
|
||||
|
||||
// true -> Done processing.
|
||||
// false -> Need more input.
|
||||
private bool processInput (byte[] data, int length)
|
||||
{
|
||||
if (_currentLine == null)
|
||||
_currentLine = new StringBuilder (64);
|
||||
|
||||
var nread = 0;
|
||||
try {
|
||||
string line;
|
||||
while ((line = readLineFrom (data, _position, length, out nread)) != null) {
|
||||
_position += nread;
|
||||
if (line.Length == 0) {
|
||||
if (_inputState == InputState.RequestLine)
|
||||
continue;
|
||||
|
||||
if (_position > 32768)
|
||||
_context.ErrorMessage = "Headers too long";
|
||||
|
||||
_currentLine = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_inputState == InputState.RequestLine) {
|
||||
_context.Request.SetRequestLine (line);
|
||||
_inputState = InputState.Headers;
|
||||
}
|
||||
else {
|
||||
_context.Request.AddHeader (line);
|
||||
}
|
||||
|
||||
if (_context.HasError)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_context.ErrorMessage = ex.Message;
|
||||
return true;
|
||||
}
|
||||
|
||||
_position += nread;
|
||||
if (_position >= 32768) {
|
||||
_context.ErrorMessage = "Headers too long";
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string readLineFrom (byte[] buffer, int offset, int length, out int read)
|
||||
{
|
||||
read = 0;
|
||||
|
||||
for (var i = offset; i < length && _lineState != LineState.Lf; i++) {
|
||||
read++;
|
||||
|
||||
var b = buffer[i];
|
||||
if (b == 13)
|
||||
_lineState = LineState.Cr;
|
||||
else if (b == 10)
|
||||
_lineState = LineState.Lf;
|
||||
else
|
||||
_currentLine.Append ((char) b);
|
||||
}
|
||||
|
||||
if (_lineState != LineState.Lf)
|
||||
return null;
|
||||
|
||||
var line = _currentLine.ToString ();
|
||||
|
||||
_currentLine.Length = 0;
|
||||
_lineState = LineState.None;
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
private void removeConnection ()
|
||||
{
|
||||
if (_lastListener != null)
|
||||
_lastListener.RemoveConnection (this);
|
||||
else
|
||||
_listener.RemoveConnection (this);
|
||||
}
|
||||
|
||||
private void unregisterContext ()
|
||||
{
|
||||
if (!_contextRegistered)
|
||||
return;
|
||||
|
||||
_context.Unregister ();
|
||||
_contextRegistered = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
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 ();
|
||||
unregisterContext ();
|
||||
init ();
|
||||
|
||||
_reuses++;
|
||||
BeginReadRequest ();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void BeginReadRequest ()
|
||||
{
|
||||
if (_buffer == null)
|
||||
_buffer = new byte[_bufferLength];
|
||||
|
||||
if (_reuses == 1)
|
||||
_timeout = 15000;
|
||||
|
||||
try {
|
||||
_timeoutCanceled.Add (_reuses, false);
|
||||
_timer.Change (_timeout, Timeout.Infinite);
|
||||
_stream.BeginRead (_buffer, 0, _bufferLength, onRead, this);
|
||||
}
|
||||
catch {
|
||||
close ();
|
||||
}
|
||||
}
|
||||
|
||||
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 ()
|
||||
{
|
||||
// TODO: Can we get this stream before reading the input?
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public void SendError ()
|
||||
{
|
||||
SendError (_context.ErrorMessage, _context.ErrorStatus);
|
||||
}
|
||||
|
||||
public void SendError (string message, int status)
|
||||
{
|
||||
if (_socket == null)
|
||||
return;
|
||||
|
||||
lock (_sync) {
|
||||
if (_socket == null)
|
||||
return;
|
||||
|
||||
try {
|
||||
var res = _context.Response;
|
||||
res.StatusCode = status;
|
||||
res.ContentType = "text/html";
|
||||
|
||||
var content = new StringBuilder (64);
|
||||
content.AppendFormat ("<html><body><h1>{0} {1}", status, res.StatusDescription);
|
||||
if (message != null && message.Length > 0)
|
||||
content.AppendFormat (" ({0})</h1></body></html>", message);
|
||||
else
|
||||
content.Append ("</h1></body></html>");
|
||||
|
||||
var enc = Encoding.UTF8;
|
||||
var entity = enc.GetBytes (content.ToString ());
|
||||
res.ContentEncoding = enc;
|
||||
res.ContentLength64 = entity.LongLength;
|
||||
|
||||
res.Close (entity, true);
|
||||
}
|
||||
catch {
|
||||
Close (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
187
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpDigestIdentity.cs
vendored
Normal file
187
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpDigestIdentity.cs
vendored
Normal file
@ -0,0 +1,187 @@
|
||||
#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
|
||||
}
|
||||
}
|
128
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpHeaderInfo.cs
vendored
Normal file
128
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpHeaderInfo.cs
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
#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
|
||||
}
|
||||
}
|
44
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpHeaderType.cs
vendored
Normal file
44
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpHeaderType.cs
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
#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
|
||||
}
|
||||
}
|
836
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListener.cs
vendored
Normal file
836
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListener.cs
vendored
Normal file
@ -0,0 +1,836 @@
|
||||
#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-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:
|
||||
* - 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 Dictionary<HttpConnection, HttpConnection> _connections;
|
||||
private object _connectionsSync;
|
||||
private List<HttpListenerContext> _ctxQueue;
|
||||
private object _ctxQueueSync;
|
||||
private Dictionary<HttpListenerContext, HttpListenerContext> _ctxRegistry;
|
||||
private object _ctxRegistrySync;
|
||||
private static readonly string _defaultRealm;
|
||||
private bool _disposed;
|
||||
private bool _ignoreWriteExceptions;
|
||||
private volatile bool _listening;
|
||||
private Logger _logger;
|
||||
private HttpListenerPrefixCollection _prefixes;
|
||||
private string _realm;
|
||||
private bool _reuseAddress;
|
||||
private ServerSslConfiguration _sslConfig;
|
||||
private Func<IIdentity, NetworkCredential> _userCredFinder;
|
||||
private List<HttpListenerAsyncResult> _waitQueue;
|
||||
private object _waitQueueSync;
|
||||
|
||||
#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;
|
||||
|
||||
_connections = new Dictionary<HttpConnection, HttpConnection> ();
|
||||
_connectionsSync = ((ICollection) _connections).SyncRoot;
|
||||
|
||||
_ctxQueue = new List<HttpListenerContext> ();
|
||||
_ctxQueueSync = ((ICollection) _ctxQueue).SyncRoot;
|
||||
|
||||
_ctxRegistry = new Dictionary<HttpListenerContext, HttpListenerContext> ();
|
||||
_ctxRegistrySync = ((ICollection) _ctxRegistry).SyncRoot;
|
||||
|
||||
_logger = new Logger ();
|
||||
|
||||
_prefixes = new HttpListenerPrefixCollection (this);
|
||||
|
||||
_waitQueue = new List<HttpListenerAsyncResult> ();
|
||||
_waitQueueSync = ((ICollection) _waitQueue).SyncRoot;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Properties
|
||||
|
||||
internal bool IsDisposed {
|
||||
get {
|
||||
return _disposed;
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
/// One of the <see cref="WebSocketSharp.Net.AuthenticationSchemes"/> enum values,
|
||||
/// represents the scheme used to authenticate the clients. The default value is
|
||||
/// <see cref="WebSocketSharp.Net.AuthenticationSchemes.Anonymous"/>.
|
||||
/// </value>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// This listener has been closed.
|
||||
/// </exception>
|
||||
public AuthenticationSchemes AuthenticationSchemes {
|
||||
get {
|
||||
CheckDisposed ();
|
||||
return _authSchemes;
|
||||
}
|
||||
|
||||
set {
|
||||
CheckDisposed ();
|
||||
_authSchemes = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the delegate called to select the scheme used to authenticate the clients.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If you set this property, the listener uses the authentication scheme selected by
|
||||
/// the delegate for each request. Or if you don't set, the listener uses the value of
|
||||
/// the <see cref="HttpListener.AuthenticationSchemes"/> property as the authentication
|
||||
/// scheme for all requests.
|
||||
/// </remarks>
|
||||
/// <value>
|
||||
/// A <c>Func<<see cref="HttpListenerRequest"/>, <see cref="AuthenticationSchemes"/>></c>
|
||||
/// delegate that references the method used to select an authentication scheme. The default
|
||||
/// value is <see langword="null"/>.
|
||||
/// </value>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// This listener has been closed.
|
||||
/// </exception>
|
||||
public Func<HttpListenerRequest, AuthenticationSchemes> AuthenticationSchemeSelector {
|
||||
get {
|
||||
CheckDisposed ();
|
||||
return _authSchemeSelector;
|
||||
}
|
||||
|
||||
set {
|
||||
CheckDisposed ();
|
||||
_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. A set of the certificate files
|
||||
/// is a pair of the <c>'port number'.cer</c> (DER) and <c>'port number'.key</c>
|
||||
/// (DER, RSA Private Key).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If this property is <see langword="null"/> or empty, the result of
|
||||
/// <c>System.Environment.GetFolderPath
|
||||
/// (<see cref="Environment.SpecialFolder.ApplicationData"/>)</c> is used as the default path.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <value>
|
||||
/// A <see cref="string"/> that represents the path to the folder in which stores
|
||||
/// the certificate files. The default value is <see langword="null"/>.
|
||||
/// </value>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// This listener has been closed.
|
||||
/// </exception>
|
||||
public string CertificateFolderPath {
|
||||
get {
|
||||
CheckDisposed ();
|
||||
return _certFolderPath;
|
||||
}
|
||||
|
||||
set {
|
||||
CheckDisposed ();
|
||||
_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>
|
||||
/// <c>true</c> if the listener shouldn't return those exceptions; otherwise, <c>false</c>.
|
||||
/// The default value is <c>false</c>.
|
||||
/// </value>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// This listener has been closed.
|
||||
/// </exception>
|
||||
public bool IgnoreWriteExceptions {
|
||||
get {
|
||||
CheckDisposed ();
|
||||
return _ignoreWriteExceptions;
|
||||
}
|
||||
|
||||
set {
|
||||
CheckDisposed ();
|
||||
_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>
|
||||
/// The default logging level is <see cref="LogLevel.Error"/>. 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.
|
||||
/// </remarks>
|
||||
/// <value>
|
||||
/// A <see cref="Logger"/> that provides the logging functions.
|
||||
/// </value>
|
||||
public Logger Log {
|
||||
get {
|
||||
return _logger;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 {
|
||||
CheckDisposed ();
|
||||
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 empty, <c>"SECRET AREA"</c> will be used as
|
||||
/// the name of the realm.
|
||||
/// </remarks>
|
||||
/// <value>
|
||||
/// A <see cref="string"/> that represents the name of the realm. The default value is
|
||||
/// <see langword="null"/>.
|
||||
/// </value>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// This listener has been closed.
|
||||
/// </exception>
|
||||
public string Realm {
|
||||
get {
|
||||
CheckDisposed ();
|
||||
return _realm;
|
||||
}
|
||||
|
||||
set {
|
||||
CheckDisposed ();
|
||||
_realm = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the SSL configuration used to authenticate the server and
|
||||
/// optionally the client for secure connection.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="ServerSslConfiguration"/> that represents the configuration used to
|
||||
/// authenticate the server and optionally the client for secure connection.
|
||||
/// </value>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// This listener has been closed.
|
||||
/// </exception>
|
||||
public ServerSslConfiguration SslConfiguration {
|
||||
get {
|
||||
CheckDisposed ();
|
||||
return _sslConfig ?? (_sslConfig = new ServerSslConfiguration ());
|
||||
}
|
||||
|
||||
set {
|
||||
CheckDisposed ();
|
||||
_sslConfig = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 isn't 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>
|
||||
/// A <c>Func<<see cref="IIdentity"/>, <see cref="NetworkCredential"/>></c> delegate
|
||||
/// that references the method used to find the credentials. The default value is
|
||||
/// <see langword="null"/>.
|
||||
/// </value>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// This listener has been closed.
|
||||
/// </exception>
|
||||
public Func<IIdentity, NetworkCredential> UserCredentialsFinder {
|
||||
get {
|
||||
CheckDisposed ();
|
||||
return _userCredFinder;
|
||||
}
|
||||
|
||||
set {
|
||||
CheckDisposed ();
|
||||
_userCredFinder = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void cleanupConnections ()
|
||||
{
|
||||
HttpConnection[] conns = null;
|
||||
lock (_connectionsSync) {
|
||||
if (_connections.Count == 0)
|
||||
return;
|
||||
|
||||
// Need to copy this since closing will call the RemoveConnection method.
|
||||
var keys = _connections.Keys;
|
||||
conns = new HttpConnection[keys.Count];
|
||||
keys.CopyTo (conns, 0);
|
||||
_connections.Clear ();
|
||||
}
|
||||
|
||||
for (var i = conns.Length - 1; i >= 0; i--)
|
||||
conns[i].Close (true);
|
||||
}
|
||||
|
||||
private void cleanupContextQueue (bool sendServiceUnavailable)
|
||||
{
|
||||
HttpListenerContext[] ctxs = null;
|
||||
lock (_ctxQueueSync) {
|
||||
if (_ctxQueue.Count == 0)
|
||||
return;
|
||||
|
||||
ctxs = _ctxQueue.ToArray ();
|
||||
_ctxQueue.Clear ();
|
||||
}
|
||||
|
||||
if (!sendServiceUnavailable)
|
||||
return;
|
||||
|
||||
foreach (var ctx in ctxs) {
|
||||
var res = ctx.Response;
|
||||
res.StatusCode = (int) HttpStatusCode.ServiceUnavailable;
|
||||
res.Close ();
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupContextRegistry ()
|
||||
{
|
||||
HttpListenerContext[] ctxs = null;
|
||||
lock (_ctxRegistrySync) {
|
||||
if (_ctxRegistry.Count == 0)
|
||||
return;
|
||||
|
||||
// Need to copy this since closing will call the UnregisterContext method.
|
||||
var keys = _ctxRegistry.Keys;
|
||||
ctxs = new HttpListenerContext[keys.Count];
|
||||
keys.CopyTo (ctxs, 0);
|
||||
_ctxRegistry.Clear ();
|
||||
}
|
||||
|
||||
for (var i = ctxs.Length - 1; i >= 0; i--)
|
||||
ctxs[i].Connection.Close (true);
|
||||
}
|
||||
|
||||
private void cleanupWaitQueue (Exception exception)
|
||||
{
|
||||
HttpListenerAsyncResult[] aress = null;
|
||||
lock (_waitQueueSync) {
|
||||
if (_waitQueue.Count == 0)
|
||||
return;
|
||||
|
||||
aress = _waitQueue.ToArray ();
|
||||
_waitQueue.Clear ();
|
||||
}
|
||||
|
||||
foreach (var ares in aress)
|
||||
ares.Complete (exception);
|
||||
}
|
||||
|
||||
private void close (bool force)
|
||||
{
|
||||
if (_listening) {
|
||||
_listening = false;
|
||||
EndPointManager.RemoveListener (this);
|
||||
}
|
||||
|
||||
lock (_ctxRegistrySync)
|
||||
cleanupContextQueue (!force);
|
||||
|
||||
cleanupContextRegistry ();
|
||||
cleanupConnections ();
|
||||
cleanupWaitQueue (new ObjectDisposedException (GetType ().ToString ()));
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
private HttpListenerAsyncResult getAsyncResultFromQueue ()
|
||||
{
|
||||
if (_waitQueue.Count == 0)
|
||||
return null;
|
||||
|
||||
var ares = _waitQueue[0];
|
||||
_waitQueue.RemoveAt (0);
|
||||
|
||||
return ares;
|
||||
}
|
||||
|
||||
private HttpListenerContext getContextFromQueue ()
|
||||
{
|
||||
if (_ctxQueue.Count == 0)
|
||||
return null;
|
||||
|
||||
var ctx = _ctxQueue[0];
|
||||
_ctxQueue.RemoveAt (0);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
internal bool AddConnection (HttpConnection connection)
|
||||
{
|
||||
if (!_listening)
|
||||
return false;
|
||||
|
||||
lock (_connectionsSync) {
|
||||
if (!_listening)
|
||||
return false;
|
||||
|
||||
_connections[connection] = connection;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
internal HttpListenerAsyncResult BeginGetContext (HttpListenerAsyncResult asyncResult)
|
||||
{
|
||||
lock (_ctxRegistrySync) {
|
||||
if (!_listening)
|
||||
throw new HttpListenerException (995);
|
||||
|
||||
var ctx = getContextFromQueue ();
|
||||
if (ctx == null)
|
||||
_waitQueue.Add (asyncResult);
|
||||
else
|
||||
asyncResult.Complete (ctx, true);
|
||||
|
||||
return asyncResult;
|
||||
}
|
||||
}
|
||||
|
||||
internal void CheckDisposed ()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException (GetType ().ToString ());
|
||||
}
|
||||
|
||||
internal string GetRealm ()
|
||||
{
|
||||
var realm = _realm;
|
||||
return realm != null && realm.Length > 0 ? realm : _defaultRealm;
|
||||
}
|
||||
|
||||
internal Func<IIdentity, NetworkCredential> GetUserCredentialsFinder ()
|
||||
{
|
||||
return _userCredFinder;
|
||||
}
|
||||
|
||||
internal bool RegisterContext (HttpListenerContext context)
|
||||
{
|
||||
if (!_listening)
|
||||
return false;
|
||||
|
||||
lock (_ctxRegistrySync) {
|
||||
if (!_listening)
|
||||
return false;
|
||||
|
||||
_ctxRegistry[context] = context;
|
||||
|
||||
var ares = getAsyncResultFromQueue ();
|
||||
if (ares == null)
|
||||
_ctxQueue.Add (context);
|
||||
else
|
||||
ares.Complete (context);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
internal void RemoveConnection (HttpConnection connection)
|
||||
{
|
||||
lock (_connectionsSync)
|
||||
_connections.Remove (connection);
|
||||
}
|
||||
|
||||
internal AuthenticationSchemes SelectAuthenticationScheme (HttpListenerRequest request)
|
||||
{
|
||||
var selector = _authSchemeSelector;
|
||||
if (selector == null)
|
||||
return _authSchemes;
|
||||
|
||||
try {
|
||||
return selector (request);
|
||||
}
|
||||
catch {
|
||||
return AuthenticationSchemes.None;
|
||||
}
|
||||
}
|
||||
|
||||
internal void UnregisterContext (HttpListenerContext context)
|
||||
{
|
||||
lock (_ctxRegistrySync)
|
||||
_ctxRegistry.Remove (context);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Shuts down the listener immediately.
|
||||
/// </summary>
|
||||
public void Abort ()
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
close (true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begins getting an incoming request asynchronously.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This asynchronous operation must be completed by calling the <c>EndGetContext</c> method.
|
||||
/// Typically, the method is invoked by the <paramref name="callback"/> delegate.
|
||||
/// </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
|
||||
/// the <paramref name="callback"/> delegate.
|
||||
/// </param>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// <para>
|
||||
/// This listener has no URI prefix on which listens.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// -or-
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This listener hasn't been started, or is currently stopped.
|
||||
/// </para>
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// This listener has been closed.
|
||||
/// </exception>
|
||||
public IAsyncResult BeginGetContext (AsyncCallback callback, Object state)
|
||||
{
|
||||
CheckDisposed ();
|
||||
if (_prefixes.Count == 0)
|
||||
throw new InvalidOperationException ("The listener has no URI prefix on which listens.");
|
||||
|
||||
if (!_listening)
|
||||
throw new InvalidOperationException ("The listener hasn't been started.");
|
||||
|
||||
return BeginGetContext (new HttpListenerAsyncResult (callback, state));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shuts down the listener.
|
||||
/// </summary>
|
||||
public void Close ()
|
||||
{
|
||||
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 <c>BeginGetContext</c> method.
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// A <see cref="HttpListenerContext"/> that represents a request.
|
||||
/// </returns>
|
||||
/// <param name="asyncResult">
|
||||
/// An <see cref="IAsyncResult"/> obtained by calling the <c>BeginGetContext</c> method.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="asyncResult"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <paramref name="asyncResult"/> wasn't obtained by calling the <c>BeginGetContext</c> method.
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// This method was already called for the specified <paramref name="asyncResult"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// This listener has been closed.
|
||||
/// </exception>
|
||||
public HttpListenerContext EndGetContext (IAsyncResult asyncResult)
|
||||
{
|
||||
CheckDisposed ();
|
||||
if (asyncResult == null)
|
||||
throw new ArgumentNullException ("asyncResult");
|
||||
|
||||
var ares = asyncResult as HttpListenerAsyncResult;
|
||||
if (ares == null)
|
||||
throw new ArgumentException ("A wrong IAsyncResult.", "asyncResult");
|
||||
|
||||
if (ares.EndCalled)
|
||||
throw new InvalidOperationException ("This IAsyncResult cannot be reused.");
|
||||
|
||||
ares.EndCalled = true;
|
||||
if (!ares.IsCompleted)
|
||||
ares.AsyncWaitHandle.WaitOne ();
|
||||
|
||||
return ares.GetContext (); // This may throw an exception.
|
||||
}
|
||||
|
||||
/// <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 hasn't been started, or is currently stopped.
|
||||
/// </para>
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// This listener has been closed.
|
||||
/// </exception>
|
||||
public HttpListenerContext GetContext ()
|
||||
{
|
||||
CheckDisposed ();
|
||||
if (_prefixes.Count == 0)
|
||||
throw new InvalidOperationException ("The listener has no URI prefix on which listens.");
|
||||
|
||||
if (!_listening)
|
||||
throw new InvalidOperationException ("The listener hasn't been started.");
|
||||
|
||||
var ares = BeginGetContext (new HttpListenerAsyncResult (null, null));
|
||||
ares.InGet = true;
|
||||
|
||||
return EndGetContext (ares);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts receiving incoming requests.
|
||||
/// </summary>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// This listener has been closed.
|
||||
/// </exception>
|
||||
public void Start ()
|
||||
{
|
||||
CheckDisposed ();
|
||||
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 ()
|
||||
{
|
||||
CheckDisposed ();
|
||||
if (!_listening)
|
||||
return;
|
||||
|
||||
_listening = false;
|
||||
EndPointManager.RemoveListener (this);
|
||||
|
||||
lock (_ctxRegistrySync)
|
||||
cleanupContextQueue (true);
|
||||
|
||||
cleanupContextRegistry ();
|
||||
cleanupConnections ();
|
||||
cleanupWaitQueue (new HttpListenerException (995, "The listener is stopped."));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Explicit Interface Implementations
|
||||
|
||||
/// <summary>
|
||||
/// Releases all resources used by the listener.
|
||||
/// </summary>
|
||||
void IDisposable.Dispose ()
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
close (true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
198
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListenerAsyncResult.cs
vendored
Normal file
198
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListenerAsyncResult.cs
vendored
Normal file
@ -0,0 +1,198 @@
|
||||
#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-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:
|
||||
* - 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 HttpListenerContext _context;
|
||||
private bool _endCalled;
|
||||
private Exception _exception;
|
||||
private bool _inGet;
|
||||
private object _state;
|
||||
private object _sync;
|
||||
private bool _syncCompleted;
|
||||
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 bool EndCalled {
|
||||
get {
|
||||
return _endCalled;
|
||||
}
|
||||
|
||||
set {
|
||||
_endCalled = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool InGet {
|
||||
get {
|
||||
return _inGet;
|
||||
}
|
||||
|
||||
set {
|
||||
_inGet = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
public object AsyncState {
|
||||
get {
|
||||
return _state;
|
||||
}
|
||||
}
|
||||
|
||||
public WaitHandle AsyncWaitHandle {
|
||||
get {
|
||||
lock (_sync)
|
||||
return _waitHandle ?? (_waitHandle = new ManualResetEvent (_completed));
|
||||
}
|
||||
}
|
||||
|
||||
public bool CompletedSynchronously {
|
||||
get {
|
||||
return _syncCompleted;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCompleted {
|
||||
get {
|
||||
lock (_sync)
|
||||
return _completed;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private static void complete (HttpListenerAsyncResult asyncResult)
|
||||
{
|
||||
lock (asyncResult._sync) {
|
||||
asyncResult._completed = true;
|
||||
|
||||
var waitHandle = asyncResult._waitHandle;
|
||||
if (waitHandle != null)
|
||||
waitHandle.Set ();
|
||||
}
|
||||
|
||||
var callback = asyncResult._callback;
|
||||
if (callback == null)
|
||||
return;
|
||||
|
||||
ThreadPool.QueueUserWorkItem (
|
||||
state => {
|
||||
try {
|
||||
callback (asyncResult);
|
||||
}
|
||||
catch {
|
||||
}
|
||||
},
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
internal void Complete (Exception exception)
|
||||
{
|
||||
_exception = _inGet && (exception is ObjectDisposedException)
|
||||
? new HttpListenerException (995, "The listener is closed.")
|
||||
: exception;
|
||||
|
||||
complete (this);
|
||||
}
|
||||
|
||||
internal void Complete (HttpListenerContext context)
|
||||
{
|
||||
Complete (context, false);
|
||||
}
|
||||
|
||||
internal void Complete (HttpListenerContext context, bool syncCompleted)
|
||||
{
|
||||
_context = context;
|
||||
_syncCompleted = syncCompleted;
|
||||
|
||||
complete (this);
|
||||
}
|
||||
|
||||
internal HttpListenerContext GetContext ()
|
||||
{
|
||||
if (_exception != null)
|
||||
throw _exception;
|
||||
|
||||
return _context;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
256
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListenerContext.cs
vendored
Normal file
256
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListenerContext.cs
vendored
Normal file
@ -0,0 +1,256 @@
|
||||
#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-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:
|
||||
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Security.Principal;
|
||||
using WebSocketSharp.Net.WebSockets;
|
||||
|
||||
namespace WebSocketSharp.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides the access to the HTTP request and response objects used by
|
||||
/// the <see cref="HttpListener"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class cannot be inherited.
|
||||
/// </remarks>
|
||||
public sealed class HttpListenerContext
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private HttpConnection _connection;
|
||||
private string _error;
|
||||
private int _errorStatus;
|
||||
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;
|
||||
_errorStatus = 400;
|
||||
_request = new HttpListenerRequest (this);
|
||||
_response = new HttpListenerResponse (this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Properties
|
||||
|
||||
internal HttpConnection Connection {
|
||||
get {
|
||||
return _connection;
|
||||
}
|
||||
}
|
||||
|
||||
internal string ErrorMessage {
|
||||
get {
|
||||
return _error;
|
||||
}
|
||||
|
||||
set {
|
||||
_error = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal int ErrorStatus {
|
||||
get {
|
||||
return _errorStatus;
|
||||
}
|
||||
|
||||
set {
|
||||
_errorStatus = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool HasError {
|
||||
get {
|
||||
return _error != 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>
|
||||
/// A <see cref="IPrincipal"/> instance that represents the client information.
|
||||
/// </value>
|
||||
public IPrincipal User {
|
||||
get {
|
||||
return _user;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
internal bool Authenticate ()
|
||||
{
|
||||
var schm = _listener.SelectAuthenticationScheme (_request);
|
||||
if (schm == AuthenticationSchemes.Anonymous)
|
||||
return true;
|
||||
|
||||
if (schm == AuthenticationSchemes.None) {
|
||||
_response.Close (HttpStatusCode.Forbidden);
|
||||
return false;
|
||||
}
|
||||
|
||||
var realm = _listener.GetRealm ();
|
||||
var user =
|
||||
HttpUtility.CreateUser (
|
||||
_request.Headers["Authorization"],
|
||||
schm,
|
||||
realm,
|
||||
_request.HttpMethod,
|
||||
_listener.GetUserCredentialsFinder ()
|
||||
);
|
||||
|
||||
if (user == null || !user.Identity.IsAuthenticated) {
|
||||
_response.CloseWithAuthChallenge (new AuthenticationChallenge (schm, realm).ToString ());
|
||||
return false;
|
||||
}
|
||||
|
||||
_user = user;
|
||||
return true;
|
||||
}
|
||||
|
||||
internal bool Register ()
|
||||
{
|
||||
return _listener.RegisterContext (this);
|
||||
}
|
||||
|
||||
internal void Unregister ()
|
||||
{
|
||||
_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 represents the subprotocol supported on
|
||||
/// this 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)
|
||||
throw new InvalidOperationException ("The accepting is already in progress.");
|
||||
|
||||
if (protocol != null) {
|
||||
if (protocol.Length == 0)
|
||||
throw new ArgumentException ("An empty string.", "protocol");
|
||||
|
||||
if (!protocol.IsToken ())
|
||||
throw new ArgumentException ("Contains an invalid character.", "protocol");
|
||||
}
|
||||
|
||||
_websocketContext = new HttpListenerWebSocketContext (this, protocol);
|
||||
return _websocketContext;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
127
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListenerException.cs
vendored
Normal file
127
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListenerException.cs
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
#region License
|
||||
/*
|
||||
* HttpListenerException.cs
|
||||
*
|
||||
* This code is derived from System.Net.HttpListenerException.cs of Mono
|
||||
* (http://www.mono-project.com).
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
|
||||
* 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:
|
||||
* - 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 a <see cref="HttpListener"/> gets an error
|
||||
/// 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 <see cref="SerializationInfo"/> and <see cref="StreamingContext"/>.
|
||||
/// </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 <paramref name="errorCode"/>.
|
||||
/// </summary>
|
||||
/// <param name="errorCode">
|
||||
/// An <see cref="int"/> that identifies the error.
|
||||
/// </param>
|
||||
public HttpListenerException (int errorCode)
|
||||
: base (errorCode)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpListenerException"/> class
|
||||
/// with the specified <paramref name="errorCode"/> and <paramref name="message"/>.
|
||||
/// </summary>
|
||||
/// <param name="errorCode">
|
||||
/// An <see cref="int"/> that identifies the error.
|
||||
/// </param>
|
||||
/// <param name="message">
|
||||
/// A <see cref="string"/> that describes the error.
|
||||
/// </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>
|
||||
/// An <see cref="int"/> that identifies the error.
|
||||
/// </value>
|
||||
public override int ErrorCode {
|
||||
get {
|
||||
return NativeErrorCode;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
228
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListenerPrefix.cs
vendored
Normal file
228
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListenerPrefix.cs
vendored
Normal file
@ -0,0 +1,228 @@
|
||||
#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-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:
|
||||
* - Gonzalo Paniagua Javier <gonzalo@novell.com>
|
||||
* - Oleg Mihailik <mihailik@gmail.com>
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
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 <paramref name="uriPrefix"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This constructor must be called after calling the CheckPrefix method.
|
||||
/// </remarks>
|
||||
/// <param name="uriPrefix">
|
||||
/// A <see cref="string"/> that represents the URI prefix.
|
||||
/// </param>
|
||||
internal HttpListenerPrefix (string uriPrefix)
|
||||
{
|
||||
_original = uriPrefix;
|
||||
parse (uriPrefix);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
public string Host {
|
||||
get {
|
||||
return _host;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSecure {
|
||||
get {
|
||||
return _secure;
|
||||
}
|
||||
}
|
||||
|
||||
public HttpListener Listener {
|
||||
get {
|
||||
return _listener;
|
||||
}
|
||||
|
||||
set {
|
||||
_listener = value;
|
||||
}
|
||||
}
|
||||
|
||||
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 startHost = uriPrefix.IndexOf (':') + 3;
|
||||
var root = uriPrefix.IndexOf ('/', startHost + 1, len - startHost - 1);
|
||||
|
||||
var colon = uriPrefix.LastIndexOf (':', root - 1, root - startHost - 1);
|
||||
if (uriPrefix[root - 1] != ']' && colon > startHost) {
|
||||
_host = uriPrefix.Substring (startHost, colon - startHost);
|
||||
_port = uriPrefix.Substring (colon + 1, root - colon - 1);
|
||||
}
|
||||
else {
|
||||
_host = uriPrefix.Substring (startHost, root - startHost);
|
||||
_port = _secure ? "443" : "80";
|
||||
}
|
||||
|
||||
_path = uriPrefix.Substring (root);
|
||||
|
||||
_prefix =
|
||||
String.Format ("http{0}://{1}:{2}{3}", _secure ? "s" : "", _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)
|
||||
throw new ArgumentException ("An empty string.", "uriPrefix");
|
||||
|
||||
if (!(uriPrefix.StartsWith ("http://") || uriPrefix.StartsWith ("https://")))
|
||||
throw new ArgumentException ("The scheme isn't 'http' or 'https'.", "uriPrefix");
|
||||
|
||||
var startHost = uriPrefix.IndexOf (':') + 3;
|
||||
if (startHost >= len)
|
||||
throw new ArgumentException ("No host is specified.", "uriPrefix");
|
||||
|
||||
if (uriPrefix[startHost] == ':')
|
||||
throw new ArgumentException ("No host is specified.", "uriPrefix");
|
||||
|
||||
var root = uriPrefix.IndexOf ('/', startHost, len - startHost);
|
||||
if (root == startHost)
|
||||
throw new ArgumentException ("No host is specified.", "uriPrefix");
|
||||
|
||||
if (root == -1 || uriPrefix[len - 1] != '/')
|
||||
throw new ArgumentException ("Ends without '/'.", "uriPrefix");
|
||||
|
||||
if (uriPrefix[root - 1] == ':')
|
||||
throw new ArgumentException ("No port is specified.", "uriPrefix");
|
||||
|
||||
if (root == len - 2)
|
||||
throw new ArgumentException ("No path is specified.", "uriPrefix");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance and the specified <see cref="Object"/> have the same value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method will be required to detect duplicates in any collection.
|
||||
/// </remarks>
|
||||
/// <param name="obj">
|
||||
/// An <see cref="Object"/> to compare to this instance.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if <paramref name="obj"/> is a <see cref="HttpListenerPrefix"/> and
|
||||
/// its value is the same as this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals (Object obj)
|
||||
{
|
||||
var pref = obj as HttpListenerPrefix;
|
||||
return pref != null && pref._prefix == _prefix;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hash code for this 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
|
||||
}
|
||||
}
|
278
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListenerPrefixCollection.cs
vendored
Normal file
278
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListenerPrefixCollection.cs
vendored
Normal file
@ -0,0 +1,278 @@
|
||||
#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-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;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace WebSocketSharp.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides the collection used to store the URI prefixes for the <see cref="HttpListener"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The <see cref="HttpListener"/> responds to the request which has a requested URI that
|
||||
/// the prefixes most closely match.
|
||||
/// </remarks>
|
||||
public class HttpListenerPrefixCollection : ICollection<string>, IEnumerable<string>, IEnumerable
|
||||
{
|
||||
#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 <paramref name="uriPrefix"/> to the collection.
|
||||
/// </summary>
|
||||
/// <param name="uriPrefix">
|
||||
/// A <see cref="string"/> that represents the URI prefix to add. The prefix must be
|
||||
/// a well-formed URI prefix with http or https scheme, and must end with a <c>'/'</c>.
|
||||
/// </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"/> associated with this collection is closed.
|
||||
/// </exception>
|
||||
public void Add (string uriPrefix)
|
||||
{
|
||||
_listener.CheckDisposed ();
|
||||
HttpListenerPrefix.CheckPrefix (uriPrefix);
|
||||
if (_prefixes.Contains (uriPrefix))
|
||||
return;
|
||||
|
||||
_prefixes.Add (uriPrefix);
|
||||
if (_listener.IsListening)
|
||||
EndPointManager.AddPrefix (uriPrefix, _listener);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all URI prefixes from the collection.
|
||||
/// </summary>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// The <see cref="HttpListener"/> associated with this collection is closed.
|
||||
/// </exception>
|
||||
public void Clear ()
|
||||
{
|
||||
_listener.CheckDisposed ();
|
||||
_prefixes.Clear ();
|
||||
if (_listener.IsListening)
|
||||
EndPointManager.RemoveListener (_listener);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the collection contains the specified
|
||||
/// <paramref name="uriPrefix"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the collection contains <paramref name="uriPrefix"/>;
|
||||
/// otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
/// <param name="uriPrefix">
|
||||
/// A <see cref="string"/> that represents the URI prefix to test.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="uriPrefix"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// The <see cref="HttpListener"/> 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 <see cref="Array"/>.
|
||||
/// </summary>
|
||||
/// <param name="array">
|
||||
/// An <see cref="Array"/> that receives the URI prefix strings in the collection.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// An <see cref="int"/> that represents the zero-based index in <paramref name="array"/>
|
||||
/// at which copying begins.
|
||||
/// </param>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// The <see cref="HttpListener"/> associated with this collection is closed.
|
||||
/// </exception>
|
||||
public void CopyTo (Array array, int offset)
|
||||
{
|
||||
_listener.CheckDisposed ();
|
||||
((ICollection) _prefixes).CopyTo (array, offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the contents of the collection to the specified array of <see cref="string"/>.
|
||||
/// </summary>
|
||||
/// <param name="array">
|
||||
/// An array of <see cref="string"/> that receives the URI prefix strings in the collection.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// An <see cref="int"/> that represents the zero-based index in <paramref name="array"/>
|
||||
/// at which copying begins.
|
||||
/// </param>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// The <see cref="HttpListener"/> associated with this collection is closed.
|
||||
/// </exception>
|
||||
public void CopyTo (string[] array, int offset)
|
||||
{
|
||||
_listener.CheckDisposed ();
|
||||
_prefixes.CopyTo (array, offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the enumerator used to iterate through the <see cref="HttpListenerPrefixCollection"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// An <see cref="T:System.Collections.Generic.IEnumerator{string}"/> instance used to iterate
|
||||
/// through the collection.
|
||||
/// </returns>
|
||||
public IEnumerator<string> GetEnumerator ()
|
||||
{
|
||||
return _prefixes.GetEnumerator ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the specified <paramref name="uriPrefix"/> from the collection.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <c>true</c> if <paramref name="uriPrefix"/> is successfully found and removed;
|
||||
/// otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
/// <param name="uriPrefix">
|
||||
/// A <see cref="string"/> that represents the URI prefix to remove.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="uriPrefix"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
/// <exception cref="ObjectDisposedException">
|
||||
/// The <see cref="HttpListener"/> associated with this collection is closed.
|
||||
/// </exception>
|
||||
public bool Remove (string uriPrefix)
|
||||
{
|
||||
_listener.CheckDisposed ();
|
||||
if (uriPrefix == null)
|
||||
throw new ArgumentNullException ("uriPrefix");
|
||||
|
||||
var ret = _prefixes.Remove (uriPrefix);
|
||||
if (ret && _listener.IsListening)
|
||||
EndPointManager.RemovePrefix (uriPrefix, _listener);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Explicit Interface Implementations
|
||||
|
||||
/// <summary>
|
||||
/// Gets the enumerator used to iterate through the <see cref="HttpListenerPrefixCollection"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// An <see cref="IEnumerator"/> instance used to iterate through the collection.
|
||||
/// </returns>
|
||||
IEnumerator IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return _prefixes.GetEnumerator ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
911
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListenerRequest.cs
vendored
Normal file
911
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListenerRequest.cs
vendored
Normal file
@ -0,0 +1,911 @@
|
||||
#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-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:
|
||||
* - 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 (',')
|
||||
.Trim ()
|
||||
.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 () ?? Encoding.UTF8;
|
||||
|
||||
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 = getInputStream () ?? 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"
|
||||
&& _protocolVersion > HttpVersion.Version10
|
||||
&& _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 (',').Trim ().ToList ().ToArray ();
|
||||
|
||||
return _userLanguages;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void finishInitialization10 ()
|
||||
{
|
||||
var transferEnc = _headers["Transfer-Encoding"];
|
||||
if (transferEnc != null) {
|
||||
_context.ErrorMessage = "Invalid Transfer-Encoding header";
|
||||
return;
|
||||
}
|
||||
|
||||
if (_httpMethod == "POST") {
|
||||
if (_contentLength == -1) {
|
||||
_context.ErrorMessage = "Content-Length header required";
|
||||
return;
|
||||
}
|
||||
|
||||
if (_contentLength == 0) {
|
||||
_context.ErrorMessage = "Invalid Content-Length header";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Encoding getContentEncoding ()
|
||||
{
|
||||
var val = _headers["Content-Type"];
|
||||
if (val == null)
|
||||
return null;
|
||||
|
||||
Encoding ret;
|
||||
HttpUtility.TryGetEncoding (val, out ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private RequestStream getInputStream ()
|
||||
{
|
||||
return _contentLength > 0 || _chunked
|
||||
? _connection.GetRequestStream (_contentLength, _chunked)
|
||||
: null;
|
||||
}
|
||||
|
||||
#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 (_protocolVersion == HttpVersion.Version10) {
|
||||
finishInitialization10 ();
|
||||
return;
|
||||
}
|
||||
|
||||
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 = String.Empty;
|
||||
_context.ErrorStatus = 501;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_chunked = true;
|
||||
}
|
||||
|
||||
if (_httpMethod == "POST" || _httpMethod == "PUT") {
|
||||
if (_contentLength <= 0 && !_chunked) {
|
||||
_context.ErrorMessage = String.Empty;
|
||||
_context.ErrorStatus = 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.IndexOf ("HTTP/") != 0) {
|
||||
_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.Major < 1) {
|
||||
_context.ErrorMessage = "Invalid request line (version)";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!method.IsHttpMethod (ver)) {
|
||||
_context.ErrorMessage = "Invalid request line (method)";
|
||||
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
|
||||
}
|
||||
}
|
1243
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListenerResponse.cs
vendored
Normal file
1243
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpListenerResponse.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
233
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpRequestHeader.cs
vendored
Normal file
233
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpRequestHeader.cs
vendored
Normal file
@ -0,0 +1,233 @@
|
||||
#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
|
||||
}
|
||||
}
|
189
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpResponseHeader.cs
vendored
Normal file
189
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpResponseHeader.cs
vendored
Normal file
@ -0,0 +1,189 @@
|
||||
#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
|
||||
}
|
||||
}
|
359
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpStatusCode.cs
vendored
Normal file
359
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpStatusCode.cs
vendored
Normal file
@ -0,0 +1,359 @@
|
||||
#region License
|
||||
/*
|
||||
* HttpStatusCode.cs
|
||||
*
|
||||
* This code is derived from System.Net.HttpStatusCode.cs 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-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
|
||||
|
||||
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
|
||||
/// hasn't 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 doesn't 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 hasn't 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 couldn't 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 hasn't found anything matching the request URI.
|
||||
/// </summary>
|
||||
NotFound = 404,
|
||||
/// <summary>
|
||||
/// Equivalent to status code 405.
|
||||
/// Indicates that the method specified in the request line isn't allowed for the resource
|
||||
/// identified by the request URI.
|
||||
/// </summary>
|
||||
MethodNotAllowed = 405,
|
||||
/// <summary>
|
||||
/// Equivalent to status code 406.
|
||||
/// Indicates that the server doesn't 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 didn't 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 couldn't 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 couldn't 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 doesn't 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 didn't 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 doesn't support the HTTP version used in the client's request.
|
||||
/// </summary>
|
||||
HttpVersionNotSupported = 505,
|
||||
}
|
||||
}
|
184
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpStreamAsyncResult.cs
vendored
Normal file
184
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpStreamAsyncResult.cs
vendored
Normal file
@ -0,0 +1,184 @@
|
||||
#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-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;
|
||||
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)
|
||||
return _waitHandle ?? (_waitHandle = new ManualResetEvent (_completed));
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
_exception = exception;
|
||||
Complete ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
1146
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpUtility.cs
vendored
Normal file
1146
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpUtility.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
73
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpVersion.cs
vendored
Normal file
73
thirdparty/websocket-sharp-master/websocket-sharp/Net/HttpVersion.cs
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
#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
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user